mirror of
https://github.com/Insality/druid.git
synced 2025-09-27 18:12:19 +02:00
Update editor scripts
This commit is contained in:
239
druid/editor_scripts/assign_layers.lua
Normal file
239
druid/editor_scripts/assign_layers.lua
Normal file
@@ -0,0 +1,239 @@
|
||||
--- 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)
|
||||
print("Removing backup file:", backup_path)
|
||||
local success, err = os.remove(backup_path)
|
||||
if not success then
|
||||
print("Warning: Could not remove backup file:", err)
|
||||
print("You may want to manually remove it:", backup_path)
|
||||
else
|
||||
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
|
@@ -1,132 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import deftree
|
||||
|
||||
current_filepath = os.path.abspath(os.path.dirname(__file__))
|
||||
TEMPLATE_PATH = current_filepath + "/widget.lua_template"
|
||||
|
||||
component_annotations = ""
|
||||
component_functions = ""
|
||||
component_define = ""
|
||||
|
||||
def to_camel_case(snake_str):
|
||||
components = snake_str.split('_')
|
||||
return ''.join(x.title() for x in components[0:])
|
||||
|
||||
|
||||
def get_id(node_name):
|
||||
return node_name.upper().replace("/", "_")
|
||||
|
||||
|
||||
def process_component(node_name, component_name):
|
||||
global component_annotations
|
||||
global component_functions
|
||||
global component_define
|
||||
|
||||
if node_name == "root":
|
||||
component_annotations += "\n---@field root node"
|
||||
component_define += "\n\tself.root = self:get_node(\"root\")"
|
||||
|
||||
if node_name.startswith("button"):
|
||||
component_annotations += "\n---@field {0} druid.button".format(node_name)
|
||||
component_functions += "\nfunction M:_on_{0}()\n\tprint(\"Click on {0}\")\nend\n\n".format(node_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_button(\"{1}\", self._on_{0})".format(node_name, node_name)
|
||||
|
||||
if node_name.startswith("text"):
|
||||
component_annotations += "\n---@field {0} druid.text".format(node_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_text(\"{1}\")".format(node_name, node_name)
|
||||
|
||||
if node_name.startswith("lang_text"):
|
||||
component_annotations += "\n---@field {0} druid.text".format(node_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_lang_text(\"{1}\", \"lang_id\")".format(node_name, node_name)
|
||||
|
||||
if node_name.startswith("grid") or node_name.startswith("static_grid"):
|
||||
component_annotations += "\n---@field {0} druid.grid".format(node_name)
|
||||
component_define += "\n--TODO: Replace prefab_name with grid element prefab"
|
||||
component_define += "\n\tself.{0} = self.druid:new_grid(\"{1}\", \"prefab_name\", 1)".format(node_name, node_name)
|
||||
|
||||
if node_name.startswith("scroll_view"):
|
||||
field_name = node_name.replace("_view", "")
|
||||
content_name = node_name.replace("_view", "_content")
|
||||
component_annotations += "\n---@field {0} druid.scroll".format(field_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_scroll(\"{1}\", \"{2}\")".format(field_name, node_name, content_name)
|
||||
|
||||
if node_name.startswith("blocker"):
|
||||
component_annotations += "\n---@field {0} druid.blocker".format(node_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_blocker(\"{1}\")".format(node_name, node_name)
|
||||
|
||||
if node_name.startswith("slider"):
|
||||
component_annotations += "\n---@field {0} druid.slider".format(node_name)
|
||||
component_define += "\n--TODO: Replace slider end position. It should be only vertical or horizontal"
|
||||
component_define += "\n\tself.{0} = self.druid:new_slider(\"{1}\", vmath.vector3(100, 0, 0), self._on_{0}_change)".format(node_name, node_name)
|
||||
component_functions += "\nfunction M:_on_{0}_change(value)\n\tprint(\"Slider change:\", value)\nend\n\n".format(node_name)
|
||||
|
||||
if node_name.startswith("progress"):
|
||||
component_annotations += "\n---@field {0} druid.progress".format(node_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_progress(\"{1}\", \"x\")".format(node_name, get_id(node_name))
|
||||
|
||||
if node_name.startswith("timer"):
|
||||
component_annotations += "\n---@field {0} druid.timer".format(node_name)
|
||||
component_define += "\n\tself.{0} = self.druid:new_timer(\"{1}\", 59, 0, self._on_{0}_end)".format(node_name, get_id(node_name))
|
||||
component_functions += "\nfunction M:_on_{0}_end()\n\tprint(\"Timer {0} trigger\")\nend\n\n".format(node_name)
|
||||
|
||||
|
||||
def main():
|
||||
global component_annotations
|
||||
global component_functions
|
||||
global component_define
|
||||
|
||||
filename = sys.argv[1]
|
||||
print("Create Druid component from gui file", filename)
|
||||
tree = deftree.parse(filename)
|
||||
root = tree.get_root()
|
||||
|
||||
output_directory = os.path.dirname(filename)
|
||||
output_filename = os.path.splitext(os.path.basename(filename))[0]
|
||||
|
||||
output_full_path = os.path.join(output_directory, output_filename + ".lua")
|
||||
is_already_exists = os.path.exists(output_full_path)
|
||||
if is_already_exists:
|
||||
print("Error: The file is already exists")
|
||||
print("File:", output_full_path)
|
||||
return
|
||||
|
||||
component_require_path = os.path.join(output_directory, output_filename).replace("/", ".").replace("..", "")
|
||||
component_name = to_camel_case(output_filename)
|
||||
component_type = output_filename
|
||||
scheme_list = []
|
||||
|
||||
# Gather nodes from GUI scene
|
||||
for node in root.iter_elements("nodes"):
|
||||
node_name = node.get_attribute("id").value
|
||||
scheme_list.append("\t" + get_id(node_name) + " = \"" + node_name + "\"")
|
||||
|
||||
is_template = node.get_attribute("template")
|
||||
is_in_template = "/" in node_name
|
||||
if not is_template and not is_in_template:
|
||||
process_component(node_name, component_name)
|
||||
|
||||
if len(component_define) > 2:
|
||||
component_define = "\n" + component_define
|
||||
|
||||
template_file = open(TEMPLATE_PATH, "r")
|
||||
filedata = template_file.read()
|
||||
template_file.close()
|
||||
|
||||
filedata = filedata.replace("{COMPONENT_NAME}", component_name)
|
||||
filedata = filedata.replace("{COMPONENT_TYPE}", component_type)
|
||||
filedata = filedata.replace("{COMPONENT_PATH}", component_require_path)
|
||||
filedata = filedata.replace("{COMPONENT_DEFINE}", component_define)
|
||||
filedata = filedata.replace("{COMPONENT_FUNCTIONS}", component_functions)
|
||||
filedata = filedata.replace("{COMPONENT_ANNOTATIONS}", component_annotations)
|
||||
#filedata = filedata.replace("{SCHEME_LIST}", ",\n".join(scheme_list))
|
||||
|
||||
output_file = open(output_full_path, "w")
|
||||
output_file.write(filedata)
|
||||
output_file.close()
|
||||
|
||||
print("Success: The file is created")
|
||||
print("File:", output_full_path)
|
||||
|
||||
|
||||
main()
|
61
druid/editor_scripts/create_druid_widget.lua
Normal file
61
druid/editor_scripts/create_druid_widget.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
local M = {}
|
||||
|
||||
local function to_camel_case(snake_str)
|
||||
local components = {}
|
||||
for component in snake_str:gmatch("[^_]+") do
|
||||
table.insert(components, component:sub(1, 1):upper() .. component:sub(2))
|
||||
end
|
||||
return table.concat(components, "")
|
||||
end
|
||||
|
||||
|
||||
function M.create_druid_widget(opts)
|
||||
local gui_filepath = editor.get(opts.selection, "path")
|
||||
local filename = gui_filepath:match("([^/]+)%.gui$")
|
||||
print("Create Druid widget for", gui_filepath)
|
||||
|
||||
local absolute_project_path = editor.external_file_attributes(".").path
|
||||
local widget_resource_path = gui_filepath:gsub("%.gui$", ".lua")
|
||||
local new_widget_absolute_path = absolute_project_path .. widget_resource_path
|
||||
|
||||
local widget_name = to_camel_case(filename)
|
||||
local widget_type = filename
|
||||
|
||||
-- Check if file already exists
|
||||
local f = io.open(new_widget_absolute_path, "r")
|
||||
if f then
|
||||
f:close()
|
||||
print("Widget file already exists at " .. new_widget_absolute_path)
|
||||
print("Creation aborted to prevent overwriting")
|
||||
return
|
||||
end
|
||||
|
||||
-- Get template path from preferences
|
||||
local template_path = editor.prefs.get("druid.widget_template_path")
|
||||
|
||||
-- Get template content using the path from preferences
|
||||
local template_content = editor.get(template_path, "text")
|
||||
if not template_content then
|
||||
print("Error: Could not load template from", template_path)
|
||||
print("Check the template path in [Druid] Settings")
|
||||
return
|
||||
end
|
||||
|
||||
-- Replace template variables
|
||||
template_content = template_content:gsub("{COMPONENT_NAME}", widget_name)
|
||||
template_content = template_content:gsub("{COMPONENT_TYPE}", widget_type)
|
||||
|
||||
-- Write file
|
||||
local file, err = io.open(new_widget_absolute_path, "w")
|
||||
if not file then
|
||||
print("Error creating widget file:", err)
|
||||
return
|
||||
end
|
||||
file:write(template_content)
|
||||
file:close()
|
||||
|
||||
print("Widget created at " .. widget_resource_path)
|
||||
end
|
||||
|
||||
|
||||
return M
|
153
druid/editor_scripts/defold_parser/defold_parser.lua
Normal file
153
druid/editor_scripts/defold_parser/defold_parser.lua
Normal file
@@ -0,0 +1,153 @@
|
||||
--- Defold Text Proto format encoder/decoder to lua table
|
||||
|
||||
local config = require("druid.editor_scripts.defold_parser.system.config")
|
||||
local system = require("druid.editor_scripts.defold_parser.system.system")
|
||||
|
||||
local M = {}
|
||||
|
||||
|
||||
--- Decode a Defold object from a string
|
||||
---@param text string
|
||||
---@return table
|
||||
function M.decode_defold_object(text)
|
||||
-- Create a root object, which will contain all the file data
|
||||
local root = {}
|
||||
-- Stack to keep track of nested objects. Always insert data to the last object in the stack
|
||||
local stack = { root }
|
||||
|
||||
-- For each line in the text, we go through the following steps:
|
||||
for raw_line in text:gmatch("[^\r\n]+") do
|
||||
system.parse_line(raw_line, stack)
|
||||
end
|
||||
|
||||
return root
|
||||
end
|
||||
|
||||
|
||||
-- Encoding Functions
|
||||
function M.encode_defold_object(obj, spaces, data_level, extension)
|
||||
spaces = spaces or 0
|
||||
data_level = data_level or 0
|
||||
local key_order = extension and config.KEY_ORDER[extension] or {}
|
||||
|
||||
local result = ''
|
||||
local tabString = string.rep(' ', spaces)
|
||||
|
||||
local keys = {}
|
||||
for key in pairs(obj) do
|
||||
table.insert(keys, key)
|
||||
end
|
||||
|
||||
table.sort(keys, function(a, b)
|
||||
local index_a = system.contains(key_order, a) or 0
|
||||
local index_b = system.contains(key_order, b) or 0
|
||||
return index_a < index_b
|
||||
end)
|
||||
|
||||
-- Iterate over the sorted keys
|
||||
for _, key in ipairs(keys) do
|
||||
local value = obj[key]
|
||||
local value_type = type(value)
|
||||
|
||||
-- Handle different types of values
|
||||
if value_type == "table" then
|
||||
-- Check if it's an array-like table
|
||||
if #value > 0 then
|
||||
-- It's an array-like table, process each element
|
||||
for _, array_item in ipairs(value) do
|
||||
local item_type = type(array_item)
|
||||
|
||||
if key == "data" and item_type == "table" then
|
||||
-- Handle nested data
|
||||
local encodedChild = M.encode_defold_object(array_item, spaces + 2, data_level + 1, extension)
|
||||
result = result .. tabString .. key .. ': "' .. encodedChild .. '"\n'
|
||||
elseif item_type == "number" or item_type == "boolean" then
|
||||
local is_contains_dot = string.find(key, "%.")
|
||||
if item_type == "number" and (system.contains(config.with_dot_params, key) and not is_contains_dot) then
|
||||
result = result .. tabString .. key .. ': ' .. string.format("%.1f", array_item) .. '\n'
|
||||
else
|
||||
result = result .. tabString .. key .. ': ' .. tostring(array_item) .. '\n'
|
||||
end
|
||||
elseif item_type == "string" then
|
||||
-- Handle multiline text
|
||||
if key == "text" then
|
||||
result = result .. tabString .. key .. ': "' .. array_item:gsub("\n", '\\n"\n' .. tabString .. '"') .. '"\n'
|
||||
else
|
||||
-- Check if the key should not have quotes
|
||||
local is_uppercase = (array_item == string.upper(array_item))
|
||||
local is_boolean = (array_item == "true" or array_item == "false")
|
||||
if (is_uppercase and not config.string_keys[key]) or is_boolean then
|
||||
result = result .. tabString .. key .. ': ' .. array_item .. '\n'
|
||||
else
|
||||
result = result .. tabString .. key .. ': "' .. array_item .. '"\n'
|
||||
end
|
||||
end
|
||||
elseif item_type == "table" then
|
||||
result = result .. tabString .. key .. ' {\n' .. M.encode_defold_object(array_item, spaces + 2, data_level, extension) .. tabString .. '}\n'
|
||||
end
|
||||
end
|
||||
else
|
||||
-- It's a dictionary-like table
|
||||
result = result .. tabString .. key .. ' {\n' .. M.encode_defold_object(value, spaces + 2, data_level, extension) .. tabString .. '}\n'
|
||||
end
|
||||
else
|
||||
-- Handle scalar values (string, number, boolean)
|
||||
if value_type == "number" or value_type == "boolean" then
|
||||
local is_contains_dot = string.find(key, "%.")
|
||||
if value_type == "number" and (system.contains(config.with_dot_params, key) and not is_contains_dot) then
|
||||
result = result .. tabString .. key .. ': ' .. string.format("%.1f", value) .. '\n'
|
||||
else
|
||||
result = result .. tabString .. key .. ': ' .. tostring(value) .. '\n'
|
||||
end
|
||||
elseif value_type == "string" then
|
||||
-- Handle multiline text
|
||||
if key == "text" then
|
||||
result = result .. tabString .. key .. ': "' .. value:gsub("\n", '\\n"\n' .. tabString .. '"') .. '"\n'
|
||||
else
|
||||
-- Check if the key should not have quotes
|
||||
local is_uppercase = (value == string.upper(value))
|
||||
local is_boolean = (value == "true" or value == "false")
|
||||
if (is_uppercase and not config.string_keys[key]) or is_boolean then
|
||||
result = result .. tabString .. key .. ': ' .. value .. '\n'
|
||||
else
|
||||
result = result .. tabString .. key .. ': "' .. value .. '"\n'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
---Load lua table from file in Defold Text Proto format
|
||||
---@param file_path string
|
||||
---@return table|nil, string|nil
|
||||
function M.load_from_file(file_path)
|
||||
local content, reason = system.read_file(file_path)
|
||||
if not content then
|
||||
return nil, reason
|
||||
end
|
||||
|
||||
return M.decode_defold_object(content), nil
|
||||
end
|
||||
|
||||
|
||||
---Write lua table to file in Defold Text Proto format
|
||||
---The path file extension will be used to determine the Defold format (*.atlas, *.gui, *.font, etc)
|
||||
---@param file_path string
|
||||
---@param lua_table table
|
||||
---@return boolean, string|nil
|
||||
function M.save_to_file(file_path, lua_table)
|
||||
-- Get extension without the dot
|
||||
local defold_format_name = file_path:match("^.+%.(.+)$")
|
||||
print("File extension:", defold_format_name)
|
||||
|
||||
local encoded_object = M.encode_defold_object(lua_table, nil, nil, defold_format_name)
|
||||
|
||||
return system.write_file(file_path, encoded_object)
|
||||
end
|
||||
|
||||
|
||||
return M
|
179
druid/editor_scripts/defold_parser/system/config.lua
Normal file
179
druid/editor_scripts/defold_parser/system/config.lua
Normal file
@@ -0,0 +1,179 @@
|
||||
local M = {}
|
||||
|
||||
-- Define a set of keys that should not have quotes
|
||||
M.string_keys = {
|
||||
text = true,
|
||||
id = true,
|
||||
value = true,
|
||||
rename_patterns = true,
|
||||
}
|
||||
|
||||
|
||||
M.ALWAYS_LIST = {
|
||||
attributes = true,
|
||||
nodes = true,
|
||||
images = true,
|
||||
children = true,
|
||||
fonts = true,
|
||||
layers = true,
|
||||
textures = true,
|
||||
embedded_components = true,
|
||||
embedded_instances = true,
|
||||
collection_instances = true,
|
||||
instances = true,
|
||||
}
|
||||
|
||||
|
||||
M.with_dot_params = {
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"w",
|
||||
"alpha",
|
||||
"outline_alpha",
|
||||
"shadow_alpha",
|
||||
"text_leading",
|
||||
"text_tracking",
|
||||
"pieFillAngle",
|
||||
"innerRadius",
|
||||
"leading",
|
||||
"tracking",
|
||||
"data",
|
||||
"t_x",
|
||||
"t_y",
|
||||
"spread",
|
||||
"start_delay",
|
||||
"inherit_velocity",
|
||||
"start_delay_spread",
|
||||
"duration_spread",
|
||||
"start_offset",
|
||||
"outline_width",
|
||||
"shadow_x",
|
||||
"shadow_y",
|
||||
"aspect_ratio",
|
||||
"far_z",
|
||||
"mass",
|
||||
"linear_damping",
|
||||
"angular_damping",
|
||||
"gain",
|
||||
"pan",
|
||||
"speed",
|
||||
"duration"
|
||||
}
|
||||
|
||||
M.KEY_ORDER = {
|
||||
["font"] = {
|
||||
"extrude_borders",
|
||||
"images",
|
||||
"inner_padding",
|
||||
"margin",
|
||||
"font",
|
||||
"material",
|
||||
"size",
|
||||
"antialias",
|
||||
"alpha",
|
||||
"outline_alpha",
|
||||
"outline_width",
|
||||
"shadow_alpha",
|
||||
"shadow_blur",
|
||||
"shadow_x",
|
||||
"shadow_y",
|
||||
"extra_characters",
|
||||
"output_format",
|
||||
"all_chars",
|
||||
"cache_width",
|
||||
"cache_height",
|
||||
"render_mode",
|
||||
},
|
||||
["atlas"] = {
|
||||
"id",
|
||||
"images",
|
||||
"playback",
|
||||
"fps",
|
||||
"flip_horizontal",
|
||||
"flip_vertical",
|
||||
"image",
|
||||
"sprite_trim_mode",
|
||||
"images",
|
||||
"animations",
|
||||
"margin",
|
||||
"extrude_borders",
|
||||
"inner_padding",
|
||||
"max_page_width",
|
||||
"max_page_height",
|
||||
"rename_patterns",
|
||||
},
|
||||
["gui"] = {
|
||||
"position",
|
||||
"rotation",
|
||||
"scale",
|
||||
"size",
|
||||
"color",
|
||||
"type",
|
||||
"blend_mode",
|
||||
"text",
|
||||
"texture",
|
||||
"font",
|
||||
"id",
|
||||
"xanchor",
|
||||
"yanchor",
|
||||
"pivot",
|
||||
"outline",
|
||||
"shadow",
|
||||
"adjust_mode",
|
||||
"line_break",
|
||||
"parent",
|
||||
"layer",
|
||||
"inherit_alpha",
|
||||
"slice9",
|
||||
"outerBounds",
|
||||
"innerRadius",
|
||||
"perimeterVertices",
|
||||
"pieFillAngle",
|
||||
"clipping_mode",
|
||||
"clipping_visible",
|
||||
"clipping_inverted",
|
||||
"alpha",
|
||||
"outline_alpha",
|
||||
"shadow_alpha",
|
||||
"overridden_fields",
|
||||
"template",
|
||||
"template_node_child",
|
||||
"text_leading",
|
||||
"text_tracking",
|
||||
"size_mode",
|
||||
"spine_scene",
|
||||
"spine_default_animation",
|
||||
"spine_skin",
|
||||
"spine_node_child",
|
||||
"particlefx",
|
||||
"custom_type",
|
||||
"enabled",
|
||||
"visible",
|
||||
|
||||
-- Scene
|
||||
"scripts",
|
||||
"fonts",
|
||||
"textures",
|
||||
"background_color",
|
||||
"nodes",
|
||||
"layers",
|
||||
"material",
|
||||
"layouts",
|
||||
"adjust_reference",
|
||||
"max_nodes",
|
||||
"spine_scenes",
|
||||
"particlefxs",
|
||||
"resources",
|
||||
"materials",
|
||||
"max_dynamic_textures",
|
||||
|
||||
-- Vectors
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"w",
|
||||
},
|
||||
}
|
||||
|
||||
return M
|
139
druid/editor_scripts/defold_parser/system/parser.lua
Normal file
139
druid/editor_scripts/defold_parser/system/parser.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
local config = require("druid.editor_scripts.defold_parser.system.config")
|
||||
|
||||
local M = {}
|
||||
|
||||
-- Example: "name: value"
|
||||
M.REGEX_KEY_COLUM_VALUE = "^%s*([%w_]+):%s*(.+)$"
|
||||
-- Example: "name {"
|
||||
M.REGEX_START_TABLE = "^%s*([%w_]*)%s*{%s*$"
|
||||
-- Example: "}"
|
||||
M.REGEX_END_TABLE = "^%s*}%s*$"
|
||||
|
||||
|
||||
---@param value string
|
||||
---@return string
|
||||
function M.unescape_text_field(value)
|
||||
-- Splitting the value by new lines and processing each line
|
||||
local lines = {}
|
||||
for line in value:gmatch("[^\r\n]+") do
|
||||
line = line:gsub('\\"', '"') -- Unescaping quotes
|
||||
line = line:gsub("\\n", "") -- Removing newline escapes
|
||||
line = line:gsub("\\", "") -- Unescaping backslashes
|
||||
table.insert(lines, line)
|
||||
end
|
||||
|
||||
-- Reconstructing the value
|
||||
value = table.concat(lines, "\n")
|
||||
return value
|
||||
end
|
||||
|
||||
|
||||
function M.is_multiline_value(value)
|
||||
return value:find("\\n\"") ~= nil
|
||||
end
|
||||
|
||||
|
||||
---@param value any
|
||||
---@param property_name string|nil
|
||||
---@return any
|
||||
function M.decode_value(value, property_name)
|
||||
if value:match('^".*"$') then
|
||||
-- Removing the quotes from the string
|
||||
value = value:sub(2, -2)
|
||||
|
||||
-- Check if value is escaped
|
||||
-- If ends with \n
|
||||
if value:sub(-2) == "\\n" then
|
||||
value = value:gsub('\\"', '"') -- Unescaping quotes
|
||||
value = value:gsub("\\n", "")
|
||||
value = value:gsub("\\", "")
|
||||
end
|
||||
|
||||
elseif value:match('^%-?[0-9.E%-]+$') then
|
||||
-- Converting to number
|
||||
value = tonumber(value)
|
||||
end
|
||||
|
||||
-- Specific handling for the "text" property
|
||||
if property_name == "text" then
|
||||
value = tostring(value)
|
||||
else
|
||||
if value == "true" then
|
||||
value = true
|
||||
elseif value == "false" then
|
||||
value = false
|
||||
end
|
||||
end
|
||||
|
||||
if property_name == "text" and M.is_multiline_value(value) and type(value) == "string" then
|
||||
value = M.unescape_text_field(value)
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
|
||||
---@param parent_object table
|
||||
---@param name string
|
||||
---@param stack table
|
||||
function M.new_inner_struct(parent_object, name, stack)
|
||||
local new_object = {}
|
||||
M.apply_value(parent_object, name, new_object)
|
||||
|
||||
local is_object_always_list = config.ALWAYS_LIST[name]
|
||||
if is_object_always_list and not M.is_array(parent_object[name]) then
|
||||
parent_object[name] = { parent_object[name] }
|
||||
end
|
||||
|
||||
table.insert(stack, new_object)
|
||||
end
|
||||
|
||||
|
||||
---Apply value to the object, if the value is already present, convert it to an array
|
||||
---@param object table
|
||||
---@param name string
|
||||
---@param value any
|
||||
---@return table object
|
||||
function M.apply_value(object, name, value)
|
||||
local is_object_always_list = config.ALWAYS_LIST[name]
|
||||
if object[name] == nil then
|
||||
object[name] = value
|
||||
if is_object_always_list then
|
||||
object[name] = { object[name] }
|
||||
end
|
||||
return object
|
||||
end
|
||||
|
||||
-- Convert to array if not already
|
||||
if not M.is_array(object[name]) then
|
||||
object[name] = { object[name] }
|
||||
end
|
||||
|
||||
table.insert(object[name], value)
|
||||
return object
|
||||
end
|
||||
|
||||
|
||||
---@param object table
|
||||
---@param value string
|
||||
---@return table @object
|
||||
function M.apply_multiline_value(object, name, value)
|
||||
if object[name] == nil then
|
||||
object[name] = value
|
||||
else
|
||||
object[name] = object[name] .. "\n" .. value
|
||||
end
|
||||
|
||||
return object
|
||||
end
|
||||
|
||||
|
||||
--- Check if table is array
|
||||
---@param t table
|
||||
---@return boolean
|
||||
function M.is_array(t)
|
||||
return type(t) == "table" and t[1] ~= nil
|
||||
end
|
||||
|
||||
|
||||
return M
|
163
druid/editor_scripts/defold_parser/system/system.lua
Normal file
163
druid/editor_scripts/defold_parser/system/system.lua
Normal file
@@ -0,0 +1,163 @@
|
||||
local parser = require("druid.editor_scripts.defold_parser.system.parser")
|
||||
|
||||
local M = {}
|
||||
|
||||
|
||||
--- Check if table-array contains element
|
||||
---@param table table
|
||||
---@param element any
|
||||
---@return number|boolean index of element or false
|
||||
function M.contains(table, element)
|
||||
for index, value in pairs(table) do
|
||||
if value == element then
|
||||
return index
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
---@param file_path string
|
||||
---@return string|nil, string|nil @success, reason
|
||||
function M.read_file(file_path)
|
||||
local file = io.open(file_path, "r")
|
||||
if file == nil then
|
||||
return nil, "Could not open file: " .. file_path
|
||||
end
|
||||
|
||||
local content = file:read("*a")
|
||||
file:close()
|
||||
|
||||
return content, nil
|
||||
end
|
||||
|
||||
|
||||
---@param file_path string
|
||||
---@param content string
|
||||
---@return boolean, string|nil @success, reason
|
||||
function M.write_file(file_path, content)
|
||||
local file = io.open(file_path, "w")
|
||||
if file == nil then
|
||||
return false, "Could not open file: " .. file_path
|
||||
end
|
||||
|
||||
file:write(content)
|
||||
file:close()
|
||||
|
||||
return true, nil
|
||||
end
|
||||
|
||||
|
||||
---@param line string
|
||||
function M.unescape_line(line)
|
||||
-- Trim whitespaces
|
||||
line = line:match("^%s*(.-)%s*$")
|
||||
|
||||
-- Remove first and last quote symbols only if exists
|
||||
if line:sub(1, 1) == '"' and line:sub(-1) == '"' then
|
||||
line = line:sub(2, -2)
|
||||
end
|
||||
|
||||
-- Trim whitespaces
|
||||
line = line:match("^%s*(.-)%s*$")
|
||||
|
||||
-- Splitting the value by new lines and processing each line
|
||||
line = line:gsub('\\"', '"') -- Unescaping quotes
|
||||
line = line:gsub("\\n", "") -- Removing newline escapes
|
||||
line = line:gsub("\\", "") -- Unescaping backslashes
|
||||
|
||||
return line
|
||||
end
|
||||
|
||||
|
||||
---@param line string
|
||||
---@return string, string, string, boolean @new_object_name, name, value, end_struct_flag
|
||||
function M.split_line(line)
|
||||
local new_object_name = line:match(parser.REGEX_START_TABLE)
|
||||
local name, value = line:match(parser.REGEX_KEY_COLUM_VALUE)
|
||||
local end_struct_flag = line:match(parser.REGEX_END_TABLE)
|
||||
|
||||
-- We hit a line what is contains only value, like multiline strings
|
||||
if not name and not value then
|
||||
value = line
|
||||
end
|
||||
|
||||
return new_object_name, name, value, end_struct_flag
|
||||
end
|
||||
|
||||
|
||||
-- what a crap...
|
||||
local LAST_USED_NAME = nil
|
||||
|
||||
---@param unescaped_line string @line to parse
|
||||
---@param stack table @stack of objects
|
||||
---@return boolean
|
||||
function M.parse_line(unescaped_line, stack)
|
||||
unescaped_line = unescaped_line:match("^%s*(.-)%s*$")
|
||||
|
||||
-- Use last object to insert data
|
||||
local object = stack[#stack]
|
||||
local line = M.unescape_line(unescaped_line)
|
||||
local inner_object_name, name, value, end_struct_flag = M.split_line(line)
|
||||
|
||||
local is_just_new_line = (unescaped_line == "\"\\n\"")
|
||||
if not end_struct_flag and (line == "\"" or line == "") and (not is_just_new_line) then
|
||||
if LAST_USED_NAME ~= "text" then
|
||||
end_struct_flag = true
|
||||
end
|
||||
end
|
||||
|
||||
if inner_object_name then
|
||||
parser.new_inner_struct(object, inner_object_name, stack)
|
||||
object = stack[#stack]
|
||||
end
|
||||
|
||||
if name and value ~= nil then
|
||||
-- If value is nested object...
|
||||
if value:sub(1, 1) == '"' then
|
||||
value = value:sub(2, -1)
|
||||
end
|
||||
if value:sub(-1) == '"' then
|
||||
value = value:sub(1, -2)
|
||||
end
|
||||
|
||||
local unescape_line = M.unescape_line(value)
|
||||
local new_object_name, field_name, _, end_flag = M.split_line(unescape_line)
|
||||
|
||||
if (new_object_name or field_name or end_flag) and name ~= "text" then
|
||||
parser.new_inner_struct(object, name, stack)
|
||||
object = stack[#stack]
|
||||
|
||||
M.parse_line(value, stack)
|
||||
else
|
||||
-- Just a hack honestly
|
||||
-- If first character is a quote, then remove it
|
||||
if value:sub(1, 1) == '"' then
|
||||
value = value:sub(2, -1)
|
||||
end
|
||||
if value:sub(-1) == '"' then
|
||||
value = value:sub(1, -2)
|
||||
end
|
||||
|
||||
value = parser.decode_value(value, name)
|
||||
LAST_USED_NAME = name
|
||||
parser.apply_value(object, name, value)
|
||||
end
|
||||
end
|
||||
|
||||
if not name and value and not inner_object_name and not end_struct_flag then
|
||||
-- We should to add value to the last as a multiline data
|
||||
parser.apply_multiline_value(object, LAST_USED_NAME, value)
|
||||
end
|
||||
|
||||
if end_struct_flag then
|
||||
-- Go back to the parent object
|
||||
table.remove(stack)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,25 +1,24 @@
|
||||
local assign_layers = require("druid.editor_scripts.assign_layers")
|
||||
local create_druid_widget = require("druid.editor_scripts.create_druid_widget")
|
||||
local druid_settings = require("druid.editor_scripts.druid_settings")
|
||||
|
||||
local M = {}
|
||||
|
||||
local DEFAULT_WIDGET_TEMPLATE_PATH = "/druid/templates/widget_full.lua.template"
|
||||
|
||||
local function ends_with(str, ending)
|
||||
return ending == "" or str:sub(-#ending) == ending
|
||||
end
|
||||
|
||||
|
||||
local function save_file_from_dependency(dependency_file_path, output_file_path)
|
||||
local content = editor.get(dependency_file_path, "text")
|
||||
local file, err = io.open(output_file_path, "w")
|
||||
if not file then
|
||||
print("Error:", err)
|
||||
return false
|
||||
end
|
||||
file:write(content)
|
||||
file:close()
|
||||
print("Write file at", output_file_path)
|
||||
return true
|
||||
|
||||
---Define preferences schema
|
||||
function M.get_prefs_schema()
|
||||
return {
|
||||
["druid.widget_template_path"] = editor.prefs.schema.string({
|
||||
default = DEFAULT_WIDGET_TEMPLATE_PATH,
|
||||
scope = editor.prefs.SCOPE.PROJECT
|
||||
})
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---Define the editor commands
|
||||
function M.get_commands()
|
||||
return {
|
||||
{
|
||||
@@ -28,24 +27,10 @@ function M.get_commands()
|
||||
query = { selection = {type = "resource", cardinality = "one"} },
|
||||
active = function(opts)
|
||||
local path = editor.get(opts.selection, "path")
|
||||
return ends_with(path, ".gui")
|
||||
return path:match("%.gui$") ~= nil
|
||||
end,
|
||||
run = function(opts)
|
||||
local file = opts.selection
|
||||
print("Run script for", editor.get(file, "path"))
|
||||
save_file_from_dependency('/druid/editor_scripts/run_python_script_on_gui.sh', "./build/run_python_script_on_gui.sh")
|
||||
save_file_from_dependency('/druid/editor_scripts/setup_layers.py', "./build/setup_layers.py")
|
||||
return {
|
||||
{
|
||||
action = "shell",
|
||||
command = {
|
||||
"bash",
|
||||
"./build/run_python_script_on_gui.sh",
|
||||
"./build/setup_layers.py",
|
||||
"." .. editor.get(file, "path")
|
||||
}
|
||||
}
|
||||
}
|
||||
return assign_layers.assign_layers(opts.selection)
|
||||
end
|
||||
},
|
||||
|
||||
@@ -55,25 +40,18 @@ function M.get_commands()
|
||||
query = { selection = {type = "resource", cardinality = "one"} },
|
||||
active = function(opts)
|
||||
local path = editor.get(opts.selection, "path")
|
||||
return ends_with(path, ".gui")
|
||||
return path:match("%.gui$") ~= nil
|
||||
end,
|
||||
run = function(opts)
|
||||
local file = opts.selection
|
||||
print("Run script for", editor.get(file, "path"))
|
||||
save_file_from_dependency('/druid/editor_scripts/run_python_script_on_gui.sh', "./build/run_python_script_on_gui.sh")
|
||||
save_file_from_dependency('/druid/editor_scripts/create_druid_component.py', "./build/create_druid_component.py")
|
||||
save_file_from_dependency('/druid/editor_scripts/widget.lua_template', "./build/widget.lua_template")
|
||||
return {
|
||||
{
|
||||
action = "shell",
|
||||
command = {
|
||||
"bash",
|
||||
"./build/run_python_script_on_gui.sh",
|
||||
"./build/create_druid_component.py",
|
||||
"." .. editor.get(file, "path")
|
||||
}
|
||||
}
|
||||
}
|
||||
return create_druid_widget.create_druid_widget(opts.selection)
|
||||
end
|
||||
},
|
||||
|
||||
{
|
||||
label = "[Druid] Settings",
|
||||
locations = { "Edit" },
|
||||
run = function()
|
||||
return druid_settings.open_settings()
|
||||
end
|
||||
}
|
||||
}
|
||||
|
122
druid/editor_scripts/druid_settings.lua
Normal file
122
druid/editor_scripts/druid_settings.lua
Normal file
@@ -0,0 +1,122 @@
|
||||
local M = {}
|
||||
|
||||
|
||||
function M.open_settings()
|
||||
print("Opening Druid settings")
|
||||
|
||||
local dialog_component = editor.ui.component(function(props)
|
||||
local template_path, set_template_path = editor.ui.use_state(editor.prefs.get("druid.widget_template_path"))
|
||||
|
||||
-- Check if the template path is valid
|
||||
local path_valid = editor.ui.use_memo(function(path)
|
||||
-- Use resource_exists to check if the resource exists
|
||||
local exists = false
|
||||
pcall(function()
|
||||
-- If we can get the text property, the resource exists
|
||||
local content = editor.get(path, "text")
|
||||
exists = content ~= nil
|
||||
end)
|
||||
return exists
|
||||
end, template_path)
|
||||
|
||||
return editor.ui.dialog({
|
||||
title = "Druid Settings",
|
||||
content = editor.ui.vertical({
|
||||
spacing = editor.ui.SPACING.MEDIUM,
|
||||
padding = editor.ui.PADDING.MEDIUM,
|
||||
children = {
|
||||
editor.ui.label({
|
||||
text = "Widget Template Path:"
|
||||
}),
|
||||
editor.ui.resource_field({
|
||||
value = template_path,
|
||||
on_value_changed = set_template_path,
|
||||
extensions = {"lua", "template"},
|
||||
padding = editor.ui.PADDING.SMALL
|
||||
}),
|
||||
not path_valid and editor.ui.label({
|
||||
text = "Warning: Path not found!",
|
||||
color = editor.ui.COLOR.WARNING
|
||||
}) or nil,
|
||||
|
||||
-- Links section title
|
||||
editor.ui.label({
|
||||
text = "Documentation:",
|
||||
color = editor.ui.COLOR.TEXT
|
||||
}),
|
||||
|
||||
-- Documentation buttons
|
||||
editor.ui.horizontal({
|
||||
spacing = editor.ui.SPACING.SMALL,
|
||||
children = {
|
||||
editor.ui.button({
|
||||
text = "Project Repository",
|
||||
on_pressed = function()
|
||||
editor.browse("https://github.com/Insality/druid")
|
||||
end
|
||||
}),
|
||||
editor.ui.button({
|
||||
text = "Open Quick API Reference",
|
||||
on_pressed = function()
|
||||
editor.browse("https://github.com/Insality/druid/blob/develop/api/quick_api_reference.md")
|
||||
end
|
||||
}),
|
||||
}
|
||||
}),
|
||||
|
||||
-- Sponsor section
|
||||
editor.ui.label({
|
||||
text = "Support the project:",
|
||||
color = editor.ui.COLOR.TEXT
|
||||
}),
|
||||
editor.ui.horizontal({
|
||||
spacing = editor.ui.SPACING.SMALL,
|
||||
children = {
|
||||
editor.ui.button({
|
||||
text = "❤️ Sponsor on GitHub",
|
||||
on_pressed = function()
|
||||
editor.browse("https://github.com/sponsors/Insality")
|
||||
end
|
||||
}),
|
||||
editor.ui.button({
|
||||
text = "☕ Ko-fi",
|
||||
on_pressed = function()
|
||||
editor.browse("https://ko-fi.com/insality")
|
||||
end
|
||||
}),
|
||||
editor.ui.button({
|
||||
text = "☕ Buy Me A Coffee",
|
||||
on_pressed = function()
|
||||
editor.browse("https://buymeacoffee.com/insality")
|
||||
end
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}),
|
||||
buttons = {
|
||||
editor.ui.dialog_button({
|
||||
text = "Cancel",
|
||||
cancel = true
|
||||
}),
|
||||
editor.ui.dialog_button({
|
||||
text = "Save",
|
||||
default = true,
|
||||
result = { template_path = template_path }
|
||||
})
|
||||
}
|
||||
})
|
||||
end)
|
||||
|
||||
local result = editor.ui.show_dialog(dialog_component({}))
|
||||
if result and result.template_path then
|
||||
-- Update the preferences
|
||||
editor.prefs.set("druid.widget_template_path", result.template_path)
|
||||
print("Widget template path updated to:", result.template_path)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
# @license MIT, Insality 2022
|
||||
# @source https://github.com/Insality/druid
|
||||
|
||||
echo "Run bash for $1"
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
# Check if pip3 is installed
|
||||
if command -v pip3 &> /dev/null; then
|
||||
PIP_CMD="pip3"
|
||||
PYTHON_CMD="python3"
|
||||
else
|
||||
PIP_CMD="pip"
|
||||
PYTHON_CMD="python"
|
||||
fi
|
||||
|
||||
is_defree_installed=$($PIP_CMD list --disable-pip-version-check | grep -E "deftree")
|
||||
if [ -z "$is_defree_installed" ]; then
|
||||
echo "The python deftree is not installed. Please install it via"
|
||||
echo "$ $PIP_CMD install deftree"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
$PYTHON_CMD $1 $2
|
@@ -1,44 +0,0 @@
|
||||
# @license MIT, Insality 2021
|
||||
# @source https://github.com/Insality/druid
|
||||
|
||||
import sys
|
||||
import deftree
|
||||
|
||||
def main():
|
||||
filename = sys.argv[1]
|
||||
print("Auto setup layers for file", filename)
|
||||
tree = deftree.parse(filename)
|
||||
root = tree.get_root()
|
||||
|
||||
layers = []
|
||||
for texture in root.iter_elements("textures"):
|
||||
layers.append(texture.get_attribute("name").value)
|
||||
|
||||
for fonts in root.iter_elements("fonts"):
|
||||
layers.append(fonts.get_attribute("name").value)
|
||||
|
||||
to_remove_layers = []
|
||||
for layer in root.iter_elements("layers"):
|
||||
to_remove_layers.append(layer)
|
||||
for layer in to_remove_layers:
|
||||
root.remove(layer)
|
||||
|
||||
for layer in layers:
|
||||
new_layer = root.add_element("layers")
|
||||
new_layer.add_attribute("name", layer)
|
||||
|
||||
for node in root.iter_elements("nodes"):
|
||||
texture = node.get_attribute("texture")
|
||||
font = node.get_attribute("font")
|
||||
|
||||
if texture and texture.value:
|
||||
layer = texture.value.split("/")[0]
|
||||
node.set_attribute("layer", layer)
|
||||
|
||||
if font:
|
||||
layer = font.value
|
||||
node.set_attribute("layer", layer)
|
||||
|
||||
tree.write()
|
||||
|
||||
main()
|
9
druid/templates/widget.lua.template
Normal file
9
druid/templates/widget.lua.template
Normal file
@@ -0,0 +1,9 @@
|
||||
---@class widget.{COMPONENT_TYPE}: druid.widget
|
||||
local M = {}
|
||||
|
||||
|
||||
function M:init()
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -13,6 +13,7 @@ function M:init()
|
||||
-- self.druid:new_button([node_id], [callback])
|
||||
-- self.druid:new_text([node_id], [text])
|
||||
-- And all functions from component.lua file
|
||||
|
||||
self.root = self:get_node("root")
|
||||
self.button = self.druid:new_button("button", self.on_button, self)
|
||||
end
|
||||
@@ -23,4 +24,4 @@ function M:on_button()
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
return M
|
Reference in New Issue
Block a user