237 lines
6.1 KiB
Lua
237 lines
6.1 KiB
Lua
--
|
|
-- NumberBox Widget.
|
|
-- @copyright Jefferson Gonzalez
|
|
-- @license MIT
|
|
--
|
|
|
|
local core = require "core"
|
|
local Widget = require "libraries.widget"
|
|
local Button = require "libraries.widget.button"
|
|
local TextBox = require "libraries.widget.textbox"
|
|
|
|
---@class widget.numberbox : widget
|
|
---@field private textbox widget.textbox
|
|
---@field private decrease_button widget.button
|
|
---@field private increase_button widget.button
|
|
---@field private minimum number
|
|
---@field private maximum number
|
|
---@field private step number
|
|
local NumberBox = Widget:extend()
|
|
|
|
---Constructor
|
|
---@param parent widget
|
|
---@param value number
|
|
---@param min? number
|
|
---@param max? number
|
|
---@param step? number
|
|
function NumberBox:new(parent, value, min, max, step)
|
|
NumberBox.super.new(self, parent)
|
|
|
|
self.type_name = "widget.numberbox"
|
|
|
|
self:set_range(min, max)
|
|
self:set_step(step)
|
|
|
|
self.textbox = TextBox(self, "")
|
|
self.textbox.scrollable = true
|
|
|
|
self.decrease_button = Button(self, "-")
|
|
self.increase_button = Button(self, "+")
|
|
|
|
self:set_value(value)
|
|
|
|
local this = self
|
|
function self.textbox.textview.doc:on_text_change(type)
|
|
if not tonumber(this.textbox:get_text()) then
|
|
if not this.coroutine_run then
|
|
this.coroutine_run = true
|
|
core.add_thread(function()
|
|
this.textbox:set_text(this.current_text)
|
|
this.coroutine_run = false
|
|
end)
|
|
end
|
|
else
|
|
this.textbox.placeholder_active = false
|
|
this.current_text = this.textbox:get_text()
|
|
this:on_change(tonumber(this.current_text))
|
|
end
|
|
end
|
|
function self.textbox:on_mouse_wheel(y)
|
|
if self.active then
|
|
if y > 0 then this:increase() else this:decrease() end
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
function self.decrease_button:on_mouse_pressed(button, x, y, clicks)
|
|
if Button.super.on_mouse_pressed(self, button, x, y, clicks) then
|
|
this.mouse_is_pressed = true
|
|
this:mouse_pressed(false)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
function self.increase_button:on_mouse_pressed(button, x, y, clicks)
|
|
if Button.super.on_mouse_pressed(self, button, x, y, clicks) then
|
|
this.mouse_is_pressed = true
|
|
this:mouse_pressed(true)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
function self.decrease_button:on_mouse_released(button, x, y)
|
|
if Button.super.on_mouse_released(self, button, x, y) then
|
|
this.mouse_is_pressed = false
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
function self.increase_button:on_mouse_released(button, x, y)
|
|
if Button.super.on_mouse_released(self, button, x, y) then
|
|
this.mouse_is_pressed = false
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
self.border.width = 0
|
|
|
|
self:set_size(
|
|
self.textbox:get_width() - 100
|
|
+ self.decrease_button:get_width()
|
|
+ self.increase_button:get_width()
|
|
)
|
|
end
|
|
|
|
---Set a new value.
|
|
---@param value number
|
|
function NumberBox:set_value(value)
|
|
if type(value) == "number" then
|
|
self.textbox:set_text(tostring(value))
|
|
elseif type(value) == "string" and tonumber(value) then
|
|
self.textbox:set_text(value)
|
|
else
|
|
self.textbox:set_text(tostring(self.minimum))
|
|
end
|
|
self.textbox.placeholder_active = false
|
|
self.current_text = self.textbox:get_text()
|
|
self:on_change(tonumber(self.current_text))
|
|
end
|
|
|
|
---Get the current value.
|
|
---@return number
|
|
function NumberBox:get_value()
|
|
return tonumber(self.textbox:get_text()) or self.minimum
|
|
end
|
|
|
|
---Set the minimum and maximum values allowed.
|
|
---@param min? number
|
|
---@param max? number
|
|
function NumberBox:set_range(min, max)
|
|
self.minimum = min or math.mininteger
|
|
self.maximum = max or math.maxinteger
|
|
end
|
|
|
|
---Set the value used to increase or decrease the number when the
|
|
---buttons are pressed.
|
|
---@param step number
|
|
function NumberBox:set_step(step)
|
|
self.step = step or 1
|
|
end
|
|
|
|
---Decrease the current value.
|
|
function NumberBox:decrease()
|
|
self.textbox.placeholder_active = false
|
|
local value = tonumber(self.textbox:get_text()) or self.maximum
|
|
if (value - self.step) >= self.minimum then
|
|
self:set_value(value - self.step)
|
|
end
|
|
end
|
|
|
|
---Increase the current value.
|
|
function NumberBox:increase()
|
|
self.textbox.placeholder_active = false
|
|
local value = tonumber(self.textbox:get_text()) or self.minimum
|
|
if (value + self.step) <= self.maximum then
|
|
self:set_value(value + self.step)
|
|
end
|
|
end
|
|
|
|
---Triggered when the mouse is pressed on the increase/decrease buttons.
|
|
---@param increase boolean
|
|
function NumberBox:mouse_pressed(increase)
|
|
if increase then self:increase() else self:decrease() end
|
|
|
|
local elapsed = system.get_time() + 0.3
|
|
local this = self
|
|
|
|
core.add_thread(function()
|
|
while this.mouse_is_pressed do
|
|
if elapsed < system.get_time() then
|
|
if increase then
|
|
this:increase()
|
|
else
|
|
this:decrease()
|
|
end
|
|
core.redraw = true
|
|
elapsed = system.get_time() + 0.1
|
|
end
|
|
coroutine.yield()
|
|
end
|
|
end)
|
|
end
|
|
|
|
---Overrided to enforce minimum allowed size.
|
|
---@param width integer
|
|
---@param height? integer Ignored on the number box
|
|
function NumberBox:set_size(width, height)
|
|
local buttons_w = self.decrease_button:get_width()
|
|
+ self.increase_button:get_width()
|
|
|
|
-- permit a minimum of 100 pixels wide for textbox
|
|
if width < (buttons_w + 100) then
|
|
width = 100 + buttons_w
|
|
end
|
|
|
|
self.textbox:set_size(width - buttons_w)
|
|
|
|
NumberBox.super.set_size(
|
|
self,
|
|
width,
|
|
math.max(
|
|
self.textbox:get_height(),
|
|
self.decrease_button:get_height(),
|
|
self.increase_button:get_height()
|
|
)
|
|
-- TODO: check what causes the need for this border size addition since
|
|
-- it shouldn't be needed but for now fixes occasional bottom border cut.
|
|
+ self.increase_button.border.width
|
|
)
|
|
end
|
|
|
|
function NumberBox:update()
|
|
if not NumberBox.super.update(self) then return false end
|
|
|
|
self:set_size(
|
|
self.textbox:get_width()
|
|
+ self.decrease_button:get_width()
|
|
+ self.increase_button:get_width()
|
|
)
|
|
|
|
self.textbox:set_position(0, 0)
|
|
|
|
self.decrease_button:set_position(
|
|
self.textbox:get_right(),
|
|
0
|
|
)
|
|
|
|
self.increase_button:set_position(
|
|
self.decrease_button:get_right(),
|
|
0
|
|
)
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
return NumberBox
|