From 2779f9cf7a9d33d55bfe385bfd6e8137b951bd86 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 5 Apr 2022 18:17:39 +0300 Subject: [PATCH 01/12] Start implement druid layout component --- druid/base/text.lua | 10 +- druid/component.lua | 3 + druid/const.lua | 9 + druid/druid.lua | 6 + druid/extended/lang_text.lua | 1 + druid/extended/layout.lua | 100 +++ druid/extended/progress.lua | 20 +- druid/system/druid_instance.lua | 12 + example/example.collection | 63 ++ example/example.gui_script | 1 + .../examples/general/layout/layout.collection | 37 ++ example/examples/general/layout/layout.gui | 615 ++++++++++++++++++ .../examples/general/layout/layout.gui_script | 32 + 13 files changed, 906 insertions(+), 3 deletions(-) create mode 100644 druid/extended/layout.lua create mode 100644 example/examples/general/layout/layout.collection create mode 100644 example/examples/general/layout/layout.gui create mode 100644 example/examples/general/layout/layout.gui_script diff --git a/druid/base/text.lua b/druid/base/text.lua index 566aba9..8981ccc 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -240,10 +240,16 @@ end -- @treturn number Height function Text.get_text_size(self, text) text = text or self.last_value - local font = gui.get_font(self.node) + local font_name = gui.get_font(self.node) + local font = gui.get_font_resource(font_name) local scale = gui.get_scale(self.node) local linebreak = gui.get_line_break(self.node) - local metrics = gui.get_text_metrics(font, text, 0, linebreak, 0, 0) + local metrics = resource.get_text_metrics(font, text, { + line_break = linebreak, + leading = 1, + tracking = 0, + width = self.start_size.x + }) local width = metrics.width for i = #text, 1, -1 do local c = string.sub(text, i, i) diff --git a/druid/component.lua b/druid/component.lua index e63fecf..02d351a 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -25,6 +25,7 @@ BaseComponent.ON_FOCUS_LOST = const.ON_FOCUS_LOST BaseComponent.ON_FOCUS_GAINED = const.ON_FOCUS_GAINED BaseComponent.ON_LAYOUT_CHANGE = const.ON_LAYOUT_CHANGE BaseComponent.ON_MESSAGE_INPUT = const.ON_MESSAGE_INPUT +BaseComponent.ON_WINDOW_RESIZED = const.ON_WINDOW_RESIZED BaseComponent.ON_LANGUAGE_CHANGE = const.ON_LANGUAGE_CHANGE @@ -37,6 +38,7 @@ BaseComponent.ALL_INTERESTS = { BaseComponent.ON_FOCUS_GAINED, BaseComponent.ON_LAYOUT_CHANGE, BaseComponent.ON_MESSAGE_INPUT, + BaseComponent.ON_WINDOW_RESIZED, BaseComponent.ON_LANGUAGE_CHANGE, } @@ -46,6 +48,7 @@ BaseComponent.SPECIFIC_UI_MESSAGES = { [hash("layout_changed")] = BaseComponent.ON_LAYOUT_CHANGE, -- The message_id from Defold [hash(BaseComponent.ON_FOCUS_LOST)] = BaseComponent.ON_FOCUS_LOST, [hash(BaseComponent.ON_FOCUS_GAINED)] = BaseComponent.ON_FOCUS_GAINED, + [hash(BaseComponent.ON_WINDOW_RESIZED)] = BaseComponent.ON_WINDOW_RESIZED, [hash(BaseComponent.ON_MESSAGE_INPUT)] = BaseComponent.ON_MESSAGE_INPUT, [hash(BaseComponent.ON_LANGUAGE_CHANGE)] = BaseComponent.ON_LANGUAGE_CHANGE, } diff --git a/druid/const.lua b/druid/const.lua index c40fc58..3e8c0d9 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -40,6 +40,7 @@ M.ON_FOCUS_LOST = "on_focus_lost" M.ON_FOCUS_GAINED = "on_focus_gained" M.ON_LAYOUT_CHANGE = "on_layout_change" M.ON_MESSAGE_INPUT = "on_message_input" +M.ON_WINDOW_RESIZED = "on_window_resized" M.ON_LANGUAGE_CHANGE = "on_language_change" @@ -83,6 +84,14 @@ M.REVERSE_PIVOTS = { } +M.LAYOUT_MODE = { + STRETCH_X = "stretch_x", + STRETCH_Y = "stretch_y", + FIT = gui.ADJUST_FIT, + STRETCH = gui.ADJUST_STRETCH, +} + + M.VECTOR_ZERO = vmath.vector3(0) M.VECTOR_ONE = vmath.vector3(1) M.SYS_INFO = sys.get_sys_info() diff --git a/druid/druid.lua b/druid/druid.lua index ed5303f..44f13c6 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -117,6 +117,12 @@ function M.on_window_callback(event) msg.post(instances[i].url, base_component.ON_FOCUS_GAINED) end end + + if event == window.WINDOW_EVENT_RESIZED then + for i = 1, #instances do + msg.post(instances[i].url, base_component.ON_WINDOW_RESIZED) + end + end end diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index f30b48a..f78b70b 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -14,6 +14,7 @@ --- +local const = require("druid.const") local Event = require("druid.event") local settings = require("druid.system.settings") local component = require("druid.component") diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua new file mode 100644 index 0000000..37963f0 --- /dev/null +++ b/druid/extended/layout.lua @@ -0,0 +1,100 @@ +-- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license + +--- Layout management on node +-- @module Layout +-- @within BaseComponent +-- @alias druid.layout + +--- + + +local const = require("druid.const") +local helper = require("druid.helper") +local component = require("druid.component") +local Event = require("druid.event") + +---@class layout : druid.base_component +local Layout = component.create("layout") + + +function Layout:init(node, mode, on_size_changed_callback) + self.node = self:get_node(node) + self.origin_size = gui.get_size(self.node) + self.pivot = helper.get_pivot_offset(gui.get_pivot(self.node)) + self.origin_position = gui.get_position(self.node) + self.position = vmath.vector3(self.origin_position) + + gui.set_size_mode(self.node, gui.SIZE_MODE_MANUAL) + gui.set_adjust_mode(self.node, gui.ADJUST_FIT) + + self._min_size = nil + self._max_size = nil + + self.window_size = vmath.vector3(gui.get_width(), gui.get_height(), 0) + self.mode = mode or const.LAYOUT_MODE.FIT + + self.on_size_changed = Event(on_size_changed_callback) + + self:on_window_resized() +end + + +function Layout:on_window_resized() + local window_x, window_y = window.get_size() + local stretch_x = window_x / self.window_size.x + local stretch_y = window_y / self.window_size.y + + local x_koef = stretch_x / math.min(stretch_x, stretch_y) + local y_koef = stretch_y / math.min(stretch_x, stretch_y) + + local new_size = vmath.vector3(self.origin_size) + if self.mode == const.LAYOUT_MODE.STRETCH_X or self.mode == const.LAYOUT_MODE.STRETCH then + new_size.x = new_size.x * x_koef + end + if self.mode == const.LAYOUT_MODE.STRETCH_Y or self.mode == const.LAYOUT_MODE.STRETCH then + new_size.y = new_size.y * y_koef + end + if self._min_size then + new_size.x = math.max(new_size.x, self._min_size.x) + new_size.y = math.max(new_size.y, self._min_size.y) + end + if self._max_size then + new_size.x = math.min(new_size.x, self._max_size.x) + new_size.y = math.min(new_size.y, self._max_size.y) + end + + gui.set_size(self.node, new_size) + + self.position.x = self.origin_position.x * x_koef + self.origin_position.x * (1 - x_koef) * self.pivot.x * 2 + self.position.y = self.origin_position.y * y_koef + self.origin_position.y * (1 - y_koef) * self.pivot.y * 2 + gui.set_position(self.node, self.position) + + self.on_size_changed:trigger(self:get_context(), new_size) +end + + +function Layout:set_min_size(min_size) + self._min_size = min_size + return self +end + + +function Layout:set_max_size(max_size) + self._max_size = max_size + return self +end + + +function Layout:set_origin_position(new_origin_position) + self.origin_position = new_origin_position or self.origin_position + return self +end + + +function Layout:set_origin_size(new_origin_size) + self.origin_size = new_origin_size or self.origin_size + return self +end + + +return Layout diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index 1ebe6e7..509e57b 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -103,11 +103,14 @@ function Progress.init(self, node, key, init_value) self.prop = hash("scale."..key) self.key = key + self._init_value = init_value or 1 self.node = self:get_node(node) self.scale = gui.get_scale(self.node) self.size = gui.get_size(self.node) self.max_size = self.size[self.key] self.slice = gui.get_slice9(self.node) + self.last_value = self._init_value + if key == const.SIDE.X then self.slice_size = self.slice.x + self.slice.z else @@ -115,8 +118,12 @@ function Progress.init(self, node, key, init_value) end self.on_change = Event() +end - self:set_to(init_value or 1) + +-- @tparam Progress self @{Progress} +function Progress.on_late_init(self) + self:set_to(self._init_value) end @@ -204,4 +211,15 @@ function Progress.to(self, to, callback) end +--- Set progress bar max node size +-- @tparam Progress self @{Progress} +-- @tparam vector3 max_size The new node maximum (full) size +-- @treturn Progress @{Progress} +function Progress:set_max_size(max_size) + self.max_size = max_size[self.key] + self:set_to(self.last_value) + return self +end + + return Progress diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index dea1439..e286e78 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -30,6 +30,7 @@ -- @see Drag -- @see DataList -- @see Hover +-- @see Layout local helper = require("druid.helper") local class = require("druid.system.middleclass") @@ -57,6 +58,7 @@ local radio_group = require("druid.extended.radio_group") local slider = require("druid.extended.slider") local timer = require("druid.extended.timer") local data_list = require("druid.extended.data_list") +local layout = require("druid.extended.layout") local DruidInstance = class("druid.druid_instance") @@ -738,4 +740,14 @@ function DruidInstance.new_progress(self, node, key, init_value) end +--- Create layout component +-- @tparam DruidInstance self +-- @tparam string|node node Layout node +-- @tparam string mode The layout mode +-- @treturn Layout layout component +function DruidInstance.new_layout(self, node, mode) + return helper.extended_component("layout") +end + + return DruidInstance diff --git a/example/example.collection b/example/example.collection index 3e861b0..fd4aca8 100644 --- a/example/example.collection +++ b/example/example.collection @@ -1688,3 +1688,66 @@ embedded_instances { z: 1.0 } } +embedded_instances { + id: "general_layout" + data: "components {\n" + " id: \"screen_factory\"\n" + " component: \"/monarch/screen_factory.script\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + " properties {\n" + " id: \"screen_id\"\n" + " value: \"general_layout\"\n" + " type: PROPERTY_TYPE_HASH\n" + " }\n" + " properties {\n" + " id: \"popup\"\n" + " value: \"true\"\n" + " type: PROPERTY_TYPE_BOOLEAN\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"collectionfactory\"\n" + " type: \"collectionfactory\"\n" + " data: \"prototype: \\\"/example/examples/general/layout/layout.collection\\\"\\n" + "load_dynamically: false\\n" + "\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/example/example.gui_script b/example/example.gui_script index 2af7cad..138172f 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -130,6 +130,7 @@ local function init_lobby(self) self.lobby_grid:add(get_button(self, "Data List", "general_data_list", "/general/data_list/data_list.gui_script")) self.lobby_grid:add(get_button(self, "Checkboxes", "general_checkboxes", "/general/checkboxes/checkboxes.gui_script")) self.lobby_grid:add(get_button(self, "Input text", "general_input", "/general/input/input.gui_script")) + self.lobby_grid:add(get_button(self, "Layout", "general_layout", "/general/layout/layout.gui_script")) self.lobby_grid:add(get_button(self, "Swipe", "general_swipe", "/general/swipe/swipe.gui_script")) self.lobby_grid:add(get_button(self, "Drag", "general_drag", "/general/drag/drag.gui_script")) diff --git a/example/examples/general/layout/layout.collection b/example/examples/general/layout/layout.collection new file mode 100644 index 0000000..3269796 --- /dev/null +++ b/example/examples/general/layout/layout.collection @@ -0,0 +1,37 @@ +name: "layout" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"layout\"\n" + " component: \"/example/examples/general/layout/layout.gui\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/example/examples/general/layout/layout.gui b/example/examples/general/layout/layout.gui new file mode 100644 index 0000000..f157508 --- /dev/null +++ b/example/examples/general/layout/layout.gui @@ -0,0 +1,615 @@ +script: "/example/examples/general/layout/layout.gui_script" +fonts { + name: "game" + font: "/example/assets/fonts/game.font" +} +textures { + name: "kenney" + texture: "/example/assets/images/kenney.atlas" +} +background_color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 +} +nodes { + position { + x: 300.0 + y: 415.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 600.0 + y: 830.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "root" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 200.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_stretch" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Regular Stretch Mode" + font: "game" + id: "text_regular" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "node_stretch" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 1.0 + y: 1.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "even_in_fit_node" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_AUTO + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 50.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "even_in_fit_node" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch" + font: "game" + id: "text_layout_stretch" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "node_layout_stretch" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: -100.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch_x" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "even_in_fit_node" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch by X" + font: "game" + id: "text_layout_stretch1" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "node_layout_stretch_x" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: -250.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch_y" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "even_in_fit_node" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch by Y" + font: "game" + id: "text_layout_stretch2" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "node_layout_stretch_y" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +layers { + name: "image" +} +layers { + name: "text" +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT +max_nodes: 512 diff --git a/example/examples/general/layout/layout.gui_script b/example/examples/general/layout/layout.gui_script new file mode 100644 index 0000000..bce9c3c --- /dev/null +++ b/example/examples/general/layout/layout.gui_script @@ -0,0 +1,32 @@ +local druid = require("druid.druid") +local const_druid = require("druid.const") +local layout = require("druid.extended.layout") + +function init(self) + druid.register("layout", layout) + self.druid = druid.new(self) + + self.druid:new_layout("node_layout_stretch", const_druid.LAYOUT_MODE.STRETCH) + self.druid:new_layout("node_layout_stretch_x", const_druid.LAYOUT_MODE.STRETCH_X) + self.druid:new_layout("node_layout_stretch_y", const_druid.LAYOUT_MODE.STRETCH_Y) +end + + +function final(self) + self.druid:final() +end + + +function update(self, dt) + self.druid:update(dt) +end + + +function on_message(self, message_id, message, sender) + self.druid:on_message(message_id, message, sender) +end + + +function on_input(self, action_id, action) + return self.druid:on_input(action_id, action) +end From dff522fbaa8775ed983f6a2b83409addef7d112d Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 5 Apr 2022 18:57:40 +0300 Subject: [PATCH 02/12] Solve #182 add table pool for events --- druid/base/back_handler.lua | 6 +++ druid/base/button.lua | 11 +++++ druid/base/drag.lua | 10 +++++ druid/base/hover.lua | 7 +++ druid/base/scroll.lua | 8 ++++ druid/base/static_grid.lua | 10 +++++ druid/base/swipe.lua | 6 +++ druid/base/text.lua | 8 ++++ druid/component.lua | 6 +++ druid/const.lua | 2 + druid/event.lua | 22 ++++++--- druid/extended/checkbox.lua | 6 +++ druid/extended/checkbox_group.lua | 7 +++ druid/extended/data_list.lua | 6 +++ druid/extended/dynamic_grid.lua | 10 +++++ druid/extended/input.lua | 11 +++++ druid/extended/lang_text.lua | 6 +++ druid/extended/layout.lua | 6 +++ druid/extended/progress.lua | 6 +++ druid/extended/radio_group.lua | 6 +++ druid/extended/slider.lua | 6 +++ druid/extended/timer.lua | 8 ++++ druid/system/druid_instance.lua | 1 + druid/system/tablepool.lua | 75 +++++++++++++++++++++++++++++++ 24 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 druid/system/tablepool.lua diff --git a/druid/base/back_handler.lua b/druid/base/back_handler.lua index a97c7d8..e3e19c8 100644 --- a/druid/base/back_handler.lua +++ b/druid/base/back_handler.lua @@ -30,6 +30,12 @@ function BackHandler.init(self, callback, params) end +function BackHandler.on_internal_remove(self) + component.on_internal_remove(self) + self.on_back:clear() +end + + --- Input handler for component -- @tparam BackHandler self @{BackHandler} -- @tparam string action_id on_input action id diff --git a/druid/base/button.lua b/druid/base/button.lua index 61c4db2..fe41c4d 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -239,6 +239,17 @@ function Button.on_late_init(self) end +function Button.on_internal_remove(self) + component.on_internal_remove(self) + self.on_click:clear() + self.on_repeated_click:clear() + self.on_long_click:clear() + self.on_double_click:clear() + self.on_hold_callback:clear() + self.on_click_outside:clear() +end + + function Button.on_input(self, action_id, action) if not is_input_match(self, action_id) then return false diff --git a/druid/base/drag.lua b/druid/base/drag.lua index b51c1af..c9c2e98 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -189,6 +189,16 @@ function Drag.init(self, node, on_drag_callback) end +function Drag.on_internal_remove(self) + component.on_internal_remove(self) + self.on_touch_start:clear() + self.on_touch_end:clear() + self.on_drag_start:clear() + self.on_drag:clear() + self.on_drag_end:clear() +end + + function Drag.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/hover.lua b/druid/base/hover.lua index 05aa0ac..9c71b18 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -38,6 +38,13 @@ function Hover.init(self, node, on_hover_callback) end +function Hover.on_internal_remove(self) + component.on_internal_remove(self) + self.on_hover:clear() + self.on_mouse_hover:clear() +end + + function Hover.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 01fbdd4..796335f 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -174,6 +174,14 @@ function Scroll.init(self, view_node, content_node) end +function Scroll.on_internal_remove(self) + component.on_internal_remove(self) + self.on_scroll:clear() + self.on_scroll_to:clear() + self.on_point_scroll:clear() +end + + function Scroll.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index c32d4c0..30f47ce 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -115,6 +115,16 @@ function StaticGrid.init(self, parent, element, in_row) end +function StaticGrid.on_internal_remove(self) + component.on_internal_remove(self) + self.on_add_item:clear() + self.on_remove_item:clear() + self.on_change_items:clear() + self.on_clear:clear() + self.on_update_positions:clear() +end + + local _temp_pos = vmath.vector3(0) --- Return pos for grid node index -- @tparam StaticGrid self @{StaticGrid} diff --git a/druid/base/swipe.lua b/druid/base/swipe.lua index d4ecc27..69e9b3a 100644 --- a/druid/base/swipe.lua +++ b/druid/base/swipe.lua @@ -99,6 +99,12 @@ function Swipe.init(self, node, on_swipe_callback) end +function Swipe.on_internal_remove(self) + component.on_internal_remove(self) + self.on_swipe:clear() +end + + function Swipe.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/text.lua b/druid/base/text.lua index 8981ccc..13ce80d 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -217,6 +217,14 @@ function Text.init(self, node, value, adjust_type) end +function Text.on_internal_remove(self) + component.on_internal_remove(self) + self.on_set_text:clear() + self.on_set_pivot:clear() + self.on_update_text_scale:clear() +end + + function Text.on_layout_change(self) self:set_to(self.last_value) end diff --git a/druid/component.lua b/druid/component.lua index 02d351a..6374344 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -8,6 +8,7 @@ local const = require("druid.const") local class = require("druid.system.middleclass") local helper = require("druid.helper") +local tablepool = require("druid.system.tablepool") local BaseComponent = class("druid.component") @@ -348,6 +349,11 @@ function BaseComponent.set_debug(self, is_debug) end +--- On remove method on druid:remove or druid:final (protected) +function BaseComponent:on_internal_remove() +end + + --- Return true, if input priority was changed -- @tparam BaseComponent self @{BaseComponent} -- @local diff --git a/druid/const.lua b/druid/const.lua index 3e8c0d9..2d23a60 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -7,6 +7,8 @@ local M = {} +M.POOL_ID = "druid_table_pool" + M.ACTION_TEXT = hash(sys.get_config("druid.input_text", "text")) M.ACTION_TOUCH = hash(sys.get_config("druid.input_touch", "touch")) M.ACTION_MARKED_TEXT = hash(sys.get_config("druid.input_marked_text", "marked_text")) diff --git a/druid/event.lua b/druid/event.lua index e540de8..11bc2f3 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -5,6 +5,8 @@ -- @alias druid.event local class = require("druid.system.middleclass") +local const = require("druid.const") +local tablepool = require("druid.system.tablepool") local DruidEvent = class("druid.event") @@ -29,11 +31,12 @@ function DruidEvent.subscribe(self, callback, context) assert(type(self) == "table", "You should subscribe to event with : syntax") assert(type(callback) == "function", "Callback should be function") - self._callbacks = self._callbacks or {} - table.insert(self._callbacks, { - callback = callback, - context = context - }) + self._callbacks = self._callbacks or tablepool.fetch(const.POOL_ID) + local callback_table = tablepool.fetch(const.POOL_ID, 0, 2) + callback_table.callback = callback + callback_table.context = context + + table.insert(self._callbacks, callback_table) return callback end @@ -50,6 +53,7 @@ function DruidEvent.unsubscribe(self, callback, context) for index, callback_info in ipairs(self._callbacks) do if callback_info.callback == callback and callback_info.context == context then + tablepool.release(self._callbacks[index]) table.remove(self._callbacks, index) return end @@ -71,6 +75,12 @@ end --- Clear the all event handlers -- @tparam DruidEvent self @{DruidEvent} function DruidEvent.clear(self) + if self._callbacks then + for index = #self._callbacks, 1, -1 do + tablepool.release(self._callbacks[index]) + end + end + tablepool.release(self._callbacks) self._callbacks = nil end @@ -83,7 +93,7 @@ function DruidEvent.trigger(self, ...) return false end - for index, callback_info in ipairs(self._callbacks) do + for _, callback_info in ipairs(self._callbacks) do if callback_info.context then callback_info.callback(callback_info.context, ...) else diff --git a/druid/extended/checkbox.lua b/druid/extended/checkbox.lua index ef1b295..f7d4c82 100755 --- a/druid/extended/checkbox.lua +++ b/druid/extended/checkbox.lua @@ -67,6 +67,12 @@ function Checkbox.on_layout_change(self) end +function Checkbox.on_internal_remove(self) + component.on_internal_remove(self) + self.on_change_state:clear() +end + + --- Set checkbox state -- @tparam Checkbox self @{Checkbox} -- @tparam bool state Checkbox state diff --git a/druid/extended/checkbox_group.lua b/druid/extended/checkbox_group.lua index 2ca9561..493e5ab 100644 --- a/druid/extended/checkbox_group.lua +++ b/druid/extended/checkbox_group.lua @@ -41,6 +41,13 @@ function CheckboxGroup.init(self, nodes, callback, click_nodes) end +function CheckboxGroup.on_internal_remove(self) + component.on_internal_remove(self) + self.on_checkbox_click:clear() +end + + + --- Set checkbox group state -- @tparam CheckboxGroup self @{CheckboxGroup} -- @tparam bool[] indexes Array of checkbox state diff --git a/druid/extended/data_list.lua b/druid/extended/data_list.lua index e8e95c6..05f21e6 100644 --- a/druid/extended/data_list.lua +++ b/druid/extended/data_list.lua @@ -76,6 +76,12 @@ function DataList.on_remove(self) end +function DataList.on_internal_remove(self) + component.on_internal_remove(self) + self.on_scroll_progress_change:clear() +end + + --- Set new data set for DataList component -- @tparam DataList self @{DataList} -- @tparam table data The new data array diff --git a/druid/extended/dynamic_grid.lua b/druid/extended/dynamic_grid.lua index 0593715..a9da0ae 100644 --- a/druid/extended/dynamic_grid.lua +++ b/druid/extended/dynamic_grid.lua @@ -89,6 +89,16 @@ function DynamicGrid.init(self, parent) end +function DynamicGrid.on_internal_remove(self) + component.on_internal_remove(self) + self.on_add_item:clear() + self.on_remove_item:clear() + self.on_change_items:clear() + self.on_clear:clear() + self.on_update_positions:clear() +end + + function DynamicGrid.on_layout_change(self) self:_update(true) end diff --git a/druid/extended/input.lua b/druid/extended/input.lua index d463871..d8f43b3 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -154,6 +154,17 @@ function Input.init(self, click_node, text_node, keyboard_type) end +function Input.on_internal_remove(self) + component.on_internal_remove(self) + self.on_input_select:clear() + self.on_input_unselect:clear() + self.on_input_text:clear() + self.on_input_empty:clear() + self.on_input_full:clear() + self.on_input_wrong:clear() +end + + function Input.on_input(self, action_id, action) if self.is_selected then local input_text = nil diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index f78b70b..fec0c7d 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -41,6 +41,12 @@ function LangText.init(self, node, locale_id, no_adjust) end +function LangText.on_internal_remove(self) + component.on_internal_remove(self) + self.on_change:clear() +end + + function LangText.on_language_change(self) if self.last_locale then self:translate(self.last_locale, unpack(self.last_locale_args)) diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 37963f0..719e2ae 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -39,6 +39,12 @@ function Layout:init(node, mode, on_size_changed_callback) end +function Layout.on_internal_remove(self) + component.on_internal_remove(self) + self.on_size_changed:clear() +end + + function Layout:on_window_resized() local window_x, window_y = window.get_size() local stretch_x = window_x / self.window_size.x diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index 509e57b..99ef6b2 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -121,6 +121,12 @@ function Progress.init(self, node, key, init_value) end +function Progress.on_internal_remove(self) + component.on_internal_remove(self) + self.on_change:clear() +end + + -- @tparam Progress self @{Progress} function Progress.on_late_init(self) self:set_to(self._init_value) diff --git a/druid/extended/radio_group.lua b/druid/extended/radio_group.lua index fef1d00..768959d 100644 --- a/druid/extended/radio_group.lua +++ b/druid/extended/radio_group.lua @@ -50,6 +50,12 @@ function RadioGroup.init(self, nodes, callback, click_nodes) end +function RadioGroup.on_internal_remove(self) + component.on_internal_remove(self) + self.on_radio_click:clear() +end + + --- Set radio group state -- @tparam RadioGroup self @{RadioGroup} -- @tparam number index Index in radio group diff --git a/druid/extended/slider.lua b/druid/extended/slider.lua index 4a8c90c..ea5470b 100644 --- a/druid/extended/slider.lua +++ b/druid/extended/slider.lua @@ -77,6 +77,12 @@ function Slider.init(self, node, end_pos, callback) end +function Slider.on_internal_remove(self) + component.on_internal_remove(self) + self.on_change_value:clear() +end + + function Slider.on_layout_change(self) self:set(self.value) end diff --git a/druid/extended/timer.lua b/druid/extended/timer.lua index 21ac56b..e31bdb7 100644 --- a/druid/extended/timer.lua +++ b/druid/extended/timer.lua @@ -65,6 +65,14 @@ function Timer.init(self, node, seconds_from, seconds_to, callback) end +function Timer.on_internal_remove(self) + component.on_internal_remove(self) + self.on_tick:clear() + self.on_set_enabled:clear() + self.on_timer_end:clear() +end + + function Timer.update(self, dt) if not self.is_on then return diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index e286e78..d2f2c99 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -289,6 +289,7 @@ function DruidInstance.remove(self, component) local all_components = self.components_all for i = #all_components, 1, -1 do if all_components[i] == component then + component:on_internal_remove() if component.on_remove then component:on_remove() end diff --git a/druid/system/tablepool.lua b/druid/system/tablepool.lua new file mode 100644 index 0000000..2c8a803 --- /dev/null +++ b/druid/system/tablepool.lua @@ -0,0 +1,75 @@ +-- Source: https://github.com/openresty/lua-tablepool/blob/master/lib/tablepool.lua + +local setmetatable = setmetatable + +local _M = {} +local max_pool_size = 500 +local pools = {} + + +function _M.fetch(tag) + local pool = pools[tag] + if not pool then + pool = {} + pools[tag] = pool + pool.c = 0 + pool[0] = 0 + + else + local len = pool[0] + if len > 0 then + local obj = pool[len] + pool[len] = nil + pool[0] = len - 1 + return obj + end + end + + return {} +end + + +function _M.release(tag, obj, noclear) + if not obj then + error("object empty", 2) + end + + local pool = pools[tag] + if not pool then + pool = {} + pools[tag] = pool + pool.c = 0 + pool[0] = 0 + end + + if not noclear then + setmetatable(obj, nil) + for k in pairs(obj) do + obj[k] = nil + end + end + + do + local cnt = pool.c + 1 + if cnt >= 20000 then + pool = {} + pools[tag] = pool + pool.c = 0 + pool[0] = 0 + return + end + pool.c = cnt + end + + local len = pool[0] + 1 + if len > max_pool_size then + -- discard it simply + return + end + + pool[len] = obj + pool[0] = len +end + + +return _M From 70e94ec14a6e01e48526d96656f8c22cf19d4a0d Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 5 Apr 2022 19:20:03 +0300 Subject: [PATCH 03/12] Fix event table pool --- druid/event.lua | 17 ++++++++++------- druid/system/druid_instance.lua | 1 + druid/system/tablepool.lua | 1 - 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/druid/event.lua b/druid/event.lua index 11bc2f3..ed78904 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -32,7 +32,8 @@ function DruidEvent.subscribe(self, callback, context) assert(type(callback) == "function", "Callback should be function") self._callbacks = self._callbacks or tablepool.fetch(const.POOL_ID) - local callback_table = tablepool.fetch(const.POOL_ID, 0, 2) + + local callback_table = tablepool.fetch(const.POOL_ID) callback_table.callback = callback callback_table.context = context @@ -53,7 +54,7 @@ function DruidEvent.unsubscribe(self, callback, context) for index, callback_info in ipairs(self._callbacks) do if callback_info.callback == callback and callback_info.context == context then - tablepool.release(self._callbacks[index]) + tablepool.release(const.POOL_ID, callback_info) table.remove(self._callbacks, index) return end @@ -75,12 +76,14 @@ end --- Clear the all event handlers -- @tparam DruidEvent self @{DruidEvent} function DruidEvent.clear(self) - if self._callbacks then - for index = #self._callbacks, 1, -1 do - tablepool.release(self._callbacks[index]) - end + if not self._callbacks then + return end - tablepool.release(self._callbacks) + + for index = #self._callbacks, 1, -1 do + tablepool.release(const.POOL_ID, self._callbacks[index]) + end + tablepool.release(const.POOL_ID, self._callbacks) self._callbacks = nil end diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index d2f2c99..9b97842 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -252,6 +252,7 @@ function DruidInstance.final(self) local components = self.components_all for i = #components, 1, -1 do + components[i]:on_internal_remove() if components[i].on_remove then components[i]:on_remove() end diff --git a/druid/system/tablepool.lua b/druid/system/tablepool.lua index 2c8a803..616a86d 100644 --- a/druid/system/tablepool.lua +++ b/druid/system/tablepool.lua @@ -14,7 +14,6 @@ function _M.fetch(tag) pools[tag] = pool pool.c = 0 pool[0] = 0 - else local len = pool[0] if len > 0 then From f7e6888c5a46910686389082921030d95741a951 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 5 Apr 2022 23:18:39 +0300 Subject: [PATCH 04/12] Revert "Solve #182 add table pool for events" This reverts commit dff522fbaa8775ed983f6a2b83409addef7d112d. --- druid/base/back_handler.lua | 6 --- druid/base/button.lua | 11 ----- druid/base/drag.lua | 10 ----- druid/base/hover.lua | 7 --- druid/base/scroll.lua | 8 ---- druid/base/static_grid.lua | 10 ----- druid/base/swipe.lua | 6 --- druid/base/text.lua | 8 ---- druid/component.lua | 6 --- druid/const.lua | 2 - druid/event.lua | 25 +++-------- druid/extended/checkbox.lua | 6 --- druid/extended/checkbox_group.lua | 7 --- druid/extended/data_list.lua | 6 --- druid/extended/dynamic_grid.lua | 10 ----- druid/extended/input.lua | 11 ----- druid/extended/lang_text.lua | 6 --- druid/extended/layout.lua | 6 --- druid/extended/progress.lua | 6 --- druid/extended/radio_group.lua | 6 --- druid/extended/slider.lua | 6 --- druid/extended/timer.lua | 8 ---- druid/system/druid_instance.lua | 2 - druid/system/tablepool.lua | 74 ------------------------------- 24 files changed, 6 insertions(+), 247 deletions(-) delete mode 100644 druid/system/tablepool.lua diff --git a/druid/base/back_handler.lua b/druid/base/back_handler.lua index e3e19c8..a97c7d8 100644 --- a/druid/base/back_handler.lua +++ b/druid/base/back_handler.lua @@ -30,12 +30,6 @@ function BackHandler.init(self, callback, params) end -function BackHandler.on_internal_remove(self) - component.on_internal_remove(self) - self.on_back:clear() -end - - --- Input handler for component -- @tparam BackHandler self @{BackHandler} -- @tparam string action_id on_input action id diff --git a/druid/base/button.lua b/druid/base/button.lua index fe41c4d..61c4db2 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -239,17 +239,6 @@ function Button.on_late_init(self) end -function Button.on_internal_remove(self) - component.on_internal_remove(self) - self.on_click:clear() - self.on_repeated_click:clear() - self.on_long_click:clear() - self.on_double_click:clear() - self.on_hold_callback:clear() - self.on_click_outside:clear() -end - - function Button.on_input(self, action_id, action) if not is_input_match(self, action_id) then return false diff --git a/druid/base/drag.lua b/druid/base/drag.lua index c9c2e98..b51c1af 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -189,16 +189,6 @@ function Drag.init(self, node, on_drag_callback) end -function Drag.on_internal_remove(self) - component.on_internal_remove(self) - self.on_touch_start:clear() - self.on_touch_end:clear() - self.on_drag_start:clear() - self.on_drag:clear() - self.on_drag_end:clear() -end - - function Drag.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/hover.lua b/druid/base/hover.lua index 9c71b18..05aa0ac 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -38,13 +38,6 @@ function Hover.init(self, node, on_hover_callback) end -function Hover.on_internal_remove(self) - component.on_internal_remove(self) - self.on_hover:clear() - self.on_mouse_hover:clear() -end - - function Hover.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 796335f..01fbdd4 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -174,14 +174,6 @@ function Scroll.init(self, view_node, content_node) end -function Scroll.on_internal_remove(self) - component.on_internal_remove(self) - self.on_scroll:clear() - self.on_scroll_to:clear() - self.on_point_scroll:clear() -end - - function Scroll.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 30f47ce..c32d4c0 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -115,16 +115,6 @@ function StaticGrid.init(self, parent, element, in_row) end -function StaticGrid.on_internal_remove(self) - component.on_internal_remove(self) - self.on_add_item:clear() - self.on_remove_item:clear() - self.on_change_items:clear() - self.on_clear:clear() - self.on_update_positions:clear() -end - - local _temp_pos = vmath.vector3(0) --- Return pos for grid node index -- @tparam StaticGrid self @{StaticGrid} diff --git a/druid/base/swipe.lua b/druid/base/swipe.lua index 69e9b3a..d4ecc27 100644 --- a/druid/base/swipe.lua +++ b/druid/base/swipe.lua @@ -99,12 +99,6 @@ function Swipe.init(self, node, on_swipe_callback) end -function Swipe.on_internal_remove(self) - component.on_internal_remove(self) - self.on_swipe:clear() -end - - function Swipe.on_late_init(self) if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) diff --git a/druid/base/text.lua b/druid/base/text.lua index 13ce80d..8981ccc 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -217,14 +217,6 @@ function Text.init(self, node, value, adjust_type) end -function Text.on_internal_remove(self) - component.on_internal_remove(self) - self.on_set_text:clear() - self.on_set_pivot:clear() - self.on_update_text_scale:clear() -end - - function Text.on_layout_change(self) self:set_to(self.last_value) end diff --git a/druid/component.lua b/druid/component.lua index 6374344..02d351a 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -8,7 +8,6 @@ local const = require("druid.const") local class = require("druid.system.middleclass") local helper = require("druid.helper") -local tablepool = require("druid.system.tablepool") local BaseComponent = class("druid.component") @@ -349,11 +348,6 @@ function BaseComponent.set_debug(self, is_debug) end ---- On remove method on druid:remove or druid:final (protected) -function BaseComponent:on_internal_remove() -end - - --- Return true, if input priority was changed -- @tparam BaseComponent self @{BaseComponent} -- @local diff --git a/druid/const.lua b/druid/const.lua index 2d23a60..3e8c0d9 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -7,8 +7,6 @@ local M = {} -M.POOL_ID = "druid_table_pool" - M.ACTION_TEXT = hash(sys.get_config("druid.input_text", "text")) M.ACTION_TOUCH = hash(sys.get_config("druid.input_touch", "touch")) M.ACTION_MARKED_TEXT = hash(sys.get_config("druid.input_marked_text", "marked_text")) diff --git a/druid/event.lua b/druid/event.lua index ed78904..e540de8 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -5,8 +5,6 @@ -- @alias druid.event local class = require("druid.system.middleclass") -local const = require("druid.const") -local tablepool = require("druid.system.tablepool") local DruidEvent = class("druid.event") @@ -31,13 +29,11 @@ function DruidEvent.subscribe(self, callback, context) assert(type(self) == "table", "You should subscribe to event with : syntax") assert(type(callback) == "function", "Callback should be function") - self._callbacks = self._callbacks or tablepool.fetch(const.POOL_ID) - - local callback_table = tablepool.fetch(const.POOL_ID) - callback_table.callback = callback - callback_table.context = context - - table.insert(self._callbacks, callback_table) + self._callbacks = self._callbacks or {} + table.insert(self._callbacks, { + callback = callback, + context = context + }) return callback end @@ -54,7 +50,6 @@ function DruidEvent.unsubscribe(self, callback, context) for index, callback_info in ipairs(self._callbacks) do if callback_info.callback == callback and callback_info.context == context then - tablepool.release(const.POOL_ID, callback_info) table.remove(self._callbacks, index) return end @@ -76,14 +71,6 @@ end --- Clear the all event handlers -- @tparam DruidEvent self @{DruidEvent} function DruidEvent.clear(self) - if not self._callbacks then - return - end - - for index = #self._callbacks, 1, -1 do - tablepool.release(const.POOL_ID, self._callbacks[index]) - end - tablepool.release(const.POOL_ID, self._callbacks) self._callbacks = nil end @@ -96,7 +83,7 @@ function DruidEvent.trigger(self, ...) return false end - for _, callback_info in ipairs(self._callbacks) do + for index, callback_info in ipairs(self._callbacks) do if callback_info.context then callback_info.callback(callback_info.context, ...) else diff --git a/druid/extended/checkbox.lua b/druid/extended/checkbox.lua index f7d4c82..ef1b295 100755 --- a/druid/extended/checkbox.lua +++ b/druid/extended/checkbox.lua @@ -67,12 +67,6 @@ function Checkbox.on_layout_change(self) end -function Checkbox.on_internal_remove(self) - component.on_internal_remove(self) - self.on_change_state:clear() -end - - --- Set checkbox state -- @tparam Checkbox self @{Checkbox} -- @tparam bool state Checkbox state diff --git a/druid/extended/checkbox_group.lua b/druid/extended/checkbox_group.lua index 493e5ab..2ca9561 100644 --- a/druid/extended/checkbox_group.lua +++ b/druid/extended/checkbox_group.lua @@ -41,13 +41,6 @@ function CheckboxGroup.init(self, nodes, callback, click_nodes) end -function CheckboxGroup.on_internal_remove(self) - component.on_internal_remove(self) - self.on_checkbox_click:clear() -end - - - --- Set checkbox group state -- @tparam CheckboxGroup self @{CheckboxGroup} -- @tparam bool[] indexes Array of checkbox state diff --git a/druid/extended/data_list.lua b/druid/extended/data_list.lua index 05f21e6..e8e95c6 100644 --- a/druid/extended/data_list.lua +++ b/druid/extended/data_list.lua @@ -76,12 +76,6 @@ function DataList.on_remove(self) end -function DataList.on_internal_remove(self) - component.on_internal_remove(self) - self.on_scroll_progress_change:clear() -end - - --- Set new data set for DataList component -- @tparam DataList self @{DataList} -- @tparam table data The new data array diff --git a/druid/extended/dynamic_grid.lua b/druid/extended/dynamic_grid.lua index a9da0ae..0593715 100644 --- a/druid/extended/dynamic_grid.lua +++ b/druid/extended/dynamic_grid.lua @@ -89,16 +89,6 @@ function DynamicGrid.init(self, parent) end -function DynamicGrid.on_internal_remove(self) - component.on_internal_remove(self) - self.on_add_item:clear() - self.on_remove_item:clear() - self.on_change_items:clear() - self.on_clear:clear() - self.on_update_positions:clear() -end - - function DynamicGrid.on_layout_change(self) self:_update(true) end diff --git a/druid/extended/input.lua b/druid/extended/input.lua index d8f43b3..d463871 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -154,17 +154,6 @@ function Input.init(self, click_node, text_node, keyboard_type) end -function Input.on_internal_remove(self) - component.on_internal_remove(self) - self.on_input_select:clear() - self.on_input_unselect:clear() - self.on_input_text:clear() - self.on_input_empty:clear() - self.on_input_full:clear() - self.on_input_wrong:clear() -end - - function Input.on_input(self, action_id, action) if self.is_selected then local input_text = nil diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index fec0c7d..f78b70b 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -41,12 +41,6 @@ function LangText.init(self, node, locale_id, no_adjust) end -function LangText.on_internal_remove(self) - component.on_internal_remove(self) - self.on_change:clear() -end - - function LangText.on_language_change(self) if self.last_locale then self:translate(self.last_locale, unpack(self.last_locale_args)) diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 719e2ae..37963f0 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -39,12 +39,6 @@ function Layout:init(node, mode, on_size_changed_callback) end -function Layout.on_internal_remove(self) - component.on_internal_remove(self) - self.on_size_changed:clear() -end - - function Layout:on_window_resized() local window_x, window_y = window.get_size() local stretch_x = window_x / self.window_size.x diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index 99ef6b2..509e57b 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -121,12 +121,6 @@ function Progress.init(self, node, key, init_value) end -function Progress.on_internal_remove(self) - component.on_internal_remove(self) - self.on_change:clear() -end - - -- @tparam Progress self @{Progress} function Progress.on_late_init(self) self:set_to(self._init_value) diff --git a/druid/extended/radio_group.lua b/druid/extended/radio_group.lua index 768959d..fef1d00 100644 --- a/druid/extended/radio_group.lua +++ b/druid/extended/radio_group.lua @@ -50,12 +50,6 @@ function RadioGroup.init(self, nodes, callback, click_nodes) end -function RadioGroup.on_internal_remove(self) - component.on_internal_remove(self) - self.on_radio_click:clear() -end - - --- Set radio group state -- @tparam RadioGroup self @{RadioGroup} -- @tparam number index Index in radio group diff --git a/druid/extended/slider.lua b/druid/extended/slider.lua index ea5470b..4a8c90c 100644 --- a/druid/extended/slider.lua +++ b/druid/extended/slider.lua @@ -77,12 +77,6 @@ function Slider.init(self, node, end_pos, callback) end -function Slider.on_internal_remove(self) - component.on_internal_remove(self) - self.on_change_value:clear() -end - - function Slider.on_layout_change(self) self:set(self.value) end diff --git a/druid/extended/timer.lua b/druid/extended/timer.lua index e31bdb7..21ac56b 100644 --- a/druid/extended/timer.lua +++ b/druid/extended/timer.lua @@ -65,14 +65,6 @@ function Timer.init(self, node, seconds_from, seconds_to, callback) end -function Timer.on_internal_remove(self) - component.on_internal_remove(self) - self.on_tick:clear() - self.on_set_enabled:clear() - self.on_timer_end:clear() -end - - function Timer.update(self, dt) if not self.is_on then return diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 9b97842..e286e78 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -252,7 +252,6 @@ function DruidInstance.final(self) local components = self.components_all for i = #components, 1, -1 do - components[i]:on_internal_remove() if components[i].on_remove then components[i]:on_remove() end @@ -290,7 +289,6 @@ function DruidInstance.remove(self, component) local all_components = self.components_all for i = #all_components, 1, -1 do if all_components[i] == component then - component:on_internal_remove() if component.on_remove then component:on_remove() end diff --git a/druid/system/tablepool.lua b/druid/system/tablepool.lua deleted file mode 100644 index 616a86d..0000000 --- a/druid/system/tablepool.lua +++ /dev/null @@ -1,74 +0,0 @@ --- Source: https://github.com/openresty/lua-tablepool/blob/master/lib/tablepool.lua - -local setmetatable = setmetatable - -local _M = {} -local max_pool_size = 500 -local pools = {} - - -function _M.fetch(tag) - local pool = pools[tag] - if not pool then - pool = {} - pools[tag] = pool - pool.c = 0 - pool[0] = 0 - else - local len = pool[0] - if len > 0 then - local obj = pool[len] - pool[len] = nil - pool[0] = len - 1 - return obj - end - end - - return {} -end - - -function _M.release(tag, obj, noclear) - if not obj then - error("object empty", 2) - end - - local pool = pools[tag] - if not pool then - pool = {} - pools[tag] = pool - pool.c = 0 - pool[0] = 0 - end - - if not noclear then - setmetatable(obj, nil) - for k in pairs(obj) do - obj[k] = nil - end - end - - do - local cnt = pool.c + 1 - if cnt >= 20000 then - pool = {} - pools[tag] = pool - pool.c = 0 - pool[0] = 0 - return - end - pool.c = cnt - end - - local len = pool[0] + 1 - if len > max_pool_size then - -- discard it simply - return - end - - pool[len] = obj - pool[0] = len -end - - -return _M From decb9fd9fd811d1029dfac243de2a01de277c876 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 10 Apr 2022 15:20:57 +0300 Subject: [PATCH 05/12] Solve #73 fix scroll drag on stretch/zoom nodes --- druid/base/drag.lua | 13 +- druid/extended/layout.lua | 12 +- druid/helper.lua | 9 ++ example/examples/general/layout/layout.gui | 126 +++++++++++++++++- .../examples/general/layout/layout.gui_script | 1 + 5 files changed, 147 insertions(+), 14 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index b51c1af..71281bd 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -186,6 +186,8 @@ function Drag.init(self, node, on_drag_callback) self.on_drag_start = Event() self.on_drag = Event(on_drag_callback) self.on_drag_end = Event() + + self:on_window_resized() end @@ -199,6 +201,13 @@ function Drag.on_late_init(self) end +function Drag.on_window_resized(self) + local x_koef, y_koef = helper.get_screen_aspect_koef() + self._x_koef = x_koef + self._y_koef = y_koef +end + + function Drag.on_input_interrupt(self) if self.is_drag or self.is_touch then end_touch(self) @@ -258,8 +267,8 @@ function Drag.on_input(self, action_id, action) local touch_modified = find_touch(action_id, action, self.touch_id) if touch_modified and self.is_drag then - self.dx = touch_modified.x - self.x - self.dy = touch_modified.y - self.y + self.dx = (touch_modified.x - self.x) * self._x_koef + self.dy = (touch_modified.y - self.y) * self._y_koef end if touch_modified then diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 37963f0..aa1bc9f 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -30,7 +30,6 @@ function Layout:init(node, mode, on_size_changed_callback) self._min_size = nil self._max_size = nil - self.window_size = vmath.vector3(gui.get_width(), gui.get_height(), 0) self.mode = mode or const.LAYOUT_MODE.FIT self.on_size_changed = Event(on_size_changed_callback) @@ -40,12 +39,7 @@ end function Layout:on_window_resized() - local window_x, window_y = window.get_size() - local stretch_x = window_x / self.window_size.x - local stretch_y = window_y / self.window_size.y - - local x_koef = stretch_x / math.min(stretch_x, stretch_y) - local y_koef = stretch_y / math.min(stretch_x, stretch_y) + local x_koef, y_koef = helper.get_screen_aspect_koef() local new_size = vmath.vector3(self.origin_size) if self.mode == const.LAYOUT_MODE.STRETCH_X or self.mode == const.LAYOUT_MODE.STRETCH then @@ -65,8 +59,8 @@ function Layout:on_window_resized() gui.set_size(self.node, new_size) - self.position.x = self.origin_position.x * x_koef + self.origin_position.x * (1 - x_koef) * self.pivot.x * 2 - self.position.y = self.origin_position.y * y_koef + self.origin_position.y * (1 - y_koef) * self.pivot.y * 2 + self.position.x = self.origin_position.x + self.origin_position.x * (1 - x_koef) * self.pivot.x * 2 + self.position.y = self.origin_position.y + self.origin_position.y * (1 - y_koef) * self.pivot.y * 2 gui.set_position(self.node, self.position) self.on_size_changed:trigger(self:get_context(), new_size) diff --git a/druid/helper.lua b/druid/helper.lua index d5ebee2..74eda23 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -97,6 +97,15 @@ function M.centrate_nodes(margin, ...) end +function M.get_screen_aspect_koef() + local window_x, window_y = window.get_size() + local stretch_x = window_x / gui.get_width() + local stretch_y = window_y / gui.get_height() + return stretch_x / math.min(stretch_x, stretch_y), + stretch_y / math.min(stretch_x, stretch_y) +end + + function M.step(current, target, step) if current < target then return math.min(current + step, target) diff --git a/example/examples/general/layout/layout.gui b/example/examples/general/layout/layout.gui index f157508..9c1d020 100644 --- a/example/examples/general/layout/layout.gui +++ b/example/examples/general/layout/layout.gui @@ -71,7 +71,7 @@ nodes { nodes { position { x: 0.0 - y: 200.0 + y: 250.0 z: 0.0 w: 1.0 } @@ -191,7 +191,7 @@ nodes { nodes { position { x: 0.0 - y: 0.0 + y: 50.0 z: 0.0 w: 1.0 } @@ -226,7 +226,7 @@ nodes { xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_STRETCH + adjust_mode: ADJUST_MODE_FIT parent: "root" layer: "" inherit_alpha: true @@ -604,6 +604,126 @@ nodes { text_tracking: 0.0 custom_type: 0 } +nodes { + position { + x: -150.0 + y: -400.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch_y_anchor_w" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_STRETCH + parent: "even_in_fit_node" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 150.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch by Y Anchor W" + font: "game" + id: "text_layout_stretch3" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: true + parent: "node_layout_stretch_y_anchor_w" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} layers { name: "image" } diff --git a/example/examples/general/layout/layout.gui_script b/example/examples/general/layout/layout.gui_script index bce9c3c..2550a26 100644 --- a/example/examples/general/layout/layout.gui_script +++ b/example/examples/general/layout/layout.gui_script @@ -9,6 +9,7 @@ function init(self) self.druid:new_layout("node_layout_stretch", const_druid.LAYOUT_MODE.STRETCH) self.druid:new_layout("node_layout_stretch_x", const_druid.LAYOUT_MODE.STRETCH_X) self.druid:new_layout("node_layout_stretch_y", const_druid.LAYOUT_MODE.STRETCH_Y) + self.druid:new_layout("node_layout_stretch_y_anchor_w", const_druid.LAYOUT_MODE.STRETCH_Y) end From 415869e2bff48bfb409d99bfbe5425bd32745478 Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 15 Jun 2022 10:29:27 +0500 Subject: [PATCH 06/12] Update layout component --- druid/extended/layout.lua | 57 +++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index aa1bc9f..8476bd4 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -19,35 +19,60 @@ local Layout = component.create("layout") function Layout:init(node, mode, on_size_changed_callback) self.node = self:get_node(node) - self.origin_size = gui.get_size(self.node) - self.pivot = helper.get_pivot_offset(gui.get_pivot(self.node)) - self.origin_position = gui.get_position(self.node) - self.position = vmath.vector3(self.origin_position) - - gui.set_size_mode(self.node, gui.SIZE_MODE_MANUAL) - gui.set_adjust_mode(self.node, gui.ADJUST_FIT) self._min_size = nil self._max_size = nil + self._inited = false + self.gui_size = vmath.vector3(gui.get_width(), gui.get_height(), 0) self.mode = mode or const.LAYOUT_MODE.FIT self.on_size_changed = Event(on_size_changed_callback) +end + +function Layout:on_late_init() + self._inited = true + self.origin_size = self.origin_size or gui.get_size(self.node) + self.fit_size = self.fit_size or vmath.vector3(self.origin_size) + self.pivot = helper.get_pivot_offset(gui.get_pivot(self.node)) + self.origin_position = gui.get_position(self.node) + self.position = vmath.vector3(self.origin_position) + gui.set_size_mode(self.node, gui.SIZE_MODE_MANUAL) + gui.set_adjust_mode(self.node, gui.ADJUST_FIT) self:on_window_resized() end function Layout:on_window_resized() - local x_koef, y_koef = helper.get_screen_aspect_koef() + if not self._inited then + return + end + + local window_x, window_y = window.get_size() + local stretch_x = window_x / self.gui_size.x + local stretch_y = window_y / self.gui_size.y + + local x_koef = self.fit_size.x / self.origin_size.x * stretch_x / math.min(stretch_x, stretch_y) + local y_koef = self.fit_size.y / self.origin_size.y * stretch_y / math.min(stretch_x, stretch_y) local new_size = vmath.vector3(self.origin_size) + if self.mode == const.LAYOUT_MODE.STRETCH_X or self.mode == const.LAYOUT_MODE.STRETCH then new_size.x = new_size.x * x_koef end if self.mode == const.LAYOUT_MODE.STRETCH_Y or self.mode == const.LAYOUT_MODE.STRETCH then new_size.y = new_size.y * y_koef end + + -- Fit to the stretched container (node size or other defined) + if self.mode == const.LAYOUT_MODE.ZOOM_MIN then + new_size = new_size * math.min(x_koef, y_koef) + end + if self.mode == const.LAYOUT_MODE.ZOOM_MAX then + new_size = new_size * math.max(x_koef, y_koef) + end + if self._min_size then new_size.x = math.max(new_size.x, self._min_size.x) new_size.y = math.max(new_size.y, self._min_size.y) @@ -87,8 +112,24 @@ end function Layout:set_origin_size(new_origin_size) self.origin_size = new_origin_size or self.origin_size + self:on_window_resized() return self end +function Layout:fit_into_size(target_size) + self.fit_size = target_size + self:on_window_resized() + return self +end + + +function Layout:fit_into_window() + return self:fit_into_size(vmath.vector3( + gui.get_width(), + gui.get_height(), + 0)) +end + + return Layout From c9f862ac0328cbca0c3cfefcecfae12700dddb2a Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 15 Jun 2022 10:34:19 +0500 Subject: [PATCH 07/12] Solve #188 Add drag component total_x/total_y --- druid/base/drag.lua | 14 +++++++------- druid/helper.lua | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 71281bd..0e8b018 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -17,10 +17,10 @@ --- Event on drag start callback(self) -- @tfield DruidEvent on_drag_start @{DruidEvent} ---- on drag progress callback(self, dx, dy) +--- on drag progress callback(self, dx, dy, total_x, total_y) -- @tfield DruidEvent on_drag Event @{DruidEvent} ---- Event on drag end callback(self) +--- Event on drag end callback(self, total_x, total_y) -- @tfield DruidEvent on_drag_end @{DruidEvent} --- Is component now touching @@ -70,7 +70,7 @@ end local function end_touch(self) if self.is_drag then - self.on_drag_end:trigger(self:get_context()) + self.on_drag_end:trigger(self:get_context(), self.x - self.touch_start_pos.x, self.y - self.touch_start_pos.y) end self.is_drag = false @@ -96,7 +96,7 @@ local function process_touch(self, touch) if not self.is_drag and distance >= self.style.DRAG_DEADZONE then self.is_drag = true self.on_drag_start:trigger(self:get_context()) - self:set_input_priority(const.PRIORITY_INPUT_MAX) + self:set_input_priority(const.PRIORITY_INPUT_MAX, true) end end @@ -267,8 +267,8 @@ function Drag.on_input(self, action_id, action) local touch_modified = find_touch(action_id, action, self.touch_id) if touch_modified and self.is_drag then - self.dx = (touch_modified.x - self.x) * self._x_koef - self.dy = (touch_modified.y - self.y) * self._y_koef + self.dx = touch_modified.x - self.x + self.dy = touch_modified.y - self.y end if touch_modified then @@ -277,7 +277,7 @@ function Drag.on_input(self, action_id, action) end if self.is_drag then - self.on_drag:trigger(self:get_context(), self.dx, self.dy) + self.on_drag:trigger(self:get_context(), self.dx, self.dy, self.x - self.touch_start_pos.x, self.y - self.touch_start_pos.y) end return self.is_drag diff --git a/druid/helper.lua b/druid/helper.lua index 74eda23..c7849d1 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -8,6 +8,7 @@ local const = require("druid.const") local M = {} + --- Text node or icon node can be nil local function get_text_width(text_node) if text_node then From 53f305734c0f3b37a108bc01768122f49d88904c Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 15 Jun 2022 10:34:47 +0500 Subject: [PATCH 08/12] Solve #189 Add temporary set input priority --- druid/component.lua | 9 +++++++-- druid/extended/input.lua | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/druid/component.lua b/druid/component.lua index 02d351a..6f09892 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -218,17 +218,22 @@ end --- Set component input priority -- @tparam BaseComponent self @{BaseComponent} -- @tparam number value The new input priority value +-- @tparam boolean is_temporary If true, the reset input priority will return to previous value -- @treturn number The component input priority -function BaseComponent.set_input_priority(self, value) +function BaseComponent.set_input_priority(self, value, is_temporary) assert(value) if self._component.input_priority ~= value then self._component.input_priority = value self._component._is_input_priority_changed = true + if not is_temporary then + self._component.default_input_priority = value + end + local children = self:get_childrens() for i = 1, #children do - children[i]:set_input_priority(value) + children[i]:set_input_priority(value, is_temporary) end end diff --git a/druid/extended/input.lua b/druid/extended/input.lua index d463871..36da224 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -281,8 +281,8 @@ function Input.select(self) gui.reset_keyboard() self.marked_value = "" if not self.is_selected then - self:set_input_priority(const.PRIORITY_INPUT_MAX) - self.button:set_input_priority(const.PRIORITY_INPUT_MAX) + self:set_input_priority(const.PRIORITY_INPUT_MAX, true) + self.button:set_input_priority(const.PRIORITY_INPUT_MAX, true) self.previous_value = self.value self.is_selected = true From e029d1eac315670a509d03be37da34943a92f042 Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 15 Jun 2022 10:35:56 +0500 Subject: [PATCH 09/12] Solve #133 Add hotkey component --- druid/extended/hotkey.lua | 148 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 druid/extended/hotkey.lua diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua new file mode 100644 index 0000000..e95bdf3 --- /dev/null +++ b/druid/extended/hotkey.lua @@ -0,0 +1,148 @@ +-- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license + +--- Druid hotkey component +-- @module Hotkey +-- @within BaseComponent +-- @alias druid.hotkey + +--- On change state callback(self, state) +-- @tfield DruidEvent on_change_state @{DruidEvent} + +--- Visual node +-- @tfield node node + +--- Button trigger node +-- @tfield[opt=node] node click_node + +--- Button component from click_node +-- @tfield Button button @{Button} + +--- + +local helper = require("druid.helper") +local component = require("druid.component") + +local Hotkey = component.create("hotkey") + + +--- Component init function +-- @tparam Hotkey self @{Hotkey} +-- @tparam string[]|string keys The keys to be pressed for trigger callback. Should contains one key and any modificator keys +-- @tparam function callback The callback function +function Hotkey.init(self, keys, callback, callback_argument) + self.druid = self:get_druid() + + self._hotkeys = {} + self._modificators = {} + self._callback = callback + + if keys then + self:add_hotkey(keys, callback_argument) + end +end + + +--- Component style params. +-- You can override this component styles params in druid styles table +-- or create your own style +-- @table style +-- @tfield string[] MODIFICATORS The list of action_id as hotkey modificators +function Hotkey.on_style_change(self, style) + self.style = {} + self.style.MODIFICATORS = style.MODIFICATORS or {} + + for index = 1, #style.MODIFICATORS do + self.style.MODIFICATORS[index] = hash(self.style.MODIFICATORS[index]) + end +end + + +--- Add hotkey for component callback +-- @tparam Hotkey self @{Hotkey} +-- @tparam string[]|hash[]|string|hash Keys that have to be pressed before key pressed to activate +function Hotkey.add_hotkey(self, keys, callback_argument) + keys = keys or {} + if type(keys) == "string" then + keys = { keys } + end + + local modificators = {} + local key = nil + + for index = 1, #keys do + local key_hash = hash(keys[index]) + if helper.contains(self.style.MODIFICATORS, key_hash) then + table.insert(modificators, key_hash) + else + if not key then + key = key_hash + else + error("The hotkey keys should contains only one key (except modificator keys)") + end + end + end + + table.insert(self._hotkeys, { + modificators = modificators, + key = key, + is_processing = false, + callback_argument = callback_argument, + }) + + -- Current hotkey status + for index = 1, #self.style.MODIFICATORS do + local modificator = hash(self.style.MODIFICATORS[index]) + self._modificators[modificator] = self._modificators[modificator] or false + end + + return self +end + + +function Hotkey.on_input(self, action_id, action) + if not action_id then + return + end + + if self._modificators[action_id] ~= nil then + if action.pressed then + self._modificators[action_id] = true + end + if action.released then + self._modificators[action_id] = false + end + end + + for index = 1, #self._hotkeys do + local hotkey = self._hotkeys[index] + if action_id == hotkey.key then + local is_modificator_ok = true + + -- Check only required modificators pressed + for i = 1, #self.style.MODIFICATORS do + local mod = self.style.MODIFICATORS[i] + if helper.contains(hotkey.modificators, mod) and self._modificators[mod] == false then + is_modificator_ok = false + end + if not helper.contains(hotkey.modificators, mod) and self._modificators[mod] == true then + is_modificator_ok = false + end + end + + if action.pressed and is_modificator_ok then + hotkey.is_processing = true + end + if action.released and is_modificator_ok and hotkey.is_processing then + hotkey.is_processing = false + if hotkey.callback_argument then + self._callback(self:get_context(), hotkey.callback_argument) + else + self._callback(self:get_context()) + end + end + end + end +end + + +return Hotkey From 0107c015a1628378d18ef3a572750c75d89d3a3d Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 15 Jun 2022 10:37:45 +0500 Subject: [PATCH 10/12] Update layout component --- druid/base/static_grid.lua | 5 ++++- druid/component.lua | 2 +- druid/const.lua | 2 ++ druid/extended/layout.lua | 18 +++++++++++++++--- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index c32d4c0..17701f5 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -33,9 +33,12 @@ --- The last index of node in grid -- @tfield number last_index ---- Item anchor +--- Item anchor [0..1] -- @tfield vector3 anchor +--- Item pivot [-0.5..0.5] +-- @tfield vector3 pivot + --- Item size -- @tfield vector3 node_size diff --git a/druid/component.lua b/druid/component.lua index 6f09892..e71add0 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -173,7 +173,7 @@ function BaseComponent.get_node(self, node_or_name) end if not node then - assert(node, "No component with name: " .. template_name .. node_or_name) + assert(node, "No component with name: " .. (template_name or "") .. (node_or_name or "")) end return node diff --git a/druid/const.lua b/druid/const.lua index 3e8c0d9..d05c537 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -87,6 +87,8 @@ M.REVERSE_PIVOTS = { M.LAYOUT_MODE = { STRETCH_X = "stretch_x", STRETCH_Y = "stretch_y", + ZOOM_MIN = "zoom_min", + ZOOM_MAX = "zoom_max", FIT = gui.ADJUST_FIT, STRETCH = gui.ADJUST_STRETCH, } diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 8476bd4..e5364f8 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -23,6 +23,7 @@ function Layout:init(node, mode, on_size_changed_callback) self._min_size = nil self._max_size = nil self._inited = false + self._is_stretch_position = nil self.gui_size = vmath.vector3(gui.get_width(), gui.get_height(), 0) self.mode = mode or const.LAYOUT_MODE.FIT @@ -81,11 +82,14 @@ function Layout:on_window_resized() new_size.x = math.min(new_size.x, self._max_size.x) new_size.y = math.min(new_size.y, self._max_size.y) end - gui.set_size(self.node, new_size) - self.position.x = self.origin_position.x + self.origin_position.x * (1 - x_koef) * self.pivot.x * 2 - self.position.y = self.origin_position.y + self.origin_position.y * (1 - y_koef) * self.pivot.y * 2 + self.position.x = self.origin_position.x + self.position.y = self.origin_position.y + if self._is_stretch_position then + self.position.x = self.position.x + self.origin_position.x * (1 - x_koef) * (self.pivot.x * 2) + self.position.y = self.position.y + self.origin_position.y * (1 - y_koef) * (self.pivot.y * 2) + end gui.set_position(self.node, self.position) self.on_size_changed:trigger(self:get_context(), new_size) @@ -110,6 +114,14 @@ function Layout:set_origin_position(new_origin_position) end +--@tparam boolean state +function Layout:set_stretch_position(state) + self._is_stretch_position = state + self:on_window_resized() + return self +end + + function Layout:set_origin_size(new_origin_size) self.origin_size = new_origin_size or self.origin_size self:on_window_resized() From 43f75cd820de598e2f288bdb1f7eb46a315e9315 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 18:08:03 +0300 Subject: [PATCH 11/12] Solve #195 Add set_enabled to Drag component --- druid/base/drag.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 0e8b018..7884ab7 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -176,6 +176,7 @@ function Drag.init(self, node, on_drag_callback) self.is_touch = false self.is_drag = false self.touch_start_pos = vmath.vector3(0) + self._is_disabled = false self.can_x = true self.can_y = true @@ -220,7 +221,7 @@ function Drag.on_input(self, action_id, action) return false end - if not helper.is_enabled(self.node) then + if not helper.is_enabled(self.node) or self._is_disabled then return false end @@ -293,4 +294,21 @@ function Drag.set_click_zone(self, node) end +--- Set Drag input enabled or disabled +-- @tparam Drag self @{Drag} +-- @tparam bool is enabled +function Drag.set_enabled(self, is_enabled) + self._is_disabled = not is_enabled +end + + +--- Check if Drag component is enabled +-- @tparam Drag self @{Drag} +-- @treturn bool +function Drag.is_enabled(self) + return self._is_disabled +end + + + return Drag From 45b48438874eef9a3ddfc3f4676063d5a042cd1b Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 18:23:07 +0300 Subject: [PATCH 12/12] Layout component update --- druid/extended/layout.lua | 17 +---- example/examples/general/layout/layout.gui | 82 ++++------------------ 2 files changed, 15 insertions(+), 84 deletions(-) diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index e5364f8..b242eb6 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -23,7 +23,6 @@ function Layout:init(node, mode, on_size_changed_callback) self._min_size = nil self._max_size = nil self._inited = false - self._is_stretch_position = nil self.gui_size = vmath.vector3(gui.get_width(), gui.get_height(), 0) self.mode = mode or const.LAYOUT_MODE.FIT @@ -84,12 +83,8 @@ function Layout:on_window_resized() end gui.set_size(self.node, new_size) - self.position.x = self.origin_position.x - self.position.y = self.origin_position.y - if self._is_stretch_position then - self.position.x = self.position.x + self.origin_position.x * (1 - x_koef) * (self.pivot.x * 2) - self.position.y = self.position.y + self.origin_position.y * (1 - y_koef) * (self.pivot.y * 2) - end + self.position.x = self.origin_position.x + self.origin_position.x * (x_koef - 1) + self.position.y = self.origin_position.y + self.origin_position.y * (y_koef - 1) gui.set_position(self.node, self.position) self.on_size_changed:trigger(self:get_context(), new_size) @@ -114,14 +109,6 @@ function Layout:set_origin_position(new_origin_position) end ---@tparam boolean state -function Layout:set_stretch_position(state) - self._is_stretch_position = state - self:on_window_resized() - return self -end - - function Layout:set_origin_size(new_origin_size) self.origin_size = new_origin_size or self.origin_size self:on_window_resized() diff --git a/example/examples/general/layout/layout.gui b/example/examples/general/layout/layout.gui index 9c1d020..f946c05 100644 --- a/example/examples/general/layout/layout.gui +++ b/example/examples/general/layout/layout.gui @@ -70,7 +70,7 @@ nodes { } nodes { position { - x: 0.0 + x: -100.0 y: 250.0 z: 0.0 w: 1.0 @@ -190,64 +190,8 @@ nodes { } nodes { position { - x: 0.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 1.0 - y: 1.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "even_in_fit_node" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_AUTO - custom_type: 0 -} -nodes { - position { - x: 0.0 - y: 50.0 + x: -100.0 + y: 100.0 z: 0.0 w: 1.0 } @@ -283,7 +227,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_CENTER adjust_mode: ADJUST_MODE_STRETCH - parent: "even_in_fit_node" + parent: "root" layer: "" inherit_alpha: true slice9 { @@ -366,8 +310,8 @@ nodes { } nodes { position { - x: 0.0 - y: -100.0 + x: -100.0 + y: -50.0 z: 0.0 w: 1.0 } @@ -403,7 +347,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_CENTER adjust_mode: ADJUST_MODE_STRETCH - parent: "even_in_fit_node" + parent: "root" layer: "" inherit_alpha: true slice9 { @@ -486,8 +430,8 @@ nodes { } nodes { position { - x: 0.0 - y: -250.0 + x: -100.0 + y: -200.0 z: 0.0 w: 1.0 } @@ -523,7 +467,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_CENTER adjust_mode: ADJUST_MODE_STRETCH - parent: "even_in_fit_node" + parent: "root" layer: "" inherit_alpha: true slice9 { @@ -606,8 +550,8 @@ nodes { } nodes { position { - x: -150.0 - y: -400.0 + x: -250.0 + y: -350.0 z: 0.0 w: 1.0 } @@ -643,7 +587,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_W adjust_mode: ADJUST_MODE_STRETCH - parent: "even_in_fit_node" + parent: "root" layer: "" inherit_alpha: true slice9 {