Skip to content

Commit 731f184

Browse files
author
okay
committed
[ui] add reflowing layout helpers
1 parent 461e513 commit 731f184

File tree

5 files changed

+255
-21
lines changed

5 files changed

+255
-21
lines changed

src/rmkit/ui/layouts.cpy

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ namespace ui:
1515
Layout(int x, y, w, h, Scene s): x(x), y(y), w(w), h(h), scene(s):
1616
pass
1717

18-
void add(Widget *w):
18+
shared_ptr<Widget> add(Widget *w):
1919
sp := shared_ptr<Widget>(w)
2020
children.push_back(sp)
2121
scene->add(sp)
22+
return sp
2223

2324
void hide():
2425
for auto w: children:
@@ -74,7 +75,7 @@ namespace ui:
7475
// the vertical layout is used for packing widgets
7576
// vertically (top to bottom). it implements only 3 functions: pack_start,
7677
// pack_end and pack_center
77-
//
78+
//
7879
class VerticalLayout: public AutoLayout:
7980
public:
8081
using AutoLayout::pack_start
@@ -220,3 +221,4 @@ namespace ui:
220221
padding_x = leftover / 2
221222
w.x = self.x + padding_x
222223
w.y += self.y
224+

src/rmkit/ui/main_loop.cpy

+24
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "widget.h"
2929
#include "task_queue.h"
3030
#include "timer.h"
31+
#include "../ui/reflow.h"
3132

3233
#include <unistd.h>
3334

@@ -219,6 +220,25 @@ namespace ui:
219220
for auto s : scene_stack:
220221
s->redraw()
221222

223+
static void reflow(Scene s):
224+
layouts := ReflowLayout::scene_to_layouts.find(s)
225+
if layouts == ReflowLayout::scene_to_layouts.end():
226+
return
227+
228+
for auto w : s->widgets:
229+
w->restore_coords()
230+
231+
unordered_map<ReflowLayout*, bool> has_parent;
232+
for auto l : layouts->second:
233+
l->restore_coords()
234+
for auto w : l->children:
235+
w->restore_coords()
236+
l->mark_children(has_parent)
237+
238+
for auto l : layouts->second:
239+
if has_parent.find(l) == has_parent.end():
240+
l->reflow()
241+
222242

223243
/// blocking read for input
224244
static void read_input(int timeout_ms=0):
@@ -240,6 +260,10 @@ namespace ui:
240260
if s->clear_under:
241261
break
242262

263+
reflow(scene)
264+
for auto &sc : scene_stack:
265+
reflow(sc)
266+
243267
// function: set_scene
244268
// set the main scene for the app to display when drawing
245269
static void set_scene(Scene s):

src/rmkit/ui/reflow.cpy

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#include "layouts.h"
2+
3+
#define RANGE(X) X.begin(), X.end()
4+
namespace ui:
5+
class ReflowLayout: public ui::Layout:
6+
public:
7+
static unordered_map<Scene, vector<ReflowLayout*>> scene_to_layouts
8+
vector<ReflowLayout*> layouts
9+
10+
class PackedChild:
11+
public:
12+
shared_ptr<ReflowLayout> sl
13+
shared_ptr<Widget> sp
14+
int padding
15+
;
16+
17+
vector<PackedChild> start
18+
vector<PackedChild> end
19+
vector<PackedChild> center
20+
21+
int _x, _y, _w, _h
22+
23+
ReflowLayout(int x, y, w, h, Scene s): Layout(x,y,w,h,s), _x(x), _y(y), _w(w), _h(h):
24+
if scene_to_layouts.find(scene) == scene_to_layouts.end():
25+
scene_to_layouts[s] = {}
26+
scene_to_layouts[s].push_back(self)
27+
28+
29+
~ReflowLayout():
30+
if scene_to_layouts.find(scene) != scene_to_layouts.end():
31+
it := find(RANGE(scene_to_layouts[scene]), self)
32+
if it == scene_to_layouts[scene].end():
33+
return
34+
35+
scene_to_layouts[scene].erase(it)
36+
37+
void restore_coords():
38+
x = _x
39+
y = _y
40+
w = _w
41+
h = _h
42+
43+
virtual void reflow():
44+
pass
45+
46+
shared_ptr<ReflowLayout> add(ReflowLayout *l):
47+
sp := shared_ptr<ReflowLayout>(l)
48+
return sp
49+
50+
void mark_children(unordered_map<ReflowLayout*, bool> &has_parent):
51+
for auto l : self.layouts:
52+
has_parent[l] = true
53+
l->mark_children(has_parent)
54+
55+
void pack_start(Widget* w, int padding=0):
56+
sp := Layout::add(w)
57+
self.start.push_back({NULL, sp, padding})
58+
void pack_end(Widget* w, int padding=0):
59+
sp := Layout::add(w)
60+
self.end.push_back({NULL, sp, padding})
61+
void pack_center(Widget* w, int padding=0):
62+
sp := Layout::add(w)
63+
self.center.push_back({NULL, sp, padding})
64+
65+
void pack_start(ReflowLayout* w, int padding=0):
66+
layouts.push_back(w)
67+
sl := ReflowLayout::add(w)
68+
self.start.push_back({sl, NULL, padding})
69+
void pack_end(ReflowLayout* w, int padding=0):
70+
layouts.push_back(w)
71+
sl := ReflowLayout::add(w)
72+
self.end.push_back({sl, NULL, padding})
73+
void pack_center(ReflowLayout* w, int padding=0):
74+
layouts.push_back(w)
75+
sl := ReflowLayout::add(w)
76+
self.center.push_back({sl, NULL, padding})
77+
;
78+
unordered_map<Scene, vector<ReflowLayout*>> ReflowLayout::scene_to_layouts = {}
79+
80+
class HorizontalReflow: public ReflowLayout:
81+
public:
82+
using ReflowLayout::pack_start;
83+
using ReflowLayout::pack_end;
84+
using ReflowLayout::pack_center;
85+
86+
HorizontalReflow(int x, y, w, h, Scene s): ReflowLayout(x,y,w,h,s):
87+
pass
88+
89+
void reflow():
90+
offset := 0
91+
debug "REFLOWING HORIZONTAL"
92+
for auto pw : self.start:
93+
if pw.sp != NULL:
94+
padding = pw.padding
95+
pw.sp->x += offset + self.x + padding
96+
pw.sp->y += self.y
97+
offset += pw.sp->w + padding
98+
pw.sp->on_reflow()
99+
if pw.sl != NULL:
100+
padding = pw.padding
101+
pw.sl->x += offset + self.x + padding
102+
pw.sl->y += self.y
103+
offset += pw.sl->w + padding
104+
pw.sl->reflow()
105+
106+
offset = self.w
107+
for auto pw : self.end:
108+
if pw.sp != NULL:
109+
padding = pw.padding
110+
pw.sp->x = self.x + offset - pw.sp->w - padding
111+
pw.sp->y += self.y
112+
offset -= pw.sp->w + padding
113+
pw.sp->on_reflow()
114+
if pw.sl != NULL:
115+
padding = pw.padding
116+
pw.sl->x = self.x + offset - pw.sl->w - padding
117+
pw.sl->y += self.y
118+
offset -= pw.sl->w + padding
119+
pw.sl->reflow()
120+
121+
for auto pw : self.center:
122+
if pw.sp != NULL:
123+
leftover := self.w - pw.sp->w
124+
padding_x := 0
125+
if leftover > 0:
126+
padding_x = leftover / 2
127+
pw.sp->x = self.x + padding_x
128+
pw.sp->y += self.y
129+
pw.sp->on_reflow()
130+
if pw.sl != NULL:
131+
leftover := self.w - pw.sl->w
132+
padding_x := 0
133+
if leftover > 0:
134+
padding_x = leftover / 2
135+
pw.sl->x = self.x + padding_x
136+
pw.sl->y += self.y
137+
pw.sl->reflow()
138+
139+
class VerticalReflow: public ReflowLayout:
140+
public:
141+
using ReflowLayout::pack_start;
142+
using ReflowLayout::pack_end;
143+
using ReflowLayout::pack_center;
144+
145+
VerticalReflow(int x, y, w, h, Scene s): ReflowLayout(x,y,w,h,s):
146+
pass
147+
148+
void reflow():
149+
debug "REFLOWING VERTICAL"
150+
offset := 0
151+
shared_ptr<Widget> w
152+
for auto pw : self.start:
153+
if pw.sp != NULL:
154+
padding := pw.padding
155+
pw.sp->y += offset + self.y + padding
156+
pw.sp->x += self.x
157+
offset += pw.sp->h + padding
158+
pw.sp->on_reflow()
159+
if pw.sl != NULL:
160+
padding := pw.padding
161+
pw.sl->y += offset + self.y + padding
162+
pw.sl->x += self.x
163+
offset += pw.sl->h + padding
164+
pw.sl->reflow()
165+
166+
offset = self.h
167+
for auto pw : self.end:
168+
if pw.sp != NULL:
169+
padding = pw.padding
170+
pw.sp->y = self.y + offset - pw.sp->h - padding
171+
pw.sp->x += self.x
172+
offset -= pw.sp->h + padding
173+
pw.sp->on_reflow()
174+
if pw.sl != NULL:
175+
padding = pw.padding
176+
pw.sl->y = self.y + offset - pw.sl->h - padding
177+
pw.sl->x += self.x
178+
offset -= pw.sl->h + padding
179+
pw.sl->reflow()
180+
181+
for auto pw : self.center:
182+
if pw.sp != NULL:
183+
leftover := self.h - pw.sp->h
184+
padding_y := 0
185+
if leftover > 0:
186+
padding_y = leftover / 2
187+
pw.sp->y = self.y + padding_y
188+
pw.sp->x += self.x
189+
pw.sp->on_reflow()
190+
if pw.sl != NULL:
191+
leftover := self.h - pw.sl->h
192+
padding_y := 0
193+
if leftover > 0:
194+
padding_y = leftover / 2
195+
pw.sl->y = self.y + padding_y
196+
pw.sl->x += self.x
197+
pw.sl->reflow()
198+

src/rmkit/ui/ui.cpy

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "dialog.h"
55
#include "dropdown.h"
66
#include "layouts.h"
7+
#include "reflow.h"
78
#include "main_loop.h"
89
#include "pager.h"
910
#include "pixmap.h"

src/rmkit/ui/widget.cpy

+28-19
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,38 @@
44
#include "../util/signals.h"
55

66
namespace ui:
7+
class Rect:
8+
public:
9+
// variables: x, y, w, h
10+
//
11+
// x - the x coordinate of the widget.
12+
// y - the y coordinate of the widget.
13+
// w - the width of the widget
14+
// h - the height of the widget
15+
int x, y, w, h
16+
int _x, _y, _w, _h // the original values the widget was instantiated with
17+
18+
Rect(int x,y,w,h): x(x), y(y), w(w), h(h), _x(x), _y(y), _w(w), _h(h):
19+
pass
20+
21+
// this restores the coordinates of a widget to the coords it was initially
22+
// given when it was constructed. this could be used to support reflowing
23+
// widgets
24+
void restore_coords():
25+
x = _x
26+
y = _y
27+
w = _w
28+
h = _h
29+
30+
virtual void on_reflow():
31+
pass
32+
733
// Class: ui::Widget
834
//
935
// The widget class is the base of all other widgets. A widget is typically
1036
// a piece of UI that can receive inputs and draw to screen through the
1137
// frame buffer
12-
class Widget:
38+
class Widget : public Rect:
1339
public:
1440

1541
// variable: fb
@@ -22,14 +48,6 @@ namespace ui:
2248
GESTURE_EVENTS_DELEGATE gestures = { &mouse }
2349
KEY_EVENTS kbd
2450

25-
// variables: x, y, w, h
26-
//
27-
// x - the x coordinate of the widget.
28-
// y - the y coordinate of the widget.
29-
// w - the width of the widget
30-
// h - the height of the widget
31-
int x, y, w, h
32-
int _x, _y, _w, _h // the original values the widget was instantiated with
3351
int mouse_down = false, mouse_inside = false, mouse_down_first = false, mouse_x, mouse_y
3452
int dirty = 1
3553
bool visible = true
@@ -43,7 +61,7 @@ namespace ui:
4361
// y - the y coord of the top left of the widget
4462
// w - the width of the widget
4563
// h - the height of the widget
46-
Widget(int x,y,w,h): x(x), y(y), w(w), h(h), _x(x), _y(y), _w(w), _h(h):
64+
Widget(int x,y,w,h): Rect(x,y,w,h):
4765
self.install_signal_handlers()
4866

4967
virtual ~Widget():
@@ -192,15 +210,6 @@ namespace ui:
192210
if d != -1:
193211
self.h = d
194212

195-
// this restores the coordinates of a widget to the coords it was initially
196-
// given when it was constructed. this could be used to support reflowing
197-
// widgets
198-
void restore_coords():
199-
x = _x
200-
y = _y
201-
w = _w
202-
h = _h
203-
204213
// function: get_render_size
205214
// gets the size of the rendered widget. this is for variable sized widgets
206215
// like text widgets which might have different sizes depending on the

0 commit comments

Comments
 (0)