From a92e4e6ae09116eae5ba940bd03a18d1c129b77b Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 12 Jul 2020 12:30:13 +0300 Subject: [PATCH 01/46] Add grid update position function --- druid/base/grid.lua | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/druid/base/grid.lua b/druid/base/grid.lua index c295a4a..5f16442 100644 --- a/druid/base/grid.lua +++ b/druid/base/grid.lua @@ -49,6 +49,8 @@ function M.init(self, parent, element, in_row) self.on_remove_item = Event() self.on_clear = Event() self.on_update_positions = Event() + + self._set_position_function = gui.set_position end @@ -87,10 +89,15 @@ local function get_pos(self, index) end -local function update_pos(self) +local function update_pos(self, is_instant) for i = 1, #self.nodes do local node = self.nodes[i] - gui.set_position(node, get_pos(self, i)) + + if is_instant then + gui.set_position(node, get_pos(self, i)) + else + self._set_position_function(node, get_pos(self, i)) + end end self.on_update_positions:trigger(self:get_context()) @@ -157,6 +164,15 @@ function M.get_all_pos(self) end +--- Chane set position function for grid nodes. It will call on +-- update poses on grid elements. Default: gui.set_position +-- @function grid:set_position_function +-- @tparam function callback Function on node set position +function M.set_position_function(self, callback) + self._set_position_function = callback or gui.set_position +end + + --- Clear grid nodes array. GUI nodes will be not deleted! -- If you want to delete GUI nodes, use grid.nodes array before grid:clear -- @function grid:clear From 32c3316a539e20d10d657c64c5cc82884f4af81f Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 12 Jul 2020 12:39:15 +0300 Subject: [PATCH 02/46] Add get_pos and get_index methods --- druid/base/grid.lua | 46 +++++++++++++++++++++++++++++++-------------- druid/const.lua | 6 ++++++ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/druid/base/grid.lua b/druid/base/grid.lua index 5f16442..1f21b85 100644 --- a/druid/base/grid.lua +++ b/druid/base/grid.lua @@ -19,6 +19,7 @@ -- @tfield vector4 border The size of item content -- @tfield vector3 border_offer The border offset for correct anchor calculations +local const = require("druid.const") local Event = require("druid.event") local helper = require("druid.helper") local component = require("druid.component") @@ -36,6 +37,7 @@ function M.init(self, parent, element, in_row) self.nodes = {} self.offset = vmath.vector3(0) + self.grid_mode = const.GRID_MODE.DYNAMIC local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) @@ -76,8 +78,27 @@ local function check_border(self, pos) end +local function update_pos(self, is_instant) + for i = 1, #self.nodes do + local node = self.nodes[i] + + if is_instant then + gui.set_position(node, self:get_pos(i)) + else + self._set_position_function(node, self:get_pos(i)) + end + end + + self.on_update_positions:trigger(self:get_context()) +end + + local temp_pos = vmath.vector3(0) -local function get_pos(self, index) +--- Return pos for grid node index +-- @function grid:get_pos +-- @tparam number index The grid element index +-- @treturn vector3 Node position +function M.get_pos(self, index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 @@ -89,22 +110,19 @@ local function get_pos(self, index) end -local function update_pos(self, is_instant) - for i = 1, #self.nodes do - local node = self.nodes[i] +--- Return index for grid pos +-- @function grid:get_index +-- @tparam vector3 pos The node position in the grid +-- @treturn number The node index +function M.get_index(self, pos) + local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) + local row = -(pos.y + self.border_offset.y) / (self.node_size.y + self.offset.y) - if is_instant then - gui.set_position(node, get_pos(self, i)) - else - self._set_position_function(node, get_pos(self, i)) - end - end - - self.on_update_positions:trigger(self:get_context()) + local index = col + (row * self.in_row) + 1 + return math.floor(index) end - --- Set grid items offset, the distance between items -- @function grid:set_offset -- @tparam vector3 offset Offset @@ -132,7 +150,7 @@ function M.add(self, item, index) table.insert(self.nodes, index, item) gui.set_parent(item, self.parent) - local pos = get_pos(self, index) + local pos = self:get_pos(index) check_border(self, pos) update_pos(self) diff --git a/druid/const.lua b/druid/const.lua index 83ed071..596ab0f 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -101,6 +101,12 @@ M.SWIPE = { } +M.GRID_MODE = { + STATIC = "static", + DYNAMIC = "dynamic", +} + + M.EMPTY_FUNCTION = function() end M.EMPTY_STRING = "" M.SPACE_STRING = " " From 02e238348b9e9ae3a0ca81d252bbe2673d288d51 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 20 Sep 2020 23:03:59 +0300 Subject: [PATCH 03/46] Copy grid from infinity scroll tests --- druid/base/grid.lua | 113 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 24 deletions(-) diff --git a/druid/base/grid.lua b/druid/base/grid.lua index c949f93..8fe45d4 100644 --- a/druid/base/grid.lua +++ b/druid/base/grid.lua @@ -43,7 +43,10 @@ function M.init(self, parent, element, in_row) self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) self.in_row = in_row or 1 - self.node_size = gui.get_size(self:get_node(element)) + local node = self:get_node(element) + self.node_size = gui.get_size(node) + self.node_pivot = const.PIVOTS[gui.get_pivot(node)] + self.border = vmath.vector4(0) self.border_offset = vmath.vector3(0) @@ -56,19 +59,25 @@ function M.init(self, parent, element, in_row) end -local function check_border(self, pos) - local border = self.border +local function _update_border(self, pos, border) local size = self.node_size + local pivot = self.node_pivot - local W = pos.x - size.x/2 + self.border_offset.x - local E = pos.x + size.x/2 + self.border_offset.x - local N = pos.y + size.y/2 + self.border_offset.y - local S = pos.y - size.y/2 + self.border_offset.y + local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x + local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x + local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y + local bottom = pos.y - size.y/2 - (size.y * pivot.y)+ self.border_offset.y - border.x = math.min(border.x, W) - border.y = math.max(border.y, N) - border.z = math.max(border.z, E) - border.w = math.min(border.w, S) + border.x = math.min(border.x, left) + border.y = math.max(border.y, top) + border.z = math.max(border.z, right) + border.w = math.min(border.w, bottom) +end + + +local function update_border_offset(self, pos) + local border = self.border + _update_border(self, pos, border) self.border_offset = vmath.vector3( (border.x + (border.z - border.x) * self.anchor.x), @@ -79,9 +88,7 @@ end local function update_pos(self, is_instant) - for i = 1, #self.nodes do - local node = self.nodes[i] - + for i, node in pairs(self.nodes) do if is_instant then gui.set_position(node, self:get_pos(i)) else @@ -118,8 +125,10 @@ function M.get_index(self, pos) local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) local row = -(pos.y + self.border_offset.y) / (self.node_size.y + self.offset.y) - local index = col + (row * self.in_row) + 1 - return math.floor(index) + row = math.floor(row) + + local index = col + (row * self.in_row) + return math.ceil(index) end @@ -152,42 +161,91 @@ end -- @tparam[opt] number index The item position. By default add as last item function M.add(self, item, index) index = index or (#self.nodes + 1) - table.insert(self.nodes, index, item) + + if self.grid_mode == const.GRID_MODE.DYNAMIC then + table.insert(self.nodes, index, item) + else + self.nodes[index] = item + end + gui.set_parent(item, self.parent) local pos = self:get_pos(index) - check_border(self, pos) + for i, _ in pairs(self.nodes) do + update_border_offset(self, self:get_pos(i)) + end + + -- Add new item instantly in new pos + gui.set_position(item, pos) update_pos(self) self.on_add_item:trigger(self:get_context(), item, index) end +function M:remove(index, delete_node) + assert(self.nodes[index], "No grid item at given index " .. index) + + local parent_node = self.nodes[index] + if delete_node then + gui.delete_node(parent_node) + end + + if self.grid_mode == const.GRID_MODE.DYNAMIC then + table.remove(self.nodes, index) + else + self.nodes[index] = nil + end + + -- Recalculate borders + self.border = vmath.vector4(0) + update_border_offset(self, self:get_pos(1)) + for i, _ in pairs(self.nodes) do + local pos = self:get_pos(i) + update_border_offset(self, pos) + end + + update_pos(self) +end + + --- Return grid content size -- @function grid:get_size -- @treturn vector3 The grid content size -function M.get_size(self) +function M.get_size(self, border) + border = border or self.border return vmath.vector3( - self.border.z - self.border.x, - self.border.y - self.border.w, + border.z - border.x, + border.y - border.w, 0) end +function M:get_size_for_elements_count(count) + local border = vmath.vector4(0) + for i = 1, count do + local pos = self:get_pos(i) + _update_border(self, pos, border) + end + + return M.get_size(self, border) +end + + --- Return array of all node positions -- @function grid:get_all_pos -- @treturn vector3[] All grid node positions function M.get_all_pos(self) local result = {} - for i = 1, #self.nodes do - table.insert(result, gui.get_position(self.nodes[i])) + for i, node in pairs(self.nodes) do + table.insert(result, gui.get_position(node)) end return result end ---- Chane set position function for grid nodes. It will call on +--- Change set position function for grid nodes. It will call on -- update poses on grid elements. Default: gui.set_position -- @function grid:set_position_function -- @tparam function callback Function on node set position @@ -209,4 +267,11 @@ function M.clear(self) end +function M:set_grid_mode(grid_mode) + assert(grid_mode == const.GRID_MODE.STATIC or grid_mode == const.GRID_MODE.DYNAMIC) + + self.grid_mode = grid_mode +end + + return M From d4101926696aa2940a0089ba9722966c34afcf71 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 20 Sep 2020 23:09:11 +0300 Subject: [PATCH 04/46] Add helper.deprecated function. Renamed grid to static_grid --- druid/base/{grid.lua => static_grid.lua} | 0 druid/helper.lua | 15 +++++++++++++++ druid/system/druid_instance.lua | 6 ++++-- example/gui/main/main.gui | 6 ------ 4 files changed, 19 insertions(+), 8 deletions(-) rename druid/base/{grid.lua => static_grid.lua} (100%) diff --git a/druid/base/grid.lua b/druid/base/static_grid.lua similarity index 100% rename from druid/base/grid.lua rename to druid/base/static_grid.lua diff --git a/druid/helper.lua b/druid/helper.lua index 1e1076f..3fd25c7 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -188,4 +188,19 @@ function M.get_border(node) ) end + +--- Show deprecated message. Once time per message +-- @function helper.deprecated +-- @tparam string message The deprecated message +local _deprecated_messages = {} +function M.deprecated(message) + if _deprecated_messages[message] then + return + end + + print("[Druid]: " .. message) + _deprecated_messages[message] = true +end + + return M diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 0b1191c..f243a6c 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -22,6 +22,7 @@ local const = require("druid.const") local druid_input = require("druid.helper.druid_input") local settings = require("druid.system.settings") local class = require("druid.system.middleclass") +local helper = require("druid.helper") local button = require("druid.base.button") local blocker = require("druid.base.blocker") @@ -31,7 +32,7 @@ local text = require("druid.base.text") local lang_text = require("druid.base.lang_text") local timer = require("druid.base.timer") local progress = require("druid.base.progress") -local grid = require("druid.base.grid") +local static_grid = require("druid.base.static_grid") local scroll = require("druid.base.scroll") local slider = require("druid.base.slider") local checkbox = require("druid.base.checkbox") @@ -407,7 +408,8 @@ end -- @tparam args ... grid init args -- @treturn Component grid component function Druid.new_grid(self, ...) - return Druid.create(self, grid, ...) + helper.deprecated("The druid:new_grid is deprecated. Please use druid:new_static_grid instead") + return Druid.create(self, static_grid, ...) end diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index d5a321f..ba77057 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10961,11 +10961,5 @@ layers { name: "text_top" } material: "/builtins/materials/gui.material" -layouts { - name: "Landscape" -} -layouts { - name: "Portrait" -} adjust_reference: ADJUST_REFERENCE_PARENT max_nodes: 512 From cded2b153cf248ededbd9dfd48ba9950ff57b659 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 20 Sep 2020 23:11:09 +0300 Subject: [PATCH 05/46] Remove const.grid_type --- druid/base/static_grid.lua | 30 +++++++----------------------- druid/const.lua | 6 ------ 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 8fe45d4..ee21443 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -37,7 +37,6 @@ function M.init(self, parent, element, in_row) self.nodes = {} self.offset = vmath.vector3(0) - self.grid_mode = const.GRID_MODE.DYNAMIC local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) @@ -100,7 +99,7 @@ local function update_pos(self, is_instant) end -local temp_pos = vmath.vector3(0) +local _temp_pos = vmath.vector3(0) --- Return pos for grid node index -- @function grid:get_pos -- @tparam number index The grid element index @@ -109,11 +108,11 @@ function M.get_pos(self, index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 - temp_pos.x = col * (self.node_size.x + self.offset.x) - self.border_offset.x - temp_pos.y = -row * (self.node_size.y + self.offset.y) - self.border_offset.y - temp_pos.z = 0 + _temp_pos.x = col * (self.node_size.x + self.offset.x) - self.border_offset.x + _temp_pos.y = -row * (self.node_size.y + self.offset.y) - self.border_offset.y + _temp_pos.z = 0 - return temp_pos + return _temp_pos end @@ -162,11 +161,7 @@ end function M.add(self, item, index) index = index or (#self.nodes + 1) - if self.grid_mode == const.GRID_MODE.DYNAMIC then - table.insert(self.nodes, index, item) - else - self.nodes[index] = item - end + self.nodes[index] = item gui.set_parent(item, self.parent) @@ -191,11 +186,7 @@ function M:remove(index, delete_node) gui.delete_node(parent_node) end - if self.grid_mode == const.GRID_MODE.DYNAMIC then - table.remove(self.nodes, index) - else - self.nodes[index] = nil - end + self.nodes[index] = nil -- Recalculate borders self.border = vmath.vector4(0) @@ -267,11 +258,4 @@ function M.clear(self) end -function M:set_grid_mode(grid_mode) - assert(grid_mode == const.GRID_MODE.STATIC or grid_mode == const.GRID_MODE.DYNAMIC) - - self.grid_mode = grid_mode -end - - return M diff --git a/druid/const.lua b/druid/const.lua index 858d1c7..cad9f8a 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -102,12 +102,6 @@ M.SWIPE = { } -M.GRID_MODE = { - STATIC = "static", - DYNAMIC = "dynamic", -} - - M.EMPTY_FUNCTION = function() end M.EMPTY_STRING = "" M.SPACE_STRING = " " From 9230f9545c372f2a6b7361448fc923498b237b24 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 20 Sep 2020 23:49:42 +0300 Subject: [PATCH 06/46] Change annotations grid -> static_grid --- druid/base/static_grid.lua | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index ee21443..8c8af2f 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -1,6 +1,6 @@ --- Component to handle placing components by row and columns. -- Grid can anchor your elements, get content size and other --- @module druid.grid +-- @module druid.static_grid --- Component events -- @table Events @@ -28,7 +28,7 @@ local M = component.create("grid", { const.ON_LAYOUT_CHANGE }) --- Component init function --- @function grid:init +-- @function static_grid:init -- @tparam node parent The gui node parent, where items will be placed -- @tparam node element Element prefab. Need to get it size -- @tparam[opt=1] number in_row How many nodes in row can be placed @@ -101,7 +101,7 @@ end local _temp_pos = vmath.vector3(0) --- Return pos for grid node index --- @function grid:get_pos +-- @function static_grid:get_pos -- @tparam number index The grid element index -- @treturn vector3 Node position function M.get_pos(self, index) @@ -117,7 +117,7 @@ end --- Return index for grid pos --- @function grid:get_index +-- @function static_grid:get_index -- @tparam vector3 pos The node position in the grid -- @treturn number The node index function M.get_index(self, pos) @@ -137,7 +137,7 @@ end --- Set grid items offset, the distance between items --- @function grid:set_offset +-- @function static_grid:set_offset -- @tparam vector3 offset Offset function M.set_offset(self, offset) self.offset = offset @@ -146,7 +146,7 @@ end --- Set grid anchor --- @function grid:set_anchor +-- @function static_grid:set_anchor -- @tparam vector3 acnhor Anchor function M.set_anchor(self, anchor) self.anchor = anchor @@ -155,7 +155,7 @@ end --- Add new item to the grid --- @function grid:add +-- @function static_grid:add -- @tparam node item Gui node -- @tparam[opt] number index The item position. By default add as last item function M.add(self, item, index) @@ -178,14 +178,9 @@ function M.add(self, item, index) end -function M:remove(index, delete_node) +function M:remove(index) assert(self.nodes[index], "No grid item at given index " .. index) - local parent_node = self.nodes[index] - if delete_node then - gui.delete_node(parent_node) - end - self.nodes[index] = nil -- Recalculate borders @@ -201,7 +196,7 @@ end --- Return grid content size --- @function grid:get_size +-- @function static_grid:get_size -- @treturn vector3 The grid content size function M.get_size(self, border) border = border or self.border @@ -224,7 +219,7 @@ end --- Return array of all node positions --- @function grid:get_all_pos +-- @function static_grid:get_all_pos -- @treturn vector3[] All grid node positions function M.get_all_pos(self) local result = {} @@ -238,7 +233,7 @@ end --- Change set position function for grid nodes. It will call on -- update poses on grid elements. Default: gui.set_position --- @function grid:set_position_function +-- @function static_grid:set_position_function -- @tparam function callback Function on node set position function M.set_position_function(self, callback) self._set_position_function = callback or gui.set_position @@ -246,8 +241,8 @@ end --- Clear grid nodes array. GUI nodes will be not deleted! --- If you want to delete GUI nodes, use grid.nodes array before grid:clear --- @function grid:clear +-- If you want to delete GUI nodes, use static_grid.nodes array before grid:clear +-- @function static_grid:clear function M.clear(self) self.border.x = 0 self.border.y = 0 From 0dc9f32b7abec832ba63d8a8cb8bc5d9a63b84a4 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 20 Sep 2020 23:51:22 +0300 Subject: [PATCH 07/46] Add druid:new instead of druid:create --- druid/system/druid_instance.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index f243a6c..0571e92 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -151,7 +151,24 @@ end -- @function druid:create -- @tparam Component component Component module -- @tparam args ... Other component params to pass it to component:init function -function Druid.create(self, component, ...) +-- @deprecated +function Druid:create(component, ...) + helper.deprecated("The druid:create is deprecated. Please use druid:new instead") + local instance = create(self, component) + + if instance.init then + instance:init(...) + end + + return instance +end + + +--- Create new druid component +-- @function druid:new +-- @tparam Component component Component module +-- @tparam args ... Other component params to pass it to component:init function +function Druid.new(self, component, ...) local instance = create(self, component) if instance.init then @@ -407,6 +424,7 @@ end -- @function druid:new_grid -- @tparam args ... grid init args -- @treturn Component grid component +-- @deprecated function Druid.new_grid(self, ...) helper.deprecated("The druid:new_grid is deprecated. Please use druid:new_static_grid instead") return Druid.create(self, static_grid, ...) From cf87c89cff261add71db47501b3bd860388e1006 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 00:00:00 +0300 Subject: [PATCH 08/46] Update grid usage at grid example page --- docs_md/changelog.md | 1 + druid/base/static_grid.lua | 2 +- druid/system/druid_instance.lua | 9 +++++++++ example/page/grid_page.lua | 23 +++++++++++++++++------ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 7f397dc..809fa45 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -102,5 +102,6 @@ Druid 0.5.0: - **Fix #76:** Add params for lang text localization component - **Fix #79:** Fix druid:remove inside on_input callback - **Fix #80:** Fix hover set_enable typo function call +- _druid:create_ deprecated. Use _druid:new_ instead (for custom components) - Add `component.tempalte.lua` as template for Druid custom component diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 8c8af2f..0e39fe8 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -46,7 +46,7 @@ function M.init(self, parent, element, in_row) self.node_size = gui.get_size(node) self.node_pivot = const.PIVOTS[gui.get_pivot(node)] - self.border = vmath.vector4(0) + self.border = vmath.vector4(0) -- Current grid content size self.border_offset = vmath.vector3(0) self.on_add_item = Event() diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 0571e92..9106251 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -431,6 +431,15 @@ function Druid.new_grid(self, ...) end +--- Create staic grid basic component +-- @function druid:new_staic_grid +-- @tparam args ... grid init args +-- @treturn Component grid component +function Druid.new_static_grid(self, ...) + return Druid.create(self, static_grid, ...) +end + + --- Create scroll basic component -- @function druid:new_scroll -- @tparam args ... scroll init args diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index db6199b..b5330cf 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -5,11 +5,19 @@ local function add_node(self) local prefab = gui.get_node("grid_nodes_prefab") local cloned = gui.clone_tree(prefab) gui.set_enabled(cloned["grid_nodes_prefab"], true) - local index = #self.grid_nodes + 1 + local index = #self.grid_nodes.nodes + 1 gui.set_text(cloned["grid_nodes_text"], index) - local button = self.druid:new_button(cloned["grid_nodes_prefab"], function() - print(index) + local button = self.druid:new_button(cloned["grid_nodes_prefab"], function(_, params, button) + gui.delete_node(button.node) + self.druid:remove(button) + self.grid_nodes:remove(index) + for i = 1, #self.grid_node_buttons do + if self.grid_node_buttons[i] == button then + table.remove(self.grid_node_buttons, i) + break + end + end end) table.insert(self.grid_node_buttons, button) @@ -19,8 +27,8 @@ end local function clear_nodes(self) local nodes = self.grid_nodes.nodes - for i = 1, #nodes do - gui.delete_node(nodes[i]) + for i, node in pairs(nodes) do + gui.delete_node(node) end for i = 1, #self.grid_node_buttons do @@ -38,7 +46,10 @@ end function M.setup_page(self) - self.grid_nodes = self.druid:new_grid("grid_nodes", "grid_nodes_prefab", 5) + self.grid_nodes = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5) + self.grid_nodes:set_position_function(function(node, pos) + gui.animate(node, "position", pos, gui.EASING_OUTSINE, 0.2) + end) self.grid_node_buttons = {} gui.set_enabled(gui.get_node("grid_nodes_prefab"), false) From ace1fc6cb129359601be1f85b3bfba739dbf8bb6 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 00:37:44 +0300 Subject: [PATCH 09/46] Add node shift at add/remove for static grid --- druid/base/static_grid.lua | 64 ++++++++++++++++++++++++++++++--- druid/system/druid_instance.lua | 19 +--------- example/gui/main/main.gui | 6 ++-- example/page/grid_page.lua | 32 ++++++++--------- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 0e39fe8..3056e9d 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -6,6 +6,7 @@ -- @table Events -- @tfield druid_event on_add_item On item add callback -- @tfield druid_event on_remove_item On item remove callback +-- @tfield druid_event on_change_items On item add or remove callback -- @tfield druid_event on_clear On grid clear callback -- @tfield druid_event on_update_positions On update item positions callback @@ -41,6 +42,9 @@ function M.init(self, parent, element, in_row) local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) + self.first_index = nil + self.last_index = nil + self.in_row = in_row or 1 local node = self:get_node(element) self.node_size = gui.get_size(node) @@ -51,6 +55,7 @@ function M.init(self, parent, element, in_row) self.on_add_item = Event() self.on_remove_item = Event() + self.on_change_items = Event() self.on_clear = Event() self.on_update_positions = Event() @@ -58,6 +63,19 @@ function M.init(self, parent, element, in_row) end +local function _update_indexes(self) + self.first_index = nil + self.last_index = nil + for index in pairs(self.nodes) do + self.first_index = self.first_index or index + self.last_index = self.last_index or index + + self.first_index = math.min(self.first_index, index) + self.last_index = math.max(self.last_index, index) + end +end + + local function _update_border(self, pos, border) local size = self.node_size local pivot = self.node_pivot @@ -131,6 +149,21 @@ function M.get_index(self, pos) end +--- Return grid index by node +-- @function static_grid:get_index_by_node +-- @tparam node node The gui node in the grid +-- @treturn number The node index +function M.get_index_by_node(self, node) + for index, grid_node in pairs(self.nodes) do + if node == grid_node then + return index + end + end + + return nil +end + + function M.on_layout_change(self) update_pos(self, true) end @@ -159,30 +192,46 @@ end -- @tparam node item Gui node -- @tparam[opt] number index The item position. By default add as last item function M.add(self, item, index) - index = index or (#self.nodes + 1) + index = index or ((self.last_index or 0) + 1) + + if self.nodes[index] then + -- Move nodes to right + for i = self.last_index, index, -1 do + self.nodes[i + 1] = self.nodes[i] + end + end self.nodes[index] = item gui.set_parent(item, self.parent) local pos = self:get_pos(index) + -- Add new item instantly in new pos + gui.set_position(item, pos) + for i, _ in pairs(self.nodes) do update_border_offset(self, self:get_pos(i)) end - - -- Add new item instantly in new pos - gui.set_position(item, pos) update_pos(self) + _update_indexes(self) + self.on_add_item:trigger(self:get_context(), item, index) + self.on_change_items:trigger(self:get_context(), index) end -function M:remove(index) +function M:remove(index, is_shift_nodes) assert(self.nodes[index], "No grid item at given index " .. index) self.nodes[index] = nil + if is_shift_nodes then + for i = index, self.last_index do + self.nodes[i] = self.nodes[i + 1] + end + end + -- Recalculate borders self.border = vmath.vector4(0) update_border_offset(self, self:get_pos(1)) @@ -192,6 +241,10 @@ function M:remove(index) end update_pos(self) + _update_indexes(self) + + self.on_add_item:trigger(self:get_context(), index) + self.on_change_items:trigger(self:get_context(), index) end @@ -250,6 +303,7 @@ function M.clear(self) self.border.z = 0 self.nodes = {} + _update_indexes(self) end diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 9106251..e9b163b 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -151,24 +151,7 @@ end -- @function druid:create -- @tparam Component component Component module -- @tparam args ... Other component params to pass it to component:init function --- @deprecated -function Druid:create(component, ...) - helper.deprecated("The druid:create is deprecated. Please use druid:new instead") - local instance = create(self, component) - - if instance.init then - instance:init(...) - end - - return instance -end - - ---- Create new druid component --- @function druid:new --- @tparam Component component Component module --- @tparam args ... Other component params to pass it to component:init function -function Druid.new(self, component, ...) +function Druid.create(self, component, ...) local instance = create(self, component) if instance.init then diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index ba77057..c019288 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10392,8 +10392,8 @@ nodes { } nodes { position { - x: 0.0 - y: 0.0 + x: 1.0 + y: 2.0 z: 0.0 w: 1.0 } @@ -10423,7 +10423,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "1" + text: "X" font: "game" id: "grid_nodes_text" xanchor: XANCHOR_NONE diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index b5330cf..7459879 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -1,23 +1,28 @@ local M = {} +local function remove_node(self, button) + gui.delete_node(button.node) + + self.druid:remove(button) + local index = self.grid_nodes:get_index_by_node(button.node) + self.grid_nodes:remove(index, true) + for i = 1, #self.grid_node_buttons do + if self.grid_node_buttons[i] == button then + table.remove(self.grid_node_buttons, i) + break + end + end +end + + local function add_node(self) local prefab = gui.get_node("grid_nodes_prefab") local cloned = gui.clone_tree(prefab) gui.set_enabled(cloned["grid_nodes_prefab"], true) - local index = #self.grid_nodes.nodes + 1 - gui.set_text(cloned["grid_nodes_text"], index) local button = self.druid:new_button(cloned["grid_nodes_prefab"], function(_, params, button) - gui.delete_node(button.node) - self.druid:remove(button) - self.grid_nodes:remove(index) - for i = 1, #self.grid_node_buttons do - if self.grid_node_buttons[i] == button then - table.remove(self.grid_node_buttons, i) - break - end - end + remove_node(self, button) end) table.insert(self.grid_node_buttons, button) @@ -40,11 +45,6 @@ local function clear_nodes(self) end -local function remove_node(self) - -- Remove is not implemented yet -end - - function M.setup_page(self) self.grid_nodes = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5) self.grid_nodes:set_position_function(function(node, pos) From 07c57d5cc64a28284878cb99ce4cf6f12a91c788 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 00:47:08 +0300 Subject: [PATCH 10/46] Add border offset fixes --- druid/base/static_grid.lua | 5 +++-- example/page/grid_page.lua | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 3056e9d..b7547d7 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -236,8 +236,7 @@ function M:remove(index, is_shift_nodes) self.border = vmath.vector4(0) update_border_offset(self, self:get_pos(1)) for i, _ in pairs(self.nodes) do - local pos = self:get_pos(i) - update_border_offset(self, pos) + update_border_offset(self, self:get_pos(i)) end update_pos(self) @@ -302,6 +301,8 @@ function M.clear(self) self.border.w = 0 self.border.z = 0 + update_border_offset(self, self:get_pos(1)) + self.nodes = {} _update_indexes(self) end diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 7459879..216b7ed 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -16,7 +16,7 @@ local function remove_node(self, button) end -local function add_node(self) +local function add_node(self, index) local prefab = gui.get_node("grid_nodes_prefab") local cloned = gui.clone_tree(prefab) gui.set_enabled(cloned["grid_nodes_prefab"], true) @@ -26,7 +26,7 @@ local function add_node(self) end) table.insert(self.grid_node_buttons, button) - self.grid_nodes:add(cloned["grid_nodes_prefab"]) + self.grid_nodes:add(cloned["grid_nodes_prefab"], index) end @@ -54,7 +54,7 @@ function M.setup_page(self) gui.set_enabled(gui.get_node("grid_nodes_prefab"), false) for i = 1, 15 do - add_node(self) + add_node(self, i) end self.druid:new_button("button_add/button", add_node) From fbcb620a8afaeb3697f0ffdf102ce6ae69afe267 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 01:01:00 +0300 Subject: [PATCH 11/46] Fix get_index by pos grid function --- druid/base/static_grid.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index b7547d7..a5d46c2 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -14,6 +14,8 @@ -- @table Fields -- @tfield node parent Parent gui node -- @tfield node[] nodes List of all grid nodes +-- @tfield number first_index The first index of node in grid +-- @tfield number last_index The last index of node in grid -- @tfield vector3 offset Item distance between each other items -- @tfield vector3 anchor Item anchor -- @tfield vector3 node_size Item size @@ -42,16 +44,14 @@ function M.init(self, parent, element, in_row) local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) - self.first_index = nil - self.last_index = nil - self.in_row = in_row or 1 + local node = self:get_node(element) self.node_size = gui.get_size(node) self.node_pivot = const.PIVOTS[gui.get_pivot(node)] self.border = vmath.vector4(0) -- Current grid content size - self.border_offset = vmath.vector3(0) + self.border_offset = vmath.vector3(0) -- Content offset for match the grid anchoring self.on_add_item = Event() self.on_remove_item = Event() @@ -83,7 +83,7 @@ local function _update_border(self, pos, border) local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y - local bottom = pos.y - size.y/2 - (size.y * pivot.y)+ self.border_offset.y + local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y border.x = math.min(border.x, left) border.y = math.max(border.y, top) @@ -139,10 +139,11 @@ end -- @tparam vector3 pos The node position in the grid -- @treturn number The node index function M.get_index(self, pos) - local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) + local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) + 1 local row = -(pos.y + self.border_offset.y) / (self.node_size.y + self.offset.y) - row = math.floor(row) + col = helper.round(col) + row = helper.round(row) local index = col + (row * self.in_row) return math.ceil(index) From 94099e0a3e30e19123a96556fdc9325c418bce79 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 01:05:37 +0300 Subject: [PATCH 12/46] Add annotations to static grid --- druid/base/static_grid.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index a5d46c2..64ab912 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -179,9 +179,9 @@ function M.set_offset(self, offset) end ---- Set grid anchor +--- Set grid anchor. Default anchor is equal to anchor of grid parent node -- @function static_grid:set_anchor --- @tparam vector3 acnhor Anchor +-- @tparam vector3 anchor Anchor function M.set_anchor(self, anchor) self.anchor = anchor update_pos(self) @@ -222,6 +222,10 @@ function M.add(self, item, index) end +--- Remove the item from the grid. Node that gui node will be not deleted +-- @function static_grid:remove +-- @tparam number index The grid node index to remove +-- @tparam bool is_shift_nodes If true, will shift nodes left after index function M:remove(index, is_shift_nodes) assert(self.nodes[index], "No grid item at given index " .. index) @@ -260,6 +264,10 @@ function M.get_size(self, border) end +--- Return grid size for amount of nodes in this grid +-- @function static_grid:get_size_for_elements_count +-- @tparam number count The grid content node amount +-- @treturn vector3 The grid content size function M:get_size_for_elements_count(count) local border = vmath.vector4(0) for i = 1, count do From 442ea090d3f902d1d9387926c5a0387d2a64b73f Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 01:12:31 +0300 Subject: [PATCH 13/46] Add grid:get_nodes function --- druid/base/static_grid.lua | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 64ab912..e9ffbaa 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -27,7 +27,7 @@ local Event = require("druid.event") local helper = require("druid.helper") local component = require("druid.component") -local M = component.create("grid", { const.ON_LAYOUT_CHANGE }) +local M = component.create("static_grid", { const.ON_LAYOUT_CHANGE }) --- Component init function @@ -222,7 +222,7 @@ function M.add(self, item, index) end ---- Remove the item from the grid. Node that gui node will be not deleted +--- Remove the item from the grid. Note that gui node will be not deleted -- @function static_grid:remove -- @tparam number index The grid node index to remove -- @tparam bool is_shift_nodes If true, will shift nodes left after index @@ -317,4 +317,13 @@ function M.clear(self) end + +--- Return the grid nodes table +-- @function static_grid:get_nodes +-- @treturn table The grid nodes +function M.get_nodes(self) + return self.nodes +end + + return M From 15a94173d256c44b2698e5339c3add958db41087 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 01:25:26 +0300 Subject: [PATCH 14/46] Refactor StaticGrid component. Change component:get_nodes -> component:get_component_nodes --- druid/base/static_grid.lua | 176 ++++++++++++++++++------------------- druid/component.lua | 6 +- example/page/main_page.lua | 2 +- 3 files changed, 92 insertions(+), 92 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index e9ffbaa..c64fb66 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -27,7 +27,7 @@ local Event = require("druid.event") local helper = require("druid.helper") local component = require("druid.component") -local M = component.create("static_grid", { const.ON_LAYOUT_CHANGE }) +local StaticGrid = component.create("static_grid", { const.ON_LAYOUT_CHANGE }) --- Component init function @@ -35,7 +35,7 @@ local M = component.create("static_grid", { const.ON_LAYOUT_CHANGE }) -- @tparam node parent The gui node parent, where items will be placed -- @tparam node element Element prefab. Need to get it size -- @tparam[opt=1] number in_row How many nodes in row can be placed -function M.init(self, parent, element, in_row) +function StaticGrid:init(parent, element, in_row) self.parent = self:get_node(parent) self.nodes = {} @@ -46,9 +46,9 @@ function M.init(self, parent, element, in_row) self.in_row = in_row or 1 - local node = self:get_node(element) - self.node_size = gui.get_size(node) - self.node_pivot = const.PIVOTS[gui.get_pivot(node)] + self._prefab = self:get_node(element) + self.node_size = gui.get_size(self._prefab) + self.node_pivot = const.PIVOTS[gui.get_pivot(self._prefab)] self.border = vmath.vector4(0) -- Current grid content size self.border_offset = vmath.vector3(0) -- Content offset for match the grid anchoring @@ -63,66 +63,12 @@ function M.init(self, parent, element, in_row) end -local function _update_indexes(self) - self.first_index = nil - self.last_index = nil - for index in pairs(self.nodes) do - self.first_index = self.first_index or index - self.last_index = self.last_index or index - - self.first_index = math.min(self.first_index, index) - self.last_index = math.max(self.last_index, index) - end -end - - -local function _update_border(self, pos, border) - local size = self.node_size - local pivot = self.node_pivot - - local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x - local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x - local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y - local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y - - border.x = math.min(border.x, left) - border.y = math.max(border.y, top) - border.z = math.max(border.z, right) - border.w = math.min(border.w, bottom) -end - - -local function update_border_offset(self, pos) - local border = self.border - _update_border(self, pos, border) - - self.border_offset = vmath.vector3( - (border.x + (border.z - border.x) * self.anchor.x), - (border.y + (border.w - border.y) * self.anchor.y), - 0 - ) -end - - -local function update_pos(self, is_instant) - for i, node in pairs(self.nodes) do - if is_instant then - gui.set_position(node, self:get_pos(i)) - else - self._set_position_function(node, self:get_pos(i)) - end - end - - self.on_update_positions:trigger(self:get_context()) -end - - local _temp_pos = vmath.vector3(0) --- Return pos for grid node index -- @function static_grid:get_pos -- @tparam number index The grid element index -- @treturn vector3 Node position -function M.get_pos(self, index) +function StaticGrid:get_pos(index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 @@ -138,7 +84,7 @@ end -- @function static_grid:get_index -- @tparam vector3 pos The node position in the grid -- @treturn number The node index -function M.get_index(self, pos) +function StaticGrid:get_index(pos) local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) + 1 local row = -(pos.y + self.border_offset.y) / (self.node_size.y + self.offset.y) @@ -154,7 +100,7 @@ end -- @function static_grid:get_index_by_node -- @tparam node node The gui node in the grid -- @treturn number The node index -function M.get_index_by_node(self, node) +function StaticGrid:get_index_by_node(node) for index, grid_node in pairs(self.nodes) do if node == grid_node then return index @@ -165,26 +111,26 @@ function M.get_index_by_node(self, node) end -function M.on_layout_change(self) - update_pos(self, true) +function StaticGrid:on_layout_change() + self:_update_pos(true) end --- Set grid items offset, the distance between items -- @function static_grid:set_offset -- @tparam vector3 offset Offset -function M.set_offset(self, offset) +function StaticGrid:set_offset(offset) self.offset = offset - update_pos(self) + self:_update_pos() end --- Set grid anchor. Default anchor is equal to anchor of grid parent node -- @function static_grid:set_anchor -- @tparam vector3 anchor Anchor -function M.set_anchor(self, anchor) +function StaticGrid:set_anchor(anchor) self.anchor = anchor - update_pos(self) + self:_update_pos() end @@ -192,7 +138,7 @@ end -- @function static_grid:add -- @tparam node item Gui node -- @tparam[opt] number index The item position. By default add as last item -function M.add(self, item, index) +function StaticGrid:add(item, index) index = index or ((self.last_index or 0) + 1) if self.nodes[index] then @@ -211,11 +157,11 @@ function M.add(self, item, index) gui.set_position(item, pos) for i, _ in pairs(self.nodes) do - update_border_offset(self, self:get_pos(i)) + self:_update_border_offset(self:get_pos(i)) end - update_pos(self) - _update_indexes(self) + self:_update_pos() + self:_update_indexes() self.on_add_item:trigger(self:get_context(), item, index) self.on_change_items:trigger(self:get_context(), index) @@ -226,7 +172,7 @@ end -- @function static_grid:remove -- @tparam number index The grid node index to remove -- @tparam bool is_shift_nodes If true, will shift nodes left after index -function M:remove(index, is_shift_nodes) +function StaticGrid:remove(index, is_shift_nodes) assert(self.nodes[index], "No grid item at given index " .. index) self.nodes[index] = nil @@ -239,13 +185,13 @@ function M:remove(index, is_shift_nodes) -- Recalculate borders self.border = vmath.vector4(0) - update_border_offset(self, self:get_pos(1)) + self:_update_border_offset(self:get_pos(1)) for i, _ in pairs(self.nodes) do - update_border_offset(self, self:get_pos(i)) + self:_update_border_offset(self:get_pos(i)) end - update_pos(self) - _update_indexes(self) + self:_update_pos() + self:_update_indexes() self.on_add_item:trigger(self:get_context(), index) self.on_change_items:trigger(self:get_context(), index) @@ -255,7 +201,7 @@ end --- Return grid content size -- @function static_grid:get_size -- @treturn vector3 The grid content size -function M.get_size(self, border) +function StaticGrid:get_size(border) border = border or self.border return vmath.vector3( border.z - border.x, @@ -268,21 +214,21 @@ end -- @function static_grid:get_size_for_elements_count -- @tparam number count The grid content node amount -- @treturn vector3 The grid content size -function M:get_size_for_elements_count(count) +function StaticGrid:get_size_for_elements_count(count) local border = vmath.vector4(0) for i = 1, count do local pos = self:get_pos(i) - _update_border(self, pos, border) + self:_update_border(pos, border) end - return M.get_size(self, border) + return self:get_size(border) end --- Return array of all node positions -- @function static_grid:get_all_pos -- @treturn vector3[] All grid node positions -function M.get_all_pos(self) +function StaticGrid:get_all_pos() local result = {} for i, node in pairs(self.nodes) do table.insert(result, gui.get_position(node)) @@ -296,7 +242,7 @@ end -- update poses on grid elements. Default: gui.set_position -- @function static_grid:set_position_function -- @tparam function callback Function on node set position -function M.set_position_function(self, callback) +function StaticGrid:set_position_function(callback) self._set_position_function = callback or gui.set_position end @@ -304,16 +250,16 @@ end --- Clear grid nodes array. GUI nodes will be not deleted! -- If you want to delete GUI nodes, use static_grid.nodes array before grid:clear -- @function static_grid:clear -function M.clear(self) +function StaticGrid:clear() self.border.x = 0 self.border.y = 0 self.border.w = 0 self.border.z = 0 - update_border_offset(self, self:get_pos(1)) + self:_update_border_offset(self:get_pos(1)) self.nodes = {} - _update_indexes(self) + self:_update_indexes() end @@ -321,9 +267,63 @@ end --- Return the grid nodes table -- @function static_grid:get_nodes -- @treturn table The grid nodes -function M.get_nodes(self) +function StaticGrid:get_nodes() return self.nodes end -return M +function StaticGrid:_update_indexes() + self.first_index = nil + self.last_index = nil + for index in pairs(self.nodes) do + self.first_index = self.first_index or index + self.last_index = self.last_index or index + + self.first_index = math.min(self.first_index, index) + self.last_index = math.max(self.last_index, index) + end +end + + +function StaticGrid:_update_border(pos, border) + local size = self.node_size + local pivot = self.node_pivot + + local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x + local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x + local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y + local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y + + border.x = math.min(border.x, left) + border.y = math.max(border.y, top) + border.z = math.max(border.z, right) + border.w = math.min(border.w, bottom) +end + + +function StaticGrid:_update_border_offset(pos) + local border = self.border + self:_update_border(pos, border) + + self.border_offset = vmath.vector3( + (border.x + (border.z - border.x) * self.anchor.x), + (border.y + (border.w - border.y) * self.anchor.y), + 0 + ) +end + + +function StaticGrid:_update_pos(is_instant) + for i, node in pairs(self.nodes) do + if is_instant then + gui.set_position(node, self:get_pos(i)) + else + self._set_position_function(node, self:get_pos(i)) + end + end + + self.on_update_positions:trigger(self:get_context()) +end + + +return StaticGrid diff --git a/druid/component.lua b/druid/component.lua index 3d8fb60..ba277dd 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -41,9 +41,9 @@ end --- Get current component nodes --- @function component:get_nodes +-- @function component:get_component_nodes -- @treturn table Component nodes table -function Component.get_nodes(self) +function Component.get_component_nodes(self) return self._meta.nodes end @@ -103,7 +103,7 @@ end -- @treturn node Gui node function Component.get_node(self, node_or_name) local template_name = self:get_template() or const.EMPTY_STRING - local nodes = self:get_nodes() + local nodes = self:get_component_nodes() if template_name ~= const.EMPTY_STRING then template_name = template_name .. "/" diff --git a/example/page/main_page.lua b/example/page/main_page.lua index 5563c0d..0877c0e 100644 --- a/example/page/main_page.lua +++ b/example/page/main_page.lua @@ -51,7 +51,7 @@ end local function setup_grid(self) - local grid = self.druid:new_grid("grid", "button_template/button", 3) + local grid = self.druid:new_static_grid("grid", "button_template/button", 3) for i = 1, 12 do local nodes = gui.clone_tree(gui.get_node("button_template/button")) From 6ce14a7a1c476364321da1067f8f0451bc7e1090 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 01:47:00 +0300 Subject: [PATCH 15/46] Add dynamic grid component stub --- druid/base/dynamic_grid.lua | 306 ++++++++++++++++++++++++++++++++ druid/system/druid_instance.lua | 17 +- 2 files changed, 320 insertions(+), 3 deletions(-) create mode 100644 druid/base/dynamic_grid.lua diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua new file mode 100644 index 0000000..422b48f --- /dev/null +++ b/druid/base/dynamic_grid.lua @@ -0,0 +1,306 @@ +--- Component to handle placing components in row +-- @module druid.dynamic_grid + +--- Component events +-- @table Events +-- @tfield druid_event on_add_item On item add callback +-- @tfield druid_event on_remove_item On item remove callback +-- @tfield druid_event on_change_items On item add or remove callback +-- @tfield druid_event on_clear On grid clear callback +-- @tfield druid_event on_update_positions On update item positions callback + +--- Component fields +-- @table Fields +-- @tfield node parent Parent gui node +-- @tfield node[] nodes List of all grid nodes +-- @tfield number first_index The first index of node in grid +-- @tfield number last_index The last index of node in grid +-- @tfield vector3 offset Item distance between each other items +-- @tfield vector3 anchor Item anchor +-- @tfield vector3 node_size Item size +-- @tfield vector4 border The size of item content +-- @tfield vector3 border_offer The border offset for correct anchor calculations + +local const = require("druid.const") +local Event = require("druid.event") +local helper = require("druid.helper") +local component = require("druid.component") + +local DynamicGrid = component.create("dynamic_grid", { const.ON_LAYOUT_CHANGE }) + + +--- Component init function +-- @function dynamic_grid:init +-- @tparam node parent The gui node parent, where items will be placed +function DynamicGrid:init(parent, side) + self.parent = self:get_node(parent) + self.nodes = {} + + self.offset = vmath.vector3(0) + + local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) + self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) + + self.border = vmath.vector4(0) -- Current grid content size + self.border_offset = vmath.vector3(0) -- Content offset for match the grid anchoring + + self.on_add_item = Event() + self.on_remove_item = Event() + self.on_change_items = Event() + self.on_clear = Event() + self.on_update_positions = Event() + + self._set_position_function = gui.set_position +end + + +local _temp_pos = vmath.vector3(0) +--- Return pos for grid node index +-- @function dynamic_grid:get_pos +-- @tparam number index The grid element index +-- @treturn vector3 Node position +function DynamicGrid:get_pos(index) + local row = math.ceil(index) - 1 + local col = (index - row) - 1 + + _temp_pos.x = col * (self.node_size.x + self.offset.x) - self.border_offset.x + _temp_pos.y = -row * (self.node_size.y + self.offset.y) - self.border_offset.y + _temp_pos.z = 0 + + return _temp_pos +end + + +--- Return index for grid pos +-- @function dynamic_grid:get_index +-- @tparam vector3 pos The node position in the grid +-- @treturn number The node index +function DynamicGrid:get_index(pos) + local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) + 1 + local row = -(pos.y + self.border_offset.y) / (self.node_size.y + self.offset.y) + + col = helper.round(col) + row = helper.round(row) + + local index = col + row + return math.ceil(index) +end + + + +function DynamicGrid:on_layout_change() + self:_update_pos(true) +end + + +--- Set grid items offset, the distance between items +-- @function dynamic_grid:set_offset +-- @tparam vector3 offset Offset +function DynamicGrid:set_offset(offset) + self.offset = offset + self:_update_pos() +end + + +--- Set grid anchor. Default anchor is equal to anchor of grid parent node +-- @function dynamic_grid:set_anchor +-- @tparam vector3 anchor Anchor +function DynamicGrid:set_anchor(anchor) + self.anchor = anchor + self:_update_pos() +end + + +--- Add new item to the grid +-- @function dynamic_grid:add +-- @tparam node item Gui node +-- @tparam[opt] number index The item position. By default add as last item +function DynamicGrid:add(item, index) + index = index or ((self.last_index or 0) + 1) + + if self.nodes[index] then + -- Move nodes to right + for i = self.last_index, index, -1 do + self.nodes[i + 1] = self.nodes[i] + end + end + + self.nodes[index] = item + + gui.set_parent(item, self.parent) + + local pos = self:get_pos(index) + -- Add new item instantly in new pos + gui.set_position(item, pos) + + for i, _ in pairs(self.nodes) do + self:_update_border_offset(self:get_pos(i)) + end + + self:_update_pos() + self:_update_indexes() + + self.on_add_item:trigger(self:get_context(), item, index) + self.on_change_items:trigger(self:get_context(), index) +end + + +--- Remove the item from the grid. Note that gui node will be not deleted +-- @function dynamic_grid:remove +-- @tparam number index The grid node index to remove +-- @tparam bool is_shift_nodes If true, will shift nodes left after index +function DynamicGrid:remove(index, is_shift_nodes) + assert(self.nodes[index], "No grid item at given index " .. index) + + self.nodes[index] = nil + + if is_shift_nodes then + for i = index, self.last_index do + self.nodes[i] = self.nodes[i + 1] + end + end + + -- Recalculate borders + self.border = vmath.vector4(0) + self:_update_border_offset(self:get_pos(1)) + for i, _ in pairs(self.nodes) do + self:_update_border_offset(self:get_pos(i)) + end + + self:_update_pos() + self:_update_indexes() + + self.on_add_item:trigger(self:get_context(), index) + self.on_change_items:trigger(self:get_context(), index) +end + + +--- Return grid content size +-- @function dynamic_grid:get_size +-- @treturn vector3 The grid content size +function DynamicGrid:get_size(border) + border = border or self.border + return vmath.vector3( + border.z - border.x, + border.y - border.w, + 0) +end + + +--- Return grid size for amount of nodes in this grid +-- @function dynamic_grid:get_size_for_elements_count +-- @tparam number count The grid content node amount +-- @treturn vector3 The grid content size +function DynamicGrid:get_size_for_elements_count(count) + local border = vmath.vector4(0) + for i = 1, count do + local pos = self:get_pos(i) + self:_update_border(pos, border) + end + + return self:get_size(border) +end + + +--- Return array of all node positions +-- @function dynamic_grid:get_all_pos +-- @treturn vector3[] All grid node positions +function DynamicGrid:get_all_pos() + local result = {} + for i, node in pairs(self.nodes) do + table.insert(result, gui.get_position(node)) + end + + return result +end + + +--- Change set position function for grid nodes. It will call on +-- update poses on grid elements. Default: gui.set_position +-- @function dynamic_grid:set_position_function +-- @tparam function callback Function on node set position +function DynamicGrid:set_position_function(callback) + self._set_position_function = callback or gui.set_position +end + + +--- Clear grid nodes array. GUI nodes will be not deleted! +-- If you want to delete GUI nodes, use dynamic_grid.nodes array before grid:clear +-- @function dynamic_grid:clear +function DynamicGrid:clear() + self.border.x = 0 + self.border.y = 0 + self.border.w = 0 + self.border.z = 0 + + self:_update_border_offset(self:get_pos(1)) + + self.nodes = {} + self:_update_indexes() +end + + + +--- Return the grid nodes table +-- @function dynamic_grid:get_nodes +-- @treturn table The grid nodes +function DynamicGrid:get_nodes() + return self.nodes +end + + +function DynamicGrid:_update_indexes() + self.first_index = nil + self.last_index = nil + for index in pairs(self.nodes) do + self.first_index = self.first_index or index + self.last_index = self.last_index or index + + self.first_index = math.min(self.first_index, index) + self.last_index = math.max(self.last_index, index) + end +end + + +function DynamicGrid:_update_border(pos, border) + local size = self.node_size + local pivot = self.node_pivot + + local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x + local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x + local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y + local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y + + border.x = math.min(border.x, left) + border.y = math.max(border.y, top) + border.z = math.max(border.z, right) + border.w = math.min(border.w, bottom) +end + + +function DynamicGrid:_update_border_offset(pos) + local border = self.border + self:_update_border(pos, border) + + self.border_offset = vmath.vector3( + (border.x + (border.z - border.x) * self.anchor.x), + (border.y + (border.w - border.y) * self.anchor.y), + 0 + ) +end + + +function DynamicGrid:_update_pos(is_instant) + for i, node in pairs(self.nodes) do + if is_instant then + gui.set_position(node, self:get_pos(i)) + else + self._set_position_function(node, self:get_pos(i)) + end + end + + self.on_update_positions:trigger(self:get_context()) +end + + +return DynamicGrid diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index e9b163b..270b7c4 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -9,7 +9,8 @@ -- @see druid.lang_text -- @see druid.timer -- @see druid.progress --- @see druid.grid +-- @see druid.static_grid +-- @see druid.dynamic_grid -- @see druid.scroll -- @see druid.slider -- @see druid.checkbox @@ -33,6 +34,7 @@ local lang_text = require("druid.base.lang_text") local timer = require("druid.base.timer") local progress = require("druid.base.progress") local static_grid = require("druid.base.static_grid") +local dynamic_grid = require("druid.base.dynamic_grid") local scroll = require("druid.base.scroll") local slider = require("druid.base.slider") local checkbox = require("druid.base.checkbox") @@ -414,8 +416,8 @@ function Druid.new_grid(self, ...) end ---- Create staic grid basic component --- @function druid:new_staic_grid +--- Create static grid basic component +-- @function druid:new_static_grid -- @tparam args ... grid init args -- @treturn Component grid component function Druid.new_static_grid(self, ...) @@ -423,6 +425,15 @@ function Druid.new_static_grid(self, ...) end +--- Create dynamic grid basic component +-- @function druid:new_dynamic_grid +-- @tparam args ... grid init args +-- @treturn Component grid component +function Druid.new_dynamic_grid(self, ...) + return Druid.create(self, dynamic_grid, ...) +end + + --- Create scroll basic component -- @function druid:new_scroll -- @tparam args ... scroll init args From f8731b26401643a13b11ea72c1b5b16204cfd445 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 21 Sep 2020 23:00:51 +0300 Subject: [PATCH 16/46] Add initial progress on dynamic grid --- druid/base/dynamic_grid.lua | 167 ++++++++++++++++-------- druid/base/static_grid.lua | 1 - example/gui/main/main.gui | 246 +++++++++++++++++++++++++++++++++-- example/page/grid_page.lua | 35 ++++- example/page/scroll_page.lua | 2 +- 5 files changed, 379 insertions(+), 72 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 422b48f..314dd51 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -34,6 +34,7 @@ local DynamicGrid = component.create("dynamic_grid", { const.ON_LAYOUT_CHANGE }) -- @tparam node parent The gui node parent, where items will be placed function DynamicGrid:init(parent, side) self.parent = self:get_node(parent) + self.nodes = {} self.offset = vmath.vector3(0) @@ -50,24 +51,35 @@ function DynamicGrid:init(parent, side) self.on_clear = Event() self.on_update_positions = Event() + self.center_pos = vmath.vector3(0) + self._set_position_function = gui.set_position end -local _temp_pos = vmath.vector3(0) --- Return pos for grid node index -- @function dynamic_grid:get_pos -- @tparam number index The grid element index +-- @tparam node node The node to be placed -- @treturn vector3 Node position -function DynamicGrid:get_pos(index) - local row = math.ceil(index) - 1 - local col = (index - row) - 1 +function DynamicGrid:get_pos(index, node) + local prev_node = self.nodes[index-1] + local next_node = self.nodes[index+1] - _temp_pos.x = col * (self.node_size.x + self.offset.x) - self.border_offset.x - _temp_pos.y = -row * (self.node_size.y + self.offset.y) - self.border_offset.y - _temp_pos.z = 0 + if not prev_node and not next_node then + -- TODO: assert no elements in grid now + -- should be center of current scroll + return self.center_pos -- first element in grid + end - return _temp_pos + -- For now it works only by vertical + if prev_node then + return self:_get_next_node_pos(index - 1, node, vmath.vector3(0, 1, 0)) + end + + if next_node then + return self:_get_next_node_pos(index + 1, node, vmath.vector3(0, -1, 0)) + end end @@ -125,17 +137,12 @@ function DynamicGrid:add(item, index) end end - self.nodes[index] = item + self:_add_node(item, index) - gui.set_parent(item, self.parent) - - local pos = self:get_pos(index) - -- Add new item instantly in new pos - gui.set_position(item, pos) - - for i, _ in pairs(self.nodes) do - self:_update_border_offset(self:get_pos(i)) - end + self:_update_borders() + -- for i, _ in pairs(self.nodes) do + -- self:_update_border_offset(self:get_pos(i)) + -- end self:_update_pos() self:_update_indexes() @@ -160,12 +167,11 @@ function DynamicGrid:remove(index, is_shift_nodes) end end - -- Recalculate borders - self.border = vmath.vector4(0) - self:_update_border_offset(self:get_pos(1)) - for i, _ in pairs(self.nodes) do - self:_update_border_offset(self:get_pos(i)) - end + self:_update_borders() + -- self:_update_border_offset(self:get_pos(1)) + -- for i, _ in pairs(self.nodes) do + -- self:_update_border_offset(self:get_pos(i)) + -- end self:_update_pos() self:_update_indexes() @@ -187,18 +193,11 @@ function DynamicGrid:get_size(border) end ---- Return grid size for amount of nodes in this grid --- @function dynamic_grid:get_size_for_elements_count --- @tparam number count The grid content node amount --- @treturn vector3 The grid content size -function DynamicGrid:get_size_for_elements_count(count) - local border = vmath.vector4(0) - for i = 1, count do - local pos = self:get_pos(i) - self:_update_border(pos, border) - end - - return self:get_size(border) +function DynamicGrid:get_center_position() + return vmath.vector3( + (self.border.x + self.border.z)/2, + (self.border.y + self.border.w)/2, + 0) end @@ -228,12 +227,8 @@ end -- If you want to delete GUI nodes, use dynamic_grid.nodes array before grid:clear -- @function dynamic_grid:clear function DynamicGrid:clear() - self.border.x = 0 - self.border.y = 0 - self.border.w = 0 - self.border.z = 0 - - self:_update_border_offset(self:get_pos(1)) + self:_update_borders() + -- self:_update_border_offset(self:get_pos(1)) self.nodes = {} self:_update_indexes() @@ -262,19 +257,31 @@ function DynamicGrid:_update_indexes() end -function DynamicGrid:_update_border(pos, border) - local size = self.node_size - local pivot = self.node_pivot +function DynamicGrid:_update_borders() + local border = vmath.vector4(math.huge, -math.huge, -math.huge, math.huge) - local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x - local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x - local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y - local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y + for index, node in pairs(self.nodes) do + local pos = node.pos + local size = node.size + local pivot = node.pivot - border.x = math.min(border.x, left) - border.y = math.max(border.y, top) - border.z = math.max(border.z, right) - border.w = math.min(border.w, bottom) + local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x + local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x + local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y + local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y + + border.x = math.min(border.x, left) + border.y = math.max(border.y, top) + border.z = math.max(border.z, right) + border.w = math.min(border.w, bottom) + end + + self.border = border + self.border_offset = vmath.vector3( + (border.x + (border.z - border.x) * self.anchor.x), + (border.y + (border.w - border.y) * self.anchor.y), + 0 + ) end @@ -291,11 +298,11 @@ end function DynamicGrid:_update_pos(is_instant) - for i, node in pairs(self.nodes) do + for index, node in pairs(self.nodes) do if is_instant then - gui.set_position(node, self:get_pos(i)) + gui.set_position(node.node, node.pos) else - self._set_position_function(node, self:get_pos(i)) + self._set_position_function(node.node, node.pos) end end @@ -303,4 +310,52 @@ function DynamicGrid:_update_pos(is_instant) end +function DynamicGrid:_get_next_node_pos(origin_node_index, new_node, place_side) + local node = self.nodes[origin_node_index] + local pos = node.pos + local size = node.size + local anchor = node.pivot + + local new_node_size = self:_get_node_size(new_node) + local new_anchor = const.PIVOTS[gui.get_pivot(new_node)] + + local dist = vmath.vector3( + (size.x/2 + new_node_size.x/2) * place_side.x, + (size.y/2 + new_node_size.y/2) * place_side.y, + 0 + ) + + local node_center = vmath.vector3( + pos.x + size.x * anchor.x, + pos.y - size.y * anchor.y, + 0 + ) + + return vmath.vector3( + node_center.x + dist.x + new_node_size.x * new_anchor.x, + node_center.y - dist.y + new_node_size.y * new_anchor.y, + 0 + ) +end + + +function DynamicGrid:_get_node_size(node) + return vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node)) +end + + +function DynamicGrid:_add_node(node, index) + self.nodes[index] = { + node = node, + pos = self:get_pos(index, node), + size = self:_get_node_size(node), + pivot = const.PIVOTS[gui.get_pivot(node)] + } + + -- Add new item instantly in new pos + gui.set_parent(node, self.parent) + gui.set_position(node, self.nodes[index].pos) +end + + return DynamicGrid diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index c64fb66..095dc49 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -263,7 +263,6 @@ function StaticGrid:clear() end - --- Return the grid nodes table -- @function static_grid:get_nodes -- @treturn table The grid nodes diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index c019288..465c22d 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -9713,8 +9713,8 @@ nodes { w: 1.0 } size { - x: 1.0 - y: 1.0 + x: 600.0 + y: 900.0 z: 0.0 w: 1.0 } @@ -9746,12 +9746,67 @@ nodes { clipping_inverted: false alpha: 1.0 template_node_child: false - size_mode: SIZE_MODE_AUTO + size_mode: SIZE_MODE_MANUAL } nodes { position { x: 0.0 - y: 200.0 + y: 450.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: 1800.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: "grid_page_content" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page" + 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 +} +nodes { + position { + x: 0.0 + y: -190.0 z: 0.0 w: 1.0 } @@ -9787,7 +9842,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_N adjust_mode: ADJUST_MODE_FIT - parent: "grid_page" + parent: "grid_page_content" layer: "" inherit_alpha: true slice9 { @@ -9806,7 +9861,7 @@ nodes { nodes { position { x: -150.0 - y: 250.0 + y: -140.0 z: 0.0 w: 1.0 } @@ -9836,7 +9891,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_add" - parent: "grid_page" + parent: "grid_page_content" layer: "" inherit_alpha: true alpha: 1.0 @@ -9965,7 +10020,7 @@ nodes { nodes { position { x: 0.0 - y: 250.0 + y: -140.0 z: 0.0 w: 1.0 } @@ -9995,7 +10050,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_remove" - parent: "grid_page" + parent: "grid_page_content" layer: "" inherit_alpha: true alpha: 1.0 @@ -10124,7 +10179,7 @@ nodes { nodes { position { x: 150.0 - y: 250.0 + y: -140.0 z: 0.0 w: 1.0 } @@ -10154,7 +10209,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_clear" - parent: "grid_page" + parent: "grid_page_content" layer: "" inherit_alpha: true alpha: 1.0 @@ -10283,7 +10338,7 @@ nodes { nodes { position { x: -160.0 - y: 160.0 + y: -230.0 z: 0.0 w: 1.0 } @@ -10319,7 +10374,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_CENTER adjust_mode: ADJUST_MODE_FIT - parent: "grid_page" + parent: "grid_page_content" layer: "" inherit_alpha: true slice9 { @@ -10453,6 +10508,171 @@ nodes { text_leading: 1.0 text_tracking: 0.0 } +nodes { + position { + x: 0.0 + y: -650.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: 400.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.9019608 + y: 0.9019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "grid_dynamic_nodes" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + 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 +} +nodes { + position { + x: 0.0 + y: -700.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: 250.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_red" + id: "grid_dynamic_prefab" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + layer: "" + inherit_alpha: true + slice9 { + x: 20.0 + y: 20.0 + z: 20.0 + w: 20.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: -650.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: 400.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.5019608 + y: 0.3019608 + z: 0.5019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "grid_area" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + 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: 0.5 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} nodes { position { x: 0.0 diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 216b7ed..76c0372 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -45,7 +45,7 @@ local function clear_nodes(self) end -function M.setup_page(self) +local function init_static_grid(self) self.grid_nodes = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5) self.grid_nodes:set_position_function(function(node, pos) gui.animate(node, "position", pos, gui.EASING_OUTSINE, 0.2) @@ -65,4 +65,37 @@ function M.setup_page(self) end +local function add_node_dynamic(self, index) + local node = gui.clone(self.prefab_dynamic) + gui.set_enabled(node, true) + gui.set_size(node, vmath.vector3(250, math.random(60, 150), 0)) + self.dynamic_grid:add(node) +end + + +local function init_dynamic_grid(self) + self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes", "vertical") + + self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") + gui.set_enabled(self.prefab_dynamic, false) + + for i = 1, 15 do + add_node_dynamic(self, i) + end + + local area = gui.get_node("grid_area") + gui.set_size(area, self.dynamic_grid:get_size()) + gui.set_position(area, self.dynamic_grid:get_center_position()) + print(self.dynamic_grid:get_center_position()) +end + + +function M.setup_page(self) + self.grid_page_scroll = self.druid:new_scroll("grid_page", "grid_page_content") + + init_static_grid(self) + init_dynamic_grid(self) +end + + return M diff --git a/example/page/scroll_page.lua b/example/page/scroll_page.lua index 1478b11..522fe51 100644 --- a/example/page/scroll_page.lua +++ b/example/page/scroll_page.lua @@ -5,7 +5,7 @@ local function init_scroll_with_grid(self) local prefab = gui.get_node("grid_prefab") local grid_scroll = self.druid:new_scroll("scroll_with_grid_size", "grid_content") - local grid = self.druid:new_grid("grid_content", "grid_prefab", 20) + local grid = self.druid:new_static_grid("grid_content", "grid_prefab", 20) for i = 1, 40 do local clone_prefab = gui.clone_tree(prefab) From 47562de78a8cd3589232ab724f20a45359c38469 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 22 Sep 2020 00:13:59 +0300 Subject: [PATCH 17/46] Add scroll to grid examples --- example/gui/main/main.gui | 171 ++++++++++++++++++++----------- example/gui/main/main.gui_script | 2 +- 2 files changed, 114 insertions(+), 59 deletions(-) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 465c22d..b877174 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -9837,7 +9837,7 @@ nodes { type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA texture: "" - id: "grid_nodes" + id: "grid_nodes_view" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE pivot: PIVOT_N @@ -9851,6 +9851,61 @@ nodes { z: 0.0 w: 0.0 } + clipping_mode: CLIPPING_MODE_STENCIL + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +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: 400.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: "grid_nodes" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "grid_nodes_view" + 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 @@ -10529,7 +10584,7 @@ nodes { } size { x: 300.0 - y: 400.0 + y: 500.0 z: 0.0 w: 1.0 } @@ -10542,7 +10597,7 @@ nodes { type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA texture: "" - id: "grid_dynamic_nodes" + id: "grid_dynamic_view" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE pivot: PIVOT_N @@ -10556,6 +10611,61 @@ nodes { z: 0.0 w: 0.0 } + clipping_mode: CLIPPING_MODE_STENCIL + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +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: 500.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.9019608 + y: 0.9019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "grid_dynamic_nodes" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "grid_dynamic_view" + 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 @@ -10618,61 +10728,6 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL } -nodes { - position { - x: 0.0 - y: -650.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: 400.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.5019608 - y: 0.3019608 - z: 0.5019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "grid_area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" - 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: 0.5 - template_node_child: false - size_mode: SIZE_MODE_MANUAL -} nodes { position { x: 0.0 diff --git a/example/gui/main/main.gui_script b/example/gui/main/main.gui_script index 8973264..55b9f81 100644 --- a/example/gui/main/main.gui_script +++ b/example/gui/main/main.gui_script @@ -65,7 +65,7 @@ function init(self) init_swipe_control(self) - self.page = 1 + self.page = 7 main_page.setup_page(self) text_page.setup_page(self) button_page.setup_page(self) From 7b1feee341158ddb04ddc02c6254f1c369ec4ff5 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 22 Sep 2020 00:25:14 +0300 Subject: [PATCH 18/46] Add scroll:set_horizontal/vertical_scroll functions --- druid/base/scroll.lua | 28 ++++++++++++++++++++++++++-- example/page/grid_page.lua | 15 ++++++++++----- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 3da85f3..cf5d663 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -283,8 +283,8 @@ local function update_size(self) self.available_pos = get_border_vector(view_border - content_border) self.available_size = get_size_vector(self.available_pos) - self.drag.can_x = self.available_size.x > 0 - self.drag.can_y = self.available_size.y > 0 + self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll + self.drag.can_y = self.available_size.y > 0 and self._is_vertical_scroll -- Extra content size calculation -- We add extra size only if scroll is available @@ -371,6 +371,8 @@ function M.init(self, view_node, content_node) self.selected = nil self.is_animate = false + self._is_horizontal_scroll = true + self._is_vertical_scroll = true update_size(self) end @@ -547,4 +549,26 @@ function M.set_points(self, points) end +--- Lock or unlock horizontal scroll +-- @function scroll:set_horizontal_scroll +-- @tparam bool state True, if horizontal scroll is enabled +-- @treturn druid.scroll Current scroll instance +function M:set_horizontal_scroll(state) + self._is_horizontal_scroll = state + self.drag.can_x = self.available_size.x > 0 and state + return self +end + + +--- Lock or unlock vertical scroll +-- @function scroll:set_vertical_scroll +-- @tparam bool state True, if vertical scroll is enabled +-- @treturn druid.scroll Current scroll instance +function M:set_vertical_scroll(state) + self._is_vertical_scroll = state + self.drag.can_y = self.available_size.y > 0 and state + return self +end + + return M diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 76c0372..794fc9f 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -10,6 +10,7 @@ local function remove_node(self, button) for i = 1, #self.grid_node_buttons do if self.grid_node_buttons[i] == button then table.remove(self.grid_node_buttons, i) + self.grid_static_scroll:set_size(self.grid_nodes:get_size()) break end end @@ -27,6 +28,8 @@ local function add_node(self, index) table.insert(self.grid_node_buttons, button) self.grid_nodes:add(cloned["grid_nodes_prefab"], index) + + self.grid_static_scroll:set_size(self.grid_nodes:get_size()) end @@ -79,20 +82,22 @@ local function init_dynamic_grid(self) self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") gui.set_enabled(self.prefab_dynamic, false) - for i = 1, 15 do + for i = 1, 20 do add_node_dynamic(self, i) end - local area = gui.get_node("grid_area") - gui.set_size(area, self.dynamic_grid:get_size()) - gui.set_position(area, self.dynamic_grid:get_center_position()) - print(self.dynamic_grid:get_center_position()) + self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) end function M.setup_page(self) self.grid_page_scroll = self.druid:new_scroll("grid_page", "grid_page_content") + self.grid_static_scroll = self.druid:new_scroll("grid_nodes_view", "grid_nodes") + :set_horizontal_scroll(false) + self.grid_dynamic_scroll = self.druid:new_scroll("grid_dynamic_view", "grid_dynamic_nodes") + :set_horizontal_scroll(false) + init_static_grid(self) init_dynamic_grid(self) end From 034abda46097fec45a818f4416ba9f09925931a4 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 22 Sep 2020 00:30:41 +0300 Subject: [PATCH 19/46] Refactor scroll component (renamed functions) --- druid/base/scroll.lua | 553 +++++++++++++++++++++--------------------- 1 file changed, 276 insertions(+), 277 deletions(-) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index cf5d663..da2b04e 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -32,7 +32,7 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local M = component.create("scroll", { const.ON_UPDATE, const.ON_LAYOUT_CHANGE }) +local Scroll = component.create("scroll", { const.ON_UPDATE, const.ON_LAYOUT_CHANGE }) local function inverse_lerp(min, max, current) @@ -61,7 +61,264 @@ local function get_size_vector(vector) end -local function on_scroll_drag(self, dx, dy) +--- Component style params. +-- You can override this component styles params in druid styles table +-- or create your own style +-- @table Style +-- @tfield[opt=0] number FRICT Multiplier for free inertion +-- @tfield[opt=0] number FRICT_HOLD Multiplier for inertion, while touching +-- @tfield[opt=3] number INERT_THRESHOLD Scroll speed to stop inertion +-- @tfield[opt=30] number INERT_SPEED Multiplier for inertion speed +-- @tfield[opt=20] number POINTS_DEADZONE Speed to check points of interests in no_inertion mode +-- @tfield[opt=0.35] number BACK_SPEED Scroll back returning lerp speed +-- @tfield[opt=0.2] number ANIM_SPEED Scroll gui.animation speed for scroll_to function +-- @tfield[opt=0] number EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect) +-- @tfield[opt=false] bool SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled +function Scroll:on_style_change(style) + self.style = {} + self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0 + self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2 + self.style.BACK_SPEED = style.BACK_SPEED or 0.35 + + self.style.FRICT = style.FRICT or 0 + self.style.FRICT_HOLD = style.FRICT_HOLD or 0 + + self.style.INERT_THRESHOLD = style.INERT_THRESHOLD or 3 + self.style.INERT_SPEED = style.INERT_SPEED or 30 + self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20 + self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false + + self._is_inert = not (self.style.FRICT == 0 or + self.style.FRICT_HOLD == 0 or + self.style.INERT_SPEED == 0) +end + + +--- Scroll constructor. +-- @function scroll:init +-- @tparam node view_node GUI view scroll node +-- @tparam node content_node GUI content scroll node +function Scroll:init(view_node, content_node) + self.druid = self:get_druid() + + self.view_node = self:get_node(view_node) + self.content_node = self:get_node(content_node) + + self.position = gui.get_position(self.content_node) + self.target_position = vmath.vector3(self.position) + self.inertion = vmath.vector3(0) + + self.drag = self.druid:new_drag(view_node, self._on_scroll_drag) + self.drag.on_touch_start:subscribe(self._on_touch_start) + self.drag.on_touch_end:subscribe(self._on_touch_end) + + self.on_scroll = Event() + self.on_scroll_to = Event() + self.on_point_scroll = Event() + + self.selected = nil + self.is_animate = false + self._is_horizontal_scroll = true + self._is_vertical_scroll = true + + self:_update_size() +end + + +function Scroll:on_layout_change() + gui.set_position(self.content_node, self.position) +end + + +function Scroll:update(dt) + if self.drag.is_drag then + self:_update_hand_scroll(dt) + else + self:_update_free_scroll(dt) + end +end + + +--- Start scroll to target point. +-- @function scroll:scroll_to +-- @tparam point vector3 Target point +-- @tparam[opt] bool is_instant Instant scroll flag +-- @usage scroll:scroll_to(vmath.vector3(0, 50, 0)) +-- @usage scroll:scroll_to(vmath.vector3(0), true) +function Scroll:scroll_to(point, is_instant) + local b = self.available_pos + local target = vmath.vector3(-point.x, -point.y, 0) + target.x = helper.clamp(target.x, b.x, b.z) + target.y = helper.clamp(target.y, b.y, b.w) + + self:_cancel_animate() + + self.is_animate = not is_instant + + if is_instant then + self.target_position = target + self:_set_scroll_position(target) + else + gui.animate(self.content_node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() + self.is_animate = false + self.target_position = target + self:_set_scroll_position(target) + end) + end + + self.on_scroll_to:trigger(self:get_context(), target, is_instant) +end + + +--- Scroll to item in scroll by point index. +-- @function scroll:scroll_to_index +-- @tparam number index Point index +-- @tparam[opt] bool skip_cb If true, skip the point callback +function Scroll:scroll_to_index(index, skip_cb) + if not self.points then + return + end + + index = helper.clamp(index, 1, #self.points) + + if self.selected ~= index then + self.selected = index + + if not skip_cb then + self.on_point_scroll:trigger(self:get_context(), index, self.points[index]) + end + end + + self:scroll_to(self.points[index]) +end + + +--- Start scroll to target scroll percent +-- @function scroll:scroll_to_percent +-- @tparam point vector3 target percent +-- @tparam[opt] bool is_instant instant scroll flag +-- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0)) +function Scroll:scroll_to_percent(percent, is_instant) + local border = self.available_pos + + local pos = vmath.vector3( + -helper.lerp(border.x, border.z, 1 - percent.x), + -helper.lerp(border.w, border.y, 1 - percent.y), + 0 + ) + + self:scroll_to(pos, is_instant) +end + + +--- Return current scroll progress status. +-- Values will be in [0..1] interval +-- @function scroll:get_percent +-- @treturn vector3 New vector with scroll progress values +function Scroll:get_percent() + local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x) + local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y) + + return vmath.vector3(x_perc, y_perc, 0) +end + + +--- Set scroll content size. +-- It will change content gui node size +-- @function scroll:set_size +-- @tparam vector3 size The new size for content node +-- @treturn druid.scroll Current scroll instance +function Scroll:set_size(size) + gui.set_size(self.content_node, size) + self:_update_size() + + return self +end + + +--- Enable or disable scroll inert. +-- If disabled, scroll through points (if exist) +-- If no points, just simple drag without inertion +-- @function scroll:set_inert +-- @tparam bool state Inert scroll state +-- @treturn druid.scroll Current scroll instance +function Scroll:set_inert(state) + self._is_inert = state + + return self +end + + +--- Return if scroll have inertion. +-- @function scroll:is_inert +-- @treturn bool If scroll have inertion +function Scroll:is_inert() + return self._is_inert +end + + +--- Set extra size for scroll stretching. +-- Set 0 to disable stretching effect +-- @function scroll:set_extra_stretch_size +-- @tparam[opt=0] number stretch_size Size in pixels of additional scroll area +-- @treturn druid.scroll Current scroll instance +function Scroll:set_extra_stretch_size(stretch_size) + self.style.EXTRA_STRETCH_SIZE = stretch_size or 0 + self:_update_size() + + return self +end + + +--- Return vector of scroll size with width and height. +-- @function scroll:get_scroll_size +-- @treturn vector3 Available scroll size +function Scroll:get_scroll_size() + return self.available_size +end + + +--- Set points of interest. +-- Scroll will always centered on closer points +-- @function scroll:set_points +-- @tparam table points Array of vector3 points +-- @treturn druid.scroll Current scroll instance +function Scroll:set_points(points) + self.points = points + + table.sort(self.points, function(a, b) + return a.x > b.x or a.y < b.y + end) + + self:_check_threshold() + + return self +end + + +--- Lock or unlock horizontal scroll +-- @function scroll:set_horizontal_scroll +-- @tparam bool state True, if horizontal scroll is enabled +-- @treturn druid.scroll Current scroll instance +function Scroll:set_horizontal_scroll(state) + self._is_horizontal_scroll = state + self.drag.can_x = self.available_size.x > 0 and state + return self +end + + +--- Lock or unlock vertical scroll +-- @function scroll:set_vertical_scroll +-- @tparam bool state True, if vertical scroll is enabled +-- @treturn druid.scroll Current scroll instance +function Scroll:set_vertical_scroll(state) + self._is_vertical_scroll = state + self.drag.can_y = self.available_size.y > 0 and state + return self +end + + +function Scroll:_on_scroll_drag(dx, dy) local t = self.target_position local b = self.available_pos local eb = self.available_pos_extra @@ -102,7 +359,7 @@ local function on_scroll_drag(self, dx, dy) end -local function check_soft_zone(self) +function Scroll:_check_soft_zone() local target = self.target_position local border = self.available_pos local speed = self.style.BACK_SPEED @@ -127,7 +384,7 @@ end --- Cancel animation on other animation or input touch -local function cancel_animate(self) +function Scroll:_cancel_animate() if self.is_animate then self.target_position = gui.get_position(self.content_node) self.position.x = self.target_position.x @@ -138,8 +395,7 @@ local function cancel_animate(self) end - -local function set_scroll_position(self, position) +function Scroll:_set_scroll_position(position) local available_extra = self.available_pos_extra position.x = helper.clamp(position.x, available_extra.x, available_extra.z) position.y = helper.clamp(position.y, available_extra.w, available_extra.y) @@ -158,7 +414,7 @@ end -- if no inert, scroll to next point by scroll direction -- if inert, find next point by scroll director -- @local -local function check_points(self) +function Scroll:_check_points() if not self.points then return end @@ -210,7 +466,7 @@ local function check_points(self) end -local function check_threshold(self) +function Scroll:_check_threshold() local is_stopped = false if self.inertion.x ~= 0 and math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then @@ -223,12 +479,12 @@ local function check_threshold(self) end if is_stopped or not self._is_inert then - check_points(self) + self:_check_points() end end -local function update_free_scroll(self, dt) +function Scroll:_update_free_scroll(dt) local target = self.target_position if self._is_inert and (self.inertion.x ~= 0 or self.inertion.y ~= 0) then @@ -236,31 +492,31 @@ local function update_free_scroll(self, dt) target.x = self.position.x + self.inertion.x * self.style.INERT_SPEED * dt target.y = self.position.y + self.inertion.y * self.style.INERT_SPEED * dt - check_threshold(self) + self:_check_threshold() end -- Inertion friction self.inertion = self.inertion * self.style.FRICT - check_soft_zone(self) + self:_check_soft_zone() if self.position.x ~= target.x or self.position.y ~= target.y then - set_scroll_position(self, target) + self:_set_scroll_position(target) end end -local function update_hand_scroll(self, dt) +function Scroll:_update_hand_scroll(dt) local dx = self.target_position.x - self.position.x local dy = self.target_position.y - self.position.y self.inertion.x = (self.inertion.x + dx) * self.style.FRICT_HOLD self.inertion.y = (self.inertion.y + dy) * self.style.FRICT_HOLD - set_scroll_position(self, self.target_position) + self:_set_scroll_position(self.target_position) end -local function on_touch_start(self) +function Scroll:_on_touch_start() self.inertion.x = 0 self.inertion.y = 0 self.target_position.x = self.position.x @@ -268,12 +524,12 @@ local function on_touch_start(self) end -local function on_touch_end(self) - check_threshold(self) +function Scroll:_on_touch_end() + self:_check_threshold() end -local function update_size(self) +function Scroll:_update_size() local view_border = helper.get_border(self.view_node) local view_size = vmath.mul_per_elem(gui.get_size(self.view_node), gui.get_scale(self.view_node)) @@ -314,261 +570,4 @@ local function update_size(self) end ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table Style --- @tfield[opt=0] number FRICT Multiplier for free inertion --- @tfield[opt=0] number FRICT_HOLD Multiplier for inertion, while touching --- @tfield[opt=3] number INERT_THRESHOLD Scroll speed to stop inertion --- @tfield[opt=30] number INERT_SPEED Multiplier for inertion speed --- @tfield[opt=20] number POINTS_DEADZONE Speed to check points of interests in no_inertion mode --- @tfield[opt=0.35] number BACK_SPEED Scroll back returning lerp speed --- @tfield[opt=0.2] number ANIM_SPEED Scroll gui.animation speed for scroll_to function --- @tfield[opt=0] number EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect) --- @tfield[opt=false] bool SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled -function M.on_style_change(self, style) - self.style = {} - self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0 - self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2 - self.style.BACK_SPEED = style.BACK_SPEED or 0.35 - - self.style.FRICT = style.FRICT or 0 - self.style.FRICT_HOLD = style.FRICT_HOLD or 0 - - self.style.INERT_THRESHOLD = style.INERT_THRESHOLD or 3 - self.style.INERT_SPEED = style.INERT_SPEED or 30 - self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20 - self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false - - self._is_inert = not (self.style.FRICT == 0 or - self.style.FRICT_HOLD == 0 or - self.style.INERT_SPEED == 0) -end - - ---- Scroll constructor. --- @function scroll:init --- @tparam node view_node GUI view scroll node --- @tparam node content_node GUI content scroll node -function M.init(self, view_node, content_node) - self.druid = self:get_druid() - - self.view_node = self:get_node(view_node) - self.content_node = self:get_node(content_node) - - self.position = gui.get_position(self.content_node) - self.target_position = vmath.vector3(self.position) - self.inertion = vmath.vector3(0) - - self.drag = self.druid:new_drag(view_node, on_scroll_drag) - self.drag.on_touch_start:subscribe(on_touch_start) - self.drag.on_touch_end:subscribe(on_touch_end) - - self.on_scroll = Event() - self.on_scroll_to = Event() - self.on_point_scroll = Event() - - self.selected = nil - self.is_animate = false - self._is_horizontal_scroll = true - self._is_vertical_scroll = true - - update_size(self) -end - - -function M.on_layout_change(self) - gui.set_position(self.content_node, self.position) -end - - -function M.update(self, dt) - if self.drag.is_drag then - update_hand_scroll(self, dt) - else - update_free_scroll(self, dt) - end -end - - ---- Start scroll to target point. --- @function scroll:scroll_to --- @tparam point vector3 Target point --- @tparam[opt] bool is_instant Instant scroll flag --- @usage scroll:scroll_to(vmath.vector3(0, 50, 0)) --- @usage scroll:scroll_to(vmath.vector3(0), true) -function M.scroll_to(self, point, is_instant) - local b = self.available_pos - local target = vmath.vector3(-point.x, -point.y, 0) - target.x = helper.clamp(target.x, b.x, b.z) - target.y = helper.clamp(target.y, b.y, b.w) - - cancel_animate(self) - - self.is_animate = not is_instant - - if is_instant then - self.target_position = target - set_scroll_position(self, target) - else - gui.animate(self.content_node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() - self.is_animate = false - self.target_position = target - set_scroll_position(self, target) - end) - end - - self.on_scroll_to:trigger(self:get_context(), target, is_instant) -end - - ---- Scroll to item in scroll by point index. --- @function scroll:scroll_to_index --- @tparam number index Point index --- @tparam[opt] bool skip_cb If true, skip the point callback -function M.scroll_to_index(self, index, skip_cb) - if not self.points then - return - end - - index = helper.clamp(index, 1, #self.points) - - if self.selected ~= index then - self.selected = index - - if not skip_cb then - self.on_point_scroll:trigger(self:get_context(), index, self.points[index]) - end - end - - self:scroll_to(self.points[index]) -end - - ---- Start scroll to target scroll percent --- @function scroll:scroll_to_percent --- @tparam point vector3 target percent --- @tparam[opt] bool is_instant instant scroll flag --- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0)) -function M.scroll_to_percent(self, percent, is_instant) - local border = self.available_pos - - local pos = vmath.vector3( - -helper.lerp(border.x, border.z, 1 - percent.x), - -helper.lerp(border.w, border.y, 1 - percent.y), - 0 - ) - - M.scroll_to(self, pos, is_instant) -end - - ---- Return current scroll progress status. --- Values will be in [0..1] interval --- @function scroll:get_percent --- @treturn vector3 New vector with scroll progress values -function M.get_percent(self) - local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x) - local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y) - - return vmath.vector3(x_perc, y_perc, 0) -end - - ---- Set scroll content size. --- It will change content gui node size --- @function scroll:set_size --- @tparam vector3 size The new size for content node --- @treturn druid.scroll Current scroll instance -function M.set_size(self, size) - gui.set_size(self.content_node, size) - update_size(self) - - return self -end - - ---- Enable or disable scroll inert. --- If disabled, scroll through points (if exist) --- If no points, just simple drag without inertion --- @function scroll:set_inert --- @tparam bool state Inert scroll state --- @treturn druid.scroll Current scroll instance -function M.set_inert(self, state) - self._is_inert = state - - return self -end - - ---- Return if scroll have inertion. --- @function scroll:is_inert --- @treturn bool If scroll have inertion -function M.is_inert(self) - return self._is_inert -end - - ---- Set extra size for scroll stretching. --- Set 0 to disable stretching effect --- @function scroll:set_extra_stretch_size --- @tparam[opt=0] number stretch_size Size in pixels of additional scroll area --- @treturn druid.scroll Current scroll instance -function M.set_extra_stretch_size(self, stretch_size) - self.style.EXTRA_STRETCH_SIZE = stretch_size or 0 - update_size(self) - - return self -end - - ---- Return vector of scroll size with width and height. --- @function scroll:get_scroll_size --- @treturn vector3 Available scroll size -function M.get_scroll_size(self) - return self.available_size -end - - ---- Set points of interest. --- Scroll will always centered on closer points --- @function scroll:set_points --- @tparam table points Array of vector3 points --- @treturn druid.scroll Current scroll instance -function M.set_points(self, points) - self.points = points - - table.sort(self.points, function(a, b) - return a.x > b.x or a.y < b.y - end) - - check_threshold(self) - - return self -end - - ---- Lock or unlock horizontal scroll --- @function scroll:set_horizontal_scroll --- @tparam bool state True, if horizontal scroll is enabled --- @treturn druid.scroll Current scroll instance -function M:set_horizontal_scroll(state) - self._is_horizontal_scroll = state - self.drag.can_x = self.available_size.x > 0 and state - return self -end - - ---- Lock or unlock vertical scroll --- @function scroll:set_vertical_scroll --- @tparam bool state True, if vertical scroll is enabled --- @treturn druid.scroll Current scroll instance -function M:set_vertical_scroll(state) - self._is_vertical_scroll = state - self.drag.can_y = self.available_size.y > 0 and state - return self -end - - -return M +return Scroll From fab60a3783bab458d074b0887c302a922ea4afe9 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 22 Sep 2020 08:20:36 +0300 Subject: [PATCH 20/46] Add FAQ documentation stub --- docs_md/changelog.md | 6 ++++-- docs_md/faq.md | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 docs_md/faq.md diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 809fa45..aee8faa 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -98,10 +98,12 @@ Druid 0.5.0: - **Fix #64:** Hover component: wrong mouse_hover default state - **Fix #71:** Blocker: blocker now correct block mouse hover event - **Fix #72:** Fix `return nil` in some `on_input` functions -- **Fix #74:** Fix typo: strech -> stretch. Scroll function `set_extra_stretch_size` renamed +- **Fix #74:** __[BREAKING]__ Fix typo: strech -> stretch. Scroll function `set_extra_stretch_size` renamed - **Fix #76:** Add params for lang text localization component - **Fix #79:** Fix druid:remove inside on_input callback - **Fix #80:** Fix hover set_enable typo function call - _druid:create_ deprecated. Use _druid:new_ instead (for custom components) -- Add `component.tempalte.lua` as template for Druid custom component +- Add _scroll:set_vertical_scroll_ and _scroll:set_horizontal_scroll_ for disable scroll sides +- **#85** Move several components from `base` folder to `extended`. In future, to use them, you have to register them manually. This is need for decrease build size by excluding unused components +- Add `component.template.lua` as template for Druid custom component diff --git a/docs_md/faq.md b/docs_md/faq.md new file mode 100644 index 0000000..eb4f793 --- /dev/null +++ b/docs_md/faq.md @@ -0,0 +1,18 @@ +# Druid FAQ + +### Q: How to remove the Druid component instance +A: --- + +### Q: How to make scroll work? +A: --- + +### Q: How the input is processing? +A: --- + +### Q: For what purpose Blocker component is exist? +A: --- + +### Q: Which stuff can I do with custom components? +A: --- + + From 28087da814740fc63a03a53246925632ab71e256 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 22 Sep 2020 08:31:16 +0300 Subject: [PATCH 21/46] Update grid changelogs --- docs_md/changelog.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index aee8faa..97ab4a1 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -94,6 +94,19 @@ Druid 0.4.0: Druid 0.5.0: +- **#77** Grid update: + - The _grid_ component now is __deprecated__. Use _static_grid_ instead. Druid will show you deprecated message, if you still using _grid_ component + - Add _static_grid_ component + - The behaviour like previous _grid_ component + - Have constant element size, so have ability to precalculate positions, indexes and size of content + - By default, not shifting elements on removing element. Add _is_shift_ flag to _static_grid:remove_ function + - This grid can spawn elements with several rows and collumns + - Add _dynamic_grid_ component + - Have dynamic element size. So have no ability to precalculate stuff like _static_grid_ + - Element size got from _gui.get_size_ * _gui.get_scale_ + - This grid can not have spaces between elements. You will get the error, if spawn element far away from other elements + - The grid can spawn elements only in row or in collumn +- **#37** Add _on_layout_change_ support. Druid will keep and restore GUI component data between changing game layout. Override function _on_layout_change_ in your custom components to do stuff you need. - **Fix #61:** Button component: fix button animation node creation - **Fix #64:** Hover component: wrong mouse_hover default state - **Fix #71:** Blocker: blocker now correct block mouse hover event From d0385a3c0324c4f5aeb39154810e3b5b31a49ed3 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 24 Sep 2020 09:23:45 +0300 Subject: [PATCH 22/46] FIx dynamic grid sides --- druid/base/dynamic_grid.lua | 60 +++++++++++++++++++------------------ example/page/grid_page.lua | 6 ++-- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 6c7d300..99d752e 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -27,30 +27,33 @@ local component = require("druid.component") local DynamicGrid = component.create("dynamic_grid", { const.ON_LAYOUT_CHANGE }) +local SIDE_VECTORS = { + LEFT = vmath.vector3(-1, 0, 0), + RIGHT = vmath.vector3(1, 0, 0), + TOP = vmath.vector3(0, -1, 0), + BOT = vmath.vector3(0, 1, 0), +} --- Component init function -- @function dynamic_grid:init -- @tparam node parent The gui node parent, where items will be placed +-- @tparam enum.side side The grid side. By default - vertical function DynamicGrid:init(parent, side) + self.nodes = {} + self.side = side or const.SIDE.Y self.parent = self:get_node(parent) - self.nodes = {} - self.offset = vmath.vector3(0) - + self.border = vmath.vector4(0) -- Current grid content size self.pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) - self.border = vmath.vector4(0) -- Current grid content size - self.on_add_item = Event() self.on_remove_item = Event() self.on_change_items = Event() self.on_clear = Event() self.on_update_positions = Event() - self.center_pos = vmath.vector3(0) - self._set_position_function = gui.set_position end @@ -69,18 +72,17 @@ function DynamicGrid:get_pos(index, node) local size = self:_get_node_size(node) local pivot = const.PIVOTS[gui.get_pivot(node)] return vmath.vector3( - size.x * pivot.x + size.x * self.pivot.x, + size.x * pivot.x - size.x * self.pivot.x, size.y * pivot.y - size.y * self.pivot.y, 0) end - -- For now it works only by vertical if prev_node then - return self:_get_next_node_pos(index - 1, node, vmath.vector3(0, 1, 0)) + return self:_get_next_node_pos(index - 1, node, self:_get_side_vector(self.side, 1)) end if next_node then - return self:_get_next_node_pos(index + 1, node, vmath.vector3(0, -1, 0)) + return self:_get_next_node_pos(index + 1, node, self:_get_side_vector(self.side, -1)) end end @@ -209,7 +211,6 @@ function DynamicGrid:clear() end - --- Return the grid nodes table -- @function dynamic_grid:get_nodes -- @treturn table The grid nodes @@ -269,28 +270,18 @@ end function DynamicGrid:_get_next_node_pos(origin_node_index, new_node, place_side) local node = self.nodes[origin_node_index] - local pos = node.pos - local size = node.size - local anchor = node.pivot local new_node_size = self:_get_node_size(new_node) - local new_anchor = const.PIVOTS[gui.get_pivot(new_node)] + local new_pivot = const.PIVOTS[gui.get_pivot(new_node)] - local dist = vmath.vector3( - (size.x/2 + new_node_size.x/2) * place_side.x, - (size.y/2 + new_node_size.y/2) * place_side.y, - 0 - ) - - local node_center = vmath.vector3( - pos.x - size.x * anchor.x, - pos.y - size.y * anchor.y, - 0 - ) + local dist_x = (node.size.x/2 + new_node_size.x/2) * place_side.x + local dist_y = (node.size.y/2 + new_node_size.y/2) * place_side.y + local node_center_x = node.pos.x - node.size.x * node.pivot.x + local node_center_y = node.pos.y - node.size.y * node.pivot.y return vmath.vector3( - node_center.x + dist.x + new_node_size.x * new_anchor.x, - node_center.y - dist.y + new_node_size.y * new_anchor.y, + node_center_x + dist_x + new_node_size.x * new_pivot.x, + node_center_y - dist_y + new_node_size.y * new_pivot.y, 0 ) end @@ -315,4 +306,15 @@ function DynamicGrid:_add_node(node, index) end +function DynamicGrid:_get_side_vector(side, is_forward) + if side == const.SIDE.X then + return is_forward and SIDE_VECTORS.RIGHT or SIDE_VECTORS.LEFT + end + + if side == const.SIDE.Y then + return is_forward and SIDE_VECTORS.BOT or SIDE_VECTORS.TOP + end +end + + return DynamicGrid diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 794fc9f..fd9268b 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -1,3 +1,5 @@ +local druid_const = require("druid.const") + local M = {} @@ -77,12 +79,12 @@ end local function init_dynamic_grid(self) - self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes", "vertical") + self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes", druid_const.SIDE.Y) self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") gui.set_enabled(self.prefab_dynamic, false) - for i = 1, 20 do + for i = 1, 8 do add_node_dynamic(self, i) end From f25a8acd9546a6e042ab34a7da3cc5685cc7802b Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 24 Sep 2020 09:32:39 +0300 Subject: [PATCH 23/46] Remove side from dynamic_grid, move it to node pivot --- docs_md/changelog.md | 1 + druid/base/dynamic_grid.lua | 13 ++++++++----- druid/const.lua | 5 +++++ example/page/grid_page.lua | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 536d82b..830b00f 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -106,6 +106,7 @@ Druid 0.5.0: - Element size got from _gui.get_size_ * _gui.get_scale_ - This grid can not have spaces between elements. You will get the error, if spawn element far away from other elements - The grid can spawn elements only in row or in collumn + - The grid node should have West or North pivot (vertical or horizontal element placement) - **#37** Add _on_layout_change_ support. Druid will keep and restore GUI component data between changing game layout. Override function _on_layout_change_ in your custom components to do stuff you need. - **#85** Move several components from `base` folder to `extended`. In future, to use them, you have to register them manually. This is need for decrease build size by excluding unused components - Add _scroll:set_vertical_scroll_ and _scroll:set_horizontal_scroll_ for disable scroll sides diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 99d752e..06d3a10 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -37,16 +37,19 @@ local SIDE_VECTORS = { --- Component init function -- @function dynamic_grid:init -- @tparam node parent The gui node parent, where items will be placed --- @tparam enum.side side The grid side. By default - vertical function DynamicGrid:init(parent, side) - self.nodes = {} - self.side = side or const.SIDE.Y self.parent = self:get_node(parent) + local parent_pivot = gui.get_pivot(self.parent) + self.pivot = helper.get_pivot_offset(parent_pivot) + self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) + + assert(parent_pivot == gui.PIVOT_W or parent_pivot == gui.PIVOT_N, const.ERRORS.GRID_DYNAMIC_ANCHOR) + self.side = (parent_pivot == gui.PIVOT_W and const.SIDE.X or const.SIDE.Y) + + self.nodes = {} self.offset = vmath.vector3(0) self.border = vmath.vector4(0) -- Current grid content size - self.pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) - self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) self.on_add_item = Event() self.on_remove_item = Event() diff --git a/druid/const.lua b/druid/const.lua index cad9f8a..151b62b 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -102,6 +102,11 @@ M.SWIPE = { } +M.ERRORS = { + GRID_DYNAMIC_ANCHOR = "The pivot of dynamic grid node should be West or North" +} + + M.EMPTY_FUNCTION = function() end M.EMPTY_STRING = "" M.SPACE_STRING = " " diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index fd9268b..f7aafd7 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -79,7 +79,7 @@ end local function init_dynamic_grid(self) - self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes", druid_const.SIDE.Y) + self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes") self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") gui.set_enabled(self.prefab_dynamic, false) From 5c4497330c25c051a53232f3b1edb2fcd775e509 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 18:59:54 +0300 Subject: [PATCH 24/46] Add vertical dynamic grid to example --- example/gui/main/main.gui | 173 ++++++++++++++++++++++++++++++++++++- example/page/grid_page.lua | 32 ++++++- 2 files changed, 198 insertions(+), 7 deletions(-) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index b877174..e16c890 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10644,14 +10644,14 @@ nodes { w: 1.0 } color { - x: 0.9019608 - y: 0.9019608 - z: 0.7019608 + x: 0.6 + y: 0.3019608 + z: 0.4 w: 1.0 } type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" + texture: "" id: "grid_dynamic_nodes" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -10728,6 +10728,171 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL } +nodes { + position { + x: -250.0 + y: -1236.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: 500.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.9019608 + y: 0.9019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "grid_dynamic_hor_view" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_STENCIL + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +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: 500.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.4 + y: 0.3019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "grid_dynamic_hor_nodes" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "grid_dynamic_hor_view" + 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 +} +nodes { + position { + x: 0.0 + y: -1232.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: 100.0 + y: 80.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_red" + id: "grid_dynamic_hor_prefab" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + layer: "" + inherit_alpha: true + slice9 { + x: 20.0 + y: 20.0 + z: 20.0 + w: 20.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} nodes { position { x: 0.0 diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index f7aafd7..2b23f7d 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -3,12 +3,12 @@ local druid_const = require("druid.const") local M = {} -local function remove_node(self, button) +local function remove_node(self, button, is_shift) gui.delete_node(button.node) self.druid:remove(button) local index = self.grid_nodes:get_index_by_node(button.node) - self.grid_nodes:remove(index, true) + self.grid_nodes:remove(index, is_shift) for i = 1, #self.grid_node_buttons do if self.grid_node_buttons[i] == button then table.remove(self.grid_node_buttons, i) @@ -25,8 +25,12 @@ local function add_node(self, index) gui.set_enabled(cloned["grid_nodes_prefab"], true) local button = self.druid:new_button(cloned["grid_nodes_prefab"], function(_, params, button) + remove_node(self, button, true) + end) + button.on_long_click:subscribe(function() remove_node(self, button) end) + table.insert(self.grid_node_buttons, button) self.grid_nodes:add(cloned["grid_nodes_prefab"], index) @@ -78,17 +82,37 @@ local function add_node_dynamic(self, index) end +local function add_node_dynamic_hor(self, index) + local node = gui.clone(self.prefab_hor_dynamic) + gui.set_enabled(node, true) + gui.set_size(node, vmath.vector3(80 + math.random(0, 80), 80, 0)) + self.dynamic_hor_grid:add(node) +end + + local function init_dynamic_grid(self) self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes") self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") gui.set_enabled(self.prefab_dynamic, false) - for i = 1, 8 do + for i = 1, 10 do add_node_dynamic(self, i) end self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) + + + self.dynamic_hor_grid = self.druid:new_dynamic_grid("grid_dynamic_hor_nodes") + + self.prefab_hor_dynamic = gui.get_node("grid_dynamic_hor_prefab") + gui.set_enabled(self.prefab_hor_dynamic, false) + + for i = 1, 10 do + add_node_dynamic_hor(self, i) + end + + self.grid_dynamic_hor_scroll:set_size(self.dynamic_hor_grid:get_size()) end @@ -99,6 +123,8 @@ function M.setup_page(self) :set_horizontal_scroll(false) self.grid_dynamic_scroll = self.druid:new_scroll("grid_dynamic_view", "grid_dynamic_nodes") :set_horizontal_scroll(false) + self.grid_dynamic_hor_scroll = self.druid:new_scroll("grid_dynamic_hor_view", "grid_dynamic_hor_nodes") + :set_vertical_scroll(false) init_static_grid(self) init_dynamic_grid(self) From 19139ca0ef0be1f622c21ffca2877ecfbe2443a2 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 22:13:15 +0300 Subject: [PATCH 25/46] Add dirty add_scroll_offset to scroll component --- druid/base/scroll.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index da2b04e..e898f0c 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -103,6 +103,7 @@ function Scroll:init(view_node, content_node) self.view_node = self:get_node(view_node) self.content_node = self:get_node(content_node) + self.scroll_offset = vmath.vector3(0) self.position = gui.get_position(self.content_node) self.target_position = vmath.vector3(self.position) @@ -236,6 +237,19 @@ function Scroll:set_size(size) end +--- Set scroll content size by borders +-- It will change content gui node sizes +-- @function scroll:set_border +-- @tparam vector4 border The new scroll borders for content node +-- @treturn druid.Scroll Current scroll instance +function Scroll:set_scroll_offset(offset) + self.scroll_offset = offset + self:_update_size() + + return self +end + + --- Enable or disable scroll inert. -- If disabled, scroll through points (if exist) -- If no points, just simple drag without inertion @@ -538,6 +552,10 @@ function Scroll:_update_size() self.available_pos = get_border_vector(view_border - content_border) self.available_size = get_size_vector(self.available_pos) + self.available_pos.x = self.available_pos.x + self.scroll_offset.x + self.available_pos.z = self.available_pos.z + self.scroll_offset.x + self.available_pos.y = self.available_pos.y + self.scroll_offset.y + self.available_pos.w = self.available_pos.w + self.scroll_offset.y self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll self.drag.can_y = self.available_size.y > 0 and self._is_vertical_scroll @@ -567,6 +585,10 @@ function Scroll:_update_size() self.available_pos_extra = get_border_vector(view_border - content_border_extra) self.available_size_extra = get_size_vector(self.available_pos_extra) + self.available_pos_extra.x = self.available_pos_extra.x + self.scroll_offset.x + self.available_pos_extra.z = self.available_pos_extra.z + self.scroll_offset.x + self.available_pos_extra.y = self.available_pos_extra.y + self.scroll_offset.y + self.available_pos_extra.w = self.available_pos_extra.w + self.scroll_offset.y end From 5db669218d881bafb770008b1d57e9452c07ac50 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 22:13:34 +0300 Subject: [PATCH 26/46] Add dynamic grid horizontal example. Add control buttons for gris --- example/gui/main/main.gui | 640 ++++++++++++++++++++++++++++++++++++- example/page/grid_page.lua | 58 +++- 2 files changed, 689 insertions(+), 9 deletions(-) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index e16c890..0e7519a 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10731,7 +10731,7 @@ nodes { nodes { position { x: -250.0 - y: -1236.0 + y: -1300.0 z: 0.0 w: 1.0 } @@ -10841,7 +10841,7 @@ nodes { nodes { position { x: 0.0 - y: -1232.0 + y: -1309.0 z: 0.0 w: 1.0 } @@ -10893,6 +10893,642 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL } +nodes { + position { + x: -60.0 + y: -620.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.75 + y: 0.75 + 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_start_dynamic" + parent: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false +} +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_start_dynamic/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_add_start_dynamic" + 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 +} +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 Start" + font: "game" + id: "button_add_start_dynamic/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_start_dynamic/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 +} +nodes { + position { + x: 60.0 + y: -620.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.75 + y: 0.75 + 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_end_dynamic" + parent: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false +} +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_end_dynamic/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_add_end_dynamic" + 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 +} +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 End" + font: "game" + id: "button_add_end_dynamic/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_end_dynamic/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 +} +nodes { + position { + x: -60.0 + y: -1211.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.75 + y: 0.75 + 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_start_dynamic_hor" + parent: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false +} +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_start_dynamic_hor/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_add_start_dynamic_hor" + 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 +} +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 Start" + font: "game" + id: "button_add_start_dynamic_hor/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_start_dynamic_hor/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 +} +nodes { + position { + x: 60.0 + y: -1211.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.75 + y: 0.75 + 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_end_dynamic_hor" + parent: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + template: "/example/templates/button.gui" + template_node_child: false +} +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_end_dynamic_hor/button" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "button_add_end_dynamic_hor" + 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 +} +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 End" + font: "game" + id: "button_add_end_dynamic_hor/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_end_dynamic_hor/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 +} nodes { position { x: 0.0 diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 2b23f7d..74f4b7a 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -30,6 +30,7 @@ local function add_node(self, index) button.on_long_click:subscribe(function() remove_node(self, button) end) + button:set_click_zone(self.grid_static_scroll.view_node) table.insert(self.grid_node_buttons, button) @@ -74,11 +75,35 @@ local function init_static_grid(self) end -local function add_node_dynamic(self, index) +local function remove_dynamic_node(self, button) + gui.delete_node(button.node) + + self.druid:remove(button) + local index = self.dynamic_grid:get_index_by_node(button.node) + self.dynamic_grid:remove(index, true) + for i = 1, #self.dynamic_node_buttons do + if self.dynamic_node_buttons[i] == button then + table.remove(self.dynamic_node_buttons, i) + self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) + break + end + end +end + + +local function add_node_dynamic(self, index, is_shift_left) local node = gui.clone(self.prefab_dynamic) gui.set_enabled(node, true) gui.set_size(node, vmath.vector3(250, math.random(60, 150), 0)) - self.dynamic_grid:add(node) + self.dynamic_grid:add(node, index, is_shift_left) + + local button = self.druid:new_button(node, function(_, params, button) + remove_dynamic_node(self, button, true) + end) + button:set_click_zone(self.grid_dynamic_scroll.view_node) + self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) + self.grid_dynamic_scroll:set_scroll_offset(self.dynamic_grid:get_zero_offset()) + table.insert(self.dynamic_node_buttons, button) end @@ -86,12 +111,19 @@ local function add_node_dynamic_hor(self, index) local node = gui.clone(self.prefab_hor_dynamic) gui.set_enabled(node, true) gui.set_size(node, vmath.vector3(80 + math.random(0, 80), 80, 0)) - self.dynamic_hor_grid:add(node) + self.dynamic_hor_grid:add(node, index) + self.grid_dynamic_hor_scroll:set_size(self.dynamic_hor_grid:get_size()) + self.grid_dynamic_hor_scroll:set_scroll_offset(self.dynamic_hor_grid:get_zero_offset()) end local function init_dynamic_grid(self) + -- Vertical horizontal grid + self.dynamic_node_buttons = {} self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes") + self.dynamic_grid:set_position_function(function(node, pos) + gui.animate(node, gui.PROP_POSITION, pos, gui.EASING_OUTSINE, 0.2) + end) self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") gui.set_enabled(self.prefab_dynamic, false) @@ -99,12 +131,19 @@ local function init_dynamic_grid(self) for i = 1, 10 do add_node_dynamic(self, i) end - - self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) + self.druid:new_button("button_add_start_dynamic/button", function() + add_node_dynamic(self, 3, true) + end) + self.druid:new_button("button_add_end_dynamic/button", function() + add_node_dynamic(self) + end) + -- Horizontal dynamic grid self.dynamic_hor_grid = self.druid:new_dynamic_grid("grid_dynamic_hor_nodes") - + self.dynamic_hor_grid:set_position_function(function(node, pos) + gui.animate(node, gui.PROP_POSITION, pos, gui.EASING_OUTSINE, 0.2) + end) self.prefab_hor_dynamic = gui.get_node("grid_dynamic_hor_prefab") gui.set_enabled(self.prefab_hor_dynamic, false) @@ -112,7 +151,12 @@ local function init_dynamic_grid(self) add_node_dynamic_hor(self, i) end - self.grid_dynamic_hor_scroll:set_size(self.dynamic_hor_grid:get_size()) + self.druid:new_button("button_add_start_dynamic_hor/button", function() + add_node_dynamic_hor(self, 1) + end) + self.druid:new_button("button_add_end_dynamic_hor/button", function() + add_node_dynamic_hor(self) + end) end From f6b7aba87f8bf18270d29ad8808183fef4e5395f Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 22:14:19 +0300 Subject: [PATCH 27/46] Start implement correct add/remove for dynamic grid with node shifts --- druid/base/dynamic_grid.lua | 155 +++++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 54 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 06d3a10..9b7b813 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -16,7 +16,6 @@ -- @tfield number first_index The first index of node in grid -- @tfield number last_index The last index of node in grid -- @tfield vector3 offset Item distance between each other items --- @tfield vector3 anchor Item anchor -- @tfield vector3 node_size Item size -- @tfield vector4 border The size of item content @@ -42,7 +41,6 @@ function DynamicGrid:init(parent, side) local parent_pivot = gui.get_pivot(self.parent) self.pivot = helper.get_pivot_offset(parent_pivot) - self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) assert(parent_pivot == gui.PIVOT_W or parent_pivot == gui.PIVOT_N, const.ERRORS.GRID_DYNAMIC_ANCHOR) self.side = (parent_pivot == gui.PIVOT_W and const.SIDE.X or const.SIDE.Y) @@ -66,11 +64,10 @@ end -- @tparam number index The grid element index -- @tparam node node The node to be placed -- @treturn vector3 Node position -function DynamicGrid:get_pos(index, node) - local prev_node = self.nodes[index-1] - local next_node = self.nodes[index+1] +function DynamicGrid:get_pos(index, node, origin_index) + local origin_node = self.nodes[origin_index] - if not prev_node and not next_node then + if not origin_node then -- TODO: assert no elements in grid now local size = self:_get_node_size(node) local pivot = const.PIVOTS[gui.get_pivot(node)] @@ -80,18 +77,16 @@ function DynamicGrid:get_pos(index, node) 0) end - if prev_node then - return self:_get_next_node_pos(index - 1, node, self:_get_side_vector(self.side, 1)) - end - - if next_node then - return self:_get_next_node_pos(index + 1, node, self:_get_side_vector(self.side, -1)) + if origin_node then + local is_forward = origin_index < index + local delta = is_forward and 1 or -1 + return self:_get_next_node_pos(index - delta, node, self:_get_side_vector(self.side, is_forward)) end end function DynamicGrid:on_layout_change() - self:_update_pos(true) + self:_update(true) end @@ -100,40 +95,60 @@ end -- @tparam vector3 offset Offset function DynamicGrid:set_offset(offset) self.offset = offset - self:_update_pos() + self:_update() end ---- Set grid anchor. Default anchor is equal to anchor of grid parent node --- @function dynamic_grid:set_anchor --- @tparam vector3 anchor Anchor -function DynamicGrid:set_anchor(anchor) - self.anchor = anchor - self:_update_pos() -end - - ---- Add new item to the grid +--- Add new node to the grid -- @function dynamic_grid:add --- @tparam node item Gui node --- @tparam[opt] number index The item position. By default add as last item -function DynamicGrid:add(item, index) +-- @tparam node node Gui node +-- @tparam[opt] number index The node position. By default add as last node +-- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right +function DynamicGrid:add(node, index, is_shift_left) index = index or ((self.last_index or 0) + 1) + print("if shift left", is_shift_left) + if self.nodes[index] then - -- Move nodes to right - for i = self.last_index, index, -1 do - self.nodes[i + 1] = self.nodes[i] + if not is_shift_left then + -- Move nodes to right + for i = self.last_index, index, -1 do + self.nodes[i + 1] = self.nodes[i] + end + else + -- Move nodes to left + for i = self.first_index, index do + self.nodes[i - 1] = self.nodes[i] + print("Move", i-1, i) + end end end - self:_add_node(item, index) + -- TODO: we must choose anchor node to add this node (next or previous) + local koef = is_shift_left and -1 or 1 + self:_add_node(node, index, index - koef) + print("Add at", index) - self:_update_borders() - self:_update_pos() - self:_update_indexes() + -- Now we can setup poses + if self.last_index then + if not is_shift_left then + for i = index + 1, self.last_index + 1 do + local move_node = self.nodes[i] + move_node.pos = self:get_pos(i, move_node.node, i - 1) + end + else + for i = index - 1, self.first_index - 1, -1 do + local move_node = self.nodes[i] + move_node.pos = self:get_pos(i, move_node.node, i + 1) + print("Recalct", i) + end + end + end - self.on_add_item:trigger(self:get_context(), item, index) + + self:_update() + + self.on_add_item:trigger(self:get_context(), node, index) self.on_change_items:trigger(self:get_context(), index) end @@ -141,21 +156,20 @@ end --- Remove the item from the grid. Note that gui node will be not deleted -- @function dynamic_grid:remove -- @tparam number index The grid node index to remove --- @tparam bool is_shift_nodes If true, will shift nodes left after index -function DynamicGrid:remove(index, is_shift_nodes) +-- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right +function DynamicGrid:remove(index, is_shift_left) assert(self.nodes[index], "No grid item at given index " .. index) self.nodes[index] = nil - if is_shift_nodes then - for i = index, self.last_index do - self.nodes[i] = self.nodes[i + 1] + for i = index, self.last_index do + self.nodes[i] = self.nodes[i + 1] + if self.nodes[i] then + self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - 1) end end - self:_update_borders() - self:_update_pos() - self:_update_indexes() + self:_update() self.on_add_item:trigger(self:get_context(), index) self.on_change_items:trigger(self:get_context(), index) @@ -174,6 +188,21 @@ function DynamicGrid:get_size(border) end +--- Return grid index by node +-- @function dynamic_grid:get_index_by_node +-- @tparam node node The gui node in the grid +-- @treturn number The node index +function DynamicGrid:get_index_by_node(node) + for index, node_info in pairs(self.nodes) do + if node == node_info.node then + return index + end + end + + return nil +end + + function DynamicGrid:get_center_position() return vmath.vector3( (self.border.x + self.border.z)/2, @@ -182,6 +211,15 @@ function DynamicGrid:get_center_position() end +function DynamicGrid:get_zero_offset() + -- zero offset: center pos - border size * anchor + return vmath.vector3( + -((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x), + -((self.border.y + self.border.w)/2 + (self.border.y - self.border.w) * self.pivot.y), + 0) +end + + --- Return array of all node positions -- @function dynamic_grid:get_all_pos -- @treturn vector3[] All grid node positions @@ -209,8 +247,7 @@ end -- @function dynamic_grid:clear function DynamicGrid:clear() self.nodes = {} - self:_update_borders() - self:_update_indexes() + self:_update() end @@ -236,7 +273,12 @@ end function DynamicGrid:_update_borders() - local border = vmath.vector4(math.huge, -math.huge, -math.huge, math.huge) + if not self.first_index then + self.border = vmath.vector4(0) + return + end + + self.border = vmath.vector4(math.huge, -math.huge, -math.huge, math.huge) for index, node in pairs(self.nodes) do local pos = node.pos @@ -248,13 +290,11 @@ function DynamicGrid:_update_borders() local top = pos.y + size.y/2 - (size.y * pivot.y) local bottom = pos.y - size.y/2 - (size.y * pivot.y) - border.x = math.min(border.x, left) - border.y = math.max(border.y, top) - border.z = math.max(border.z, right) - border.w = math.min(border.w, bottom) + self.border.x = math.min(self.border.x, left) + self.border.y = math.max(self.border.y, top) + self.border.z = math.max(self.border.z, right) + self.border.w = math.min(self.border.w, bottom) end - - self.border = border end @@ -271,6 +311,13 @@ function DynamicGrid:_update_pos(is_instant) end +function DynamicGrid:_update(is_instant) + self:_update_indexes() + self:_update_borders() + self:_update_pos(is_instant) +end + + function DynamicGrid:_get_next_node_pos(origin_node_index, new_node, place_side) local node = self.nodes[origin_node_index] @@ -295,10 +342,10 @@ function DynamicGrid:_get_node_size(node) end -function DynamicGrid:_add_node(node, index) +function DynamicGrid:_add_node(node, index, origin_index) self.nodes[index] = { node = node, - pos = self:get_pos(index, node), + pos = self:get_pos(index, node, origin_index), size = self:_get_node_size(node), pivot = const.PIVOTS[gui.get_pivot(node)] } From ea0e7366d0c29cced7fe16ebad55098326e4dc9e Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 22:33:26 +0300 Subject: [PATCH 28/46] Refactor dynamic grid add --- druid/base/dynamic_grid.lua | 63 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 9b7b813..0fb60f7 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -105,47 +105,34 @@ end -- @tparam[opt] number index The node position. By default add as last node -- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right function DynamicGrid:add(node, index, is_shift_left) + local delta = is_shift_left and -1 or 1 + + -- By default add node at end index = index or ((self.last_index or 0) + 1) - print("if shift left", is_shift_left) - + -- If node exist at index place, shifting them if self.nodes[index] then - if not is_shift_left then - -- Move nodes to right - for i = self.last_index, index, -1 do - self.nodes[i + 1] = self.nodes[i] - end - else - -- Move nodes to left - for i = self.first_index, index do - self.nodes[i - 1] = self.nodes[i] - print("Move", i-1, i) - end + -- We need to iterate from index to start or end grid, depends of shift side + local start_index = is_shift_left and self.first_index or self.last_index + for i = start_index, index, -delta do + self.nodes[i + delta] = self.nodes[i] end end -- TODO: we must choose anchor node to add this node (next or previous) - local koef = is_shift_left and -1 or 1 - self:_add_node(node, index, index - koef) - print("Add at", index) + self:_add_node(node, index, index - delta) - -- Now we can setup poses + -- After shifting we should recalc node poses if self.last_index then - if not is_shift_left then - for i = index + 1, self.last_index + 1 do - local move_node = self.nodes[i] - move_node.pos = self:get_pos(i, move_node.node, i - 1) - end - else - for i = index - 1, self.first_index - 1, -1 do - local move_node = self.nodes[i] - move_node.pos = self:get_pos(i, move_node.node, i + 1) - print("Recalct", i) - end + -- We need to iterate from placed node to start or end grid, depends of shift side + local target_index = is_shift_left and self.first_index or self.last_index + for i = index + delta, target_index + delta, delta do + local move_node = self.nodes[i] + move_node.pos = self:get_pos(i, move_node.node, i - delta) end end - + -- Sync grid data self:_update() self.on_add_item:trigger(self:get_context(), node, index) @@ -162,10 +149,20 @@ function DynamicGrid:remove(index, is_shift_left) self.nodes[index] = nil - for i = index, self.last_index do - self.nodes[i] = self.nodes[i + 1] - if self.nodes[i] then - self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - 1) + -- Move other nodes closer to deleted index + if not is_shift_left then + for i = index, self.last_index do + self.nodes[i] = self.nodes[i + 1] + if self.nodes[i] then + self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - 1) + end + end + else + for i = index, self.first_index, -1 do + self.nodes[i] = self.nodes[i - 1] + if self.nodes[i] then + self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i + 1) + end end end From 954e4c0d6eb452005242b7f3df9653b051ba121d Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 22:33:37 +0300 Subject: [PATCH 29/46] Remove scroll node color (debug mode) --- example/gui/main/main.gui | 10 +++++----- example/page/grid_page.lua | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 0e7519a..58331c8 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10651,7 +10651,7 @@ nodes { } type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA - texture: "" + texture: "kenney/empty" id: "grid_dynamic_nodes" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -10809,14 +10809,14 @@ nodes { w: 1.0 } color { - x: 0.4 - y: 0.3019608 - z: 0.7019608 + x: 1.0 + y: 1.0 + z: 1.0 w: 1.0 } type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA - texture: "" + texture: "kenney/empty" id: "grid_dynamic_hor_nodes" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 74f4b7a..333d61a 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -85,6 +85,7 @@ local function remove_dynamic_node(self, button) if self.dynamic_node_buttons[i] == button then table.remove(self.dynamic_node_buttons, i) self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) + self.grid_dynamic_scroll:set_scroll_offset(self.dynamic_grid:get_zero_offset()) break end end @@ -132,7 +133,7 @@ local function init_dynamic_grid(self) add_node_dynamic(self, i) end self.druid:new_button("button_add_start_dynamic/button", function() - add_node_dynamic(self, 3, true) + add_node_dynamic(self, 1) end) self.druid:new_button("button_add_end_dynamic/button", function() add_node_dynamic(self) From a6963f1055bc69b3e8a02cd2c0de8f5ad74fc146 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 27 Sep 2020 23:19:35 +0300 Subject: [PATCH 30/46] Refactor dynamic_gri remove --- druid/base/dynamic_grid.lua | 48 ++++++++++++++++++++++++------------- example/page/grid_page.lua | 7 +++--- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 0fb60f7..5e24eeb 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -67,8 +67,21 @@ end function DynamicGrid:get_pos(index, node, origin_index) local origin_node = self.nodes[origin_index] + -- If anchor node is not exist, check around nodes if not origin_node then - -- TODO: assert no elements in grid now + if self.nodes[index + 1] then + origin_index = index + 1 + end + if self.nodes[index - 1] then + origin_index = index - 1 + end + origin_node = self.nodes[origin_index] + end + + if not origin_node then + assert(not self.first_index, "Dynamic Grid can't have gaps between nodes. Error on grid:add") + + -- If not origin node, so it should be first element in the grid local size = self:_get_node_size(node) local pivot = const.PIVOTS[gui.get_pivot(node)] return vmath.vector3( @@ -78,6 +91,7 @@ function DynamicGrid:get_pos(index, node, origin_index) end if origin_node then + -- Other nodes spawn from other side of the origin node local is_forward = origin_index < index local delta = is_forward and 1 or -1 return self:_get_next_node_pos(index - delta, node, self:_get_side_vector(self.side, is_forward)) @@ -111,23 +125,27 @@ function DynamicGrid:add(node, index, is_shift_left) index = index or ((self.last_index or 0) + 1) -- If node exist at index place, shifting them - if self.nodes[index] then + local is_shift = self.nodes[index] + if is_shift then -- We need to iterate from index to start or end grid, depends of shift side local start_index = is_shift_left and self.first_index or self.last_index for i = start_index, index, -delta do self.nodes[i + delta] = self.nodes[i] + print("move", i + delta, i) end end -- TODO: we must choose anchor node to add this node (next or previous) self:_add_node(node, index, index - delta) + print("Add", index, "From", index - delta) -- After shifting we should recalc node poses - if self.last_index then + if is_shift then -- We need to iterate from placed node to start or end grid, depends of shift side local target_index = is_shift_left and self.first_index or self.last_index for i = index + delta, target_index + delta, delta do local move_node = self.nodes[i] + print("Recalc", i, i - delta) move_node.pos = self:get_pos(i, move_node.node, i - delta) end end @@ -145,27 +163,23 @@ end -- @tparam number index The grid node index to remove -- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right function DynamicGrid:remove(index, is_shift_left) + local delta = is_shift_left and -1 or 1 + assert(self.nodes[index], "No grid item at given index " .. index) + -- Just set nil for delete node data self.nodes[index] = nil - -- Move other nodes closer to deleted index - if not is_shift_left then - for i = index, self.last_index do - self.nodes[i] = self.nodes[i + 1] - if self.nodes[i] then - self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - 1) - end - end - else - for i = index, self.first_index, -1 do - self.nodes[i] = self.nodes[i - 1] - if self.nodes[i] then - self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i + 1) - end + -- After delete node, we should shift nodes and recalc their poses, depends from is_shift_left + local target_index = is_shift_left and self.first_index or self.last_index + for i = index, target_index, delta do + self.nodes[i] = self.nodes[i + delta] + if self.nodes[i] then + self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - delta) end end + -- Sync grid data self:_update() self.on_add_item:trigger(self:get_context(), index) diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 333d61a..ad477a7 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -80,7 +80,7 @@ local function remove_dynamic_node(self, button) self.druid:remove(button) local index = self.dynamic_grid:get_index_by_node(button.node) - self.dynamic_grid:remove(index, true) + self.dynamic_grid:remove(index) for i = 1, #self.dynamic_node_buttons do if self.dynamic_node_buttons[i] == button then table.remove(self.dynamic_node_buttons, i) @@ -99,7 +99,7 @@ local function add_node_dynamic(self, index, is_shift_left) self.dynamic_grid:add(node, index, is_shift_left) local button = self.druid:new_button(node, function(_, params, button) - remove_dynamic_node(self, button, true) + remove_dynamic_node(self, button) end) button:set_click_zone(self.grid_dynamic_scroll.view_node) self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) @@ -133,7 +133,8 @@ local function init_dynamic_grid(self) add_node_dynamic(self, i) end self.druid:new_button("button_add_start_dynamic/button", function() - add_node_dynamic(self, 1) + local start_index = (self.dynamic_grid.first_index or 2) - 1 + add_node_dynamic(self, start_index) end) self.druid:new_button("button_add_end_dynamic/button", function() add_node_dynamic(self) From caeb3bbf2fc8594930cd3ee0c0958e146bb0f99e Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 01:35:44 +0300 Subject: [PATCH 31/46] Add offset to grid components to center nodes --- druid/base/dynamic_grid.lua | 13 ++-- druid/base/static_grid.lua | 119 +++++++++++++++++------------------- example/page/grid_page.lua | 3 - 3 files changed, 62 insertions(+), 73 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 5e24eeb..4f3f831 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -131,13 +131,10 @@ function DynamicGrid:add(node, index, is_shift_left) local start_index = is_shift_left and self.first_index or self.last_index for i = start_index, index, -delta do self.nodes[i + delta] = self.nodes[i] - print("move", i + delta, i) end end - -- TODO: we must choose anchor node to add this node (next or previous) self:_add_node(node, index, index - delta) - print("Add", index, "From", index - delta) -- After shifting we should recalc node poses if is_shift then @@ -145,11 +142,11 @@ function DynamicGrid:add(node, index, is_shift_left) local target_index = is_shift_left and self.first_index or self.last_index for i = index + delta, target_index + delta, delta do local move_node = self.nodes[i] - print("Recalc", i, i - delta) move_node.pos = self:get_pos(i, move_node.node, i - delta) end end + -- Sync grid data self:_update() @@ -310,11 +307,13 @@ end function DynamicGrid:_update_pos(is_instant) + local offset = self:get_zero_offset() + for index, node in pairs(self.nodes) do if is_instant then - gui.set_position(node.node, node.pos) + gui.set_position(node.node, node.pos + offset) else - self._set_position_function(node.node, node.pos) + self._set_position_function(node.node, node.pos + offset) end end @@ -363,7 +362,7 @@ function DynamicGrid:_add_node(node, index, origin_index) -- Add new item instantly in new pos gui.set_parent(node, self.parent) - gui.set_position(node, self.nodes[index].pos) + gui.set_position(node, self.nodes[index].pos + self:get_zero_offset()) end diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 095dc49..a4b663d 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -41,8 +41,8 @@ function StaticGrid:init(parent, element, in_row) self.offset = vmath.vector3(0) - local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) - self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) + self.pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) + self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) self.in_row = in_row or 1 @@ -51,7 +51,6 @@ function StaticGrid:init(parent, element, in_row) self.node_pivot = const.PIVOTS[gui.get_pivot(self._prefab)] self.border = vmath.vector4(0) -- Current grid content size - self.border_offset = vmath.vector3(0) -- Content offset for match the grid anchoring self.on_add_item = Event() self.on_remove_item = Event() @@ -72,8 +71,8 @@ function StaticGrid:get_pos(index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 - _temp_pos.x = col * (self.node_size.x + self.offset.x) - self.border_offset.x - _temp_pos.y = -row * (self.node_size.y + self.offset.y) - self.border_offset.y + _temp_pos.x = col * (self.node_size.x + self.offset.x) + _temp_pos.y = -row * (self.node_size.y + self.offset.y) _temp_pos.z = 0 return _temp_pos @@ -85,8 +84,8 @@ end -- @tparam vector3 pos The node position in the grid -- @treturn number The node index function StaticGrid:get_index(pos) - local col = (pos.x + self.border_offset.x) / (self.node_size.x + self.offset.x) + 1 - local row = -(pos.y + self.border_offset.y) / (self.node_size.y + self.offset.y) + local col = pos.x / (self.node_size.x + self.offset.x) + 1 + local row = -pos.y / (self.node_size.y + self.offset.y) col = helper.round(col) row = helper.round(row) @@ -112,7 +111,7 @@ end function StaticGrid:on_layout_change() - self:_update_pos(true) + self:_update(true) end @@ -121,7 +120,7 @@ end -- @tparam vector3 offset Offset function StaticGrid:set_offset(offset) self.offset = offset - self:_update_pos() + self:_update() end @@ -130,7 +129,7 @@ end -- @tparam vector3 anchor Anchor function StaticGrid:set_anchor(anchor) self.anchor = anchor - self:_update_pos() + self:_update() end @@ -156,12 +155,7 @@ function StaticGrid:add(item, index) -- Add new item instantly in new pos gui.set_position(item, pos) - for i, _ in pairs(self.nodes) do - self:_update_border_offset(self:get_pos(i)) - end - - self:_update_pos() - self:_update_indexes() + self:_update() self.on_add_item:trigger(self:get_context(), item, index) self.on_change_items:trigger(self:get_context(), index) @@ -185,13 +179,8 @@ function StaticGrid:remove(index, is_shift_nodes) -- Recalculate borders self.border = vmath.vector4(0) - self:_update_border_offset(self:get_pos(1)) - for i, _ in pairs(self.nodes) do - self:_update_border_offset(self:get_pos(i)) - end - self:_update_pos() - self:_update_indexes() + self:_update() self.on_add_item:trigger(self:get_context(), index) self.on_change_items:trigger(self:get_context(), index) @@ -210,21 +199,6 @@ function StaticGrid:get_size(border) end ---- Return grid size for amount of nodes in this grid --- @function static_grid:get_size_for_elements_count --- @tparam number count The grid content node amount --- @treturn vector3 The grid content size -function StaticGrid:get_size_for_elements_count(count) - local border = vmath.vector4(0) - for i = 1, count do - local pos = self:get_pos(i) - self:_update_border(pos, border) - end - - return self:get_size(border) -end - - --- Return array of all node positions -- @function static_grid:get_all_pos -- @treturn vector3[] All grid node positions @@ -256,10 +230,18 @@ function StaticGrid:clear() self.border.w = 0 self.border.z = 0 - self:_update_border_offset(self:get_pos(1)) - self.nodes = {} - self:_update_indexes() + self:_update() +end + + +function StaticGrid:get_zero_offset() + -- zero offset: center pos - border size * anchor + return vmath.vector3( + -((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x), + -((self.border.y + self.border.w)/2 + (self.border.y - self.border.w) * self.pivot.y), + 0 + ) end @@ -271,6 +253,13 @@ function StaticGrid:get_nodes() end +function StaticGrid:_update(is_instant) + self:_update_indexes() + self:_update_borders() + self:_update_pos(is_instant) +end + + function StaticGrid:_update_indexes() self.first_index = nil self.last_index = nil @@ -284,40 +273,44 @@ function StaticGrid:_update_indexes() end -function StaticGrid:_update_border(pos, border) +function StaticGrid:_update_borders() + if not self.first_index then + self.border = vmath.vector4(0) + return + end + + self.border = vmath.vector4(math.huge, -math.huge, -math.huge, math.huge) + local size = self.node_size local pivot = self.node_pivot + for index, node in pairs(self.nodes) do + local pos = self:get_pos(index) - local left = pos.x - size.x/2 - (size.x * pivot.x) + self.border_offset.x - local right = pos.x + size.x/2 - (size.x * pivot.x) + self.border_offset.x - local top = pos.y + size.y/2 - (size.y * pivot.y) + self.border_offset.y - local bottom = pos.y - size.y/2 - (size.y * pivot.y) + self.border_offset.y + local left = pos.x - size.x/2 - (size.x * pivot.x) + local right = pos.x + size.x/2 - (size.x * pivot.x) + local top = pos.y + size.y/2 - (size.y * pivot.y) + local bottom = pos.y - size.y/2 - (size.y * pivot.y) - border.x = math.min(border.x, left) - border.y = math.max(border.y, top) - border.z = math.max(border.z, right) - border.w = math.min(border.w, bottom) -end - - -function StaticGrid:_update_border_offset(pos) - local border = self.border - self:_update_border(pos, border) - - self.border_offset = vmath.vector3( - (border.x + (border.z - border.x) * self.anchor.x), - (border.y + (border.w - border.y) * self.anchor.y), - 0 - ) + self.border.x = math.min(self.border.x, left) + self.border.y = math.max(self.border.y, top) + self.border.z = math.max(self.border.z, right) + self.border.w = math.min(self.border.w, bottom) + end end function StaticGrid:_update_pos(is_instant) + local zero_offset = self:get_zero_offset() + for i, node in pairs(self.nodes) do + local pos = self:get_pos(i) + pos.x = pos.x + zero_offset.x + pos.y = pos.y + zero_offset.y + if is_instant then - gui.set_position(node, self:get_pos(i)) + gui.set_position(node, pos) else - self._set_position_function(node, self:get_pos(i)) + self._set_position_function(node, pos) end end diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index ad477a7..cd7c16d 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -85,7 +85,6 @@ local function remove_dynamic_node(self, button) if self.dynamic_node_buttons[i] == button then table.remove(self.dynamic_node_buttons, i) self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) - self.grid_dynamic_scroll:set_scroll_offset(self.dynamic_grid:get_zero_offset()) break end end @@ -103,7 +102,6 @@ local function add_node_dynamic(self, index, is_shift_left) end) button:set_click_zone(self.grid_dynamic_scroll.view_node) self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) - self.grid_dynamic_scroll:set_scroll_offset(self.dynamic_grid:get_zero_offset()) table.insert(self.dynamic_node_buttons, button) end @@ -114,7 +112,6 @@ local function add_node_dynamic_hor(self, index) gui.set_size(node, vmath.vector3(80 + math.random(0, 80), 80, 0)) self.dynamic_hor_grid:add(node, index) self.grid_dynamic_hor_scroll:set_size(self.dynamic_hor_grid:get_size()) - self.grid_dynamic_hor_scroll:set_scroll_offset(self.dynamic_hor_grid:get_zero_offset()) end From 40af3f6181be3012efd0f997865e2d03ef1789bb Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 01:36:14 +0300 Subject: [PATCH 32/46] Remove scroll offset --- druid/base/scroll.lua | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index e898f0c..36c8159 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -103,7 +103,6 @@ function Scroll:init(view_node, content_node) self.view_node = self:get_node(view_node) self.content_node = self:get_node(content_node) - self.scroll_offset = vmath.vector3(0) self.position = gui.get_position(self.content_node) self.target_position = vmath.vector3(self.position) @@ -237,19 +236,6 @@ function Scroll:set_size(size) end ---- Set scroll content size by borders --- It will change content gui node sizes --- @function scroll:set_border --- @tparam vector4 border The new scroll borders for content node --- @treturn druid.Scroll Current scroll instance -function Scroll:set_scroll_offset(offset) - self.scroll_offset = offset - self:_update_size() - - return self -end - - --- Enable or disable scroll inert. -- If disabled, scroll through points (if exist) -- If no points, just simple drag without inertion @@ -552,10 +538,10 @@ function Scroll:_update_size() self.available_pos = get_border_vector(view_border - content_border) self.available_size = get_size_vector(self.available_pos) - self.available_pos.x = self.available_pos.x + self.scroll_offset.x - self.available_pos.z = self.available_pos.z + self.scroll_offset.x - self.available_pos.y = self.available_pos.y + self.scroll_offset.y - self.available_pos.w = self.available_pos.w + self.scroll_offset.y + self.available_pos.x = self.available_pos.x + self.available_pos.z = self.available_pos.z + self.available_pos.y = self.available_pos.y + self.available_pos.w = self.available_pos.w self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll self.drag.can_y = self.available_size.y > 0 and self._is_vertical_scroll @@ -585,10 +571,10 @@ function Scroll:_update_size() self.available_pos_extra = get_border_vector(view_border - content_border_extra) self.available_size_extra = get_size_vector(self.available_pos_extra) - self.available_pos_extra.x = self.available_pos_extra.x + self.scroll_offset.x - self.available_pos_extra.z = self.available_pos_extra.z + self.scroll_offset.x - self.available_pos_extra.y = self.available_pos_extra.y + self.scroll_offset.y - self.available_pos_extra.w = self.available_pos_extra.w + self.scroll_offset.y + self.available_pos_extra.x = self.available_pos_extra.x + self.available_pos_extra.z = self.available_pos_extra.z + self.available_pos_extra.y = self.available_pos_extra.y + self.available_pos_extra.w = self.available_pos_extra.w end From c0bd3e599ba56cd6f70f2ba411179278c9c60169 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 01:42:49 +0300 Subject: [PATCH 33/46] Add correct static grid node spawn --- druid/base/static_grid.lua | 10 ++++++---- example/page/grid_page.lua | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index a4b663d..c2be36f 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -151,11 +151,13 @@ function StaticGrid:add(item, index) gui.set_parent(item, self.parent) - local pos = self:get_pos(index) - -- Add new item instantly in new pos - gui.set_position(item, pos) + -- Add new item instantly in new pos. Break update function for correct positioning + self:_update_indexes() + self:_update_borders() - self:_update() + gui.set_position(item, self:get_pos(index) + self:get_zero_offset()) + + self:_update_pos() self.on_add_item:trigger(self:get_context(), item, index) self.on_change_items:trigger(self:get_context(), index) diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index cd7c16d..35a8509 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -67,7 +67,9 @@ local function init_static_grid(self) add_node(self, i) end - self.druid:new_button("button_add/button", add_node) + self.druid:new_button("button_add/button", function() + add_node(self) + end) self.druid:new_button("button_clear/button", clear_nodes) local remove_button = self.druid:new_button("button_remove/button", remove_node) From 0b1051b5b2d1d2527fafbafe339b6c4e4089d842 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 01:56:43 +0300 Subject: [PATCH 34/46] Add scroll:bind_grid function --- druid/base/dynamic_grid.lua | 4 +++ druid/base/scroll.lua | 30 +++++++++++++++++++++ druid/base/static_grid.lua | 6 +++++ druid/event.lua | 2 ++ example/page/grid_page.lua | 53 +++++++++++++++++-------------------- 5 files changed, 67 insertions(+), 28 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 4f3f831..c0e4302 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -245,17 +245,21 @@ end -- update poses on grid elements. Default: gui.set_position -- @function dynamic_grid:set_position_function -- @tparam function callback Function on node set position +-- @treturn druid.dynamic_grid Current grid instance function DynamicGrid:set_position_function(callback) self._set_position_function = callback or gui.set_position + return self end --- Clear grid nodes array. GUI nodes will be not deleted! -- If you want to delete GUI nodes, use dynamic_grid.nodes array before grid:clear -- @function dynamic_grid:clear +-- @treturn druid.dynamic_grid Current grid instance function DynamicGrid:clear() self.nodes = {} self:_update() + return self end diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 36c8159..2c7c9c2 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -118,8 +118,11 @@ function Scroll:init(view_node, content_node) self.selected = nil self.is_animate = false + self._is_horizontal_scroll = true self._is_vertical_scroll = true + self._grid_on_change = nil + self._grid_on_change_callback = nil self:_update_size() end @@ -139,6 +142,11 @@ function Scroll:update(dt) end +function Scroll:on_remove() + self:bind_grid(nil) +end + + --- Start scroll to target point. -- @function scroll:scroll_to -- @tparam point vector3 Target point @@ -318,6 +326,28 @@ function Scroll:set_vertical_scroll(state) end + +function Scroll:bind_grid(grid) + if self._grid_on_change then + self._grid_on_change:unsubscribe(self._grid_on_change_callback) + + self._grid_on_change = nil + self._grid_on_change_callback = nil + end + + if not grid then + return + end + + self._grid_on_change = grid.on_change_items + self._grid_on_change_callback = self._grid_on_change:subscribe(function() + self:set_size(grid:get_size()) + end) + + return self +end + + function Scroll:_on_scroll_drag(dx, dy) local t = self.target_position local b = self.available_pos diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index c2be36f..4982ac1 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -218,14 +218,18 @@ end -- update poses on grid elements. Default: gui.set_position -- @function static_grid:set_position_function -- @tparam function callback Function on node set position +-- @treturn druid.static_grid Current grid instance function StaticGrid:set_position_function(callback) self._set_position_function = callback or gui.set_position + + return self end --- Clear grid nodes array. GUI nodes will be not deleted! -- If you want to delete GUI nodes, use static_grid.nodes array before grid:clear -- @function static_grid:clear +-- @treturn druid.static_grid Current grid instance function StaticGrid:clear() self.border.x = 0 self.border.y = 0 @@ -234,6 +238,8 @@ function StaticGrid:clear() self.nodes = {} self:_update() + + return self end diff --git a/druid/event.lua b/druid/event.lua index b4bc110..a31d6cc 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -27,6 +27,8 @@ function M.subscribe(self, callback) assert(type(callback) == "function", "Callback should be function") table.insert(self._callbacks, callback) + + return callback end diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 35a8509..2d91c48 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -3,16 +3,20 @@ local druid_const = require("druid.const") local M = {} +local function simple_animate(node, pos) + gui.animate(node, "position", pos, gui.EASING_OUTSINE, 0.2) +end + + local function remove_node(self, button, is_shift) gui.delete_node(button.node) self.druid:remove(button) - local index = self.grid_nodes:get_index_by_node(button.node) - self.grid_nodes:remove(index, is_shift) + local index = self.grid_static_grid:get_index_by_node(button.node) + self.grid_static_grid:remove(index, is_shift) for i = 1, #self.grid_node_buttons do if self.grid_node_buttons[i] == button then table.remove(self.grid_node_buttons, i) - self.grid_static_scroll:set_size(self.grid_nodes:get_size()) break end end @@ -34,9 +38,7 @@ local function add_node(self, index) table.insert(self.grid_node_buttons, button) - self.grid_nodes:add(cloned["grid_nodes_prefab"], index) - - self.grid_static_scroll:set_size(self.grid_nodes:get_size()) + self.grid_static_grid:add(cloned["grid_nodes_prefab"], index) end @@ -51,15 +53,11 @@ local function clear_nodes(self) end self.grid_node_buttons = {} - self.grid_nodes:clear() + self.grid_static_grid:clear() end local function init_static_grid(self) - self.grid_nodes = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5) - self.grid_nodes:set_position_function(function(node, pos) - gui.animate(node, "position", pos, gui.EASING_OUTSINE, 0.2) - end) self.grid_node_buttons = {} gui.set_enabled(gui.get_node("grid_nodes_prefab"), false) @@ -81,12 +79,11 @@ local function remove_dynamic_node(self, button) gui.delete_node(button.node) self.druid:remove(button) - local index = self.dynamic_grid:get_index_by_node(button.node) - self.dynamic_grid:remove(index) + local index = self.grid_dynamic_grid:get_index_by_node(button.node) + self.grid_dynamic_grid:remove(index) for i = 1, #self.dynamic_node_buttons do if self.dynamic_node_buttons[i] == button then table.remove(self.dynamic_node_buttons, i) - self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) break end end @@ -97,13 +94,12 @@ local function add_node_dynamic(self, index, is_shift_left) local node = gui.clone(self.prefab_dynamic) gui.set_enabled(node, true) gui.set_size(node, vmath.vector3(250, math.random(60, 150), 0)) - self.dynamic_grid:add(node, index, is_shift_left) + self.grid_dynamic_grid:add(node, index, is_shift_left) local button = self.druid:new_button(node, function(_, params, button) remove_dynamic_node(self, button) end) button:set_click_zone(self.grid_dynamic_scroll.view_node) - self.grid_dynamic_scroll:set_size(self.dynamic_grid:get_size()) table.insert(self.dynamic_node_buttons, button) end @@ -112,18 +108,13 @@ local function add_node_dynamic_hor(self, index) local node = gui.clone(self.prefab_hor_dynamic) gui.set_enabled(node, true) gui.set_size(node, vmath.vector3(80 + math.random(0, 80), 80, 0)) - self.dynamic_hor_grid:add(node, index) - self.grid_dynamic_hor_scroll:set_size(self.dynamic_hor_grid:get_size()) + self.grid_dynamic_hor_grid:add(node, index) end local function init_dynamic_grid(self) -- Vertical horizontal grid self.dynamic_node_buttons = {} - self.dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes") - self.dynamic_grid:set_position_function(function(node, pos) - gui.animate(node, gui.PROP_POSITION, pos, gui.EASING_OUTSINE, 0.2) - end) self.prefab_dynamic = gui.get_node("grid_dynamic_prefab") gui.set_enabled(self.prefab_dynamic, false) @@ -132,19 +123,14 @@ local function init_dynamic_grid(self) add_node_dynamic(self, i) end self.druid:new_button("button_add_start_dynamic/button", function() - local start_index = (self.dynamic_grid.first_index or 2) - 1 + local start_index = (self.grid_dynamic_grid.first_index or 2) - 1 add_node_dynamic(self, start_index) end) self.druid:new_button("button_add_end_dynamic/button", function() add_node_dynamic(self) end) - -- Horizontal dynamic grid - self.dynamic_hor_grid = self.druid:new_dynamic_grid("grid_dynamic_hor_nodes") - self.dynamic_hor_grid:set_position_function(function(node, pos) - gui.animate(node, gui.PROP_POSITION, pos, gui.EASING_OUTSINE, 0.2) - end) self.prefab_hor_dynamic = gui.get_node("grid_dynamic_hor_prefab") gui.set_enabled(self.prefab_hor_dynamic, false) @@ -164,12 +150,23 @@ end function M.setup_page(self) self.grid_page_scroll = self.druid:new_scroll("grid_page", "grid_page_content") + self.grid_static_grid = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5) + :set_position_function(simple_animate) self.grid_static_scroll = self.druid:new_scroll("grid_nodes_view", "grid_nodes") :set_horizontal_scroll(false) + :bind_grid(self.grid_static_grid) + + self.grid_dynamic_grid = self.druid:new_dynamic_grid("grid_dynamic_nodes") + :set_position_function(simple_animate) self.grid_dynamic_scroll = self.druid:new_scroll("grid_dynamic_view", "grid_dynamic_nodes") :set_horizontal_scroll(false) + :bind_grid(self.grid_dynamic_grid) + + self.grid_dynamic_hor_grid = self.druid:new_dynamic_grid("grid_dynamic_hor_nodes") + :set_position_function(simple_animate) self.grid_dynamic_hor_scroll = self.druid:new_scroll("grid_dynamic_hor_view", "grid_dynamic_hor_nodes") :set_vertical_scroll(false) + :bind_grid(self.grid_dynamic_hor_grid) init_static_grid(self) init_dynamic_grid(self) From 246574c86b7dba91ab6d7c41dca189843d0c6615 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 02:21:44 +0300 Subject: [PATCH 35/46] Update grid and scroll documentation --- druid/base/dynamic_grid.lua | 94 ++++++++++++++++++------------------- druid/base/scroll.lua | 14 +++--- druid/base/static_grid.lua | 28 ++++++----- example/page/grid_page.lua | 2 - 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index c0e4302..6e6348f 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -33,20 +33,20 @@ local SIDE_VECTORS = { BOT = vmath.vector3(0, 1, 0), } + --- Component init function -- @function dynamic_grid:init -- @tparam node parent The gui node parent, where items will be placed function DynamicGrid:init(parent, side) self.parent = self:get_node(parent) - local parent_pivot = gui.get_pivot(self.parent) + local parent_pivot = gui.get_pivot(self.parent) self.pivot = helper.get_pivot_offset(parent_pivot) assert(parent_pivot == gui.PIVOT_W or parent_pivot == gui.PIVOT_N, const.ERRORS.GRID_DYNAMIC_ANCHOR) self.side = (parent_pivot == gui.PIVOT_W and const.SIDE.X or const.SIDE.Y) self.nodes = {} - self.offset = vmath.vector3(0) self.border = vmath.vector4(0) -- Current grid content size self.on_add_item = Event() @@ -59,6 +59,11 @@ function DynamicGrid:init(parent, side) end +function DynamicGrid:on_layout_change() + self:_update(true) +end + + --- Return pos for grid node index -- @function dynamic_grid:get_pos -- @tparam number index The grid element index @@ -99,11 +104,6 @@ function DynamicGrid:get_pos(index, node, origin_index) end -function DynamicGrid:on_layout_change() - self:_update(true) -end - - --- Set grid items offset, the distance between items -- @function dynamic_grid:set_offset -- @tparam vector3 offset Offset @@ -211,23 +211,6 @@ function DynamicGrid:get_index_by_node(node) end -function DynamicGrid:get_center_position() - return vmath.vector3( - (self.border.x + self.border.z)/2, - (self.border.y + self.border.w)/2, - 0) -end - - -function DynamicGrid:get_zero_offset() - -- zero offset: center pos - border size * anchor - return vmath.vector3( - -((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x), - -((self.border.y + self.border.w)/2 + (self.border.y - self.border.w) * self.pivot.y), - 0) -end - - --- Return array of all node positions -- @function dynamic_grid:get_all_pos -- @treturn vector3[] All grid node positions @@ -263,14 +246,34 @@ function DynamicGrid:clear() end ---- Return the grid nodes table --- @function dynamic_grid:get_nodes --- @treturn table The grid nodes -function DynamicGrid:get_nodes() - return self.nodes +function DynamicGrid:_add_node(node, index, origin_index) + self.nodes[index] = { + node = node, + pos = self:get_pos(index, node, origin_index), + size = self:_get_node_size(node), + pivot = const.PIVOTS[gui.get_pivot(node)] + } + + -- Add new item instantly in new pos + gui.set_parent(node, self.parent) + gui.set_position(node, self.nodes[index].pos + self:_get_zero_offset()) end +--- Update grid inner state +-- @function dynamic_grid:_update +-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback +-- @local +function DynamicGrid:_update(is_instant) + self:_update_indexes() + self:_update_borders() + self:_update_pos(is_instant) +end + + +--- Update first and last indexes of grid nodes +-- @function dynamic_grid:_update_indexes +-- @local function DynamicGrid:_update_indexes() self.first_index = nil self.last_index = nil @@ -284,6 +287,9 @@ function DynamicGrid:_update_indexes() end +--- Update grid content borders, recalculate min and max values +-- @function dynamic_grid:_update_borders +-- @local function DynamicGrid:_update_borders() if not self.first_index then self.border = vmath.vector4(0) @@ -310,8 +316,12 @@ function DynamicGrid:_update_borders() end +--- Update grid nodes position +-- @function dynamic_grid:_update_indexes +-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback +-- @local function DynamicGrid:_update_pos(is_instant) - local offset = self:get_zero_offset() + local offset = self:_get_zero_offset() for index, node in pairs(self.nodes) do if is_instant then @@ -325,13 +335,6 @@ function DynamicGrid:_update_pos(is_instant) end -function DynamicGrid:_update(is_instant) - self:_update_indexes() - self:_update_borders() - self:_update_pos(is_instant) -end - - function DynamicGrid:_get_next_node_pos(origin_node_index, new_node, place_side) local node = self.nodes[origin_node_index] @@ -356,17 +359,12 @@ function DynamicGrid:_get_node_size(node) end -function DynamicGrid:_add_node(node, index, origin_index) - self.nodes[index] = { - node = node, - pos = self:get_pos(index, node, origin_index), - size = self:_get_node_size(node), - pivot = const.PIVOTS[gui.get_pivot(node)] - } - - -- Add new item instantly in new pos - gui.set_parent(node, self.parent) - gui.set_position(node, self.nodes[index].pos + self:get_zero_offset()) +function DynamicGrid:_get_zero_offset() + -- zero offset: center pos - border size * anchor + return vmath.vector3( + -((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x), + -((self.border.y + self.border.w)/2 + (self.border.y - self.border.w) * self.pivot.y), + 0) end diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 2c7c9c2..6a324ba 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -327,6 +327,11 @@ end +--- Bind the grid component (Static or Dynamic) to recalc +-- scroll size on grid changes +-- @function scroll:bind_grid +-- @tparam druid.static_grid|druid.dynamic_grid Druid grid component +-- @treturn druid.scroll Current scroll instance function Scroll:bind_grid(grid) if self._grid_on_change then self._grid_on_change:unsubscribe(self._grid_on_change_callback) @@ -343,6 +348,7 @@ function Scroll:bind_grid(grid) self._grid_on_change_callback = self._grid_on_change:subscribe(function() self:set_size(grid:get_size()) end) + self:set_size(grid:get_size()) return self end @@ -568,10 +574,6 @@ function Scroll:_update_size() self.available_pos = get_border_vector(view_border - content_border) self.available_size = get_size_vector(self.available_pos) - self.available_pos.x = self.available_pos.x - self.available_pos.z = self.available_pos.z - self.available_pos.y = self.available_pos.y - self.available_pos.w = self.available_pos.w self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll self.drag.can_y = self.available_size.y > 0 and self._is_vertical_scroll @@ -601,10 +603,6 @@ function Scroll:_update_size() self.available_pos_extra = get_border_vector(view_border - content_border_extra) self.available_size_extra = get_size_vector(self.available_pos_extra) - self.available_pos_extra.x = self.available_pos_extra.x - self.available_pos_extra.z = self.available_pos_extra.z - self.available_pos_extra.y = self.available_pos_extra.y - self.available_pos_extra.w = self.available_pos_extra.w end diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 4982ac1..8a39f80 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -155,7 +155,7 @@ function StaticGrid:add(item, index) self:_update_indexes() self:_update_borders() - gui.set_position(item, self:get_pos(index) + self:get_zero_offset()) + gui.set_position(item, self:get_pos(index) + self:_get_zero_offset()) self:_update_pos() @@ -243,7 +243,7 @@ function StaticGrid:clear() end -function StaticGrid:get_zero_offset() +function StaticGrid:_get_zero_offset() -- zero offset: center pos - border size * anchor return vmath.vector3( -((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x), @@ -253,14 +253,10 @@ function StaticGrid:get_zero_offset() end ---- Return the grid nodes table --- @function static_grid:get_nodes --- @treturn table The grid nodes -function StaticGrid:get_nodes() - return self.nodes -end - - +--- Update grid inner state +-- @function static_grid:_update +-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback +-- @local function StaticGrid:_update(is_instant) self:_update_indexes() self:_update_borders() @@ -268,6 +264,9 @@ function StaticGrid:_update(is_instant) end +--- Update first and last indexes of grid nodes +-- @function static_grid:_update_indexes +-- @local function StaticGrid:_update_indexes() self.first_index = nil self.last_index = nil @@ -281,6 +280,9 @@ function StaticGrid:_update_indexes() end +--- Update grid content borders, recalculate min and max values +-- @function static_grid:_update_borders +-- @local function StaticGrid:_update_borders() if not self.first_index then self.border = vmath.vector4(0) @@ -307,8 +309,12 @@ function StaticGrid:_update_borders() end +--- Update grid nodes position +-- @function static_grid:_update_indexes +-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback +-- @local function StaticGrid:_update_pos(is_instant) - local zero_offset = self:get_zero_offset() + local zero_offset = self:_get_zero_offset() for i, node in pairs(self.nodes) do local pos = self:get_pos(i) diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 2d91c48..e2aff6d 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -1,5 +1,3 @@ -local druid_const = require("druid.const") - local M = {} From c4589857db2ebb78ed7239c1ed7cc6592adca6d5 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 02:23:10 +0300 Subject: [PATCH 36/46] Remove set_offset grid functions --- druid/base/dynamic_grid.lua | 10 ---------- druid/base/static_grid.lua | 21 ++++----------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 6e6348f..4d05a56 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -15,7 +15,6 @@ -- @tfield node[] nodes List of all grid nodes -- @tfield number first_index The first index of node in grid -- @tfield number last_index The last index of node in grid --- @tfield vector3 offset Item distance between each other items -- @tfield vector3 node_size Item size -- @tfield vector4 border The size of item content @@ -104,15 +103,6 @@ function DynamicGrid:get_pos(index, node, origin_index) end ---- Set grid items offset, the distance between items --- @function dynamic_grid:set_offset --- @tparam vector3 offset Offset -function DynamicGrid:set_offset(offset) - self.offset = offset - self:_update() -end - - --- Add new node to the grid -- @function dynamic_grid:add -- @tparam node node Gui node diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 8a39f80..d6d56c2 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -16,11 +16,9 @@ -- @tfield node[] nodes List of all grid nodes -- @tfield number first_index The first index of node in grid -- @tfield number last_index The last index of node in grid --- @tfield vector3 offset Item distance between each other items -- @tfield vector3 anchor Item anchor -- @tfield vector3 node_size Item size -- @tfield vector4 border The size of item content --- @tfield vector3 border_offer The border offset for correct anchor calculations local const = require("druid.const") local Event = require("druid.event") @@ -39,8 +37,6 @@ function StaticGrid:init(parent, element, in_row) self.parent = self:get_node(parent) self.nodes = {} - self.offset = vmath.vector3(0) - self.pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) @@ -71,8 +67,8 @@ function StaticGrid:get_pos(index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 - _temp_pos.x = col * (self.node_size.x + self.offset.x) - _temp_pos.y = -row * (self.node_size.y + self.offset.y) + _temp_pos.x = col * self.node_size.x + _temp_pos.y = -row * self.node_size.y _temp_pos.z = 0 return _temp_pos @@ -84,8 +80,8 @@ end -- @tparam vector3 pos The node position in the grid -- @treturn number The node index function StaticGrid:get_index(pos) - local col = pos.x / (self.node_size.x + self.offset.x) + 1 - local row = -pos.y / (self.node_size.y + self.offset.y) + local col = pos.x / self.node_size.x + 1 + local row = -pos.y / self.node_size.y col = helper.round(col) row = helper.round(row) @@ -115,15 +111,6 @@ function StaticGrid:on_layout_change() end ---- Set grid items offset, the distance between items --- @function static_grid:set_offset --- @tparam vector3 offset Offset -function StaticGrid:set_offset(offset) - self.offset = offset - self:_update() -end - - --- Set grid anchor. Default anchor is equal to anchor of grid parent node -- @function static_grid:set_anchor -- @tparam vector3 anchor Anchor From 1c292f44b768b9da69d50ed61a11270948aa969c Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 02:24:20 +0300 Subject: [PATCH 37/46] Remove grid and scroll from main page in example --- example/gui/main/main.gui | 112 +------------------------------ example/gui/main/main.gui_script | 2 +- example/page/main_page.lua | 23 ------- 3 files changed, 2 insertions(+), 135 deletions(-) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 58331c8..3e91200 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -198,7 +198,7 @@ nodes { } size { x: 600.0 - y: 1500.0 + y: 900.0 z: 0.0 w: 1.0 } @@ -2879,116 +2879,6 @@ nodes { template_node_child: true size_mode: SIZE_MODE_AUTO } -nodes { - position { - x: 0.0 - y: -890.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: "section_grid" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - 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_AUTO -} -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: 400.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: "grid" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "section_grid" - 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 -} nodes { position { x: 0.0 diff --git a/example/gui/main/main.gui_script b/example/gui/main/main.gui_script index 55b9f81..8973264 100644 --- a/example/gui/main/main.gui_script +++ b/example/gui/main/main.gui_script @@ -65,7 +65,7 @@ function init(self) init_swipe_control(self) - self.page = 7 + self.page = 1 main_page.setup_page(self) text_page.setup_page(self) button_page.setup_page(self) diff --git a/example/page/main_page.lua b/example/page/main_page.lua index 0877c0e..4e0925d 100644 --- a/example/page/main_page.lua +++ b/example/page/main_page.lua @@ -50,22 +50,6 @@ local function setup_progress(self) end -local function setup_grid(self) - local grid = self.druid:new_static_grid("grid", "button_template/button", 3) - - for i = 1, 12 do - local nodes = gui.clone_tree(gui.get_node("button_template/button")) - - local root = nodes["button_template/button"] - self.druid:new_button(root, function(context, param) - grid:set_offset(vmath.vector3(param)) - end, i) - self.druid:new_text(nodes["button_template/text"], "Grid"..i) - grid:add(root) - end -end - - local function setup_slider(self) local slider = self.druid:new_slider("slider_pin", vmath.vector3(95, 0, 0), function(_, value) gui.set_text(gui.get_node("text_progress_slider"), math.ceil(value * 100) .. "%") @@ -96,11 +80,6 @@ local function setup_timer(self) end -local function setup_scroll(self) - self.druid:new_scroll("main_page", "scroll_content") -end - - local function setup_back_handler(self) self.druid:new_back_handler(empty_callback, "back button") end @@ -117,10 +96,8 @@ function M.setup_page(self) setup_button(self) setup_progress(self) - setup_grid(self) setup_timer(self) setup_checkbox(self) - setup_scroll(self) setup_slider(self) setup_back_handler(self) setup_input(self) From 0e96c582c9380c25dbee4df3c07b2c6762b28ac1 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 02:33:47 +0300 Subject: [PATCH 38/46] Better grid example hints --- example/gui/main/main.gui | 259 ++++++++++++------------------------ example/page/grid_page.lua | 14 +- example/page/texts_page.lua | 2 +- 3 files changed, 91 insertions(+), 184 deletions(-) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 3e91200..79d53f6 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -9696,7 +9696,7 @@ nodes { nodes { position { x: 0.0 - y: -190.0 + y: -354.0 z: 0.0 w: 1.0 } @@ -9805,8 +9805,8 @@ nodes { } nodes { position { - x: -150.0 - y: -140.0 + x: -80.0 + y: -304.0 z: 0.0 w: 1.0 } @@ -9964,167 +9964,8 @@ nodes { } 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: 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_remove" - parent: "grid_page_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/templates/button.gui" - template_node_child: false -} -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_remove/button" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "button_remove" - 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 -} -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: "Remove" - font: "game" - id: "button_remove/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_remove/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 -} -nodes { - position { - x: 150.0 - y: -140.0 + x: 80.0 + y: -304.0 z: 0.0 w: 1.0 } @@ -10283,7 +10124,7 @@ nodes { nodes { position { x: -160.0 - y: -230.0 + y: -394.0 z: 0.0 w: 1.0 } @@ -10456,7 +10297,7 @@ nodes { nodes { position { x: 0.0 - y: -650.0 + y: -814.0 z: 0.0 w: 1.0 } @@ -10566,7 +10407,7 @@ nodes { nodes { position { x: 0.0 - y: -700.0 + y: -864.0 z: 0.0 w: 1.0 } @@ -10621,7 +10462,7 @@ nodes { nodes { position { x: -250.0 - y: -1300.0 + y: -1464.0 z: 0.0 w: 1.0 } @@ -10731,7 +10572,7 @@ nodes { nodes { position { x: 0.0 - y: -1309.0 + y: -1473.0 z: 0.0 w: 1.0 } @@ -10786,7 +10627,7 @@ nodes { nodes { position { x: -60.0 - y: -620.0 + y: -784.0 z: 0.0 w: 1.0 } @@ -10911,7 +10752,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Add Start" + text: "Add First" font: "game" id: "button_add_start_dynamic/text" xanchor: XANCHOR_NONE @@ -10945,7 +10786,7 @@ nodes { nodes { position { x: 60.0 - y: -620.0 + y: -784.0 z: 0.0 w: 1.0 } @@ -11070,7 +10911,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Add End" + text: "Add Last" font: "game" id: "button_add_end_dynamic/text" xanchor: XANCHOR_NONE @@ -11104,7 +10945,7 @@ nodes { nodes { position { x: -60.0 - y: -1211.0 + y: -1375.0 z: 0.0 w: 1.0 } @@ -11229,7 +11070,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Add Start" + text: "Add First" font: "game" id: "button_add_start_dynamic_hor/text" xanchor: XANCHOR_NONE @@ -11263,7 +11104,7 @@ nodes { nodes { position { x: 60.0 - y: -1211.0 + y: -1375.0 z: 0.0 w: 1.0 } @@ -11388,7 +11229,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Add End" + text: "Add Last" font: "game" id: "button_add_end_dynamic_hor/text" xanchor: XANCHOR_NONE @@ -11419,6 +11260,70 @@ nodes { text_leading: 1.0 text_tracking: 0.0 } +nodes { + position { + x: -200.0 + y: -180.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.75 + y: 0.75 + z: 1.0 + w: 1.0 + } + size { + x: 533.33 + y: 200.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Tap on node for remove\n" + "Long tap on node for remove without node shift" + font: "game" + id: "text_grid_hint" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + outline { + x: 1.0 + y: 1.0 + z: 1.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: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 +} nodes { position { x: 0.0 diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index e2aff6d..4a0f9b3 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -66,19 +66,18 @@ local function init_static_grid(self) self.druid:new_button("button_add/button", function() add_node(self) end) - self.druid:new_button("button_clear/button", clear_nodes) - - local remove_button = self.druid:new_button("button_remove/button", remove_node) - gui.set_enabled(remove_button.node, false) + self.druid:new_button("button_clear/button", function() + clear_nodes(self) + end) end -local function remove_dynamic_node(self, button) +local function remove_dynamic_node(self, button, is_shift_left) gui.delete_node(button.node) self.druid:remove(button) local index = self.grid_dynamic_grid:get_index_by_node(button.node) - self.grid_dynamic_grid:remove(index) + self.grid_dynamic_grid:remove(index, is_shift_left) for i = 1, #self.dynamic_node_buttons do if self.dynamic_node_buttons[i] == button then table.remove(self.dynamic_node_buttons, i) @@ -97,6 +96,9 @@ local function add_node_dynamic(self, index, is_shift_left) local button = self.druid:new_button(node, function(_, params, button) remove_dynamic_node(self, button) end) + button.on_long_click:subscribe(function() + remove_dynamic_node(self, button, true) + end) button:set_click_zone(self.grid_dynamic_scroll.view_node) table.insert(self.dynamic_node_buttons, button) end diff --git a/example/page/texts_page.lua b/example/page/texts_page.lua index b77da1e..bb64294 100644 --- a/example/page/texts_page.lua +++ b/example/page/texts_page.lua @@ -27,7 +27,7 @@ local function setup_texts(self) timer.delay(0.3, true, function() anchoring:set_pivot(pivots[pivot_index]) - pivot_index = pivot_index + 1 + pivot_index = pivot_index + 1 if pivot_index > #pivots then pivot_index = 1 end From af61d4561a250c5b3d5b8633cf50d75dba6bf55b Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 02:52:38 +0300 Subject: [PATCH 39/46] Update changelogs --- docs_md/changelog.md | 19 +++++++++++-------- druid/base/scroll.lua | 2 +- druid/base/static_grid.lua | 10 +++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 830b00f..f4c73ba 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -96,6 +96,7 @@ Druid 0.4.0: Druid 0.5.0: - **#77** Grid update: - The _grid_ component now is __deprecated__. Use _static_grid_ instead. Druid will show you deprecated message, if you still using _grid_ component + - __[BREAKING]__ Remove the _grid:set_offset_ grid functions. To adjust the distance between nodes inside grid - setup correct node sizes - Add _static_grid_ component - The behaviour like previous _grid_ component - Have constant element size, so have ability to precalculate positions, indexes and size of content @@ -103,22 +104,24 @@ Druid 0.5.0: - This grid can spawn elements with several rows and collumns - Add _dynamic_grid_ component - Have dynamic element size. So have no ability to precalculate stuff like _static_grid_ - - Element size got from _gui.get_size_ * _gui.get_scale_ - - This grid can not have spaces between elements. You will get the error, if spawn element far away from other elements + - This grid can't have gaps between elements. You will get the error, if spawn element far away from other elements - The grid can spawn elements only in row or in collumn - - The grid node should have West or North pivot (vertical or horizontal element placement) + - The grid node should have __West__ or __North__ pivot (vertical or horizontal element placement) + - Able to shift nodes left or right on _grid:add_/_grid:remove_ functions +- Scroll update: + - Add _scroll:set_vertical_scroll_ and _scroll:set_horizontal_scroll_ for disable scroll sides + - Add _scroll:bind_grid_ function. It's allow bind grid component (static or dynamic) to the scroll for auto refresh the scroll size on grid nodes changing - **#37** Add _on_layout_change_ support. Druid will keep and restore GUI component data between changing game layout. Override function _on_layout_change_ in your custom components to do stuff you need. -- **#85** Move several components from `base` folder to `extended`. In future, to use them, you have to register them manually. This is need for decrease build size by excluding unused components -- Add _scroll:set_vertical_scroll_ and _scroll:set_horizontal_scroll_ for disable scroll sides +- **#85** Move several components from `base` folder to `extended`. In future to use them, you have to register them manually. This is done for decrease build size by excluding unused components - **Fix #61:** Button component: fix button animation node creation - **Fix #64:** Hover component: wrong mouse_hover default state - **Fix #71:** Blocker: blocker now correct block mouse hover event - **Fix #72:** Fix `return nil` in some `on_input` functions - **Fix #74:** __[BREAKING]__ Fix typo: strech -> stretch. Scroll function `set_extra_stretch_size` renamed - **Fix #76:** Add params for lang text localization component -- **Fix #79:** Fix druid:remove inside on_input callback -- **Fix #80:** Fix hover set_enable typo function call -- **Fix #88:** Add _component:set_input_enabled_ function to enable/disable input for druid component +- **Fix #79:** Fix _druid:remove_ inside on_input callback +- **Fix #80:** Fix _hover:set_enable_ typo function call +- **Fix #88:** Add _component:set_input_enabled_ function to enable/disable input for druid component. Now you can disable input of any druid component, even complex (with other components inside) - Add `component.tempalte.lua` as template for Druid custom component >>>>>>> develop diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 6a324ba..bd7139a 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -327,7 +327,7 @@ end ---- Bind the grid component (Static or Dynamic) to recalc +--- Bind the grid component (Static or Dynamic) to recalculate -- scroll size on grid changes -- @function scroll:bind_grid -- @tparam druid.static_grid|druid.dynamic_grid Druid grid component diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index d6d56c2..ffdd11c 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -166,9 +166,6 @@ function StaticGrid:remove(index, is_shift_nodes) end end - -- Recalculate borders - self.border = vmath.vector4(0) - self:_update() self.on_add_item:trigger(self:get_context(), index) @@ -179,11 +176,10 @@ end --- Return grid content size -- @function static_grid:get_size -- @treturn vector3 The grid content size -function StaticGrid:get_size(border) - border = border or self.border +function StaticGrid:get_size() return vmath.vector3( - border.z - border.x, - border.y - border.w, + self.border.z - self.border.x, + self.border.y - self.border.w, 0) end From a36ba5ab1c316096230df51ebc814220e3823ea1 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 02:58:43 +0300 Subject: [PATCH 40/46] Add more available pivots for dynamic grid --- docs_md/changelog.md | 2 +- druid/base/dynamic_grid.lua | 12 ++++++++++-- druid/const.lua | 2 +- druid/helper.lua | 10 ++++++++++ example/gui/main/main.gui | 10 +++++----- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/docs_md/changelog.md b/docs_md/changelog.md index f4c73ba..1b48160 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -106,7 +106,7 @@ Druid 0.5.0: - Have dynamic element size. So have no ability to precalculate stuff like _static_grid_ - This grid can't have gaps between elements. You will get the error, if spawn element far away from other elements - The grid can spawn elements only in row or in collumn - - The grid node should have __West__ or __North__ pivot (vertical or horizontal element placement) + - The grid node should have __West__, __East__, __South__ or __North__ pivot (vertical or horizontal element placement) - Able to shift nodes left or right on _grid:add_/_grid:remove_ functions - Scroll update: - Add _scroll:set_vertical_scroll_ and _scroll:set_horizontal_scroll_ for disable scroll sides diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index 4d05a56..cefd9b3 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -32,6 +32,13 @@ local SIDE_VECTORS = { BOT = vmath.vector3(0, 1, 0), } +local AVAILABLE_PIVOTS = { + gui.PIVOT_N, + gui.PIVOT_S, + gui.PIVOT_W, + gui.PIVOT_E, +} + --- Component init function -- @function dynamic_grid:init @@ -42,8 +49,9 @@ function DynamicGrid:init(parent, side) local parent_pivot = gui.get_pivot(self.parent) self.pivot = helper.get_pivot_offset(parent_pivot) - assert(parent_pivot == gui.PIVOT_W or parent_pivot == gui.PIVOT_N, const.ERRORS.GRID_DYNAMIC_ANCHOR) - self.side = (parent_pivot == gui.PIVOT_W and const.SIDE.X or const.SIDE.Y) + assert(helper.contains(AVAILABLE_PIVOTS, parent_pivot), const.ERRORS.GRID_DYNAMIC_ANCHOR) + self.side = ((parent_pivot == gui.PIVOT_W or parent_pivot == gui.PIVOT_E) + and const.SIDE.X or const.SIDE.Y) self.nodes = {} self.border = vmath.vector4(0) -- Current grid content size diff --git a/druid/const.lua b/druid/const.lua index 151b62b..3437fe4 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -103,7 +103,7 @@ M.SWIPE = { M.ERRORS = { - GRID_DYNAMIC_ANCHOR = "The pivot of dynamic grid node should be West or North" + GRID_DYNAMIC_ANCHOR = "The pivot of dynamic grid node should be West, East, South or North" } diff --git a/druid/helper.lua b/druid/helper.lua index 3b6792a..c4c0041 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -131,6 +131,16 @@ function M.lerp(a, b, t) end +function M.contains(t, value) + for i = 1, #t do + if t[i] == value then + return i + end + end + return false +end + + --- Check if node is enabled in gui hierarchy. -- Return false, if node or any his parent is disabled -- @function helper.is_enabled diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 79d53f6..0497466 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10297,7 +10297,7 @@ nodes { nodes { position { x: 0.0 - y: -814.0 + y: -1320.0 z: 0.0 w: 1.0 } @@ -10331,7 +10331,7 @@ nodes { id: "grid_dynamic_view" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE - pivot: PIVOT_N + pivot: PIVOT_S adjust_mode: ADJUST_MODE_FIT parent: "grid_page_content" layer: "" @@ -10386,7 +10386,7 @@ nodes { id: "grid_dynamic_nodes" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE - pivot: PIVOT_N + pivot: PIVOT_S adjust_mode: ADJUST_MODE_FIT parent: "grid_dynamic_view" layer: "" @@ -10461,7 +10461,7 @@ nodes { } nodes { position { - x: -250.0 + x: 250.0 y: -1464.0 z: 0.0 w: 1.0 @@ -10479,7 +10479,7 @@ nodes { w: 1.0 } size { - x: 500.0 + x: -500.0 y: 100.0 z: 0.0 w: 1.0 From 453c8327c89e4fda3ce132bc97a6eb58bf0816e3 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 21:40:09 +0300 Subject: [PATCH 41/46] Update FAQ --- docs_md/faq.md | 53 ++++++++++++++++++++++++++++++++----- druid/base/dynamic_grid.lua | 2 +- example/gui/main/main.gui | 4 +-- example/page/grid_page.lua | 2 +- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/docs_md/faq.md b/docs_md/faq.md index eb4f793..e25fad0 100644 --- a/docs_md/faq.md +++ b/docs_md/faq.md @@ -1,18 +1,59 @@ + # Druid FAQ -### Q: How to remove the Druid component instance -A: --- +### Q: Why I want use Druid? +**A:** --- + + +### Q: How to remove the Druid component instance? +**A:** Any created **Druid** component can be removed with _druid:remove_. [API reference link](https://insality.github.io/druid/modules/druid_instance.html#druid:remove). + ### Q: How to make scroll work? -A: --- +**A:** --- + ### Q: How the input is processing? -A: --- +**A:** +*SImply*: the **Druid** has a LIFO queue to check input. Last added buttons have more priority than first. Placing your buttons from behind to the front is correct in most cases. + ### Q: For what purpose Blocker component is exist? -A: --- +**A:** Component explanation [here](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#notes-2). +With Blocker you can block input in some zone. It is useful for make unclickable zone in buttons or kind of buttons panel on other big button (ex. close windows on window background click) + ### Q: Which stuff can I do with custom components? -A: --- +**A:** Any of you can imagine! There is a lot of examples, but in general: custom components allow you place component and some game logic separately from other stuff. It will be reusable, easier for testing and developing. + +For example it can be element in scroll with buttons, your custom GUI widget or even component with your game logic. Usually custom components going with templates. You can do several templates for single component module (for different visuals!) + +Some examples of custom components you can find [here](https://github.com/Insality/druid-assets). +### Q: How *self:get_node()* is working? +**A:** The node can be placed in gui directly or can be cloned via *gui.clone_tree()*. Also nodes can be placed as templates, so full node id will be composed from template name and node name (in cloned nodes too). + +**Druid** component *self:get_node()* trying to search in all of this places. Use *self:set_template()* and *self:set_component_nodes()* for correct setup component nodes before any call of *self:get_node()*. + +Remember, usually you should pass *__string name__ of the node*, not gui node itself. It's better and more druid-way. + + +### Q: My button in scroll is clickable outside the stencil node +**A:** Since **Druid** checking click node with _gui.pick_node_, stencil is not prevent this. You can setup additional click zone on your buttons with _button:set_click_zone_. + +The usual Druid way after add button to the scroll do: +```lua +-- Scroll view node usually is stencil node +button:set_click_zone(scroll.view_node) + ``` + +### Q: How to use EmmyLua annotations? +**A:** Since the dependencies can't be processed by external editors, for use generated EmmyLua annotations you should copy the _annotations.lua_ to your project. For EmmyLua it will be enough. Remember you can _restart emmylua server_ for refresh the changes, if something goes wrong. +After the annotations is processed, you should point the type of druid in requires: +```lua +---@type druid +local druid = require("druid.druid") + +-- Now the autocomplete is working +``` diff --git a/druid/base/dynamic_grid.lua b/druid/base/dynamic_grid.lua index cefd9b3..212afcc 100644 --- a/druid/base/dynamic_grid.lua +++ b/druid/base/dynamic_grid.lua @@ -43,7 +43,7 @@ local AVAILABLE_PIVOTS = { --- Component init function -- @function dynamic_grid:init -- @tparam node parent The gui node parent, where items will be placed -function DynamicGrid:init(parent, side) +function DynamicGrid:init(parent) self.parent = self:get_node(parent) local parent_pivot = gui.get_pivot(self.parent) diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 0497466..e7d18f3 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -10461,7 +10461,7 @@ nodes { } nodes { position { - x: 250.0 + x: -250.0 y: -1464.0 z: 0.0 w: 1.0 @@ -10479,7 +10479,7 @@ nodes { w: 1.0 } size { - x: -500.0 + x: 500.0 y: 100.0 z: 0.0 w: 1.0 diff --git a/example/page/grid_page.lua b/example/page/grid_page.lua index 4a0f9b3..4eba0c1 100644 --- a/example/page/grid_page.lua +++ b/example/page/grid_page.lua @@ -41,7 +41,7 @@ end local function clear_nodes(self) - local nodes = self.grid_nodes.nodes + local nodes = self.grid_static_grid.nodes for i, node in pairs(nodes) do gui.delete_node(node) end From 59aed96d332cea413ba0530fa582683b8d4ee255 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 21:56:46 +0300 Subject: [PATCH 42/46] Update README and components documentation --- README.md | 57 +++++++++++++++++++++------------------- docs_md/01-components.md | 48 +++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 2fad178..71ba46a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ - - - [![](media/druid_logo.png)](https://insality.github.io/druid/) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/insality/druid)](https://github.com/Insality/druid/releases) -**Druid** - powerful Defold component UI library. Use basic **Druid** components or make your own game-specific components to make amazing GUI in your games. +**Druid** - powerful Defold component UI library. Use basic and extended **Druid** components or make your own game-specific components to make amazing GUI in your games. ## Setup @@ -35,7 +32,7 @@ For **Druid** to work requires next input bindings: ### Input capturing [optional] -By default, **Druid** will auto-capture input focus, if any input component will be created. So you don't need to call `msg.post(".", "acquire_input_focus)"` +By default, **Druid** will auto-capture input focus, if any input component will be created. So you don't need to call `msg.post(".", "acquire_input_focus")` If you not need this behaviour, you can disable it by settings `druid.no_auto_input` field in _game.project_: ``` @@ -76,35 +73,19 @@ druid.on_window_callback(event) ## Components -**Druid** provides next basic components: +**Druid** provides next *basic* components: -- **[Button](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#button)** - Basic Druid input component +- **[Button](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#button)** - Basic Druid button input component. Handles all types of interaction (tap, long-tap, hold-tap, double-tap, simple key triggers, etc) -- **[Text](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#text)** - Basic Druid text component - -- **[Lang text](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#lang-text)** - Wrap on Text component to handle localization +- **[Text](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#text)** - Basic Druid text component. Wrap on gui text node, handle text size adjusting. - **[Scroll](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#scroll)** - Basic Druid scroll component -- **[Progress](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#progress)** - Basic Druid progress bar component - -- **[Slider](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#slider)** - Basic Druid slider component - -- **[Input](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#input)** - Basic Druid text input component (unimplemented) - -- **[Checkbox](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox)** - Basic Druid checkbox component - -- **[Checkbox group](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox-group)** - Several checkboxes in one group - -- **[Radio group](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#radio-group)** - Several checkboxes in one group with single choice - - **[Blocker](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#blocker)** - Block input in node zone component -- **[Back Handler](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#back-handler)** - Handle back button (Android back, backspace) +- **[Back Handler](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#back-handler)** - Handle back button (Android back button, backspace key) -- **[Timer](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#timer)** - Handle timer work on gui text node - -- **[Grid](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#grid)** - Component for manage node positions +- **[Static Grid](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#static-grid)** - Component for manage node positions with equal sizes - **[Hover](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#hover)** - System Druid component, handle hover node state @@ -112,6 +93,27 @@ druid.on_window_callback(event) - **[Drag](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#drag)** - System Druid component, handle drag input on node +**Druid** also provides next *extended* components: +***Note**: In future, to use extended components, you should register them first. It's required for make **Druid** modular - to exclude unused components from build* + +- **[Checkbox](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox)** - Checkbox component + +- **[Checkbox group](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox-group)** - Several checkboxes in one group + +- **[Dynamic Grid](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#dynamic-grid)** - Component for manage node positions with different sizes. Only in one row or column + +- **[Input](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#input)** - User text input component + +- **[Lang text](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#lang-text)** - Wrap on Text component to handle localization + +- **[Progress](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#progress)** - Progress bar component + +- **[Radio group](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#radio-group)** - Several checkboxes in one group with single choice + +- **[Slider](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#slider)** - Slider component + +- **[Timer](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#timer)** - Handle timer work on gui text node + Full info see on _[components.md](https://github.com/Insality/druid/blob/master/docs_md/01-components.md)_ @@ -157,7 +159,7 @@ Any **Druid** components as callbacks uses [Druid Events](https://insality.githu Any events can handle several callbacks, if needed. -## Druid lifecycle +## Druid Lifecycle Here is full druid lifecycle setup in your ***.gui_script** file: ```lua @@ -213,6 +215,7 @@ Try the [HTML5 version](https://insality.github.io/druid/druid/) of the example To learn **Druid** better, read next documentation: - [Druid components](https://github.com/Insality/druid/blob/master/docs_md/01-components.md) - [Create custom components](https://github.com/Insality/druid/blob/master/docs_md/02-creating_custom_components.md) +- [See FAQ article](https://github.com/Insality/druid/blob/master/docs_md/FAQ.md) - [Druid styles](https://github.com/Insality/druid/blob/master/docs_md/03-styles.md) - [Druid asset store](https://github.com/Insality/druid/blob/master/docs_md/04-druid_assets.md) diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 39e1087..0624c5d 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -13,6 +13,9 @@ Basic Druid input component. Handle input on node and provide different callback Create button with druid: `button = druid:new_button(node_name, callback, [params], [animation_node])` Where node name is name of node from GUI scene. You can use `node_name` as input trigger zone and point another node for animation via `animation_node` +### Usecase +_fill example usecases_ + ### Notes - Button callback have next params: (self, params, button_instance) - **self** - Druid self context @@ -146,6 +149,7 @@ Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or ju - Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene - If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles + ## Slider [Slider API here](https://insality.github.io/druid/modules/druid.slider.html) @@ -161,11 +165,12 @@ Pin node (node_name in params) should be placed in zero position (initial). It w - 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) - For now, start pos and end pos should be on vertical or horizontal line (their x or y value should be equal) + ## Input [Input API here](https://insality.github.io/druid/modules/druid.input.html) ### Overview -Basic Druid text input component (unimplemented) +Basic Druid text input component ### Setup Create input component with druid: `input = druid:new_input(button_node_name, text_node_name, keyboard_type)` @@ -194,6 +199,7 @@ Create checkbox component with druid: `checkbox = druid:new_checkbox(node, callb - Checkbox uses button to handle click - You can setup another node to handle input with click_node arg in component init: `druid:new_checkbox(node, callback, [click_node])` + ## Checkbox group [Checkbox group API here](https://insality.github.io/druid/modules/druid.checkbox_group.html) @@ -222,6 +228,7 @@ Create radio_group component with druid: `group = druid:new_radio_group(nodes[], - You can get/set radio_group state with `group:set_state()` and `group:get_state()` - Only different from checkbox_group: on click another checkboxes in this group will be unchecked + ## Timer [Timer API here](https://insality.github.io/druid/modules/druid.timer.html) @@ -236,21 +243,46 @@ Create timer component with druid: `timer = druid:new_timer(text_node, from_seco - Timer will setup text node with current timer value - Timer uses update function to handle time -## Grid -[Grid API here](https://insality.github.io/druid/modules/druid.grid.html) + +## Static Grid +[Static Grid API here](https://insality.github.io/druid/modules/druid.static_grid.html) ### Overview -Component for manage node positions. Very simple implementation for nodes with equal size +Component for manage node positions. Static grid have constant node size, so it possible to calculate node positions before placement. Nodes can be placed with gaps. Static grid can shift elements on add/remove functions. ### Setup -Create component with druid: `grid = druid:new_grid(parent_node, prefab_node, max_in_row_elements)` +Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_node, max_in_row_elements)` ### Notes -- Grid on _adding elements_ will setup parent to _parent_node_ +- On _add node_ grid will set node parent to _parent_node_ - You can get array of position of every element for setup points of interest in scroll component - You can get size of all elements for setup size in scroll component -- You can adjust anchor and border between elements -- _Prefab node_ in component init used to get grid item size +- You can also bind the grid to the scroll component for auto resize scroll content size +- Pivot of parent_node matter for node placement +- _Prefab node_ used to get node size and anchor +- You can point *position_function* for animations with _static_grid:set_position_function(node, pos)_ callback. Default - *gui.set_position()* + + +## Dynamic Grid +[Dynamic Grid API here](https://insality.github.io/druid/modules/druid.dynamic_grid.html) + +### 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 - 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) + +### Setup +Create component with druid: `grid = druid:new_dynamic_grid(parent_node)` + +Check the _parent_node_ have correct pivot point. You will get the error otherwise. + +### Notes +- On _add node_ grid will set node parent to _parent_node_ +- You can get array of position of every element for setup points of interest in scroll component +- You can get size of all elements for setup size in scroll component +- You can also bind the grid to the scroll component for auto resize scroll content size +- Pivot of parent_node matter for node placement +- You can point *position_function* for animations with _static_grid:set_position_function(node, pos)_ callback. Default - *gui.set_position()* +- First node placed at Grid pivot point. Other nodes placed nearby of other nodes. +- On *add/remove* nodes always shifted. You can point the shift side in this functions (*is_shift_left* boolean argument) ## Hover [Hover API here](https://insality.github.io/druid/modules/druid.hover.html) From e97b0d22c87e0382d918db9083db9145d07ffd81 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 21:58:52 +0300 Subject: [PATCH 43/46] Add dynamic_grid and lang_text to the extended components --- druid/{base => extended}/dynamic_grid.lua | 0 druid/{base => extended}/lang_text.lua | 0 druid/system/druid_instance.lua | 58 ++++++++++++----------- 3 files changed, 30 insertions(+), 28 deletions(-) rename druid/{base => extended}/dynamic_grid.lua (100%) rename druid/{base => extended}/lang_text.lua (100%) diff --git a/druid/base/dynamic_grid.lua b/druid/extended/dynamic_grid.lua similarity index 100% rename from druid/base/dynamic_grid.lua rename to druid/extended/dynamic_grid.lua diff --git a/druid/base/lang_text.lua b/druid/extended/lang_text.lua similarity index 100% rename from druid/base/lang_text.lua rename to druid/extended/lang_text.lua diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index ce00c7e..f77ecec 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -30,16 +30,16 @@ local blocker = require("druid.base.blocker") local button = require("druid.base.button") local drag = require("druid.base.drag") local hover = require("druid.base.hover") -local lang_text = require("druid.base.lang_text") -local static_grid = require("druid.base.static_grid") -local dynamic_grid = require("druid.base.dynamic_grid") local scroll = require("druid.base.scroll") +local static_grid = require("druid.base.static_grid") local swipe = require("druid.base.swipe") local text = require("druid.base.text") local checkbox = require("druid.extended.checkbox") local checkbox_group = require("druid.extended.checkbox_group") +local dynamic_grid = require("druid.base.dynamic_grid") local input = require("druid.extended.input") +local lang_text = require("druid.base.lang_text") local progress = require("druid.extended.progress") local radio_group = require("druid.extended.radio_group") local slider = require("druid.extended.slider") @@ -383,15 +383,6 @@ function Druid.new_text(self, ...) end ---- Create lang_text basic component --- @function druid:new_lang_text --- @tparam args ... lang_text init args --- @treturn Component lang_text component -function Druid.new_lang_text(self, ...) - return Druid.create(self, lang_text, ...) -end - - --- Create grid basic component -- @function druid:new_grid -- @tparam args ... grid init args @@ -412,15 +403,6 @@ function Druid.new_static_grid(self, ...) end ---- Create dynamic grid basic component --- @function druid:new_dynamic_grid --- @tparam args ... grid init args --- @treturn Component grid component -function Druid.new_dynamic_grid(self, ...) - return Druid.create(self, dynamic_grid, ...) -end - - --- Create scroll basic component -- @function druid:new_scroll -- @tparam args ... scroll init args @@ -448,7 +430,27 @@ function Druid.new_drag(self, ...) end ---- Create slider basic component +--- Create dynamic grid component +-- @function druid:new_dynamic_grid +-- @tparam args ... grid init args +-- @treturn Component grid component +function Druid.new_dynamic_grid(self, ...) + -- return helper.extended_component("dynamic_grid") + return Druid.create(self, dynamic_grid, ...) +end + + +--- Create lang_text component +-- @function druid:new_lang_text +-- @tparam args ... lang_text init args +-- @treturn Component lang_text component +function Druid.new_lang_text(self, ...) + -- return helper.extended_component("lang_text") + return Druid.create(self, lang_text, ...) +end + + +--- Create slider component -- @function druid:new_slider -- @tparam args ... slider init args -- @treturn Component slider component @@ -458,7 +460,7 @@ function Druid.new_slider(self, ...) end ---- Create checkbox basic component +--- Create checkbox component -- @function druid:new_checkbox -- @tparam args ... checkbox init args -- @treturn Component checkbox component @@ -468,7 +470,7 @@ function Druid.new_checkbox(self, ...) end ---- Create input basic component +--- Create input component -- @function druid:new_input -- @tparam args ... input init args -- @treturn Component input component @@ -478,7 +480,7 @@ function Druid.new_input(self, ...) end ---- Create checkbox_group basic component +--- Create checkbox_group component -- @function druid:new_checkbox_group -- @tparam args ... checkbox_group init args -- @treturn Component checkbox_group component @@ -488,7 +490,7 @@ function Druid.new_checkbox_group(self, ...) end ---- Create radio_group basic component +--- Create radio_group component -- @function druid:new_radio_group -- @tparam args ... radio_group init args -- @treturn Component radio_group component @@ -498,7 +500,7 @@ function Druid.new_radio_group(self, ...) end ---- Create timer basic component +--- Create timer component -- @function druid:new_timer -- @tparam args ... timer init args -- @treturn Component timer component @@ -508,7 +510,7 @@ function Druid.new_timer(self, ...) end ---- Create progress basic component +--- Create progress component -- @function druid:new_progress -- @tparam args ... progress init args -- @treturn Component progress component From 67b43ca800d22d682e2695c4dc8a92b8d4cb73ed Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 22:01:55 +0300 Subject: [PATCH 44/46] Fix new lines in markdown --- README.md | 1 + docs_md/01-components.md | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71ba46a..b50d678 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ druid.on_window_callback(event) - **[Drag](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#drag)** - System Druid component, handle drag input on node **Druid** also provides next *extended* components: + ***Note**: In future, to use extended components, you should register them first. It's required for make **Druid** modular - to exclude unused components from build* - **[Checkbox](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox)** - Checkbox component diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 0624c5d..11322f7 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -248,7 +248,9 @@ Create timer component with druid: `timer = druid:new_timer(text_node, from_seco [Static Grid API here](https://insality.github.io/druid/modules/druid.static_grid.html) ### Overview -Component for manage node positions. Static grid have constant node size, so it possible to calculate node positions before placement. Nodes can be placed with gaps. Static grid can shift elements on add/remove functions. +Component for manage node positions. +Static grid have constant node size, so it possible to calculate node positions before placement. Nodes can be placed with gaps. +Static grid can shift elements on add/remove functions. ### Setup Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_node, max_in_row_elements)` @@ -267,7 +269,10 @@ Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_ [Dynamic Grid API here](https://insality.github.io/druid/modules/druid.dynamic_grid.html) ### 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 - 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) +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 - 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) ### Setup Create component with druid: `grid = druid:new_dynamic_grid(parent_node)` From e00ab4f0a1b171800847928ff2482d50b5482551 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 22:11:09 +0300 Subject: [PATCH 45/46] Update grid example --- druid/system/druid_instance.lua | 4 +- example/gui/main/main.gui | 786 ++++++++++++++++++++++---------- 2 files changed, 542 insertions(+), 248 deletions(-) diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index f77ecec..f3c4c99 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -37,9 +37,9 @@ local text = require("druid.base.text") local checkbox = require("druid.extended.checkbox") local checkbox_group = require("druid.extended.checkbox_group") -local dynamic_grid = require("druid.base.dynamic_grid") +local dynamic_grid = require("druid.extended.dynamic_grid") local input = require("druid.extended.input") -local lang_text = require("druid.base.lang_text") +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") diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index e7d18f3..834027c 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -9659,7 +9659,7 @@ nodes { } size { x: 600.0 - y: 1800.0 + y: 2000.0 z: 0.0 w: 1.0 } @@ -9693,6 +9693,125 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL } +nodes { + position { + x: 0.0 + y: -190.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.6 + y: 0.6 + z: 1.0 + w: 1.0 + } + size { + x: 700.0 + y: 200.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Tap on node for remove\n" + "Long tap on node for remove without node shift" + font: "game" + id: "text_grid_hint" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.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: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.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: "info_grid_static" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + 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 +} nodes { position { x: 0.0 @@ -9732,7 +9851,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_N adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" + parent: "info_grid_static" layer: "" inherit_alpha: true slice9 { @@ -9836,7 +9955,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_add" - parent: "grid_page_content" + parent: "info_grid_static" layer: "" inherit_alpha: true alpha: 1.0 @@ -9995,7 +10114,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_clear" - parent: "grid_page_content" + parent: "info_grid_static" layer: "" inherit_alpha: true alpha: 1.0 @@ -10160,7 +10279,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_CENTER adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" + parent: "info_grid_static" layer: "" inherit_alpha: true slice9 { @@ -10297,7 +10416,127 @@ nodes { nodes { position { x: 0.0 - y: -1320.0 + y: -853.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.6 + y: 0.6 + z: 1.0 + w: 1.0 + } + size { + x: 800.0 + y: 200.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "This Dynamic Grid have pivot on South\n" + "\n" + "Nodes closer to the bottom, like in message app" + font: "game" + id: "text_grid_hint1" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.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: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 0.7 + text_tracking: 0.0 +} +nodes { + position { + x: 0.0 + y: -935.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: "info_grid_dynamic" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + 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 +} +nodes { + position { + x: 0.0 + y: -567.0 z: 0.0 w: 1.0 } @@ -10333,7 +10572,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_S adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" + parent: "info_grid_dynamic" layer: "" inherit_alpha: true slice9 { @@ -10407,7 +10646,7 @@ nodes { nodes { position { x: 0.0 - y: -864.0 + y: -111.0 z: 0.0 w: 1.0 } @@ -10443,172 +10682,7 @@ nodes { yanchor: YANCHOR_NONE pivot: PIVOT_CENTER adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" - layer: "" - inherit_alpha: true - slice9 { - x: 20.0 - y: 20.0 - z: 20.0 - w: 20.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL -} -nodes { - position { - x: -250.0 - y: -1464.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: 500.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9019608 - y: 0.9019608 - z: 0.7019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "grid_dynamic_hor_view" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_STENCIL - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL -} -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: 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_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "grid_dynamic_hor_nodes" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - adjust_mode: ADJUST_MODE_FIT - parent: "grid_dynamic_hor_view" - 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 -} -nodes { - position { - x: 0.0 - y: -1473.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: 100.0 - y: 80.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_red" - id: "grid_dynamic_hor_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "grid_page_content" + parent: "info_grid_dynamic" layer: "" inherit_alpha: true slice9 { @@ -10627,7 +10701,7 @@ nodes { nodes { position { x: -60.0 - y: -784.0 + y: -31.0 z: 0.0 w: 1.0 } @@ -10657,7 +10731,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_add_start_dynamic" - parent: "grid_page_content" + parent: "info_grid_dynamic" layer: "" inherit_alpha: true alpha: 1.0 @@ -10786,7 +10860,7 @@ nodes { nodes { position { x: 60.0 - y: -784.0 + y: -31.0 z: 0.0 w: 1.0 } @@ -10816,7 +10890,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_add_end_dynamic" - parent: "grid_page_content" + parent: "info_grid_dynamic" layer: "" inherit_alpha: true alpha: 1.0 @@ -10942,10 +11016,294 @@ nodes { text_leading: 1.0 text_tracking: 0.0 } +nodes { + position { + x: 0.0 + y: -1583.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 0.6 + y: 0.6 + z: 1.0 + w: 1.0 + } + size { + x: 700.0 + y: 200.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Horizontal Dynamic Grid Example\n" + "Pivot point at West" + font: "game" + id: "text_grid_hint2" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.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: "grid_page_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 +} +nodes { + position { + x: 0.0 + y: -1637.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: "info_grid_dynamic_hor" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "grid_page_content" + 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 +} +nodes { + position { + x: -250.0 + y: -126.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: 500.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.9019608 + y: 0.9019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "grid_dynamic_hor_view" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "info_grid_dynamic_hor" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_STENCIL + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +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: 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_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "grid_dynamic_hor_nodes" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "grid_dynamic_hor_view" + 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 +} +nodes { + position { + x: 0.0 + y: -135.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: 100.0 + y: 80.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_red" + id: "grid_dynamic_hor_prefab" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "info_grid_dynamic_hor" + layer: "" + inherit_alpha: true + slice9 { + x: 20.0 + y: 20.0 + z: 20.0 + w: 20.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} nodes { position { x: -60.0 - y: -1375.0 + y: -37.0 z: 0.0 w: 1.0 } @@ -10975,7 +11333,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_add_start_dynamic_hor" - parent: "grid_page_content" + parent: "info_grid_dynamic_hor" layer: "" inherit_alpha: true alpha: 1.0 @@ -11104,7 +11462,7 @@ nodes { nodes { position { x: 60.0 - y: -1375.0 + y: -37.0 z: 0.0 w: 1.0 } @@ -11134,7 +11492,7 @@ nodes { } type: TYPE_TEMPLATE id: "button_add_end_dynamic_hor" - parent: "grid_page_content" + parent: "info_grid_dynamic_hor" layer: "" inherit_alpha: true alpha: 1.0 @@ -11260,70 +11618,6 @@ nodes { text_leading: 1.0 text_tracking: 0.0 } -nodes { - position { - x: -200.0 - y: -180.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 533.33 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Tap on node for remove\n" - "Long tap on node for remove without node shift" - font: "game" - id: "text_grid_hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 1.0 - y: 1.0 - z: 1.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: "grid_page_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 -} nodes { position { x: 0.0 From 0b56a18578823a18ae750c5a7ff622347aa01737 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 28 Sep 2020 22:22:46 +0300 Subject: [PATCH 46/46] Add more annotations --- README.md | 2 +- druid/base/static_grid.lua | 5 +++++ druid/extended/dynamic_grid.lua | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b50d678..e692a76 100644 --- a/README.md +++ b/README.md @@ -231,8 +231,8 @@ _Will fill later_ ## License -- Original created by [AGulev](https://github.com/AGulev) - Developed and supporting by [Insality](https://github.com/Insality) +- Original idea by [AGulev](https://github.com/AGulev) - Assets from [Kenney](http://www.kenney.nl/) **MIT** License diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index ffdd11c..2dd9a42 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -226,6 +226,11 @@ function StaticGrid:clear() end +--- Return elements offset for correct posing nodes. Correct posing at +-- parent pivot node (0:0) with adjusting of node sizes and anchoring +-- @function static_grid:_get_zero_offset +-- @treturn vector3 The offset vector +-- @local function StaticGrid:_get_zero_offset() -- zero offset: center pos - border size * anchor return vmath.vector3( diff --git a/druid/extended/dynamic_grid.lua b/druid/extended/dynamic_grid.lua index 212afcc..ff96d4f 100644 --- a/druid/extended/dynamic_grid.lua +++ b/druid/extended/dynamic_grid.lua @@ -357,6 +357,11 @@ function DynamicGrid:_get_node_size(node) end +--- Return elements offset for correct posing nodes. Correct posing at +-- parent pivot node (0:0) with adjusting of node sizes and anchoring +-- @function dynamic_grid:_get_zero_offset +-- @treturn vector3 The offset vector +-- @local function DynamicGrid:_get_zero_offset() -- zero offset: center pos - border size * anchor return vmath.vector3( @@ -366,6 +371,7 @@ function DynamicGrid:_get_zero_offset() end +--- Return side vector to correct node shifting function DynamicGrid:_get_side_vector(side, is_forward) if side == const.SIDE.X then return is_forward and SIDE_VECTORS.RIGHT or SIDE_VECTORS.LEFT