More widgets stuff, cleaning code

This commit is contained in:
Insality 2024-11-19 23:06:57 +02:00
parent 37190684c4
commit c35dfc7066
36 changed files with 1494 additions and 508 deletions

View File

@ -212,7 +212,9 @@ end
---@param node_or_node_id node|string
---@param on_drag_callback function
function M:init(node_or_node_id, on_drag_callback)
self.druid = self:get_druid()
self.node = self:get_node(node_or_node_id)
self.hover = self.druid:new_hover(self.node)
self.dx = 0
self.dy = 0
@ -239,6 +241,20 @@ function M:init(node_or_node_id, on_drag_callback)
self.on_drag_end = Event()
self:on_window_resized()
self:set_drag_cursors(true)
end
---Set Drag component enabled state.
---@param is_enabled boolean
function M:set_drag_cursors(is_enabled)
if defos and is_enabled then
self.hover.style.ON_HOVER_CURSOR = defos.CURSOR_CROSSHAIR
self.hover.style.ON_MOUSE_HOVER_CURSOR = defos.CURSOR_HAND
else
self.hover.style.ON_HOVER_CURSOR = nil
self.hover.style.ON_MOUSE_HOVER_CURSOR = nil
end
end

View File

@ -796,6 +796,8 @@ function M:_update_size()
self:_set_scroll_position(self.position.x, self.position.y)
self.target_position.x = self.position.x
self.target_position.y = self.position.y
self.drag:set_drag_cursors(self.drag.can_x or self.drag.can_y)
end

View File

@ -391,10 +391,11 @@ end
--- Set text to text field
---@deprecated
---@param set_to string Text for node
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_to(set_to)
set_to = set_to or ""
set_to = tostring(set_to or "")
self.last_value = set_to
gui.set_text(self.node, set_to)
@ -407,9 +408,20 @@ function M:set_to(set_to)
end
function M:set_text(new_text)
---@diagnostic disable-next-line: deprecated
return self:set_to(new_text)
end
function M:get_text()
return self.last_value
end
--- Set text area size
---@param size vector3 The new text area size
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_size(size)
self.start_size = size
self.text_area = vmath.vector3(size)
@ -421,7 +433,7 @@ end
--- Set color
---@param color vector4 Color for node
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_color(color)
self.color = color
gui.set_color(self.node, color)
@ -432,7 +444,7 @@ end
--- Set alpha
---@param alpha number Alpha for node
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_alpha(alpha)
self.color.w = alpha
gui.set_color(self.node, self.color)
@ -443,7 +455,7 @@ end
--- Set scale
---@param scale vector3 Scale for node
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_scale(scale)
self.last_scale = scale
gui.set_scale(self.node, scale)
@ -454,7 +466,7 @@ end
--- Set text pivot. Text will re-anchor inside text area
---@param pivot number The gui.PIVOT_* constant
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_pivot(pivot)
local prev_pivot = gui.get_pivot(self.node)
local prev_offset = const.PIVOTS[prev_pivot]
@ -487,7 +499,7 @@ end
--- Set text adjust, refresh the current text visuals, if needed
---@param adjust_type string|nil See const.TEXT_ADJUST. If pass nil - use current adjust type
---@param minimal_scale number|nil If pass nil - not use minimal scale
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_text_adjust(adjust_type, minimal_scale)
self.adjust_type = adjust_type
self._minimal_scale = minimal_scale
@ -499,7 +511,7 @@ end
--- Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types
---@param minimal_scale number If pass nil - not use minimal scale
---@return Text Current text instance
---@return druid.text Current text instance
function M:set_minimal_scale(minimal_scale)
self._minimal_scale = minimal_scale

48
druid/bindings.lua Normal file
View File

@ -0,0 +1,48 @@
local event = require("event.event")
local M = {}
local WRAPPED_WIDGETS = {}
---Set a widget to the current game object. The game object can acquire the widget by calling `bindings.get_widget`
---It wraps only top level functions, so no access to nested widgets
---@param widget druid.widget
function M.set_widget(widget)
local object = msg.url()
object.fragment = nil
-- Make a copy of the widget with all functions wrapped in events
-- It makes available to call gui functions from game objects
local wrapped_widget = setmetatable({}, { __index = widget })
local parent_table = getmetatable(widget).__index
-- Go through all functions and wrap them in events
for key, value in pairs(parent_table) do
if type(value) == "function" then
wrapped_widget[key] = event.create(function(_, ...)
return value(widget, ...)
end)
end
end
WRAPPED_WIDGETS[object.socket] = WRAPPED_WIDGETS[object.socket] or {}
WRAPPED_WIDGETS[object.socket][object.path] = wrapped_widget
end
---@param object_url string|userdata|url @root object
---@return druid.widget|nil
function M.get_widget(object_url)
assert(object_url, "You must provide an object_url")
object_url = msg.url(object_url --[[@as string]])
local socket_widgets = WRAPPED_WIDGETS[object_url.socket]
if not socket_widgets then
return nil
end
return socket_widgets[object_url.path]
end
return M

View File

@ -13,6 +13,13 @@ local M = {}
---@param color_id string
---@return vector4
function M.get(color_id)
-- Check is it hex: starts with "#" or contains only 3 or 6 hex symbols
if type(color_id) == "string" then
if string.sub(color_id, 1, 1) == "#" or string.match(color_id, "^[0-9a-fA-F]+$") then
return M.hex2vector4(color_id)
end
end
return PALETTE_DATA[CURRENT_PALETTE] and PALETTE_DATA[CURRENT_PALETTE][color_id] or DEFAULT_COLOR
end

View File

@ -1,117 +1,35 @@
script: ""
fonts {
name: "text_bold"
font: "/example/assets/fonts/text_bold.font"
font: "/druid/fonts/text_bold.font"
}
textures {
name: "druid"
texture: "/example/assets/druid.atlas"
}
background_color {
x: 0.0
y: 0.0
z: 0.0
w: 0.0
texture: "/druid/druid.atlas"
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 500.0
y: 80.0
z: 0.0
w: 1.0
}
color {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
x: 200.0
y: 40.0
}
type: TYPE_BOX
blend_mode: BLEND_MODE_ALPHA
texture: ""
id: "root"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
adjust_mode: ADJUST_MODE_FIT
layer: ""
inherit_alpha: true
slice9 {
x: 0.0
y: 0.0
z: 0.0
w: 0.0
}
clipping_mode: CLIPPING_MODE_NONE
clipping_visible: true
clipping_inverted: false
alpha: 1.0
template_node_child: false
size_mode: SIZE_MODE_MANUAL
custom_type: 0
enabled: true
visible: false
material: ""
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 500.0
y: 80.0
z: 0.0
w: 1.0
x: 200.0
y: 40.0
}
color {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
x: 0.31
y: 0.318
z: 0.322
}
type: TYPE_BOX
blend_mode: BLEND_MODE_ALPHA
texture: "druid/rect_round2_width1"
texture: "druid/rect_round2_width2"
id: "button"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
adjust_mode: ADJUST_MODE_FIT
parent: "root"
layer: ""
inherit_alpha: true
slice9 {
x: 4.0
@ -119,192 +37,89 @@ nodes {
z: 4.0
w: 4.0
}
clipping_mode: CLIPPING_MODE_NONE
clipping_visible: true
clipping_inverted: false
alpha: 1.0
template_node_child: false
size_mode: SIZE_MODE_MANUAL
custom_type: 0
enabled: true
visible: true
material: ""
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
x: 0.5
y: 0.5
}
size {
x: 480.0
y: 60.0
z: 0.0
w: 1.0
x: 380.0
y: 50.0
}
color {
x: 0.31
y: 0.318
z: 0.322
w: 1.0
}
type: TYPE_TEXT
blend_mode: BLEND_MODE_ALPHA
text: "Placeholder"
font: "text_bold"
id: "placeholder_text"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
outline {
x: 0.4
y: 0.4
z: 0.4
w: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
line_break: false
parent: "button"
layer: ""
parent: "root"
inherit_alpha: true
alpha: 1.0
outline_alpha: 0.0
shadow_alpha: 0.0
template_node_child: false
text_leading: 1.0
text_tracking: 0.0
custom_type: 0
enabled: true
visible: true
material: ""
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
x: 0.5
y: 0.5
}
size {
x: 480.0
y: 60.0
z: 0.0
w: 1.0
x: 380.0
y: 50.0
}
color {
x: 0.722
y: 0.741
z: 0.761
w: 1.0
}
type: TYPE_TEXT
blend_mode: BLEND_MODE_ALPHA
text: "User input"
font: "text_bold"
id: "input_text"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
outline {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
line_break: false
parent: "button"
layer: ""
parent: "root"
inherit_alpha: true
alpha: 1.0
outline_alpha: 0.0
shadow_alpha: 0.0
template_node_child: false
text_leading: 1.0
text_tracking: 0.0
custom_type: 0
enabled: true
visible: true
material: ""
}
nodes {
position {
x: 118.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
x: 61.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
x: 0.5
y: 0.5
}
size {
x: 16.0
y: 50.0
z: 0.0
w: 1.0
}
color {
x: 0.631
y: 0.843
z: 0.961
w: 1.0
}
type: TYPE_BOX
blend_mode: BLEND_MODE_ALPHA
texture: "druid/ui_circle_16"
id: "cursor_node"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
adjust_mode: ADJUST_MODE_FIT
parent: "button"
layer: ""
parent: "root"
inherit_alpha: true
slice9 {
x: 8.0
@ -312,84 +127,34 @@ nodes {
z: 8.0
w: 8.0
}
clipping_mode: CLIPPING_MODE_NONE
clipping_visible: true
clipping_inverted: false
alpha: 0.5
template_node_child: false
size_mode: SIZE_MODE_MANUAL
custom_type: 0
enabled: true
visible: true
material: ""
}
nodes {
position {
x: 0.0
x: -1.4
y: 4.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.2
y: 1.2
z: 1.0
w: 1.0
}
size {
x: 20.0
y: 40.0
z: 0.0
w: 1.0
}
color {
x: 0.722
y: 0.741
z: 0.761
w: 1.0
}
type: TYPE_TEXT
blend_mode: BLEND_MODE_ALPHA
text: "|"
font: "text_bold"
id: "cursor_text"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
outline {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
line_break: false
parent: "cursor_node"
layer: ""
inherit_alpha: false
alpha: 1.0
outline_alpha: 0.0
shadow_alpha: 0.0
template_node_child: false
text_leading: 1.0
text_tracking: 0.0
custom_type: 0
enabled: true
visible: true
material: ""
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT
max_nodes: 512

View File

@ -22,4 +22,10 @@ images {
images {
image: "/druid/images/panels/rect_round2_width2.png"
}
images {
image: "/druid/images/icons/icon_drag.png"
}
images {
image: "/druid/images/icons/icon_arrow.png"
}
extrude_borders: 2

View File

@ -0,0 +1,15 @@
---@class widget.TEMPLATE: druid.widget
local M = {}
function M:init()
self.root = self:get_node("root")
self.button = self.druid:new_button("button"), self.on_button, self)
end
function M:on_button()
print("Root node", self.root)
end
return M

View File

@ -196,7 +196,7 @@ end
---Get current size of layout node
---@return vector3 size
function M:get_size()
return self.size
return vmath.vector3(self.size)
end

View File

@ -88,8 +88,8 @@ end
function M:set_padding(padding_x, padding_y, padding_z, padding_w)
self.padding.x = padding_x or self.padding.x
self.padding.y = padding_y or self.padding.y
self.padding.z = padding_z or padding_x or self.padding.z
self.padding.w = padding_w or padding_y or self.padding.w
self.padding.z = padding_z or self.padding.z
self.padding.w = padding_w or self.padding.w
self.is_dirty = true
return self
@ -153,7 +153,6 @@ function M:add(node_or_node_id)
---@cast node node
table.insert(self.entities, node)
gui.set_parent(node, self.node)
self.is_dirty = true
return self
@ -229,7 +228,7 @@ function M:refresh_layout()
local node_height = rows_data.nodes_height[node]
local pivot_offset = helper.get_pivot_offset(gui.get_pivot(node))
if node_width > 0 and node_height > 0 then
if node_width > 0 or node_height > 0 then
-- Calculate position for current node
local position_x, position_y
@ -396,7 +395,7 @@ function M:calculate_rows_data()
rows_data.nodes_height[node] = node_height
end
if node_width > 0 and node_height > 0 then
if node_width > 0 or node_height > 0 then
if type == "horizontal" then
current_row.width = current_row.width + node_width + margin.x
current_row.height = math.max(current_row.height, node_height)

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

View File

@ -0,0 +1,18 @@
#version 140
uniform sampler2D texture_sampler;
in vec2 var_texcoord0;
in vec4 var_color;
out vec4 color_out;
void main() {
lowp vec4 tex = texture(texture_sampler, var_texcoord0.xy);
if (tex.a < 0.5) {
discard;
}
// Final color of stencil texture
color_out = tex * var_color;
}

View File

@ -0,0 +1,8 @@
name: "repeat"
tags: "gui"
vertex_program: "/druid/materials/stencil/gui_stencil.vp"
fragment_program: "/druid/materials/stencil/gui_stencil.fp"
vertex_constants {
name: "view_proj"
type: CONSTANT_TYPE_VIEWPROJ
}

View File

@ -0,0 +1,20 @@
#version 140
uniform vertex_inputs {
highp mat4 view_proj;
};
// positions are in world space
in mediump vec3 position;
in mediump vec2 texcoord0;
in lowp vec4 color;
out mediump vec2 var_texcoord0;
out lowp vec4 var_color;
void main()
{
var_texcoord0 = texcoord0;
var_color = vec4(color.rgb * color.a, color.a);
gl_Position = view_proj * vec4(position.xyz, 1.0);
}

View File

@ -61,7 +61,7 @@ M["hover"] = {
}
M["drag"] = {
DRAG_DEADZONE = 4, -- Size in pixels of drag deadzone
DRAG_DEADZONE = 10, -- Size in pixels of drag deadzone
NO_USE_SCREEN_KOEF = false,
}

View File

@ -0,0 +1,2 @@
---@class druid.widget: druid.base_component
---@field druid druid_instance

View File

@ -733,7 +733,7 @@ local rich_input = require("druid.custom.rich_input.rich_input")
---Create RichInput component.
-- As a template please check rich_input.gui layout.
---@param template string The template string name
---@param nodes table Nodes table from gui.clone_tree
---@param nodes table|nil Nodes table from gui.clone_tree
---@return druid.rich_input RichInput component
function M:new_rich_input(template, nodes)
return self:new(rich_input, template, nodes)

View File

@ -0,0 +1,222 @@
fonts {
name: "text_regular"
font: "/druid/fonts/text_regular.font"
}
fonts {
name: "text_bold"
font: "/druid/fonts/text_bold.font"
}
textures {
name: "druid"
texture: "/druid/druid.atlas"
}
nodes {
size {
x: 200.0
y: 100.0
}
type: TYPE_BOX
id: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
type: TYPE_TEMPLATE
id: "mini_graph"
parent: "root"
inherit_alpha: true
template: "/druid/widget/mini_graph/mini_graph.gui"
}
nodes {
color {
x: 0.173
y: 0.184
z: 0.204
}
type: TYPE_BOX
id: "mini_graph/root"
parent: "mini_graph"
overridden_fields: 5
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "mini_graph/header"
parent: "mini_graph/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
text: "FPS"
id: "mini_graph/text_header"
parent: "mini_graph/header"
overridden_fields: 8
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "mini_graph/icon_drag"
parent: "mini_graph/header"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "mini_graph/content"
parent: "mini_graph/root"
template_node_child: true
}
nodes {
color {
x: 0.525
y: 0.525
z: 0.525
}
type: TYPE_BOX
id: "mini_graph/prefab_line"
parent: "mini_graph/content"
overridden_fields: 5
template_node_child: true
}
nodes {
color {
x: 0.957
y: 0.608
z: 0.608
}
type: TYPE_BOX
id: "mini_graph/color_low"
parent: "mini_graph/content"
overridden_fields: 5
template_node_child: true
}
nodes {
size {
x: 200.0
y: 100.0
}
type: TYPE_BOX
id: "content"
parent: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
position {
x: -96.0
y: 12.0
}
scale {
x: 0.3
y: 0.3
}
size {
x: 260.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "12 FPS"
font: "text_regular"
id: "text_min_fps"
pivot: PIVOT_W
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "content"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
y: 12.0
}
scale {
x: 0.3
y: 0.3
}
size {
x: 260.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "60 FPS"
font: "text_bold"
id: "text_fps"
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "content"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
x: -33.4
y: 30.0
}
size {
x: 3.0
y: 8.0
}
color {
x: 0.173
y: 0.184
z: 0.204
}
type: TYPE_BOX
texture: "druid/pixel"
id: "line_second_1"
pivot: PIVOT_N
parent: "content"
inherit_alpha: true
}
nodes {
position {
x: 33.2
y: 30.0
}
size {
x: 3.0
y: 8.0
}
color {
x: 0.173
y: 0.184
z: 0.204
}
type: TYPE_BOX
texture: "druid/pixel"
id: "line_second_2"
pivot: PIVOT_N
parent: "content"
inherit_alpha: true
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@ -0,0 +1,84 @@
local mini_graph = require("druid.widget.mini_graph.mini_graph")
---@class widget.fps_panel: druid.widget
---@field root node
local M = {}
local TARGET_FPS = sys.get_config_int("display.update_frequency", 60)
if TARGET_FPS == 0 then
TARGET_FPS = 60
end
function M:init()
self.delta_time = 0.1 -- in seconds
self.collect_time = 3 -- in seconds
self.collect_time_counter = 0
self.graph_samples = self.collect_time / self.delta_time
-- Store frame time in seconds last collect_time seconds
self.fps_samples = {}
self.mini_graph = self.druid:new_widget(mini_graph, "mini_graph")
self.mini_graph:set_samples(self.graph_samples) -- show last 30 seconds
self.mini_graph:set_max_value(TARGET_FPS)
gui.set_parent(self:get_node("content"), self.mini_graph.content, true)
self.text_min_fps = self.druid:new_text("text_min_fps")
self.text_fps = self.druid:new_text("text_fps")
self.timer_id = timer.delay(self.delta_time, true, function()
self:push_fps_value()
end)
end
function M:update(dt)
if not self.previous_time then
self.previous_time = socket.gettime()
return
end
local current_time = socket.gettime()
local delta_time = current_time - self.previous_time
self.previous_time = current_time
self.collect_time_counter = self.collect_time_counter + delta_time
table.insert(self.fps_samples, 1, delta_time)
while self.collect_time_counter > self.collect_time do
-- Remove last
local removed_value = table.remove(self.fps_samples)
self.collect_time_counter = self.collect_time_counter - removed_value
end
end
function M:push_fps_value()
if #self.fps_samples == 0 then
return
end
local max_frame_time = 0
local average_frame_time = 0
local average_samples_count = self.delta_time
local average_collected = 0
for index = 1, #self.fps_samples do
if average_frame_time < average_samples_count then
average_frame_time = average_frame_time + self.fps_samples[index]
average_collected = average_collected + 1
end
max_frame_time = math.max(max_frame_time, self.fps_samples[index])
end
average_frame_time = average_frame_time / average_collected
self.mini_graph:push_line_value(1 / average_frame_time)
self.text_fps:set_to(tostring(math.ceil(1 / average_frame_time) .. " FPS"))
local lowest_value = math.ceil(self.mini_graph:get_lowest_value())
self.text_min_fps:set_to(lowest_value .. " lowest")
end
return M

View File

@ -1,3 +1,15 @@
fonts {
name: "text_regular"
font: "/druid/fonts/text_regular.font"
}
fonts {
name: "text_bold"
font: "/druid/fonts/text_bold.font"
}
textures {
name: "druid"
texture: "/druid/druid.atlas"
}
nodes {
size {
x: 200.0
@ -23,36 +35,208 @@ nodes {
template_node_child: true
}
nodes {
type: TYPE_TEXT
text: "Memory Panel"
id: "mini_graph/text_header"
type: TYPE_BOX
id: "mini_graph/header"
parent: "mini_graph/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
text: "Memory"
id: "mini_graph/text_header"
parent: "mini_graph/header"
overridden_fields: 8
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "mini_graph/icon_drag"
parent: "mini_graph/root"
parent: "mini_graph/header"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "mini_graph/panel_diagram"
id: "mini_graph/content"
parent: "mini_graph/root"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "mini_graph/prefab_line"
parent: "mini_graph/panel_diagram"
parent: "mini_graph/content"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "mini_graph/text_value"
parent: "mini_graph/root"
type: TYPE_BOX
id: "mini_graph/color_low"
parent: "mini_graph/content"
template_node_child: true
}
nodes {
size {
x: 200.0
y: 100.0
}
type: TYPE_BOX
id: "content"
parent: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
position {
x: -96.0
y: 12.0
}
scale {
x: 0.3
y: 0.3
}
size {
x: 200.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "120.23 KB"
font: "text_regular"
id: "text_max_value"
pivot: PIVOT_W
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "content"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
x: 96.0
y: 12.0
}
scale {
x: 0.3
y: 0.3
}
size {
x: 200.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "120 KB/s"
font: "text_regular"
id: "text_per_second"
pivot: PIVOT_E
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "content"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
x: -33.4
y: 30.0
}
size {
x: 3.0
y: 8.0
}
color {
x: 0.173
y: 0.184
z: 0.204
}
type: TYPE_BOX
texture: "druid/pixel"
id: "line_second_1"
pivot: PIVOT_N
parent: "content"
inherit_alpha: true
}
nodes {
position {
x: 33.2
y: 30.0
}
size {
x: 3.0
y: 8.0
}
color {
x: 0.173
y: 0.184
z: 0.204
}
type: TYPE_BOX
texture: "druid/pixel"
id: "line_second_2"
pivot: PIVOT_N
parent: "content"
inherit_alpha: true
}
nodes {
position {
y: 12.0
}
scale {
x: 0.3
y: 0.3
}
size {
x: 200.0
y: 40.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "120 KB"
font: "text_bold"
id: "text_memory"
outline {
x: 1.0
y: 1.0
z: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
}
parent: "content"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@ -4,19 +4,73 @@ local mini_graph = require("druid.widget.mini_graph.mini_graph")
---@field root node
local M = {}
function M:init()
self.druid = self:get_druid()
self.delta_time = 0.1
self.samples_count = 30
self.memory_limit = 100
self.mini_graph = self.druid:new_widget(mini_graph, "mini_graph")
self.mini_graph:set_samples(self.samples_count)
gui.set_parent(self:get_node("content"), self.mini_graph.content, true)
--for index = 1, 32 do
-- self.mini_graph:set_line_value(index, 0)
--end
self.max_value = self.druid:new_text("text_max_value")
self.text_per_second = self.druid:new_text("text_per_second")
self.text_memory = self.druid:new_text("text_memory")
timer.delay(0.1, true, function()
self.mini_graph:push_line_value(math.random())
self.memory = collectgarbage("count")
self.memory_samples = {}
self:update_text_memory()
self.timer_id = timer.delay(self.delta_time, true, function()
self:push_next_value()
end)
end
function M:set_low_memory_limit(limit)
self.memory_limit = limit
end
function M:push_next_value()
local memory = collectgarbage("count")
local diff = math.max(0, memory - self.memory)
self.memory = memory
self:update_text_memory()
table.insert(self.memory_samples, diff)
if #self.memory_samples > self.samples_count then
table.remove(self.memory_samples, 1)
end
self.mini_graph:push_line_value(diff)
local max_value = math.max(unpack(self.memory_samples))
max_value = math.max(max_value, self.memory_limit) -- low limit to display
self.mini_graph:set_max_value(max_value)
local max_memory = math.ceil(self.mini_graph:get_highest_value())
self.max_value:set_to(max_memory .. " KB")
local last_second = 0
local last_second_samples = math.ceil(1 / self.delta_time)
for index = #self.memory_samples - last_second_samples + 1, #self.memory_samples do
last_second = last_second + (self.memory_samples[index] or 0)
end
self.text_per_second:set_to(math.ceil(last_second) .. " KB/s")
end
function M:update_text_memory()
local memory = math.ceil(collectgarbage("count")) -- in KB
if memory > 1024 then
memory = memory / 1024
self.text_memory:set_to(string.format("%.2f", memory) .. " MB")
else
self.text_memory:set_to(memory .. " KB")
end
end
return M

View File

@ -31,10 +31,26 @@ nodes {
w: 8.0
}
}
nodes {
position {
y: 70.0
}
size {
x: 200.0
y: 40.0
}
type: TYPE_BOX
id: "header"
pivot: PIVOT_N
parent: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
position {
x: -92.0
y: 63.0
y: -8.0
}
scale {
x: 0.5
@ -64,26 +80,26 @@ nodes {
y: 1.0
z: 1.0
}
parent: "root"
parent: "header"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
x: 92.0
y: 67.0
x: 96.0
y: -4.0
}
color {
x: 0.129
y: 0.141
z: 0.157
x: 0.306
y: 0.31
z: 0.314
}
type: TYPE_BOX
texture: "druid/ui_circle_32"
texture: "druid/icon_drag"
id: "icon_drag"
pivot: PIVOT_NE
parent: "root"
parent: "header"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
}
@ -102,7 +118,7 @@ nodes {
}
type: TYPE_BOX
texture: "druid/ui_circle_16"
id: "panel_diagram"
id: "content"
pivot: PIVOT_S
parent: "root"
inherit_alpha: true
@ -113,6 +129,7 @@ nodes {
w: 8.0
}
clipping_mode: CLIPPING_MODE_STENCIL
material: "gui_stencil"
}
nodes {
size {
@ -128,44 +145,32 @@ nodes {
texture: "druid/pixel"
id: "prefab_line"
pivot: PIVOT_S
parent: "panel_diagram"
parent: "content"
inherit_alpha: true
}
nodes {
position {
y: 12.0
}
scale {
x: 0.7
y: 0.7
x: -10.0
y: 4.0
}
size {
x: 260.0
y: 40.0
x: 8.0
y: 8.0
}
color {
x: 0.463
y: 0.475
z: 0.49
x: 0.557
y: 0.835
z: 0.62
}
type: TYPE_TEXT
text: "120.23 KB"
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: "root"
type: TYPE_BOX
texture: "druid/pixel"
id: "color_low"
parent: "content"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT
materials {
name: "gui_stencil"
material: "/druid/materials/stencil/gui_stencil.material"
}

View File

@ -7,25 +7,46 @@ local SIZE_Y = hash("size.y")
function M:init()
self.druid = self:get_druid()
self.root = self:get_node("root")
self.container = self.druid:new_container(self.root)
self.text_header = self.druid:new_text("text_header")
self.text_value = self.druid:new_text("text_value")
self.drag_corner = self.druid:new_drag("icon_drag", self.on_drag_corner)
self.layout = self.druid:new_layout("panel_diagram", "horizontal")
self.druid:new_drag("header", self.on_drag_widget)
self.druid:new_button("icon_drag", self.toggle_hide)
:set_style(nil)
self.content = self:get_node("content")
self.layout = self.druid:new_layout(self.content, "horizontal")
:set_margin(0, 0)
:set_padding(0, 0, 0, 0)
self.prefab_line = self:get_node("prefab_line")
gui.set_enabled(self.prefab_line, false)
self.color_zero = color.hex2vector4("#8ED59E")
self.color_one = color.hex2vector4("#F49B9B")
local node_color_low = self:get_node("color_low")
self.color_zero = gui.get_color(node_color_low)
self.color_one = gui.get_color(self.prefab_line)
gui.set_enabled(node_color_low, false)
self.is_hidden = false
self.max_value = 1 -- in this value line will be at max height
self.lines = {}
self.values = {}
self.samples = 64
self.container = self.druid:new_container(self.root)
self.container:add_container("header")
self.default_size = self.container:get_size()
end
function M:set_samples(samples)
self.samples = samples
self.layout:clear_layout()
for index = 1, #self.lines do
gui.delete_node(self.lines[index])
end
self.lines = {}
local line_width = self.layout:get_size().x / self.samples
for index = 1, self.samples do
local line = gui.clone(self.prefab_line)
@ -34,11 +55,6 @@ function M:init()
self.layout:add(line)
table.insert(self.lines, line)
end
for index = 1, self.samples do
local outsine = index/self.samples
self:set_line_value(index, outsine)
end
end
@ -50,39 +66,78 @@ function M:set_line_value(index, value)
return
end
local target_color = color.lerp(value * value, self.color_zero, self.color_one)
gui.set(line, SIZE_Y, value * 70)
gui.set_color(line, target_color)
self.values[index] = value
local normalized = vmath.clamp(value/self.max_value, 0, 1)
local target_color = color.lerp(normalized, self.color_zero, self.color_one)
gui.set_color(line, target_color)
self:set_line_height(index)
end
---@return number
function M:get_line_value(index)
return self.values[index]
return self.values[index] or 0
end
function M:push_line_value(value)
for index = 1, self.samples - 1 do
self:set_line_value(index, self:get_line_value(index + 1), true)
self:set_line_value(index, self:get_line_value(index + 1))
end
self:set_line_value(self.samples, value, true)
self:set_line_value(self.samples, value)
end
---@param text string
function M:set_text(text)
self.text_value:set_to(text)
function M:set_max_value(max_value)
if self.max_value == max_value then
return
end
self.max_value = max_value
for index = 1, self.samples do
self:set_line_height(index)
end
end
function M:on_drag_corner(dx, dy)
function M:set_line_height(index)
local value = self.values[index] or 0
local normalized = vmath.clamp(value / self.max_value, 0, 1)
local size_y = normalized * 70
gui.set(self.lines[index], SIZE_Y, size_y)
end
function M:get_lowest_value()
return math.min(unpack(self.values))
end
function M:get_highest_value()
return math.max(unpack(self.values))
end
function M:on_drag_widget(dx, dy)
local position = self.container:get_position()
self.container:set_position(position.x + dx, position.y + dy)
end
function M:toggle_hide()
self.is_hidden = not self.is_hidden
local hidden_size = gui.get_size(self:get_node("header"))
local new_size = self.is_hidden and hidden_size or self.default_size
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
return M

View File

@ -23,11 +23,11 @@ nodes {
x: -200.0
}
scale {
x: 0.65
y: 0.65
x: 0.5
y: 0.5
}
size {
x: 200.0
x: 350.0
y: 40.0
}
color {
@ -50,6 +50,7 @@ nodes {
y: 1.0
z: 1.0
}
adjust_mode: ADJUST_MODE_STRETCH
parent: "root"
inherit_alpha: true
outline_alpha: 0.0
@ -119,12 +120,12 @@ nodes {
}
nodes {
scale {
x: 0.65
y: 0.65
x: 0.5
y: 0.5
}
size {
x: 250.0
y: 30.0
x: 380.0
y: 50.0
}
color {
x: 0.722

View File

@ -1,3 +1,5 @@
local color = require("druid.color")
---@class property_button: druid.widget
---@field root node
---@field container druid.container
@ -7,11 +9,7 @@
---@field druid druid_instance
local M = {}
---@param template string
---@param nodes table<hash, node>
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes)
function M:init()
self.root = self:get_node("root")
self.text_name = self.druid:new_text("text_name")
self.selected = self:get_node("selected")
@ -21,7 +19,9 @@ function M:init(template, nodes)
self.text_button = self.druid:new_text("text_button")
self.container = self.druid:new_container(self.root)
self.container:add_container("text_name")
self.container:add_container("text_name", nil, function(_, size)
self.text_button:set_size(size)
end)
self.container:add_container("E_Anchor")
end
@ -32,4 +32,17 @@ function M:on_click()
end
---@param text string
---@return property_button
function M:set_text_button(text)
self.text_button:set_text(text)
return self
end
function M:set_color(color_value)
color.set_color(self:get_node("button"), color_value)
end
return M

View File

@ -23,11 +23,11 @@ nodes {
x: -200.0
}
scale {
x: 0.65
y: 0.65
x: 0.5
y: 0.5
}
size {
x: 200.0
x: 360.0
y: 40.0
}
color {

View File

@ -1,16 +1,13 @@
---@class property_checkbox: druid.widget
---@field root node
---@field druid druid_instance
---@field text_name druid.lang_text
---@field text_name druid.text
---@field button druid.button
---@field selected node
local M = {}
---@param template string
---@param nodes table<hash, node>
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes)
function M:init()
self.root = self:get_node("root")
self.icon = self:get_node("icon")
@ -19,7 +16,7 @@ function M:init(template, nodes)
self.selected = self:get_node("selected")
gui.set_alpha(self.selected, 0)
self.text_name = self.druid:new_lang_text("text_name")
self.text_name = self.druid:new_text("text_name")
self.button = self.druid:new_button("button", self.on_click)

View File

@ -0,0 +1,143 @@
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: 350.0
y: 50.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "Button"
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: -100.0
}
type: TYPE_TEMPLATE
id: "rich_input"
parent: "E_Anchor"
inherit_alpha: true
template: "/druid/custom/rich_input/rich_input.gui"
}
nodes {
type: TYPE_BOX
id: "rich_input/root"
parent: "rich_input"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "rich_input/button"
parent: "rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "rich_input/placeholder_text"
parent: "rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "rich_input/input_text"
parent: "rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "rich_input/cursor_node"
parent: "rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "rich_input/cursor_text"
parent: "rich_input/cursor_node"
template_node_child: true
}
nodes {
position {
x: -100.0
y: -20.0
}
size {
x: 200.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
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@ -0,0 +1,38 @@
---@class property_input: druid.widget
---@field root node
---@field container druid.container
---@field text_name druid.text
---@field button druid.button
---@field text_button druid.text
---@field druid druid_instance
local M = {}
function M:init()
self.root = self:get_node("root")
self.text_name = self.druid:new_text("text_name")
self.selected = self:get_node("selected")
gui.set_alpha(self.selected, 0)
self.rich_input = self.druid:new_rich_input("rich_input")
self.container = self.druid:new_container(self.root)
self.container:add_container("text_name")
self.container:add_container("E_Anchor")
end
function M:on_click()
gui.set_alpha(self.selected, 1)
gui.animate(self.selected, "color.w", 0, gui.EASING_INSINE, 0.16)
end
---@param text string
---@return property_input
function M:set_text_button(text)
self.text_button:set_text(text)
return self
end
return M

View File

@ -23,11 +23,11 @@ nodes {
x: -200.0
}
scale {
x: 0.65
y: 0.65
x: 0.5
y: 0.5
}
size {
x: 200.0
x: 380.0
y: 40.0
}
color {

View File

@ -2,23 +2,19 @@
---@field root node
---@field container druid.container
---@field druid druid_instance
---@field text_name druid.lang_text
---@field text_name druid.text
---@field text_value druid.text
---@field slider druid.slider
local M = {}
---@param template string
---@param nodes table<hash, node>
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes)
function M:init()
self.root = self:get_node("root")
self.selected = self:get_node("selected")
gui.set_alpha(self.selected, 0)
self._value = 0
self.text_name = self.druid:new_lang_text("text_name") --[[@as druid.lang_text]]
self.text_name = self.druid:new_text("text_name")
self.text_value = self.druid:new_text("text_value")
self.slider = self.druid:new_slider("slider_pin", vmath.vector3(55, 0, 0), self._on_slider_change_by_user) --[[@as druid.slider]]
self.slider:set_input_node("slider")
@ -36,7 +32,7 @@ end
---@param callback fun(value:number):string
function M:set_text_function(callback)
self._text_function = callback
self.text_value:set_to(self._text_function(self._value))
self.text_value:set_text(self._text_function(self._value))
end

View File

@ -0,0 +1,96 @@
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: 400.0
y: 50.0
}
color {
x: 0.463
y: 0.475
z: 0.49
}
type: TYPE_TEXT
text: "Text"
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
}
scale {
x: 0.5
y: 0.5
}
size {
x: 350.0
y: 50.0
}
color {
x: 0.722
y: 0.741
z: 0.761
}
type: TYPE_TEXT
text: "Text"
font: "text_bold"
id: "text_right"
pivot: PIVOT_E
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
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@ -0,0 +1,39 @@
---@class property_text: druid.widget
---@field root node
---@field container druid.container
---@field text_name druid.text
---@field text_right druid.text
local M = {}
function M:init()
self.root = self:get_node("root")
self.text_name = self.druid:new_text("text_name")
self.text_right = self.druid:new_text("text_right", "")
self.container = self.druid:new_container(self.root)
self.container:add_container("text_name", nil, function(_, size)
self.text_name:set_size(size)
end)
self.container:add_container("text_right", nil, function(_, size)
self.text_right:set_size(size)
end)
end
---@param text string
---@return property_text
function M:set_text(text)
self.text_name:set_text(text)
return self
end
---@param text string
---@return property_text
function M:set_right_text(text)
self.text_right:set_text(text or "")
return self
end
return M

View File

@ -33,15 +33,31 @@ nodes {
}
nodes {
position {
x: -192.0
y: 116.0
}
scale {
x: 0.8
y: 0.8
y: 120.0
}
size {
x: 245.0
x: 400.0
y: 40.0
}
type: TYPE_BOX
id: "header"
pivot: PIVOT_N
parent: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
position {
x: -192.0
y: -8.0
}
scale {
x: 0.5
y: 0.5
}
size {
x: 500.0
y: 50.0
}
color {
@ -64,15 +80,49 @@ nodes {
y: 1.0
z: 1.0
}
parent: "root"
parent: "header"
inherit_alpha: true
outline_alpha: 0.0
shadow_alpha: 0.0
}
nodes {
position {
x: 192.0
y: -4.0
}
color {
x: 0.306
y: 0.31
z: 0.314
}
type: TYPE_BOX
texture: "druid/icon_drag"
id: "icon_drag"
pivot: PIVOT_NE
parent: "header"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
}
nodes {
position {
y: -120.0
}
size {
x: 400.0
y: 190.0
}
type: TYPE_BOX
id: "content"
pivot: PIVOT_S
parent: "root"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
}
nodes {
position {
x: -200.0
y: 70.0
y: 190.0
}
size {
x: 400.0
@ -84,7 +134,7 @@ nodes {
xanchor: XANCHOR_LEFT
pivot: PIVOT_NW
adjust_mode: ADJUST_MODE_STRETCH
parent: "root"
parent: "content"
inherit_alpha: true
clipping_mode: CLIPPING_MODE_STENCIL
}
@ -109,51 +159,12 @@ nodes {
}
nodes {
position {
x: -200.0
y: 115.0
}
scale {
x: 0.7
y: 0.7
}
size {
x: 570.0
y: 50.0
}
color {
x: 0.31
y: 0.318
z: 0.322
}
type: TYPE_TEXT
text: "No properties for this example"
font: "text_regular"
id: "text_no_properties"
pivot: PIVOT_NW
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
enabled: false
}
nodes {
position {
y: 50.0
y: 170.0
}
type: TYPE_BOX
texture: "druid/empty"
id: "propeties"
parent: "root"
parent: "content"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
visible: false
@ -313,21 +324,107 @@ nodes {
}
nodes {
position {
x: 192.0
y: 112.0
y: -150.0
}
color {
x: 0.129
y: 0.141
z: 0.157
}
type: TYPE_BOX
texture: "druid/ui_circle_32"
id: "icon_drag"
pivot: PIVOT_NE
parent: "root"
type: TYPE_TEMPLATE
id: "property_input"
parent: "propeties"
inherit_alpha: true
size_mode: SIZE_MODE_AUTO
template: "/druid/widget/properties_panel/properties/property_input.gui"
}
nodes {
type: TYPE_BOX
id: "property_input/root"
parent: "property_input"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_input/text_name"
parent: "property_input/root"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_input/E_Anchor"
parent: "property_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEMPLATE
id: "property_input/rich_input"
parent: "property_input/E_Anchor"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_input/rich_input/root"
parent: "property_input/rich_input"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_input/rich_input/button"
parent: "property_input/rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_input/rich_input/placeholder_text"
parent: "property_input/rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_input/rich_input/input_text"
parent: "property_input/rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_input/rich_input/cursor_node"
parent: "property_input/rich_input/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_input/rich_input/cursor_text"
parent: "property_input/rich_input/cursor_node"
template_node_child: true
}
nodes {
type: TYPE_BOX
id: "property_input/selected"
parent: "property_input/E_Anchor"
template_node_child: true
}
nodes {
position {
y: -200.0
}
type: TYPE_TEMPLATE
id: "property_text"
parent: "propeties"
inherit_alpha: true
template: "/druid/widget/properties_panel/properties/property_text.gui"
}
nodes {
type: TYPE_BOX
id: "property_text/root"
parent: "property_text"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_text/text_name"
parent: "property_text/root"
template_node_child: true
}
nodes {
type: TYPE_TEXT
id: "property_text/text_right"
parent: "property_text/root"
template_node_child: true
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT

View File

@ -1,32 +1,41 @@
local property_checkbox = require("druid.widget.properties_panel.properties.property_checkbox")
local property_slider = require("druid.widget.properties_panel.properties.property_slider")
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")
---@class properties_panel: druid.widget
---@field root node
---@field text_no_properties node
---@field scroll druid.scroll
---@field druid druid_instance
local M = {}
---@param template string
---@param nodes table<hash, node>
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes)
--self.root = self.druid:new_container("root")
function M:init()
self.root = self:get_node("root")
self.text_no_properties = self:get_node("text_no_properties")
self.content = self:get_node("content")
self.container = self.druid:new_container(self.root)
self.container:add_container("header")
self.container_content = self.container:add_container("content")
self.container_scroll_view = self.container_content:add_container("scroll_view")
self.contaienr_scroll_content = self.container_scroll_view:add_container("scroll_content")
self.default_size = self.container:get_size()
self.properties = {}
self.text_header = self.druid:new_text("text_header")
self.scroll = self.druid:new_scroll("scroll_view", "scroll_content")
self.layout = self.druid:new_layout("scroll_content", "vertical")
:set_hug_content(false, true)
:set_padding(nil, 0)
self.layout.on_size_changed:subscribe(self.on_size_changed, self)
self.drag_corner = self.druid:new_drag("icon_drag", self.on_drag_corner)
self.druid:new_drag("header", self.on_drag_widget)
self.druid:new_button("icon_drag", self.toggle_hide)
:set_style(nil)
self.property_checkbox_prefab = self:get_node("property_checkbox/root")
gui.set_enabled(self.property_checkbox_prefab, false)
@ -37,17 +46,15 @@ function M:init(template, nodes)
self.property_button_prefab = self:get_node("property_button/root")
gui.set_enabled(self.property_button_prefab, false)
self.container = self.druid:new_container(self.root)
self.container:add_container("text_header")
self.container:add_container("icon_drag")
--self.container:create_draggable_corners()
self.property_input_prefab = self:get_node("property_input/root")
gui.set_enabled(self.property_input_prefab, false)
self.container_scroll_view = self.container:add_container("scroll_view")
self.contaienr_scroll_content = self.container_scroll_view:add_container("scroll_content")
self.property_text_prefab = self:get_node("property_text/root")
gui.set_enabled(self.property_text_prefab, false)
end
function M:on_drag_corner(dx, dy)
function M:on_drag_widget(dx, dy)
local position = self.container:get_position()
self.container:set_position(position.x + dx, position.y + dy)
end
@ -55,15 +62,21 @@ end
function M:clear()
for index = 1, #self.properties do
gui.delete_node(self.properties[index].root)
self.druid:remove(self.properties[index])
end
self.layout:clear_layout()
self.properties = {}
gui.set_enabled(self.text_no_properties, true)
end
function M:on_size_changed(new_size)
self.container:set_size(new_size.x, new_size.y + 50, gui.PIVOT_N)
self.container_content:set_size(new_size.x, new_size.y, gui.PIVOT_N)
self.default_size = vmath.vector3(new_size.x, new_size.y + 50, 0)
if not self.is_hidden then
self.container:set_size(self.default_size.x, self.default_size.y, gui.PIVOT_N)
end
local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z
for index = 1, #self.properties do
@ -72,51 +85,39 @@ function M:on_size_changed(new_size)
end
---@param text_id string
---@param text string
---@param initial_value boolean
---@param on_change_callback function
---@return property_checkbox
function M:add_checkbox(text_id, initial_value, on_change_callback)
function M:add_checkbox(text, initial_value, on_change_callback)
text = tostring(text)
local nodes = gui.clone_tree(self.property_checkbox_prefab)
local instance = self.druid:new_widget(property_checkbox, "property_checkbox", nodes)
instance.text_name:set_to(text_id)
self:add_property(instance)
instance.text_name:set_to(text)
instance:set_value(initial_value, true)
instance.button.on_click:subscribe(function()
on_change_callback(instance:get_value())
end)
gui.set_enabled(instance.root, true)
self.layout:add(instance.root)
table.insert(self.properties, instance)
local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z
instance.container:set_size(width)
gui.set_enabled(self.text_no_properties, false)
return instance
end
---@param text_id string
---@param text string
---@param initial_value number
---@param on_change_callback function
---@return property_slider
function M:add_slider(text_id, initial_value, on_change_callback)
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)
instance.text_name:set_to(text_id)
self:add_property(instance)
instance.text_name:set_text(text)
instance:set_value(initial_value, true)
gui.set_enabled(instance.root, true)
self.layout:add(instance.root)
table.insert(self.properties, instance)
local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z
instance.container:set_size(width)
gui.set_enabled(self.text_no_properties, false)
instance.slider.on_change_value:subscribe(function(_, value)
on_change_callback(value)
end)
@ -125,23 +126,15 @@ function M:add_slider(text_id, initial_value, on_change_callback)
end
---@param text_id string
---@param text string
---@param on_click_callback function|nil
---@param callback_context any|nil
function M:add_button(text_id, on_click_callback, callback_context)
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)
instance.text_name:set_to(text_id)
gui.set_enabled(instance.root, true)
self.layout:add(instance.root)
table.insert(self.properties, instance)
local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z
instance.container:set_size(width)
gui.set_enabled(self.text_no_properties, false)
self:add_property(instance)
instance.text_name:set_text(text)
if on_click_callback then
instance.button.on_click:subscribe(on_click_callback, callback_context)
end
@ -150,6 +143,48 @@ function M:add_button(text_id, on_click_callback, callback_context)
end
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)
instance.text_name:set_text(text)
instance.rich_input:set_text(initial_value)
instance.rich_input:set_placeholder("")
instance.rich_input.input.on_input_unselect:subscribe(function(_, value)
on_change_callback(value)
end)
end
---@param text string
---@param right_text string|nil
---@return 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)
instance:set_text(text)
instance:set_right_text(right_text)
return instance
end
---@private
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)
return widget
end
function M:remove(widget)
for index = 1, #self.properties do
if self.properties[index] == widget then
@ -160,10 +195,19 @@ function M:remove(widget)
break
end
end
if #self.properties == 0 then
gui.set_enabled(self.text_no_properties, true)
end
function M:toggle_hide()
self.is_hidden = not self.is_hidden
local hidden_size = gui.get_size(self:get_node("header"))
local new_size = self.is_hidden and hidden_size or self.default_size
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