From 830359b9a7c0ed8d9dc9c145954fa899813d9c32 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 25 Sep 2023 18:13:37 +0300 Subject: [PATCH] Layout adjustable size WIP --- deployer_build_stats.csv | 1 + druid/const.lua | 34 + druid/editor_scripts/component.lua_template | 12 +- druid/extended/layout.lua | 226 +++++- druid/styles/default/style.lua | 5 + example/example.collection | 66 ++ example/example.gui_script | 1 + example/examples/general/layout/layout.gui | 33 + .../examples/general/layout/layout.gui_script | 1 + .../layout_resize/layout_resize.collection | 39 + .../layout/layout_resize/layout_resize.gui | 672 ++++++++++++++++++ .../layout_resize/layout_resize.gui_script | 151 ++++ 12 files changed, 1222 insertions(+), 19 deletions(-) create mode 100644 example/examples/layout/layout_resize/layout_resize.collection create mode 100644 example/examples/layout/layout_resize/layout_resize.gui create mode 100644 example/examples/layout/layout_resize/layout_resize.gui_script diff --git a/deployer_build_stats.csv b/deployer_build_stats.csv index 2a151af3..b70929bf 100644 --- a/deployer_build_stats.csv +++ b/deployer_build_stats.csv @@ -16,3 +16,4 @@ date,sha,version,build_size,build_time,platform,mode,is_cache_using,commits_coun 2023-08-05T16:02:55Z,628723386eb3875f7190d079a2e7c510d044a311,0.11.692,2456,40,js-web,release,true,692 2023-08-05T16:31:19Z,37fff52aa59feb20f761ef4d340d9f677743d54b,0.11.693,2456,43,js-web,release,true,693 2023-08-05T16:41:25Z,d7dd4a86b81d73d345ad7e136de9c2c488bc4d8b,0.11.694,2452,43,js-web,release,true,694 +2023-08-06T11:00:24Z,d1195a47a2e464532ff942a1008257685310741f,0.11.699,7360,19,x86_64-macos,headless,true,699 diff --git a/druid/const.lua b/druid/const.lua index 86f674e4..e00c3e8c 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -57,6 +57,31 @@ M.PIVOTS = { [gui.PIVOT_NW] = vmath.vector3(-0.5, 0.5, 0), } + +M.CORNER_PIVOTS = { + gui.PIVOT_NE, + gui.PIVOT_NW, + gui.PIVOT_SE, + gui.PIVOT_SW, +} + + +M.CORNER_PIVOTS_TO_ANCHOR_X = { + [gui.PIVOT_NE] = gui.ANCHOR_RIGHT, + [gui.PIVOT_SE] = gui.ANCHOR_RIGHT, + [gui.PIVOT_NW] = gui.ANCHOR_LEFT, + [gui.PIVOT_SW] = gui.ANCHOR_LEFT, +} + + +M.CORNER_PIVOTS_TO_ANCHOR_Y = { + [gui.PIVOT_NE] = gui.ANCHOR_TOP, + [gui.PIVOT_SE] = gui.ANCHOR_BOTTOM, + [gui.PIVOT_NW] = gui.ANCHOR_TOP, + [gui.PIVOT_SW] = gui.ANCHOR_BOTTOM, +} + + M.REVERSE_PIVOTS = { [gui.PIVOT_CENTER] = gui.PIVOT_CENTER, [gui.PIVOT_N] = gui.PIVOT_S, @@ -69,6 +94,14 @@ M.REVERSE_PIVOTS = { [gui.PIVOT_NW] = gui.PIVOT_SE, } + +M.ANCHORS = { + [gui.ANCHOR_LEFT] = vmath.vector3(-1, 1, 0), -- Equals to ANCHOR_TOP + [gui.ANCHOR_RIGHT] = vmath.vector3(1, -1, 0), -- Equals to ANCHOR_BOTTOM + [gui.ANCHOR_NONE] = vmath.vector3(0, 0, 0), +} + + M.LAYOUT_MODE = { STRETCH_X = "stretch_x", STRETCH_Y = "stretch_y", @@ -79,6 +112,7 @@ M.LAYOUT_MODE = { } M.VECTOR_ZERO = vmath.vector3(0) +M.TEMP_VECTOR = vmath.vector3(0) M.SYS_INFO = sys.get_sys_info() M.CURRENT_SYSTEM_NAME = M.SYS_INFO.system_name diff --git a/druid/editor_scripts/component.lua_template b/druid/editor_scripts/component.lua_template index d50db11a..80f0cef6 100644 --- a/druid/editor_scripts/component.lua_template +++ b/druid/editor_scripts/component.lua_template @@ -1,9 +1,9 @@ ---- For component interest functions ---- see https://github.com/Insality/druid/blob/develop/docs_md/02-creating_custom_components.md ---- Require this component in you gui file: ---- local {COMPONENT_NAME} = require("{COMPONENT_PATH}") ---- And create this component via: ---- self.{COMPONENT_TYPE} = self.druid:new({COMPONENT_NAME}, template, nodes) +--- Require this component in you GUI file: +--local {COMPONENT_NAME} = require("{COMPONENT_PATH}") +--- Create this component with next code: +--self.{COMPONENT_TYPE} = self.druid:new({COMPONENT_NAME}, template, nodes) +--- Custom components documentation: +--- https://github.com/Insality/druid/blob/develop/docs_md/02-creating_custom_components.md local component = require("druid.component") diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 7bcd8f08..0aeeb124 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -35,6 +35,7 @@ local Layout = component.create("layout") -- @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.druid = self:get_druid() self._min_size = nil self._max_size = nil @@ -44,6 +45,7 @@ function Layout.init(self, node, mode, on_size_changed_callback) self._fit_node = nil self._anchors = {} + self._draggable_corners = {} self.mode = mode or const.LAYOUT_MODE.FIT @@ -55,12 +57,28 @@ 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.pivot_offset = helper.get_pivot_offset(gui.get_pivot(self.node)) + self.center_offset = vmath.vector3(self.origin_size.x * self.pivot_offset.x, self.origin_size.y * self.pivot_offset.y, 0) 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() + self:update_anchors() +end + + +--- Component style params. +-- You can override this component styles params in Druid styles table +-- or create your own style +-- @table style +-- @tfield[opt=vector3(24, 24, 0)] vector3 DRAGGABLE_CORNER_SIZE Size of box node for debug draggable corners +-- @tfield[opt=vector4(1)] vector4 DRAGGABLE_CORNER_COLOR Color of debug draggable corners +function Layout.on_style_change(self, style) + self.style = {} + self.style.DRAGGABLE_CORNER_SIZE = style.DRAGGABLE_CORNER_SIZE or vmath.vector3(24, 24, 0) + self.style.DRAGGABLE_CORNER_COLOR = style.DRAGGABLE_CORNER_COLOR or vmath.vector4(1) end @@ -110,22 +128,11 @@ function Layout.on_window_resized(self) 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 - self._current_size = new_size - 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) - self.on_size_changed:trigger(self:get_context(), new_size) + self:set_size(new_size) end @@ -149,6 +156,34 @@ function Layout.set_max_size(self, max_size) end +--- Set new size of layout node +-- @tparam Layout self @{Layout} +-- @tparam vector3 size +-- @treturn Layout @{Layout} +function Layout.set_size(self, size) + local new_size = const.TEMP_VECTOR + new_size.x = size.x + new_size.y = size.y + new_size.z = 0 + + 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._current_size = new_size + self:update_anchors() + self.on_size_changed:trigger(self:get_context(), new_size) + + return self +end + + --- Set new origin position of layout node. You should apply this on node movement -- @tparam Layout self @{Layout} -- @tparam vector3 new_origin_position @@ -214,4 +249,169 @@ function Layout.fit_into_window(self) end +-- @tparam Layout self @{Layout} +-- @treturn Layout @{Layout} +function Layout.add_anchor(self, node) + node = self:get_node(node) + table.insert(self._anchors, { + node = node, + init_position = gui.get_position(node), + init_size = gui.get_size(node), + adjust_mode = gui.get_adjust_mode(node), + x_anchor = gui.get_xanchor(node), + y_anchor = gui.get_yanchor(node), + parent_size = gui.get_size(self.node), + }) + + gui.set_adjust_mode(node, gui.ADJUST_FIT) + return self +end + + +-- @tparam Layout self @{Layout} +-- @treturn Layout @{Layout} +function Layout.remove_anchor(self, node) + for index = 1, #self._anchors do + local anchor = self._anchors[index] + if anchor.node == node then + table.remove(self._anchors, index) + return + end + end + + return self +end + + +-- @tparam Layout self @{Layout} +-- @treturn Layout @{Layout} +function Layout.update_anchors(self) + if not self._inited then + return + end + + for index = 1, #self._anchors do + local child = self._anchors[index] + local node = child.node + + --- Position update (for FIT) + local pos = vmath.vector3(child.init_position) + local x_koef = const.ANCHORS[child.x_anchor].x + local y_koef = const.ANCHORS[child.y_anchor].y + + local right_offset = child.parent_size.x/2 - (pos.x * x_koef) + + if x_koef ~= 0 then + pos.x = ((self._current_size.x/2) - right_offset) * x_koef + end + + local top_offset = child.parent_size.y/2 - (pos.y * y_koef) + + if y_koef ~= 0 then + pos.y = ((self._current_size.y/2) - top_offset) * y_koef + end + + gui.set_position(node, pos) + + -- Size Update (for stretch) + if child.adjust_mode == gui.ADJUST_STRETCH then + local size = vmath.vector3(child.init_size) + local stretch_side_x = child.parent_size.x + if x_koef ~= 0 then + stretch_side_x = child.parent_size.x - (child.parent_size.x/2 - (child.init_position.x * x_koef)) + end + + -- Perc of stretch side: + local fill_perc = vmath.vector3( + child.init_size.x / stretch_side_x, + child.init_size.y / child.parent_size.y, + 0 + ) + + size.x = self._current_size.x * fill_perc.x + size.y = self._current_size.y * fill_perc.y + gui.set_size(node, size) + end + end +end + + +-- @tparam Layout self @{Layout} +-- @treturn Layout @{Layout} +function Layout.create_draggable_corners(self) + self:clear_draggable_corners() + local node_size = gui.get_size(self.node) + self.pivot_offset = helper.get_pivot_offset(gui.get_pivot(self.node)) + self.center_offset = -vmath.vector3(node_size.x * self.pivot_offset.x, node_size.y * self.pivot_offset.y, 0) + + for _, corner_pivot in pairs(const.CORNER_PIVOTS) do + local corner_offset = helper.get_pivot_offset(corner_pivot) + local anchor_position = vmath.vector3( + self.center_offset.x + node_size.x * corner_offset.x, + self.center_offset.y + node_size.y * corner_offset.y, + 0) + + local new_draggable_node = gui.new_box_node(anchor_position, self.style.DRAGGABLE_CORNER_SIZE) + gui.set_parent(new_draggable_node, self.node) + gui.set_xanchor(new_draggable_node, const.CORNER_PIVOTS_TO_ANCHOR_X[corner_pivot] or gui.ANCHOR_NONE) + gui.set_yanchor(new_draggable_node, const.CORNER_PIVOTS_TO_ANCHOR_Y[corner_pivot] or gui.ANCHOR_NONE) + + self:add_anchor(new_draggable_node) + table.insert(self._draggable_corners, new_draggable_node) + + ---@type druid.drag + local drag = self.druid:new_drag(new_draggable_node, function(_, x, y) + self:_on_corner_drag(x, y, corner_offset) + end) + + drag.style.DRAG_DEADZONE = 0 + end + + self:update_anchors() + + return self +end + + +-- @tparam Layout self @{Layout} +-- @treturn Layout @{Layout} +function Layout.clear_draggable_corners(self) + for index = 1, #self._draggable_corners do + local drag_component = self._draggable_corners[index] + self.druid:remove(drag_component) + gui.delete_node(drag_component.node) + self:remove_anchor(drag_component.node) + end + + self._draggable_corners = {} + + return self +end + + +function Layout._on_corner_drag(self, x, y, corner_offset) + if corner_offset.x < 0 then + x = -x + end + if corner_offset.y < 0 then + y = -y + end + + local position = gui.get_position(self.node) + local center_pos = position + + local pivot = gui.get_pivot(self.node) + local pivot_offset = helper.get_pivot_offset(pivot) + + center_pos.x = center_pos.x + (x * (pivot_offset.x + corner_offset.x)) + center_pos.y = center_pos.y + (y * (pivot_offset.y + corner_offset.y)) + gui.set_position(self.node, center_pos) + + local size = gui.get_size(self.node) + size.x = size.x + x + size.y = size.y + y + self:set_size(size) +end + + return Layout diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 3b074c1e..02e391f5 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -181,4 +181,9 @@ M["rich_text"] = { } +M["layout"] = { + DRAGGABLE_CORNER_SIZE = vmath.vector3(24, 24, 0), + DRAGGABLE_CORNER_COLOR = vmath.vector4(1, 1, 1, 1), +} + return M diff --git a/example/example.collection b/example/example.collection index 0d91d8ee..a3f4d660 100644 --- a/example/example.collection +++ b/example/example.collection @@ -2493,3 +2493,69 @@ embedded_instances { z: 1.0 } } +embedded_instances { + id: "layout_resize" + 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_resize\"\n" + " type: PROPERTY_TYPE_HASH\n" + " }\n" + " properties {\n" + " id: \"popup\"\n" + " value: \"true\"\n" + " type: PROPERTY_TYPE_BOOLEAN\n" + " }\n" + " property_decls {\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"collectionfactory\"\n" + " type: \"collectionfactory\"\n" + " data: \"prototype: \\\"/example/examples/layout/layout_resize/layout_resize.collection\\\"\\n" + "load_dynamically: true\\n" + "dynamic_prototype: 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 ccdc45fc..80aafb42 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -197,6 +197,7 @@ local function init_lobby(self) self.lobby_grid:add(get_title(self, "Layouts")) self.lobby_grid:add(get_button(self, "Layout fit", "layout_fit", "/custom/layout_fit/layout_fit.gui_script")) + self.lobby_grid:add(get_button(self, "Layout resize", "layout_resize", "/custom/layout_resize/layout_resize.gui_script")) self.lobby_grid:add(get_title(self, "Custom components")) self.lobby_grid:add(get_button(self, "Rich Input", "custom_rich_input", "/custom/rich_input/rich_input.gui_script")) diff --git a/example/examples/general/layout/layout.gui b/example/examples/general/layout/layout.gui index 385aaff0..bd523b4f 100644 --- a/example/examples/general/layout/layout.gui +++ b/example/examples/general/layout/layout.gui @@ -67,6 +67,9 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -123,6 +126,9 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -187,6 +193,9 @@ nodes { text_leading: 1.0 text_tracking: 0.0 custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -243,6 +252,9 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -307,6 +319,9 @@ nodes { text_leading: 1.0 text_tracking: 0.0 custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -363,6 +378,9 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -427,6 +445,9 @@ nodes { text_leading: 1.0 text_tracking: 0.0 custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -483,6 +504,9 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -547,6 +571,9 @@ nodes { text_leading: 1.0 text_tracking: 0.0 custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -603,6 +630,9 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -667,6 +697,9 @@ nodes { text_leading: 1.0 text_tracking: 0.0 custom_type: 0 + enabled: true + visible: true + material: "" } layers { name: "image" diff --git a/example/examples/general/layout/layout.gui_script b/example/examples/general/layout/layout.gui_script index a5adf93b..a428833c 100644 --- a/example/examples/general/layout/layout.gui_script +++ b/example/examples/general/layout/layout.gui_script @@ -1,4 +1,5 @@ local druid = require("druid.druid") +local helper = require("druid.helper") local const_druid = require("druid.const") local layout = require("druid.extended.layout") diff --git a/example/examples/layout/layout_resize/layout_resize.collection b/example/examples/layout/layout_resize/layout_resize.collection new file mode 100644 index 00000000..35fbdee6 --- /dev/null +++ b/example/examples/layout/layout_resize/layout_resize.collection @@ -0,0 +1,39 @@ +name: "layout_resize" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"layout_resize\"\n" + " component: \"/example/examples/layout/layout_resize/layout_resize.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" + " property_decls {\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/layout/layout_resize/layout_resize.gui b/example/examples/layout/layout_resize/layout_resize.gui new file mode 100644 index 00000000..552fdc40 --- /dev/null +++ b/example/examples/layout/layout_resize/layout_resize.gui @@ -0,0 +1,672 @@ +script: "/example/examples/layout/layout_resize/layout_resize.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 + enabled: true + visible: true + material: "" +} +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: 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: "test" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: -120.0 + y: 30.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: 24.0 + y: 24.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: "" + id: "box_nw" + xanchor: XANCHOR_LEFT + yanchor: YANCHOR_TOP + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: 0.0 + y: 30.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: 24.0 + y: 24.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: "" + id: "box_n" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_TOP + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: 120.0 + y: 30.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: 24.0 + y: 24.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: "" + id: "box_ne" + xanchor: XANCHOR_RIGHT + yanchor: YANCHOR_TOP + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: -120.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: 24.0 + y: 24.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: "" + id: "box_w" + xanchor: XANCHOR_LEFT + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +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: 24.0 + y: 24.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: "" + id: "box_c" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: 120.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: 24.0 + y: 24.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: "" + id: "box_e" + xanchor: XANCHOR_RIGHT + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: -120.0 + y: -30.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: 24.0 + y: 24.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: "" + id: "box_sw" + xanchor: XANCHOR_LEFT + yanchor: YANCHOR_BOTTOM + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: 0.0 + y: -30.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: 24.0 + y: 24.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: "" + id: "box_s" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_BOTTOM + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +nodes { + position { + x: 120.0 + y: -30.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: 24.0 + y: 24.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: "" + id: "box_se" + xanchor: XANCHOR_RIGHT + yanchor: YANCHOR_BOTTOM + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "test" + 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 + enabled: true + visible: true + material: "" +} +layers { + name: "image" +} +layers { + name: "text" +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT +max_nodes: 512 diff --git a/example/examples/layout/layout_resize/layout_resize.gui_script b/example/examples/layout/layout_resize/layout_resize.gui_script new file mode 100644 index 00000000..f11fa990 --- /dev/null +++ b/example/examples/layout/layout_resize/layout_resize.gui_script @@ -0,0 +1,151 @@ +local druid = require("druid.druid") +local const_druid = require("druid.const") +local helper = require("druid.helper") +local layout = require("druid.extended.layout") + + +local PIVOTS = { + vmath.vector3(-0.5, 0.5, 0), + vmath.vector3(0.5, 0.5, 0), + vmath.vector3(-0.5, -0.5, 0), + vmath.vector3(0.5, -0.5, 0), +} + + +local function add_child(self, box_id, parent_node) + local node = gui.get_node(box_id) + self._childrens = self._childrens or {} + + table.insert(self._childrens, { + node = node, + init_pos = gui.get_position(node), + init_size = gui.get_size(node), + adjust_mode = gui.get_adjust_mode(node), + x_anchor = gui.get_xanchor(node), + y_anchor = gui.get_yanchor(node), + parent = parent_node, + parent_size = gui.get_size(parent_node), + }) + + gui.set_adjust_mode(node, gui.ADJUST_FIT) +end + + +local ANCHORS = { + [gui.ANCHOR_LEFT] = vmath.vector3(-1, 1, 0), + [gui.ANCHOR_RIGHT] = vmath.vector3(1, -1, 0), + [gui.ANCHOR_NONE] = vmath.vector3(0, 0, 0), + [gui.ANCHOR_TOP] = vmath.vector3(-1, 1, 0), + [gui.ANCHOR_BOTTOM] = vmath.vector3(1, -1, 0), +} + +local function update_childrens(self) + for index = 1, #self._childrens do + local child = self._childrens[index] + local node = child.node + + --- Position update (for FIT) + local pos = vmath.vector3(child.init_pos) + local x_koef = ANCHORS[child.x_anchor].x + local y_koef = ANCHORS[child.y_anchor].y + + local current_parent_size = gui.get_size(child.parent) + local right_offset = child.parent_size.x/2 - (pos.x * x_koef) + + if x_koef ~= 0 then + pos.x = ((current_parent_size.x/2) - right_offset) * x_koef + end + + local top_offset = child.parent_size.y/2 - (pos.y * y_koef) + + if y_koef ~= 0 then + pos.y = ((current_parent_size.y/2) - top_offset) * y_koef + end + + gui.set_position(node, pos) + + + -- Size Update (for stretch) + if child.adjust_mode == gui.ADJUST_STRETCH then + local size = vmath.vector3(child.init_size) + local stretch_side_x = child.parent_size.x + if x_koef ~= 0 then + -- -100 -75 -50 -25 0 25 50 75 100 + stretch_side_x = child.parent_size.x - (child.parent_size.x/2 - (child.init_pos.x * x_koef)) + end + + -- Perc of stretch side: + local fill_perc = vmath.vector3( + child.init_size.x / stretch_side_x, + child.init_size.y / child.parent_size.y, + 0 + ) + + size.x = current_parent_size.x * fill_perc.x + size.y = current_parent_size.y * fill_perc.y + gui.set_size(node, size) + end + end +end + + + +function init(self) + druid.register("layout", layout) + self.druid = druid.new(self) + + self._childrens = {} + local node = gui.get_node("test") + local layout_instance = self.druid:new_layout(node) + layout_instance:create_draggable_corners() + layout_instance:add_anchor("box_nw") + layout_instance:add_anchor("box_n") + layout_instance:add_anchor("box_ne") + layout_instance:add_anchor("box_w") + layout_instance:add_anchor("box_c") + layout_instance:add_anchor("box_e") + layout_instance:add_anchor("box_sw") + layout_instance:add_anchor("box_s") + layout_instance:add_anchor("box_se") + + --add_child(self, "box", node) + --add_child(self, "box1", node) + --add_child(self, "box2", node) + + --self.druid:new_drag(node, function(_, x, y) + -- x = -x + -- local position = gui.get_position(node) + -- local center_pos = position + + -- local pivot = gui.get_pivot(node) + -- local pivot_offset = helper.get_pivot_offset(pivot) + + -- -- Right side + -- center_pos.x = center_pos.x - (x * (0.5 + pivot_offset.x)) + -- gui.set_position(node, center_pos) + + -- local size = gui.get_size(node) + -- size.x = size.x - x + -- gui.set_size(node, size) + --end) +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