1 #ifndef YLAYOUT_H
2 #define YLAYOUT_H
3
4 /*
5 * Layout widgets.
6 * Use in dialogs.
7 */
8
9 #include "yarray.h"
10
11 class YWindow;
12
13 /*
14 * Layout base interface.
15 */
16 class Sizeable {
17 public:
~Sizeable()18 virtual ~Sizeable() { }
19 virtual unsigned width() = 0;
20 virtual unsigned height() = 0;
21 virtual int x() = 0;
22 virtual int y() = 0;
23 virtual void setPosition(int x, int y) = 0;
24 virtual void realize() = 0;
25
26 void layout(YWindow* outside);
27 };
28
29 /*
30 * Create internal space in a dialog.
31 */
32 class Spacer : public Sizeable {
33 public:
Spacer(unsigned width,unsigned height)34 Spacer(unsigned width, unsigned height) :
35 fW(width), fH(height), fX(0), fY(0) { }
width()36 unsigned width() override { return fW; }
height()37 unsigned height() override { return fH; }
x()38 int x() override { return fX; }
y()39 int y() override { return fY; }
setPosition(int x,int y)40 void setPosition(int x, int y) override {
41 fX = x;
42 fY = y;
43 }
realize()44 void realize() override { }
45 protected:
46 unsigned fW, fH;
47 int fX, fY;
48 };
49
50 /*
51 * Hold a YWindow.
52 */
53 class Cell : public Sizeable {
54 public:
Cell(YWindow * win)55 Cell(YWindow* win) : fWin(win) { }
~Cell()56 ~Cell() { delete fWin; }
width()57 unsigned width() override { return fWin->width(); }
height()58 unsigned height() override { return fWin->height(); }
x()59 int x() override { return fWin->x(); }
y()60 int y() override { return fWin->y(); }
setPosition(int x,int y)61 void setPosition(int x, int y) override {
62 fWin->setPosition(x, y);
63 }
realize()64 void realize() override { fWin->show(); }
65 protected:
66 YWindow* fWin;
67 };
68
69 /*
70 * Create space around others.
71 */
72 class Padder : public Sizeable {
73 public:
Padder(Sizeable * win,int hpad,int vpad)74 Padder(Sizeable* win, int hpad, int vpad) :
75 fWin(win), fHori(hpad), fVert(vpad) { }
~Padder()76 ~Padder() { delete fWin; }
width()77 unsigned width() override { return fWin->width() + 2 * fHori; }
height()78 unsigned height() override { return fWin->height() + 2 * fVert; }
x()79 int x() override { return fWin->x() - fHori; }
y()80 int y() override { return fWin->y() - fVert; }
setPosition(int x,int y)81 void setPosition(int x, int y) override {
82 fWin->setPosition(x + fHori, y + fVert);
83 }
realize()84 void realize() override { fWin->realize(); }
85 protected:
86 Sizeable* fWin;
87 int fHori, fVert;
88 };
89
90 /*
91 * Group sizeables vertically.
92 */
93 class Ladder : public Sizeable {
94 public:
95 Ladder& operator+=(Sizeable* step) {
96 fSteps += step;
97 return *this;
98 }
99 Ladder& operator+=(YWindow* win) {
100 return operator+=(new Cell(win));
101 }
empty()102 bool empty() const {
103 return fSteps.isEmpty();
104 }
width()105 unsigned width() override {
106 unsigned w = 1;
107 for (Sizeable* step : fSteps)
108 w = max(w, step->width());
109 return w;
110 }
height()111 unsigned height() override {
112 unsigned h = 0;
113 for (Sizeable* step : fSteps)
114 h += step->height();
115 return h;
116 }
x()117 int x() override { return empty() ? 0 : fSteps[0]->x(); }
y()118 int y() override { return empty() ? 0 : fSteps[0]->y(); }
setPosition(int x,int y)119 void setPosition(int x, int y) override {
120 for (Sizeable* step : fSteps) {
121 step->setPosition(x, y);
122 y += step->height();
123 }
124 }
realize()125 void realize() override {
126 for (Sizeable* step : fSteps)
127 step->realize();
128 }
129
130 protected:
131 YObjectArray<Sizeable> fSteps;
132 };
133
134 /*
135 * Group sizeables horizontally.
136 */
137 class Row : public Sizeable {
138 public:
139 Row(Sizeable* left, Sizeable* right = nullptr) :
fLeft(left)140 fLeft(left), fRight(right),
141 fOffset(fRight ? 20 + left->width() : 0) { }
142 Row(YWindow* left, YWindow* right = nullptr) :
143 Row(new Cell(left), right ? new Cell(right) : nullptr) { }
~Row()144 ~Row() {
145 delete fLeft;
146 delete fRight;
147 }
offset()148 unsigned offset() {
149 return fRight ? max(fOffset, fLeft->width()) : 0;
150 }
setOffset(unsigned newOffset)151 void setOffset(unsigned newOffset) {
152 if (fOffset != newOffset) {
153 fOffset = newOffset;
154 if (fRight)
155 fRight->setPosition(x() + offset(), y());
156 }
157 }
width()158 unsigned width() override {
159 return fRight ? offset() + fRight->width() : fLeft->width();
160 }
height()161 unsigned height() override {
162 return max(fLeft->height(), fRight ? fRight->height() : 0);
163 }
x()164 int x() override { return fLeft->x(); }
y()165 int y() override { return fLeft->y(); }
setPosition(int x,int y)166 void setPosition(int x, int y) override {
167 fLeft->setPosition(x, y);
168 if (fRight)
169 fRight->setPosition(x + offset(), y);
170 }
realize()171 void realize() override {
172 fLeft->realize();
173 if (fRight)
174 fRight->realize();
175 }
swapColumns()176 void swapColumns() {
177 if (fLeft && fRight)
178 ::swap(fLeft, fRight);
179 }
180
181 protected:
182 Sizeable* fLeft;
183 Sizeable* fRight;
184 unsigned fOffset;
185 };
186
187 /*
188 * A grid of rows.
189 * The second column is aligned.
190 */
191 class Table : public Sizeable {
192 public:
Table()193 Table() { }
~Table()194 ~Table() { }
195 Table& operator+=(Row* row) {
196 if (row) fRows += row;
197 return *this;
198 }
width()199 unsigned width() override {
200 unsigned w = 1;
201 for (Sizeable* row : fRows)
202 w = max(w, row->width());
203 return w;
204 }
height()205 unsigned height() override {
206 unsigned h = 1;
207 for (Sizeable* row : fRows)
208 h = max(h, row->y() + row->height());
209 return h - y();
210 }
x()211 int x() override {
212 int x = fRows.nonempty() ? fRows[0]->x() : 0;
213 for (Sizeable* row : fRows)
214 x = min(x, row->x());
215 return x;
216 }
y()217 int y() override {
218 return fRows.nonempty() ? fRows[0]->y() : 0;
219 }
setPosition(int x,int y)220 void setPosition(int x, int y) override {
221 for (Sizeable* row : fRows) {
222 row->setPosition(x, y);
223 y += row->height();
224 }
225 }
realize()226 void realize() override {
227 unsigned offset = 0;
228 for (Row* row : fRows) {
229 offset = max(offset, row->offset());
230 }
231 for (Row* row : fRows) {
232 row->setOffset(offset);
233 row->realize();
234 }
235 }
swapColumns()236 void swapColumns() {
237 for (Row* row : fRows) {
238 row->swapColumns();
239 }
240 }
241 protected:
242 YObjectArray<Row> fRows;
243 };
244
245 /*
246 * Communicate a layout to the outside world.
247 */
layout(YWindow * outside)248 inline void Sizeable::layout(YWindow* outside) {
249 setPosition(0, 0);
250 realize();
251 outside->setSize(width(), height());
252 }
253
254 #endif
255
256 // vim: set sw=4 ts=4 et:
257