From c263c60de89bf6b0200541d567bb24be3fe4efd9 Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 12 Mar 2022 12:18:33 +0200 Subject: [PATCH 01/30] Fix changelog type --- docs_md/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index ae7ec62..26ffabb 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -382,7 +382,7 @@ Take care of yourself - The docs in (https://insality.github.io/druid/) now have cross links for every custom type - **#175** Remove Druid Assets repository, move to Druid library - Added folder `druid/custom`. It will have the complex custom components. Usually you should to use default GUI template or create your own with similar GUI scheme. Currently add `RichInput` and `PinKnob` components from druid-assets repository. - - Usually to use custom component you have to require lua file first and create it's via `druid:new(Component, template_name, [nodes]). See component docs to see constructor params. + - Usually to use custom component you have to require lua file first and create it's via `druid:new(Component, template_name, [nodes])`. See component docs to see constructor params. - This components will be included in build only if used - **#176** Keep last scene and scroll position in Druid example - Probably, it's useful for faster debug, but anyway. The example now keep the last scene and scroll position. From 2779f9cf7a9d33d55bfe385bfd6e8137b951bd86 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 5 Apr 2022 18:17:39 +0300 Subject: [PATCH 02/30] 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 03/30] 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 04/30] 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 05/30] 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 06/30] 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 13fd4babb1463d7e95bf87f39ba23b3d225247f0 Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 16 Apr 2022 10:16:29 +0300 Subject: [PATCH 07/30] Solve #187 Temporary removed default gui templates --- .../styles/default/templates => templates}/druid_button_blue.gui | 0 .../styles/default/templates => templates}/druid_button_green.gui | 0 .../styles/default/templates => templates}/druid_button_red.gui | 0 .../default/templates => templates}/druid_button_yellow.gui | 0 {druid/styles/default/templates => templates}/druid_checkbox.gui | 0 {druid/styles/default/templates => templates}/druid_input.gui | 0 {druid/styles/default/templates => templates}/druid_slider.gui | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {druid/styles/default/templates => templates}/druid_button_blue.gui (100%) rename {druid/styles/default/templates => templates}/druid_button_green.gui (100%) rename {druid/styles/default/templates => templates}/druid_button_red.gui (100%) rename {druid/styles/default/templates => templates}/druid_button_yellow.gui (100%) rename {druid/styles/default/templates => templates}/druid_checkbox.gui (100%) rename {druid/styles/default/templates => templates}/druid_input.gui (100%) rename {druid/styles/default/templates => templates}/druid_slider.gui (100%) diff --git a/druid/styles/default/templates/druid_button_blue.gui b/templates/druid_button_blue.gui similarity index 100% rename from druid/styles/default/templates/druid_button_blue.gui rename to templates/druid_button_blue.gui diff --git a/druid/styles/default/templates/druid_button_green.gui b/templates/druid_button_green.gui similarity index 100% rename from druid/styles/default/templates/druid_button_green.gui rename to templates/druid_button_green.gui diff --git a/druid/styles/default/templates/druid_button_red.gui b/templates/druid_button_red.gui similarity index 100% rename from druid/styles/default/templates/druid_button_red.gui rename to templates/druid_button_red.gui diff --git a/druid/styles/default/templates/druid_button_yellow.gui b/templates/druid_button_yellow.gui similarity index 100% rename from druid/styles/default/templates/druid_button_yellow.gui rename to templates/druid_button_yellow.gui diff --git a/druid/styles/default/templates/druid_checkbox.gui b/templates/druid_checkbox.gui similarity index 100% rename from druid/styles/default/templates/druid_checkbox.gui rename to templates/druid_checkbox.gui diff --git a/druid/styles/default/templates/druid_input.gui b/templates/druid_input.gui similarity index 100% rename from druid/styles/default/templates/druid_input.gui rename to templates/druid_input.gui diff --git a/druid/styles/default/templates/druid_slider.gui b/templates/druid_slider.gui similarity index 100% rename from druid/styles/default/templates/druid_slider.gui rename to templates/druid_slider.gui From 4d47b6e656266bbe2e958e2eff9ce0bd19cc0a75 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 18 Apr 2022 15:52:50 +0300 Subject: [PATCH 08/30] Solve #186 fix set in row static grid zero offset --- druid/base/static_grid.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index c32d4c0..405c1e8 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -104,7 +104,6 @@ function StaticGrid.init(self, parent, element, in_row) self.border = vmath.vector4(0) -- Current grid content size - self.on_add_item = Event() self.on_remove_item = Event() self.on_change_items = Event() @@ -359,6 +358,11 @@ end function StaticGrid.set_in_row(self, in_row) self.in_row = in_row self._grid_horizonal_offset = self.node_size.x * (self.in_row - 1) * self.anchor.x + self._zero_offset = vmath.vector3( + self.node_size.x * self.node_pivot.x - self.node_size.x * self.pivot.x - self._grid_horizonal_offset, + self.node_size.y * self.node_pivot.y - self.node_size.y * self.pivot.y, + 0) + self:_update(true) self.on_change_items:trigger(self:get_context()) From 415869e2bff48bfb409d99bfbe5425bd32745478 Mon Sep 17 00:00:00 2001 From: Insality Date: Wed, 15 Jun 2022 10:29:27 +0500 Subject: [PATCH 09/30] 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 10/30] 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 11/30] 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 12/30] 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 13/30] 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 14/30] 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 15/30] 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 { From 46bcbb596d79b80869606a3aa143ab6d578ff22a Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 18:27:38 +0300 Subject: [PATCH 16/30] Fix drag is_enabled, add to example --- druid/base/drag.lua | 3 +- example/examples/general/drag/drag.gui | 163 ++++++++++++++++++ example/examples/general/drag/drag.gui_script | 10 +- 3 files changed, 173 insertions(+), 3 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 7884ab7..d9f5e19 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -306,9 +306,8 @@ end -- @tparam Drag self @{Drag} -- @treturn bool function Drag.is_enabled(self) - return self._is_disabled + return not self._is_disabled end - return Drag diff --git a/example/examples/general/drag/drag.gui b/example/examples/general/drag/drag.gui index 4aed380..a0c145a 100644 --- a/example/examples/general/drag/drag.gui +++ b/example/examples/general/drag/drag.gui @@ -308,6 +308,169 @@ nodes { text_tracking: 0.0 custom_type: 0 } +nodes { + position { + x: 0.0 + y: -344.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: 200.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_TEMPLATE + id: "button_drag" + parent: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false + 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: 300.0 + y: 60.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/button_blue" + id: "button_drag/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_drag" + layer: "image" + inherit_alpha: true + slice9 { + x: 15.0 + y: 15.0 + z: 15.0 + w: 15.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + overridden_fields: 4 + template_node_child: true + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 7.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 200.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: "Toggle Drag Enabled" + font: "game" + id: "button_drag/text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.101960786 + y: 0.2 + z: 0.6 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "button_drag/button" + layer: "text" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.78 + overridden_fields: 8 + template_node_child: true + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} layers { name: "image" } diff --git a/example/examples/general/drag/drag.gui_script b/example/examples/general/drag/drag.gui_script index 46c4dcf..06e3584 100644 --- a/example/examples/general/drag/drag.gui_script +++ b/example/examples/general/drag/drag.gui_script @@ -1,9 +1,10 @@ local druid = require("druid.druid") -local function on_drag_callback(self, dx, dy) +local function on_drag_callback(self, dx, dy, total_x, total_y) self.position.x = self.position.x + dx self.position.y = self.position.y + dy + print("Total drag:", total_x, total_y) gui.set_position(self.box, self.position) end @@ -15,6 +16,11 @@ local function on_drag_end(self) end +local function on_drag_toggle(self) + self.drag:set_enabled(not self.drag:is_enabled()) +end + + function init(self) self.druid = druid.new(self) @@ -23,6 +29,8 @@ function init(self) self.drag = self.druid:new_drag("drag_node", on_drag_callback) self.drag.on_drag_end:subscribe(on_drag_end, self) + + self.druid:new_button("button_drag/button", on_drag_toggle) end From 3e5a90920eaa8977292220182d3b7577ac45c75c Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 18:41:02 +0300 Subject: [PATCH 17/30] Update drag screen koef value --- druid/base/drag.lua | 6 +++++- druid/base/scroll.lua | 1 - druid/extended/layout.lua | 8 +------- druid/styles/default/style.lua | 5 +++++ example/example.gui | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index d9f5e19..249a664 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -278,7 +278,11 @@ 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.x - self.touch_start_pos.x, self.y - self.touch_start_pos.y) + self.on_drag:trigger(self:get_context(), + self.dx * self._x_koef, + self.dy * self._y_koef, + (self.x - self.touch_start_pos.x) * self._x_koef, + (self.y - self.touch_start_pos.y) * self._y_koef) end return self.is_drag diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 01fbdd4..5de95c7 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -743,7 +743,6 @@ function Scroll._process_scroll_wheel(self, action_id, action) return false end - local koef = (action_id == const.ACTION_SCROLL_UP) and 1 or -1 if self.style.WHEEL_SCROLL_INVERTED then koef = -koef diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index b242eb6..eeaa77d 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -49,13 +49,7 @@ function Layout:on_window_resized() 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 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 diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index bd18a78..a4d4dbc 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -147,4 +147,9 @@ M["text"] = { } +M["hotkey"] = { + MODIFICATORS = {}, -- Add key ids to mark it as modificator keys +} + + return M diff --git a/example/example.gui b/example/example.gui index f613534..64f0e71 100644 --- a/example/example.gui +++ b/example/example.gui @@ -274,7 +274,7 @@ nodes { xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE pivot: PIVOT_N - adjust_mode: ADJUST_MODE_STRETCH + adjust_mode: ADJUST_MODE_FIT parent: "lobby_view" layer: "" inherit_alpha: true From 77e56e874769d130ce9ffa129ff6683a63d6a80a Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 19:07:35 +0300 Subject: [PATCH 18/30] Add hotkey example --- druid/const.lua | 6 +- druid/extended/hotkey.lua | 6 +- druid/styles/default/style.lua | 2 +- druid/system/druid_instance.lua | 13 +- example/example.collection | 63 ++++++ example/example.gui_script | 1 + .../examples/general/hotkey/hotkey.collection | 37 ++++ example/examples/general/hotkey/hotkey.gui | 207 ++++++++++++++++++ .../examples/general/hotkey/hotkey.gui_script | 38 ++++ input/game.input_binding | 12 + 10 files changed, 379 insertions(+), 6 deletions(-) create mode 100644 example/examples/general/hotkey/hotkey.collection create mode 100644 example/examples/general/hotkey/hotkey.gui create mode 100644 example/examples/general/hotkey/hotkey.gui_script diff --git a/druid/const.lua b/druid/const.lua index d05c537..12839ba 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -86,11 +86,11 @@ M.REVERSE_PIVOTS = { M.LAYOUT_MODE = { STRETCH_X = "stretch_x", - STRETCH_Y = "stretch_y", + STRETCH_Y = "stretch_y", ZOOM_MIN = "zoom_min", ZOOM_MAX = "zoom_max", - FIT = gui.ADJUST_FIT, - STRETCH = gui.ADJUST_STRETCH, + FIT = gui.ADJUST_FIT, + STRETCH = gui.ADJUST_STRETCH, } diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua index e95bdf3..8e8be29 100644 --- a/druid/extended/hotkey.lua +++ b/druid/extended/hotkey.lua @@ -101,7 +101,7 @@ end function Hotkey.on_input(self, action_id, action) if not action_id then - return + return false end if self._modificators[action_id] ~= nil then @@ -136,12 +136,16 @@ function Hotkey.on_input(self, action_id, action) hotkey.is_processing = false if hotkey.callback_argument then self._callback(self:get_context(), hotkey.callback_argument) + return true else self._callback(self:get_context()) + return true end end end end + + return false end diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index a4d4dbc..897b599 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -148,7 +148,7 @@ M["text"] = { M["hotkey"] = { - MODIFICATORS = {}, -- Add key ids to mark it as modificator keys + MODIFICATORS = { "key_lshift", "key_rshift", "key_lctrl", "key_rctrl", "key_lalt", "key_ralt", "key_lsuper", "key_rsuper" }, -- Add key ids to mark it as modificator keys } diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index e286e78..ee0d77b 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -31,6 +31,7 @@ -- @see DataList -- @see Hover -- @see Layout +-- @see Hotkey local helper = require("druid.helper") local class = require("druid.system.middleclass") @@ -58,7 +59,6 @@ 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") @@ -750,4 +750,15 @@ function DruidInstance.new_layout(self, node, mode) end +--- Create hotkey component +-- @tparam DruidInstance self +-- @tparam string|string[] string Keys for trigger action. Should contains one action key and any amount of modificator keys +-- @tparam function callback Button callback +-- @tparam[opt] value params Button callback params +-- @treturn Layout layout component +function DruidInstance.new_hotkey(self, keys_array, callback, params) + return helper.extended_component("hotkey") +end + + return DruidInstance diff --git a/example/example.collection b/example/example.collection index fd4aca8..f82f0b2 100644 --- a/example/example.collection +++ b/example/example.collection @@ -1751,3 +1751,66 @@ embedded_instances { z: 1.0 } } +embedded_instances { + id: "general_hotkey" + 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_hotkey\"\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/hotkey/hotkey.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 138172f..e60a116 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -133,6 +133,7 @@ local function init_lobby(self) 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")) + self.lobby_grid:add(get_button(self, "Hotkey", "general_hotkey", "/general/hotkey/hotkey.gui_script")) self.lobby_grid:add(get_title(self, "Texts")) self.lobby_grid:add(get_button(self, "Texts", "texts_general", "/texts/texts_general/texts_general.gui_script")) diff --git a/example/examples/general/hotkey/hotkey.collection b/example/examples/general/hotkey/hotkey.collection new file mode 100644 index 0000000..0b41685 --- /dev/null +++ b/example/examples/general/hotkey/hotkey.collection @@ -0,0 +1,37 @@ +name: "hotkey" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"template\"\n" + " component: \"/example/examples/general/hotkey/hotkey.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/hotkey/hotkey.gui b/example/examples/general/hotkey/hotkey.gui new file mode 100644 index 0000000..34d0b7c --- /dev/null +++ b/example/examples/general/hotkey/hotkey.gui @@ -0,0 +1,207 @@ +script: "/example/examples/general/hotkey/hotkey.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_FIT + 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: 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: 400.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: "Use Ctrl + G or Cmd + G to tirgger the hotkey" + font: "game" + id: "text_hint" + 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: "root" + 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: -140.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: 400.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: "Counter: 0" + font: "game" + id: "text_counter" + 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: "root" + 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/hotkey/hotkey.gui_script b/example/examples/general/hotkey/hotkey.gui_script new file mode 100644 index 0000000..2b920d6 --- /dev/null +++ b/example/examples/general/hotkey/hotkey.gui_script @@ -0,0 +1,38 @@ +local hotkey = require("druid.extended.hotkey") +local druid = require("druid.druid") + + +local function on_hotkey(self) + self.counter = self.counter + 1 + gui.set_text(gui.get_node("text_counter"), "Counter: " .. self.counter) +end + + +function init(self) + druid.register("hotkey", hotkey) + self.druid = druid.new(self) + self.counter = 0 + + self.hotkey = self.druid:new_hotkey({ "key_lsuper", "key_g" }, on_hotkey) + self.hotkey:add_hotkey({ "key_lctrl", "key_g"}) +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 diff --git a/input/game.input_binding b/input/game.input_binding index 0b6d8ca..a6d0b3a 100644 --- a/input/game.input_binding +++ b/input/game.input_binding @@ -18,6 +18,18 @@ key_trigger { input: KEY_ESC action: "key_esc" } +key_trigger { + input: KEY_LSUPER + action: "key_lsuper" +} +key_trigger { + input: KEY_LCTRL + action: "key_lctrl" +} +key_trigger { + input: KEY_G + action: "key_g" +} mouse_trigger { input: MOUSE_WHEEL_UP action: "scroll_up" From 847bee2e6bbe678a5f3a16c336e91ba41635ed10 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 19:19:25 +0300 Subject: [PATCH 19/30] Update docs --- docs/index.html | 10 + docs/modules/BackHandler.html | 2 + docs/modules/BaseComponent.html | 10 +- docs/modules/Blocker.html | 2 + docs/modules/Button.html | 2 + docs/modules/Checkbox.html | 2 + docs/modules/CheckboxGroup.html | 2 + docs/modules/DataList.html | 2 + docs/modules/Drag.html | 70 ++++- docs/modules/DruidEvent.html | 2 + docs/modules/DruidInstance.html | 87 +++++++ docs/modules/DynamicGrid.html | 2 + docs/modules/Helper.html | 2 + docs/modules/Hotkey.html | 314 +++++++++++++++++++++++ docs/modules/Hover.html | 2 + docs/modules/Input.html | 2 + docs/modules/LangText.html | 2 + docs/modules/Layout.html | 91 +++++++ docs/modules/PinKnob.html | 2 + docs/modules/Progress.html | 37 +++ docs/modules/RadioGroup.html | 2 + docs/modules/RichInput.html | 2 + docs/modules/Scroll.html | 2 + docs/modules/Slider.html | 2 + docs/modules/StaticGrid.html | 30 ++- docs/modules/Swipe.html | 2 + docs/modules/Text.html | 2 + docs/modules/Timer.html | 2 + docs/modules/druid.html | 2 + docs_md/01-components.md | 65 ++++- docs_md/02-creating_custom_components.md | 3 + druid/annotations.lua | 68 ++++- druid/base/drag.lua | 2 +- druid/extended/hotkey.lua | 4 +- druid/extended/layout.lua | 2 +- druid/extended/progress.lua | 2 +- druid/system/druid_instance.lua | 4 +- 37 files changed, 818 insertions(+), 23 deletions(-) create mode 100644 docs/modules/Hotkey.html create mode 100644 docs/modules/Layout.html diff --git a/docs/index.html b/docs/index.html index 772268e..1b184f4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -49,8 +49,10 @@
  • CheckboxGroup
  • DataList
  • DynamicGrid
  • +
  • Hotkey
  • Input
  • LangText
  • +
  • Layout
  • Progress
  • RadioGroup
  • Slider
  • @@ -140,6 +142,10 @@ DynamicGrid Component to handle placing components in row + + Hotkey + Druid hotkey component + Input Druid input text component. @@ -149,6 +155,10 @@ Component to handle all GUI texts Good working with localization system + + Layout + Layout management on node + Progress Basic progress bar component. diff --git a/docs/modules/BackHandler.html b/docs/modules/BackHandler.html index a6c768d..6d23e39 100644 --- a/docs/modules/BackHandler.html +++ b/docs/modules/BackHandler.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/BaseComponent.html b/docs/modules/BaseComponent.html index d920a1c..77841a8 100644 --- a/docs/modules/BaseComponent.html +++ b/docs/modules/BaseComponent.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • @@ -136,7 +138,7 @@ Set component input state. - set_input_priority(self, value) + set_input_priority(self, value, is_temporary) Set component input priority @@ -563,7 +565,7 @@
    - set_input_priority(self, value) + set_input_priority(self, value, is_temporary)
    Set component input priority @@ -579,6 +581,10 @@ number The new input priority value +
  • is_temporary + boolean + If true, the reset input priority will return to previous value +
  • Returns:

    diff --git a/docs/modules/Blocker.html b/docs/modules/Blocker.html index 0297f82..6e8651d 100644 --- a/docs/modules/Blocker.html +++ b/docs/modules/Blocker.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Button.html b/docs/modules/Button.html index 4d3b310..f22eac1 100644 --- a/docs/modules/Button.html +++ b/docs/modules/Button.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Checkbox.html b/docs/modules/Checkbox.html index 3cb13d5..3c9542f 100644 --- a/docs/modules/Checkbox.html +++ b/docs/modules/Checkbox.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/CheckboxGroup.html b/docs/modules/CheckboxGroup.html index 912993e..1f108e2 100644 --- a/docs/modules/CheckboxGroup.html +++ b/docs/modules/CheckboxGroup.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/DataList.html b/docs/modules/DataList.html index ede353d..88e0455 100644 --- a/docs/modules/DataList.html +++ b/docs/modules/DataList.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Drag.html b/docs/modules/Drag.html index 09aee5c..42925c2 100644 --- a/docs/modules/Drag.html +++ b/docs/modules/Drag.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • @@ -87,9 +89,17 @@ Drag component constructor + is_enabled(self) + Check if Drag component is enabled + + set_click_zone(self, node) Strict drag click area. + + set_enabled(self, is_enabled) + Set Drag input enabled or disabled +

    Tables

    @@ -118,11 +128,11 @@ - + - + @@ -185,6 +195,33 @@ + +
    + + is_enabled(self) +
    +
    + Check if Drag component is enabled + + +

    Parameters:

    +
      +
    • self + Drag + Drag +
    • +
    + +

    Returns:

    +
      + + bool + +
    + + + +
    @@ -211,6 +248,31 @@ + +
    + + set_enabled(self, is_enabled) +
    +
    + Set Drag input enabled or disabled + + +

    Parameters:

    +
      +
    • self + Drag + Drag +
    • +
    • is_enabled + bool + +
    • +
    + + + + +

    Tables

    @@ -329,7 +391,7 @@ on_drag
    - on drag progress callback(self, dx, dy) + on drag progress callback(self, dx, dy, total_x, total_y)
    + + + + @@ -167,6 +175,10 @@ + + + + @@ -658,6 +670,46 @@ + +
    + + new_hotkey(self, keys_array, callback[, params]) +
    +
    + Create hotkey component + + +

    Parameters:

    +
      +
    • self + DruidInstance + +
    • +
    • keys_array + string or string[] + Keys for trigger action. Should contains one action key and any amount of modificator keys +
    • +
    • callback + function + Button callback +
    • +
    • params + value + Button callback params + (optional) +
    • +
    + +

    Returns:

    +
      + + Hotkey + hotkey component +
    + + + +
    @@ -772,6 +824,41 @@ + +
    + + new_layout(self, node, mode) +
    +
    + Create layout component + + +

    Parameters:

    +
      +
    • self + DruidInstance + +
    • +
    • node + string or node + Layout node +
    • +
    • mode + string + The layout mode +
    • +
    + +

    Returns:

    +
      + + Layout + layout component +
    + + + +
    diff --git a/docs/modules/DynamicGrid.html b/docs/modules/DynamicGrid.html index 2879b8f..d4f1b92 100644 --- a/docs/modules/DynamicGrid.html +++ b/docs/modules/DynamicGrid.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Helper.html b/docs/modules/Helper.html index 7550096..cdcb021 100644 --- a/docs/modules/Helper.html +++ b/docs/modules/Helper.html @@ -50,9 +50,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Hotkey.html b/docs/modules/Hotkey.html new file mode 100644 index 0000000..8ea2ccd --- /dev/null +++ b/docs/modules/Hotkey.html @@ -0,0 +1,314 @@ + + + + + Defold Druid UI Library + + + + +
    + +
    + +
    +
    +
    + + +
    + + + + + + +
    + +

    Module Hotkey

    +

    Druid hotkey component

    +

    + + +

    Functions

    +
    on_dragon drag progress callback(self, dx, dy)on drag progress callback(self, dx, dy, total_x, total_y)
    on_drag_endEvent on drag end callback(self)Event on drag end callback(self, total_x, total_y)
    on_drag_start new_grid(self, parent, element[, in_row=1]) Create grid basic component Deprecated
    new_hotkey(self, keys_array, callback[, params])Create hotkey component
    new_hover(self, node, on_hover_callback)Create lang_text component
    new_layout(self, node, mode)Create layout component
    new_progress(self, node, key[, init_value=1]) Create progress component
    + + + + + + + + +
    add_hotkey(self, keys[, callback_argument])Add hotkey for component callback
    init(self, keys, callback[, callback_argument])Component init function
    +

    Tables

    + + + + + +
    styleComponent style params.
    +

    Fields

    + + + + + + + + + + + + + + + + + +
    buttonButton component from click_node
    click_nodeButton trigger node
    nodeVisual node
    on_change_stateOn change state callback(self, state)
    + +
    +
    + + +

    Functions

    + +
    +
    + + add_hotkey(self, keys[, callback_argument]) +
    +
    + Add hotkey for component callback + + +

    Parameters:

    +
      +
    • self + Hotkey + Hotkey +
    • +
    • keys + string[], hash[], string or hash + that have to be pressed before key pressed to activate +
    • +
    • callback_argument + value + The argument to pass into the callback function + (optional) +
    • +
    + + + + + +
    +
    + + init(self, keys, callback[, callback_argument]) +
    +
    + Component init function + + +

    Parameters:

    +
      +
    • self + Hotkey + Hotkey +
    • +
    • keys + string[] or string + The keys to be pressed for trigger callback. Should contains one key and any modificator keys +
    • +
    • callback + function + The callback function +
    • +
    • callback_argument + value + The argument to pass into the callback function + (optional) +
    • +
    + + + + + +
    +
    +

    Tables

    + +
    +
    + + style +
    +
    + Component style params. + You can override this component styles params in druid styles table + or create your own style + + +

    Fields:

    +
      +
    • MODIFICATORS + string[] + The list of action_id as hotkey modificators +
    • +
    + + + + + +
    +
    +

    Fields

    + +
    +
    + + button +
    +
    + Button component from click_node + + +
      +
    • button + Button + Button +
    • +
    + + + + + +
    +
    + + click_node +
    +
    + Button trigger node + + +
      +
    • click_node + node + + (default node) +
    • +
    + + + + + +
    +
    + + node +
    +
    + Visual node + + +
      +
    • node + node + +
    • +
    + + + + + +
    +
    + + on_change_state +
    +
    + On change state callback(self, state) + + + + + + + + +
    +
    + + + + +
    +generated by LDoc TESTING +Last updated 2015-01-01 12:00:00 +
    + + + diff --git a/docs/modules/Hover.html b/docs/modules/Hover.html index e3b6d47..9172f9c 100644 --- a/docs/modules/Hover.html +++ b/docs/modules/Hover.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Input.html b/docs/modules/Input.html index d247b11..ed576a0 100644 --- a/docs/modules/Input.html +++ b/docs/modules/Input.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/LangText.html b/docs/modules/LangText.html index ab9f8b8..7f524ba 100644 --- a/docs/modules/LangText.html +++ b/docs/modules/LangText.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Layout.html b/docs/modules/Layout.html new file mode 100644 index 0000000..fa51dd2 --- /dev/null +++ b/docs/modules/Layout.html @@ -0,0 +1,91 @@ + + + + + Defold Druid UI Library + + + + +
    + +
    + +
    +
    +
    + + +
    + + + + + + +
    + +

    Module Layout

    +

    Layout management on node

    +

    + + + +
    +
    + + + + +
    +
    +
    +generated by LDoc TESTING +Last updated 2015-01-01 12:00:00 +
    +
    + + diff --git a/docs/modules/PinKnob.html b/docs/modules/PinKnob.html index 1fe3571..8a53914 100644 --- a/docs/modules/PinKnob.html +++ b/docs/modules/PinKnob.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Progress.html b/docs/modules/Progress.html index 4494d3f..4ac940c 100644 --- a/docs/modules/Progress.html +++ b/docs/modules/Progress.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • @@ -97,6 +99,10 @@ Component init function + set_max_size(self, max_size) + Set progress bar max node size + + set_steps(self, steps, callback) Set points on progress bar to fire the callback @@ -251,6 +257,37 @@ +
    +
    + + set_max_size(self, max_size) +
    +
    + Set progress bar max node size + + +

    Parameters:

    +
      +
    • self + Progress + Progress +
    • +
    • max_size + vector3 + The new node maximum (full) size +
    • +
    + +

    Returns:

    +
      + + Progress + Progress +
    + + + +
    diff --git a/docs/modules/RadioGroup.html b/docs/modules/RadioGroup.html index a451edd..8522b32 100644 --- a/docs/modules/RadioGroup.html +++ b/docs/modules/RadioGroup.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/RichInput.html b/docs/modules/RichInput.html index df5f87b..4d192af 100644 --- a/docs/modules/RichInput.html +++ b/docs/modules/RichInput.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Scroll.html b/docs/modules/Scroll.html index 2781ee8..8098938 100644 --- a/docs/modules/Scroll.html +++ b/docs/modules/Scroll.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Slider.html b/docs/modules/Slider.html index 6b7b70d..ccf9abd 100644 --- a/docs/modules/Slider.html +++ b/docs/modules/Slider.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/StaticGrid.html b/docs/modules/StaticGrid.html index a9a9c6c..5775504 100644 --- a/docs/modules/StaticGrid.html +++ b/docs/modules/StaticGrid.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • @@ -148,7 +150,7 @@ - + @@ -194,6 +196,10 @@ + + + +
    anchorItem anchorItem anchor [0..1]
    borderparent Parent gui node
    pivotItem pivot [-0.5..0.5]

    @@ -677,7 +683,7 @@ anchor
    - Item anchor + Item anchor [0..1]
      @@ -911,6 +917,26 @@ +
    +
    + + pivot +
    +
    + Item pivot [-0.5..0.5] + + +
      +
    • pivot + vector3 + +
    • +
    + + + + +
    diff --git a/docs/modules/Swipe.html b/docs/modules/Swipe.html index 87fc435..de50f8c 100644 --- a/docs/modules/Swipe.html +++ b/docs/modules/Swipe.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Text.html b/docs/modules/Text.html index 8fd4d8a..271b2d8 100644 --- a/docs/modules/Text.html +++ b/docs/modules/Text.html @@ -52,9 +52,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/Timer.html b/docs/modules/Timer.html index 61a3214..de1e335 100644 --- a/docs/modules/Timer.html +++ b/docs/modules/Timer.html @@ -51,9 +51,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs/modules/druid.html b/docs/modules/druid.html index 20b016c..3a2f78b 100644 --- a/docs/modules/druid.html +++ b/docs/modules/druid.html @@ -50,9 +50,11 @@
  • DruidInstance
  • DynamicGrid
  • Helper
  • +
  • Hotkey
  • Hover
  • Input
  • LangText
  • +
  • Layout
  • PinKnob
  • Progress
  • RadioGroup
  • diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 5b9eb98..ed81422 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -147,7 +147,7 @@ Basic Druid progress bar component ### Setup Create progress bar component with druid: `progress = druid:new_progress(node_name, key, init_value)` -Node name should have maximum node size, so in GUI scene, node_name should be fully filled. +Node name should have maximum node size, so in GUI scene, node_name should be fully filled. Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or just "y") ### Notes @@ -165,7 +165,7 @@ Basic Druid slider component ### Setup Create slider component with druid: `slider = druid:new_slider(node_name, end_pos, callback)` -Pin node (node_name in params) should be placed in zero position (initial). It will be available to mode Pin node between start pos and end pos. +Pin node (node_name in params) should be placed in zero position (initial). It will be available to mode Pin node between start pos and end pos. ### Notes - You can setup points of interests on slider via `slider:set_steps`. If steps are exist, slider values will be only from this steps (notched slider) @@ -277,7 +277,7 @@ Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_ ### Overview Component for manage node positions with different node sizes. Unlike Static Grid, Dynamic Grid can place nodes only in one row or in one column. -Dynamic Grid can't have gaps between elements +Dynamic Grid can't have gaps between elements - you will get error, if try spawn element far away from others. Dynamic Grid should have __West__, __East__, __South__ or __North__ pivot (vertical or horizontal element placement) @@ -301,7 +301,7 @@ Check the _parent_node_ have correct pivot point. You will get the error otherwi [Data List API here](https://insality.github.io/druid/modules/DataList.html) ### Overview -Component to manage data for huge dataset in scroll. DataList create elements only in scroll view. +Component to manage data for huge dataset in scroll. DataList create elements only in scroll view. It requires Druid Scroll and Druid Grid (Static or Dynamic) components @@ -368,10 +368,12 @@ System Druid component, handle drag actions on node Create drag component with druid: `hover = druid:new_drag(node, drag_callback)` ### Notes -- Drag callback have next params: (self, swipe_side, distance, time) +- Drag callback have next params: (self, dx, dy, total_x, total_y) - **self**: Druid self context - **dx**: *number* - delta x position - **dy**: *number* - delta y position + - **total_x**: *number* - total delta x position + - **total_y**: *number* - total delta y position - In styles, you can point the drag start deadzone. Default value is 10 pixels - Drag correctly process multitouch. You can switch touch_id, while dragging on node with correct _dx_ and _dy_ values (made for correct scrolling) - You can restrict horizontal or vertical dragging by setting `drag.can_x` or `drag.can_y` to _false_ value @@ -387,3 +389,56 @@ Create drag component with druid: `hover = druid:new_drag(node, drag_callback)` - _on_drag_ (self, dx, dy) - Event on drag process - _on_drag_end_ (self) - Event on drag end - Drag node zone can be restricted via `drag:set_click_zone(node)` + + +## Hotkey +[Hotkey API here](https://insality.github.io/druid/modules/Hotkey.html) + +### Overview +Druid component to handle keyboard hotkeys with key modificators + +### Setup +This is extended component. Before use it, you should register it: +``` +local druid = require("druid.druid") +local hotkey = require("druid.extended.hotkey") +druid.register("hotkey", hotkey) +``` +Create drag component with druid: `hotkey = druid:new_hotkey(keys_array, callback, [callback_argument])` + +### Notes +- Hotkey callback is similar with button callback: (self, callback_argument) + - **self**: Druid self context + - **callback_argument**: *value* - Any value passed at component constructor +- In styles, you can point the array of modificator keys. This keys should be pressed with main key to trigger the callback +- The keys_arrays should contains one action key and any amount of modificator keys +- You can add additional hotkeys to hotkey component with `hotkey:add_hotkey(keys_array, callback_argument)` + + +## Layout +[Layout API here](https://insality.github.io/druid/modules/Layout.html) + +### Overview +Component to handle node size depends on layout mode. Unlike from Defold Adjust modes, you able to select node stretch by one size or zoom by minimum or maximum side + +### Setup +This is extended component. Before use it, you should register it: +``` +local druid = require("druid.druid") +local layout = require("druid.extended.layout") +druid.register("layout", layout) +``` +Create drag component with druid: `layout = druid:new_layout(node, layout_mode, on_size_change_callback)` + + +### Notes +- Layout mode can be next: + - `const.LAYOUT_MODE.STRETCH_X` - Stretch node only by X + - `const.LAYOUT_MODE.STRETCH_Y` - Stretch node only by Y + - `const.LAYOUT_MODE.ZOOM_MIN` - Zoom node by minimal stretch multiplier + - `const.LAYOUT_MODE.ZOOM_MAX` - Zoom node by maximum stretch multiplier + - `const.LAYOUT_MODE.FIT` - Usual Defold Fit mode + - `const.LAYOUT_MODE.STRETCH` - Usual Defold Stretch Mode +- The Layout component will change the node size property. So it's able to increase size of 9patch nodes without scaling issue +- The Layout works even inside parent node with Fit adjust mode + diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index 64303d3..ad96efc 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -85,6 +85,9 @@ function Component:on_language_change() end -- [OPTIONAL] Call if game layout has changed and need to restore values in component function Component:on_layout_change() end +-- [OPTIONAL] Call if game window size is changed +function Component:on_window_resized() end + -- [OPTIONAL] Call, if input was capturing before this component -- Example: scroll is start scrolling, so you need unhover button function Component:on_input_interrupt() end diff --git a/druid/annotations.lua b/druid/annotations.lua index b286f87..9a716f2 100644 --- a/druid/annotations.lua +++ b/druid/annotations.lua @@ -149,8 +149,9 @@ function druid__base_component.set_input_enabled(self, state) end --- Set component input priority ---@param self druid.base_component @{BaseComponent} ---@param value number The new input priority value +---@param is_temporary boolean If true, the reset input priority will return to previous value ---@return number The component input priority -function druid__base_component.set_input_priority(self, value) end +function druid__base_component.set_input_priority(self, value, is_temporary) end --- Set current component nodes (protected) ---@protected @@ -387,8 +388,8 @@ function druid__data_list.set_data(self, data) end ---@field can_y bool Is drag component process horizontal. ---@field is_drag bool Is component now dragging ---@field is_touch bool Is component now touching ----@field on_drag druid.event on drag progress callback(self, dx, dy) ----@field on_drag_end druid.event Event on drag end callback(self) +---@field on_drag druid.event on drag progress callback(self, dx, dy, total_x, total_y) +---@field on_drag_end druid.event Event on drag end callback(self, total_x, total_y) ---@field on_drag_start druid.event Event on drag start callback(self) ---@field on_touch_end druid.event Event on touch end callback(self) ---@field on_touch_start druid.event Event on touch start callback(self) @@ -404,12 +405,22 @@ local druid__drag = {} ---@param on_drag_callback function Callback for on_drag_event(self, dx, dy) function druid__drag.init(self, node, on_drag_callback) end +--- Check if Drag component is enabled +---@param self druid.drag @{Drag} +---@return bool +function druid__drag.is_enabled(self) end + --- Strict drag click area. --- Useful for restrict events outside stencil node ---@param self druid.drag @{Drag} ---@param node node Gui node function druid__drag.set_click_zone(self, node) end +--- Set Drag input enabled or disabled +---@param self druid.drag @{Drag} +---@param is_enabled bool +function druid__drag.set_enabled(self, is_enabled) end + ---@class druid.drag.style ---@field DRAG_DEADZONE field Distance in pixels to start dragging @@ -551,6 +562,33 @@ local druid__helper = {} function druid__helper.table_to_string(t) end +---@class druid.hotkey : druid.base_component +---@field button druid.button Button component from click_node +---@field click_node node Button trigger node +---@field node node Visual node +---@field on_change_state druid.event On change state callback(self, state) +---@field style druid.hotkey.style Component style params. +local druid__hotkey = {} + +--- Add hotkey for component callback +---@param self druid.hotkey @{Hotkey} +---@param keys string[]|hash[]|string|hash that have to be pressed before key pressed to activate +---@param callback_argument value The argument to pass into the callback function +function druid__hotkey.add_hotkey(self, keys, callback_argument) end + +--- Component init function +---@param self druid.hotkey @{Hotkey} +---@param keys string[]|string The keys to be pressed for trigger callback. Should contains one key and any modificator keys +---@param callback function The callback function +---@param callback_argument value The argument to pass into the callback function +function druid__hotkey.init(self, keys, callback, callback_argument) end + + +---@class druid.hotkey.style +---@field MODIFICATORS field The list of action_id as hotkey modificators +local druid__hotkey__style = {} + + ---@class druid.hover : druid.base_component ---@field on_hover druid.event On hover callback(self, state) ---@field on_mouse_hover druid.event On mouse hover callback(self, state) @@ -766,6 +804,12 @@ function druid__progress.get(self) end ---@param init_value number Initial value of progress bar function druid__progress.init(self, node, key, init_value) end +--- Set progress bar max node size +---@param self druid.progress @{Progress} +---@param max_size vector3 The new node maximum (full) size +---@return druid.progress @{Progress} +function druid__progress.set_max_size(self, max_size) end + --- Set points on progress bar to fire the callback ---@param self druid.progress @{Progress} ---@param steps number[] Array of progress bar values @@ -1009,7 +1053,7 @@ function druid__slider.set_steps(self, steps) end ---@class druid.static_grid : druid.base_component ----@field anchor vector3 Item anchor +---@field anchor vector3 Item anchor [0..1] ---@field border vector4 The size of item content ---@field first_index number The first index of node in grid ---@field last_index number The last index of node in grid @@ -1021,6 +1065,7 @@ function druid__slider.set_steps(self, steps) end ---@field on_remove_item druid.event On item remove callback(self, index) ---@field on_update_positions druid.event On update item positions callback(self) ---@field parent node Parent gui node +---@field pivot vector3 Item pivot [-0.5..0.5] ---@field style druid.static_grid.style Component style params. local druid__static_grid = {} @@ -1365,6 +1410,14 @@ function druid_instance.new_dynamic_grid(self, parent) end ---@return druid.static_grid grid component function druid_instance.new_grid(self, parent, element, in_row) end +--- Create hotkey component +---@param self druid_instance +---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys +---@param callback function Button callback +---@param params value Button callback params +---@return druid.hotkey hotkey component +function druid_instance.new_hotkey(self, keys_array, callback, params) end + --- Create hover basic component ---@param self druid_instance ---@param node node Gui node @@ -1388,6 +1441,13 @@ function druid_instance.new_input(self, click_node, text_node, keyboard_type) en ---@return druid.lang_text lang_text component function druid_instance.new_lang_text(self, node, locale_id, no_adjust) end +--- Create layout component +---@param self druid_instance +---@param node string|node Layout node +---@param mode string The layout mode +---@return druid.layout layout component +function druid_instance.new_layout(self, node, mode) end + --- Create progress component ---@param self druid_instance ---@param node string|node Progress bar fill node or node name diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 249a664..cd0a50f 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -300,7 +300,7 @@ end --- Set Drag input enabled or disabled -- @tparam Drag self @{Drag} --- @tparam bool is enabled +-- @tparam bool is_enabled function Drag.set_enabled(self, is_enabled) self._is_disabled = not is_enabled end diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua index 8e8be29..23ecd49 100644 --- a/druid/extended/hotkey.lua +++ b/druid/extended/hotkey.lua @@ -29,6 +29,7 @@ local Hotkey = component.create("hotkey") -- @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 +-- @tparam[opt] value callback_argument The argument to pass into the callback function function Hotkey.init(self, keys, callback, callback_argument) self.druid = self:get_druid() @@ -59,7 +60,8 @@ 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 +-- @tparam string[]|hash[]|string|hash keys that have to be pressed before key pressed to activate +-- @tparam[opt] value callback_argument The argument to pass into the callback function function Hotkey.add_hotkey(self, keys, callback_argument) keys = keys or {} if type(keys) == "string" then diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index eeaa77d..2a4a24f 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -13,7 +13,7 @@ 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") diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index 509e57b..aa2cd03 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -215,7 +215,7 @@ end -- @tparam Progress self @{Progress} -- @tparam vector3 max_size The new node maximum (full) size -- @treturn Progress @{Progress} -function Progress:set_max_size(max_size) +function Progress.set_max_size(self, max_size) self.max_size = max_size[self.key] self:set_to(self.last_value) return self diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index ee0d77b..192e684 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -752,10 +752,10 @@ end --- Create hotkey component -- @tparam DruidInstance self --- @tparam string|string[] string Keys for trigger action. Should contains one action key and any amount of modificator keys +-- @tparam string|string[] keys_array Keys for trigger action. Should contains one action key and any amount of modificator keys -- @tparam function callback Button callback -- @tparam[opt] value params Button callback params --- @treturn Layout layout component +-- @treturn Hotkey hotkey component function DruidInstance.new_hotkey(self, keys_array, callback, params) return helper.extended_component("hotkey") end From 2f964c6ed3d63858527e0ba1955ebf1f0c468aae Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 19:22:36 +0300 Subject: [PATCH 20/30] Update docs --- docs_md/01-components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs_md/01-components.md b/docs_md/01-components.md index ed81422..892b8d1 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -404,7 +404,7 @@ local druid = require("druid.druid") local hotkey = require("druid.extended.hotkey") druid.register("hotkey", hotkey) ``` -Create drag component with druid: `hotkey = druid:new_hotkey(keys_array, callback, [callback_argument])` +Create hotkey component with druid: `hotkey = druid:new_hotkey(keys_array, callback, [callback_argument])` ### Notes - Hotkey callback is similar with button callback: (self, callback_argument) @@ -428,7 +428,7 @@ local druid = require("druid.druid") local layout = require("druid.extended.layout") druid.register("layout", layout) ``` -Create drag component with druid: `layout = druid:new_layout(node, layout_mode, on_size_change_callback)` +Create layout component with druid: `layout = druid:new_layout(node, layout_mode, on_size_change_callback)` ### Notes From 0c47828d9691a15989b218916390f0c3337a1934 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 17 Jul 2022 19:38:19 +0300 Subject: [PATCH 21/30] Add changelog for 0.10.0 --- docs_md/changelog.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 26ffabb..54d312f 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -391,3 +391,45 @@ Take care of yourself - Move emmylua annotations inside Druid dependency folder. You can copy it from Defold Editor outline - Optimize different stuff(Scroll, Druid Event, Druid instance and Base component) - Force Data List component to `IS_DYNAMIC_NODE_POSES = false` style + + +### Druid 0.10.0 + +Hello! Here is new Druid small update. It's brings to you two new components: Layout and Hotkey. Both components are "extended", so to use it, you should register it first (when you try to use it, in console will be prompt with code you should use) + +In general: +``` +local layout = require("druid.extended.layout") +druid.register("layout", layout) +``` + +The drag component now knows about window scaling, so now it have more accuracy dx/dy values depends on the screen size. The scroll and other components should work better :) + +Also now you can change the input priority of components temporary. For example while you interact with them (input fields, drag on select etc). + +**Changelog 0.10.0** + +--- + +- **#133** [Hotkey] Add new extended component: Hotkey + - It's allow you set hotkeys to call callbacks + - You should pass one action key and several modificator keys (left shift, ctrl etc) + - List of modificator keys setup via component style (you can change it) + - You can add several hotkeys on one callback via `hotkey:add_hotkey` with additional params +- **#98** [Layout] Add new extended component: Layout + - It's allow you to extend standart Defold node adjust modes + - Layout mode can be next: + - `const.LAYOUT_MODE.STRETCH_X` - Stretch node only by X + - `const.LAYOUT_MODE.STRETCH_Y` - Stretch node only by Y + - `const.LAYOUT_MODE.ZOOM_MIN` - Zoom node by minimal stretch multiplier + - `const.LAYOUT_MODE.ZOOM_MAX` - Zoom node by maximum stretch multiplier + - `const.LAYOUT_MODE.FIT` - Usual Defold Fit mode + - `const.LAYOUT_MODE.STRETCH` - Usual Defold Stretch Mode + - The Layout changes the node size property. So it's look much better if you use 9slice nodes + - Works even the node parent is have Fit adjust mode +- **#190** [Progress] Add `progress:set_max_size` function to change max size of progress bar +- **#188** [Drag] Add two values passed to on_drag callback. Now it is `on_drag(self, dx, dy, total_x, total_y)` to check the overral drag distance +- **#195** [Drag] Add `drag:is_enabled` and `drag:set_enabled` to enable/disable drag input component +- **#186** [Grid] Fix: Method set_in_row works incorrectly with IS_DYNAMIC_NODE_POSES style option +- **#185** [System] Add `on_window_resized` component interest. It will called on game window size changes +- **#189** [System] Add optional flag to `component:set_input_priority` to mark it as temporary. It will reset to default input priority after the `component:reset_input_priority` From 2f844a31c47d27dc1c0121696f45d1e1ba705a9b Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 29 Aug 2022 21:50:58 +0300 Subject: [PATCH 22/30] Update the Druid logo --- media/druid_logo.png | Bin 6863 -> 121448 bytes media/druid_thumb_logo.png | Bin 1179 -> 12930 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/media/druid_logo.png b/media/druid_logo.png index 84d44b9e31487c53b51fa13d3dccf07b5e7cef12..6b5174b552c992b2ec60baca2d1c2718b1d2fcfd 100644 GIT binary patch literal 121448 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 literal 1179 zcmeAS@N?(olHy`uVBq!ia0y~yVDtiE7G|JGCp)(pkP;2>32}8V@bTaA$A9OaZ(nbn zeEPWJIPmcu+ilT^ zCk(9>4GBdILB$Oj)&G@w1afcrrf**vf6e~=)K3BN_56Q07MwkNIChEt{U^)U^T$v5 z(;}qmHAN$EkxM7Vj8n5iu4JqHpML7tnu%Uhnx<@vvf5d{z(z;zkTt}HPr@2ocb*E* z3a*{9b6?Qx#Z|u)ic3>nR`nZQ4~rA}wD`={slNZ8OKC^EY}+QX_Rag#%^9hEA5WbQ zYhzfIRLvFMHq9n1OFeewsu`W(y9&~)e&$w&SpW1|ofUfLVC_w=e!2OJ-HW2ljE26io?2d1I>)p0udK#a zm(=@@m&$rEP2JZmSG=|>W|gYeWsi_$fwt57Rtc;OS*sbnGL~seSVnyjhff?x_ENhnLT6 z-tGD3WxFL+cCq{Uoj2C4uzB_(^YS;ho_S&Of@TMI&D&h*xtp!}Y0z7*Q<41rd%b+7 ze`9&9*TWkg=ge?+SJm0b4Q5MUo9Qtd`&g#sC$8JQ=)%g^#hG?RZ?DcQv-N#$x$MN$ zck@+|;_|=q)1yaNpM{vUa%Drr|9RHy;IhWRZ zKb^|AxcuTVMVr)xdad;#X|PPrqj{;xzt*hwKChO1%W0*vc-m7-zS&!i z&D?hLEjd1AWkmX=kDro`xnFg4|9WVD;IU`fYrKE&?~k4KDyT&EQ|!i*Igj^l3c2-v z&7Gs?{^_~D{LJt#tg>&W!qQ($H{}Q1^b&9P5r2WJ7 zeZN1;S9iUCT>5%W%yqwi-9H}vb~*ZVY2Dr9AGWvt+O}@R&0=S8zWYD(lij|=*7sL_ u#+>^7!%a(&lX|(*f7u^3``X$a-Cvk(7jbBFyk!OzLkym-elF{r5}E*mUNaK_ From a3f109123e45827a1a259bad176ad2308ecf0a15 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 29 Aug 2022 21:58:29 +0300 Subject: [PATCH 23/30] Update the changelog for 0.10.0 --- docs_md/changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 54d312f..5893be1 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -427,9 +427,16 @@ Also now you can change the input priority of components temporary. For example - `const.LAYOUT_MODE.STRETCH` - Usual Defold Stretch Mode - The Layout changes the node size property. So it's look much better if you use 9slice nodes - Works even the node parent is have Fit adjust mode +- **#200** [Scroll] Glitch if content size equals to scroll view size in runtime +- **#201** [DataList] Update DataList: + - Add two events: `on_element_add` and `on_element_remove` + - Add `data_list:get_data()` to access all current data in DataList + - Add `data_list:get_created_nodes()` to access currently visual nodes in DataList + - Add `data_list:get_created_components()` to access currenly visual component in DataList (if created) - **#190** [Progress] Add `progress:set_max_size` function to change max size of progress bar - **#188** [Drag] Add two values passed to on_drag callback. Now it is `on_drag(self, dx, dy, total_x, total_y)` to check the overral drag distance - **#195** [Drag] Add `drag:is_enabled` and `drag:set_enabled` to enable/disable drag input component - **#186** [Grid] Fix: Method set_in_row works incorrectly with IS_DYNAMIC_NODE_POSES style option - **#185** [System] Add `on_window_resized` component interest. It will called on game window size changes - **#189** [System] Add optional flag to `component:set_input_priority` to mark it as temporary. It will reset to default input priority after the `component:reset_input_priority` +- **#204** [System] Fix: wrong code example link, if open example from direct URL From 2c92a792f7d06c54fba651a6aef54ddd48e07ebe Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 29 Aug 2022 22:18:20 +0300 Subject: [PATCH 24/30] Fix the HTML logo stretch --- example/light_theme.css | 85 +++++++++++++++++++++++++++++++++++++++++ game.project | 1 + 2 files changed, 86 insertions(+) create mode 100644 example/light_theme.css diff --git a/example/light_theme.css b/example/light_theme.css new file mode 100644 index 0000000..3b658db --- /dev/null +++ b/example/light_theme.css @@ -0,0 +1,85 @@ + .canvas-app-progress { + position: absolute; + background-color: #d1dbeb; + height: 6px; + margin-top: -6px; + width: 100%; + } + + .canvas-app-progress-bar { + font-size: 12px; + height: 6px; + color: rgb(255, 255, 255); + background-color: #1a72eb; + text-align: center; + line-height: 20px; + } +{{#html5.show_fullscreen_button}} + .button { + background-image: url("data:image/svg+xml,%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg xmlns='http://www.w3.org/2000/svg' baseProfile='full' width='16' height='16' viewBox='0 0 16 16' version='1.1' xml:space='preserve'%3E%3Ctitle%3Eic-16-fullscreen%3C/title%3E%3Cg id='ic-16-fullscreen' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cpath d='M3,11.5 C3,11.776 3.224,12 3.5,12 L12.5,12 C12.776,12 13,11.776 13,11.5 L13,4.5 C13,4.224 12.776,4 12.5,4 L3.5,4 C3.224,4 3,4.224 3,4.5 L3,11.5 Z M14,11 L14,13 L12,13 C11.724,13 11.5,13.224 11.5,13.5 C11.5,13.776 11.724,14 12,14 L14.5,14 C14.776,14 15,13.776 15,13.5 L15,11 C15,10.724 14.776,10.5 14.5,10.5 C14.224,10.5 14,10.724 14,11 Z M12,2 C11.724,2 11.5,2.224 11.5,2.5 C11.5,2.776 11.724,3 12,3 L14,3 L14,5 C14,5.276 14.224,5.5 14.5,5.5 C14.776,5.5 15,5.276 15,5 L15,2.5 C15,2.224 14.776,2 14.5,2 L12,2 Z M2,13 L2,11 C2,10.724 1.776,10.5 1.5,10.5 C1.224,10.5 1,10.724 1,11 L1,13.5 C1,13.776 1.224,14 1.5,14 L4,14 C4.276,14 4.5,13.776 4.5,13.5 C4.5,13.224 4.276,13 4,13 L2,13 Z M1,2.5 C1,2.224 1.224,2 1.5,2 L4,2 C4.276,2 4.5,2.224 4.5,2.5 C4.5,2.776 4.276,3 4,3 L2,3 L2,5 C2,5.276 1.776,5.5 1.5,5.5 C1.224,5.5 1,5.276 1,5 L1,2.5 Z ' id='fill_1' fill='%23006fff'%3E%3C/path%3E%3C/g%3E%3C/svg%3E"); + background-repeat: no-repeat; + border-color: transparent; + float: left; + color: #006fff; + padding-left: 50%; + padding: 0px 0px 0px 20px; + cursor:pointer; + background-position: left bottom; + margin-left: 2px; + } +{{/html5.show_fullscreen_button}} +{{#html5.show_made_with_defold}} + .link { + text-align: right; + color: #4e5258; + margin-right: 2px; + } + a { + font-weight: 600; + color: #006fff; + text-decoration: none; + } +{{/html5.show_made_with_defold}} + .link, .button { + font-family: sans-serif; + font-size: 14px; + font-weight: normal; + font-style: normal; + font-stretch: normal; + line-height: normal; + letter-spacing: 0px; + padding-top: 12px; + } + + .buttons-background { + background-color: #ffffff; + width: 100%; + height: 42px; + } + + body { + background-color: #ffffff; + } + + .canvas-app-container { + background: rgba(250,252,255,1); + background: -moz-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%); + background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(250,252,255,1)), color-stop(50%, rgba(250,252,255,1)), color-stop(50%, rgba(245,249,255,1)), color-stop(100%, rgba(245,249,255,1))); + background: -webkit-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%); + background: -o-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%); + background: -ms-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%); + background: linear-gradient(135deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fafcff', endColorstr='#f5f9ff', GradientType=1 ); + } + + .canvas-app-canvas { + background-repeat:no-repeat; + background-position: center center; + background-size: contain; +{{#DEFOLD_SPLASH_IMAGE}} + background-image: url("{{DEFOLD_SPLASH_IMAGE}}"); +{{/DEFOLD_SPLASH_IMAGE}} +{{^DEFOLD_SPLASH_IMAGE}} + background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='300px' height='64px' viewBox='-2467.5 2469 300 64' style='enable-background:new -2467.5 2469 300 64;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:%2315244A;%7D .st1%7Bfill:url(%23SVGID_1_);%7D .st2%7Bfill:url(%23SVGID_2_);%7D%0A%3C/style%3E%3Ctitle%3Edefold-logo-html5-splash%3C/title%3E%3Cpolygon class='st0' points='-2177,2482.9 -2175.5,2482.9 -2175.5,2486.7 -2174.4,2486.7 -2174.4,2482.9 -2173.2,2482.9 -2173.2,2481.9 -2177,2481.9 '/%3E%3Cpolygon class='st0' points='-2169.8,2484.1 -2171,2482.1 -2172.1,2482.1 -2172.1,2486.7 -2171,2486.7 -2171,2483.5 -2169.7,2485.6 -2169.7,2485.6 -2168.5,2483.5 -2168.5,2486.7 -2167.5,2486.7 -2167.5,2482.1 -2168.6,2482.1 '/%3E%3Cpath class='st0' d='M-2376,2482h-13.8v38h13.6c6.6,0,12.2-1.9,16.1-5.5c3.8-3.5,5.8-8.5,5.7-13.7v-0.1 C-2354.5,2489.3-2362.9,2482-2376,2482z M-2364,2501.2c0,6.7-4.5,10.9-11.8,10.9h-4.7v-22h4.7c7.3,0,11.8,4.2,11.8,10.9 L-2364,2501.2z'/%3E%3Cpolygon class='st0' points='-2340.9,2505 -2325.1,2505 -2325.1,2497.4 -2340.9,2497.4 -2340.9,2489.6 -2322.4,2489.6 -2322.4,2481.9 -2350.1,2481.9 -2350.1,2520 -2322.2,2520 -2322.2,2512.4 -2340.9,2512.4 '/%3E%3Cpolygon class='st0' points='-2317.1,2481.9 -2317.1,2520 -2307.9,2520 -2307.9,2505.9 -2293,2505.9 -2293,2498.4 -2307.9,2498.4 -2307.9,2489.9 -2289.6,2489.9 -2289.6,2481.9 '/%3E%3Cpolygon class='st0' points='-2233,2482.1 -2242.2,2482.1 -2242.2,2520 -2216.3,2520 -2216.3,2512.2 -2233,2512.2 '/%3E%3Cpath class='st0' d='M-2197.1,2482h-13.7v38h13.5c6.7,0,12.2-1.9,16.1-5.5c3.8-3.5,5.8-8.5,5.7-13.7v-0.1 C-2175.5,2489.3-2184,2482-2197.1,2482z M-2185.1,2501.2c0,6.7-4.5,10.9-11.8,10.9h-4.7v-22h4.7c7.3,0,11.8,4.2,11.8,10.9V2501.2z' /%3E%3Cpath class='st0' d='M-2267.5,2481.7c-10.8,0-19.6,8.8-19.6,19.7c0,10.8,8.8,19.6,19.7,19.6c10.8,0,19.6-8.8,19.6-19.6l0,0 C-2247.8,2490.5-2256.6,2481.7-2267.5,2481.7C-2267.5,2481.7-2267.5,2481.7-2267.5,2481.7z M-2258,2507.9l-8.8,5.1 c-0.5,0.3-1.2,0.3-1.8,0l-8.8-5.1c-0.5-0.3-0.9-0.9-0.9-1.5v-10.2c0-0.6,0.3-1.2,0.9-1.5l8.8-5.1c0.5-0.3,1.2-0.3,1.8,0l8.8,5.1 c0.5,0.3,0.9,0.9,0.9,1.5v10.2C-2257.1,2507-2257.4,2507.6-2258,2507.9z'/%3E%3Cpath class='st0' d='M-2423.2,2494.6l-11.1,6.4l-11.1-6.4l11.1-6.4L-2423.2,2494.6z M-2412.1,2501v12.8l11.1-6.4L-2412.1,2501z M-2467.5,2507.4l11.1,6.4V2501L-2467.5,2507.4z M-2434.3,2526.6l11.1,6.4l11.1-6.4l-11.1-6.4l11.1-6.4l-11.1-6.4l-11.1,6.4 l-11.1-6.4l-11.1,6.4l11.1,6.4l-11.1,6.4l11.1,6.4L-2434.3,2526.6z'/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='-2451.2178' y1='2525.4604' x2='-2406.2178' y2='2499.6304' gradientTransform='matrix(1 0 0 -1 0 5004)'%3E%3Cstop offset='0' style='stop-color:%231C68EC'/%3E%3Cstop offset='1' style='stop-color:%2300E9DF'/%3E%3C/linearGradient%3E%3Cpath class='st1' d='M-2412.1,2513.8v12.8l-11.1-6.4L-2412.1,2513.8z M-2434.3,2513.8V2501l-11.1-6.4v12.8L-2434.3,2513.8z M-2445.4,2469v12.8l11.1-6.4L-2445.4,2469z M-2412.1,2488.2L-2412.1,2488.2 M-2423.2,2507.4l11.1,6.4V2501l11.1,6.4v-12.8 l-11.1-6.4v-12.8l0,0l-11.1-6.4v12.8l-11.1-6.4v12.8l11.1,6.4V2507.4z'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='-2465.9385' y1='2521.2493' x2='-2423.5085' y2='2496.7893' gradientTransform='matrix(1 0 0 -1 0 5004)'%3E%3Cstop offset='0' style='stop-color:%23FF3C2A'/%3E%3Cstop offset='1' style='stop-color:%23FFD215'/%3E%3C/linearGradient%3E%3Cpath class='st2' d='M-2434.3,2513.8V2501l11.1-6.4v12.8L-2434.3,2513.8z M-2434.3,2475.4l11.1,6.4V2469L-2434.3,2475.4z M-2456.5,2488.2L-2456.5,2488.2 M-2445.4,2494.6l11.1-6.4v-12.8l-11.1,6.4V2469l-11.1,6.4l0,0v12.8l-11.1,6.4v12.8l11.1-6.4v12.8 l11.1-6.4V2494.6z M-2456.5,2513.8v12.8l11.1-6.4L-2456.5,2513.8z'/%3E%3C/svg%3E%0A"); +{{/DEFOLD_SPLASH_IMAGE}} + } diff --git a/game.project b/game.project index 66a1aaa..04d940e 100644 --- a/game.project +++ b/game.project @@ -47,6 +47,7 @@ splash_image = /media/druid_logo.png scale_mode = fit show_fullscreen_button = 0 show_made_with_defold = 0 +cssfile = /example/light_theme.css [native_extension] app_manifest = /example/game.appmanifest From e683eed90fc6fdf31fb8f387b8c36c6e6645cf22 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 6 Sep 2022 21:35:43 +0300 Subject: [PATCH 25/30] Solve #202 set check stencil node enabled by default --- README.md | 6 +++--- druid/const.lua | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6944e06..681033d 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,11 @@ no_auto_template = 1 ### Stencil check [optional] -When creating input components inside stencil nodes, you probably will use `component:set_click_zone()` to restrict clicks outside this stencil zone. -Druid can do it automatically on _late_init_ component step. To enable this feature add next field in your _game.project_ file +When creating input components inside stencil nodes, **Druid** automatically setup `component:set_click_zone()` on _late_init_ component step to restrict input clicks outside this stencil zone. +To disable this feature add next field in your _game.project_ file ``` [druid] -stencil_check = 1 +no_stencil_check = 1 ``` diff --git a/druid/const.lua b/druid/const.lua index 12839ba..5276299 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -21,7 +21,7 @@ M.ACTION_SCROLL_UP = hash(sys.get_config("druid.input_scroll_up", "scroll_up")) M.ACTION_SCROLL_DOWN = hash(sys.get_config("druid.input_scroll_down", "scroll_down")) -M.IS_STENCIL_CHECK = sys.get_config("druid.stencil_check") == "1" +M.IS_STENCIL_CHECK = not (sys.get_config("druid.no_stencil_check") == "1") M.RELEASED = "released" @@ -93,7 +93,6 @@ M.LAYOUT_MODE = { STRETCH = gui.ADJUST_STRETCH, } - M.VECTOR_ZERO = vmath.vector3(0) M.VECTOR_ONE = vmath.vector3(1) M.SYS_INFO = sys.get_sys_info() From 25a17773e704e8b881e3ade6ee8de8b50fa780bd Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 6 Sep 2022 22:09:32 +0300 Subject: [PATCH 26/30] Solve #198 move input init and late init to Druid instance init function --- druid/system/druid_instance.lua | 19 ++++++++++++++----- game.project | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 192e684..ea002ca 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -57,7 +57,7 @@ local lang_text = require("druid.extended.lang_text") local progress = require("druid.extended.progress") local radio_group = require("druid.extended.radio_group") local slider = require("druid.extended.slider") -local timer = require("druid.extended.timer") +local timer_component = require("druid.extended.timer") local data_list = require("druid.extended.data_list") @@ -215,6 +215,10 @@ function DruidInstance.initialize(self, context, style) for i = 1, #base_component.ALL_INTERESTS do self.components_interest[base_component.ALL_INTERESTS[i]] = {} end + + timer.delay(0, false, function() + self:late_init() + end) end @@ -311,10 +315,9 @@ function DruidInstance.remove(self, component) end ---- Druid update function +--- Druid late update function call after init and before udpate step -- @tparam DruidInstance self --- @tparam number dt Delta time -function DruidInstance.update(self, dt) +function DruidInstance.late_init(self) local late_init_components = self.components_interest[base_component.ON_LATE_INIT] while late_init_components[1] do late_init_components[1]:on_late_init() @@ -325,7 +328,13 @@ function DruidInstance.update(self, dt) -- Input init on late init step, to be sure it goes after user go acquire input input_init(self) end +end + +--- Druid update function +-- @tparam DruidInstance self +-- @tparam number dt Delta time +function DruidInstance.update(self, dt) self._is_late_remove_enabled = true local components = self.components_interest[base_component.ON_UPDATE] for i = 1, #components do @@ -724,7 +733,7 @@ end -- @treturn Timer timer component function DruidInstance.new_timer(self, node, seconds_from, seconds_to, callback) -- return helper.extended_component("timer") - return DruidInstance.new(self, timer, node, seconds_from, seconds_to, callback) + return DruidInstance.new(self, timer_component, node, seconds_from, seconds_to, callback) end diff --git a/game.project b/game.project index 04d940e..2ae077f 100644 --- a/game.project +++ b/game.project @@ -27,7 +27,7 @@ use_accelerometer = 0 [druid] no_auto_input = 0 -stencil_check = 0 +no_stencil_check = 0 no_auto_template = 0 input_text = text input_touch = touch From ba383261b03dc5aebef6d38a3abce3dc9deafafa Mon Sep 17 00:00:00 2001 From: Insality Date: Fri, 9 Sep 2022 20:45:08 +0300 Subject: [PATCH 27/30] Update layout component, add layout fit example --- docs_md/changelog.md | 3 +- druid/extended/layout.lua | 198 ++- example/assets/images/kenney.atlas | 4 + example/assets/images/logo.png | Bin 0 -> 25918 bytes example/example.gui_script | 3 + example/examples/general/layout/layout.gui | 10 +- .../examples/general/layout/layout.gui_script | 2 +- .../layout/layout_fit/layout_fit.collection | 37 + .../examples/layout/layout_fit/layout_fit.gui | 1247 +++++++++++++++++ .../layout/layout_fit/layout_fit.gui_script | 44 + 10 files changed, 1472 insertions(+), 76 deletions(-) create mode 100644 example/assets/images/logo.png create mode 100644 example/examples/layout/layout_fit/layout_fit.collection create mode 100644 example/examples/layout/layout_fit/layout_fit.gui create mode 100644 example/examples/layout/layout_fit/layout_fit.gui_script diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 5893be1..d14ca49 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -413,7 +413,7 @@ Also now you can change the input priority of components temporary. For example - **#133** [Hotkey] Add new extended component: Hotkey - It's allow you set hotkeys to call callbacks - - You should pass one action key and several modificator keys (left shift, ctrl etc) + - You should pass one action key and several modificator keys (left shift, right ctrl etc) - List of modificator keys setup via component style (you can change it) - You can add several hotkeys on one callback via `hotkey:add_hotkey` with additional params - **#98** [Layout] Add new extended component: Layout @@ -440,3 +440,4 @@ Also now you can change the input priority of components temporary. For example - **#185** [System] Add `on_window_resized` component interest. It will called on game window size changes - **#189** [System] Add optional flag to `component:set_input_priority` to mark it as temporary. It will reset to default input priority after the `component:reset_input_priority` - **#204** [System] Fix: wrong code example link, if open example from direct URL +- **#202** [System] Enabled stencil check to true by default. To disable this, use druid.no_stencil_check in game.project settings diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 2a4a24f..f2cfd75 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -5,6 +5,15 @@ -- @within BaseComponent -- @alias druid.layout +--- Layout node +-- @tfield node node + +--- Current layout mode +-- @tfield string mode + +---On window resize callback(self, new_size) +-- @tfield DruidEvent on_size_changed @{DruidEvent} + --- @@ -17,111 +26,162 @@ local Event = require("druid.event") local Layout = component.create("layout") -function Layout:init(node, mode, on_size_changed_callback) - self.node = self:get_node(node) +--- Component init function +-- @tparam Layout self @{Layout} +-- @tparam node node Gui node +-- @tparam string node The layout mode (from const.LAYOUT_MODE) +-- @tparam[opt] function on_size_changed_callback The callback on window resize +function Layout.init(self, node, mode, on_size_changed_callback) + self.node = self:get_node(node) - self._min_size = nil - self._max_size = nil - self._inited = false + 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._fit_node = nil - self.on_size_changed = Event(on_size_changed_callback) + 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() +function Layout.on_late_init(self) + 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() - if not self._inited then - return - end +function Layout.on_window_resized(self) + if not self._inited then + return + end 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 - 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._fit_node then + self.fit_size = gui.get_size(self._fit_node) + self.fit_size.x = self.fit_size.x / x_koef + self.fit_size.y = self.fit_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 + x_koef = self.fit_size.x / self.origin_size.x * x_koef + y_koef = self.fit_size.y / self.origin_size.y * y_koef - 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) + 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) + 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 + 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) + gui.set_position(self.node, self.position) - self.on_size_changed:trigger(self:get_context(), new_size) + 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 +--- Set minimal size of layout node +-- @tparam Layout self @{Layout} +-- @tparam vector3 min_size +-- @treturn Layout @{Layout} +function Layout.set_min_size(self, min_size) + self._min_size = min_size + return self end -function Layout:set_max_size(max_size) - self._max_size = max_size - return self +--- Set maximum size of layout node +-- @tparam Layout self @{Layout} +-- @tparam vector3 min_size +-- @treturn Layout @{Layout} +function Layout.set_max_size(self, 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 +--- Set new origin position of layout node. You should apply this on node movement +-- @tparam Layout self @{Layout} +-- @tparam vector3 new_origin_position +-- @treturn Layout @{Layout} +function Layout.set_origin_position(self, new_origin_position) + self.origin_position = new_origin_position or self.origin_position + 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() - return self +--- Set new origin size of layout node. You should apply this on node manual size change +-- @tparam Layout self @{Layout} +-- @tparam vector3 new_origin_size +-- @treturn Layout @{Layout} +function Layout.set_origin_size(self, 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 +--- Set size for layout node to fit inside it +-- @tparam Layout self @{Layout} +-- @tparam vector3 target_size +-- @treturn Layout @{Layout} +function Layout.fit_into_size(self, 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)) +--- Set node for layout node to fit inside it. Pass nil to reset +-- @tparam Layout self @{Layout} +-- @tparam[opt] Node node +-- @treturn Layout @{Layout} +function Layout.fit_into_node(self, node) + self._fit_node = node + self:on_window_resized() + return self +end + + +--- Set current size for layout node to fit inside it +-- @tparam Layout self @{Layout} +-- @treturn Layout @{Layout} +function Layout.fit_into_window(self) + return self:fit_into_size(vmath.vector3( + gui.get_width(), + gui.get_height(), + 0)) end diff --git a/example/assets/images/kenney.atlas b/example/assets/images/kenney.atlas index 31a9f7b..ead7b5a 100644 --- a/example/assets/images/kenney.atlas +++ b/example/assets/images/kenney.atlas @@ -62,6 +62,10 @@ images { image: "/example/assets/images/buttons/button_blue.png" sprite_trim_mode: SPRITE_TRIM_MODE_OFF } +images { + image: "/example/assets/images/logo.png" + sprite_trim_mode: SPRITE_TRIM_MODE_OFF +} margin: 0 extrude_borders: 2 inner_padding: 0 diff --git a/example/assets/images/logo.png b/example/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7a56d26e89423b887d35d220c3b5c0d189f15a7c GIT binary patch literal 25918 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 Date: Fri, 9 Sep 2022 20:45:27 +0300 Subject: [PATCH 28/30] Update progress bar component, add progress bar example --- druid/extended/progress.lua | 4 + example/example.collection | 126 +++ example/example.gui_script | 2 +- .../progress_bar/progress_bar.collection | 37 + .../general/progress_bar/progress_bar.gui | 981 ++++++++++++++++++ .../progress_bar/progress_bar.gui_script | 66 ++ 6 files changed, 1215 insertions(+), 1 deletion(-) create mode 100644 example/examples/general/progress_bar/progress_bar.collection create mode 100644 example/examples/general/progress_bar/progress_bar.gui create mode 100644 example/examples/general/progress_bar/progress_bar.gui_script diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index aa2cd03..1e6fd4d 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -75,6 +75,9 @@ local function set_bar_to(self, set_to, is_silent) if not is_silent then check_steps(self, prev_value, set_to) + if prev_value ~= self.last_value then + self.on_change:trigger(self:get_context(), self.last_value) + end end end @@ -170,6 +173,7 @@ end -- @tparam Progress self @{Progress} -- @tparam number to Progress bar value, from 0 to 1 function Progress.set_to(self, to) + to = helper.clamp(to, 0, 1) set_bar_to(self, to) end diff --git a/example/example.collection b/example/example.collection index f6f8c84..097a84f 100644 --- a/example/example.collection +++ b/example/example.collection @@ -1877,3 +1877,129 @@ embedded_instances { z: 1.0 } } +embedded_instances { + id: "layout_fit" + 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: \"layout_fit\"\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/layout/layout_fit/layout_fit.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 + } +} +embedded_instances { + id: "general_progress_bar" + 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_progress_bar\"\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/progress_bar/progress_bar.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 4b50739..e8f0709 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -128,7 +128,7 @@ local function init_lobby(self) self.lobby_grid:add(get_button(self, "Sliders", "general_sliders", "/general/sliders/sliders.gui_script")) self.lobby_grid:add(get_button(self, "Scrolls", "general_scroll", "/general/scroll/scroll.gui_script")) self.lobby_grid:add(get_button(self, "Grids", "general_grid", "/general/grid/grid.gui_script")) - self.lobby_grid:add(get_button_disabled(self, "Progress Bar", "scene_name")) + self.lobby_grid:add(get_button(self, "Progress Bar", "general_progress_bar", "/general/progress_bar/progress_bar.gui_script")) 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")) diff --git a/example/examples/general/progress_bar/progress_bar.collection b/example/examples/general/progress_bar/progress_bar.collection new file mode 100644 index 0000000..022f807 --- /dev/null +++ b/example/examples/general/progress_bar/progress_bar.collection @@ -0,0 +1,37 @@ +name: "progress_bar" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"progress_bar\"\n" + " component: \"/example/examples/general/progress_bar/progress_bar.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/progress_bar/progress_bar.gui b/example/examples/general/progress_bar/progress_bar.gui new file mode 100644 index 0000000..24c3154 --- /dev/null +++ b/example/examples/general/progress_bar/progress_bar.gui @@ -0,0 +1,981 @@ +script: "/example/examples/general/progress_bar/progress_bar.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_FIT + 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: -150.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: 45.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/progress_back" + id: "progress_back_x" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "root" + layer: "image" + 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: 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: 300.0 + y: 45.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/progress_fill_yellow" + id: "progress_fill_x" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "progress_back_x" + layer: "image" + inherit_alpha: true + slice9 { + x: 10.0 + y: 0.0 + z: 10.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: 150.0 + y: 2.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 100.0 + y: 60.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: "15%" + font: "game" + id: "text_progress_amount_x" + 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: "progress_back_x" + layer: "text" + 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: -195.0 + y: 123.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: 45.0 + y: 300.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/progress_back" + id: "progress_back_y" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "root" + layer: "image" + inherit_alpha: true + slice9 { + x: 0.0 + y: 10.0 + z: 0.0 + w: 10.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: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 45.0 + y: 300.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/progress_fill_yellow" + id: "progress_fill_y" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "progress_back_y" + layer: "image" + inherit_alpha: true + slice9 { + x: 10.0 + y: 10.0 + z: 10.0 + w: 10.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: -150.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 90.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 100.0 + y: 60.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: "15%" + font: "game" + id: "text_progress_amount_y" + 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: "progress_back_y" + layer: "text" + 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: -150.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: 200.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_TEMPLATE + id: "button_set_0" + parent: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false + 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: 130.0 + y: 60.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/button_blue" + id: "button_set_0/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_set_0" + layer: "image" + inherit_alpha: true + slice9 { + x: 15.0 + y: 15.0 + z: 15.0 + w: 15.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: true + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 7.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 200.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: "Set 0" + font: "game" + id: "button_set_0/text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.101960786 + y: 0.2 + z: 0.6 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "button_set_0/button" + layer: "text" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.78 + overridden_fields: 8 + template_node_child: true + text_leading: 1.0 + text_tracking: 0.0 + 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: 200.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_TEMPLATE + id: "button_add_25" + parent: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false + 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: 130.0 + y: 60.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/button_blue" + id: "button_add_25/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_add_25" + layer: "image" + inherit_alpha: true + slice9 { + x: 15.0 + y: 15.0 + z: 15.0 + w: 15.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: true + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 7.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 200.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: "Add 25" + font: "game" + id: "button_add_25/text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.101960786 + y: 0.2 + z: 0.6 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "button_add_25/button" + layer: "text" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.78 + overridden_fields: 8 + template_node_child: true + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: 150.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: 200.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_TEMPLATE + id: "button_set_100" + parent: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false + 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: 130.0 + y: 60.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/button_blue" + id: "button_set_100/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_set_100" + layer: "image" + inherit_alpha: true + slice9 { + x: 15.0 + y: 15.0 + z: 15.0 + w: 15.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: true + size_mode: SIZE_MODE_MANUAL + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 7.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.7 + y: 0.7 + z: 1.0 + w: 1.0 + } + size { + x: 200.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: "Set 100" + font: "game" + id: "button_set_100/text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 0.101960786 + y: 0.2 + z: 0.6 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "button_set_100/button" + layer: "text" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.78 + overridden_fields: 8 + template_node_child: true + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: 0.0 + y: 40.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.5 + y: 0.5 + z: 1.0 + w: 1.0 + } + size { + x: 500.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: "Last step triggered: none" + font: "game" + id: "text_x_hint" + 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: "root" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.75 + 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/progress_bar/progress_bar.gui_script b/example/examples/general/progress_bar/progress_bar.gui_script new file mode 100644 index 0000000..1d504e6 --- /dev/null +++ b/example/examples/general/progress_bar/progress_bar.gui_script @@ -0,0 +1,66 @@ +local druid = require("druid.druid") + + +local function on_button_set_0(self) + self.progress_x:to(0) + self.progress_y:set_to(0) +end + + +local function on_button_add_25(self) + self.progress_x:to(self.progress_x:get() + 0.25) + self.progress_y:set_to(self.progress_x:get() + 0.25) +end + + +local function on_button_set_100(self) + self.progress_x:to(1) + self.progress_y:set_to(1) +end + + +local function on_progress_step(self, value) + gui.set_text(gui.get_node("text_x_hint"), "Last step triggered: " .. value) +end + + +function init(self) + self.druid = druid.new(self) + + self.progress_x = self.druid:new_progress("progress_fill_x", "x", 0.4) + self.progress_x:set_steps({0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1}, on_progress_step) + self.progress_x.on_change:subscribe(function(_, value) + value = math.floor(value * 100) + gui.set_text(gui.get_node("text_progress_amount_x"), value .. "%") + end) + + self.progress_y = self.druid:new_progress("progress_fill_y", "y", 0.6) + self.progress_y.on_change:subscribe(function(_, value) + value = math.floor(value * 100) + gui.set_text(gui.get_node("text_progress_amount_y"), value .. "%") + end) + + self.druid:new_button("button_set_0/button", on_button_set_0) + self.druid:new_button("button_add_25/button", on_button_add_25) + self.druid:new_button("button_set_100/button", on_button_set_100) +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 072507cc9e715541bdee7636d2e5eeeb3c22a57d Mon Sep 17 00:00:00 2001 From: Insality Date: Fri, 9 Sep 2022 20:46:26 +0300 Subject: [PATCH 29/30] Fix progress bar example --- example/examples/general/progress_bar/progress_bar.gui_script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/examples/general/progress_bar/progress_bar.gui_script b/example/examples/general/progress_bar/progress_bar.gui_script index 1d504e6..1026d58 100644 --- a/example/examples/general/progress_bar/progress_bar.gui_script +++ b/example/examples/general/progress_bar/progress_bar.gui_script @@ -9,7 +9,7 @@ end local function on_button_add_25(self) self.progress_x:to(self.progress_x:get() + 0.25) - self.progress_y:set_to(self.progress_x:get() + 0.25) + self.progress_y:set_to(self.progress_y:get() + 0.25) end From cb5df2b5bcf12cea125ff67ad088c04c2a84450d Mon Sep 17 00:00:00 2001 From: Insality Date: Fri, 9 Sep 2022 21:01:33 +0300 Subject: [PATCH 30/30] Update docs, html example --- deployer_build_stats.csv | 2 + docs/druid/archive/archive_files.json | 2 +- docs/druid/archive/game.arcd0 | Bin 421233 -> 449757 bytes docs/druid/archive/game.arci0 | Bin 17728 -> 19808 bytes docs/druid/archive/game.dmanifest0 | Bin 18513 -> 20704 bytes docs/druid/archive/game.projectc0 | 12 +- docs/druid/index.html | 4 +- docs/modules/DruidInstance.html | 25 ++ docs/modules/Layout.html | 371 ++++++++++++++++++++++++++ docs_md/changelog.md | 17 +- druid/annotations.lua | 62 +++++ druid/extended/layout.lua | 4 +- game.project | 2 +- 13 files changed, 484 insertions(+), 17 deletions(-) diff --git a/deployer_build_stats.csv b/deployer_build_stats.csv index de95ac5..09bbddc 100644 --- a/deployer_build_stats.csv +++ b/deployer_build_stats.csv @@ -7,3 +7,5 @@ date,sha,version,build_size,build_time,platform,mode,is_cache_using,commits_coun 2022-03-12T10:01:30Z,d0f3d6641a08b0d6b719b13017aa85907d1667e5,0.8.564,2200,44,js-web,release,true,564 2022-08-29T18:27:58Z,b2643ebd268b15884363efd17724e689279946f1,0.9.589,2316,45,js-web,release,true,589 2022-08-29T18:46:47Z,13003e472169cbd261e703eca7b133adf64a24f7,0.9.592,2316,40,js-web,release,true,592 +2022-09-09T17:55:42Z,072507cc9e715541bdee7636d2e5eeeb3c22a57d,0.10.603,2340,43,js-web,release,true,603 +2022-09-09T18:00:07Z,072507cc9e715541bdee7636d2e5eeeb3c22a57d,0.10.603,2340,5,js-web,release,true,603 diff --git a/docs/druid/archive/archive_files.json b/docs/druid/archive/archive_files.json index 5138234..28c4c68 100644 --- a/docs/druid/archive/archive_files.json +++ b/docs/druid/archive/archive_files.json @@ -1 +1 @@ -{"content":[{"name":"game.projectc","size":3808,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":17728,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":421233,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":18513,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]} \ No newline at end of file +{"content":[{"name":"game.projectc","size":3797,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":19808,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":449757,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":20704,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]} \ No newline at end of file diff --git a/docs/druid/archive/game.arcd0 b/docs/druid/archive/game.arcd0 index 39b87ed22d807536fe40dda6b1f991875813544c..3e66d7633b0b7b6b072277ac902e1ee17ae76e83 100644 GIT binary patch delta 54920 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 CQPfHR delta 28481 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 To}?MEwI!D(yNtunv#0$Zvz{CC diff --git a/docs/druid/archive/game.dmanifest0 b/docs/druid/archive/game.dmanifest0 index 04fba65f43f967a9f8240f663acb6768f327be03..05763cbaa4c38a6404c5cf2ef9c83865eb2939ea 100644 GIT binary patch delta 2784 zcmai$c|2768^_H|wm}VZsO&{quFPiU*s>NCS+bTcX3m@uDH@bEWoehCua;ZZT$M(a zCQ3!6#4U*sC3`6$5hbMG%=q2=QvH^{&N+X4-_PfHp3nDrPJI%lGYf;mS7j#SmO(E~ zvOoB4c95fb+!;FQzaXigMN&H1U_sHwLLBtriH!DKx%u^Vt;o`Z2NjKPfPw+goI{4H zg6h@Y6iL=~u?ls^wP0zB>`Tgg_MB{th6kQR@(Vz>qFiP;%JzdQ^Q<$GeDvcGzfFpVS!svYoUI#$ zjc5qWFk+%CCX>n`i-dPy&S@?mepsm?j6v2N^0DpNANgD6sE+T(T!qvD!}t6Hcz?_S zy=k#=-Fw|0R=2lRO*Ok#?_5=)u8UD#4_r-Et%I36Ln6XSGmjrKD6JX2lbA6%tRtik z7}!uh73~^#J)Ofzfujx60_fKSj2(E_WPerAj+qC{WC?szSyL>Oz9fWb-m9pX*;9RC zk$0(1!K$F6;PBiv7*Rm8O(Ef%(Ve83hanOY9E>92fgxKF!XJYz*HdpiZXyc4Z$}Fpy0_|RS3UF0b1{PMbz+e6fRC?9-Qd<#sf?4HDN|3>S zVfjYy71$_FS%z^gN^EVF`Btg6KW}5-!*~3?BZBjh_;rHwL=a^#52$MC0%@Wf>?7U^at+l9>z+hc0sUWX{2<>QkLLYlW&G z;Zqa#L{Bbv%Gsyan_DC&FNX~~HC~0p=0*gvNoZs^x|NNx|Mqrp1QQ{=$^TH&^WgN|Fd=euA*EUk2!rigrpeM zZ8^EUwdIakj}HcOTepql^Zpl$ECFA%&q4%~-o*G;%d*3V_v>psRVR5FNn7%BmfXNV z&tj8hEQn*YzovLrFNpgM-ex#w1=}4^c;r#T7LrocF%F6nPVL>Zjw} z@CHH;(|@_e2!Z#tula64b}qmO1@_Ari1&Od1O;{^UagoLj@ z%!Lb|qtgyee$CGj$*_GdD@i4g9ow_k_BEF8s+m*KZzU+TCy3Tm1*vpAxJRW}+x+T+ ze-9jy3%Xu4?9V%y*gHcsOmJ`WI~y}4&h(EW*<%;T`??twzv1;V{yJ$qIB zvNsSy@#MtSqK^Kt8Iq+7-0Zc*OoC?ohG}&v{qWhGYcw z_rM#9rfHG|k-yBO7X!l_)PzklW|NIkhG4?Y42P7?*o&?CaeqD*p^9Q|E0(_@O7swI zBB6~N%+|lKr2>qZqoe(g%MYO$BM6yJVWLdB5zLvne=ianPM4(g#ny^YE4R9oe0vnN z^cc-z>1%!WTQZWWg|k!z(}-ZNnG@6ld2Je5o0Q=r(;GK3R13RgNtS~SvnmV+3@bsx zHm&;aZJIrr+RxY2_q@(4sh^2{r^bC@kIf0w0mXGZGK$nbBF&|;D3G@ zP9HhfUX#{%=DCQeKGwb5=;>)W+g0~XPp9gY&kGuh2cZ^Z@Vg+$95Z=3n`4Za7*p5` z6sA#TY7(Ez`;yRbYqCW|F!kNvb1Ssz(W%32tQARx6UVitmVpaK>U^w4CH9vZQ#mGN zDu>FUnV>WTooUzGMGZne+aUkJk1L&ie<%O^)2j-w z&E9EW;4aI^*3QFJP5ZHjAyQbiH_GmS)%m%60bM_O^+eGD=CxlG;|%UDyvt7dvt5cJ}$w z7d}htGtn9;-@f{2xY!pqxL~vN`+Nyzw7gPbJ<&*+pnb!^sc%3n&XKWh1$_Cyk$(Zz CLVT(K delta 942 zcmV;f15y0op#jm50RsxSkC6i{6kZD0ISqG>hNPou<*jK@18R=DhLJ27v0ShN6iPCt zh-e2$k1TEMVupn#)Kv>`fwJLuZ;y2ZB>(@4-}I`5H_>b z5M=_BkrUPw_`cJbOEB_4wXhJ)WA$X@-LWQclY10|8dh{%hl(P&5KA+APVY;g??E|! z@+biscnVUJp%)XAKrIiG3@Ig(U=>yrS=1nwgS5PDw2SeOkEmw4Ir=kuv&t3Y1hWJi zO9K?{*hg5pO*@>q1MA$tkwRD5neYXZV;(&e^Ms1%FY;WQtT?n?e(szaPAz(Tv$P%v z1G5(*bpf-~BXWcnVUJp%)XAKrIiG3@N`9 zvnem}cS!7lf+o?ODJgfxv=h?7v)?JW0ThOD?kdCXTJ%V-;KBZt3sNqZ5XiHuD_a8; zzCkKL&yb2-Qd+f58pAFA9cCp)lP^6MlQ1ucvkfq21Cz)zdlVZSd!1K=rYU1*twmO+ zD$61IP7{+?G=vlamcgj+Yq~a*i#aZm4JkZNFRt#h?=+7BlfyeFlL$C516v9-lc5(H zlN=uzle0L5v++3-0u+4?ZGtK5(NI8%DGimWDkwGVp9ZrSJVpT;^32K(WEO8myWL{W zAKfdOeEmHpC;=K-3Nn+S7aEi20vD61J(mr*t{kx%1gHy$kAAj~H9wf1_BZw0LX7RoTN zw=yyH-QYrWiRZXiNcaH8`ZV)8`%?){!8NyM84}_b8l}HA - druid 0.9.592 + druid 0.10.603 diff --git a/docs/modules/DruidInstance.html b/docs/modules/DruidInstance.html index 8423387..6cfea85 100644 --- a/docs/modules/DruidInstance.html +++ b/docs/modules/DruidInstance.html @@ -114,6 +114,10 @@ Call on final function on gui_script. + late_init(self) + Druid late update function call after init and before udpate step + + log_message(self, message[, context]) Log message, if is_debug mode is enabled @@ -268,6 +272,27 @@ + +
    + + late_init(self) +
    +
    + Druid late update function call after init and before udpate step + + +

    Parameters:

    +
      +
    • self + DruidInstance + +
    • +
    + + + + +
    diff --git a/docs/modules/Layout.html b/docs/modules/Layout.html index fa51dd2..cb33308 100644 --- a/docs/modules/Layout.html +++ b/docs/modules/Layout.html @@ -30,6 +30,11 @@
  • Index
  • +

    Contents

    +

    Modules

    @@ -73,11 +78,377 @@

    +

    Functions

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    fit_into_node(self[, node])Set node for layout node to fit inside it.
    fit_into_size(self, target_size)Set size for layout node to fit inside it
    fit_into_window(self)Set current size for layout node to fit inside it
    init(self, node, mode[, on_size_changed_callback])Component init function
    set_max_size(self, max_size)Set maximum size of layout node
    set_min_size(self, min_size)Set minimal size of layout node
    set_origin_position(self, new_origin_position)Set new origin position of layout node.
    set_origin_size(self, new_origin_size)Set new origin size of layout node.
    +

    Fields

    + + + + + + + + + + + + + +
    modeCurrent layout mode
    nodeLayout node
    on_size_changedOn window resize callback(self, new_size)


    +

    Functions

    + +
    +
    + + fit_into_node(self[, node]) +
    +
    + Set node for layout node to fit inside it. Pass nil to reset + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • node + Node + + (optional) +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    + + fit_into_size(self, target_size) +
    +
    + Set size for layout node to fit inside it + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • target_size + vector3 + +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    + + fit_into_window(self) +
    +
    + Set current size for layout node to fit inside it + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    + + init(self, node, mode[, on_size_changed_callback]) +
    +
    + Component init function + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • node + node + Gui node +
    • +
    • mode + string + The layout mode (from const.LAYOUT_MODE) +
    • +
    • on_size_changed_callback + function + The callback on window resize + (optional) +
    • +
    + + + + + +
    +
    + + set_max_size(self, max_size) +
    +
    + Set maximum size of layout node + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • max_size + vector3 + +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    + + set_min_size(self, min_size) +
    +
    + Set minimal size of layout node + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • min_size + vector3 + +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    + + set_origin_position(self, new_origin_position) +
    +
    + Set new origin position of layout node. You should apply this on node movement + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • new_origin_position + vector3 + +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    + + set_origin_size(self, new_origin_size) +
    +
    + Set new origin size of layout node. You should apply this on node manual size change + + +

    Parameters:

    +
      +
    • self + Layout + Layout +
    • +
    • new_origin_size + vector3 + +
    • +
    + +

    Returns:

    +
      + + Layout + Layout +
    + + + + +
    +
    +

    Fields

    + +
    +
    + + mode +
    +
    + Current layout mode + + + + + + + + +
    +
    + + node +
    +
    + Layout node + + +
      +
    • node + node + +
    • +
    + + + + + +
    +
    + + on_size_changed +
    +
    + On window resize callback(self, new_size) + + + + + + + + +
    +
    diff --git a/docs_md/changelog.md b/docs_md/changelog.md index d14ca49..a442d6b 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -395,7 +395,7 @@ Take care of yourself ### Druid 0.10.0 -Hello! Here is new Druid small update. It's brings to you two new components: Layout and Hotkey. Both components are "extended", so to use it, you should register it first (when you try to use it, in console will be prompt with code you should use) +Hello! Here is new Druid update. It's brings to you two new components: Layout and Hotkey. Both components are "extended", so to use it, you should register it first (when you try to use it, in console will be prompt with code you should use) In general: ``` @@ -403,9 +403,13 @@ local layout = require("druid.extended.layout") druid.register("layout", layout) ``` -The drag component now knows about window scaling, so now it have more accuracy dx/dy values depends on the screen size. The scroll and other components should work better :) +The Drag component now knows about window scaling, so now it have more accuracy dx/dy values depends on the screen size. The scroll and other components should work better :) -Also now you can change the input priority of components temporary. For example while you interact with them (input fields, drag on select etc). +Now you can change the input priority of components temporary. For example while you interact with them (input fields, drag on select etc). + +Also the update brings several bug fixes and now **Druid** have stencil_check mode enabled by default. It should be more easy to use input components with stencil nodes without manual `set_click_zone` functions. + +And yeah, the new **Druid** logo is here! **Changelog 0.10.0** @@ -414,7 +418,7 @@ Also now you can change the input priority of components temporary. For example - **#133** [Hotkey] Add new extended component: Hotkey - It's allow you set hotkeys to call callbacks - You should pass one action key and several modificator keys (left shift, right ctrl etc) - - List of modificator keys setup via component style (you can change it) + - List of modificator keys ids setup via component style (you can change it) - You can add several hotkeys on one callback via `hotkey:add_hotkey` with additional params - **#98** [Layout] Add new extended component: Layout - It's allow you to extend standart Defold node adjust modes @@ -436,8 +440,9 @@ Also now you can change the input priority of components temporary. For example - **#190** [Progress] Add `progress:set_max_size` function to change max size of progress bar - **#188** [Drag] Add two values passed to on_drag callback. Now it is `on_drag(self, dx, dy, total_x, total_y)` to check the overral drag distance - **#195** [Drag] Add `drag:is_enabled` and `drag:set_enabled` to enable/disable drag input component -- **#186** [Grid] Fix: Method set_in_row works incorrectly with IS_DYNAMIC_NODE_POSES style option +- **#186** [Grid] Fix: Method `set_in_row` works incorrectly with IS_DYNAMIC_NODE_POSES style option - **#185** [System] Add `on_window_resized` component interest. It will called on game window size changes - **#189** [System] Add optional flag to `component:set_input_priority` to mark it as temporary. It will reset to default input priority after the `component:reset_input_priority` - **#204** [System] Fix: wrong code example link, if open example from direct URL -- **#202** [System] Enabled stencil check to true by default. To disable this, use druid.no_stencil_check in game.project settings +- **#202** [System] Enabled stencil check to true by default. To disable this, use `druid.no_stencil_check` in game.project settings +- [Examples] Add layout, layout fit, progres bar, data list + component examples diff --git a/druid/annotations.lua b/druid/annotations.lua index 30a751a..7d33117 100644 --- a/druid/annotations.lua +++ b/druid/annotations.lua @@ -763,6 +763,64 @@ function druid__lang_text.set_to(self, text) end function druid__lang_text.translate(self, locale_id, a, b, c, d, e, f, g) end +---@class druid.layout : druid.base_component +---@field mode string Current layout mode +---@field node node Layout node +---@field on_size_changed druid.event On window resize callback(self, new_size) +local druid__layout = {} + +--- Set node for layout node to fit inside it. +--- Pass nil to reset +---@param self druid.layout @{Layout} +---@param node Node +---@return druid.layout @{Layout} +function druid__layout.fit_into_node(self, node) end + +--- Set size for layout node to fit inside it +---@param self druid.layout @{Layout} +---@param target_size vector3 +---@return druid.layout @{Layout} +function druid__layout.fit_into_size(self, target_size) end + +--- Set current size for layout node to fit inside it +---@param self druid.layout @{Layout} +---@return druid.layout @{Layout} +function druid__layout.fit_into_window(self) end + +--- Component init function +---@param self druid.layout @{Layout} +---@param node node Gui node +---@param mode string The layout mode (from const.LAYOUT_MODE) +---@param on_size_changed_callback function The callback on window resize +function druid__layout.init(self, node, mode, on_size_changed_callback) end + +--- Set maximum size of layout node +---@param self druid.layout @{Layout} +---@param max_size vector3 +---@return druid.layout @{Layout} +function druid__layout.set_max_size(self, max_size) end + +--- Set minimal size of layout node +---@param self druid.layout @{Layout} +---@param min_size vector3 +---@return druid.layout @{Layout} +function druid__layout.set_min_size(self, min_size) end + +--- Set new origin position of layout node. +--- You should apply this on node movement +---@param self druid.layout @{Layout} +---@param new_origin_position vector3 +---@return druid.layout @{Layout} +function druid__layout.set_origin_position(self, new_origin_position) end + +--- Set new origin size of layout node. +--- You should apply this on node manual size change +---@param self druid.layout @{Layout} +---@param new_origin_size vector3 +---@return druid.layout @{Layout} +function druid__layout.set_origin_size(self, new_origin_size) end + + ---@class druid.pin_knob : druid.base_component ---@field druid druid_instance The component druid instance ---@field is_drag bool Is currently under user control @@ -1347,6 +1405,10 @@ local druid_instance = {} ---@param self druid_instance function druid_instance.final(self) end +--- Druid late update function call after init and before udpate step +---@param self druid_instance +function druid_instance.late_init(self) end + --- Log message, if is_debug mode is enabled ---@param self druid_instance @{DruidInstance} ---@param message string diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index f2cfd75..0c544f5 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -29,7 +29,7 @@ local Layout = component.create("layout") --- Component init function -- @tparam Layout self @{Layout} -- @tparam node node Gui node --- @tparam string node The layout mode (from const.LAYOUT_MODE) +-- @tparam string mode The layout mode (from const.LAYOUT_MODE) -- @tparam[opt] function on_size_changed_callback The callback on window resize function Layout.init(self, node, mode, on_size_changed_callback) self.node = self:get_node(node) @@ -122,7 +122,7 @@ end --- Set maximum size of layout node -- @tparam Layout self @{Layout} --- @tparam vector3 min_size +-- @tparam vector3 max_size -- @treturn Layout @{Layout} function Layout.set_max_size(self, max_size) self._max_size = max_size diff --git a/game.project b/game.project index 2ae077f..d5aaf3a 100644 --- a/game.project +++ b/game.project @@ -12,7 +12,7 @@ dynamic_orientation = 1 [project] title = druid -version = 0.9.0 +version = 0.10.0 publisher = Insality developer = Insality dependencies#0 = https://github.com/insalitygames/deftest/archive/master.zip