fix(libtui): improve flex layout handling

This commit is contained in:
Guillaume ARM 2026-06-08 00:53:52 +02:00
parent e7666715b0
commit c99426a3a9

View File

@ -1,4 +1,4 @@
local _VERSION = '0.1.0';
local _VERSION = '0.1.1';
local NODE_TEXT = 'text';
local NODE_BUTTON = 'button';
@ -260,26 +260,45 @@ local function buttonLabel(props)
return '[ ' .. tostring(props.text or props.label or '') .. ' ]';
end
local function flexOf(child)
local f = (child.props or {}).flex;
if f == true then
return 1;
end
if type(f) == 'number' and f > 0 then
return f;
end
return nil;
end
local naturalSize;
local function childrenNaturalSize(children, direction, gap)
local width = 0;
local height = 0;
local mainCount = 0;
for index, child in ipairs(children) do
for _, child in ipairs(children) do
local hasFlex = flexOf(child) ~= nil;
local childWidth, childHeight = naturalSize(child);
if direction == 'row' then
width = width + childWidth;
height = math.max(height, childHeight);
if index > 1 then
width = width + gap;
if not hasFlex then
if mainCount > 0 then
width = width + gap;
end
width = width + childWidth;
mainCount = mainCount + 1;
end
else
width = math.max(width, childWidth);
height = height + childHeight;
if index > 1 then
height = height + gap;
if not hasFlex then
if mainCount > 0 then
height = height + gap;
end
height = height + childHeight;
mainCount = mainCount + 1;
end
end
end
@ -336,41 +355,38 @@ local function layoutChildren(children, rect, direction, gap)
local flexSize = 0;
local axisSize = direction == 'row' and rect.w or rect.h;
local layouts = {};
local remaining;
local lastFlexIndex = nil;
local flexes = {};
for _, child in ipairs(children) do
local props = child.props or {};
if props.flex then
flexSize = flexSize + props.flex;
for index, child in ipairs(children) do
local flex = flexOf(child);
flexes[index] = flex;
if flex then
flexSize = flexSize + flex;
lastFlexIndex = index;
else
fixedSize = fixedSize + childAxisSize(child, direction);
end
end
remaining = axisSize - fixedSize - math.max(#children - 1, 0) * gap;
local remaining = axisSize - fixedSize - math.max(#children - 1, 0) * gap;
if remaining < 0 then
remaining = 0;
end
local cursor = direction == 'row' and rect.x or rect.y;
local lastFlexIndex = nil;
local usedFlexSize = 0;
for index, child in ipairs(children) do
if (child.props or {}).flex then
lastFlexIndex = index;
end
end
for index, child in ipairs(children) do
local props = child.props or {};
local flex = flexes[index];
local size;
if props.flex then
if flex then
if index == lastFlexIndex then
size = remaining - usedFlexSize;
else
size = math.floor(remaining * props.flex / flexSize);
size = math.floor(remaining * flex / flexSize);
usedFlexSize = usedFlexSize + size;
end
else
@ -548,12 +564,27 @@ local function createTui(eventloop)
end
function api.rerender()
if root == nil then
return;
end
safeRedraw();
end
local function restoreTerminal()
if not previousState then
return;
end
term.setTextColor(previousState.color);
term.setBackgroundColor(previousState.bgColor);
term.clear();
term.setCursorPos(previousState.cursorX, previousState.cursorY);
term.setCursorBlink(previousState.cursorBlink);
previousState = nil;
end
function api.render(nextRoot)
root = nextRoot;
finalEvent = nil;
root = nextRoot;
previousState = {
color = term.getTextColor(),
@ -572,13 +603,7 @@ local function createTui(eventloop)
end
eventloop.onStart(safeRedraw);
eventloop.onStop(function()
term.setTextColor(previousState.color);
term.setBackgroundColor(previousState.bgColor);
term.clear();
term.setCursorPos(previousState.cursorX, previousState.cursorY);
term.setCursorBlink(previousState.cursorBlink);
end);
eventloop.onStop(restoreTerminal);
eventloop.register('mouse_click', function(button, x, y)
for index = #clickables, 1, -1 do
@ -606,6 +631,7 @@ local function createTui(eventloop)
local ok, reason = pcall(eventloop.startLoop);
if not ok then
pcall(restoreTerminal);
finalEvent = createErrorEvent(reason);
end
@ -616,18 +642,17 @@ local function createTui(eventloop)
end
api.Text = makeText;
api.text = makeText;
api.Button = makeButton;
api.button = makeButton;
api.Box = makeBox;
api.box = makeBox;
api.List = makeList;
api.list = makeList;
api.Fragment = makeFragment;
api.version = _VERSION;
api.eventloop = eventloop;
api.text = makeText;
api.button = makeButton;
api.box = makeBox;
api.list = makeList;
return api;
end