#111 Add druid.stencil_check for auto stencil check to call set_click_zone

This commit is contained in:
Insality 2021-10-23 14:08:24 +03:00
parent 063e4f4a31
commit 91fb8ced52
13 changed files with 126 additions and 14 deletions

View File

@ -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:

View File

@ -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:

View File

@ -238,3 +238,7 @@ Have a good day.
- 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
- **#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!

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -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