From 91fb8ced52c81e515d7de20e5c12185562b2e09e Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 23 Oct 2021 14:08:24 +0300 Subject: [PATCH] #111 Add druid.stencil_check for auto stencil check to call set_click_zone --- README.md | 10 +++++++++ docs_md/02-creating_custom_components.md | 8 +++++++- docs_md/changelog.md | 6 +++++- druid/base/button.lua | 16 ++++++++++++++- druid/base/drag.lua | 12 ++++++++++- druid/base/hover.lua | 12 ++++++++++- druid/base/scroll.lua | 17 +++++++++++++++- druid/base/swipe.lua | 12 ++++++++++- druid/component.lua | 2 ++ druid/const.lua | 4 ++++ druid/helper.lua | 26 ++++++++++++++++++++++++ druid/system/druid_instance.lua | 14 ++++++------- game.project | 1 + 13 files changed, 126 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 02b1be4..14ab394 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,16 @@ If you don't need this behaviour, you can disable it by settings `druid.no_auto_ no_auto_input = 1 ``` + +### Stencil check [optional] + +When creating input components inside stencil nodes, you probably will use `component:set_click_zone()` to restrict clicks outside this stencil zone. +Druid can do it automatically on _late_init_ component step. To enable this feature add next field in your _game.project_ file +``` +[druid] +stencil_check = 1 +``` + ### Code [optional] Adjust **Druid** settings, if needed: diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index b2fff06..dbfa445 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -23,7 +23,7 @@ end function M.update(self, dt) end --- Call only if exist interest: component.ON_INPUT or component.ON_INPUT_HIGH +-- Call only if exist interest: component.ON_INPUT function M.on_input(self, action_id, action) end @@ -60,6 +60,10 @@ end function M.on_focus_gained(self) end +-- Call only if exist interest: component.ON_LATE_INIT +function M.on_late_init(self) +end + -- Call on component remove or on druid:final function M.on_remove(self) end @@ -117,6 +121,8 @@ There is next interests in druid: - **ON_FOCUS_GAINED** will call _on_focust_gained_ function in on focus gained event. You need to pass window_callback to global `druid:on_window_callback` +- **ON_LATE_INIT** will call _on_late_init_ function once after component init on update step. + ## Best practice on custom components On each component recommended describe component scheme in next way: diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 6b22484..7ad4ec3 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -237,4 +237,8 @@ Have a good day. - `value` - optional field for several actions. For example value is text for **TEXT_SET** - Add Druid component interest: `component.ON_MESSAGE_INPUT` - Implement new interest via function `component:on_message_input(node_id, message)` - - See **System: Message input** example \ No newline at end of file + - See **System: Message input** example +- **#111**: Add autocheck for input and stencil nodes. To enable this feature, add `druid.stencil_check = 1` to your game.project file. + - Add `helper.get_closest_stencil_node` function to get closest parent non inverted stencil node + - Add `component.ON_LATE_INIT` interest. If component with with interest, it will call `component.on_late_init` function once after component init on update step. This can be used to do something after all gui components are was initialized and setup. + - This feature is using for auto setup `component:set_click_zone` to restrict clicks outside scrolls zone for example. Now you can don't think about click zone and let Druid do it instead of you! \ No newline at end of file diff --git a/druid/base/button.lua b/druid/base/button.lua index 0a748a0..0ef1f84 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -57,7 +57,11 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Button = component.create("button", { component.ON_INPUT, component.ON_MESSAGE_INPUT }) +local Button = component.create("button", { + component.ON_INPUT, + component.ON_MESSAGE_INPUT, + component.ON_LATE_INIT +}) local function is_input_match(self, action_id) @@ -221,6 +225,16 @@ function Button.init(self, node, callback, params, anim_node) end +function Button.on_late_init(self) + if not self.click_zone and const.IS_STENCIL_CHECK then + local stencil_node = helper.get_closest_stencil_node(self.node) + if stencil_node then + self:set_click_zone(stencil_node) + end + end +end + + function Button.on_input(self, action_id, action) if not is_input_match(self, action_id) then return false diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 3312c52..71cd176 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -51,7 +51,7 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Drag = component.create("drag", { component.ON_INPUT }, const.PRIORITY_INPUT_HIGH) +local Drag = component.create("drag", { component.ON_INPUT, component.ON_LATE_INIT }, const.PRIORITY_INPUT_HIGH) local function start_touch(self, touch) @@ -189,6 +189,16 @@ function Drag.init(self, node, on_drag_callback) end +function Drag.on_late_init(self) + if not self.click_zone and const.IS_STENCIL_CHECK then + local stencil_node = helper.get_closest_stencil_node(self.node) + if stencil_node then + self:set_click_zone(stencil_node) + end + end +end + + function Drag.on_input_interrupt(self) if self.is_drag or self.is_touch then end_touch(self) diff --git a/druid/base/hover.lua b/druid/base/hover.lua index ac947f9..e30009e 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -18,7 +18,7 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Hover = component.create("hover", { component.ON_INPUT }) +local Hover = component.create("hover", { component.ON_INPUT, component.ON_LATE_INIT }) --- Component init function @@ -38,6 +38,16 @@ function Hover.init(self, node, on_hover_callback) end +function Hover.on_late_init(self) + if not self.click_zone and const.IS_STENCIL_CHECK then + local stencil_node = helper.get_closest_stencil_node(self.node) + if stencil_node then + self:set_click_zone(stencil_node) + end + end +end + + function Hover.on_input(self, action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= nil then return false diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 7cc25dc..265cd9e 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -61,7 +61,12 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Scroll = component.create("scroll", { component.ON_INPUT, component.ON_UPDATE, component.ON_LAYOUT_CHANGE }) +local Scroll = component.create("scroll", { + component.ON_INPUT, + component.ON_UPDATE, + component.ON_LAYOUT_CHANGE, + component.ON_LATE_INIT +}) local function inverse_lerp(min, max, current) @@ -172,6 +177,16 @@ function Scroll.init(self, view_node, content_node) end +function Scroll.on_late_init(self) + if not self.click_zone and const.IS_STENCIL_CHECK then + local stencil_node = helper.get_closest_stencil_node(self.node) + if stencil_node then + self:set_click_zone(stencil_node) + end + end +end + + function Scroll.on_layout_change(self) gui.set_position(self.content_node, self.position) end diff --git a/druid/base/swipe.lua b/druid/base/swipe.lua index 51b2a32..bba7980 100644 --- a/druid/base/swipe.lua +++ b/druid/base/swipe.lua @@ -23,7 +23,7 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Swipe = component.create("swipe", { component.ON_INPUT }) +local Swipe = component.create("swipe", { component.ON_INPUT, component.ON_LATE_INIT }) local function start_swipe(self, action) @@ -99,6 +99,16 @@ function Swipe.init(self, node, on_swipe_callback) end +function Swipe.on_late_init(self) + if not self.click_zone and const.IS_STENCIL_CHECK then + local stencil_node = helper.get_closest_stencil_node(self.node) + if stencil_node then + self:set_click_zone(stencil_node) + end + end +end + + function Swipe.on_input(self, action_id, action) if action_id ~= const.ACTION_TOUCH then return false diff --git a/druid/component.lua b/druid/component.lua index 0e6cb87..87c9488 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -18,6 +18,7 @@ BaseComponent.ALL = const.ALL BaseComponent.ON_INPUT = const.ON_INPUT BaseComponent.ON_UPDATE = const.ON_UPDATE BaseComponent.ON_MESSAGE = const.ON_MESSAGE +BaseComponent.ON_LATE_INIT = const.ON_LATE_INIT BaseComponent.ON_FOCUS_LOST = const.ON_FOCUS_LOST BaseComponent.ON_FOCUS_GAINED = const.ON_FOCUS_GAINED BaseComponent.ON_LAYOUT_CHANGE = const.ON_LAYOUT_CHANGE @@ -30,6 +31,7 @@ BaseComponent.ALL_INTERESTS = { BaseComponent.ON_INPUT, BaseComponent.ON_UPDATE, BaseComponent.ON_MESSAGE, + BaseComponent.ON_LATE_INIT, BaseComponent.ON_FOCUS_LOST, BaseComponent.ON_FOCUS_GAINED, BaseComponent.ON_LAYOUT_CHANGE, diff --git a/druid/const.lua b/druid/const.lua index 0e1d0c1..158e871 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -21,6 +21,9 @@ M.ACTION_SCROLL_UP = hash(sys.get_config("druid.input_scroll_up", "scroll_up")) M.ACTION_SCROLL_DOWN = hash(sys.get_config("druid.input_scroll_down", "scroll_down")) +M.IS_STENCIL_CHECK = sys.get_config("druid.stencil_check") == 1 + + M.RELEASED = "released" M.PRESSED = "pressed" M.STRING = "string" @@ -33,6 +36,7 @@ M.ALL = "all" M.ON_INPUT = hash("on_input") M.ON_UPDATE = hash("on_update") M.ON_MESSAGE = hash("on_message") +M.ON_LATE_INIT = hash("on_late_init") M.ON_FOCUS_LOST = hash("on_focus_lost") M.ON_FOCUS_GAINED = hash("on_focus_gained") M.ON_LAYOUT_CHANGE = hash("layout_changed") diff --git a/druid/helper.lua b/druid/helper.lua index 2a805da..cbd5332 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -171,6 +171,32 @@ function M.is_enabled(node) end + +--- Return closest non inverted clipping parent node for node +-- @function helper.get_closest_stencil_node +-- @tparam node node Gui node +-- @treturn node|nil The clipping node +function M.get_closest_stencil_node(node) + if not node then + return nil + end + + local parent = gui.get_parent(node) + while parent do + local clipping_mode = gui.get_clipping_mode(parent) + local is_clipping_normal = not gui.get_clipping_inverted(parent) + + if is_clipping_normal and clipping_mode == gui.CLIPPING_MODE_STENCIL then + return parent + end + + parent = gui.get_parent(parent) + end + + return nil +end + + --- Get node offset for given gui pivot -- @function helper.get_pivot_offset -- @tparam gui.pivot pivot The node pivot diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index bd4380c..50af3b4 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -225,13 +225,7 @@ end function DruidInstance.create(self, 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 + return DruidInstance.new(self, component, ...) end @@ -316,6 +310,12 @@ end -- @tparam DruidInstance self -- @tparam number dt Delta time function DruidInstance.update(self, dt) + local late_init_components = self.components[base_component.ON_LATE_INIT] + while late_init_components[1] do + late_init_components[1]:on_late_init() + table.remove(late_init_components, 1) + end + local components = self.components[base_component.ON_UPDATE] for i = 1, #components do components[i]:update(dt) diff --git a/game.project b/game.project index ee33433..0e1a044 100644 --- a/game.project +++ b/game.project @@ -25,6 +25,7 @@ use_accelerometer = 0 [druid] no_auto_input = 0 +stencil_check = 0 input_text = text input_touch = touch input_marked_text = marked_text