tested new layout system
This commit is contained in:
parent
24ac28e0d9
commit
2619873ca7
220
lib/ugui.c3l/LAYOUT
Normal file
220
lib/ugui.c3l/LAYOUT
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
Div Children Alignment
|
||||||
|
+------------------------------------------------+
|
||||||
|
|TOP-LEFT TOP TOP-RIGHT|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
|LEFT CENTER RIGHT|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
|BOTTOM-LEFT BOTTOM BOTTOM-RIGHT|
|
||||||
|
+------------------------------------------------+
|
||||||
|
|
||||||
|
ALIGNMENT CHART:
|
||||||
|
+------------------------------+----------------------+------------------------------+-----------------------+------------------------------+----------------------+
|
||||||
|
| TOP-LEFT, ROW: | TOP-LEFT, COLUMN: | BOTTOM, ROW: | BOTTOM, COLUMN: | TOP-RIGHT, ROW: | TOP-RIGHT, COLUMN: |
|
||||||
|
| | | | | | |
|
||||||
|
| +------------------------- - | +----------- - | | +----+ | | - -----------+ |
|
||||||
|
| |+-------++-----++-----+ | |+-------+ | | | E1 | | | +-------+| |
|
||||||
|
| || E1 || E2 || | | || E1 | | | | | | - -----------------------+ | | E1 || |
|
||||||
|
| || |+-----+| E3 | | || | | | +----+ | +-------++-----++-----+| | | || |
|
||||||
|
| |+-------+ | | | |+-------+ | +-------+ +---+ | +------+ | | E1 || E2 || || | +-------+| |
|
||||||
|
| | +-----+ | |+----+ | | E1 |+------+|E3 | | | E2 | | | |+-----+| E3 || | +----+| |
|
||||||
|
| ' | || E2 | | | || E2 || | | | | | +-------+ | || | | E2 || |
|
||||||
|
| ' | |+----+ | +-------++------++---+ | +------+ | +-----+| | +----+| |
|
||||||
|
| | |+---------+ | - ------------------------ - | +--+ | ' | +---------+| |
|
||||||
|
| | || E3 | | | |E3| | ' | | E3 || |
|
||||||
|
| | |+---------+ | | +--+ | | +---------+| |
|
||||||
|
| | ' | | - ----------- - | | ' |
|
||||||
|
| | ' | | | | ' |
|
||||||
|
| | | | | | |
|
||||||
|
+------------------------------+----------------------+------------------------------+-----------------------+------------------------------+----------------------+
|
||||||
|
| LEFT, ROW: | LEFT, COLUMN: | BOTTOM-RIGHT, ROW: | BOTTOM-RIGHT, COLUMN: | TOP, ROW: | TOP, COLUMN: |
|
||||||
|
| | | | | | |
|
||||||
|
| | ' | | ' | | - -------------- - |
|
||||||
|
| ' | |+-------+ | | +-------+| | | +----------+ |
|
||||||
|
| | +----+ | || E1 | | ' | | E1 || | - ----------------------- - | | E1 | |
|
||||||
|
| |+------+ | | | || | | +-----+| | | || | +------++----++-----+ | | | |
|
||||||
|
| || |+-----+| | | |+-------+ | +-------+ | || | +-------+| | | E1 || E2 || E3 | | +----------+ |
|
||||||
|
| || E1 || E2 || E3 | | |+----+ | | E1 |+-----+| E3 || | +----+| | | |+----+| | | +--------+ |
|
||||||
|
| || |+-----+| | | || E2 | | | || E2 || || | | E2 || | +------+ | | | | E2 | |
|
||||||
|
| |+------+ | | | |+----+ | +-------++-----++-----+| | +----+| | +-----+ | +--------+ |
|
||||||
|
| | +----+ | |+---------+ | - -----------------------+ | +---------+| | | +------+ |
|
||||||
|
| ' | || E3 | | | | E3 || | | | E3 | |
|
||||||
|
| ' | |+---------+ | | +---------+| | | | | |
|
||||||
|
| | ' | | - -----------+ | | +------+ |
|
||||||
|
| | ' | | | | |
|
||||||
|
+------------------------------+----------------------+------------------------------+-----------------------+------------------------------+----------------------+
|
||||||
|
| BOTTOM-LEFT, ROW: | BOTTOM-LEFT, COLUMN: | RIGHT, ROW: | RIGHT, COLUMN: | CENTER, ROW: | CENTER, COLUMN: |
|
||||||
|
| | | | | | |
|
||||||
|
| | ' | | ' | | | |
|
||||||
|
| | |+-------+ | | +-------+| | | | +-----------+ |
|
||||||
|
| | || E1 | | ' | | E1 || | | | | E1 | |
|
||||||
|
| ' | || | | +----+| | | || | | +----+ | | | | |
|
||||||
|
| | +-----+ | |+-------+ | +------+ | || | +-------+| | +------+ | | | | +-----------+ |
|
||||||
|
| |+-------+ | | | |+----+ | | |+-----+| || | +----+| | | |+----+| | | +---------+ |
|
||||||
|
| || E1 |+-----+| E3 | | || E2 | | | E1 || E2 || E3 || | | E2 || | ---|--E1--||-E2-||-E3-|--- | ----|---E2----|---- |
|
||||||
|
| || || E2 || | | |+----+ | | |+-----+| || | +----+| | | |+----+| | | +---------+ |
|
||||||
|
| |+-------++-----++-----+ | |+---------+ | +------+ | || | +---------+| | +------+ | | | | +-------+ |
|
||||||
|
| +------------------------- - | || E3 | | +----+| | | E3 || | | +----+ | | E3 | |
|
||||||
|
| | |+---------+ | ' | +---------+| | | | | | | |
|
||||||
|
| | +----------- - | ' | ' | | | +-------+ |
|
||||||
|
| | | | ' | | | |
|
||||||
|
| | | | | | |
|
||||||
|
+------------------------------+----------------------+------------------------------+-----------------------+------------------------------+----------------------+
|
||||||
|
|
||||||
|
div (
|
||||||
|
align: TOP-LEFT | LEFT | BOTTOM-LEFT | BOTTOM | BOTTOM-RIGHT | RIGHT | TOP-RIGHT | RIGHT | CENTER
|
||||||
|
size_x/y: EXACT(x) | GROW() | FIT(min, max)
|
||||||
|
scroll_x/y: true | false
|
||||||
|
resize_x/y: true | false
|
||||||
|
layout: ROW | COLUMN
|
||||||
|
)
|
||||||
|
|
||||||
|
align: alignment of the children elements
|
||||||
|
size: how the div should be sized
|
||||||
|
scroll: enables scrollbars
|
||||||
|
layout: the layout direction of the children
|
||||||
|
|
||||||
|
COLUMN ROW
|
||||||
|
+--------------------+ +----------------------------------------------------+
|
||||||
|
| +----------------+ | |+----------------+ +------------------+|
|
||||||
|
| | | | || |+------------+| ||
|
||||||
|
| | | | || || || E3 ||
|
||||||
|
| | E1 | | || E1 || E2 || ||
|
||||||
|
| | | | || || || ||
|
||||||
|
| | | | || |+------------++------------------+|
|
||||||
|
| +----------------+ | |+----------------+ |
|
||||||
|
| +------------+ | +----------------------------------------------------+
|
||||||
|
| | | |
|
||||||
|
| | E2 | |
|
||||||
|
| | | |
|
||||||
|
| +------------+ |
|
||||||
|
|+------------------+|
|
||||||
|
|| ||
|
||||||
|
|| E3 ||
|
||||||
|
|| ||
|
||||||
|
|| ||
|
||||||
|
|+------------------+|
|
||||||
|
+--------------------+
|
||||||
|
|
||||||
|
Element {
|
||||||
|
id: uint
|
||||||
|
sizing: { min_w, min_h max_w, max_h }
|
||||||
|
bounds: { x, y, w, h }
|
||||||
|
}
|
||||||
|
|
||||||
|
id: unique identifier of the element
|
||||||
|
sizing: the size that the element wants
|
||||||
|
bounds: the absoulte bounds that the element got assigned
|
||||||
|
|
||||||
|
Rendering
|
||||||
|
=========
|
||||||
|
|
||||||
|
Rendering happens when the element is called (immediately for leaf widgets like buttons and at the end
|
||||||
|
for root widgets like divs). The drawing is done on the bounds assigned to the widget, these bounds
|
||||||
|
have a one-frame delay on the current layout.
|
||||||
|
|
||||||
|
The layout is calculated by each div at the end of their block and at frame end all the sizes and positions
|
||||||
|
are assigned at frame end by iterating the element tree.
|
||||||
|
|
||||||
|
ElemDiv {
|
||||||
|
align: TOP-LEFT | LEFT | BOTTOM-LEFT | BOTTOM | BOTTOM-RIGHT | RIGHT | TOP-RIGHT | RIGHT | CENTER
|
||||||
|
size_x/y: { min, max }
|
||||||
|
scroll_x/y: true | false
|
||||||
|
layout: ROW | COLUMN
|
||||||
|
children_size_x/y: { min, max }
|
||||||
|
}
|
||||||
|
|
||||||
|
size:
|
||||||
|
- min != max -> FIT sizing, fit to the content but respect the min and max size
|
||||||
|
- min == max == 0 -> GROW sizing, grow to the max amount of space possible
|
||||||
|
- min == max != 0 -> EXACT sizing
|
||||||
|
children_size: the size of the combined children sizes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
root(size_x: screen width, size_y: screen height, layout: ROW) {
|
||||||
|
|
||||||
|
div1(layout: COLUMN, size_x: FIT, size_y GROW, resize_x: true) {
|
||||||
|
E1()
|
||||||
|
E2()
|
||||||
|
E3()
|
||||||
|
E4()
|
||||||
|
} <-(end div 1)
|
||||||
|
|
||||||
|
div2(size_x: GROW, size_y: GROW) {
|
||||||
|
...
|
||||||
|
} <-(end div 2)
|
||||||
|
|
||||||
|
div3(layout: COLUMN, size_x: FIT, size_y: GROW) {
|
||||||
|
E5()
|
||||||
|
E6()
|
||||||
|
E7()
|
||||||
|
} <-(end div 3)
|
||||||
|
|
||||||
|
} <-(end root)
|
||||||
|
(frame end)
|
||||||
|
|
||||||
|
|
||||||
|
+-Root-Div------------------------------------------------+
|
||||||
|
|+-Div-1----------++-Div-2--------------------++-Div-3---+|
|
||||||
|
||+--------------+|| ||+-------+||
|
||||||
|
||| E1 ||| ||| E5 |||
|
||||||
|
||| ||| ||| |||
|
||||||
|
||+--------------+|| ||+-------+|| [Root Div]
|
||||||
|
||+--------------+|| ||+-------+|| |
|
||||||
|
||| E2 ||| ||| E6 ||| +----------+----+-------+
|
||||||
|
||| ||| ||| ||| v v v
|
||||||
|
||+--------------+|| ||+-------+|| [Div 1] [Div 2] [Div 3]
|
||||||
|
||+------+ || ||+-------+|| | |
|
||||||
|
||| | || ||| E7 ||| +----+----+----+ |
|
||||||
|
||| E3 | || ||| ||| v v v v |
|
||||||
|
||| | || ||+-------+|| [E1] [E2] [E3] [E4] +----+----+
|
||||||
|
||+------+ || || || v v v
|
||||||
|
||+------+ || || || [E5] [E6] [E7]
|
||||||
|
||| | || || ||
|
||||||
|
||| E4 | || || ||
|
||||||
|
||| | || || ||
|
||||||
|
||+------+ || || ||
|
||||||
|
|| || || ||
|
||||||
|
|+----------------++--------------------------++---------+|
|
||||||
|
+---------------------------------------------------------+
|
||||||
|
|
||||||
|
the call order is as follows
|
||||||
|
|
||||||
|
E1() -> updates the children size of div1
|
||||||
|
E2() -> " "
|
||||||
|
E3() -> " "
|
||||||
|
E4() -> " "
|
||||||
|
end div1() -> updates the children size of root
|
||||||
|
end div2() -> updates the children size of root
|
||||||
|
E5() -> updates the children size of div3
|
||||||
|
E6() -> " "
|
||||||
|
E7() -> " "
|
||||||
|
end root() -> does nothing
|
||||||
|
|
||||||
|
at frame end:
|
||||||
|
* Root: the root has a size constraint of fit so the bounds get assigned the whole window
|
||||||
|
* Div 1: the width has a size of fit, so it gets set to the children bounds, the height is set
|
||||||
|
to the root height since it has a height of GROW
|
||||||
|
- E1 to E4 get laid out
|
||||||
|
* Div 2: it has a width of GROW which is **along** the layout axis, so it gets added to grow list
|
||||||
|
the height gets set to the root height
|
||||||
|
* Div 3: the width is FIT, so it gets set to the content width, the height gets se to the root
|
||||||
|
height.
|
||||||
|
- E5 to E7 get laid out
|
||||||
|
* Div 2: is given a width (if there were other contending grow divs along the layout axis they
|
||||||
|
would also get sized).
|
||||||
|
- Now that div 2 has a size all it's children can be given a size
|
||||||
|
|
||||||
|
Styling
|
||||||
|
=======
|
||||||
|
|
@ -24,9 +24,17 @@ macro @zero()
|
|||||||
{
|
{
|
||||||
$if @assignable_to(0, ElemType):
|
$if @assignable_to(0, ElemType):
|
||||||
return 0;
|
return 0;
|
||||||
$else
|
$endif
|
||||||
|
|
||||||
|
$if @assignable_to(null, ElemType):
|
||||||
|
return null;
|
||||||
|
$endif
|
||||||
|
|
||||||
|
$if @assignable_to({}, ElemType):
|
||||||
return {};
|
return {};
|
||||||
$endif
|
$endif
|
||||||
|
|
||||||
|
//$assert true == false : ElemType.nameof +++ " is not assignable to zero or equivalent";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void? VTree.init(&tree, usz size, Allocator allocator)
|
fn void? VTree.init(&tree, usz size, Allocator allocator)
|
||||||
@ -217,6 +225,8 @@ fn usz? VTree.subtree_size(&tree, isz ref)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bool? VTree.is_root(&tree, isz node) => node == tree.parentof(node)!;
|
||||||
|
|
||||||
// iterate through the first level children, use a cursor like strtok_r
|
// iterate through the first level children, use a cursor like strtok_r
|
||||||
fn isz? VTree.children_it(&tree, isz parent, isz *cursor)
|
fn isz? VTree.children_it(&tree, isz parent, isz *cursor)
|
||||||
{
|
{
|
||||||
|
436
test/test_tree_layout.c3
Normal file
436
test/test_tree_layout.c3
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
import vtree;
|
||||||
|
import std::io;
|
||||||
|
import std::math;
|
||||||
|
import std::thread;
|
||||||
|
|
||||||
|
const short WIDTH = 128;
|
||||||
|
const short HEIGHT = 64;
|
||||||
|
|
||||||
|
struct Size {
|
||||||
|
short min, max;
|
||||||
|
}
|
||||||
|
macro Size @grow() => {.min = 0, .max = 0};
|
||||||
|
macro Size @exact(short s) => {.min = s, .max = s};
|
||||||
|
macro Size @fit(short min = 0, short max = short.max) => {.min = min, .max = max};
|
||||||
|
macro bool Size.@is_grow(s) => (s.min == 0 && s.max == 0);
|
||||||
|
macro bool Size.@is_exact(s) => (s.min == s.max && s.min != 0);
|
||||||
|
macro bool Size.@is_fit(s) => (s.min != s.max);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct Rect {
|
||||||
|
short x, y, w, h;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LayoutDirection {
|
||||||
|
ROW,
|
||||||
|
COLUMN
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ElemType {
|
||||||
|
DIV,
|
||||||
|
ELEM
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Anchor {
|
||||||
|
TOP_LEFT,
|
||||||
|
LEFT,
|
||||||
|
BOTTOM_LEFT,
|
||||||
|
BOTTOM,
|
||||||
|
BOTTOM_RIGHT,
|
||||||
|
RIGHT,
|
||||||
|
TOP_RIGHT,
|
||||||
|
TOP,
|
||||||
|
CENTER
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Elem {
|
||||||
|
ElemType type;
|
||||||
|
Size w, h;
|
||||||
|
Rect bounds;
|
||||||
|
Size ch_w, ch_h; // children width / height
|
||||||
|
uint grow_children; // how many children want to grow, decreased once a child has grown
|
||||||
|
short orig_x, orig_y;
|
||||||
|
short occupied; // occupied space in the layout direction
|
||||||
|
LayoutDirection layout_dir;
|
||||||
|
Anchor anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
alias ElemTree = vtree::VTree{Elem*};
|
||||||
|
|
||||||
|
|
||||||
|
char[HEIGHT][WIDTH] screen;
|
||||||
|
fn void paint(Rect bounds, char c)
|
||||||
|
{
|
||||||
|
for (short x = bounds.x; x < WIDTH && x < bounds.x + bounds.w; x++) {
|
||||||
|
for (short y = bounds.y; y < HEIGHT && y < bounds.y + bounds.h; y++) {
|
||||||
|
screen[x][y] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isz Elem.div_start(&e, ElemTree* tree, isz parent, Size w, Size h, LayoutDirection dir = ROW, Anchor anchor = TOP_LEFT, char c = ' ')
|
||||||
|
{
|
||||||
|
e.type = DIV;
|
||||||
|
e.w = w;
|
||||||
|
e.h = h;
|
||||||
|
e.layout_dir = dir;
|
||||||
|
e.anchor = anchor;
|
||||||
|
|
||||||
|
e.grow_children = 0;
|
||||||
|
e.occupied = 0;
|
||||||
|
e.ch_w = e.ch_h = {};
|
||||||
|
e.orig_x = e.orig_y = 0;
|
||||||
|
|
||||||
|
// update grow children if necessary
|
||||||
|
Elem* p = tree.get(parent) ?? &&{};
|
||||||
|
if ((p.layout_dir == ROW && e.w.@is_grow()) || ((p.layout_dir == COLUMN && e.h.@is_grow()))) {
|
||||||
|
p.grow_children++;
|
||||||
|
}
|
||||||
|
|
||||||
|
paint(e.bounds, c);
|
||||||
|
return tree.add(e, parent)!!;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void update_parent_size(Elem* parent, Elem* child)
|
||||||
|
{
|
||||||
|
// update the parent children size
|
||||||
|
switch (parent.layout_dir) {
|
||||||
|
case ROW: // on rows grow the ch width by the child width and only grow ch height if it exceeds
|
||||||
|
parent.ch_w.min += child.w.min;
|
||||||
|
parent.ch_w.max += child.w.max;
|
||||||
|
parent.ch_h.min = math::max(child.h.min, parent.ch_h.min);
|
||||||
|
parent.ch_h.max = math::max(child.h.max, parent.ch_h.max);
|
||||||
|
case COLUMN: // do the opposite on column
|
||||||
|
parent.ch_w.min = math::max(child.w.min, parent.ch_w.min);
|
||||||
|
parent.ch_w.max = math::max(child.w.max, parent.ch_w.max);
|
||||||
|
parent.ch_h.min += child.h.min;
|
||||||
|
parent.ch_h.max += child.h.max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isz Elem.div_end(&e, ElemTree* tree, isz node)
|
||||||
|
{
|
||||||
|
isz parent = tree.parentof(node) ?? -1;
|
||||||
|
if (parent > 0) {
|
||||||
|
Elem* p = tree.get(parent)!!;
|
||||||
|
update_parent_size(p, e);
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void resolve_dimensions(Elem* e, Elem* p)
|
||||||
|
{
|
||||||
|
// ASSIGN WIDTH
|
||||||
|
switch {
|
||||||
|
case e.w.@is_exact():
|
||||||
|
e.bounds.w = e.w.min;
|
||||||
|
case e.w.@is_grow():
|
||||||
|
break;
|
||||||
|
// done in another pass
|
||||||
|
case e.w.@is_fit(): // fit the element's children
|
||||||
|
short min = math::max(e.ch_w.min, e.w.min);
|
||||||
|
short max = math::min(e.ch_w.max, e.w.max);
|
||||||
|
if (max >= min) { // OK!
|
||||||
|
e.bounds.w = max;
|
||||||
|
} else {
|
||||||
|
unreachable("cannot fit children");
|
||||||
|
}
|
||||||
|
default: unreachable("width is not exact, grow or fit");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASSIGN HEIGHT
|
||||||
|
switch {
|
||||||
|
case e.h.@is_exact():
|
||||||
|
e.bounds.h = e.h.min;
|
||||||
|
case e.h.@is_grow():
|
||||||
|
break;
|
||||||
|
// done in another pass
|
||||||
|
case e.h.@is_fit(): // fit the element's children
|
||||||
|
short min = math::max(e.ch_h.min, e.h.min);
|
||||||
|
short max = math::min(e.ch_h.max, e.h.max);
|
||||||
|
if (max >= min) { // OK!
|
||||||
|
e.bounds.h = max;
|
||||||
|
} else {
|
||||||
|
unreachable("cannot fit children");
|
||||||
|
}
|
||||||
|
default: unreachable("width is not exact, grow or fit");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (p.layout_dir) {
|
||||||
|
case ROW:
|
||||||
|
if (!e.w.@is_grow()) p.occupied += e.bounds.w;
|
||||||
|
case COLUMN:
|
||||||
|
if (!e.h.@is_grow()) p.occupied += e.bounds.h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void resolve_grow_elements(Elem* e, Elem* p)
|
||||||
|
{
|
||||||
|
// WIDTH
|
||||||
|
if (e.w.@is_grow()) {
|
||||||
|
if (p.layout_dir == ROW) { // grow along the axis, divide the parent size
|
||||||
|
e.bounds.w = (short)((int)(p.bounds.w - p.occupied) / (int)p.grow_children);
|
||||||
|
p.grow_children--;
|
||||||
|
p.occupied += e.bounds.w;
|
||||||
|
} else if (p.layout_dir == COLUMN) { // grow across the layout axis, inherit width of the parent
|
||||||
|
e.bounds.w = p.bounds.w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEIGHT
|
||||||
|
if (e.h.@is_grow()) {
|
||||||
|
if (p.layout_dir == COLUMN) { // grow along the axis, divide the parent size
|
||||||
|
e.bounds.h = (short)((int)(p.bounds.h - p.occupied) / (int)p.grow_children);
|
||||||
|
p.grow_children--;
|
||||||
|
p.occupied += e.bounds.h;
|
||||||
|
} else if (p.layout_dir == ROW) { // grow across the layout axis, inherit width of the parent
|
||||||
|
e.bounds.h = p.bounds.h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void resolve_placement(Elem* e, Elem* p)
|
||||||
|
{
|
||||||
|
switch (p.anchor) {
|
||||||
|
case TOP_LEFT:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y;
|
||||||
|
case LEFT:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y + p.bounds.h/2;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.y -= p.occupied/2;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.y -= e.bounds.h/2;
|
||||||
|
}
|
||||||
|
case BOTTOM_LEFT:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x;
|
||||||
|
e.bounds.y = p.bounds.y + p.bounds.h + p.orig_y;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.y -= p.occupied;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.y -= e.bounds.h;
|
||||||
|
}
|
||||||
|
case BOTTOM:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x + p.bounds.w/2;
|
||||||
|
e.bounds.y = p.bounds.y + p.bounds.h + p.orig_y;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.y -= p.occupied;
|
||||||
|
e.bounds.x -= e.bounds.w/2;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.y -= e.bounds.h;
|
||||||
|
e.bounds.x -= p.occupied/2;
|
||||||
|
}
|
||||||
|
case BOTTOM_RIGHT:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x + p.bounds.w;
|
||||||
|
e.bounds.y = p.bounds.y + p.bounds.h + p.orig_y;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.y -= p.occupied;
|
||||||
|
e.bounds.x -= e.bounds.w;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.y -= e.bounds.h;
|
||||||
|
e.bounds.x -= p.occupied;
|
||||||
|
}
|
||||||
|
case RIGHT:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x + p.bounds.w;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y + p.bounds.h/2;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.y -= p.occupied/2;
|
||||||
|
e.bounds.x -= e.bounds.w;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.y -= e.bounds.h/2;
|
||||||
|
e.bounds.x -= p.occupied;
|
||||||
|
}
|
||||||
|
case TOP_RIGHT:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x + p.bounds.w;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.x -= e.bounds.w;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.x -= p.occupied;
|
||||||
|
}
|
||||||
|
case TOP:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x + p.bounds.w/2;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.x -= e.bounds.w/2;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.x -= p.occupied/2;
|
||||||
|
}
|
||||||
|
case CENTER:
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x + p.bounds.w/2;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y + p.bounds.h/2;
|
||||||
|
if (p.layout_dir == COLUMN) {
|
||||||
|
e.bounds.x -= e.bounds.w/2;
|
||||||
|
e.bounds.y -= p.occupied/2;
|
||||||
|
} else if (p.layout_dir == ROW) {
|
||||||
|
e.bounds.x -= p.occupied/2;
|
||||||
|
e.bounds.y -= e.bounds.h/2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
e.bounds.x = p.bounds.x + p.orig_x;
|
||||||
|
e.bounds.y = p.bounds.y + p.orig_y;
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (p.layout_dir) {
|
||||||
|
case ROW:
|
||||||
|
p.orig_x += e.bounds.w;
|
||||||
|
case COLUMN:
|
||||||
|
p.orig_y += e.bounds.h;
|
||||||
|
default: unreachable("unknown layout direction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void frame_end(ElemTree* tree, isz root)
|
||||||
|
{
|
||||||
|
// assign the element bounds
|
||||||
|
isz cursor = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// RESOLVE DIMENSIONS
|
||||||
|
isz current = tree.level_order_it(root, &cursor)!!;
|
||||||
|
for (; current >= 0; current = tree.level_order_it(root, &cursor)!!) {
|
||||||
|
Elem* e = tree.get(current)!!;
|
||||||
|
isz pi = tree.parentof(current)!!;
|
||||||
|
Elem* p = (pi != current) ? tree.get(pi) ?? &&{} : &&{};
|
||||||
|
resolve_dimensions(e, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESOLVE GROW ELEMENTS
|
||||||
|
cursor = -1;
|
||||||
|
current = tree.level_order_it(root, &cursor)!!;
|
||||||
|
for (; current >= 0; current = tree.level_order_it(root, &cursor)!!) {
|
||||||
|
Elem* e = tree.get(current)!!;
|
||||||
|
isz pi = tree.parentof(current)!!; if (ch == current) continue;
|
||||||
|
Elem* p = (pi != current) ? tree.get(pi) ?? &&{} : &&{};
|
||||||
|
|
||||||
|
resolve_grow_elements(e, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// RESOLVE PLACEMENT
|
||||||
|
cursor = -1;
|
||||||
|
current = tree.level_order_it(root, &cursor)!!;
|
||||||
|
for (; current >= 0; current = tree.level_order_it(root, &cursor)!!) {
|
||||||
|
Elem* e = tree.get(current)!!;
|
||||||
|
isz pi = tree.parentof(current)!!;
|
||||||
|
Elem* p = (pi != current) ? tree.get(pi) ?? &&{} : &&{};
|
||||||
|
|
||||||
|
resolve_placement(e, p);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
cursor = -1;
|
||||||
|
isz current = tree.level_order_it(root, &cursor)!!;
|
||||||
|
for (; current >= 0; current = tree.level_order_it(root, &cursor)!!) {
|
||||||
|
Elem* p = tree.get(current)!!;
|
||||||
|
|
||||||
|
// RESOLVE KNOWN DIMENSIONS
|
||||||
|
isz ch_cur = 0;
|
||||||
|
isz ch = tree.children_it(current, &ch_cur)!!;
|
||||||
|
for (; ch >= 0; ch = tree.children_it(current, &ch_cur)!!) {
|
||||||
|
Elem* c = tree.get(ch)!!;
|
||||||
|
if (tree.is_root(ch)!!) {
|
||||||
|
resolve_dimensions(p, &&{});
|
||||||
|
} else {
|
||||||
|
resolve_dimensions(c, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESOLVE GROW CHILDREN
|
||||||
|
ch_cur = 0;
|
||||||
|
ch = tree.children_it(current, &ch_cur)!!;
|
||||||
|
for (; ch >= 0; ch = tree.children_it(current, &ch_cur)!!) {
|
||||||
|
Elem* c = tree.get(ch)!!;
|
||||||
|
if (tree.is_root(ch)!!) {
|
||||||
|
resolve_grow_elements(p, &&{});
|
||||||
|
} else {
|
||||||
|
resolve_grow_elements(c, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESOLVE CHILDREN PLACEMENT
|
||||||
|
ch_cur = 0;
|
||||||
|
ch = tree.children_it(current, &ch_cur)!!;
|
||||||
|
for (; ch >= 0; ch = tree.children_it(current, &ch_cur)!!) {
|
||||||
|
Elem* c = tree.get(ch)!!;
|
||||||
|
if (tree.is_root(ch)!!) {
|
||||||
|
resolve_placement(p, &&{});
|
||||||
|
} else {
|
||||||
|
resolve_placement(c, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void main()
|
||||||
|
{
|
||||||
|
ElemTree tree;
|
||||||
|
tree.init(64, mem)!!;
|
||||||
|
isz parent;
|
||||||
|
defer (void)tree.free();
|
||||||
|
|
||||||
|
Elem root; // root div
|
||||||
|
Elem div1, div2, div3, div4;
|
||||||
|
usz frame;
|
||||||
|
while (true) {
|
||||||
|
parent = root.div_start(&tree, parent, @exact(WIDTH), @exact(HEIGHT), ROW, anchor: RIGHT);
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
parent = div1.div_start(&tree, parent, @grow(), @grow(), dir: ROW, c: '1');
|
||||||
|
{
|
||||||
|
parent = div4.div_start(&tree, parent, @exact(30), @exact(30), dir: ROW, c: '4');
|
||||||
|
parent = div4.div_end(&tree, parent);
|
||||||
|
}
|
||||||
|
parent = div1.div_end(&tree, parent);
|
||||||
|
|
||||||
|
if (frame < 200) {
|
||||||
|
parent = div2.div_start(&tree, parent, @exact(20), @fit(), dir: COLUMN, c: '2');
|
||||||
|
{
|
||||||
|
parent = div3.div_start(&tree, parent, @exact(10), @exact(10), dir: ROW, c: '3');
|
||||||
|
parent = div3.div_end(&tree, parent);
|
||||||
|
}
|
||||||
|
parent = div2.div_end(&tree, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
parent = div3.div_start(&tree, parent, @fit(), @fit(), COLUMN, anchor: CENTER);
|
||||||
|
{
|
||||||
|
parent = div1.div_start(&tree, parent, @exact(20), @exact(20), dir: ROW, c: '1');
|
||||||
|
parent = div1.div_end(&tree, parent);
|
||||||
|
|
||||||
|
parent = div2.div_start(&tree, parent, @exact(10), @exact(10), dir: ROW, c: '2');
|
||||||
|
parent = div2.div_end(&tree, parent);
|
||||||
|
}
|
||||||
|
parent = div3.div_end(&tree, parent);
|
||||||
|
|
||||||
|
parent = root.div_end(&tree, parent);
|
||||||
|
|
||||||
|
frame_end(&tree, parent);
|
||||||
|
tree.nuke();
|
||||||
|
|
||||||
|
|
||||||
|
// draw the screen
|
||||||
|
//io::print("\e[1;1H\e[2J");
|
||||||
|
for (short x = 0; x < WIDTH+2; x++) io::printf("%c", x == 0 || x == WIDTH+1 ? '+' : '-');
|
||||||
|
io::printn();
|
||||||
|
for (short y = 0; y < HEIGHT; y++) {
|
||||||
|
io::print("|");
|
||||||
|
for (short x = 0; x < WIDTH; x++) {
|
||||||
|
char c = screen[x][y] == 0 ? 'x' : screen[x][y];
|
||||||
|
io::printf("%c", c);
|
||||||
|
}
|
||||||
|
io::print("|");
|
||||||
|
io::printn();
|
||||||
|
}
|
||||||
|
for (short x = 0; x < WIDTH+2; x++) io::printf("%c", x == 0 || x == WIDTH+1 ? '+' : '-');
|
||||||
|
io::printn("\n\n");
|
||||||
|
|
||||||
|
thread::sleep_ms(10);
|
||||||
|
frame++;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user