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