1 #include "config.h"
2
3 #ifdef HAVE_ALLOCA_H
4 #include <alloca.h>
5 #endif
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "newt.h"
10 #include "newt_pr.h"
11
12 struct gridField {
13 enum newtGridElement type;
14 union {
15 newtGrid grid;
16 newtComponent co;
17 } u;
18 int padLeft, padTop, padRight, padBottom;
19 int anchor;
20 int flags;
21 };
22
23 struct grid_s {
24 int rows, cols;
25 int width, height; /* totals, -1 means unknown */
26 struct gridField ** fields;
27 };
28
29 /* this is a bit of a hack */
30 extern struct componentOps formOps[];
31
newtCreateGrid(int cols,int rows)32 newtGrid newtCreateGrid(int cols, int rows) {
33 newtGrid grid;
34
35 grid = malloc(sizeof(*grid));
36 grid->rows = rows;
37 grid->cols = cols;
38
39 grid->fields = malloc(sizeof(*grid->fields) * cols);
40 while (cols--) {
41 grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows);
42 memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows);
43 }
44
45 grid->width = grid->height = -1;
46
47 return grid;
48 }
49
newtGridSetField(newtGrid grid,int col,int row,enum newtGridElement type,void * val,int padLeft,int padTop,int padRight,int padBottom,int anchor,int flags)50 void newtGridSetField(newtGrid grid, int col, int row,
51 enum newtGridElement type, void * val, int padLeft,
52 int padTop, int padRight, int padBottom, int anchor,
53 int flags) {
54 struct gridField * field = &grid->fields[col][row];
55
56 if (field->type == NEWT_GRID_SUBGRID)
57 newtGridFree(field->u.grid, 1);
58
59 field->type = type;
60 field->u.co = (void *) val;
61
62 field->padLeft = padLeft;
63 field->padRight = padRight;
64 field->padTop = padTop;
65 field->padBottom = padBottom;
66 field->anchor = anchor;
67 field->flags = flags;
68
69 grid->width = grid->height = -1;
70 }
71
distSpace(int extra,int items,int * list)72 static void distSpace(int extra, int items, int * list) {
73 int all, some, i;
74
75 all = extra / items;
76 some = extra % items;
77 for (i = 0; i < items; i++) {
78 list[i] += all;
79 if (some) {
80 list[i]++;
81 some--;
82 }
83 }
84 }
85
shuffleGrid(newtGrid grid,int left,int top,int set)86 static void shuffleGrid(newtGrid grid, int left, int top, int set) {
87 struct gridField * field;
88 int row, col;
89 int i, j;
90 int minWidth, minHeight;
91 int * widths, * heights;
92 int thisLeft, thisTop;
93 int x, y, remx, remy;
94
95 widths = alloca(sizeof(*widths) * grid->cols);
96 memset(widths, 0, sizeof(*widths) * grid->cols);
97 heights = alloca(sizeof(*heights) * grid->rows);
98 memset(heights, 0, sizeof(*heights) * grid->rows);
99
100 minWidth = 0;
101 for (row = 0; row < grid->rows; row++) {
102 i = 0;
103 for (col = 0; col < grid->cols; col++) {
104 field = &grid->fields[col][row];
105 if (field->type == NEWT_GRID_SUBGRID) {
106 /* we'll have to redo this later */
107 if (field->u.grid->width == -1)
108 shuffleGrid(field->u.grid, left, top, 0);
109 j = field->u.grid->width;
110 } else if (field->type == NEWT_GRID_COMPONENT) {
111 if (field->u.co->ops == formOps)
112 newtFormSetSize(field->u.co);
113 j = field->u.co->width;
114 } else
115 j = 0;
116
117 j += field->padLeft + field->padRight;
118
119 if (j > widths[col]) widths[col] = j;
120 i += widths[col];
121 }
122
123 if (i > minWidth) minWidth = i;
124 }
125
126 minHeight = 0;
127 for (col = 0; col < grid->cols; col++) {
128 i = 0;
129 for (row = 0; row < grid->rows; row++) {
130 field = &grid->fields[col][row];
131 if (field->type == NEWT_GRID_SUBGRID) {
132 /* we'll have to redo this later */
133 if (field->u.grid->height == -1)
134 shuffleGrid(field->u.grid, 0, 0, 0);
135 j = field->u.grid->height;
136 } else if (field->type == NEWT_GRID_COMPONENT){
137 j = field->u.co->height;
138 } else
139 j = 0;
140
141 j += field->padTop + field->padBottom;
142
143 if (j > heights[row]) heights[row] = j;
144 i += heights[row];
145 }
146
147 if (i > minHeight) minHeight = i;
148 }
149
150 /* this catches the -1 case */
151 if (grid->width < minWidth) grid->width = minWidth; /* ack! */
152 if (grid->height < minHeight) grid->height = minHeight; /* ditto! */
153
154 if (!set) return;
155
156 distSpace(grid->width - minWidth, grid->cols, widths);
157 distSpace(grid->height - minHeight, grid->rows, heights);
158
159 thisTop = top;
160 for (row = 0; row < grid->rows; row++) {
161 i = 0;
162 thisLeft = left;
163 for (col = 0; col < grid->cols; col++) {
164 field = &grid->fields[col][row];
165
166 if (field->type == NEWT_GRID_EMPTY) continue;
167
168 x = thisLeft + field->padLeft;
169 remx = widths[col] - field->padLeft - field->padRight;
170 y = thisTop + field->padTop;
171 remy = heights[row] - field->padTop - field->padBottom;
172
173 if (field->type == NEWT_GRID_SUBGRID) {
174 remx -= field->u.grid->width;
175 remy -= field->u.grid->height;
176 } else if (field->type == NEWT_GRID_COMPONENT) {
177 remx -= field->u.co->width;
178 remy -= field->u.co->height;
179 }
180
181 if (!(field->flags & NEWT_GRID_FLAG_GROWX)) {
182 if (field->anchor & NEWT_ANCHOR_RIGHT)
183 x += remx;
184 else if (!(field->anchor & NEWT_ANCHOR_LEFT))
185 x += (remx / 2);
186 }
187
188 if (!(field->flags & NEWT_GRID_FLAG_GROWY)) {
189 if (field->anchor & NEWT_ANCHOR_BOTTOM)
190 y += remx;
191 else if (!(field->anchor & NEWT_ANCHOR_TOP))
192 y += (remy / 2);
193 }
194
195 if (field->type == NEWT_GRID_SUBGRID) {
196 if (field->flags & NEWT_GRID_FLAG_GROWX)
197 field->u.grid->width = widths[col] - field->padLeft
198 - field->padRight;
199 if (field->flags & NEWT_GRID_FLAG_GROWY)
200 field->u.grid->height = heights[col] - field->padTop
201 - field->padBottom;
202
203 shuffleGrid(field->u.grid, x, y, 1);
204 } else if (field->type == NEWT_GRID_COMPONENT) {
205 field->u.co->ops->place(field->u.co, x, y);
206 }
207
208 thisLeft += widths[col];
209 }
210
211 thisTop += heights[row];
212 }
213 }
214
newtGridPlace(newtGrid grid,int left,int top)215 void newtGridPlace(newtGrid grid, int left, int top) {
216 shuffleGrid(grid, left, top, 1);
217 }
218
newtGridFree(newtGrid grid,int recurse)219 void newtGridFree(newtGrid grid, int recurse) {
220 int row, col;
221
222 for (col = 0; col < grid->cols; col++) {
223 if (recurse) {
224 for (row = 0; row < grid->rows; row++) {
225 if (grid->fields[col][row].type == NEWT_GRID_SUBGRID)
226 newtGridFree(grid->fields[col][row].u.grid, 1);
227 }
228 }
229
230 free(grid->fields[col]);
231 }
232
233 free(grid->fields);
234 free(grid);
235 }
236
newtGridGetSize(newtGrid grid,int * width,int * height)237 void newtGridGetSize(newtGrid grid, int * width, int * height) {
238 if (grid->width == -1 || grid->height == -1) {
239 grid->width = grid->height = -1;
240 shuffleGrid(grid, 0, 0, 1);
241 }
242
243 *width = grid->width;
244 *height = grid->height;
245 }
246
newtGridWrappedWindow(newtGrid grid,char * title)247 void newtGridWrappedWindow(newtGrid grid, char * title) {
248 int w, width, height, offset = 0;
249
250 newtGridGetSize(grid, &width, &height);
251 w = wstrlen(title,-1);
252 if (width < w + 2) {
253 offset = ((w + 2) - width) / 2;
254 width = w + 2;
255 }
256 newtCenteredWindow(width + 2, height + 2, title);
257 newtGridPlace(grid, 1 + offset, 1);
258 }
259
newtGridWrappedWindowAt(newtGrid grid,char * title,int left,int top)260 void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) {
261 int width, height;
262
263 newtGridGetSize(grid, &width, &height);
264 newtOpenWindow(left, top, width + 2, height + 2, title);
265 newtGridPlace(grid, 1, 1);
266 }
267
newtGridAddComponentsToForm(newtGrid grid,newtComponent form,int recurse)268 void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
269 int recurse) {
270 int row, col;
271
272 for (col = 0; col < grid->cols; col++) {
273 for (row = 0; row < grid->rows; row++) {
274 if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse)
275 newtGridAddComponentsToForm(grid->fields[col][row].u.grid,
276 form, 1);
277 else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT)
278 newtFormAddComponent(form, grid->fields[col][row].u.co);
279 }
280 }
281 }
282
283 /* this handles up to 50 items */
stackem(int isVert,enum newtGridElement type1,void * what1,va_list args,int close)284 static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1,
285 va_list args, int close) {
286 struct item {
287 enum newtGridElement type;
288 void * what;
289 } items[50];
290 int i, num;
291 newtGrid grid;
292
293 items[0].type = type1, items[0].what = what1, num = 1;
294 while (1) {
295 items[num].type = va_arg(args, enum newtGridElement);
296 if (items[num].type == NEWT_GRID_EMPTY) break;
297
298 items[num].what = va_arg(args, void *);
299 num++;
300 }
301
302 grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1);
303
304 for (i = 0; i < num; i++) {
305 newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0,
306 items[i].type, items[i].what,
307 close ? 0 : (i ? (isVert ? 0 : 1) : 0),
308 close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0);
309 }
310
311 return grid;
312 }
313
newtGridHCloseStacked(enum newtGridElement type1,void * what1,...)314 newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) {
315 va_list args;
316 newtGrid grid;
317
318 va_start(args, what1);
319
320 grid = stackem(0, type1, what1, args, 1);
321
322 va_end(args);
323
324 return grid;
325 }
326
newtGridVCloseStacked(enum newtGridElement type1,void * what1,...)327 newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) {
328 va_list args;
329 newtGrid grid;
330
331 va_start(args, what1);
332
333 grid = stackem(1, type1, what1, args, 1);
334
335 va_end(args);
336
337 return grid;
338 }
339
newtGridVStacked(enum newtGridElement type1,void * what1,...)340 newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) {
341 va_list args;
342 newtGrid grid;
343
344 va_start(args, what1);
345
346 grid = stackem(1, type1, what1, args, 0);
347
348 va_end(args);
349
350 return grid;
351 }
352
newtGridHStacked(enum newtGridElement type1,void * what1,...)353 newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) {
354 va_list args;
355 newtGrid grid;
356
357 va_start(args, what1);
358
359 grid = stackem(0, type1, what1, args, 0);
360
361 va_end(args);
362
363 return grid;
364 }
365
newtGridBasicWindow(newtComponent text,newtGrid middle,newtGrid buttons)366 newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
367 newtGrid buttons) {
368 newtGrid grid;
369
370 grid = newtCreateGrid(1, 3);
371 newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
372 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
373 newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle,
374 0, 1, 0, 0, 0, 0);
375 newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
376 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
377
378 return grid;
379 }
380
newtGridSimpleWindow(newtComponent text,newtComponent middle,newtGrid buttons)381 newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
382 newtGrid buttons) {
383 newtGrid grid;
384
385 grid = newtCreateGrid(1, 3);
386 newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
387 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
388 newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle,
389 0, 1, 0, 0, 0, 0);
390 newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
391 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
392
393 return grid;
394 }
395