implement reactive rectangle

This commit is contained in:
PeaAshMeter 2025-08-21 20:54:25 +03:00
parent 9613e660c3
commit 1b92c0b344
3 changed files with 58 additions and 44 deletions

View File

@ -73,7 +73,7 @@ end
---@param dt number ---@param dt number
function Element:update(dt) function Element:update(dt)
-- По умолчанию спускаем update вниз -- По умолчанию спускаем update вниз
for _, ch in ipairs(self.children) do for _, ch in ipairs(self.children or {}) do
ch:update(dt) ch:update(dt)
end end
end end
@ -201,7 +201,7 @@ end
-- =============== Align (single child) =============== -- =============== Align (single child) ===============
---@class Align: SingleChildElement ---@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 — занимает все доступное от родителя ---@field expand boolean если true — занимает все доступное от родителя
local Align = setmetatable({}, { __index = SingleChildElement }) local Align = setmetatable({}, { __index = SingleChildElement })
Align.__index = Align Align.__index = Align
@ -239,6 +239,7 @@ function Align:arrange(origin)
local cw, ch = self.child.size.x, self.child.size.y local cw, ch = self.child.size.x, self.child.size.y
local x, y = self.origin.x, self.origin.y local x, y = self.origin.x, self.origin.y
--- @todo сделать красиво
if self.alignment == "center" then if self.alignment == "center" then
x = x + (pw - cw) / 2 x = x + (pw - cw) / 2
y = y + (ph - ch) / 2 y = y + (ph - ch) / 2
@ -249,10 +250,15 @@ function Align:arrange(origin)
y = y + (ph - ch) / 2 y = y + (ph - ch) / 2
elseif self.alignment == "top_left" then elseif self.alignment == "top_left" then
-- x,y остаются -- x,y остаются
elseif self.alignment == "top_center" then
x = x + (pw - cw) / 2
elseif self.alignment == "top_right" then elseif self.alignment == "top_right" then
x = x + (pw - cw) x = x + (pw - cw)
elseif self.alignment == "bottom_left" then elseif self.alignment == "bottom_left" then
y = y + (ph - ch) 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 elseif self.alignment == "bottom_right" then
x = x + (pw - cw) x = x + (pw - cw)
y = y + (ph - ch) y = y + (ph - ch)
@ -459,18 +465,6 @@ function Expanded:arrange(origin)
end end
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) =============== -- =============== Padding (single child) ===============
---@class Padding: SingleChildElement ---@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 }) self.child:arrange(Vec3 { self.origin.x + L, self.origin.y + T, self.origin.z })
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
ui.Element = Element ui.Element = Element
ui.Root = mk_ctor(Root) ui.Root = mk_ctor(Root)
ui.Align = mk_ctor(Align) ui.Align = mk_ctor(Align)

36
lib/ui/layout.lua Normal file
View File

@ -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

View File

@ -1,6 +1,6 @@
-- CameraLoader = require 'lib/camera' -- CameraLoader = require 'lib/camera'
local ui = require "lib.ui.core" local Widgets = require "lib.ui.layout"
local character = require "lib/character/character" local character = require "lib/character/character"
require "lib/tree" require "lib/tree"
@ -24,34 +24,6 @@ function love.load()
end end
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 } -- PlayerFaction.characters = { Hero1, Hero2 }
love.window.setMode(1080, 720, { resizable = true, msaa = 4, vsync = true }) love.window.setMode(1080, 720, { resizable = true, msaa = 4, vsync = true })
end end
@ -60,11 +32,11 @@ local lt = "0"
function love.update(dt) function love.update(dt)
local t1 = love.timer.getTime() local t1 = love.timer.getTime()
Tree.controls:poll() Tree.controls:poll()
Widgets:update(dt) -- логика UI-слоя должна отработать раньше всех, потому что нужно перехватить жесты и не пустить их дальше
Tree.panning:update(dt) Tree.panning:update(dt)
Tree.level:update(dt) Tree.level:update(dt)
Tree.controls:cache() Tree.controls:cache()
Widgets:update(dt)
local t2 = love.timer.getTime() local t2 = love.timer.getTime()
lt = string.format("%.3f", (t2 - t1) * 1000) lt = string.format("%.3f", (t2 - t1) * 1000)
end end