mirror of
https://github.com/Insality/druid
synced 2025-06-27 10:27:48 +02:00
239 lines
6.5 KiB
Lua
239 lines
6.5 KiB
Lua
--- Module for assigning layers to GUI nodes based on textures and fonts
|
|
|
|
local defold_parser = require("druid.editor_scripts.defold_parser.defold_parser")
|
|
local system = require("druid.editor_scripts.defold_parser.system.system")
|
|
|
|
local M = {}
|
|
|
|
|
|
---Create a backup of a file
|
|
---@param file_path string - The path of the file to backup
|
|
---@return string|nil - The backup file path, or nil if backup failed
|
|
local function create_backup(file_path)
|
|
local backup_path = file_path .. ".backup"
|
|
print("Creating backup at:", backup_path)
|
|
|
|
-- Read and write using system module
|
|
local content, err_read = system.read_file(file_path)
|
|
if not content then
|
|
print("Error reading original file for backup:", err_read)
|
|
return nil
|
|
end
|
|
|
|
local success, err_write = system.write_file(backup_path, content)
|
|
if not success then
|
|
print("Error creating backup file:", err_write)
|
|
return nil
|
|
end
|
|
|
|
print("Backup created successfully")
|
|
return backup_path
|
|
end
|
|
|
|
|
|
---Restore from a backup file
|
|
---@param backup_path string - The path of the backup file
|
|
---@param original_path string - The path to restore to
|
|
---@return boolean - True if restore was successful
|
|
local function restore_from_backup(backup_path, original_path)
|
|
print("Restoring from backup:", backup_path)
|
|
|
|
-- Read backup file
|
|
local content, err = system.read_file(backup_path)
|
|
if not content then
|
|
print("Error reading backup file:", err)
|
|
return false
|
|
end
|
|
|
|
-- Write to original file
|
|
local success, err = system.write_file(original_path, content)
|
|
if not success then
|
|
print("Error restoring from backup:", err)
|
|
return false
|
|
end
|
|
|
|
print("Restored successfully from backup")
|
|
return true
|
|
end
|
|
|
|
|
|
---Remove a backup file
|
|
---@param backup_path string - The path of the backup file to remove
|
|
local function remove_backup(backup_path)
|
|
-- Check file exists and remove it
|
|
local file = io.open(backup_path, "r")
|
|
if file then
|
|
file:close()
|
|
os.remove(backup_path)
|
|
print("Backup file removed successfully")
|
|
end
|
|
end
|
|
|
|
---Assign layers to GUI nodes based on textures and fonts
|
|
---@param gui_resource string - The GUI resource to process
|
|
---@return table - Editor command to reload the resource
|
|
function M.assign_layers(gui_resource)
|
|
local gui_path = editor.get(gui_resource, "path")
|
|
print("Setting up layers for", gui_path)
|
|
|
|
-- Get the absolute path to the file
|
|
local absolute_project_path = editor.external_file_attributes(".").path
|
|
if not absolute_project_path:match("[\\/]$") then
|
|
absolute_project_path = absolute_project_path .. "/"
|
|
end
|
|
local clean_gui_path = gui_path
|
|
if clean_gui_path:sub(1, 1) == "/" then
|
|
clean_gui_path = clean_gui_path:sub(2)
|
|
end
|
|
local gui_absolute_path = absolute_project_path .. clean_gui_path
|
|
|
|
-- Create a backup before modifying the file
|
|
local backup_path = create_backup(gui_absolute_path)
|
|
if not backup_path then
|
|
print("Failed to create backup, aborting...")
|
|
return {}
|
|
end
|
|
|
|
-- Parse the GUI file using defold_parser
|
|
print("Parsing GUI file...")
|
|
local gui_data = defold_parser.load_from_file(gui_absolute_path)
|
|
if not gui_data then
|
|
print("Error: Failed to parse GUI file")
|
|
return {}
|
|
end
|
|
|
|
-- Collect all textures and fonts
|
|
print("Collecting all available textures and fonts...")
|
|
local all_textures = {}
|
|
local all_fonts = {}
|
|
|
|
-- Get textures
|
|
if gui_data.textures then
|
|
for _, texture in ipairs(gui_data.textures) do
|
|
print("Found texture:", texture.name)
|
|
all_textures[texture.name] = true
|
|
end
|
|
end
|
|
|
|
-- Get fonts
|
|
if gui_data.fonts then
|
|
for _, font in ipairs(gui_data.fonts) do
|
|
print("Found font:", font.name)
|
|
all_fonts[font.name] = true
|
|
end
|
|
end
|
|
|
|
-- Track which textures and fonts are actually used by nodes
|
|
print("Finding used textures and fonts...")
|
|
local used_layers = {}
|
|
|
|
-- First pass: find all used textures and fonts
|
|
if gui_data.nodes then
|
|
for _, node in ipairs(gui_data.nodes) do
|
|
if node.texture then
|
|
local layer_name = node.texture:match("([^/]+)")
|
|
if layer_name and all_textures[layer_name] then
|
|
used_layers[layer_name] = true
|
|
print("Node", node.id, "uses texture:", layer_name)
|
|
end
|
|
elseif node.font then
|
|
local layer_name = node.font
|
|
if all_fonts[layer_name] then
|
|
used_layers[layer_name] = true
|
|
print("Node", node.id, "uses font:", layer_name)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Create a set of existing layer names for faster lookup
|
|
print("Checking existing layers...")
|
|
local existing_layers = {}
|
|
if gui_data.layers then
|
|
for _, layer in ipairs(gui_data.layers) do
|
|
if layer.name then
|
|
existing_layers[layer.name] = true
|
|
print("Found existing layer:", layer.name)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Convert set to array of used layers
|
|
local layers = {}
|
|
for layer_name in pairs(used_layers) do
|
|
if not existing_layers[layer_name] then
|
|
table.insert(layers, layer_name)
|
|
print("Adding new layer:", layer_name)
|
|
else
|
|
print("Layer already exists:", layer_name)
|
|
end
|
|
end
|
|
|
|
-- Sort new layers for consistent output
|
|
table.sort(layers)
|
|
|
|
print("Found", #layers, "new layers to add")
|
|
|
|
-- Add new layers (preserving existing ones)
|
|
print("Adding new layers...")
|
|
gui_data.layers = gui_data.layers or {}
|
|
for _, layer_name in ipairs(layers) do
|
|
table.insert(gui_data.layers, {
|
|
name = layer_name,
|
|
})
|
|
end
|
|
|
|
-- Create a lookup table for faster matching - include both existing and new layers
|
|
local layer_lookup = {}
|
|
for layer_name in pairs(existing_layers) do
|
|
layer_lookup[layer_name] = true
|
|
end
|
|
for _, layer_name in ipairs(layers) do
|
|
layer_lookup[layer_name] = true
|
|
end
|
|
|
|
-- Update nodes to use the correct layer
|
|
print("Updating node layers...")
|
|
if gui_data.nodes then
|
|
for _, node in ipairs(gui_data.nodes) do
|
|
if node.texture then
|
|
local layer_name = node.texture:match("([^/]+)")
|
|
if layer_name and layer_lookup[layer_name] then
|
|
print("Assigning node", node.id, "to layer:", layer_name)
|
|
node.layer = layer_name
|
|
end
|
|
elseif node.font then
|
|
local layer_name = node.font
|
|
if layer_lookup[layer_name] then
|
|
print("Assigning node", node.id, "to layer:", layer_name)
|
|
node.layer = layer_name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Write the updated GUI file
|
|
print("Writing updated GUI file...")
|
|
local success = defold_parser.save_to_file(gui_absolute_path, gui_data)
|
|
|
|
if not success then
|
|
print("Error: Failed to save GUI file")
|
|
print("Attempting to restore from backup...")
|
|
local restored = restore_from_backup(backup_path, gui_absolute_path)
|
|
if not restored then
|
|
print("Critical: Failed to restore from backup. Manual intervention may be required.")
|
|
end
|
|
return {}
|
|
end
|
|
|
|
-- Everything worked, remove the backup
|
|
remove_backup(backup_path)
|
|
|
|
print("Successfully assigned layers for GUI:", gui_path)
|
|
|
|
return {}
|
|
end
|
|
|
|
|
|
return M
|