fix(libtui): improve flex layout handling
This commit is contained in:
parent
e7666715b0
commit
c99426a3a9
@ -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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user