More widgets, additional adjusts for text

This commit is contained in:
Insality
2024-11-20 01:42:12 +02:00
parent c35dfc7066
commit 37d7168bd6
15 changed files with 698 additions and 72 deletions

View File

@@ -1,6 +1,6 @@
local color = require("druid.color")
---@class property_button: druid.widget
---@class widget.property_button: druid.widget
---@field root node
---@field container druid.container
---@field text_name druid.text
@@ -12,6 +12,8 @@ local M = {}
function M:init()
self.root = self:get_node("root")
self.text_name = self.druid:new_text("text_name")
:set_text_adjust("trim_left")
self.selected = self:get_node("selected")
gui.set_alpha(self.selected, 0)
@@ -33,7 +35,7 @@ end
---@param text string
---@return property_button
---@return widget.property_button
function M:set_text_button(text)
self.text_button:set_text(text)
return self

View File

@@ -1,4 +1,4 @@
---@class property_checkbox: druid.widget
---@class widget.property_checkbox: druid.widget
---@field root node
---@field druid druid_instance
---@field text_name druid.text

View File

@@ -36,7 +36,7 @@ nodes {
z: 0.49
}
type: TYPE_TEXT
text: "Button"
text: "Input"
font: "text_bold"
id: "text_name"
pivot: PIVOT_W

View File

@@ -1,4 +1,4 @@
---@class property_input: druid.widget
---@class widget.property_input: druid.widget
---@field root node
---@field container druid.container
---@field text_name druid.text

View File

@@ -0,0 +1,212 @@
fonts {
name: "text_bold"
font: "/druid/fonts/text_bold.font"
}
textures {
name: "druid"
texture: "/druid/druid.atlas"
}
nodes {
size {
x: 400.0
y: 40.0
}
type: TYPE_BOX
texture: "druid/empty"
id: "root"
adjust_mode: ADJUST_MODE_STRETCH
inherit_alpha: true
visible: false
}
nodes {
position {
x: -200.0
}
scale {
x: 0.5
y: 0.5
}
size {
x: 360.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "Left Right Selector"
font: "text_bold"
id: "text_name"
pivot: PIVOT_W
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "root"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
x: 200.0
}
size {
x: 200.0
y: 40.0
}
type: TYPE_BOX
id: "E_Anchor"
pivot: PIVOT_E
parent: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
position {
x: -180.0
}
size {
x: 40.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_BOX
texture: "druid/rect_round2_width2"
id: "button_left"
parent: "E_Anchor"
inherit_alpha: true
slice9 {
x: 5.0
y: 5.0
z: 5.0
w: 5.0
}
}
nodes {
rotation {
z: 180.0
}
color {
x: 0.722
y: 0.741
z: 0.761
}
type: TYPE_BOX
texture: "druid/icon_arrow"
id: "icon_left"
parent: "button_left"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
}
nodes {
position {
x: -20.0
}
size {
x: 40.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_BOX
texture: "druid/rect_round2_width2"
id: "button_right"
parent: "E_Anchor"
inherit_alpha: true
slice9 {
x: 5.0
y: 5.0
z: 5.0
w: 5.0
}
}
nodes {
color {
x: 0.722
y: 0.741
z: 0.761
}
type: TYPE_BOX
texture: "druid/icon_arrow"
id: "icon_right"
parent: "button_right"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
}
nodes {
position {
x: -100.0
y: -20.0
}
size {
x: 120.0
y: 4.0
}
color {
x: 0.894
y: 0.506
z: 0.333
}
type: TYPE_BOX
texture: "druid/pixel"
id: "selected"
pivot: PIVOT_S
adjust_mode: ADJUST_MODE_STRETCH
parent: "E_Anchor"
inherit_alpha: true
}
nodes {
position {
x: -100.0
}
scale {
x: 0.5
y: 0.5
}
size {
x: 220.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "42"
font: "text_bold"
id: "text_value"
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "E_Anchor"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@@ -0,0 +1,204 @@
local event = require("druid.event")
---@class widget.property_left_right_selector: druid.widget
---@field root node
---@field druid druid_instance
---@field text_name druid.text
---@field button druid.button
---@field selected node
---@field value string|number
local M = {}
function M:init()
self.root = self:get_node("root")
self.selected = self:get_node("selected")
gui.set_alpha(self.selected, 0)
self.text_name = self.druid:new_text("text_name")
self.text_value = self.druid:new_text("text_value")
self.button_left = self.druid:new_button("button_left", self.on_button_left)
self.button_right = self.druid:new_button("button_right", self.on_button_right)
self.on_change_value = event.create()
self.container = self.druid:new_container(self.root)
self.container:add_container("text_name")
self.container:add_container("E_Anchor")
end
function M:set_text(text)
self.text_name:set_text(text)
return self
end
---Helper to cycle number in range
---@param value number Current value
---@param min number Min range value
---@param max number Max range value
---@param step number Step size
---@param is_loop boolean Is looped
---@return number Cycled value
local function step_number(value, min, max, step, is_loop)
local range = max - min + 1
if is_loop then
-- Normalize step within range
local effective_step = step
if math.abs(step) >= range then
effective_step = step % range
if effective_step == 0 then
effective_step = step > 0 and range or -range
end
end
value = value + effective_step
-- Handle wrapping
if max then
while value > max do
value = min + (value - max - 1)
end
end
if min then
while value < min do
value = max - (min - value - 1)
end
end
else
-- Clamp values
value = value + step
if max and value > max then
return max
elseif min and value < min then
return min
end
end
return value
end
---Helper to cycle array index with proper step wrapping
---@param array table Array to cycle through
---@param current_value any Current value to find index for
---@param step number Step direction
---@param is_loop boolean If true, cycle values. If false, clamp at ends
---@return any Next value in cycle
local function step_array(array, current_value, step, is_loop)
local index = 1
for i, v in ipairs(array) do
if v == current_value then
index = i
break
end
end
if is_loop then
-- Normalize step within array length
local range = #array
local effective_step = step
if math.abs(step) >= range then
effective_step = step % range
if effective_step == 0 then
effective_step = step > 0 and range or -range
end
end
index = index + effective_step
-- Handle wrapping
while index > range do
index = 1 + (index - range - 1)
end
while index < 1 do
index = range - (1 - index - 1)
end
else
-- Clamp values
index = index + step
if index > #array then
index = #array
elseif index < 1 then
index = 1
end
end
return array[index]
end
function M:on_button_left()
self:add_value(true)
end
function M:on_button_right()
self:add_value(false)
end
function M:add_value(is_left)
local koef = is_left and -1 or 1
local array_type = self.array_type
if array_type then
local value = self.value
local new_value = step_array(array_type.array, value, koef * array_type.steps, array_type.is_loop)
self:set_value(new_value)
return
end
local number_type = self.number_type
if number_type then
local value = tonumber(self.value) --[[@as number]]
local new_value = step_number(value, number_type.min, number_type.max, koef * number_type.steps, number_type.is_loop)
self:set_value(new_value)
return
end
end
function M:set_number_type(min, max, is_loop, steps)
self.number_type = {
min = min,
max = max,
steps = steps or 1,
is_loop = is_loop,
}
return self
end
function M:set_array_type(array, is_loop, steps)
self.array_type = {
array = array,
steps = steps or 1,
is_loop = is_loop,
}
return self
end
---@param value string|number
function M:set_value(value, is_instant)
if self.value == value then
return
end
self.value = value
self.text_value:set_text(tostring(value))
self.on_change_value:trigger(value)
if not is_instant then
gui.set_alpha(self.selected, 1)
gui.animate(self.selected, "color.w", 0, gui.EASING_INSINE, 0.16)
end
end
---@return string|number
function M:get_value()
return self.value
end
return M

View File

@@ -1,4 +1,4 @@
---@class property_slider: druid.widget
---@class widget.property_slider: druid.widget
---@field root node
---@field container druid.container
---@field druid druid_instance

View File

@@ -1,4 +1,4 @@
---@class property_text: druid.widget
---@class widget.property_text: druid.widget
---@field root node
---@field container druid.container
---@field text_name druid.text
@@ -8,6 +8,7 @@ local M = {}
function M:init()
self.root = self:get_node("root")
self.text_name = self.druid:new_text("text_name")
:set_text_adjust("scale_when_trim_left", 0.3)
self.text_right = self.druid:new_text("text_right", "")
self.container = self.druid:new_container(self.root)
@@ -21,15 +22,15 @@ end
---@param text string
---@return property_text
---@return widget.property_text
function M:set_text(text)
self.text_name:set_text(text)
return self
end
---@param text string
---@return property_text
---@param text string|nil
---@return widget.property_text
function M:set_right_text(text)
self.text_right:set_text(text or "")
return self

View File

@@ -426,5 +426,69 @@ nodes {
parent: "property_text/root"
template_node_child: true
}
nodes {
position {
y: -250.0
}
type: TYPE_TEMPLATE
id: "property_left_right_selector"
parent: "propeties"
inherit_alpha: true
template: "/druid/widget/properties_panel/properties/property_left_right_selector.gui"
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/root"
parent: "property_left_right_selector"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_left_right_selector/text_name"
parent: "property_left_right_selector/root"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/E_Anchor"
parent: "property_left_right_selector/root"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/button_left"
parent: "property_left_right_selector/E_Anchor"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/icon_left"
parent: "property_left_right_selector/button_left"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/button_right"
parent: "property_left_right_selector/E_Anchor"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/icon_right"
parent: "property_left_right_selector/button_right"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_left_right_selector/selected"
parent: "property_left_right_selector/E_Anchor"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_left_right_selector/text_value"
parent: "property_left_right_selector/E_Anchor"
template_node_child: true
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@@ -3,8 +3,9 @@ local property_slider = require("druid.widget.properties_panel.properties.proper
local property_button = require("druid.widget.properties_panel.properties.property_button")
local property_input = require("druid.widget.properties_panel.properties.property_input")
local property_text = require("druid.widget.properties_panel.properties.property_text")
local property_left_right_selector = require("druid.widget.properties_panel.properties.property_left_right_selector")
---@class properties_panel: druid.widget
---@class widget.properties_panel: druid.widget
---@field root node
---@field scroll druid.scroll
---@field druid druid_instance
@@ -24,6 +25,9 @@ function M:init()
self.default_size = self.container:get_size()
self.properties = {}
self.properties_constructors = {}
self.current_page = 1
self.properties_per_page = 15
self.text_header = self.druid:new_text("text_header")
self.scroll = self.druid:new_scroll("scroll_view", "scroll_content")
@@ -51,6 +55,23 @@ function M:init()
self.property_text_prefab = self:get_node("property_text/root")
gui.set_enabled(self.property_text_prefab, false)
self.property_left_right_selector_prefab = self:get_node("property_left_right_selector/root")
gui.set_enabled(self.property_left_right_selector_prefab, false)
self.paginator = self:add_left_right_selector("Page", self.current_page, function(value)
self.current_page = value
self:refresh_page()
end):set_number_type(1, 1, true)
gui.set_enabled(self.paginator.root, false)
-- Remove paginator from properties
for index = 1, #self.properties do
if self.properties[index] == self.paginator then
table.remove(self.properties, index)
break
end
end
end
@@ -66,7 +87,12 @@ function M:clear()
self.druid:remove(self.properties[index])
end
self.layout:clear_layout()
self.layout:add(self.paginator.root)
self.properties = {}
self.properties_constructors = {}
self:refresh_page()
end
@@ -88,15 +114,11 @@ end
---@param text string
---@param initial_value boolean
---@param on_change_callback function
---@return property_checkbox
---@return widget.property_checkbox
function M:add_checkbox(text, initial_value, on_change_callback)
text = tostring(text)
local instance = self:create_from_prefab(property_checkbox, "property_checkbox", self.property_checkbox_prefab)
local nodes = gui.clone_tree(self.property_checkbox_prefab)
local instance = self.druid:new_widget(property_checkbox, "property_checkbox", nodes)
self:add_property(instance)
instance.text_name:set_to(text)
instance.text_name:set_text(text)
instance:set_value(initial_value, true)
instance.button.on_click:subscribe(function()
on_change_callback(instance:get_value())
@@ -109,12 +131,9 @@ end
---@param text string
---@param initial_value number
---@param on_change_callback function
---@return property_slider
---@return widget.property_slider
function M:add_slider(text, initial_value, on_change_callback)
text = tostring(text)
local nodes = gui.clone_tree(self.property_slider_prefab)
local instance = self.druid:new_widget(property_slider, "property_slider", nodes)
self:add_property(instance)
local instance = self:create_from_prefab(property_slider, "property_slider", self.property_slider_prefab)
instance.text_name:set_text(text)
instance:set_value(initial_value, true)
@@ -129,10 +148,9 @@ end
---@param text string
---@param on_click_callback function|nil
---@param callback_context any|nil
---@return widget.property_button
function M:add_button(text, on_click_callback, callback_context)
local nodes = gui.clone_tree(self.property_button_prefab)
local instance = self.druid:new_widget(property_button, "property_button", nodes)
self:add_property(instance)
local instance = self:create_from_prefab(property_button, "property_button", self.property_button_prefab)
instance.text_name:set_text(text)
if on_click_callback then
@@ -143,11 +161,12 @@ function M:add_button(text, on_click_callback, callback_context)
end
---@param text string
---@param initial_value string
---@param on_change_callback function
---@return widget.property_input
function M:add_input(text, initial_value, on_change_callback)
text = tostring(text)
local nodes = gui.clone_tree(self.property_input_prefab)
local instance = self.druid:new_widget(property_input, "property_input", nodes)
self:add_property(instance)
local instance = self:create_from_prefab(property_input, "property_input", self.property_input_prefab)
instance.text_name:set_text(text)
instance.rich_input:set_text(initial_value)
@@ -155,20 +174,44 @@ function M:add_input(text, initial_value, on_change_callback)
instance.rich_input.input.on_input_unselect:subscribe(function(_, value)
on_change_callback(value)
end)
return instance
end
---@param text string
---@param right_text string|nil
---@return property_text
---@return widget.property_text
function M:add_text(text, right_text)
text = tostring(text)
local nodes = gui.clone_tree(self.property_text_prefab)
local instance = self.druid:new_widget(property_text, "property_text", nodes)
self:add_property(instance)
local instance = self:create_from_prefab(property_text, "property_text", self.property_text_prefab)
instance:set_text(text)
instance:set_right_text(right_text)
return instance
end
---@param text string
---@param value string|number|nil
---@param on_change_callback fun(value: string|number)
---@return widget.property_left_right_selector
function M:add_left_right_selector(text, value, on_change_callback)
local instance = self:create_from_prefab(property_left_right_selector, "property_left_right_selector", self.property_left_right_selector_prefab)
instance:set_text(text)
instance:set_value(value or 0, true)
instance.on_change_value:subscribe(on_change_callback)
return instance
end
---@private
function M:create_from_prefab(widget_class, widget_name, prefab)
local nodes = gui.clone_tree(prefab)
local instance = self.druid:new_widget(widget_class, widget_name, nodes)
self:add_property(instance)
return instance
end
@@ -177,14 +220,36 @@ end
function M:add_property(widget)
gui.set_enabled(widget.root, true)
self.layout:add(widget.root)
table.insert(self.properties, widget)
local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z
widget.container:set_size(width)
if #self.properties > self.properties_per_page then
self:refresh_page()
end
return widget
end
function M:refresh_page()
local start_index = (self.current_page - 1) * self.properties_per_page + 1
local end_index = start_index + self.properties_per_page - 1
for index = 1, #self.properties do
local is_visible = index >= start_index and index <= end_index
gui.set_enabled(self.properties[index].root, is_visible)
end
gui.set_enabled(self.paginator.root, #self.properties > self.properties_per_page)
self.paginator:set_number_type(1, math.ceil(#self.properties / self.properties_per_page), true)
self.paginator.text_value:set_text(self.current_page .. " / " .. math.ceil(#self.properties / self.properties_per_page))
self.layout:set_dirty()
end
function M:remove(widget)
for index = 1, #self.properties do
if self.properties[index] == widget then
@@ -206,9 +271,14 @@ function M:toggle_hide()
self.container:set_size(new_size.x, new_size.y, gui.PIVOT_N)
gui.set_enabled(self.content, not self.is_hidden)
return self
end
---@param properties_per_page number
function M:set_properties_per_page(properties_per_page)
self.properties_per_page = properties_per_page
end
return M