From 1b92c0b344495d0909d1243d5a6bd20098c0ab4d Mon Sep 17 00:00:00 2001 From: PeaAshMeter Date: Thu, 21 Aug 2025 20:54:25 +0300 Subject: [PATCH] implement reactive rectangle --- lib/ui/core.lua | 34 ++++++++++++++++++++-------------- lib/ui/layout.lua | 36 ++++++++++++++++++++++++++++++++++++ main.lua | 32 ++------------------------------ 3 files changed, 58 insertions(+), 44 deletions(-) create mode 100644 lib/ui/layout.lua diff --git a/lib/ui/core.lua b/lib/ui/core.lua index 0cecde3..3fe6fe5 100644 --- a/lib/ui/core.lua +++ b/lib/ui/core.lua @@ -73,7 +73,7 @@ end ---@param dt number function Element:update(dt) -- По умолчанию спускаем update вниз - for _, ch in ipairs(self.children) do + for _, ch in ipairs(self.children or {}) do ch:update(dt) end end @@ -201,7 +201,7 @@ end -- =============== Align (single child) =============== ---@class Align: SingleChildElement ----@field alignment string "center"|"top_left"|"top_right"|"bottom_left"|"bottom_right" +---@field alignment string "center_left" | "center" | "center_right" | "top_left" | "top_center" | "top_right" | "bottom_left" | "bottom_center" | "bottom_right" ---@field expand boolean если true — занимает все доступное от родителя local Align = setmetatable({}, { __index = SingleChildElement }) Align.__index = Align @@ -239,6 +239,7 @@ function Align:arrange(origin) local cw, ch = self.child.size.x, self.child.size.y local x, y = self.origin.x, self.origin.y + --- @todo сделать красиво if self.alignment == "center" then x = x + (pw - cw) / 2 y = y + (ph - ch) / 2 @@ -249,10 +250,15 @@ function Align:arrange(origin) y = y + (ph - ch) / 2 elseif self.alignment == "top_left" then -- x,y остаются + elseif self.alignment == "top_center" then + x = x + (pw - cw) / 2 elseif self.alignment == "top_right" then x = x + (pw - cw) elseif self.alignment == "bottom_left" then y = y + (ph - ch) + elseif self.alignment == "bottom_center" then + y = y + (ph - ch) + x = x + (pw - cw) / 2 elseif self.alignment == "bottom_right" then x = x + (pw - cw) y = y + (ph - ch) @@ -459,18 +465,6 @@ function Expanded:arrange(origin) end end --- =============== Public constructors (callable) =============== - -local function mk_ctor(class) - -- Сохраняем существующую метатаблицу (в ней уже есть __index на родителя!) - local mt = getmetatable(class) or {} - mt.__call = function(_, props) - return class:new(props or {}) - end - setmetatable(class, mt) - return class -end - -- =============== Padding (single child) =============== ---@class Padding: SingleChildElement @@ -527,6 +521,18 @@ function Padding:arrange(origin) self.child:arrange(Vec3 { self.origin.x + L, self.origin.y + T, self.origin.z }) end +-- =============== Public constructors (callable) =============== + +local function mk_ctor(class) + -- Сохраняем существующую метатаблицу (в ней уже есть __index на родителя!) + local mt = getmetatable(class) or {} + mt.__call = function(_, props) + return class:new(props or {}) + end + setmetatable(class, mt) + return class +end + ui.Element = Element ui.Root = mk_ctor(Root) ui.Align = mk_ctor(Align) diff --git a/lib/ui/layout.lua b/lib/ui/layout.lua new file mode 100644 index 0000000..554df3e --- /dev/null +++ b/lib/ui/layout.lua @@ -0,0 +1,36 @@ +local Vec3 = require "lib.utils.vec3" +local ui = require "lib.ui.core" + +--- @type Rectangle +local ReactiveRectangle = ui.Rectangle { + size = Vec3 { 100, 100 }, + color = { 1, 0, 0 }, + state = { tick = 0 } +} +function ReactiveRectangle:update(dt) + getmetatable(self):update(dt) + + local mx, my = love.mouse.getPosition() + if mx > self.origin.x and mx < self.origin.x + self.size.x + and my > self.origin.y and my < self.origin.y + self.size.y + then + self.color = { 0, 1, 0 } + else + self.color = { 1, 0, 0 } + end + + self.state.tick = self.state.tick + 1 +end + +local Layout = ui.Root { + child = ui.Align { + alignment = "bottom_center", + child = ui.Row { + children = { + ReactiveRectangle + } + } + } +} + +return Layout diff --git a/main.lua b/main.lua index 650b868..384a675 100644 --- a/main.lua +++ b/main.lua @@ -1,6 +1,6 @@ -- CameraLoader = require 'lib/camera' -local ui = require "lib.ui.core" +local Widgets = require "lib.ui.layout" local character = require "lib/character/character" require "lib/tree" @@ -24,34 +24,6 @@ function love.load() end end - Widgets = ui.Root { - child = - ui.Column { - children = { - ui.Row { - gap = 8, - children = { - ui.Rectangle { size = Vec3 { 100, 100 }, color = { 0, 0, 1 } }, - ui.Rectangle { size = Vec3 { 200, 100 }, color = { 1, 0, 0 } }, - ui.Padding { padding = { left = 10, right = 10 }, child = ui.Rectangle { size = Vec3 { 100, 150 }, color = { 0, 1, 0 } } }, - ui.Rectangle { size = Vec3 { 100, 100 }, color = { 1, 1, 0 } }, - } - }, - ui.Expanded {}, - ui.Row { - gap = 8, - children = { - ui.Rectangle { size = Vec3 { 100, 100 }, color = { 0, 0, 1 } }, - ui.Rectangle { size = Vec3 { 200, 100 }, color = { 1, 0, 0 } }, - ui.Expanded { flex = 1, child = ui.Rectangle { size = Vec3 { 100, 150 }, color = { 0, 1, 0 } } }, - ui.Rectangle { size = Vec3 { 100, 100 }, color = { 1, 1, 0 } }, - } - }, - } - } - - } - -- PlayerFaction.characters = { Hero1, Hero2 } love.window.setMode(1080, 720, { resizable = true, msaa = 4, vsync = true }) end @@ -60,11 +32,11 @@ local lt = "0" function love.update(dt) local t1 = love.timer.getTime() Tree.controls:poll() + Widgets:update(dt) -- логика UI-слоя должна отработать раньше всех, потому что нужно перехватить жесты и не пустить их дальше Tree.panning:update(dt) Tree.level:update(dt) Tree.controls:cache() - Widgets:update(dt) local t2 = love.timer.getTime() lt = string.format("%.3f", (t2 - t1) * 1000) end