This commit is contained in:
asrael 2025-11-01 12:39:59 -05:00
parent e862b02019
commit 0ed7fc4496
No known key found for this signature in database
GPG key ID: 2786557804DFAE24
21 changed files with 1267 additions and 148 deletions

View file

@ -0,0 +1,283 @@
-- pxl8 tile properties editor
-- provides a ui for editing custom properties of tilemap tiles
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()
-- Save all current field values and apply type conversions
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
-- Apply default values when type changes
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()
-- Save current field values before deleting
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()
-- Save current field values before adding new property
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)
log("=== PLUGIN INIT START ===")
if not plugin then
print("[tile-properties] ERROR: plugin is nil!")
return
end
-- Register in Sprite menu
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
}
log("Command registered in Sprite menu")
log("=== PLUGIN INIT COMPLETE ===")
end
function exit(plugin)
log("=== PLUGIN EXIT ===")
end