2025-11-11 23:26:51 -06:00
|
|
|
-- pxl8 tile properties dialog menu
|
|
|
|
|
-- provides a ui for editing custom properties on tilemap tiles
|
2025-11-01 12:39:59 -05:00
|
|
|
|
|
|
|
|
local DEBUG = false
|
|
|
|
|
|
|
|
|
|
local function log(msg)
|
|
|
|
|
if DEBUG then
|
|
|
|
|
print("[tile-properties] " .. msg)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function getSelectedTile()
|
|
|
|
|
log("getSelectedTile() called")
|
|
|
|
|
|
|
|
|
|
if not app then
|
|
|
|
|
log("ERROR: app is nil!")
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local sprite = app.sprite
|
|
|
|
|
log("sprite: " .. tostring(sprite))
|
|
|
|
|
if not sprite then
|
|
|
|
|
log("No sprite selected")
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local layer = app.layer
|
|
|
|
|
log("layer: " .. tostring(layer))
|
|
|
|
|
if not layer or not layer.isTilemap then
|
|
|
|
|
log("Layer is not a tilemap")
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local tileset = layer.tileset
|
|
|
|
|
log("tileset: " .. tostring(tileset))
|
|
|
|
|
if not tileset then
|
|
|
|
|
log("No tileset in layer")
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local tileIndex = app.fgTile
|
|
|
|
|
log("tileIndex: " .. tostring(tileIndex))
|
|
|
|
|
if not tileIndex or tileIndex < 0 then
|
|
|
|
|
log("Invalid tile index")
|
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
log("Selected tile: tileset=" .. tostring(tileset) .. ", index=" .. tostring(tileIndex))
|
|
|
|
|
return tileset, tileIndex
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function getTileProperties(tileset, tileIndex)
|
|
|
|
|
log("getTileProperties() called for tile index: " .. tostring(tileIndex))
|
|
|
|
|
|
|
|
|
|
local tile = tileset:tile(tileIndex)
|
|
|
|
|
if not tile then
|
|
|
|
|
log("Could not get tile object")
|
|
|
|
|
return {}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not tile.properties then
|
|
|
|
|
log("Tile has no properties")
|
|
|
|
|
return {}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local props = {}
|
|
|
|
|
for key, value in pairs(tile.properties) do
|
|
|
|
|
local propType = "string"
|
|
|
|
|
if type(value) == "boolean" then
|
|
|
|
|
propType = "boolean"
|
|
|
|
|
elseif type(value) == "number" then
|
|
|
|
|
propType = "number"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
table.insert(props, {
|
|
|
|
|
key = key,
|
|
|
|
|
type = propType,
|
|
|
|
|
value = value
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
log("Found " .. #props .. " properties")
|
|
|
|
|
return props
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function setTileProperties(tileset, tileIndex, props)
|
|
|
|
|
log("setTileProperties() called for tile index: " .. tostring(tileIndex))
|
|
|
|
|
|
|
|
|
|
local tile = tileset:tile(tileIndex)
|
|
|
|
|
if not tile then
|
|
|
|
|
log("Could not get tile object")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
tile.properties = {}
|
|
|
|
|
local count = 0
|
|
|
|
|
for _, prop in ipairs(props) do
|
|
|
|
|
if prop.key and prop.key ~= "" then
|
|
|
|
|
local value = prop.value
|
|
|
|
|
if prop.type == "boolean" then
|
|
|
|
|
value = (value == true or value == "true")
|
|
|
|
|
elseif prop.type == "number" then
|
|
|
|
|
value = tonumber(value) or 0
|
|
|
|
|
end
|
|
|
|
|
tile.properties[prop.key] = value
|
|
|
|
|
count = count + 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
log("Set " .. count .. " properties")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function showPropertyEditor(existingProps)
|
|
|
|
|
log("showPropertyEditor() called")
|
|
|
|
|
|
|
|
|
|
local tileset, tileIndex = getSelectedTile()
|
|
|
|
|
|
|
|
|
|
if not tileset then
|
|
|
|
|
log("No tileset selected, showing alert")
|
|
|
|
|
app.alert("Please select a tile in the tileset")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
log("Getting properties for tile")
|
|
|
|
|
local properties = existingProps or getTileProperties(tileset, tileIndex)
|
|
|
|
|
|
|
|
|
|
local dlg = Dialog("Tile Properties - Tile #" .. tileIndex)
|
|
|
|
|
|
|
|
|
|
dlg:label{ text="Properties:" }
|
|
|
|
|
|
|
|
|
|
for i, prop in ipairs(properties) do
|
|
|
|
|
dlg:separator()
|
|
|
|
|
dlg:entry{
|
|
|
|
|
id = "key_" .. i,
|
|
|
|
|
label = "Name:",
|
|
|
|
|
text = prop.key
|
|
|
|
|
}
|
|
|
|
|
dlg:combobox{
|
|
|
|
|
id = "type_" .. i,
|
|
|
|
|
label = "Type:",
|
|
|
|
|
option = prop.type,
|
|
|
|
|
options = { "boolean", "number", "string" },
|
|
|
|
|
onchange = function()
|
|
|
|
|
for j = 1, #properties do
|
|
|
|
|
properties[j].key = dlg.data["key_" .. j] or properties[j].key
|
|
|
|
|
local newType = dlg.data["type_" .. j] or properties[j].type
|
|
|
|
|
local oldType = properties[j].type
|
|
|
|
|
|
|
|
|
|
if newType ~= oldType then
|
|
|
|
|
if newType == "boolean" then
|
|
|
|
|
properties[j].value = false
|
|
|
|
|
elseif newType == "number" then
|
|
|
|
|
properties[j].value = 0
|
|
|
|
|
else -- string
|
|
|
|
|
properties[j].value = ""
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
properties[j].value = dlg.data["value_" .. j] or properties[j].value
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
properties[j].type = newType
|
|
|
|
|
end
|
|
|
|
|
dlg:close()
|
|
|
|
|
showPropertyEditor(properties)
|
|
|
|
|
end
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if prop.type == "boolean" then
|
|
|
|
|
dlg:check{
|
|
|
|
|
id = "value_" .. i,
|
|
|
|
|
text = "",
|
|
|
|
|
selected = prop.value
|
|
|
|
|
}
|
|
|
|
|
elseif prop.type == "number" then
|
|
|
|
|
dlg:number{
|
|
|
|
|
id = "value_" .. i,
|
|
|
|
|
label = "Value:",
|
|
|
|
|
text = tostring(prop.value),
|
|
|
|
|
decimals = 0
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
dlg:entry{
|
|
|
|
|
id = "value_" .. i,
|
|
|
|
|
label = "Value:",
|
|
|
|
|
text = tostring(prop.value)
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
dlg:button{
|
|
|
|
|
id = "delete_" .. i,
|
|
|
|
|
text = "Delete",
|
|
|
|
|
onclick = function()
|
|
|
|
|
for j = 1, #properties do
|
|
|
|
|
properties[j].key = dlg.data["key_" .. j] or properties[j].key
|
|
|
|
|
properties[j].type = dlg.data["type_" .. j] or properties[j].type
|
|
|
|
|
properties[j].value = dlg.data["value_" .. j] or properties[j].value
|
|
|
|
|
end
|
|
|
|
|
table.remove(properties, i)
|
|
|
|
|
dlg:close()
|
|
|
|
|
showPropertyEditor(properties)
|
|
|
|
|
end
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
dlg:separator()
|
|
|
|
|
dlg:button{
|
|
|
|
|
text = "Add Property",
|
|
|
|
|
onclick = function()
|
|
|
|
|
for i = 1, #properties do
|
|
|
|
|
properties[i].key = dlg.data["key_" .. i] or properties[i].key
|
|
|
|
|
properties[i].type = dlg.data["type_" .. i] or properties[i].type
|
|
|
|
|
properties[i].value = dlg.data["value_" .. i] or properties[i].value
|
|
|
|
|
end
|
|
|
|
|
table.insert(properties, {
|
|
|
|
|
key = "",
|
|
|
|
|
type = "string",
|
|
|
|
|
value = ""
|
|
|
|
|
})
|
|
|
|
|
dlg:close()
|
|
|
|
|
showPropertyEditor(properties)
|
|
|
|
|
end
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlg:separator()
|
|
|
|
|
dlg:button{
|
|
|
|
|
text = "Apply",
|
|
|
|
|
onclick = function()
|
|
|
|
|
local newProps = {}
|
|
|
|
|
for i = 1, #properties do
|
|
|
|
|
local key = dlg.data["key_" .. i]
|
|
|
|
|
local propType = dlg.data["type_" .. i]
|
|
|
|
|
local value = dlg.data["value_" .. i]
|
|
|
|
|
|
|
|
|
|
if key and key ~= "" then
|
|
|
|
|
table.insert(newProps, {
|
|
|
|
|
key = key,
|
|
|
|
|
type = propType,
|
|
|
|
|
value = value
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
setTileProperties(tileset, tileIndex, newProps)
|
|
|
|
|
dlg:close()
|
|
|
|
|
end
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlg:button{ text = "Cancel" }
|
|
|
|
|
|
|
|
|
|
dlg:show()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function init(plugin)
|
|
|
|
|
if not plugin then
|
|
|
|
|
print("[tile-properties] ERROR: plugin is nil!")
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
2025-11-11 23:26:51 -06:00
|
|
|
-- register in sprite menu
|
2025-11-01 12:39:59 -05:00
|
|
|
plugin:newCommand{
|
|
|
|
|
id = "TilePropertiesEditor",
|
|
|
|
|
title = "Tile Properties",
|
|
|
|
|
group = "sprite_properties",
|
|
|
|
|
onenabled = function()
|
|
|
|
|
local tileset, tileIndex = getSelectedTile()
|
|
|
|
|
return tileset ~= nil and tileIndex ~= nil
|
|
|
|
|
end,
|
|
|
|
|
onclick = showPropertyEditor
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function exit(plugin)
|
|
|
|
|
end
|