diff --git a/druid/base/drag.lua b/druid/base/drag.lua index b51c1af..7884ab7 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -17,10 +17,10 @@ --- Event on drag start callback(self) -- @tfield DruidEvent on_drag_start @{DruidEvent} ---- on drag progress callback(self, dx, dy) +--- on drag progress callback(self, dx, dy, total_x, total_y) -- @tfield DruidEvent on_drag Event @{DruidEvent} ---- Event on drag end callback(self) +--- Event on drag end callback(self, total_x, total_y) -- @tfield DruidEvent on_drag_end @{DruidEvent} --- Is component now touching @@ -70,7 +70,7 @@ end local function end_touch(self) if self.is_drag then - self.on_drag_end:trigger(self:get_context()) + self.on_drag_end:trigger(self:get_context(), self.x - self.touch_start_pos.x, self.y - self.touch_start_pos.y) end self.is_drag = false @@ -96,7 +96,7 @@ local function process_touch(self, touch) if not self.is_drag and distance >= self.style.DRAG_DEADZONE then self.is_drag = true self.on_drag_start:trigger(self:get_context()) - self:set_input_priority(const.PRIORITY_INPUT_MAX) + self:set_input_priority(const.PRIORITY_INPUT_MAX, true) end end @@ -176,6 +176,7 @@ function Drag.init(self, node, on_drag_callback) self.is_touch = false self.is_drag = false self.touch_start_pos = vmath.vector3(0) + self._is_disabled = false self.can_x = true self.can_y = true @@ -186,6 +187,8 @@ function Drag.init(self, node, on_drag_callback) self.on_drag_start = Event() self.on_drag = Event(on_drag_callback) self.on_drag_end = Event() + + self:on_window_resized() end @@ -199,6 +202,13 @@ function Drag.on_late_init(self) end +function Drag.on_window_resized(self) + local x_koef, y_koef = helper.get_screen_aspect_koef() + self._x_koef = x_koef + self._y_koef = y_koef +end + + function Drag.on_input_interrupt(self) if self.is_drag or self.is_touch then end_touch(self) @@ -211,7 +221,7 @@ function Drag.on_input(self, action_id, action) return false end - if not helper.is_enabled(self.node) then + if not helper.is_enabled(self.node) or self._is_disabled then return false end @@ -268,7 +278,7 @@ function Drag.on_input(self, action_id, action) end if self.is_drag then - self.on_drag:trigger(self:get_context(), self.dx, self.dy) + self.on_drag:trigger(self:get_context(), self.dx, self.dy, self.x - self.touch_start_pos.x, self.y - self.touch_start_pos.y) end return self.is_drag @@ -284,4 +294,21 @@ function Drag.set_click_zone(self, node) end +--- Set Drag input enabled or disabled +-- @tparam Drag self @{Drag} +-- @tparam bool is enabled +function Drag.set_enabled(self, is_enabled) + self._is_disabled = not is_enabled +end + + +--- Check if Drag component is enabled +-- @tparam Drag self @{Drag} +-- @treturn bool +function Drag.is_enabled(self) + return self._is_disabled +end + + + return Drag diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index 405c1e8..a08788d 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -33,9 +33,12 @@ --- The last index of node in grid -- @tfield number last_index ---- Item anchor +--- Item anchor [0..1] -- @tfield vector3 anchor +--- Item pivot [-0.5..0.5] +-- @tfield vector3 pivot + --- Item size -- @tfield vector3 node_size diff --git a/druid/base/text.lua b/druid/base/text.lua index 566aba9..8981ccc 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -240,10 +240,16 @@ end -- @treturn number Height function Text.get_text_size(self, text) text = text or self.last_value - local font = gui.get_font(self.node) + local font_name = gui.get_font(self.node) + local font = gui.get_font_resource(font_name) local scale = gui.get_scale(self.node) local linebreak = gui.get_line_break(self.node) - local metrics = gui.get_text_metrics(font, text, 0, linebreak, 0, 0) + local metrics = resource.get_text_metrics(font, text, { + line_break = linebreak, + leading = 1, + tracking = 0, + width = self.start_size.x + }) local width = metrics.width for i = #text, 1, -1 do local c = string.sub(text, i, i) diff --git a/druid/component.lua b/druid/component.lua index e63fecf..e71add0 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -25,6 +25,7 @@ BaseComponent.ON_FOCUS_LOST = const.ON_FOCUS_LOST BaseComponent.ON_FOCUS_GAINED = const.ON_FOCUS_GAINED BaseComponent.ON_LAYOUT_CHANGE = const.ON_LAYOUT_CHANGE BaseComponent.ON_MESSAGE_INPUT = const.ON_MESSAGE_INPUT +BaseComponent.ON_WINDOW_RESIZED = const.ON_WINDOW_RESIZED BaseComponent.ON_LANGUAGE_CHANGE = const.ON_LANGUAGE_CHANGE @@ -37,6 +38,7 @@ BaseComponent.ALL_INTERESTS = { BaseComponent.ON_FOCUS_GAINED, BaseComponent.ON_LAYOUT_CHANGE, BaseComponent.ON_MESSAGE_INPUT, + BaseComponent.ON_WINDOW_RESIZED, BaseComponent.ON_LANGUAGE_CHANGE, } @@ -46,6 +48,7 @@ BaseComponent.SPECIFIC_UI_MESSAGES = { [hash("layout_changed")] = BaseComponent.ON_LAYOUT_CHANGE, -- The message_id from Defold [hash(BaseComponent.ON_FOCUS_LOST)] = BaseComponent.ON_FOCUS_LOST, [hash(BaseComponent.ON_FOCUS_GAINED)] = BaseComponent.ON_FOCUS_GAINED, + [hash(BaseComponent.ON_WINDOW_RESIZED)] = BaseComponent.ON_WINDOW_RESIZED, [hash(BaseComponent.ON_MESSAGE_INPUT)] = BaseComponent.ON_MESSAGE_INPUT, [hash(BaseComponent.ON_LANGUAGE_CHANGE)] = BaseComponent.ON_LANGUAGE_CHANGE, } @@ -170,7 +173,7 @@ function BaseComponent.get_node(self, node_or_name) end if not node then - assert(node, "No component with name: " .. template_name .. node_or_name) + assert(node, "No component with name: " .. (template_name or "") .. (node_or_name or "")) end return node @@ -215,17 +218,22 @@ end --- Set component input priority -- @tparam BaseComponent self @{BaseComponent} -- @tparam number value The new input priority value +-- @tparam boolean is_temporary If true, the reset input priority will return to previous value -- @treturn number The component input priority -function BaseComponent.set_input_priority(self, value) +function BaseComponent.set_input_priority(self, value, is_temporary) assert(value) if self._component.input_priority ~= value then self._component.input_priority = value self._component._is_input_priority_changed = true + if not is_temporary then + self._component.default_input_priority = value + end + local children = self:get_childrens() for i = 1, #children do - children[i]:set_input_priority(value) + children[i]:set_input_priority(value, is_temporary) end end diff --git a/druid/const.lua b/druid/const.lua index c40fc58..d05c537 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -40,6 +40,7 @@ M.ON_FOCUS_LOST = "on_focus_lost" M.ON_FOCUS_GAINED = "on_focus_gained" M.ON_LAYOUT_CHANGE = "on_layout_change" M.ON_MESSAGE_INPUT = "on_message_input" +M.ON_WINDOW_RESIZED = "on_window_resized" M.ON_LANGUAGE_CHANGE = "on_language_change" @@ -83,6 +84,16 @@ M.REVERSE_PIVOTS = { } +M.LAYOUT_MODE = { + STRETCH_X = "stretch_x", + STRETCH_Y = "stretch_y", + ZOOM_MIN = "zoom_min", + ZOOM_MAX = "zoom_max", + FIT = gui.ADJUST_FIT, + STRETCH = gui.ADJUST_STRETCH, +} + + M.VECTOR_ZERO = vmath.vector3(0) M.VECTOR_ONE = vmath.vector3(1) M.SYS_INFO = sys.get_sys_info() diff --git a/druid/druid.lua b/druid/druid.lua index ed5303f..44f13c6 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -117,6 +117,12 @@ function M.on_window_callback(event) msg.post(instances[i].url, base_component.ON_FOCUS_GAINED) end end + + if event == window.WINDOW_EVENT_RESIZED then + for i = 1, #instances do + msg.post(instances[i].url, base_component.ON_WINDOW_RESIZED) + end + end end diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua new file mode 100644 index 0000000..e95bdf3 --- /dev/null +++ b/druid/extended/hotkey.lua @@ -0,0 +1,148 @@ +-- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license + +--- Druid hotkey component +-- @module Hotkey +-- @within BaseComponent +-- @alias druid.hotkey + +--- On change state callback(self, state) +-- @tfield DruidEvent on_change_state @{DruidEvent} + +--- Visual node +-- @tfield node node + +--- Button trigger node +-- @tfield[opt=node] node click_node + +--- Button component from click_node +-- @tfield Button button @{Button} + +--- + +local helper = require("druid.helper") +local component = require("druid.component") + +local Hotkey = component.create("hotkey") + + +--- Component init function +-- @tparam Hotkey self @{Hotkey} +-- @tparam string[]|string keys The keys to be pressed for trigger callback. Should contains one key and any modificator keys +-- @tparam function callback The callback function +function Hotkey.init(self, keys, callback, callback_argument) + self.druid = self:get_druid() + + self._hotkeys = {} + self._modificators = {} + self._callback = callback + + if keys then + self:add_hotkey(keys, callback_argument) + end +end + + +--- Component style params. +-- You can override this component styles params in druid styles table +-- or create your own style +-- @table style +-- @tfield string[] MODIFICATORS The list of action_id as hotkey modificators +function Hotkey.on_style_change(self, style) + self.style = {} + self.style.MODIFICATORS = style.MODIFICATORS or {} + + for index = 1, #style.MODIFICATORS do + self.style.MODIFICATORS[index] = hash(self.style.MODIFICATORS[index]) + end +end + + +--- Add hotkey for component callback +-- @tparam Hotkey self @{Hotkey} +-- @tparam string[]|hash[]|string|hash Keys that have to be pressed before key pressed to activate +function Hotkey.add_hotkey(self, keys, callback_argument) + keys = keys or {} + if type(keys) == "string" then + keys = { keys } + end + + local modificators = {} + local key = nil + + for index = 1, #keys do + local key_hash = hash(keys[index]) + if helper.contains(self.style.MODIFICATORS, key_hash) then + table.insert(modificators, key_hash) + else + if not key then + key = key_hash + else + error("The hotkey keys should contains only one key (except modificator keys)") + end + end + end + + table.insert(self._hotkeys, { + modificators = modificators, + key = key, + is_processing = false, + callback_argument = callback_argument, + }) + + -- Current hotkey status + for index = 1, #self.style.MODIFICATORS do + local modificator = hash(self.style.MODIFICATORS[index]) + self._modificators[modificator] = self._modificators[modificator] or false + end + + return self +end + + +function Hotkey.on_input(self, action_id, action) + if not action_id then + return + end + + if self._modificators[action_id] ~= nil then + if action.pressed then + self._modificators[action_id] = true + end + if action.released then + self._modificators[action_id] = false + end + end + + for index = 1, #self._hotkeys do + local hotkey = self._hotkeys[index] + if action_id == hotkey.key then + local is_modificator_ok = true + + -- Check only required modificators pressed + for i = 1, #self.style.MODIFICATORS do + local mod = self.style.MODIFICATORS[i] + if helper.contains(hotkey.modificators, mod) and self._modificators[mod] == false then + is_modificator_ok = false + end + if not helper.contains(hotkey.modificators, mod) and self._modificators[mod] == true then + is_modificator_ok = false + end + end + + if action.pressed and is_modificator_ok then + hotkey.is_processing = true + end + if action.released and is_modificator_ok and hotkey.is_processing then + hotkey.is_processing = false + if hotkey.callback_argument then + self._callback(self:get_context(), hotkey.callback_argument) + else + self._callback(self:get_context()) + end + end + end + end +end + + +return Hotkey diff --git a/druid/extended/input.lua b/druid/extended/input.lua index d463871..36da224 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -281,8 +281,8 @@ function Input.select(self) gui.reset_keyboard() self.marked_value = "" if not self.is_selected then - self:set_input_priority(const.PRIORITY_INPUT_MAX) - self.button:set_input_priority(const.PRIORITY_INPUT_MAX) + self:set_input_priority(const.PRIORITY_INPUT_MAX, true) + self.button:set_input_priority(const.PRIORITY_INPUT_MAX, true) self.previous_value = self.value self.is_selected = true diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index f30b48a..f78b70b 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -14,6 +14,7 @@ --- +local const = require("druid.const") local Event = require("druid.event") local settings = require("druid.system.settings") local component = require("druid.component") diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua new file mode 100644 index 0000000..b242eb6 --- /dev/null +++ b/druid/extended/layout.lua @@ -0,0 +1,134 @@ +-- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license + +--- Layout management on node +-- @module Layout +-- @within BaseComponent +-- @alias druid.layout + +--- + + +local const = require("druid.const") +local helper = require("druid.helper") +local component = require("druid.component") +local Event = require("druid.event") + +---@class layout : druid.base_component +local Layout = component.create("layout") + + +function Layout:init(node, mode, on_size_changed_callback) + self.node = self:get_node(node) + + self._min_size = nil + self._max_size = nil + self._inited = false + + self.gui_size = vmath.vector3(gui.get_width(), gui.get_height(), 0) + self.mode = mode or const.LAYOUT_MODE.FIT + + self.on_size_changed = Event(on_size_changed_callback) +end + + +function Layout:on_late_init() + self._inited = true + self.origin_size = self.origin_size or gui.get_size(self.node) + self.fit_size = self.fit_size or vmath.vector3(self.origin_size) + self.pivot = helper.get_pivot_offset(gui.get_pivot(self.node)) + self.origin_position = gui.get_position(self.node) + self.position = vmath.vector3(self.origin_position) + gui.set_size_mode(self.node, gui.SIZE_MODE_MANUAL) + gui.set_adjust_mode(self.node, gui.ADJUST_FIT) + self:on_window_resized() +end + + +function Layout:on_window_resized() + if not self._inited then + return + end + + local window_x, window_y = window.get_size() + local stretch_x = window_x / self.gui_size.x + local stretch_y = window_y / self.gui_size.y + + local x_koef = self.fit_size.x / self.origin_size.x * stretch_x / math.min(stretch_x, stretch_y) + local y_koef = self.fit_size.y / self.origin_size.y * stretch_y / math.min(stretch_x, stretch_y) + + local new_size = vmath.vector3(self.origin_size) + + if self.mode == const.LAYOUT_MODE.STRETCH_X or self.mode == const.LAYOUT_MODE.STRETCH then + new_size.x = new_size.x * x_koef + end + if self.mode == const.LAYOUT_MODE.STRETCH_Y or self.mode == const.LAYOUT_MODE.STRETCH then + new_size.y = new_size.y * y_koef + end + + -- Fit to the stretched container (node size or other defined) + if self.mode == const.LAYOUT_MODE.ZOOM_MIN then + new_size = new_size * math.min(x_koef, y_koef) + end + if self.mode == const.LAYOUT_MODE.ZOOM_MAX then + new_size = new_size * math.max(x_koef, y_koef) + end + + if self._min_size then + new_size.x = math.max(new_size.x, self._min_size.x) + new_size.y = math.max(new_size.y, self._min_size.y) + end + if self._max_size then + new_size.x = math.min(new_size.x, self._max_size.x) + new_size.y = math.min(new_size.y, self._max_size.y) + end + gui.set_size(self.node, new_size) + + self.position.x = self.origin_position.x + self.origin_position.x * (x_koef - 1) + self.position.y = self.origin_position.y + self.origin_position.y * (y_koef - 1) + gui.set_position(self.node, self.position) + + self.on_size_changed:trigger(self:get_context(), new_size) +end + + +function Layout:set_min_size(min_size) + self._min_size = min_size + return self +end + + +function Layout:set_max_size(max_size) + self._max_size = max_size + return self +end + + +function Layout:set_origin_position(new_origin_position) + self.origin_position = new_origin_position or self.origin_position + return self +end + + +function Layout:set_origin_size(new_origin_size) + self.origin_size = new_origin_size or self.origin_size + self:on_window_resized() + return self +end + + +function Layout:fit_into_size(target_size) + self.fit_size = target_size + self:on_window_resized() + return self +end + + +function Layout:fit_into_window() + return self:fit_into_size(vmath.vector3( + gui.get_width(), + gui.get_height(), + 0)) +end + + +return Layout diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index 1ebe6e7..509e57b 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -103,11 +103,14 @@ function Progress.init(self, node, key, init_value) self.prop = hash("scale."..key) self.key = key + self._init_value = init_value or 1 self.node = self:get_node(node) self.scale = gui.get_scale(self.node) self.size = gui.get_size(self.node) self.max_size = self.size[self.key] self.slice = gui.get_slice9(self.node) + self.last_value = self._init_value + if key == const.SIDE.X then self.slice_size = self.slice.x + self.slice.z else @@ -115,8 +118,12 @@ function Progress.init(self, node, key, init_value) end self.on_change = Event() +end - self:set_to(init_value or 1) + +-- @tparam Progress self @{Progress} +function Progress.on_late_init(self) + self:set_to(self._init_value) end @@ -204,4 +211,15 @@ function Progress.to(self, to, callback) end +--- Set progress bar max node size +-- @tparam Progress self @{Progress} +-- @tparam vector3 max_size The new node maximum (full) size +-- @treturn Progress @{Progress} +function Progress:set_max_size(max_size) + self.max_size = max_size[self.key] + self:set_to(self.last_value) + return self +end + + return Progress diff --git a/druid/helper.lua b/druid/helper.lua index d5ebee2..c7849d1 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -8,6 +8,7 @@ local const = require("druid.const") local M = {} + --- Text node or icon node can be nil local function get_text_width(text_node) if text_node then @@ -97,6 +98,15 @@ function M.centrate_nodes(margin, ...) end +function M.get_screen_aspect_koef() + local window_x, window_y = window.get_size() + local stretch_x = window_x / gui.get_width() + local stretch_y = window_y / gui.get_height() + return stretch_x / math.min(stretch_x, stretch_y), + stretch_y / math.min(stretch_x, stretch_y) +end + + function M.step(current, target, step) if current < target then return math.min(current + step, target) diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index dea1439..e286e78 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -30,6 +30,7 @@ -- @see Drag -- @see DataList -- @see Hover +-- @see Layout local helper = require("druid.helper") local class = require("druid.system.middleclass") @@ -57,6 +58,7 @@ local radio_group = require("druid.extended.radio_group") local slider = require("druid.extended.slider") local timer = require("druid.extended.timer") local data_list = require("druid.extended.data_list") +local layout = require("druid.extended.layout") local DruidInstance = class("druid.druid_instance") @@ -738,4 +740,14 @@ function DruidInstance.new_progress(self, node, key, init_value) end +--- Create layout component +-- @tparam DruidInstance self +-- @tparam string|node node Layout node +-- @tparam string mode The layout mode +-- @treturn Layout layout component +function DruidInstance.new_layout(self, node, mode) + return helper.extended_component("layout") +end + + return DruidInstance diff --git a/example/example.collection b/example/example.collection index 3e861b0..fd4aca8 100644 --- a/example/example.collection +++ b/example/example.collection @@ -1688,3 +1688,66 @@ embedded_instances { z: 1.0 } } +embedded_instances { + id: "general_layout" + data: "components {\n" + " id: \"screen_factory\"\n" + " component: \"/monarch/screen_factory.script\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + " properties {\n" + " id: \"screen_id\"\n" + " value: \"general_layout\"\n" + " type: PROPERTY_TYPE_HASH\n" + " }\n" + " properties {\n" + " id: \"popup\"\n" + " value: \"true\"\n" + " type: PROPERTY_TYPE_BOOLEAN\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"collectionfactory\"\n" + " type: \"collectionfactory\"\n" + " data: \"prototype: \\\"/example/examples/general/layout/layout.collection\\\"\\n" + "load_dynamically: false\\n" + "\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/example/example.gui_script b/example/example.gui_script index 2af7cad..138172f 100644 --- a/example/example.gui_script +++ b/example/example.gui_script @@ -130,6 +130,7 @@ local function init_lobby(self) self.lobby_grid:add(get_button(self, "Data List", "general_data_list", "/general/data_list/data_list.gui_script")) self.lobby_grid:add(get_button(self, "Checkboxes", "general_checkboxes", "/general/checkboxes/checkboxes.gui_script")) self.lobby_grid:add(get_button(self, "Input text", "general_input", "/general/input/input.gui_script")) + self.lobby_grid:add(get_button(self, "Layout", "general_layout", "/general/layout/layout.gui_script")) self.lobby_grid:add(get_button(self, "Swipe", "general_swipe", "/general/swipe/swipe.gui_script")) self.lobby_grid:add(get_button(self, "Drag", "general_drag", "/general/drag/drag.gui_script")) diff --git a/example/examples/general/layout/layout.collection b/example/examples/general/layout/layout.collection new file mode 100644 index 0000000..3269796 --- /dev/null +++ b/example/examples/general/layout/layout.collection @@ -0,0 +1,37 @@ +name: "layout" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"layout\"\n" + " component: \"/example/examples/general/layout/layout.gui\"\n" + " position {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " }\n" + " rotation {\n" + " x: 0.0\n" + " y: 0.0\n" + " z: 0.0\n" + " w: 1.0\n" + " }\n" + "}\n" + "" + position { + x: 0.0 + y: 0.0 + z: 0.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale3 { + x: 1.0 + y: 1.0 + z: 1.0 + } +} diff --git a/example/examples/general/layout/layout.gui b/example/examples/general/layout/layout.gui new file mode 100644 index 0000000..f946c05 --- /dev/null +++ b/example/examples/general/layout/layout.gui @@ -0,0 +1,679 @@ +script: "/example/examples/general/layout/layout.gui_script" +fonts { + name: "game" + font: "/example/assets/fonts/game.font" +} +textures { + name: "kenney" + texture: "/example/assets/images/kenney.atlas" +} +background_color { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 +} +nodes { + position { + x: 300.0 + y: 415.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: 600.0 + y: 830.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "root" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + 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 +} +nodes { + position { + x: -100.0 + y: 250.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: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_stretch" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.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 +} +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: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Regular Stretch Mode" + font: "game" + id: "text_regular" + 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: "node_stretch" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: -100.0 + y: 100.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: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.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 +} +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: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch" + font: "game" + id: "text_layout_stretch" + 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: "node_layout_stretch" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: -100.0 + y: -50.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: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch_x" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.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 +} +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: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch by X" + font: "game" + id: "text_layout_stretch1" + 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: "node_layout_stretch_x" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: -100.0 + y: -200.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: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch_y" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.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 +} +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: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch by Y" + font: "game" + id: "text_layout_stretch2" + 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: "node_layout_stretch_y" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +nodes { + position { + x: -250.0 + y: -350.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: 300.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/slider_move" + id: "node_layout_stretch_y_anchor_w" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_STRETCH + parent: "root" + layer: "" + inherit_alpha: true + slice9 { + x: 17.0 + y: 17.0 + z: 17.0 + w: 17.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 +} +nodes { + position { + x: 150.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: 0.65 + y: 0.65 + z: 1.0 + w: 1.0 + } + size { + x: 450.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Layout Stretch by Y Anchor W" + font: "game" + id: "text_layout_stretch3" + 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: true + parent: "node_layout_stretch_y_anchor_w" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 1.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 + custom_type: 0 +} +layers { + name: "image" +} +layers { + name: "text" +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT +max_nodes: 512 diff --git a/example/examples/general/layout/layout.gui_script b/example/examples/general/layout/layout.gui_script new file mode 100644 index 0000000..2550a26 --- /dev/null +++ b/example/examples/general/layout/layout.gui_script @@ -0,0 +1,33 @@ +local druid = require("druid.druid") +local const_druid = require("druid.const") +local layout = require("druid.extended.layout") + +function init(self) + druid.register("layout", layout) + self.druid = druid.new(self) + + self.druid:new_layout("node_layout_stretch", const_druid.LAYOUT_MODE.STRETCH) + self.druid:new_layout("node_layout_stretch_x", const_druid.LAYOUT_MODE.STRETCH_X) + self.druid:new_layout("node_layout_stretch_y", const_druid.LAYOUT_MODE.STRETCH_Y) + self.druid:new_layout("node_layout_stretch_y_anchor_w", const_druid.LAYOUT_MODE.STRETCH_Y) +end + + +function final(self) + self.druid:final() +end + + +function update(self, dt) + self.druid:update(dt) +end + + +function on_message(self, message_id, message, sender) + self.druid:on_message(message_id, message, sender) +end + + +function on_input(self, action_id, action) + return self.druid:on_input(action_id, action) +end