diff --git a/druid/base/button.lua b/druid/base/button.lua index 5674df6..7cbc865 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -16,7 +16,6 @@ local component = require("druid.component") ---@field on_mouse_hover fun(self, node, hover_state)|nil ---@field on_set_enabled fun(self, node, enabled_state)|nil - ---Clickable node with various interaction callbacks ---@class druid.button: druid.component ---@field on_click event function(self, custom_args, button_instance) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index cc212fa..fda7b63 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -1,95 +1,23 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle scroll content. --- # Overview # --- --- The Scroll component is designed to handle scrollable content and consists of two nodes: the scroll parent and the scroll input. --- --- The scroll input represents the user input zone and remains static. --- --- The scroll parent is the movable part of the scroll and changes its position. --- --- The initial scroll size can be set by adjusting the size of the scroll parent. --- If the size of the scroll parent is smaller than the scroll input size, scrolling is not available. --- --- # Notes # --- --- • By default, the scroll style includes inertia and extra size for a stretching effect. --- These settings can be adjusted using the scroll style settings. --- For more details, refer to the scroll style settings. --- --- • "Points of interest" can be set up for the scroll. --- The scroll will always be centered on the closest point of interest. --- This feature allows creating a slider without inertia and with points of interest on each scroll element. --- --- • The scroll content size can be adjusted using the scroll:set_size(node_size) method. --- This method sets a new size for the _content node. --- --- • Inertial scrolling mode can be enabled or disabled using the scroll:set_inert(state) method. --- --- • The extra stretch size can be adjusted using the scroll:set_extra_stretch_size method. --- --- • Multitouch is required for scrolling. The scroll component correctly handles --- touch ID swaps while dragging the scroll. --- --- Example Link --- @module Scroll --- @within BaseComponent --- @alias druid.scroll - - ---- On scroll move callback(self, position) --- @tfield event on_scroll event - ---- On scroll_to function callback(self, target, is_instant) --- @tfield event on_scroll_to event - ---- On scroll_to_index function callback(self, index, point) --- @tfield event on_point_scroll event - ---- Scroll view node --- @tfield node view_node - ---- Scroll view size --- @tfield vector3 view_size - ---- Scroll content node --- @tfield node content_node - ---- Flag, if scroll now moving by inertion --- @tfield boolean _is_inert - ---- Current inert speed --- @tfield vector3 inertion - ---- Current scroll posisition --- @tfield vector3 position - ---- Current scroll target position --- @tfield vector3 target_position - ---- Available position for content node: (min_x, max_y, max_x, min_y) --- @tfield vector4 available_pos - ---- Size of available positions: (width, height, 0) --- @tfield vector3 available_size - ---- Drag Druid component --- @tfield Drag drag Drag - ---- Current index of points of interests --- @tfield number|nil selected - ---- Flag, if scroll now animating by gui.animate --- @tfield boolean is_animate - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") +---Scroll style parameters +---@class druid.scroll.style +---@field FRICT number|nil Multiplier for free inertion. Default: 0 +---@field FRICT_HOLD number|nil Multiplier for inertion, while touching. Default: 0 +---@field INERT_THRESHOLD number|nil Scroll speed to stop inertion. Default: 3 +---@field INERT_SPEED number|nil Multiplier for inertion speed. Default: 30 +---@field POINTS_DEADZONE number|nil Speed to check points of interests in no_inertion mode. Default: 20 +---@field BACK_SPEED number|nil Scroll back returning lerp speed. Default: 35 +---@field ANIM_SPEED number|nil Scroll gui.animation speed for scroll_to function. Default: 2 +---@field EXTRA_STRETCH_SIZE number|nil extra size in pixels outside of scroll (stretch effect). Default: 0 +---@field SMALL_CONTENT_SCROLL boolean|nil If true, content node with size less than view node size can be scrolled. Default: false +---@field WHEEL_SCROLL_SPEED number|nil The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 +---@field WHEEL_SCROLL_INVERTED boolean|nil If true, invert direction for touchpad and mouse wheel scroll. Default: false +---@field WHEEL_SCROLL_BY_INERTION boolean|nil If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false + ---@class druid.scroll: druid.component ---@field node node The root node ---@field click_zone node|nil Optional click zone to restrict scroll area @@ -107,6 +35,7 @@ local component = require("druid.component") ---@field drag druid.drag The drag component instance ---@field selected number|nil Current selected point of interest index ---@field is_animate boolean True if scroll is animating +---@field style druid.scroll.style Component style parameters ---@field private _is_inert boolean True if inertial scrolling is enabled ---@field private inertion vector3 Current inertial movement vector ---@field private _is_horizontal_scroll boolean True if horizontal scroll enabled @@ -114,7 +43,6 @@ local component = require("druid.component") ---@field private _grid_on_change event Grid items change event ---@field private _grid_on_change_callback function Grid change callback ---@field private _offset vector3 Content start offset ----@field private style table Component style parameters local M = component.create("scroll") @@ -147,22 +75,7 @@ local function get_size_vector(vector) end ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield number|nil FRICT Multiplier for free inertion. Default: 0 --- @tfield number|nil FRICT_HOLD Multiplier for inertion, while touching. Default: 0 --- @tfield number|nil INERT_THRESHOLD Scroll speed to stop inertion. Default: 3 --- @tfield number|nil INERT_SPEED Multiplier for inertion speed. Default: 30 --- @tfield number|nil POINTS_DEADZONE Speed to check points of interests in no_inertion mode. Default: 20 --- @tfield number|nil BACK_SPEED Scroll back returning lerp speed. Default: 35 --- @tfield number|nil ANIM_SPEED Scroll gui.animation speed for scroll_to function. Default: 2 --- @tfield number|nil EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect). Default: 0 --- @tfield boolean|nil SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled. Default: false --- @tfield boolean|nil WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 --- @tfield boolean|nil WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll. Default: false --- @tfield boolean|nil WHEEL_SCROLL_BY_INERTION If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false +---@param style druid.scroll.style function M:on_style_change(style) self.style = {} self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0 diff --git a/druid/component.lua b/druid/component.lua index 6ae8656..8028500 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -181,15 +181,17 @@ end function M:set_input_priority(value, is_temporary) assert(value) - if self._component.input_priority == value then + local component = self._component + + if component.input_priority == value then return self end - self._component.input_priority = value - self._component._is_input_priority_changed = true + component.input_priority = value + component._is_input_priority_changed = true if not is_temporary then - self._component.default_input_priority = value + component.default_input_priority = value end local children = self:get_childrens() diff --git a/druid/extended/container.lua b/druid/extended/container.lua index cdca841..ebc9fab 100644 --- a/druid/extended/container.lua +++ b/druid/extended/container.lua @@ -252,6 +252,7 @@ function M:add_container(node_or_container, mode, on_resize_callback) end -- Covert node_id to node if needed + ---@cast node node node = self:get_node(node) container = container or self.druid:new(M, node, mode) diff --git a/druid/extended/swipe.lua b/druid/extended/swipe.lua index 89c4689..6997dce 100644 --- a/druid/extended/swipe.lua +++ b/druid/extended/swipe.lua @@ -1,30 +1,16 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle swipe gestures on node. --- Swipe will be triggered, if swipe was started and --- ended on one node --- --- Example Link --- @module Swipe --- @within BaseComponent --- @alias druid.swipe - ---- Swipe node ---@param node node - ---- Restriction zone ---@param click_zone node|nil - ---- Trigger on swipe event(self, swipe_side, dist, delta_time) ---@param event event on_swipe - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") +---Component style params. +---You can override this component styles params in druid styles table +---or create your own style +---@class druid.swipe.style +---@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4 +---@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50 +---@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false + ---@class druid.swipe: druid.component ---@field node node ---@field on_swipe event function(side, dist, dt), side - "left", "right", "up", "down" @@ -38,56 +24,6 @@ local component = require("druid.component") local M = component.create("swipe") -local function start_swipe(self, action) - self._swipe_start_time = socket.gettime() - self._start_pos.x = action.x - self._start_pos.y = action.y -end - - -local function reset_swipe(self, action) - self._swipe_start_time = 0 -end - - -local function check_swipe(self, action) - local dx = action.x - self._start_pos.x - local dy = action.y - self._start_pos.y - local dist = helper.distance(self._start_pos.x, self._start_pos.y, action.x, action.y) - local delta_time = socket.gettime() - self._swipe_start_time - local is_swipe = self.style.SWIPE_THRESHOLD <= dist and delta_time <= self.style.SWIPE_TIME - - if is_swipe then - local is_x_swipe = math.abs(dx) >= math.abs(dy) - local swipe_side = "undefined" - - if is_x_swipe and dx > 0 then - swipe_side = "right" - end - if is_x_swipe and dx < 0 then - swipe_side = "left" - end - if not is_x_swipe and dy > 0 then - swipe_side = "up" - end - if not is_x_swipe and dy < 0 then - swipe_side = "down" - end - - self.on_swipe:trigger(self:get_context(), swipe_side, dist, delta_time) - reset_swipe(self) - end -end - - ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style ----@class druid.swipe.style ----@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4 ----@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50 ----@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false - ---@param style druid.swipe.style function M:on_style_change(style) self.style = {} @@ -135,20 +71,20 @@ function M:on_input(action_id, action) local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone) if not is_pick then - reset_swipe(self, action) + self:_reset_swipe() return false end if self._swipe_start_time ~= 0 and (self._trigger_on_move or action.released) then - check_swipe(self, action) + self:_check_swipe(action) end if action.pressed then - start_swipe(self, action) + self:_start_swipe(action) end if action.released then - reset_swipe(self, action) + self:_reset_swipe() end return true @@ -156,7 +92,7 @@ end function M:on_input_interrupt() - reset_swipe(self) + self:_reset_swipe() end @@ -173,4 +109,54 @@ function M:set_click_zone(zone) end +---Start swipe event +---@param action action +function M:_start_swipe(action) + self._swipe_start_time = socket.gettime() + self._start_pos.x = action.x + self._start_pos.y = action.y +end + + +---Reset swipe event +function M:_reset_swipe() + self._swipe_start_time = 0 +end + + +---Check swipe event +---@param self druid.swipe +---@param action action +function M:_check_swipe(action) + local dx = action.x - self._start_pos.x + local dy = action.y - self._start_pos.y + local dist = helper.distance(self._start_pos.x, self._start_pos.y, action.x, action.y) + local delta_time = socket.gettime() - self._swipe_start_time + local is_swipe = self.style.SWIPE_THRESHOLD <= dist and delta_time <= self.style.SWIPE_TIME + + if is_swipe then + local is_x_swipe = math.abs(dx) >= math.abs(dy) + local swipe_side = "undefined" + + if is_x_swipe and dx > 0 then + swipe_side = "right" + end + if is_x_swipe and dx < 0 then + swipe_side = "left" + end + if not is_x_swipe and dy > 0 then + swipe_side = "up" + end + if not is_x_swipe and dy < 0 then + swipe_side = "down" + end + + self.on_swipe:trigger(self:get_context(), swipe_side, dist, delta_time) + self:_reset_swipe() + end +end + + + + return M diff --git a/druid/system/druid_annotations.lua b/druid/system/druid_annotations.lua index 7318618..860c639 100644 --- a/druid/system/druid_annotations.lua +++ b/druid/system/druid_annotations.lua @@ -27,3 +27,32 @@ ---@field lower fun() ---@field upper fun() ---@field rep fun() + +---@class action +---@field value number The amount of input given by the user. This is usually 1 for buttons and 0-1 for analogue inputs. This is not present for mouse movement. +---@field pressed boolean If the input was pressed this frame. This is not present for mouse movement. +---@field released boolean If the input was released this frame. This is not present for mouse movement. +---@field repeated boolean If the input was repeated this frame. This is similar to how a key on a keyboard is repeated when you hold it down. This is not present for mouse movement. +---@field x number The x value of a pointer device, if present. +---@field y number The y value of a pointer device, if present. +---@field screen_x number The screen space x value of a pointer device, if present. +---@field screen_y number The screen space y value of a pointer device, if present. +---@field dx number The change in x value of a pointer device, if present. +---@field dy number The change in y value of a pointer device, if present. +---@field screen_dx number The change in screen space x value of a pointer device, if present. +---@field screen_dy number The change in screen space y value of a pointer device, if present. +---@field gamepad number The index of the gamepad device that provided the input. +---@field touch touch[] List of touch input, one element per finger, if present. See table below about touch input + +---@class touch +---@field id number A number identifying the touch input during its duration. +---@field pressed boolean True if the finger was pressed this frame. +---@field released boolean True if the finger was released this frame. +---@field tap_count number Number of taps, one for single, two for double-tap, etc +---@field x number The x touch location. +---@field y number The y touch location. +---@field dx number The change in x value. +---@field dy number The change in y value. +---@field acc_x number|nil Accelerometer x value (if present). +---@field acc_y number|nil Accelerometer y value (if present). +---@field acc_z number|nil Accelerometer z value (if present). diff --git a/druid/widget/properties_panel/properties_panel.lua b/druid/widget/properties_panel/properties_panel.lua index 7b80451..03b05c1 100644 --- a/druid/widget/properties_panel/properties_panel.lua +++ b/druid/widget/properties_panel/properties_panel.lua @@ -139,8 +139,9 @@ function M:on_size_changed(new_size) local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z for index = 1, #self.properties do local property = self.properties[index] - if property.container then - property.container:set_size(width) + local container = property.container --[[@as druid.container]] + if container then + container:set_size(width) end end self.paginator.container:set_size(width) diff --git a/example/druid.gui_script b/example/druid.gui_script index 4b5c865..e896661 100644 --- a/example/druid.gui_script +++ b/example/druid.gui_script @@ -14,7 +14,7 @@ local output_list = require("example.components.output_list.output_list") local druid_examples = require("example.examples.druid_examples") ---@class druid.example ----@field druid druid_instance +---@field druid druid.instance ---@field container_root druid.container ---@field container_left druid.container ---@field container_logo druid.container @@ -210,4 +210,4 @@ end ---@param action action function on_input(self, action_id, action) return self.druid:on_input(action_id, action) -end \ No newline at end of file +end