LLS refactor

This commit is contained in:
Insality
2025-03-07 21:09:01 +02:00
parent 3bb8705444
commit be03a5bd50
18 changed files with 244 additions and 169 deletions

View File

@@ -38,8 +38,6 @@ local helper = require("druid.helper")
---@field private _meta druid.component.meta
local M = {}
local INTERESTS = {} -- Cache interests per component class in runtime
local uid = 0
---@private
@@ -234,6 +232,13 @@ function M:set_input_enabled(state)
end
---Get component input state. By default it's enabled. Can be disabled by `set_input_enabled` function.
---@return boolean
function M:get_input_enabled()
return self._meta.input_enabled
end
---Get parent component
---@return druid.component|nil parent_component The parent component if exist or nil
function M:get_parent_component()
@@ -286,28 +291,6 @@ function M:_reset_input_priority_changed()
end
---Get current component interests
---@return table List of component interests
---@private
function M:__get_interests()
local instance_class = self._meta.instance_class
if INTERESTS[instance_class] then
return INTERESTS[instance_class]
end
local interests = {}
for index = 1, #const.ALL_INTERESTS do
local interest = const.ALL_INTERESTS[index]
if self[interest] and type(self[interest]) == "function" then
table.insert(interests, interest)
end
end
INTERESTS[instance_class] = interests
return INTERESTS[instance_class]
end
---Get current component nodes
---@return table<hash, node>|nil
function M:get_nodes()
@@ -333,7 +316,6 @@ function M:__add_child(child)
end
---Remove child from component children list
---@generic T: druid.component
---@param child T The druid component instance
@@ -394,4 +376,45 @@ function M.create(name, input_priority)
end
local WIDGET_METATABLE = { __index = M }
---Create the Druid component instance
---@param self druid.instance
---@param widget_class druid.widget
---@param context table
---@return druid.widget
function M.create_widget(self, widget_class, context)
local instance = setmetatable({}, {
__index = setmetatable(widget_class, WIDGET_METATABLE)
})
instance._component = {
_uid = M.create_uid(),
name = "Druid Widget",
input_priority = const.PRIORITY_INPUT,
default_input_priority = const.PRIORITY_INPUT,
_is_input_priority_changed = true, -- Default true for sort once time after GUI init
}
instance._meta = {
druid = self,
template = "",
nodes = nil,
context = context,
style = nil,
input_enabled = true,
children = {},
parent = type(context) ~= "userdata" and context or nil,
instance_class = widget_class
}
-- Register
if instance._meta.parent then
instance._meta.parent:__add_child(instance)
end
---@cast instance druid.widget
return instance
end
return M

View File

@@ -44,7 +44,7 @@ local CORNER_PIVOTS = {
---@field fit_size vector3
---@field min_size_x number|nil
---@field min_size_y number|nil
---@field on_size_changed event @function on_size_changed(size)
---@field on_size_changed event fun(self: druid.container, size: vector3)
---@field _parent_container druid.container
---@field _containers table
---@field _draggable_corners table
@@ -244,7 +244,7 @@ function M:add_container(node_or_container, mode, on_resize_callback)
local node = node_or_container
-- Check it's a container components instead of node
if type(node_or_container) == "table" and node_or_container._component then
if type(node_or_container) == "table" and node_or_container.add_container then
node = node_or_container.node
container = node_or_container
mode = mode or container.mode

View File

@@ -148,8 +148,6 @@ function M:set_max_size(max_size)
end
---@private
function M:_check_steps(from, to, exactly)
if not self.steps then

View File

@@ -298,7 +298,7 @@ end
---@param node node
---@param x number
---@param y number
---@param node_click_area node|nil
---@param node_click_area node|nil Additional node to check for click area. If nil, only node will be checked
---@local
function M.pick_node(node, x, y, node_click_area)
local is_pick = gui_pick_node(node, x, y)

View File

@@ -1,6 +1,5 @@
---@class druid.widget: druid.component
---@field druid druid.instance Ready to use druid instance
---@field root node Is it really needed?
---@class GUITextMetrics
---@field width number

View File

@@ -1,18 +1,16 @@
-- Hello! Wish you a good day!
-- Hello, Defolder! Wish you a good day!
local events = require("event.events")
local const = require("druid.const")
local helper = require("druid.helper")
local settings = require("druid.system.settings")
local base_component = require("druid.component")
local druid_component = require("druid.component")
---@class druid.instance
---@field components_all druid.component[] All created components
---@field components_interest table<string, druid.component[]> All components sorted by interest
---@field url url
---@field private _context table Druid context
---@field private _context table Druid context, usually a self of gui script
---@field private _style table Druid style table
---@field private _deleted boolean
---@field private _is_late_remove_enabled boolean
---@field private _late_remove druid.component[]
---@field private _input_blacklist druid.component[]|nil
@@ -25,6 +23,7 @@ local M = {}
local MSG_ADD_FOCUS = hash("acquire_input_focus")
local MSG_REMOVE_FOCUS = hash("release_input_focus")
local IS_NO_AUTO_INPUT = sys.get_config_int("druid.no_auto_input", 0) == 1
local INTERESTS_CACHE = {} -- Cache interests per component class in runtime
local function set_input_state(self, is_input_inited)
if IS_NO_AUTO_INPUT or (self.input_inited == is_input_inited) then
@@ -36,17 +35,19 @@ local function set_input_state(self, is_input_inited)
end
-- The a and b - two Druid components
---@private
local function sort_input_comparator(a, b)
local a_priority = a:get_input_priority()
local b_priority = b:get_input_priority()
---@param component_a druid.component
---@param component_b druid.component
---@return boolean
local function sort_input_comparator(component_a, component_b)
local a_priority = component_a:get_input_priority()
local b_priority = component_b:get_input_priority()
if a_priority ~= b_priority then
return a_priority < b_priority
end
return a:get_uid() < b:get_uid()
return component_a:get_uid() < component_b:get_uid()
end
@@ -60,64 +61,62 @@ local function sort_input_stack(self)
end
-- Create the Druid component instance
local function create(self, instance_class)
local instance = instance_class()
instance:setup_component(self, self._context, self._style, instance_class)
---Get current component interests
---@param instance druid.component
---@return table interest_list List of component interests
local function get_component_interests(instance)
---@diagnostic disable-next-line: invisible
local instance_class = instance._meta.instance_class
if INTERESTS_CACHE[instance_class] then
return INTERESTS_CACHE[instance_class]
end
local interests = {}
for index = 1, #const.ALL_INTERESTS do
local interest = const.ALL_INTERESTS[index]
if instance[interest] and type(instance[interest]) == "function" then
table.insert(interests, interest)
end
end
INTERESTS_CACHE[instance_class] = interests
return INTERESTS_CACHE[instance_class]
end
---@private
---@param self druid.instance
---@param instance druid.component
local function register_interests(self, instance)
table.insert(self.components_all, instance)
local register_to = instance:__get_interests()
for i = 1, #register_to do
local interest = register_to[i]
local interest_list = get_component_interests(instance)
for i = 1, #interest_list do
local interest = interest_list[i]
table.insert(self.components_interest[interest], instance)
end
end
-- Create the Druid component instance
---@param self druid.instance
---@param instance_class druid.component
---@return druid.component
local function create(self, instance_class)
local instance = instance_class()
instance:setup_component(self, self:get_context(), self:get_style(), instance_class)
register_interests(self, instance)
return instance
end
local WIDGET_METATABLE = { __index = base_component }
---Create the Druid component instance
---@private
---@param self druid.instance
---@param widget_class druid.component
---@param widget_class druid.widget
---@return druid.widget
local function create_widget(self, widget_class)
local instance = setmetatable({}, {
__index = setmetatable(widget_class, WIDGET_METATABLE)
})
instance._component = {
_uid = base_component.create_uid(),
name = "Druid Widget",
input_priority = const.PRIORITY_INPUT,
default_input_priority = const.PRIORITY_INPUT,
_is_input_priority_changed = true, -- Default true for sort once time after GUI init
}
instance._meta = {
druid = self,
template = "",
nodes = nil,
context = self._context,
style = nil,
input_enabled = true,
children = {},
parent = type(self._context) ~= "userdata" and self._context,
instance_class = widget_class
}
-- Register
if instance._meta.parent then
instance._meta.parent:__add_child(instance)
end
table.insert(self.components_all, instance)
local register_to = instance:__get_interests()
for i = 1, #register_to do
local interest = register_to[i]
table.insert(self.components_interest[interest], instance)
end
local instance = druid_component.create_widget(self, widget_class, self:get_context())
register_interests(self, instance)
return instance
end
@@ -176,8 +175,9 @@ function M:_process_input(action_id, action, components)
for i = #components, 1, -1 do
local component = components[i]
local meta = component._meta
if meta.input_enabled and self:_can_use_input_component(component) then
local input_enabled = component:get_input_enabled()
if input_enabled and self:_can_use_input_component(component) then
if not is_input_consumed then
is_input_consumed = component:on_input(action_id, action) or false
else
@@ -210,7 +210,6 @@ end
function M:initialize(context, style)
self._context = context
self._style = style or settings.default_style
self._deleted = false
self._is_late_remove_enabled = false
self._late_remove = {}
@@ -257,8 +256,6 @@ function M:final()
end
end
self._deleted = true
set_input_state(self, false)
events.unsubscribe("druid.window_event", self.on_window_event, self)
@@ -303,9 +300,9 @@ function M:remove(component)
end
end
local interests = component:__get_interests()
for i = 1, #interests do
local interest = interests[i]
local interest_list = get_component_interests(component)
for i = 1, #interest_list do
local interest = interest_list[i]
local components = self.components_interest[interest]
for j = #components, 1, -1 do
if components[j] == component then
@@ -318,6 +315,22 @@ function M:remove(component)
end
---Get a context of Druid instance (usually a self of gui script)
---@package
---@return any
function M:get_context()
return self._context
end
---Get a style of Druid instance
---@package
---@return table
function M:get_style()
return self._style
end
---Druid late update function called after initialization and before the regular update step.
---This function is used to check the GUI state and perform actions after all components and nodes have been created.
---An example use case is performing an auto stencil check in the GUI hierarchy for input components.
@@ -506,7 +519,7 @@ end
local button = require("druid.base.button")
---Create Button component
---@param node string|node The node_id or gui.get_node(node_id)
---@param callback function|nil Button callback
---@param callback function|event|nil Button callback
---@param params any|nil Button callback params
---@param anim_node node|string|nil Button anim node (node, if not provided)
---@return druid.button Button component

View File

@@ -102,13 +102,16 @@ end
function M:clear_created_properties()
for index = 1, #self.properties do
local property = self.properties[index]
local root = property.root --[[@as node]]
-- If prefab used clone nodes we can remove it
if property:get_nodes() then
gui.delete_node(property.root)
else
-- Probably we have component placed on scene directly
gui.set_enabled(property.root, false)
if root then
-- If prefab used clone nodes we can remove it
if property:get_nodes() then
gui.delete_node(root)
else
-- Probably we have component placed on scene directly
gui.set_enabled(root, false)
end
end
self.druid:remove(self.properties[index])