First dirty commit of old code

This commit is contained in:
Alexey Gulev 2019-03-25 21:11:38 +01:00
parent e7ab5ec934
commit 00e984efdc
22 changed files with 1650 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
/.internal
/build
.externalToolBuilders
.DS_Store
Thumbs.db
.lock-wscript
*.pyc
.project
.cproject
builtins

View File

@ -1,2 +1,14 @@
# druid
Defold UI library
This project was created from the "empty" project template.
The settings in ["game.project"](defold://open?path=/game.project) are all the default. A bootstrap empty ["main.collection"](defold://open?path=/main/main.collection) is included.
Check out [the documentation pages](https://defold.com/learn) for examples, tutorials, manuals and API docs.
If you run into trouble, help is available in [our forum](https://forum.defold.com).
Happy Defolding!
---

View File

@ -0,0 +1,11 @@
local M = {}
--- input handler
-- @param action_id - input action id
-- @param action - input action
function M.on_input(instance, action_id, action)
instance.callback(instance.parent.parent)
return true
end
return M

119
druid/components/button.lua Normal file
View File

@ -0,0 +1,119 @@
local M = {}
local ui_animate = require "modules.ui.ui_animate"
M.DEFAULT_SCALE_CHANGE = vmath.vector3(-0.05, - 0.1, 1)
M.DEFAULT_POS_CHANGE = vmath.vector3(0, - 10, 0)
M.DEFAULT_MOVE_SPEED = 5
M.DEFAULT_ALPHA_DOWN = 0.8
M.DEFAULT_TIME_ANIM = 0.1
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.DEFAUL_ACTIVATION_TIME = 0.2
--- Set text to text field
-- @param action_id - input action id
-- @param action - input action
function M.on_input(instance, action_id, action)
if gui.is_enabled(instance.node) and gui.pick_node(instance.node, action.x, action.y) then
if not instance.disabled then
instance.tap_anim(instance)
return true
else
instance.sound_disable()
return false
end
end
return false
end
function M.tap_scale_animation(instance)
ui_animate.scale_to(instance, instance.anim_node, instance.scale_to,
function()
if instance.back_anim then
instance.back_anim(instance)
end
instance.sound()
instance.callback(instance.parent.parent, instance.params, instance)
end
)
end
function M.back_scale_animation(instance)
ui_animate.scale_to(instance, instance.anim_node, instance.scale_from)
end
function M.tap_tab_animation(instance, force)
ui_animate.alpha(instance, instance.anim_node, M.DEFAULT_ALPHA_DOWN, nil, M.DEFAULT_TIME_ANIM)
ui_animate.fly_to(instance, instance.anim_node, instance.pos + M.DEFAULT_POS_CHANGE, M.DEFAULT_MOVE_SPEED)
ui_animate.scale_to(instance, instance.anim_node, instance.scale_to,
function()
if instance.back_anim then
instance.back_anim(instance)
end
instance.callback(instance.parent.parent, instance.params, force)
end
)
end
function M.back_tab_animation(instance)
ui_animate.alpha(instance, instance.anim_node, 1, nil, M.DEFAULT_TIME_ANIM)
ui_animate.fly_to(instance, instance.anim_node, instance.pos, M.DEFAULT_MOVE_SPEED)
ui_animate.scale_to(instance, instance.anim_node, instance.scale_from)
end
function M.deactivate(instance, is_animate, callback)
instance.disabled = true
if is_animate then
local counter = 0
local clbk = function()
counter = counter + 1
if counter == 3 and callback then
callback(instance.parent.parent)
end
end
ui_animate.color(instance, instance.node, M.DEFAULT_DEACTIVATE_COLOR, clbk, M.DEFAUL_ACTIVATION_TIME, 0,
gui.EASING_OUTBOUNCE)
ui_animate.scale_y_from_to(instance, instance.node, M.DEFAULT_ACTIVATE_SCALE.x, M.DEFAULT_DEACTIVATE_SCALE.x, clbk,
M.DEFAUL_ACTIVATION_TIME, gui.EASING_OUTBOUNCE)
ui_animate.scale_x_from_to(instance, instance.node, M.DEFAULT_ACTIVATE_SCALE.y, M.DEFAULT_DEACTIVATE_SCALE.y, clbk,
M.DEFAUL_ACTIVATION_TIME, gui.EASING_OUTBOUNCE)
else
gui.set_color(instance.node, M.DEFAULT_DEACTIVATE_COLOR)
gui.set_scale(instance.node, M.DEFAULT_DEACTIVATE_SCALE)
if callback then
callback(instance.parent.parent)
end
end
end
function M.activate(instance, is_animate, callback)
if is_animate then
local counter = 0
local clbk = function()
counter = counter + 1
if counter == 3 then
instance.disabled = false
if callback then
callback(instance.parent.parent)
end
end
end
ui_animate.color(instance, instance.node, ui_animate.TINT_SHOW, clbk, M.DEFAUL_ACTIVATION_TIME, 0,
gui.EASING_OUTBOUNCE)
ui_animate.scale_y_from_to(instance, instance.node, M.DEFAULT_DEACTIVATE_SCALE.x, M.DEFAULT_ACTIVATE_SCALE.x, clbk,
M.DEFAUL_ACTIVATION_TIME, gui.EASING_OUTBOUNCE)
ui_animate.scale_x_from_to(instance, instance.node, M.DEFAULT_DEACTIVATE_SCALE.y, M.DEFAULT_ACTIVATE_SCALE.y, clbk,
M.DEFAUL_ACTIVATION_TIME, gui.EASING_OUTBOUNCE)
else
gui.set_color(instance.node, ui_animate.TINT_SHOW)
gui.set_scale(instance.node, M.DEFAULT_ACTIVATE_SCALE)
instance.disabled = false
if callback then
callback(instance.parent.parent)
end
end
end
return M

View File

@ -0,0 +1,67 @@
local M = {}
local text_field = require "modules.ui.components.text_field"
local FRAMES = 60
--- Bounce text field
M.bounce = text_field.bounce
--- Set text to text field
-- @param set_to - set value to text field
M.set_to = text_field.set_to
--- Set color
-- @param color
M.set_color = text_field.set_color
--- Set scale
-- @param scale
M.set_scale = text_field.set_scale
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
text_field.on_layout_updated(instance)
if instance.last_value then
text_field.set_to(instance, instance.last_value)
end
end
--- Animate counter
-- @param set_to - set value to text field
function M.animate_to(instance, set_to, frames)
if set_to == instance.last_value then
text_field.set_to(instance, set_to)
elseif not instance.is_animate then
frames = frames or FRAMES
instance.end_anim_value = set_to
local diff = set_to - instance.last_value
instance.anim_step = math.floor((set_to - instance.last_value) / frames)
if diff ~= 0 and instance.anim_step == 0 then
instance.anim_step = diff > 0 and 1 or - 1
end
instance.is_animate = true
else
instance.end_anim_value = set_to
end
end
--- Called when update
-- @param dt - delta time
function M.on_updated(instance, dt)
if instance.is_animate then
instance.last_value = instance.last_value + instance.anim_step
text_field.set_to(instance, instance.last_value)
if not instance.is_in_bounce then
instance.is_in_bounce = true
text_field.bounce(instance, function() instance.is_in_bounce = false end)
end
if instance.anim_step > 0 and instance.last_value >= instance.end_anim_value or
instance.anim_step < 0 and instance.last_value <= instance.end_anim_value then
instance.is_animate = false
text_field.set_to(instance, instance.end_anim_value)
end
end
end
return M

View File

@ -0,0 +1,52 @@
local M = {}
local ui_animate = require "modules.ui.ui_animate"
local function fly_to(instance, pos_from, speed, callback)
local pos_to = instance.get_pos_func()
instance.last_speed = speed
instance.last_callback = callback
instance.last_particle = instance.last_particle + 1
if instance.last_particle > #instance.fly_particles then
instance.last_particle = 1
end
local fly_particle = instance.fly_particles[instance.last_particle]
if pos_from then
gui.set_position(fly_particle, pos_from)
end
gui.play_particlefx(fly_particle)
instance.is_anim = true
ui_animate.fly_to(nil, fly_particle, pos_to, speed,
function()
instance.is_anim = false
gui.stop_particlefx(fly_particle)
if callback then
callback(instance.parent.parent)
instance.last_callback = nil
end
end,
0, gui.EASING_INSINE)
end
--- Start animation of a flying particles
-- @param pos_from - fly from this position
-- @param speed - speed of flying
-- @param callback - callback when progress ended if need
function M.fly_to(instance, pos_from, speed, callback)
fly_to(instance, pos_from, speed, callback)
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
if instance.is_anim then
instance.last_particle = instance.last_particle - 1
if instance.last_particle < 1 then
instance.last_particle = #instance.fly_particles
end
fly_to(instance, nil, instance.last_speed, instance.last_callback)
end
end
return M

View File

@ -0,0 +1,46 @@
local M = {}
local ui_animate = require "modules.ui.ui_animate"
--- Bounce image
function M.bounce(instance)
gui.set_scale(instance.node, instance.scale_from)
ui_animate.bounce(nil, instance.node, instance.scale_to)
end
--- Set image anim
-- @param set_to - index of animation or animation name
function M.set_to(instance, set_to)
instance.last_value = set_to
gui.play_flipbook(instance.node, instance.anim_table and instance.anim_table[set_to] or set_to)
end
--- Set position to the image
-- @param pos - set position of the image
function M.set_pos(instance, pos)
instance.last_pos = pos
gui.set_position(instance.node, pos)
end
--- Set tint to the image
-- @param color - set color of the image
function M.set_color(instance, color)
instance.last_color = color
gui.set_color(instance.node, color)
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
if instance.last_value then
M.set_to(instance, instance.last_value)
end
if instance.last_pos then
M.set_pos(instance, instance.last_pos)
end
if instance.last_color then
M.set_color(instance, instance.last_color)
end
end
return M

View File

@ -0,0 +1,51 @@
local M = {}
local FULL_FILL = 360
local function set_bar_to(instance, set_to)
instance.last_value = set_to
gui.cancel_animation(instance.node, gui.PROP_FILL_ANGLE)
gui.set_fill_angle(instance.node, FULL_FILL * set_to)
end
--- Fill a pie progress bar and stop progress animation
function M.fill_bar(instance)
set_bar_to(instance, 1)
end
--- To empty a pie progress bar
function M.empty_bar(instance)
set_bar_to(instance, 0)
end
--- Set fill a pie progress bar to value
-- @param to - value between 0..1
function M.set_to(instance, to)
set_bar_to(instance, to)
end
--- Start animation of a pie progress bar
-- @param to - value between 0..1
-- @param duration - time of animation
-- @param callback - callback when progress ended if need
function M.start_progress_to(instance, to, duration, callback)
instance.is_anim = true
instance.last_value = to
gui.animate(instance.node, gui.PROP_FILL_ANGLE, FULL_FILL * to, gui.EASING_LINEAR, duration, 0,
function()
instance.is_anim = false
if callback then
callback(instance.parent.parent)
end
end
)
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
if not instance.is_anim then
set_bar_to(instance, instance.last_value)
end
end
return M

View File

@ -0,0 +1,93 @@
local M = {}
local function set_bar_to(instance, set_to)
instance.last_value = set_to
gui.cancel_animation(instance.node, instance.prop)
instance.scale[instance.key] = set_to
gui.set_scale(instance.node, instance.scale)
end
local function circle_anim(instance, full, steps, num, full_duration, callback)
local duration = (math.abs(steps[num - 1] - steps[num]) / full) * full_duration
local to = steps[num]
gui.animate(instance.node, instance.prop, to, gui.EASING_LINEAR, duration, 0,
function()
callback(num, callback)
end
)
end
--- Fill a progress bar and stop progress animation
function M.fill_bar(instance)
set_bar_to(instance, 1)
end
--- To empty a progress bar
function M.empty_bar(instance)
set_bar_to(instance, 0)
end
--- Set fill a progress bar to value
-- @param to - value between 0..1
function M.set_to(instance, to)
set_bar_to(instance, to)
end
--- Start animation of a progress bar
-- @param to - value between 0..1
-- @param duration - time of animation
-- @param callback - callback when progress ended if need
-- @param callback_values - whitch values should callback
function M.start_progress_to(instance, to, duration, callback, callback_values)
instance.is_anim = true
local steps
if callback_values then
steps = {instance.last_value}
if instance.last_value > to then
table.sort(callback_values, function(a, b) return a > b end)
else
table.sort(callback_values, function(a, b) return a < b end)
end
for i, v in ipairs(callback_values) do
if (instance.last_value > v and to < v) or (instance.last_value < v and to > v) then
steps[#steps + 1] = v
end
end
steps[#steps + 1] = to
end
if not steps then
gui.animate(instance.node, instance.prop, to, gui.EASING_LINEAR, duration, 0,
function()
set_bar_to(instance, to)
instance.is_anim = false
if callback then
callback(instance.parent.parent, to)
end
end
)
else
local full = math.abs(steps[1] - steps[#steps])
local _callback = function (num, _callback)
if num == #steps then
set_bar_to(instance, steps[num])
instance.is_anim = false
callback(instance.parent.parent, steps[num])
else
callback(instance.parent.parent, steps[num])
num = num + 1
circle_anim(instance, full, steps, num, duration, _callback)
end
end
circle_anim(instance, full, steps, 2, duration, _callback)
end
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
if not instance.is_anim then
set_bar_to(instance, instance.last_value)
end
end
return M

View File

@ -0,0 +1,237 @@
local M = {}
local input = require "modules.input.input"
local ui_animate = require "modules.ui.ui_animate"
local extra_math = require "modules.utils.extra_math"
M.START = hash("START")
M.FINISH = hash("FINISH")
M.SCROLLING = hash("SCROLLING")
M.INTEREST_MOVE = hash("INTEREST_MOVE")
M.OUT_OF_ZONE_MOVE = hash("OUT_OF_ZONE_MOVE")
M.BACK_TIME = 0.2
M.ANIM_TIME = 0.4
local function callback(instance, event, type, param)
if instance.callback then
instance.callback(instance.parent.parent, event, type, param)
end
end
local function checkSwipeDirection(swipe, action)
swipe.xDistance = math.abs(swipe.endX - swipe.beginX)
swipe.yDistance = math.abs(swipe.endY - swipe.beginY)
if swipe.is_x and swipe.xDistance > swipe.yDistance then
if swipe.beginX > swipe.endX then
swipe.totalSwipeDistanceLeft = swipe.beginX - swipe.endX
if swipe.totalSwipeDistanceLeft > swipe.minSwipeDistance then
swipe.speed.x = action.dx * swipe.speed_up_coef.x * swipe.end_move_coef_x
return true
else
return false
end
else
swipe.totalSwipeDistanceRight = swipe.endX - swipe.beginX
if swipe.totalSwipeDistanceRight > swipe.minSwipeDistance then
swipe.speed.x = action.dx * swipe.speed_up_coef.x * swipe.end_move_coef_x
return true
else
return false
end
end
elseif swipe.is_y and swipe.xDistance < swipe.yDistance then
if swipe.beginY > swipe.endY then
swipe.totalSwipeDistanceUp = swipe.beginY - swipe.endY
if swipe.totalSwipeDistanceUp > swipe.minSwipeDistance then
swipe.speed.y = action.dy * swipe.speed_up_coef.y * swipe.end_move_coef_y
return true
else
return false
end
else
swipe.totalSwipeDistanceDown = swipe.endY - swipe.beginY
if swipe.totalSwipeDistanceDown > swipe.minSwipeDistance then
swipe.speed.y = action.dy * swipe.speed_up_coef.y * swipe.end_move_coef_y
return true
else
return false
end
end
end
end
local function back_move(instance)
if not instance.swipe.end_position_x and not instance.swipe.end_position_y then
if instance.points_of_interest then
local min_index, min_lenght = 0, math.huge
local len
for k, v in pairs(instance.points_of_interest) do
len = extra_math.lenght(instance.pos.x, instance.pos.y, v.x, v.y)
if len < min_lenght then
min_lenght = len
min_index = k
end
end
instance.swipe.speed.x = 0
instance.swipe.speed.y = 0
gui.cancel_animation(instance.node, gui.PROP_POSITION)
instance.swipe.special_move = true
callback(instance, M.START, M.INTEREST_MOVE, instance.points_of_interest[min_index])
gui.animate(instance.node, gui.PROP_POSITION, instance.points_of_interest[min_index],
gui.EASING_LINEAR, M.ANIM_TIME, 0,
function()
instance.swipe.special_move = false
instance.pos.x = instance.points_of_interest[min_index].x
instance.pos.y = instance.points_of_interest[min_index].y
callback(instance, M.FINISH, M.SCROLLING, instance.pos)
callback(instance, M.FINISH, M.INTEREST_MOVE, instance.pos)
end
)
else
callback(instance, M.FINISH, M.SCROLLING, instance.pos)
end
end
if instance.swipe.end_position_x then
local swipe = instance.swipe
swipe.speed.x = 0
instance.pos.x = swipe.end_position_x
swipe.special_move = true
callback(instance, M.START, M.OUT_OF_ZONE_MOVE, instance.pos)
gui.animate(instance.node, ui_animate.PROP_POS_X, swipe.end_position_x, gui.EASING_INSINE, M.BACK_TIME, 0,
function()
swipe.special_move = false
callback(instance, M.FINISH, M.SCROLLING, instance.pos)
callback(instance, M.FINISH, M.OUT_OF_ZONE_MOVE, instance.pos)
end
)
swipe.end_position_x = nil
end
if instance.swipe.end_position_y then
local swipe = instance.swipe
swipe.speed.y = 0
instance.pos.y = swipe.end_position_y
swipe.special_move = true
callback(instance, M.START, M.OUT_OF_ZONE_MOVE, instance.pos)
gui.animate(instance.node, ui_animate.PROP_POS_Y, swipe.end_position_y, gui.EASING_INSINE, M.BACK_TIME, 0,
function()
swipe.special_move = false
callback(instance, M.FINISH, M.SCROLLING, instance.pos)
callback(instance, M.FINISH, M.OUT_OF_ZONE_MOVE, instance.pos)
end
)
swipe.end_position_y = nil
end
end
--- Set text to text field
-- @param action_id - input action id
-- @param action - input action
function M.on_input(instance, action_id, action)
if action_id == input.A_CLICK then
if gui.pick_node(instance.scrolling_zone, action.x, action.y) then
local swipe = instance.swipe
if action.pressed then
swipe.pressed = true
swipe.beginX = action.x
swipe.beginY = action.y
input.is_swipe = false
swipe.end_move_coef_x = 1
elseif not action.released and not action.pressed and not swipe.special_move then
swipe.endX = action.x
swipe.endY = action.y
local before = swipe.is_swipe
swipe.is_swipe = checkSwipeDirection(swipe, action)
if not before and swipe.is_swipe and not swipe.special_move and not swipe.waiting_for_back_move then
callback(instance, M.START, M.SCROLLING, instance.pos)
end
return swipe.is_swipe or swipe.special_move
elseif action.released then
swipe.beginX = 0
swipe.beginY = 0
swipe.endX = 0
swipe.endY = 0
swipe.pressed = false
if swipe.waiting_for_back_move then
back_move(instance)
swipe.waiting_for_back_move = false
end
return swipe.is_swipe or swipe.special_move
end
elseif action.released then
instance.swipe.pressed = false
if instance.swipe.waiting_for_back_move then
back_move(instance)
instance.swipe.waiting_for_back_move = false
end
end
end
end
--- Called when update
-- @param dt - delta time
function M.on_updated(instance, dt)
if instance.swipe.speed.x ~= 0 or instance.swipe.speed.y ~= 0 then
local swipe = instance.swipe
instance.pos.x = instance.pos.x + swipe.speed.x
instance.pos.y = instance.pos.y + swipe.speed.y
if instance.pos.x < instance.start_pos.x then
swipe.end_move_coef_x = swipe.back_slow_coef
swipe.end_position_x = instance.start_pos.x
elseif instance.pos.x > instance.maximum.x then
swipe.end_move_coef_x = swipe.back_slow_coef
swipe.end_position_x = instance.maximum.x
else
swipe.end_move_coef_x = 1
swipe.end_position_x = nil
end
if instance.pos.y < instance.start_pos.y then
swipe.end_move_coef_y = swipe.back_slow_coef
swipe.end_position_y = instance.start_pos.y
elseif instance.pos.y > instance.maximum.y then
swipe.end_move_coef_y = swipe.back_slow_coef
swipe.end_position_y = instance.maximum.y
else
swipe.end_move_coef_y = 1
swipe.end_position_y = nil
end
gui.set_position(instance.node, instance.pos)
swipe.speed.x = swipe.speed.x / swipe.speed_down_coef * swipe.end_move_coef_x
swipe.speed.y = swipe.speed.y / swipe.speed_down_coef * swipe.end_move_coef_y
if swipe.speed.x < swipe.min_speed and swipe.speed.x > - swipe.min_speed then
swipe.speed.x = 0
if not swipe.pressed then
back_move(instance)
else
swipe.waiting_for_back_move = true
end
if swipe.speed.y < swipe.min_speed and swipe.speed.y > - swipe.min_speed then
swipe.speed.y = 0
end
if swipe.speed.y == 0 and swipe.speed.x == 0 then
swipe.is_swipe = false
end
end
end
end
--- Scroll position to
-- @param pos - positon for set
-- @param is_animate - is animated set
function M.scroll_to(instance, pos, is_animate, cb, time_scrolling)
local time = is_animate and M.ANIM_TIME or 0
time = time_scrolling or time
instance.pos.x = pos.x
instance.pos.y = pos.y
gui.animate(instance.node, gui.PROP_POSITION, instance.pos, gui.EASING_INSINE, time, 0,
function()
if cb then
cb(instance.parent.parent)
end
end
)
end
return M

View File

@ -0,0 +1,62 @@
local M = {}
--- Set animation scene
-- @param scene - animations scene
function M.set_scene(instance, scene)
instance.last_scene = scene
gui.set_spine_scene(instance.node, scene)
end
--- Set idle animation
-- @param anim - idle animation name or index in idle table
-- @param properties - properties of the animation
function M.play_idle(instance, anim, properties)
if not anim then
return
end
anim = (instance.idle_table and instance.idle_table[anim]) and instance.idle_table[anim] or anim
instance.last_value = anim
properties = properties or {}
gui.play_spine_anim(instance.node, anim, gui.PLAYBACK_LOOP_FORWARD, properties)
end
--- Set active animation
-- @param anim - active animation name or index in active table
-- @param callback - call when animation done
-- @param idle_after - set idle after active anim
function M.play_active(instance, anim, callback, idle_after)
instance.is_play_now = true
anim = instance.active_table and instance.active_table[anim] or anim
instance.last_value = anim
instance.callback = callback
M.play_idle(instance, idle_after)
gui.play_spine_anim(instance.node, anim, gui.PLAYBACK_ONCE_FORWARD, {},
function()
M.play_idle(instance, idle_after)
instance.is_play_now = false
if callback then
callback(instance.parent.parent)
end
end
)
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
if instance.last_scene then
M.set_scene(instance, instance.last_scene)
end
if instance.last_value then
M.play_idle(instance, instance.last_value)
end
if instance.is_play_now then
instance.is_play_now = false
if instance.callback then
instance.callback(instance.parent.parent)
end
end
end
return M

View File

@ -0,0 +1,92 @@
--[[ Single tab screen module. Assumed to be used with Tab Bar module.
-- Create tab screen with parental gui node:
self.tab = tab.create "tab_bkg"
-- Show and hide tab manually:
self.tab.slide_in(self, vmath.vector3(0, -540, 0))
self.tab.slide_out(self, vmath.vector3(0, -540, 0))
-- Or receive show and hide messages:
function on_message(self, message_id, message, sender)
self.tab.on_message(self, message_id, message)
end
]]
local M = {}
M.T_SLIDE_IN = hash("t_slide_in")
M.T_SLIDE_OUT = hash("t_slide_out")
M.STATE_START = hash("state_start")
M.STATE_FINISH = hash("state_finish")
local ENABLE = hash("enable")
local DISABLE = hash("disable")
local PATH_COMP = "#"
M.DEFAULT_EASING = gui.EASING_INOUTQUAD
M.DEFAULT_DURATION = 0.3
function M.slide_in(instance, out_pos, is_force)
msg.post(PATH_COMP, ENABLE)
if instance.callback then
instance.callback(instance.parent.parent, instance, M.T_SLIDE_IN, M.STATE_START)
end
if is_force then
gui.set_position(instance.node, instance.in_pos)
if instance.callback then
instance.callback(instance.parent.parent, instance, M.T_SLIDE_IN, M.STATE_FINISH)
end
else
instance.in_action = true
out_pos = out_pos or instance.put_pos
gui.set_position(instance.node, out_pos or instance.out_pos)
gui.animate(instance.node, gui.PROP_POSITION, instance.in_pos, instance.easing, instance.duration, 0,
function()
instance.in_action = false
if instance.callback then
instance.callback(instance.parent.parent, instance, M.T_SLIDE_IN, M.STATE_FINISH)
end
end
)
end
end
function M.slide_out(instance, out_pos, is_force)
out_pos = out_pos or instance.put_pos
if instance.callback then
instance.callback(instance.parent.parent, instance, M.T_SLIDE_OUT, M.STATE_START)
end
if is_force then
gui.set_position(instance.node, out_pos)
if instance.callback then
instance.callback(instance.parent.parent, instance, M.T_SLIDE_OUT, M.STATE_FINISH)
end
msg.post(PATH_COMP, DISABLE)
else
instance.in_action = true
gui.set_position(instance.node, instance.in_pos)
gui.animate(instance.node, gui.PROP_POSITION, out_pos, instance.easing, instance.duration, 0,
function()
instance.in_action = false
if instance.callback then
instance.callback(instance.parent.parent, instance, M.T_SLIDE_OUT, M.STATE_FINISH)
end
msg.post(PATH_COMP, DISABLE)
end
)
end
end
function M.on_message(instance, message_id, message, sender)
if message_id == M.T_SLIDE_IN then
M.slide_in(instance, message.out_pos, message.is_force)
return true
elseif message_id == M.T_SLIDE_OUT then
M.slide_out(instance, message.out_pos, message.is_force)
return true
end
end
return M

View File

@ -0,0 +1,50 @@
local M = {}
local helper = require "modules.render.helper"
local tab_page = require "modules.ui.components.tab_page"
local DISABLE = hash("disable")
function M.update_sizes(instance, width)
width = width or helper.config_x
instance.left = vmath.vector3(width * - 1, 0, 0)
instance.right = vmath.vector3(width * 1, 0, 0)
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance, message)
local width = helper.settings_x
M.update_sizes(instance, width)
end
function M.switch_tab(instance, params, force)
if instance.current == params then
return
end
if instance.current then
instance.btns[instance.current.index]:manual_back()
end
local out_pos
if instance.current and instance.current.url then
out_pos = (instance.current and instance.current.index < params.index) and instance.left or instance.right
msg.post(instance.current.url, tab_page.T_SLIDE_OUT, { out_pos = out_pos, is_force = force })
end
if params and params.url then
out_pos = (instance.current and instance.current.index > params.index) and instance.left or instance.right
msg.post(params.url, tab_page.T_SLIDE_IN, { out_pos = out_pos, is_force = force })
instance.current = params
end
end
--- Select current tab manually
function M.select(instance, node_name)
for k, v in pairs(instance.btns) do
if k == instance[node_name].index then
v:tap_anim(true)
else
msg.post(instance[v.name].url, DISABLE)
end
end
end
return M

View File

@ -0,0 +1,42 @@
local M = {}
local ui_animate = require "modules.ui.ui_animate"
--- Bounce text field
function M.bounce(instance, callback)
gui.set_scale(instance.node, instance.scale_from)
ui_animate.bounce(nil, instance.node, instance.scale_to, callback)
end
--- Set text to text field
-- @param set_to - set value to text field
function M.set_to(instance, set_to)
instance.last_value = set_to
gui.set_text(instance.node, set_to)
end
--- Set color
-- @param color
function M.set_color(instance, color)
instance.last_color = color
gui.set_color(instance.node, color)
end
--- Set scale
-- @param scale
function M.set_scale(instance, scale)
instance.last_scale = scale
gui.set_scale(instance.node, scale)
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
if instance.last_color then
M.set_color(instance, instance.last_color)
end
if instance.last_scale then
M.set_scale(instance, instance.last_scale)
end
end
return M

View File

@ -0,0 +1,53 @@
local M = {}
local formats = require "modules.utils.formats"
--- Set text to text field
-- @param set_to - set value in seconds
function M.set_to(instance, set_to)
instance.last_value = set_to
gui.set_text(instance.node, formats.second_string_min(set_to))
end
--- Called when layout updated (rotate for example)
function M.on_layout_updated(instance)
M.set_to(instance, instance.last_value)
end
--- Called when update
-- @param is_on - boolean is timer on
function M.set_work_mode(instance, is_on)
instance.is_on = is_on
end
--- Set time interval
-- @param from - "from" time in seconds
-- @param to - "to" time in seconds
function M.set_interval(instance, from, to)
instance.second_from = from
instance.seconds_counter = from
instance.seconds_temp = 0
instance.seconds_to = to
instance.second_step = from < to and 1 or - 1
M.set_work_mode(instance, true)
M.set_to(instance, from)
end
--- Called when update
-- @param dt - delta time
function M.on_updated(instance, dt)
if instance.is_on then
instance.seconds_temp = instance.seconds_temp + dt
if instance.seconds_temp > 1 then
instance.seconds_temp = instance.seconds_temp - 1
instance.seconds_counter = instance.seconds_counter + instance.second_step
M.set_to(instance, instance.seconds_counter)
if instance.seconds_counter == instance.seconds_to then
instance.is_on = false
instance.callback(instance)
end
end
end
end
return M

25
druid/input.lua Normal file
View File

@ -0,0 +1,25 @@
local M = {}
local ADD_FOCUS = hash("acquire_input_focus")
local REMOVE_FOCUS = hash("release_input_focus")
local PATH_OBJ = "."
M.A_CLICK = hash("click")
M.A_TEXT = hash("text")
M.A_BACKSPACE = hash("backspace")
M.A_ENTER = hash("enter")
M.A_ANDR_BACK = hash("back")
M.RELEASED = "released"
M.PRESSED = "pressed"
function M.focus()
msg.post(PATH_OBJ, ADD_FOCUS)
end
function M.remove()
msg.post(PATH_OBJ, REMOVE_FOCUS)
end
return M

169
druid/ui_animate.lua Normal file
View File

@ -0,0 +1,169 @@
local M = {}
local PROP_SCALE = gui.PROP_SCALE
local PROP_POSITION = gui.PROP_POSITION
M.PROP_POS_X = hash("position.x")
M.PROP_POS_Y = hash("position.y")
M.PROP_ALPHA = hash("color.w")
local PROP_COLOR = hash("color")
local PROP_SCALE_X = "scale.x"
local PROP_SCALE_Y = "scale.y"
M.TINT_HIDE = vmath.vector4(1, 1, 1, 0)
M.TINT_SHOW = vmath.vector4(1, 1, 1, 1)
M.V3_ONE = vmath.vector3(1, 1, 1)
M.V3_ZERO = vmath.vector3(0, 0, 1)
M.SCALE_ANIMATION_TIME = 0.1
M.BOUNCE_ANIMATION_TIME = 0.25
M.ALPHA_ANIMATION_TIME = 0.25
function M.alpha(self, node, alpha, callback, time, delay, easing, playback)
time = time or M.ALPHA_ANIMATION_TIME
delay = delay or 0
easing = easing or gui.EASING_LINEAR
playback = playback or gui.PLAYBACK_ONCE_FORWARD
gui.animate(node, M.PROP_ALPHA, alpha, easing, time, delay,
function()
if callback then
callback(self, node)
end
end,
playback)
end
function M.color(self, node, color, callback, time, delay, easing, playback)
time = time or M.ALPHA_ANIMATION_TIME
delay = delay or 0
easing = easing or gui.EASING_LINEAR
playback = playback or gui.PLAYBACK_ONCE_FORWARD
gui.animate(node, PROP_COLOR, color, easing, time, delay,
function()
if callback then
callback(self, node)
end
end,
playback)
end
function M.shake(self, node, callback, str, time)
str = str or - 30
time = time or 0.25
local pos = gui.get_position(node)
pos.x = pos.x + str
gui.animate(node, PROP_POSITION, pos, gui.EASING_INELASTIC, time,
0,
function()
if callback then
callback(self)
end
end,
gui.PLAYBACK_ONCE_BACKWARD
)
end
function M.bounce(self, node, change_to, callback, time, easing, playback, delaly)
time = time or M.BOUNCE_ANIMATION_TIME
delaly = delaly or 0
easing = easing or gui.EASING_OUTSINE
playback = playback or gui.PLAYBACK_ONCE_PINGPONG
gui.animate(node, PROP_SCALE, change_to, easing, time, delaly,
function()
if callback then
callback(self)
end
end,
playback)
end
function M.fly_to(self, node, to_pos, speed, callback, delay, easing)
easing = easing or gui.EASING_OUTSINE
delay = delay or 0
local time = vmath.length(to_pos - gui.get_position(node)) / 100 / speed
gui.animate(node, gui.PROP_POSITION, to_pos, easing, time, delay,
function()
if callback then
callback(self, node)
end
end)
end
function M.fly_by_x(self, node, to_x, time, callback, delay, easing, playback)
playback = playback or gui.PLAYBACK_ONCE_FORWARD
easing = easing or gui.EASING_OUTSINE
delay = delay or 0
gui.animate(node, M.PROP_POS_X, to_x, easing, time, delay,
function()
if callback then
callback(self, node)
end
end,
playback)
end
function M.fly_by_y(self, node, to_y, time, callback, delay, easing, playback)
playback = playback or gui.PLAYBACK_ONCE_FORWARD
easing = easing or gui.EASING_OUTSINE
delay = delay or 0
time = time or 0.25
gui.animate(node, M.PROP_POS_Y, to_y, easing, time, delay,
function()
if callback then
callback(self, node)
end
end,
playback)
end
function M.scale_to(self, node, to, callback, time, delay, easing)
easing = easing or gui.EASING_INSINE
time = time or M.SCALE_ANIMATION_TIME
delay = delay or 0
time = time or 0.25
gui.animate(node, PROP_SCALE, to, easing, time, delay,
function()
if callback then
callback(self, node)
end
end
)
end
function M.scale_x_from_to(self, node, from, to, callback, time, easing, delay, playback)
easing = easing or gui.EASING_INSINE
time = time or M.SCALE_ANIMATION_TIME
delay = delay or 0
playback = playback or gui.PLAYBACK_ONCE_FORWARD
local scale = gui.get_scale(node)
scale.x = from
gui.set_scale(node, scale)
gui.animate(node, PROP_SCALE_X, to, easing, time, delay,
function()
if callback then
callback(self)
end
end,
playback
)
end
function M.scale_y_from_to(self, node, from, to, callback, time, easing, delay, playback)
easing = easing or gui.EASING_INSINE
time = time or M.SCALE_ANIMATION_TIME
delay = delay or 0
playback = playback or gui.PLAYBACK_ONCE_FORWARD
local scale = gui.get_scale(node)
scale.y = from
gui.set_scale(node, scale)
gui.animate(node, PROP_SCALE_Y, to, easing, time, delay,
function()
if callback then
callback(self)
end
end,
playback
)
end
return M

421
druid/ui_factory.lua Normal file
View File

@ -0,0 +1,421 @@
local M = {}
local lang = require "modules.localize.lang"
local input = require "modules.input.input"
M.input = input
local pie_progress_bar = require "modules.ui.components.pie_progress_bar"
local progress_bar = require "modules.ui.components.progress_bar"
local flying_particles = require "modules.ui.components.flying_particles"
local text_field = require "modules.ui.components.text_field"
local counter = require "modules.ui.components.counter"
local image = require "modules.ui.components.image"
local button = require "modules.ui.components.button"
local timer = require "modules.ui.components.timer"
local tab_page = require "modules.ui.components.tab_page"
local tabs_container = require "modules.ui.components.tabs_container"
local spine_anim = require "modules.ui.components.spine_anim"
local scrolling_box = require "modules.ui.components.scrolling_box"
local andr_back_btn = require "modules.ui.components.andr_back_btn"
local LAYOUT_CHANGED = hash("layout_changed")
local ON_MESSAGE = hash("on_message")
local ON_INPUT = hash("on_input")
local ON_SWIPE = hash("on_swipe")
local ON_UPDATE = hash("on_update")
M.TRANSLATABLE = hash("TRANSLATABLE")
local STRING = "string"
--- Call this method when you need to update translations.
function M.translate(factory)
if factory[M.TRANSLATABLE] then
local key, result
for i, v in ipairs(factory[M.TRANSLATABLE]) do
key = v.lang_key or v.name
if key then
if v.lang_params then
result = lang.txp(key, v.lang_params)
else
result = lang.txt(key)
end
if result then
lang.set_node_properties(v.node, key)
end
result = result or v.last_value
v:set_to(result)
end
end
end
end
--- Called on_message
function M.on_message(factory, message_id, message, sender)
if message_id == LAYOUT_CHANGED then
if factory[LAYOUT_CHANGED] then
M.translate(factory)
for i, v in ipairs(factory[LAYOUT_CHANGED]) do
v:on_layout_updated(message)
end
end
elseif message_id == M.TRANSLATABLE then
M.translate(factory)
else
if factory[ON_MESSAGE] then
for i, v in ipairs(factory[ON_MESSAGE]) do
v:on_message(message_id, message, sender)
end
end
end
end
--- Called ON_INPUT
function M.on_input(factory, action_id, action)
if factory[ON_SWIPE] then
local v, result
local len = #factory[ON_SWIPE]
for i = 1, len do
v = factory[ON_SWIPE][i]
result = result or v:on_input(action_id, action)
end
if result then
return true
end
end
if factory[ON_INPUT] then
local v
local len = #factory[ON_INPUT]
for i = 1, len do
v = factory[ON_INPUT][i]
if action_id == v.event and action[v.action] and v:on_input(action_id, action) then
return true
end
end
return false
end
return false
end
--- Called on_update
function M.on_update(factory, dt)
if factory[ON_UPDATE] then
for i, v in ipairs(factory[ON_UPDATE]) do
v:on_updated(dt)
end
end
end
--- Create UI instance for ui elements
-- @return instance with all ui components
function M.new(self)
local factory = setmetatable({}, {__index = M})
factory.parent = self
return factory
end
local function input_init(factory)
if not factory.input_inited then
factory.input_inited = true
input.focus()
end
end
--------------------------------------------------------------------------------
local function create(meta, factory, name, ...)
local instance = setmetatable({}, {__index = meta})
instance.parent = factory
if name then
if type(name) == STRING then
instance.name = name
instance.node = gui.get_node(name)
else
--name already is node
instance.name = nil
instance.node = name
end
end
factory[#factory + 1] = instance
local register_to = {...}
for i, v in ipairs(register_to) do
if not factory[v] then
factory[v] = {}
end
factory[v][#factory[v] + 1] = instance
end
return instance
end
--- Create new instance of a text_field
-- @param factory - parent factory
-- @param name - name of text node
-- @param init_value - init ui object with this value
-- @return instance of a text_field
function M.new_text_field(factory, name, init_value, bounce_in)
local instance = create(text_field, factory, name, M.TRANSLATABLE, LAYOUT_CHANGED)
instance.scale_from = gui.get_scale(instance.node)
instance.scale_to = bounce_in and vmath.mul_per_elem(instance.scale_from, bounce_in) or instance.scale_from
instance:set_to(init_value or 0)
return instance
end
--- Create new instance of a counter
-- @param factory - parent factory
-- @param name - name of text node
-- @param init_value - init ui object with this value
-- @return instance of a text_field
function M.new_counter(factory, name, init_value)
local instance = create(counter, factory, name, LAYOUT_CHANGED, ON_UPDATE)
instance.scale_from = gui.get_scale(instance.node)
instance.scale_to = instance.scale_from * 1.2
instance:set_to(init_value or 0)
return instance
end
--- Create new instance of an image
-- @param factory - parent factory
-- @param name - name of image node
-- @param anim_table - table with animations or frames
-- @param init_frame - init with this frame
-- @return instance of an image
function M.new_image(factory, name, anim_table, init_frame, bounce_in)
local instance = create(image, factory, name, LAYOUT_CHANGED)
instance.scale_from = gui.get_scale(instance.node)
instance.scale_to = bounce_in and vmath.mul_per_elem(instance.scale_from, bounce_in) or instance.scale_from
instance.anim_table = anim_table
if init_frame then
instance:set_to(init_frame)
elseif anim_table then
instance:set_to(1)
end
return instance
end
--- Create new instance of a timer
-- @param factory - parent factory
-- @param name - name of image node
-- @param second_from - start time
-- @param seconds_to - end time
-- @param callback - call when timer finished
-- @return instance of a timer
function M.new_timer(factory, name, second_from, seconds_to, callback)
local instance = create(timer, factory, name, LAYOUT_CHANGED, ON_UPDATE)
instance:set_to(second_from)
instance:set_interval(second_from, seconds_to)
instance.is_on = true
instance.callback = callback
return instance
end
--- Add new pie progress component for handling
-- @param factory - parent factory
-- @param name - a node name for a pie progress instance
-- @param init_value - init ui object with this value
-- @return instance with pie_progress
function M.new_pie_progress(factory, name, init_value)
local instance = create(pie_progress_bar, factory, name, LAYOUT_CHANGED)
instance:set_to(init_value or 1)
return instance
end
--- Add new progress bar component for handling
-- @param factory - parent factory
-- @param name - name of the fill node
-- @param key - x or y - key for scale
-- @param init_value - init ui object with this value
-- @return instance with pie_progress
function M.new_progress_bar(factory, name, key, init_value)
local instance = create(progress_bar, factory, name, LAYOUT_CHANGED)
instance.prop = hash("scale."..key)
instance.key = key
instance.node = gui.get_node(name)
instance.scale = gui.get_scale(instance.node)
instance:set_to(init_value or 1)
return instance
end
--- Create new instance of a flying particles
-- @param factory - parent factory
-- @param name - name of prototype
-- @param count - how many particles need to cache
-- @param get_pos_func - function that returns target pos for flying
-- @return instance of a flying particles
function M.new_flying_particles(factory, name, count, get_pos_func)
local instance = create(flying_particles, factory, name, LAYOUT_CHANGED)
instance.get_pos_func = get_pos_func
local node = instance.node
instance.node = node
instance.fly_particles = {}
instance.fly_particles[1] = node
for i = 2, count do
instance.fly_particles[i] = gui.clone(node)
end
instance.scale = gui.get_scale(node)
instance.last_particle = 0
return instance
end
M.BTN_SOUND_FUNC = function() end
M.BTN_SOUND_DISABLE_FUNC = function()end
--- Add new button component for handling
-- @param factory - parent factory
-- @param name - a node name for a button instance
-- @param callback - click button callback
-- @param params - callback parameters, will be returned with self callback(self, params)
-- @param animate_node_name - node for animation, if it's not a main node
-- @return instance of button
function M.new_button(factory, name, callback, params, animate_node_name, event, action, sound, sound_disable)
input_init(factory)
local instance = create(button, factory, name, ON_INPUT)
instance.event = event or input.A_CLICK
instance.action = action or input.RELEASED
instance.anim_node = animate_node_name and gui.get_node(animate_node_name) or instance.node
instance.scale_from = gui.get_scale(instance.anim_node)
instance.scale_to = instance.scale_from + button.DEFAULT_SCALE_CHANGE
instance.pos = gui.get_position(instance.anim_node)
instance.callback = callback
instance.params = params
instance.tap_anim = button.tap_scale_animation
instance.back_anim = button.back_scale_animation
instance.sound = sound or M.BTN_SOUND_FUNC
instance.sound_disable = sound_disable or M.BTN_SOUND_DISABLE_FUNC
return instance
end
--- Add reaction for back btn (on Android for example)
-- @param factory - parent factory
-- @param callback - tap button callback
function M.new_back_handler(factory, callback)
input_init(factory)
local instance = create(andr_back_btn, factory, nil, ON_INPUT)
instance.event = input.A_ANDR_BACK
instance.action = input.RELEASED
instance.callback = callback
return instance
end
--- Create new tab page instance
-- @param factory - parent factory
-- @param name - name of parental node that represents tab page content
-- @param easing - easing for tab page
-- @param duration - duration of animation for tab page
-- @param callback - call when change page
-- @return instance that represents the tab page
function M.new_tab_page(factory, name, easing, duration, callback)
local instance = create(tab_page, factory, name, ON_MESSAGE)
instance.in_pos = gui.get_position(instance.node)
instance.out_pos = gui.get_position(instance.node)
instance.easing = easing or tab_page.DEFAULT_EASING
instance.duration = duration or tab_page.DEFAULT_DURATION
instance.callback = callback
return instance
end
--- Create new tab btns container instance
-- @param factory - parent factory
-- @param name - name of parental node that represents tab btns container
-- @return instance that represents the tab btns container
function M.new_tabs_container(factory, name, callback)
local instance = create(tabs_container, factory, name, LAYOUT_CHANGED)
instance:update_sizes()
instance.url = msg.url()
--- Create new tab btn instance
-- @param name - name of parental node that represents tab btn
-- @return instance that represents the tab btn
function instance.new_tab_btn(_instance, _name, url, index)
local params = {url = url, index = index, name = _name}
local btn = M.new_button(factory, _name, nil, params)
btn.back_anim = nil
btn.manual_back = button.back_tab_animation
btn.tap_anim = button.tap_tab_animation
btn.callback = function(_, _, force)
instance.switch_tab(instance, params, force)
if callback then
callback(factory.parent, index, force)
end
end
instance[_name] = params
if not instance.btns then
instance.btns = {}
end
instance.btns[index] = btn
return btn
end
return instance
end
--- Add new spine animation
-- @param factory - parent factory
-- @param name - a node name for a spine anim
-- @param idle_table - table with idle animations
-- @param active_table - table with active animations
-- @param init_idle - init idle animation name or index in idle table
-- @return instance with spine anim
function M.new_spine_anim(factory, name, idle_table, active_table, init_idle)
local instance = create(spine_anim, factory, name, LAYOUT_CHANGED)
instance.idle_table = idle_table
instance.active_table = active_table
instance:play_idle(init_idle)
return instance
end
--- Add new scrolling box
-- @param factory - parent factory
-- @param name - a node name for a spine anim
-- @param zone_name - node name of zone for tap
-- @param speed_coef - vector3 coef. of speed for scrolling
-- @param maximum - vector3 maximum position for scrolling
-- @param points_of_interest - table with vector3 point of interes
-- @param callback - scrolling events callback
-- @return instance with scrolling box
function M.new_scrolling_box(factory, name, zone_name, speed_coef, maximum, points_of_interest, callback)
local instance = create(scrolling_box, factory, name, ON_UPDATE, ON_SWIPE)
instance.pos = gui.get_position(instance.node)
instance.start_pos = vmath.vector3(instance.pos)
instance.maximum = maximum
instance.points_of_interest = points_of_interest
instance.callback = callback
if instance.start_pos.x > instance.maximum.x then
instance.start_pos.x, instance.maximum.x = instance.maximum.x, instance.start_pos.x
end
if instance.start_pos.y > instance.maximum.y then
instance.start_pos.y, instance.maximum.y = instance.maximum.y, instance.start_pos.y
end
if type(name) == STRING then
instance.scrolling_zone = gui.get_node(zone_name)
else
instance.scrolling_zone = zone_name
end
instance.swipe = {
minSwipeDistance = 40,
speed_down_coef = 1.1,
speed_up_coef = speed_coef or vmath.vector3(1.1, 1.1, 0),
speed = vmath.vector3(0, 0, 0),
maximum = vmath.vector3(0, 0, 0),
min_speed = 2,
beginX = 0,
beginY = 0,
endX = 0,
endY = 0,
xDistance = nil,
yDistance = nil,
totalSwipeDistanceLeft = nil,
totalSwipeDistanceRight = nil,
totalSwipeDistanceUp = nil,
totalSwipeDistanceDown = nil,
is_swipe = nil,
end_move_coef_x = 1,
end_move_coef_y = 1,
back_slow_coef = 0.4,
end_position_x = nil,
end_position_y = nil,
is_x = instance.start_pos.x ~= instance.maximum.x,
is_y = instance.start_pos.y ~= instance.maximum.y
}
return instance
end
return M

16
druid/ui_helper.lua Normal file
View File

@ -0,0 +1,16 @@
local M = {}
function M.centrate_text_with_icon(text_node, icon_node)
local metr = gui.get_text_metrics_from_node(text_node)
local scl = gui.get_scale(text_node).x
local scl_i = gui.get_scale(icon_node).x
local pos_i = gui.get_position(icon_node)
local pos = gui.get_position(text_node)
local w = metr.width * scl * scl_i
local icon_w = gui.get_size(icon_node).x * scl_i
local width = w + icon_w + (math.abs(pos.x) - icon_w / 2) * scl_i
pos_i.x = width / 2 - (icon_w / 2)
gui.set_position(icon_node, pos_i)
end
return M

16
game.project Normal file
View File

@ -0,0 +1,16 @@
[bootstrap]
main_collection = /main/main.collectionc
[script]
shared_state = 1
[display]
width = 960
height = 640
[project]
title = druid
[library]
include_dirs = druid

4
input/game.input_binding Normal file
View File

@ -0,0 +1,4 @@
mouse_trigger {
input: MOUSE_BUTTON_1
action: "touch"
}

2
main/main.collection Normal file
View File

@ -0,0 +1,2 @@
name: "main"
scale_along_z: 0