This commit is contained in:
Insality 2024-11-21 22:00:05 +02:00
parent 69ebb252e1
commit 5a1668a8af
22 changed files with 174 additions and 205 deletions

3
.gitignore vendored
View File

@ -14,4 +14,5 @@ deployer_version_settings.txt
.deployer_cache .deployer_cache
bob*.jar bob*.jar
manifest.private.der manifest.private.der
manifest.public.der manifest.public.der
/.editor_settings

View File

@ -154,7 +154,7 @@ local component = require("druid.component")
---@field anim_node node ---@field anim_node node
---@field params any ---@field params any
---@field hover druid.hover ---@field hover druid.hover
---@field click_zone node ---@field click_zone node|nil
---@field start_scale vector3 ---@field start_scale vector3
---@field start_pos vector3 ---@field start_pos vector3
---@field disabled boolean ---@field disabled boolean
@ -474,7 +474,7 @@ end
---@param zone node|string|nil Gui node ---@param zone node|string|nil Gui node
---@return druid.button self ---@return druid.button self
function M:set_click_zone(zone) function M:set_click_zone(zone)
self.click_zone = self:get_node(zone) self.click_zone = zone and self:get_node(zone) or nil
self.hover:set_click_zone(zone) self.hover:set_click_zone(zone)
return self return self

View File

@ -70,7 +70,7 @@ local component = require("druid.component")
---@field on_drag event ---@field on_drag event
---@field on_drag_end event ---@field on_drag_end event
---@field style table ---@field style table
---@field click_zone node ---@field click_zone node|nil
---@field is_touch boolean ---@field is_touch boolean
---@field is_drag boolean ---@field is_drag boolean
---@field can_x boolean ---@field can_x boolean
@ -365,9 +365,9 @@ end
---Set Drag click zone ---Set Drag click zone
---@param node node|string|nil ---@param node node|string|nil
---@return druid.drag self ---@return druid.drag self Current instance
function M:set_click_zone(node) function M:set_click_zone(node)
self.click_zone = self:get_node(node) self.click_zone = node and self:get_node(node) or nil
return self return self
end end
@ -375,7 +375,7 @@ end
---Set Drag component enabled state. ---Set Drag component enabled state.
---@param is_enabled boolean ---@param is_enabled boolean
---@return druid.drag self ---@return druid.drag self Current instance
function M:set_enabled(is_enabled) function M:set_enabled(is_enabled)
self._is_enabled = is_enabled self._is_enabled = is_enabled

View File

@ -541,7 +541,7 @@ end
---@private ---@private
function M:_get_zero_offset() function M:_get_zero_offset()
if not self.style.IS_DYNAMIC_NODE_POSES then if not self.style.IS_DYNAMIC_NODE_POSES then
return const.VECTOR_ZERO return vmath.vector3(0)
end end
-- zero offset: center pos - border size * anchor -- zero offset: center pos - border size * anchor

View File

@ -1,17 +1,15 @@
---Base component class for all Druid components.
local const = require("druid.const") local const = require("druid.const")
local helper = require("druid.helper") local helper = require("druid.helper")
---@class druid.base_component.meta ---@class druid.base_component.meta
---@field template string ---@field template string
---@field context table ---@field context table
---@field nodes table ---@field nodes table<string|hash, node>|nil
---@field style table ---@field style table|nil
---@field druid druid_instance ---@field druid druid_instance
---@field input_enabled boolean ---@field input_enabled boolean
---@field children table ---@field children table
---@field parent druid.base_component ---@field parent druid.base_component|nil
---@field instance_class table ---@field instance_class table
---@class druid.base_component.component ---@class druid.base_component.component
@ -64,15 +62,6 @@ M.ALL_INTERESTS = {
M.ON_LANGUAGE_CHANGE, M.ON_LANGUAGE_CHANGE,
} }
-- Mapping from on_message method to specific method name
M.SPECIFIC_UI_MESSAGES = {
[hash("layout_changed")] = M.ON_LAYOUT_CHANGE, -- The message_id from Defold
[hash(M.ON_FOCUS_LOST)] = M.ON_FOCUS_LOST,
[hash(M.ON_FOCUS_GAINED)] = M.ON_FOCUS_GAINED,
[hash(M.ON_WINDOW_RESIZED)] = M.ON_WINDOW_RESIZED,
[hash(M.ON_LANGUAGE_CHANGE)] = M.ON_LANGUAGE_CHANGE,
}
local uid = 0 local uid = 0
function M.create_uid() function M.create_uid()
@ -136,7 +125,7 @@ end
---Set current component nodes, returned from `gui.clone_tree` function. ---Set current component nodes, returned from `gui.clone_tree` function.
---@param nodes table<hash, node> ---@param nodes table<string|hash, node>
---@return druid.base_component ---@return druid.base_component
function M:set_nodes(nodes) function M:set_nodes(nodes)
self._meta.nodes = nodes self._meta.nodes = nodes
@ -271,7 +260,7 @@ end
---@param context table Druid context. Usually it is self of script ---@param context table Druid context. Usually it is self of script
---@param style table Druid style module ---@param style table Druid style module
---@param instance_class table The component instance class ---@param instance_class table The component instance class
---@return component BaseComponent itself ---@return druid.base_component BaseComponent itself
---@private ---@private
function M:setup_component(druid_instance, context, style, instance_class) function M:setup_component(druid_instance, context, style, instance_class)
self._meta = { self._meta = {
@ -282,7 +271,7 @@ function M:setup_component(druid_instance, context, style, instance_class)
druid = druid_instance, druid = druid_instance,
input_enabled = true, input_enabled = true,
children = {}, children = {},
parent = type(context) ~= "userdata" and context, parent = type(context) ~= "userdata" and context --[[@as druid.base_component]],
instance_class = instance_class instance_class = instance_class
} }
@ -341,20 +330,28 @@ function M:get_nodes()
if parent then if parent then
nodes = nodes or parent:get_nodes() nodes = nodes or parent:get_nodes()
end end
return nodes return nodes
end end
---Add child to component children list ---Add child to component children list
---@param child druid.base_component The druid component instance ---@generic T: druid.base_component
---@param child T The druid component instance
---@return T self The component itself for chaining
---@private ---@private
function M:__add_child(child) function M:__add_child(child)
table.insert(self._meta.children, child) table.insert(self._meta.children, child)
return self
end end
--- Remove child from component children list
---@param child component The druid component instance ---Remove child from component children list
---@generic T: druid.base_component
---@param child T The druid component instance
---@return boolean true if child was removed
---@private ---@private
function M:__remove_child(child) function M:__remove_child(child)
for i = #self._meta.children, 1, -1 do for i = #self._meta.children, 1, -1 do
@ -363,6 +360,8 @@ function M:__remove_child(child)
return true return true
end end
end end
return false
end end

View File

@ -27,19 +27,13 @@ M.ON_LAYOUT_CHANGE = "on_layout_change"
M.ON_WINDOW_RESIZED = "on_window_resized" M.ON_WINDOW_RESIZED = "on_window_resized"
M.ON_LANGUAGE_CHANGE = "on_language_change" M.ON_LANGUAGE_CHANGE = "on_language_change"
M.MSG_LAYOUT_CHANGED = hash("layout_changed")
-- Components with higher priority value processed first -- Components with higher priority value processed first
M.PRIORITY_INPUT = 10 M.PRIORITY_INPUT = 10
M.PRIORITY_INPUT_HIGH = 20 M.PRIORITY_INPUT_HIGH = 20
M.PRIORITY_INPUT_MAX = 100 M.PRIORITY_INPUT_MAX = 100
M.MESSAGE_INPUT = {
BUTTON_CLICK = "button_click",
BUTTON_LONG_CLICK = "button_long_click",
BUTTON_DOUBLE_CLICK = "button_double_click",
BUTTON_REPEATED_CLICK = "button_repeated_click",
TEXT_SET = "text_set",
}
M.PIVOTS = { M.PIVOTS = {
[gui.PIVOT_CENTER] = vmath.vector3(0), [gui.PIVOT_CENTER] = vmath.vector3(0),
[gui.PIVOT_N] = vmath.vector3(0, 0.5, 0), [gui.PIVOT_N] = vmath.vector3(0, 0.5, 0),
@ -73,7 +67,6 @@ M.LAYOUT_MODE = {
STRETCH = gui.ADJUST_STRETCH, STRETCH = gui.ADJUST_STRETCH,
} }
M.VECTOR_ZERO = vmath.vector3(0)
M.SYS_INFO = sys.get_sys_info() M.SYS_INFO = sys.get_sys_info()
M.CURRENT_SYSTEM_NAME = M.SYS_INFO.system_name M.CURRENT_SYSTEM_NAME = M.SYS_INFO.system_name
@ -94,13 +87,13 @@ M.SHIFT = {
M.TEXT_ADJUST = { M.TEXT_ADJUST = {
DOWNSCALE = "downscale", DOWNSCALE = "downscale",
NO_ADJUST = "no_adjust",
DOWNSCALE_LIMITED = "downscale_limited",
SCROLL = "scroll",
TRIM = "trim", TRIM = "trim",
TRIM_LEFT = "trim_left", TRIM_LEFT = "trim_left",
SCALE_THEN_TRIM = "scale_then_trim", SCALE_THEN_TRIM = "scale_then_trim",
SCALE_THEN_TRIM_LEFT = "scale_then_trim_left", SCALE_THEN_TRIM_LEFT = "scale_then_trim_left",
NO_ADJUST = "no_adjust",
DOWNSCALE_LIMITED = "downscale_limited",
SCROLL = "scroll",
SCALE_THEN_SCROLL = "scale_then_scroll", SCALE_THEN_SCROLL = "scale_then_scroll",
} }
@ -109,13 +102,5 @@ M.SIDE = {
Y = "y" Y = "y"
} }
M.SWIPE = {
UP = "up",
DOWN = "down",
LEFT = "left",
RIGHT = "right",
}
M.EMPTY_FUNCTION = function() end
return M return M

View File

@ -279,8 +279,8 @@ end
--- Set input field text --- Set input field text
---@return druid.input Current input instance
---@param text string The input text ---@param text string The input text
---@return druid.rich_input self Current instance
function M:set_text(text) function M:set_text(text)
self.input:set_text(text) self.input:set_text(text)
gui.set_enabled(self.placeholder.node, true and #self.input:get_text() == 0) gui.set_enabled(self.placeholder.node, true and #self.input:get_text() == 0)
@ -291,7 +291,7 @@ end
--- Set input field font --- Set input field font
---@param font hash The font hash ---@param font hash The font hash
---@return druid.input Current input instance ---@return druid.rich_input self Current instance
function M:set_font(font) function M:set_font(font)
gui.set_font(self.input.text.node, font) gui.set_font(self.input.text.node, font)
gui.set_font(self.placeholder.node, font) gui.set_font(self.placeholder.node, font)
@ -310,7 +310,7 @@ end
-- See: https://defold.com/ref/stable/string/ -- See: https://defold.com/ref/stable/string/
-- ex: [%a%d] for alpha and numeric -- ex: [%a%d] for alpha and numeric
---@param characters string Regulax exp. for validate user input ---@param characters string Regulax exp. for validate user input
---@return RichInput Current instance ---@return druid.rich_input Current instance
function M:set_allowed_characters(characters) function M:set_allowed_characters(characters)
self.input:set_allowed_characters(characters) self.input:set_allowed_characters(characters)

View File

@ -1,27 +1,26 @@
local const = require("druid.const") local events = require("event.events")
local settings = require("druid.system.settings") local settings = require("druid.system.settings")
local base_component = require("druid.component")
local druid_instance = require("druid.system.druid_instance") local druid_instance = require("druid.system.druid_instance")
local default_style = require("druid.styles.default.style") local default_style = require("druid.styles.default.style")
---@class druid ---@class druid
local M = {} local M = {}
local druid_instances = {}
local function clean_deleted_druid_instances() ---Create a new Druid instance for creating GUI components.
for i = #druid_instances, 1, -1 do ---@param context table The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks.
if druid_instances[i]._deleted then ---@param style table|nil The Druid style table to override style parameters for this Druid instance.
table.remove(druid_instances, i) ---@return druid_instance druid_instance The new Druid instance
end function M.new(context, style)
if settings.default_style == nil then
M.set_default_style(default_style)
end end
end
local new_instance = setmetatable({}, { __index = druid_instance })
new_instance:initialize(context, style)
local function get_druid_instances() return new_instance
clean_deleted_druid_instances()
return druid_instances
end end
@ -39,25 +38,6 @@ function M.register(name, module)
end end
---Create a new Druid instance for creating GUI components.
---@param context table The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks.
---@param style table|nil The Druid style table to override style parameters for this Druid instance.
---@return druid_instance druid_instance The new Druid instance
function M.new(context, style)
clean_deleted_druid_instances()
if settings.default_style == nil then
M.set_default_style(default_style)
end
local new_instance = setmetatable({}, { __index = druid_instance })
new_instance:initialize(context, style)
table.insert(druid_instances, new_instance)
return new_instance
end
---Set the default style for all Druid instances. ---Set the default style for all Druid instances.
---@param style table Default style ---@param style table Default style
function M.set_default_style(style) function M.set_default_style(style)
@ -68,7 +48,7 @@ end
---Set the text function for the LangText component. ---Set the text function for the LangText component.
---@param callback fun(text_id: string): string Get localized text function ---@param callback fun(text_id: string): string Get localized text function
function M.set_text_function(callback) function M.set_text_function(callback)
settings.get_text = callback or const.EMPTY_FUNCTION settings.get_text = callback or function() end
M.on_language_change() M.on_language_change()
end end
@ -76,7 +56,7 @@ end
---Set the sound function to able components to play sounds. ---Set the sound function to able components to play sounds.
---@param callback fun(sound_id: string) Sound play callback ---@param callback fun(sound_id: string) Sound play callback
function M.set_sound_function(callback) function M.set_sound_function(callback)
settings.play_sound = callback or const.EMPTY_FUNCTION settings.play_sound = callback or function() end
end end
@ -84,40 +64,22 @@ end
---window listener, so if you have one, you should call M.on_window_callback manually. ---window listener, so if you have one, you should call M.on_window_callback manually.
function M.init_window_listener() function M.init_window_listener()
window.set_listener(function(_, window_event) window.set_listener(function(_, window_event)
M.on_window_callback(window_event) events.trigger("druid.window_event", window_event)
end) end)
end end
---Set the window callback to enable Druid window events. ---Set the window callback to enable Druid window events.
---@param event constant Event param from window listener ---@param window_event constant Event param from window listener
function M.on_window_callback(event) function M.on_window_callback(window_event)
local instances = get_druid_instances() events.trigger("druid.window_event", window_event)
if event == window.WINDOW_EVENT_FOCUS_LOST then
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_FOCUS_LOST)
end
elseif event == window.WINDOW_EVENT_FOCUS_GAINED then
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_FOCUS_GAINED)
end
elseif event == window.WINDOW_EVENT_RESIZED then
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_WINDOW_RESIZED)
end
end
end end
---Call this function when the game language changes. ---Call this function when the game language changes.
---It will notify all Druid instances to update the lang text components. ---It will notify all Druid instances to update the lang text components.
function M.on_language_change() function M.on_language_change()
local instances = get_druid_instances() events.trigger("druid.language_change")
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_LANGUAGE_CHANGE)
end
end end

View File

@ -69,7 +69,7 @@ end
--- Setup raw text to lang_text component --- Setup raw text to lang_text component
---@param text string Text for text node ---@param text string Text for text node
---@return LangText Current instance ---@return druid.lang_text Current instance
function M:set_to(text) function M:set_to(text)
self.last_locale = false self.last_locale = false
self.text:set_to(text) self.text:set_to(text)
@ -88,7 +88,7 @@ end
---@param e string|nil Optional param to string.format ---@param e string|nil Optional param to string.format
---@param f string|nil Optional param to string.format ---@param f string|nil Optional param to string.format
---@param g string|nil Optional param to string.format ---@param g string|nil Optional param to string.format
---@return LangText Current instance ---@return druid.lang_text Current instance
function M:translate(locale_id, a, b, c, d, e, f, g) function M:translate(locale_id, a, b, c, d, e, f, g)
self.last_locale_args = { a, b, c, d, e, f, g } self.last_locale_args = { a, b, c, d, e, f, g }
self.last_locale = locale_id or self.last_locale self.last_locale = locale_id or self.last_locale
@ -106,7 +106,7 @@ end
---@param e string|nil Optional param to string.format ---@param e string|nil Optional param to string.format
---@param f string|nil Optional param to string.format ---@param f string|nil Optional param to string.format
---@param g string|nil Optional param to string.format ---@param g string|nil Optional param to string.format
---@return LangText Current instance ---@return druid.lang_text Current instance
function M:format(a, b, c, d, e, f, g) function M:format(a, b, c, d, e, f, g)
self.last_locale_args = { a, b, c, d, e, f, g } self.last_locale_args = { a, b, c, d, e, f, g }
self.text:set_to(settings.get_text(self.last_locale, a, b, c, d, e, f, g) or "") self.text:set_to(settings.get_text(self.last_locale, a, b, c, d, e, f, g) or "")

View File

@ -221,6 +221,7 @@ function M:refresh_layout()
local layout_pivot_offset = helper.get_pivot_offset(gui.get_pivot(layout_node)) -- {x: -0.5, y: -0.5} - is left bot, {x: 0.5, y: 0.5} - is right top local layout_pivot_offset = helper.get_pivot_offset(gui.get_pivot(layout_node)) -- {x: -0.5, y: -0.5} - is left bot, {x: 0.5, y: 0.5} - is right top
local rows_data = self:calculate_rows_data() local rows_data = self:calculate_rows_data()
self.rows_data = rows_data
local rows = rows_data.rows local rows = rows_data.rows
local row_index = 1 local row_index = 1
local row = rows[row_index] local row = rows[row_index]

View File

@ -247,7 +247,7 @@ end
--- Set progress bar max node size --- Set progress bar max node size
---@param max_size vector3 The new node maximum (full) size ---@param max_size vector3 The new node maximum (full) size
---@return Progress Progress ---@return druid.progress Progress
function M:set_max_size(max_size) function M:set_max_size(max_size)
self.max_size[self.key] = max_size[self.key] self.max_size[self.key] = max_size[self.key]
self:set_to(self.last_value) self:set_to(self.last_value)

View File

@ -212,7 +212,7 @@ end
-- apply closest step position -- apply closest step position
---@param steps number[] Array of steps ---@param steps number[] Array of steps
-- @usage slider:set_steps({0, 0.2, 0.6, 1}) -- @usage slider:set_steps({0, 0.2, 0.6, 1})
---@return Slider Slider ---@return druid.slider Slider
function M:set_steps(steps) function M:set_steps(steps)
self.steps = steps self.steps = steps
return self return self
@ -224,8 +224,13 @@ end
-- move at this position and node drag will start. -- move at this position and node drag will start.
-- This function require the Defold version 1.3.0+ -- This function require the Defold version 1.3.0+
---@param input_node node|string|nil ---@param input_node node|string|nil
---@return Slider Slider ---@return druid.slider Slider
function M:set_input_node(input_node) function M:set_input_node(input_node)
if not input_node then
self._input_node = nil
return self
end
self._input_node = self:get_node(input_node) self._input_node = self:get_node(input_node)
return self return self
end end

View File

@ -16,7 +16,7 @@
---@param click_zone node|nil ---@param click_zone node|nil
--- Trigger on swipe event(self, swipe_side, dist, delta_time) --- Trigger on swipe event(self, swipe_side, dist, delta_time)
-- @tfield event on_swipe) event ---@param event event on_swipe
--- ---
@ -27,7 +27,7 @@ local component = require("druid.component")
---@class druid.swipe: druid.base_component ---@class druid.swipe: druid.base_component
---@field node node ---@field node node
---@field on_swipe event ---@field on_swipe event function(side, dist, dt), side - "left", "right", "up", "down"
---@field style table ---@field style table
---@field click_zone node ---@field click_zone node
---@field private _trigger_on_move boolean ---@field private _trigger_on_move boolean
@ -62,16 +62,16 @@ local function check_swipe(self, action)
local swipe_side = false local swipe_side = false
if is_x_swipe and dx > 0 then if is_x_swipe and dx > 0 then
swipe_side = const.SWIPE.RIGHT swipe_side = "right"
end end
if is_x_swipe and dx < 0 then if is_x_swipe and dx < 0 then
swipe_side = const.SWIPE.LEFT swipe_side = "left"
end end
if not is_x_swipe and dy > 0 then if not is_x_swipe and dy > 0 then
swipe_side = const.SWIPE.UP swipe_side = "up"
end end
if not is_x_swipe and dy < 0 then if not is_x_swipe and dy < 0 then
swipe_side = const.SWIPE.DOWN swipe_side = "down"
end end
self.on_swipe:trigger(self:get_context(), swipe_side, dist, delta_time) self.on_swipe:trigger(self:get_context(), swipe_side, dist, delta_time)
@ -83,10 +83,12 @@ end
--- Component style params. --- Component style params.
-- You can override this component styles params in druid styles table -- You can override this component styles params in druid styles table
-- or create your own style -- or create your own style
-- @table style ---@class druid.swipe.style
-- @tfield number|nil SWIPE_TIME Maximum time for swipe trigger. Default: 0.4 ---@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4
-- @tfield number|nil SWIPE_THRESHOLD Minimum distance for swipe trigger. Default: 50 ---@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50
-- @tfield boolean|nil SWIPE_TRIGGER_ON_MOVE If true, trigger on swipe moving, not only release action. Default: false ---@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false
---@param style druid.swipe.style
function M:on_style_change(style) function M:on_style_change(style)
self.style = {} self.style = {}
self.style.SWIPE_TIME = style.SWIPE_TIME or 0.4 self.style.SWIPE_TIME = style.SWIPE_TIME or 0.4

View File

@ -1,7 +1,6 @@
--- Druid Helper module
local const = require("druid.const") local const = require("druid.const")
-- Localize functions for better performance
local gui_get_node = gui.get_node local gui_get_node = gui.get_node
local gui_get = gui.get local gui_get = gui.get
local gui_pick_node = gui.pick_node local gui_pick_node = gui.pick_node
@ -153,8 +152,7 @@ end
---@return number scale_x ---@return number scale_x
function M.get_gui_scale() function M.get_gui_scale()
local window_x, window_y = window.get_size() local window_x, window_y = window.get_size()
return math.min(window_x / gui.get_width(), return math.min(window_x / gui.get_width(), window_y / gui.get_height())
window_y / gui.get_height())
end end
@ -462,7 +460,7 @@ end
---Add value to array with shift policy ---Add value to array with shift policy
-- Shift policy can be: left, right, no_shift ---Shift policy can be: left, right, no_shift
---@param array table Array ---@param array table Array
---@param item any Item to insert ---@param item any Item to insert
---@param index number|nil Index to insert. If nil, item will be inserted at the end of array ---@param index number|nil Index to insert. If nil, item will be inserted at the end of array
@ -492,7 +490,6 @@ end
---Remove value from array with shift policy ---Remove value from array with shift policy
--
-- Shift policy can be: left, right, no_shift -- Shift policy can be: left, right, no_shift
---@param array any[] Array ---@param array any[] Array
---@param index number|nil Index to remove. If nil, item will be removed from the end of array ---@param index number|nil Index to remove. If nil, item will be removed from the end of array

View File

@ -0,0 +1,10 @@
varying mediump vec2 var_texcoord0;
varying lowp vec4 var_color;
uniform lowp sampler2D texture_sampler;
void main()
{
lowp vec4 tex = texture2D(texture_sampler, var_texcoord0.xy);
gl_FragColor = tex * var_color;
}

View File

@ -0,0 +1,8 @@
name: "gui_world"
tags: "tile"
vertex_program: "/druid/materials/gui_world/gui_world.vp"
fragment_program: "/druid/materials/gui_world/gui_world.fp"
vertex_constants {
name: "view_proj"
type: CONSTANT_TYPE_VIEWPROJ
}

View File

@ -0,0 +1,16 @@
uniform highp mat4 view_proj;
// positions are in world space
attribute highp vec3 position;
attribute mediump vec2 texcoord0;
attribute lowp vec4 color;
varying mediump vec2 var_texcoord0;
varying lowp vec4 var_color;
void main()
{
var_texcoord0 = texcoord0;
var_color = vec4(color.rgb * color.a, color.a);
gl_Position = view_proj * vec4(position.xyz, 1.0);
}

View File

@ -1,20 +1,4 @@
local events = require("event.events")
-- Please review the following API pages:
--
-- Helper - A useful set of functions for working with GUI nodes, such as centering nodes, get GUI scale ratio, etc
--
-- event - The core event system in Druid. Learn how to subscribe to any event in every Druid component.
--
-- BaseComponent - The parent class of all Druid components. You can find all default component methods there.
--
-- # Tech Info #
--
-- • To use Druid, you need to create a Druid instance first. This instance is used to spawn components.
--
-- • When using Druid components, provide the node name as a string argument directly. Avoid calling gui.get_node() before passing it to the component. Because Druid can get nodes from template and cloned gui nodes.
--
-- • All Druid and component methods are called using the colon operator (e.g., self.druid:new_button()).
local const = require("druid.const") local const = require("druid.const")
local helper = require("druid.helper") local helper = require("druid.helper")
local settings = require("druid.system.settings") local settings = require("druid.system.settings")
@ -162,7 +146,10 @@ local function check_sort_input_stack(self, components)
end end
--- Check whitelists and blacklists for input components ---Check whitelists and blacklists for input components
---@param self druid_instance
---@param component druid.base_component
---@return boolean
local function can_use_input_component(self, component) local function can_use_input_component(self, component)
local can_by_whitelist = true local can_by_whitelist = true
local can_by_blacklist = true local can_by_blacklist = true
@ -222,7 +209,6 @@ function M:initialize(context, style)
self._deleted = false self._deleted = false
self._is_late_remove_enabled = false self._is_late_remove_enabled = false
self._late_remove = {} self._late_remove = {}
self.url = msg.url()
self._input_blacklist = nil self._input_blacklist = nil
self._input_whitelist = nil self._input_whitelist = nil
@ -232,6 +218,9 @@ function M:initialize(context, style)
for i = 1, #base_component.ALL_INTERESTS do for i = 1, #base_component.ALL_INTERESTS do
self.components_interest[base_component.ALL_INTERESTS[i]] = {} self.components_interest[base_component.ALL_INTERESTS[i]] = {}
end end
events.subscribe("druid.window_event", self.on_window_event, self)
events.subscribe("druid.language_change", self.on_language_change, self)
end end
@ -267,6 +256,9 @@ function M:final()
self._deleted = true self._deleted = true
set_input_state(self, false) set_input_state(self, false)
events.unsubscribe("druid.window_event", self.on_window_event, self)
events.unsubscribe("druid.language_change", self.on_language_change, self)
end end
@ -340,9 +332,7 @@ function M:late_init()
end end
--- Call this in gui_script update function. ---Call this in gui_script update function.
--
-- Used for: scroll, progress, timer components
---@param dt number Delta time ---@param dt number Delta time
function M:update(dt) function M:update(dt)
self._is_late_remove_enabled = true self._is_late_remove_enabled = true
@ -357,9 +347,7 @@ function M:update(dt)
end end
--- Call this in gui_script on_input function. ---Call this in gui_script on_input function.
--
-- Used for almost all components
---@param action_id hash Action_id from on_input ---@param action_id hash Action_id from on_input
---@param action table Action from on_input ---@param action table Action from on_input
---@return boolean The boolean value is input was consumed ---@return boolean The boolean value is input was consumed
@ -378,22 +366,15 @@ end
--- Call this in gui_script on_message function. --- Call this in gui_script on_message function.
--
-- Used for special actions. See SPECIFIC_UI_MESSAGES table
---@param message_id hash Message_id from on_message ---@param message_id hash Message_id from on_message
---@param message table Message from on_message ---@param message table Message from on_message
---@param sender url Sender from on_message ---@param sender url Sender from on_message
function M:on_message(message_id, message, sender) function M:on_message(message_id, message, sender)
local specific_ui_message = base_component.SPECIFIC_UI_MESSAGES[message_id] if message_id == const.MSG_LAYOUT_CHANGED then
if specific_ui_message then
-- Resend special message to all components with the related interest -- Resend special message to all components with the related interest
local components = self.components_interest[specific_ui_message] local components = self.components_interest[base_component.ON_LAYOUT_CHANGE]
if components then for i = 1, #components do
for i = 1, #components do components[i]:on_layout_change()
local component = components[i]
component[specific_ui_message](component, message, sender)
end
end end
else else
-- Resend message to all components with on_message interest -- Resend message to all components with on_message interest
@ -405,24 +386,22 @@ function M:on_message(message_id, message, sender)
end end
--- Calls the on_focus_lost function in all related components function M:on_window_event(window_event)
-- This one called by on_window_callback by global window listener if window_event == window.WINDOW_EVENT_FOCUS_LOST then
---@private local components = self.components_interest[base_component.ON_FOCUS_LOST]
function M:on_focus_lost() for i = 1, #components do
local components = self.components_interest[base_component.ON_FOCUS_LOST] components[i]:on_focus_lost()
for i = 1, #components do end
components[i]:on_focus_lost() elseif window_event == window.WINDOW_EVENT_FOCUS_GAINED then
end local components = self.components_interest[base_component.ON_FOCUS_GAINED]
end for i = 1, #components do
components[i]:on_focus_gained()
end
--- Calls the on_focus_gained function in all related components elseif window_event == window.WINDOW_EVENT_RESIZED then
-- This one called by on_window_callback by global window listener local components = self.components_interest[base_component.ON_WINDOW_RESIZED]
---@private for i = 1, #components do
function M:on_focus_gained() components[i]:on_window_resized()
local components = self.components_interest[base_component.ON_FOCUS_GAINED] end
for i = 1, #components do
components[i]:on_focus_gained()
end end
end end
@ -439,9 +418,9 @@ function M:on_language_change()
end end
--- Set whitelist components for input processing. ---Set whitelist components for input processing.
-- If whitelist is not empty and component not contains in this list, ---If whitelist is not empty and component not contains in this list,
-- component will be not processed on input step ---component will be not processed on input step
---@param whitelist_components table|druid.base_component[]|nil The array of component to whitelist ---@param whitelist_components table|druid.base_component[]|nil The array of component to whitelist
---@return druid_instance ---@return druid_instance
function M:set_whitelist(whitelist_components) function M:set_whitelist(whitelist_components)
@ -459,9 +438,9 @@ function M:set_whitelist(whitelist_components)
end end
--- Set blacklist components for input processing. ---Set blacklist components for input processing.
-- If blacklist is not empty and component contains in this list, ---If blacklist is not empty and component contains in this list,
-- component will be not processed on input step DruidInstance ---component will be not processed on input step DruidInstance
---@param blacklist_components table|druid.base_component[]|nil The array of component to blacklist ---@param blacklist_components table|druid.base_component[]|nil The array of component to blacklist
---@return druid_instance ---@return druid_instance
function M:set_blacklist(blacklist_components) function M:set_blacklist(blacklist_components)
@ -497,11 +476,17 @@ end
---@generic T: druid.base_component ---@generic T: druid.base_component
---@param widget T ---@param widget T
---@param template string|nil The template name used by widget ---@param template string|nil The template name used by widget
---@param nodes table|nil The nodes table from gui.clone_tree ---@param nodes table|node|nil The nodes table from gui.clone_tree or prefab node to use for clone
---@vararg any ---@vararg any
---@return T ---@return T
function M:new_widget(widget, template, nodes, ...) function M:new_widget(widget, template, nodes, ...)
local instance = create_widget(self, widget) local instance = create_widget(self, widget)
if type(nodes) == "userdata" then
-- It's a node, we will use it as a root node to make nodes
nodes = gui.clone_tree(nodes)
end
instance.druid = instance:get_druid(template, nodes) instance.druid = instance:get_druid(template, nodes)
if instance.init then if instance.init then
@ -614,7 +599,7 @@ local lang_text = require("druid.extended.lang_text")
---@param node string|node The_node id or gui.get_node(node_id) ---@param node string|node The_node id or gui.get_node(node_id)
---@param locale_id string|nil Default locale id or text from node as default ---@param locale_id string|nil Default locale id or text from node as default
---@param adjust_type string|nil Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE ---@param adjust_type string|nil Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE
---@return druid.lang_text LangText component ---@return druid.lang_text lang_text component
function M:new_lang_text(node, locale_id, adjust_type) function M:new_lang_text(node, locale_id, adjust_type)
return self:new(lang_text, node, locale_id, adjust_type) return self:new(lang_text, node, locale_id, adjust_type)
end end
@ -625,7 +610,7 @@ local slider = require("druid.extended.slider")
---@param pin_node string|node The_node id or gui.get_node(node_id). ---@param pin_node string|node The_node id or gui.get_node(node_id).
---@param end_pos vector3 The end position of slider ---@param end_pos vector3 The end position of slider
---@param callback function|nil On slider change callback ---@param callback function|nil On slider change callback
---@return druid.slider Slider component ---@return druid.slider slider component
function M:new_slider(pin_node, end_pos, callback) function M:new_slider(pin_node, end_pos, callback)
return self:new(slider, pin_node, end_pos, callback) return self:new(slider, pin_node, end_pos, callback)
end end
@ -636,7 +621,7 @@ local input = require("druid.extended.input")
---@param click_node string|node Button node to enabled input component ---@param click_node string|node Button node to enabled input component
---@param text_node string|node|druid.text Text node what will be changed on user input ---@param text_node string|node|druid.text Text node what will be changed on user input
---@param keyboard_type number|nil Gui keyboard type for input field ---@param keyboard_type number|nil Gui keyboard type for input field
---@return druid.input Input component ---@return druid.input input component
function M:new_input(click_node, text_node, keyboard_type) function M:new_input(click_node, text_node, keyboard_type)
return self:new(input, click_node, text_node, keyboard_type) return self:new(input, click_node, text_node, keyboard_type)
end end
@ -647,7 +632,7 @@ local data_list = require("druid.extended.data_list")
---@param druid_scroll druid.scroll The Scroll instance for Data List component ---@param druid_scroll druid.scroll The Scroll instance for Data List component
---@param druid_grid druid.grid The StaticGrid} or @{DynamicGrid instance for Data List component ---@param druid_grid druid.grid The StaticGrid} or @{DynamicGrid instance for Data List component
---@param create_function function The create function callback(self, data, index, data_list). Function should return (node, [component]) ---@param create_function function The create function callback(self, data, index, data_list). Function should return (node, [component])
---@return druid.data_list DataList component ---@return druid.data_list data_list component
function M:new_data_list(druid_scroll, druid_grid, create_function) function M:new_data_list(druid_scroll, druid_grid, create_function)
return self:new(data_list, druid_scroll, druid_grid, create_function) return self:new(data_list, druid_scroll, druid_grid, create_function)
end end
@ -659,7 +644,7 @@ local timer_component = require("druid.extended.timer")
---@param seconds_from number|nil Start timer value in seconds ---@param seconds_from number|nil Start timer value in seconds
---@param seconds_to number|nil End timer value in seconds ---@param seconds_to number|nil End timer value in seconds
---@param callback function|nil Function on timer end ---@param callback function|nil Function on timer end
---@return druid.timer Timer component ---@return druid.timer timer component
function M:new_timer(node, seconds_from, seconds_to, callback) function M:new_timer(node, seconds_from, seconds_to, callback)
return self:new(timer_component, node, seconds_from, seconds_to, callback) return self:new(timer_component, node, seconds_from, seconds_to, callback)
end end
@ -670,7 +655,7 @@ local progress = require("druid.extended.progress")
---@param node string|node Progress bar fill node or node name ---@param node string|node Progress bar fill node or node name
---@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y ---@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y
---@param init_value number|nil Initial value of progress bar. Default: 1 ---@param init_value number|nil Initial value of progress bar. Default: 1
---@return druid.progress Progress component ---@return druid.progress progress component
function M:new_progress(node, key, init_value) function M:new_progress(node, key, init_value)
return self:new(progress, node, key, init_value) return self:new(progress, node, key, init_value)
end end
@ -680,7 +665,7 @@ local layout = require("druid.extended.layout")
---Create Layout component ---Create Layout component
---@param node string|node The_node id or gui.get_node(node_id). ---@param node string|node The_node id or gui.get_node(node_id).
---@param mode string|nil vertical|horizontal|horizontal_wrap. Default: horizontal ---@param mode string|nil vertical|horizontal|horizontal_wrap. Default: horizontal
---@return druid.layout Layout component ---@return druid.layout layout component
function M:new_layout(node, mode) function M:new_layout(node, mode)
return self:new(layout, node, mode) return self:new(layout, node, mode)
end end
@ -691,7 +676,7 @@ local container = require("druid.extended.container")
---@param node string|node The_node id or gui.get_node(node_id). ---@param node string|node The_node id or gui.get_node(node_id).
---@param mode string|nil Layout mode ---@param mode string|nil Layout mode
---@param callback fun(self: druid.container, size: vector3)|nil Callback on size changed ---@param callback fun(self: druid.container, size: vector3)|nil Callback on size changed
---@return druid.container Container component ---@return druid.container container component
function M:new_container(node, mode, callback) function M:new_container(node, mode, callback)
return self:new(container, node, mode, callback) return self:new(container, node, mode, callback)
end end
@ -702,7 +687,7 @@ local hotkey = require("druid.extended.hotkey")
---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys ---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys
---@param callback function|nil The callback function ---@param callback function|nil The callback function
---@param callback_argument any|nil The argument to pass into the callback function ---@param callback_argument any|nil The argument to pass into the callback function
---@return druid.hotkey Hotkey component ---@return druid.hotkey hotkey component
function M:new_hotkey(keys_array, callback, callback_argument) function M:new_hotkey(keys_array, callback, callback_argument)
return self:new(hotkey, keys_array, callback, callback_argument) return self:new(hotkey, keys_array, callback, callback_argument)
end end

View File

@ -8,7 +8,6 @@ local SIZE_Y = hash("size.y")
function M:init() function M:init()
self.root = self:get_node("root") self.root = self:get_node("root")
self.container = self.druid:new_container(self.root)
self.text_header = self.druid:new_text("text_header") self.text_header = self.druid:new_text("text_header")
self.druid:new_drag("header", self.on_drag_widget) self.druid:new_drag("header", self.on_drag_widget)

View File

@ -37,7 +37,7 @@ nodes {
} }
type: TYPE_TEXT type: TYPE_TEXT
text: "Left Right Selector" text: "Left Right Selector"
font: "text_bold" font: "druid_text_bold"
id: "text_name" id: "text_name"
pivot: PIVOT_W pivot: PIVOT_W
outline { outline {
@ -191,7 +191,7 @@ nodes {
} }
type: TYPE_TEXT type: TYPE_TEXT
text: "42" text: "42"
font: "text_bold" font: "druid_text_bold"
id: "text_value" id: "text_value"
outline { outline {
x: 1.0 x: 1.0

View File

@ -214,8 +214,7 @@ end
---@private ---@private
function M:create_from_prefab(widget_class, widget_name, prefab) function M:create_from_prefab(widget_class, widget_name, prefab)
local nodes = gui.clone_tree(prefab) local instance = self.druid:new_widget(widget_class, widget_name, prefab)
local instance = self.druid:new_widget(widget_class, widget_name, nodes)
self:add_property(instance) self:add_property(instance)
return instance return instance
end end

View File

@ -2,7 +2,7 @@
bob_folder=./ bob_folder=./
# You can point bob version for project in format "filename:sha" # You can point bob version for project in format "filename:sha"
bob_sha="193:e4aaff11f49c941fde1dd93883cf69c6b8abebe4" bob_sha="195:87b6907759f7b8dff830d54b2250b8d721bde291"
# Select Defold channel. Values: stable, beta, alpha # Select Defold channel. Values: stable, beta, alpha
bob_channel="stable" bob_channel="stable"