From c35dfc70660d2507e09363c682af49238b647da9 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 19 Nov 2024 23:06:57 +0200 Subject: [PATCH] More widgets stuff, cleaning code --- druid/base/drag.lua | 16 + druid/base/scroll.lua | 2 + druid/base/text.lua | 30 +- druid/bindings.lua | 48 +++ druid/color.lua | 7 + druid/custom/rich_input/rich_input.gui | 285 ++---------------- druid/druid.atlas | 6 + druid/editor_scripts/widget.lua_template | 15 + druid/extended/container.lua | 2 +- druid/extended/layout.lua | 9 +- druid/images/icons/icon_arrow.png | Bin 0 -> 330 bytes druid/images/icons/icon_drag.png | Bin 0 -> 200 bytes druid/materials/stencil/gui_stencil.fp | 18 ++ druid/materials/stencil/gui_stencil.material | 8 + druid/materials/stencil/gui_stencil.vp | 20 ++ druid/styles/default/style.lua | 2 +- druid/system/druid_annotations.lua | 2 + druid/system/druid_instance.lua | 2 +- druid/widget/fps_panel/fps_panel.gui | 222 ++++++++++++++ druid/widget/fps_panel/fps_panel.lua | 84 ++++++ druid/widget/memory_panel/memory_panel.gui | 202 ++++++++++++- druid/widget/memory_panel/memory_panel.lua | 68 ++++- druid/widget/mini_graph/mini_graph.gui | 81 ++--- druid/widget/mini_graph/mini_graph.lua | 101 +++++-- .../properties/property_button.gui | 15 +- .../properties/property_button.lua | 25 +- .../properties/property_checkbox.gui | 6 +- .../properties/property_checkbox.lua | 9 +- .../properties/property_input.gui | 143 +++++++++ .../properties/property_input.lua | 38 +++ .../properties/property_slider.gui | 6 +- .../properties/property_slider.lua | 12 +- .../properties/property_text.gui | 96 ++++++ .../properties/property_text.lua | 39 +++ .../properties_panel/properties_panel.gui | 225 ++++++++++---- .../properties_panel/properties_panel.lua | 158 ++++++---- 36 files changed, 1494 insertions(+), 508 deletions(-) create mode 100644 druid/bindings.lua create mode 100644 druid/editor_scripts/widget.lua_template create mode 100644 druid/images/icons/icon_arrow.png create mode 100644 druid/images/icons/icon_drag.png create mode 100644 druid/materials/stencil/gui_stencil.fp create mode 100644 druid/materials/stencil/gui_stencil.material create mode 100644 druid/materials/stencil/gui_stencil.vp create mode 100644 druid/system/druid_annotations.lua create mode 100644 druid/widget/fps_panel/fps_panel.gui create mode 100644 druid/widget/fps_panel/fps_panel.lua create mode 100644 druid/widget/properties_panel/properties/property_input.gui create mode 100644 druid/widget/properties_panel/properties/property_input.lua create mode 100644 druid/widget/properties_panel/properties/property_text.gui create mode 100644 druid/widget/properties_panel/properties/property_text.lua diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 5458900..0b0b36f 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -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 diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 55f632a..077dc8f 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -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 diff --git a/druid/base/text.lua b/druid/base/text.lua index f00b506..1c9e9d3 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -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 diff --git a/druid/bindings.lua b/druid/bindings.lua new file mode 100644 index 0000000..15f87a4 --- /dev/null +++ b/druid/bindings.lua @@ -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 diff --git a/druid/color.lua b/druid/color.lua index d677233..8a1ccc9 100644 --- a/druid/color.lua +++ b/druid/color.lua @@ -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 diff --git a/druid/custom/rich_input/rich_input.gui b/druid/custom/rich_input/rich_input.gui index 5467ee9..46c7d7f 100644 --- a/druid/custom/rich_input/rich_input.gui +++ b/druid/custom/rich_input/rich_input.gui @@ -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 diff --git a/druid/druid.atlas b/druid/druid.atlas index 59904d2..10868c4 100644 --- a/druid/druid.atlas +++ b/druid/druid.atlas @@ -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 diff --git a/druid/editor_scripts/widget.lua_template b/druid/editor_scripts/widget.lua_template new file mode 100644 index 0000000..18875f6 --- /dev/null +++ b/druid/editor_scripts/widget.lua_template @@ -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 \ No newline at end of file diff --git a/druid/extended/container.lua b/druid/extended/container.lua index 3a4a17f..317e2bb 100644 --- a/druid/extended/container.lua +++ b/druid/extended/container.lua @@ -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 diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 804e518..c06752e 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -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) diff --git a/druid/images/icons/icon_arrow.png b/druid/images/icons/icon_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..40fbf2a8dbb946fad836f98e07fae61eac6d44a3 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND9BhG zN6VhIDT3pdFnG@l6 z!1nN6^Y%4r1y@_5IZbXAa5pM9N#5(4B+)3_6n;s(=6-yg^Hv_l`PXKgcUSv7`3@sr XWA2+%6SdX?y~^O}>gTe~DWM4fs?T{W literal 0 HcmV?d00001 diff --git a/druid/images/icons/icon_drag.png b/druid/images/icons/icon_drag.png new file mode 100644 index 0000000000000000000000000000000000000000..3bd2c35abb6704ce93a317cf37f1ae2f21abea59 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND9BhG zC zJntUf4{vOxG)?yTJ85v(iwZI9nYvqFm#= 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 \ No newline at end of file diff --git a/druid/widget/memory_panel/memory_panel.gui b/druid/widget/memory_panel/memory_panel.gui index c1ed80a..d0c9c9a 100644 --- a/druid/widget/memory_panel/memory_panel.gui +++ b/druid/widget/memory_panel/memory_panel.gui @@ -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 diff --git a/druid/widget/memory_panel/memory_panel.lua b/druid/widget/memory_panel/memory_panel.lua index 800447a..672751a 100644 --- a/druid/widget/memory_panel/memory_panel.lua +++ b/druid/widget/memory_panel/memory_panel.lua @@ -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 \ No newline at end of file diff --git a/druid/widget/mini_graph/mini_graph.gui b/druid/widget/mini_graph/mini_graph.gui index 1de9224..ceefa96 100644 --- a/druid/widget/mini_graph/mini_graph.gui +++ b/druid/widget/mini_graph/mini_graph.gui @@ -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" +} diff --git a/druid/widget/mini_graph/mini_graph.lua b/druid/widget/mini_graph/mini_graph.lua index 553a1b8..cf266fc 100644 --- a/druid/widget/mini_graph/mini_graph.lua +++ b/druid/widget/mini_graph/mini_graph.lua @@ -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 \ No newline at end of file diff --git a/druid/widget/properties_panel/properties/property_button.gui b/druid/widget/properties_panel/properties/property_button.gui index 8876f9e..6efe3df 100644 --- a/druid/widget/properties_panel/properties/property_button.gui +++ b/druid/widget/properties_panel/properties/property_button.gui @@ -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 diff --git a/druid/widget/properties_panel/properties/property_button.lua b/druid/widget/properties_panel/properties/property_button.lua index 71b30f6..27368bf 100644 --- a/druid/widget/properties_panel/properties/property_button.lua +++ b/druid/widget/properties_panel/properties/property_button.lua @@ -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 -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 diff --git a/druid/widget/properties_panel/properties/property_checkbox.gui b/druid/widget/properties_panel/properties/property_checkbox.gui index a8b5ba0..59824fd 100644 --- a/druid/widget/properties_panel/properties/property_checkbox.gui +++ b/druid/widget/properties_panel/properties/property_checkbox.gui @@ -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 { diff --git a/druid/widget/properties_panel/properties/property_checkbox.lua b/druid/widget/properties_panel/properties/property_checkbox.lua index 30f1793..345e59e 100644 --- a/druid/widget/properties_panel/properties/property_checkbox.lua +++ b/druid/widget/properties_panel/properties/property_checkbox.lua @@ -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 -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) diff --git a/druid/widget/properties_panel/properties/property_input.gui b/druid/widget/properties_panel/properties/property_input.gui new file mode 100644 index 0000000..59b6101 --- /dev/null +++ b/druid/widget/properties_panel/properties/property_input.gui @@ -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 diff --git a/druid/widget/properties_panel/properties/property_input.lua b/druid/widget/properties_panel/properties/property_input.lua new file mode 100644 index 0000000..ede2073 --- /dev/null +++ b/druid/widget/properties_panel/properties/property_input.lua @@ -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 diff --git a/druid/widget/properties_panel/properties/property_slider.gui b/druid/widget/properties_panel/properties/property_slider.gui index 89c26a1..a0bb0a4 100644 --- a/druid/widget/properties_panel/properties/property_slider.gui +++ b/druid/widget/properties_panel/properties/property_slider.gui @@ -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 { diff --git a/druid/widget/properties_panel/properties/property_slider.lua b/druid/widget/properties_panel/properties/property_slider.lua index 90156a0..cb89b09 100644 --- a/druid/widget/properties_panel/properties/property_slider.lua +++ b/druid/widget/properties_panel/properties/property_slider.lua @@ -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 -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 diff --git a/druid/widget/properties_panel/properties/property_text.gui b/druid/widget/properties_panel/properties/property_text.gui new file mode 100644 index 0000000..8966c90 --- /dev/null +++ b/druid/widget/properties_panel/properties/property_text.gui @@ -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 diff --git a/druid/widget/properties_panel/properties/property_text.lua b/druid/widget/properties_panel/properties/property_text.lua new file mode 100644 index 0000000..0f8b69d --- /dev/null +++ b/druid/widget/properties_panel/properties/property_text.lua @@ -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 diff --git a/druid/widget/properties_panel/properties_panel.gui b/druid/widget/properties_panel/properties_panel.gui index 4365bd7..2df907a 100644 --- a/druid/widget/properties_panel/properties_panel.gui +++ b/druid/widget/properties_panel/properties_panel.gui @@ -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 diff --git a/druid/widget/properties_panel/properties_panel.lua b/druid/widget/properties_panel/properties_panel.lua index 5502ff8..7cae30d 100644 --- a/druid/widget/properties_panel/properties_panel.lua +++ b/druid/widget/properties_panel/properties_panel.lua @@ -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 -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 +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