diff --git a/druid/base/button.lua b/druid/base/button.lua index 8a11e86..5398ac6 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -6,21 +6,13 @@ -- Repeated tap local const = require("druid.const") -local ui_animate = require("druid.helper.druid_animate") -local settings = require("druid.settings") local helper = require("druid.helper") -local b_settings = settings.button local M = {} M.interest = { const.ON_INPUT } -M.DEFAULT_DEACTIVATE_COLOR = vmath.vector4(0, 0, 0, 0) -M.DEFAULT_DEACTIVATE_SCALE = vmath.vector3(0.8, 0.9, 1) -M.DEFAULT_ACTIVATE_SCALE = vmath.vector3(1, 1, 1) -M.DEFAULT_ACTIVATION_TIME = 0.2 - --- Component init function -- @function button:init @@ -31,37 +23,26 @@ M.DEFAULT_ACTIVATION_TIME = 0.2 -- @tparam[opt] node anim_node Button anim node (node, if not provided) -- @tparam[opt] string event Button react event, const.ACTION_TOUCH by default function M.init(self, node, callback, params, anim_node, event) + assert(callback, "Button should have callback. To block input on zone use blocker component") + self.style = helper.get_style(self, "BUTTON") self.node = helper.node(node) + self.event = const.ACTION_TOUCH self.anim_node = anim_node and helper.node(anim_node) or self.node self.scale_from = gui.get_scale(self.anim_node) - self.scale_to = self.scale_from + b_settings.SCALE_CHANGE - self.scale_hover_to = self.scale_from + b_settings.HOVER_SCALE self.pos = gui.get_position(self.anim_node) self.callback = callback self.params = params - self.tap_anim = M.tap_scale_animation - self.back_anim = M.back_scale_animation - self.hover_anim = b_settings.IS_HOVER - self.sound = b_settings.BTN_SOUND - self.sound_disable = b_settings.BTN_SOUND_DISABLED + self.hover_anim = self.style.IS_HOVER self.click_zone = nil - - -- TODO: to separate component "block_input"? - -- If callback is nil, so the buttons is stub and without anim - -- Used for zones, what should dont pass the input to other UI elements - if not callback then - self.stub = true - self.hover_anim = false - self.callback = function() end - end end local function set_hover(self, state) - if self.hover_anim and self._is_hovered ~= state then - local target_scale = state and self.scale_hover_to or self.scale_from - ui_animate.scale(self, self.anim_node, target_scale, b_settings.HOVER_TIME) + if self._is_hovered ~= state then + if self.style.on_hover then + self.style.on_hover(self, self.anim_node, state) + end self._is_hovered = state end end @@ -71,17 +52,18 @@ local function on_button_release(self) if not self.disabled then if not self.stub and self.can_action then self.can_action = false - if self.tap_anim then - self.tap_anim(self) + if self.style.on_click then + self.style.on_click(self, self.anim_node) end self.callback(self.context, self.params, self) - settings.play_sound(self.sound) else set_hover(self, false) end return true else - settings.play_sound(self.sound_disable) + if self.style.on_click_disabled then + self.style.on_click_disabled(self, self.anim_node) + end return false end end @@ -129,76 +111,20 @@ function M.on_swipe(self) end -function M.tap_scale_animation(self) - ui_animate.scale_to(self, self.anim_node, self.scale_to, - function() - if self.back_anim then - self.back_anim(self) - end - end - ) -end +function M.set_enabled(self, state) + -- if self.disabled == state then + -- return + -- end - -function M.back_scale_animation(self) - ui_animate.scale_to(self, self.anim_node, self.scale_from) -end - - -function M.deactivate(self, is_animate, callback) - self.disabled = true - if is_animate then - -- callback call three times in gui.animation - local clbk = helper.after(3, function() - if callback then - callback(self.context) - end - end) - - ui_animate.color(self, self.node, M.DEFAULT_DEACTIVATE_COLOR, - clbk, M.DEFAULT_ACTIVATION_TIME, 0, gui.EASING_OUTBOUNCE) - - ui_animate.scale_y_from_to(self, self.node, M.DEFAULT_ACTIVATE_SCALE.x, - M.DEFAULT_DEACTIVATE_SCALE.x, clbk, M.DEFAULT_ACTIVATION_TIME, gui.EASING_OUTBOUNCE) - - ui_animate.scale_x_from_to(self, self.node, M.DEFAULT_ACTIVATE_SCALE.y, - M.DEFAULT_DEACTIVATE_SCALE.y, clbk, M.DEFAULT_ACTIVATION_TIME, gui.EASING_OUTBOUNCE) - else - gui.set_color(self.node, M.DEFAULT_DEACTIVATE_COLOR) - gui.set_scale(self.node, M.DEFAULT_DEACTIVATE_SCALE) - if callback then - callback(self.context) - end + self.disabled = not state + if self.style.on_set_enabled then + self.style.on_set_enabled(self, self.node, state) end end -function M.activate(self, is_animate, callback) - if is_animate then - -- callback call three times in gui.animation - local clbk = helper.after(3, function() - self.disabled = false - if callback then - callback(self.context) - end - end) - - ui_animate.color(self, self.node, ui_animate.TINT_SHOW, - clbk, M.DEFAULT_ACTIVATION_TIME, 0, gui.EASING_OUTBOUNCE) - - ui_animate.scale_y_from_to(self, self.node, M.DEFAULT_DEACTIVATE_SCALE.x, - M.DEFAULT_ACTIVATE_SCALE.x, clbk, M.DEFAULT_ACTIVATION_TIME, gui.EASING_OUTBOUNCE) - - ui_animate.scale_x_from_to(self, self.node, M.DEFAULT_DEACTIVATE_SCALE.y, - M.DEFAULT_ACTIVATE_SCALE.y, clbk, M.DEFAULT_ACTIVATION_TIME, gui.EASING_OUTBOUNCE) - else - gui.set_color(self.node, ui_animate.TINT_SHOW) - gui.set_scale(self.node, M.DEFAULT_ACTIVATE_SCALE) - self.disabled = false - if callback then - callback(self.context) - end - end +function M.get_enabled(self) + return not self.disabled end @@ -207,8 +133,6 @@ end -- @tparam table self Component instance function M.disable_animation(self) self.hover_anim = false - self.tap_anim = nil - self.back_anim = nil end diff --git a/druid/base/checkbox.lua b/druid/base/checkbox.lua index 7725082..d7406be 100644 --- a/druid/base/checkbox.lua +++ b/druid/base/checkbox.lua @@ -6,19 +6,15 @@ local helper = require("druid.helper") local M = {} -local function state_animate(node, state) - local target = state and 1 or 0 - gui.animate(node, "color.w", target, gui.EASING_OUTSINE, 0.1) -end - - function M.set_state(self, state, is_silence) if self.state == state then return end self.state = state - state_animate(self.node, state) + if self.style.on_change_state then + self.style.on_change_state(self, self.node, state) + end if not is_silence and self.callback then self.callback(self.context, state) @@ -37,6 +33,7 @@ end function M.init(self, node, callback, click_node) + self.style = helper.get_style(self, "CHECKBOX") self.druid = helper.get_druid(self) self.node = helper.node(node) self.click_node = helper.node(click_node) diff --git a/druid/base/progress.lua b/druid/base/progress.lua index 450f2a4..5a5778b 100644 --- a/druid/base/progress.lua +++ b/druid/base/progress.lua @@ -3,8 +3,6 @@ local const = require("druid.const") local helper = require("druid.helper") -local settings = require("druid.settings") -local p_settings = settings.progress local M = {} @@ -20,14 +18,12 @@ M.interest = { -- @tparam string key Progress bar direction (x or y) -- @tparam number init_value Initial value of progress bar function M.init(self, node, key, init_value) - if key ~= const.SIDE.X and key ~= const.SIDE.Y then - settings.log("progress component: key must be 'x' or 'y'. Passed:", key) - key = const.SIDE.X - end + assert(key == const.SIDE.X or const.SIDE.Y, "Progress bar key should be 'x' or 'y'") self.prop = hash("scale."..key) self.key = key + self.style = helper.get_style(self, "PROGRESS") self.node = helper.node(node) self.scale = gui.get_scale(self.node) self.size = gui.get_size(self.node) @@ -152,8 +148,8 @@ end function M.update(self, dt) if self.target then local prev_value = self.last_value - local step = math.abs(self.last_value - self.target) * (p_settings.SPEED*dt) - step = math.max(step, p_settings.MIN_DELTA) + local step = math.abs(self.last_value - self.target) * (self.style.SPEED*dt) + step = math.max(step, self.style.MIN_DELTA) self:set_to(helper.step(self.last_value, self.target, step)) if self.last_value == self.target then diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index e3e79ee..fa5d169 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -3,7 +3,6 @@ local helper = require("druid.helper") local const = require("druid.const") -local settings = require("druid.settings").scroll local M = {} @@ -18,10 +17,12 @@ M.current_scroll = nil function M.init(self, scroll_parent, input_zone, border) + self.style = helper.get_style(self, "SCROLL") self.node = helper.node(scroll_parent) self.input_zone = helper.node(input_zone) + self.zone_size = gui.get_size(self.input_zone) - self.soft_size = settings.SOFT_ZONE_SIZE + self.soft_size = self.style.SOFT_ZONE_SIZE -- Distance from node to node's center local offset = helper.get_pivot_offset(gui.get_pivot(self.input_zone)) @@ -61,16 +62,16 @@ local function check_soft_target(self) local b = self.border if t.y < b.y then - t.y = helper.step(t.y, b.y, math.abs(t.y - b.y) * settings.BACK_SPEED) + t.y = helper.step(t.y, b.y, math.abs(t.y - b.y) * self.style.BACK_SPEED) end if t.x < b.x then - t.x = helper.step(t.x, b.x, math.abs(t.x - b.x) * settings.BACK_SPEED) + t.x = helper.step(t.x, b.x, math.abs(t.x - b.x) * self.style.BACK_SPEED) end if t.y > b.w then - t.y = helper.step(t.y, b.w, math.abs(t.y - b.w) * settings.BACK_SPEED) + t.y = helper.step(t.y, b.w, math.abs(t.y - b.w) * self.style.BACK_SPEED) end if t.x > b.z then - t.x = helper.step(t.x, b.z, math.abs(t.x - b.z) * settings.BACK_SPEED) + t.x = helper.step(t.x, b.z, math.abs(t.x - b.z) * self.style.BACK_SPEED) end end @@ -94,8 +95,8 @@ local function update_hand_scroll(self, dt) inert.x = math.abs(inert.x) * helper.sign(delta_x) inert.y = math.abs(inert.y) * helper.sign(delta_y) - inert.x = inert.x * settings.FRICT_HOLD - inert.y = inert.y * settings.FRICT_HOLD + inert.x = inert.x * self.style.FRICT_HOLD + inert.y = inert.y * self.style.FRICT_HOLD set_pos(self, self.target) end @@ -116,11 +117,11 @@ local function check_points(self) local inert = self.inert if not self.is_inert then - if math.abs(inert.x) > settings.DEADZONE then + if math.abs(inert.x) > self.style.DEADZONE then self:scroll_to_index(self.selected - helper.sign(inert.x)) return end - if math.abs(inert.y) > settings.DEADZONE then + if math.abs(inert.y) > self.style.DEADZONE then self:scroll_to_index(self.selected + helper.sign(inert.y)) return end @@ -154,13 +155,14 @@ local function check_points(self) temp_dist_on_inert = dist end end + self:scroll_to_index(index_on_inert or index) end local function check_threshold(self) local inert = self.inert - if not self.is_inert or vmath.length(inert) < settings.INERT_THRESHOLD then + if not self.is_inert or vmath.length(inert) < self.style.INERT_THRESHOLD then check_points(self) inert.x = 0 inert.y = 0 @@ -171,11 +173,11 @@ end local function update_free_inert(self, dt) local inert = self.inert if inert.x ~= 0 or inert.y ~= 0 then - self.target.x = self.pos.x + (inert.x * dt * settings.INERT_SPEED) - self.target.y = self.pos.y + (inert.y * dt * settings.INERT_SPEED) + self.target.x = self.pos.x + (inert.x * dt * self.style.INERT_SPEED) + self.target.y = self.pos.y + (inert.y * dt * self.style.INERT_SPEED) - inert.x = inert.x * settings.FRICT - inert.y = inert.y * settings.FRICT + inert.x = inert.x * self.style.FRICT + inert.y = inert.y * self.style.FRICT -- Stop, when low inert speed and go to points check_threshold(self) @@ -213,6 +215,7 @@ local function add_delta(self, dx, dy) local t = self.target local b = self.border local soft = self.soft_size + -- TODO: Can we calc it more easier? -- A lot of calculations for every side of border @@ -275,7 +278,7 @@ function M.on_input(self, action_id, action) self.target.y = self.pos.y else local dist = helper.distance(action.x, action.y, inp.start_x, inp.start_y) - if not M.current_scroll and dist >= settings.DEADZONE then + if not M.current_scroll and dist >= self.style.DEADZONE then local dx = math.abs(inp.start_x - action.x) local dy = math.abs(inp.start_y - action.y) inp.side = (dx > dy) and const.SIDE.X or const.SIDE.Y @@ -331,7 +334,7 @@ function M.scroll_to(self, point, is_instant) self.target = target set_pos(self, target) else - gui.animate(self.node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, settings.ANIM_SPEED, 0, function() + gui.animate(self.node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() self.animate = false self.target = target set_pos(self, target) diff --git a/druid/druid.lua b/druid/druid.lua index ce533c3..3f9e40f 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -4,14 +4,19 @@ -- to create your own rich components. -- @module druid + local const = require("druid.const") local druid_input = require("druid.helper.druid_input") local settings = require("druid.settings") local M = {} + local log = settings.log local _fct_metatable = {} +-- Temporary, what the place for it? +local default_style = {} + --- Basic components M.comps = { @@ -57,9 +62,9 @@ function M.register(name, module) end ---- Create UI instance for ui elements +--- Create Druid instance for creating components -- @return instance with all ui components -function M.new(component_script) +function M.new(component_script, style) if register_basic_components then register_basic_components() register_basic_components = false @@ -68,10 +73,16 @@ function M.new(component_script) -- Druid context here (who created druid) -- Usually gui_script, but can be component from helper.get_druid(component) self._context = component_script + self._style = style or default_style return self end +function M.set_default_style(style) + default_style = style +end + + local function input_init(self) if not self.input_inited then self.input_inited = true @@ -80,10 +91,12 @@ local function input_init(self) end +-- Create the component local function create(self, module) local instance = setmetatable({}, { __index = module }) -- Component context, self from component creation instance.context = self._context + instance.druid_style = self._style table.insert(self, instance) local register_to = module.interest diff --git a/druid/helper.lua b/druid/helper.lua index 1a3a893..5c66d14 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -1,10 +1,12 @@ --- Druid helper module -- @module helper + local const = require("druid.const") local M = {} + --- Text node or icon node can be nil local function get_text_width(text_node) if text_node then @@ -154,4 +156,13 @@ function M.get_druid(self) end +function M.get_style(self, section) + if not self.druid_style then + return {} + end + + return self.druid_style[section] or {} +end + + return M diff --git a/druid/rich/progress_rich.lua b/druid/rich/progress_rich.lua index 793c9d5..277e435 100644 --- a/druid/rich/progress_rich.lua +++ b/druid/rich/progress_rich.lua @@ -2,14 +2,13 @@ -- @module rich.progress_rich local helper = require("druid.helper") -local settings = require("druid.settings") -local pr_settings = settings.progress_rich local M = {} function M.init(self, name, red, green, key) self.druid = helper.get_druid(self) + self.style = helper.get_style(self, "PROGRESS_RICH") self.red = self.druid:new_progress(red, key) self.green = self.druid:new_progress(green, key) self.fill = self.druid:new_progress(name, key) @@ -51,7 +50,7 @@ function M.to(self, to, callback) if self.fill.last_value < to then self.red:to(self.fill.last_value) self.green:to(to, function() - self.timer = timer.delay(pr_settings.DELAY, false, function() + self.timer = timer.delay(self.style.DELAY, false, function() self.red:to(to) self.fill:to(to, callback) end) @@ -61,7 +60,7 @@ function M.to(self, to, callback) if self.fill.last_value > to then self.green:to(self.red.last_value) self.fill:to(to, function() - self.timer = timer.delay(pr_settings.DELAY, false, function() + self.timer = timer.delay(self.style.DELAY, false, function() self.green:to(to) self.red:to(to, callback) end) diff --git a/druid/settings.lua b/druid/settings.lua index d0b51d5..3529af5 100644 --- a/druid/settings.lua +++ b/druid/settings.lua @@ -3,37 +3,9 @@ local M = {} --- TODO: to JSON? + M.is_debug = false -M.button = { - IS_HOVER = true, - IS_HOLD = true, - BTN_SOUND = "click", - BTN_SOUND_DISABLED = "click_disabled", - HOVER_SCALE = vmath.vector3(-0.025, -0.025, 1), - HOVER_TIME = 0.05, - SCALE_CHANGE = vmath.vector3(-0.05, - 0.05, 1), -} -M.progress = { - SPEED = 5, -- progress bar fill rate, more faster - MIN_DELTA = 0.005 -} - -M.progress_rich = { - DELAY = 1, -- delay in seconds before main fill -} - -M.scroll = { - FRICT_HOLD = 0.8, -- mult. for inert, while touching - FRICT = 0.93, -- mult for free inert - INERT_THRESHOLD = 2, -- speed to stop inertion - INERT_SPEED = 25, -- koef. of inert speed - DEADZONE = 6, -- in px - SOFT_ZONE_SIZE = 160, -- size of outside zone (back move) - BACK_SPEED = 0.2, -- lerp speed - ANIM_SPEED = 0.3, -- gui.animation speed to point -} function M.get_text(name) -- override to get text for localized text diff --git a/druid/styles/bounce/anims.lua b/druid/styles/bounce/anims.lua new file mode 100644 index 0000000..bb642a6 --- /dev/null +++ b/druid/styles/bounce/anims.lua @@ -0,0 +1,26 @@ +local ui_animate = require("druid.helper.druid_animate") + + +local M = {} + + +function M.back_scale_animation(self, node, target_scale) + ui_animate.scale_to(self, node, target_scale) +end + + +function M.tap_scale_animation(self, node, target_scale) + ui_animate.scale_to(self, node, target_scale, + function() + M.back_scale_animation(self, node, self.scale_from) + end + ) +end + + +function M.hover_scale(self, target, time) + ui_animate.scale(self, self.anim_node, target, time) +end + + +return M diff --git a/druid/styles/bounce/style.lua b/druid/styles/bounce/style.lua new file mode 100644 index 0000000..2acd7e9 --- /dev/null +++ b/druid/styles/bounce/style.lua @@ -0,0 +1,77 @@ +local settings = require("druid.settings") +local anims = require("druid.styles.bounce.anims") + +local M = {} + + +M.BUTTON = { + HOVER_SCALE = vmath.vector3(-0.025, -0.025, 1), + HOVER_TIME = 0.05, + SCALE_CHANGE = vmath.vector3(-0.05, - 0.05, 1), + BTN_SOUND = "click", + BTN_SOUND_DISABLED = "click", + DISABLED_COLOR = vmath.vector4(0, 0, 0, 1), + ENABLED_COLOR = vmath.vector4(1), + IS_HOVER = true, + + on_hover = function(self, node, state) + if self.hover_anim then + local scale_to = self.scale_from + M.BUTTON.HOVER_SCALE + + local target_scale = state and scale_to or self.scale_from + anims.hover_scale(self, target_scale, M.BUTTON.HOVER_TIME) + end + end, + + on_click = function(self, node) + local scale_to = self.scale_from + M.BUTTON.SCALE_CHANGE + anims.tap_scale_animation(self, node, scale_to) + settings.play_sound(M.BUTTON.BTN_SOUND) + end, + + on_click_disabled = function(self, node) + settings.play_sound(M.BUTTON.BTN_SOUND_DISABLED) + end, + + on_set_enabled = function(self, node, state) + if state then + gui.set_color(node, M.BUTTON.ENABLED_COLOR) + else + gui.set_color(node, M.BUTTON.DISABLED_COLOR) + end + end +} + + +M.SCROLL = { + FRICT_HOLD = 0.8, -- mult. for inert, while touching + FRICT = 0.93, -- mult for free inert + INERT_THRESHOLD = 2, -- speed to stop inertion + INERT_SPEED = 25, -- koef. of inert speed + DEADZONE = 6, -- in px + SOFT_ZONE_SIZE = 160, -- size of outside zone (back move) + BACK_SPEED = 0.2, -- lerp speed + ANIM_SPEED = 0.3, -- gui.animation speed to point +} + + +M.PROGRESS = { + SPEED = 5, -- progress bar fill rate, more faster + MIN_DELTA = 0.005 +} + + +M.PROGRESS_RICH = { + DELAY = 1, -- delay in seconds before main fill +} + + +M.CHECKBOX = { + on_change_state = function(self, node, state) + local target = state and 1 or 0 + gui.animate(node, "color.w", target, gui.EASING_OUTSINE, 0.1) + end +} + + +return M diff --git a/druid/styles/empty/style.lua b/druid/styles/empty/style.lua new file mode 100644 index 0000000..10f627d --- /dev/null +++ b/druid/styles/empty/style.lua @@ -0,0 +1,43 @@ +local M = {} + + +M.BUTTON = { + BTN_SOUND = "click", + BTN_SOUND_DISABLED = "click", + DISABLED_COLOR = vmath.vector4(0, 0, 0, 1), + ENABLED_COLOR = vmath.vector4(1), + IS_HOVER = false, +} + + +M.SCROLL = { + FRICT_HOLD = 0, -- mult. for inert, while touching + FRICT = 0, -- mult for free inert + INERT_THRESHOLD = 2, -- speed to stop inertion + INERT_SPEED = 0, -- koef. of inert speed + DEADZONE = 6, -- in px + SOFT_ZONE_SIZE = 20, -- size of outside zone (back move) + BACK_SPEED = 0, -- lerp speed + ANIM_SPEED = 0, -- gui.animation speed to point +} + + +M.PROGRESS = { + SPEED = 5, -- progress bar fill rate, more faster + MIN_DELTA = 1 +} + + +M.PROGRESS_RICH = { + DELAY = 0, -- delay in seconds before main fill +} + + +M.CHECKBOX = { + on_change_state = function(self, node, state) + gui.set_enabled(node, state) + end +} + + +return M diff --git a/example/example.gui.gui_script b/example/example.gui.gui_script index 1acb004..b640db7 100644 --- a/example/example.gui.gui_script +++ b/example/example.gui.gui_script @@ -58,7 +58,7 @@ local function init_progress(self) local simple = self.druid:new_progress("simple_fill", "x", val) local vert = self.druid:new_progress("simple_vert_fill", "y", val) - simple:set_steps({0, 0.3, 0.6, 1}, function(self, step) + simple:set_steps({0, 0.3, 0.6, 1}, function(_, step) print("STEP:", step) end) diff --git a/example/kenney/gui/main/main.gui_script b/example/kenney/gui/main/main.gui_script index 9734c99..c0b923b 100644 --- a/example/kenney/gui/main/main.gui_script +++ b/example/kenney/gui/main/main.gui_script @@ -1,4 +1,6 @@ local druid = require("druid.druid") +local bounce_style = require("druid.styles.bounce.style") +local empty_style = require("druid.styles.empty.style") local main_page = require("example.kenney.page.main") @@ -15,6 +17,7 @@ end function init(self) + druid.set_default_style(empty_style) self.druid = druid.new(self) init_top_panel(self) diff --git a/example/kenney/page/main.lua b/example/kenney/page/main.lua index 7c00641..225f1cb 100644 --- a/example/kenney/page/main.lua +++ b/example/kenney/page/main.lua @@ -17,8 +17,11 @@ end local function setup_button(self) - self.druid:new_button("button_simple", lang.toggle_locale, "button_param") - self.druid:new_button("button_template/button", empty_callback, "button_param") + local b = self.druid:new_button("button_simple", lang.toggle_locale, "button_param") + self.druid:new_button("button_template/button", function() + print(b:get_enabled()) + b:set_enabled(not b:get_enabled()) + end, "button_param") end