Skip to content

Commit 17db117

Browse files
committed
Add flex and grid sizer elements
1 parent 5ec5d9d commit 17db117

12 files changed

+859
-18
lines changed

builtin/ui/elem_defs.lua

+57
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,60 @@ function ui.Root:_encode_fields()
3232

3333
return ui._encode("ZS", ui.Elem._encode_fields(self), ui._encode_flags(fl))
3434
end
35+
36+
ui.Flex = ui._new_type(ui.Elem, "flex", 0x02, false)
37+
38+
function ui.Flex:new(props)
39+
ui.Elem.new(self, props)
40+
41+
self._dir = props.dir
42+
self._wrap = props.wrap
43+
end
44+
45+
local dir_map = {left = 0, up = 1, right = 2, down = 3};
46+
local wrap_map = {none = 0, forward = 1, backward = 2}
47+
48+
function ui.Flex:_encode_fields()
49+
local fl = ui._make_flags()
50+
51+
if ui._shift_flag(fl, self._dir) then
52+
ui._encode_flag(fl, "B", dir_map[self._dir])
53+
end
54+
if ui._shift_flag(fl, self._wrap) then
55+
ui._encode_flag(fl, "B", wrap_map[self._wrap])
56+
end
57+
58+
return ui._encode("ZS", ui.Elem._encode_fields(self), ui._encode_flags(fl))
59+
end
60+
61+
ui.Grid = ui._new_type(ui.Elem, "grid", 0x03, false)
62+
63+
function ui.Grid:new(props)
64+
ui.Elem.new(self, props)
65+
66+
self._hsizes = table.merge(props.hsizes or {})
67+
self._vsizes = table.merge(props.vsizes or {})
68+
69+
self._hweights = table.merge(props.hweights or {})
70+
self._vweights = table.merge(props.vweights or {})
71+
end
72+
73+
function ui.Grid:_encode_fields()
74+
local fl = ui._make_flags()
75+
76+
if ui._shift_flag(fl, #self._hsizes > 0) then
77+
ui._encode_flag(fl, "Z", ui._encode_array("f", self._hsizes))
78+
end
79+
if ui._shift_flag(fl, #self._vsizes > 0) then
80+
ui._encode_flag(fl, "Z", ui._encode_array("f", self._vsizes))
81+
end
82+
83+
if ui._shift_flag(fl, #self._hweights > 0) then
84+
ui._encode_flag(fl, "Z", ui._encode_array("f", self._hweights))
85+
end
86+
if ui._shift_flag(fl, #self._vweights > 0) then
87+
ui._encode_flag(fl, "Z", ui._encode_array("f", self._vweights))
88+
end
89+
90+
return ui._encode("ZS", ui.Elem._encode_fields(self), ui._encode_flags(fl))
91+
end

builtin/ui/style.lua

+24
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ function ui._cascade_props(add, props)
7979
new.margin = add.margin or props.margin
8080
new.padding = add.padding or props.padding
8181

82+
new.gap = add.gap or props.gap
83+
new.weight = add.weight or props.weight
84+
new.span = add.span or props.span
85+
86+
new.hspacing = add.hspacing or props.hspacing
87+
new.vspacing = add.vspacing or props.vspacing
88+
8289
cascade_layer(new, add, props, "bg")
8390
cascade_layer(new, add, props, "fg")
8491

@@ -164,6 +171,23 @@ function ui._encode_props(props)
164171
ui._encode_flag(fl, "ffff", unpack(props.padding))
165172
end
166173

174+
if ui._shift_flag(fl, props.gap) then
175+
ui._encode_flag(fl, "ff", unpack(props.gap))
176+
end
177+
if ui._shift_flag(fl, props.weight) then
178+
ui._encode_flag(fl, "f", props.weight)
179+
end
180+
if ui._shift_flag(fl, props.span) then
181+
ui._encode_flag(fl, "ii", unpack(props.span))
182+
end
183+
184+
if ui._shift_flag(fl, props.hspacing) then
185+
ui._encode_flag(fl, "B", spacing_map[props.hspacing])
186+
end
187+
if ui._shift_flag(fl, props.vspacing) then
188+
ui._encode_flag(fl, "B", spacing_map[props.vspacing])
189+
end
190+
167191
local bg_fl = encode_layer(props, "bg")
168192
if ui._shift_flag(fl, bg_fl.flags ~= 0) then
169193
ui._encode_flag(fl, "s", ui._encode_flags(bg_fl))

src/gui/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ set(gui_SRCS
3333
${CMAKE_CURRENT_SOURCE_DIR}/manager.cpp
3434
${CMAKE_CURRENT_SOURCE_DIR}/modalMenu.cpp
3535
${CMAKE_CURRENT_SOURCE_DIR}/profilergraph.cpp
36+
${CMAKE_CURRENT_SOURCE_DIR}/sizer_elems.cpp
3637
${CMAKE_CURRENT_SOURCE_DIR}/texture.cpp
3738
${CMAKE_CURRENT_SOURCE_DIR}/window.cpp
3839
${extra_gui_SRCS}

src/gui/box.cpp

+50-5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ namespace ui
3737
return (Align)align;
3838
}
3939

40+
Spacing toSpacing(u8 spacing)
41+
{
42+
if (spacing >= (u8)Spacing::MAX_SPACING) {
43+
return Spacing::AFTER;
44+
}
45+
return (Spacing)spacing;
46+
}
47+
4048
void Layer::reset()
4149
{
4250
image = Texture();
@@ -92,6 +100,13 @@ namespace ui
92100
margin = rf32(0.0f, 0.0f, 0.0f, 0.0f);
93101
padding = rf32(0.0f, 0.0f, 0.0f, 0.0f);
94102

103+
gap = v2f32(0.0f, 0.0f);
104+
weight = 0.0f;
105+
span = v2s32(1, 1);
106+
107+
hspacing = Spacing::AFTER;
108+
vspacing = Spacing::AFTER;
109+
95110
bg.reset();
96111
fg.reset();
97112

@@ -130,6 +145,19 @@ namespace ui
130145
padding.LowerRightCorner = readV2F32(is);
131146
}
132147

148+
if (testShift(set_mask))
149+
gap = clamp_vec(readV2F32(is));
150+
if (testShift(set_mask))
151+
weight = std::max(readF32(is), 0.0f);
152+
if (testShift(set_mask)) {
153+
span = clamp_vec(readV2S32(is), v2s32(1, 1));
154+
}
155+
156+
if (testShift(set_mask))
157+
hspacing = toSpacing(readU8(is));
158+
if (testShift(set_mask))
159+
vspacing = toSpacing(readU8(is));
160+
133161
if (testShift(set_mask))
134162
bg.read(is);
135163
if (testShift(set_mask))
@@ -188,7 +216,7 @@ namespace ui
188216
}
189217
}
190218

191-
void Box::layout(const rf32 &parent_rect, const rf32 &parent_clip)
219+
void Box::layout(const rf32 &parent_rect, const rf32 &parent_clip, bool sizer)
192220
{
193221
// Before we layout the box, we need to recompute the style so we have
194222
// fully updated style properties.
@@ -197,20 +225,37 @@ namespace ui
197225
// First, calculate the size of the element in absolute coordinates
198226
// based on the normalized size.
199227
d2f32 origin_size(
200-
(m_style.rel_size.Width * parent_rect.getWidth()) + m_style.size.Width,
201-
(m_style.rel_size.Height * parent_rect.getHeight()) + m_style.size.Height
228+
(m_style.rel_size.Width * parent_rect.getWidth()),
229+
(m_style.rel_size.Height * parent_rect.getHeight())
202230
);
203231

232+
if (!sizer) {
233+
// If this box is not in a sizer, then the "pos" and "size"
234+
// attributes are absolute pixel amounts to offset the rect by.
235+
origin_size.Width += m_style.size.Width;
236+
origin_size.Height += m_style.size.Height;
237+
} else {
238+
// Otherwise, the "size" attribute is the minimum size of the box
239+
// and the "pos" attribute is reserved for the sizer's use.
240+
origin_size.Width = std::max(origin_size.Width, m_style.size.Width);
241+
origin_size.Height = std::max(origin_size.Height, m_style.size.Height);
242+
}
243+
204244
// Then, create the rect of the element relative to the origin by
205245
// converting the normalized position absolute coordinates, while
206246
// accounting for the anchor based on the previously calculated size.
207247
v2f32 origin_pos(
208-
(m_style.rel_pos.X * parent_rect.getWidth()) + m_style.pos.X -
248+
(m_style.rel_pos.X * parent_rect.getWidth()) -
209249
(m_style.rel_anchor.X * origin_size.Width),
210-
(m_style.rel_pos.Y * parent_rect.getHeight()) + m_style.pos.Y -
250+
(m_style.rel_pos.Y * parent_rect.getHeight()) -
211251
(m_style.rel_anchor.Y * origin_size.Height)
212252
);
213253

254+
if (!sizer) {
255+
origin_pos.X += m_style.pos.X;
256+
origin_pos.Y += m_style.pos.Y;
257+
}
258+
214259
rf32 origin_rect(origin_pos, origin_size);
215260

216261
// The absolute rect of the element is made by shifting the origin to

src/gui/box.h

+24-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ namespace ui
4141

4242
Align toAlign(u8 align);
4343

44+
// Serialized enum; do not change order of entries.
45+
enum class Spacing
46+
{
47+
BEFORE,
48+
AFTER,
49+
OUTSIDE,
50+
AROUND,
51+
BETWEEN,
52+
EVENLY,
53+
REMOVE,
54+
55+
MAX_SPACING,
56+
};
57+
58+
Spacing toSpacing(u8 spacing);
59+
4460
struct Layer
4561
{
4662
Texture image;
@@ -75,6 +91,13 @@ namespace ui
7591
rf32 margin;
7692
rf32 padding;
7793

94+
v2f32 gap;
95+
float weight;
96+
d2s32 span;
97+
98+
Spacing hspacing;
99+
Spacing vspacing;
100+
78101
Layer bg;
79102
Layer fg;
80103

@@ -152,7 +175,7 @@ namespace ui
152175
void reset();
153176
void read(std::istream &is);
154177

155-
void layout(const rf32 &parent_rect, const rf32 &parent_clip);
178+
void layout(const rf32 &parent_rect, const rf32 &parent_clip, bool sizer);
156179
void draw(Canvas &parent);
157180

158181
private:

src/gui/elem.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2727

2828
// Include every element header for Elem::create()
2929
#include "gui/generic_elems.h"
30+
#include "gui/sizer_elems.h"
3031

3132
namespace ui
3233
{
@@ -42,6 +43,8 @@ namespace ui
4243
switch (type) {
4344
CREATE(ELEM, Elem);
4445
CREATE(ROOT, Root);
46+
CREATE(FLEX, Flex);
47+
CREATE(GRID, Grid);
4548
default:
4649
return nullptr;
4750
}
@@ -86,9 +89,9 @@ namespace ui
8689
m_main_box.read(is);
8790
}
8891

89-
void Elem::layout(const rf32 &parent_rect, const rf32 &parent_clip)
92+
void Elem::layout(const rf32 &parent_rect, const rf32 &parent_clip, bool sizer)
9093
{
91-
layoutBoxes(parent_rect, parent_clip);
94+
layoutBoxes(parent_rect, parent_clip, sizer);
9295
layoutChildren();
9396
}
9497

@@ -101,15 +104,15 @@ namespace ui
101104
}
102105
}
103106

104-
void Elem::layoutBoxes(const rf32 &parent_rect, const rf32 &parent_clip)
107+
void Elem::layoutBoxes(const rf32 &parent_rect, const rf32 &parent_clip, bool sizer)
105108
{
106-
m_main_box.layout(parent_rect, parent_clip);
109+
m_main_box.layout(parent_rect, parent_clip, sizer);
107110
}
108111

109112
void Elem::layoutChildren()
110113
{
111114
for (Elem *child : m_children) {
112-
child->layout(m_main_box.getChildRect(), m_main_box.getChildClip());
115+
child->layout(m_main_box.getChildRect(), m_main_box.getChildClip(), false);
113116
}
114117
}
115118

src/gui/elem.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ namespace ui
4040
{
4141
ELEM = 0x00,
4242
ROOT = 0x01,
43+
FLEX = 0x02,
44+
GRID = 0x03,
4345
};
4446

4547
private:
@@ -83,12 +85,12 @@ namespace ui
8385
virtual void reset();
8486
virtual void read(std::istream &is);
8587

86-
void layout(const rf32 &parent_rect, const rf32 &parent_clip);
88+
void layout(const rf32 &parent_rect, const rf32 &parent_clip, bool sizer);
8789
void drawAll(Canvas &canvas);
8890

8991
protected:
9092
virtual void layoutBoxes(
91-
const rf32 &parent_rect, const rf32 &parent_clip);
93+
const rf32 &parent_rect, const rf32 &parent_clip, bool sizer);
9294
virtual void layoutChildren();
9395

9496
virtual void draw(Canvas &canvas);

src/gui/generic_elems.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ namespace ui
4444
m_backdrop_box.read(is);
4545
}
4646

47-
void Root::layoutBoxes(const rf32 &parent_rect, const rf32 &parent_clip)
47+
void Root::layoutBoxes(const rf32 &parent_rect, const rf32 &parent_clip, bool sizer)
4848
{
49-
m_backdrop_box.layout(parent_rect, parent_clip);
49+
m_backdrop_box.layout(parent_rect, parent_clip, false);
5050

5151
Elem::layoutBoxes(
52-
m_backdrop_box.getChildRect(), m_backdrop_box.getChildClip());
52+
m_backdrop_box.getChildRect(), m_backdrop_box.getChildClip(), sizer);
5353
}
5454

5555
void Root::draw(Canvas &canvas)

src/gui/generic_elems.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace ui
4646

4747
protected:
4848
virtual void layoutBoxes(
49-
const rf32 &parent_rect, const rf32 &parent_clip);
49+
const rf32 &parent_rect, const rf32 &parent_clip, bool sizer);
5050

5151
virtual void draw(Canvas &canvas);
5252
};

0 commit comments

Comments
 (0)