1 /* Copyright (C) 2006-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "gdraw.h"
31 #include "ggadgetP.h"
32
33 /* If the locale is hebrew or arabic should we lay out boxes right to left???*/
34
35 #define GG_Glue ((GGadget *) -1) /* Special entries */
36 #define GG_ColSpan ((GGadget *) -2) /* for box elements */
37 #define GG_RowSpan ((GGadget *) -3) /* Must match those in ggadget.h */
38 #define GG_HPad10 ((GGadget *) -4)
39
40 static GBox hvgroup_box = GBOX_EMPTY; /* Don't initialize here */
41 static GBox hvbox_box = GBOX_EMPTY; /* Don't initialize here */
42 static int ghvbox_inited = false;
43
44 GResInfo ghvgroupbox_ri = {
45 NULL, &ggadget_ri, NULL, NULL,
46 &hvgroup_box,
47 NULL,
48 NULL,
49 NULL,
50 N_("HV Group Box"),
51 N_("A box drawn around other gadgets"),
52 "GGroup",
53 "Gdraw",
54 false,
55 omf_border_type|omf_border_shape|omf_padding|omf_main_background|omf_disabled_background,
56 NULL,
57 GBOX_EMPTY,
58 NULL,
59 NULL,
60 NULL
61 };
62
_GHVBox_Init(void)63 static void _GHVBox_Init(void) {
64 if ( ghvbox_inited )
65 return;
66 _GGadgetCopyDefaultBox(&hvgroup_box);
67 _GGadgetCopyDefaultBox(&hvbox_box);
68 hvgroup_box.border_type = bt_engraved;
69 hvbox_box.border_type = bt_none;
70 hvbox_box.border_width = 0;
71 hvgroup_box.border_shape = hvbox_box.border_shape = bs_rect;
72 hvgroup_box.padding = 2;
73 hvbox_box.padding = 0;
74 /*hvgroup_box.flags = hvbox_box.flags = 0;*/
75 hvgroup_box.main_background = COLOR_TRANSPARENT;
76 hvgroup_box.disabled_background = COLOR_TRANSPARENT;
77 _GGadgetInitDefaultBox("GHVBox.",&hvbox_box,NULL);
78 _GGadgetInitDefaultBox("GGroup.",&hvgroup_box,NULL);
79 ghvbox_inited = true;
80 }
81
GHVBox_destroy(GGadget * g)82 static void GHVBox_destroy(GGadget *g) {
83 GHVBox *gb = (GHVBox *) g;
84 int i;
85
86 if ( gb->label != NULL )
87 GGadgetDestroy( gb->label );
88 for ( i=0; i<gb->rows*gb->cols; ++i )
89 if ( gb->children[i]!=GG_Glue && gb->children[i]!=GG_ColSpan &&
90 gb->children[i]!=GG_RowSpan && gb->children[i]!=GG_HPad10 )
91 GGadgetDestroy(gb->children[i]);
92 free(gb->children);
93 _ggadget_destroy(g);
94 }
95
GHVBoxMove(GGadget * g,int32 x,int32 y)96 static void GHVBoxMove(GGadget *g, int32 x, int32 y) {
97 GHVBox *gb = (GHVBox *) g;
98 int offx = x-g->r.x, offy = y-g->r.y;
99 int i;
100
101 if ( gb->label!=NULL )
102 GGadgetMove(gb->label,gb->label->inner.x+offx,gb->label->inner.y+offy);
103 for ( i=0; i<gb->rows*gb->cols; ++i )
104 if ( gb->children[i]!=GG_Glue && gb->children[i]!=GG_ColSpan &&
105 gb->children[i]!=GG_RowSpan && gb->children[i]!=GG_HPad10 )
106 GGadgetMove(gb->children[i],
107 gb->children[i]->r.x+offx, gb->children[i]->r.y+offy);
108 _ggadget_move(g,x,y);
109 }
110
111 struct sizedata {
112 int extra_space; /* a default button has "extra_space" */
113 int min; /* This value includes padding */
114 int sized;
115 int allocated;
116 int allglue;
117 };
118
119 struct sizeinfo {
120 struct sizedata *cols;
121 struct sizedata *rows;
122 int label_height, label_width;
123 int width, height;
124 int minwidth, minheight;
125 };
126
GHVBoxGatherSizeInfo(GHVBox * gb,struct sizeinfo * si)127 static void GHVBoxGatherSizeInfo(GHVBox *gb,struct sizeinfo *si) {
128 int i,c,r,spanc, spanr, totc,totr, max, plus, extra, es;
129 GRect outer;
130 int ten = GDrawPointsToPixels(gb->g.base,10);
131
132 memset(si,0,sizeof(*si));
133 si->cols = calloc(gb->cols,sizeof(struct sizedata));
134 si->rows = calloc(gb->rows,sizeof(struct sizedata));
135 for ( c=0; c<gb->cols; ++c ) si->cols[c].allglue = true;
136 for ( r=0; r<gb->rows; ++r ) si->rows[r].allglue = true;
137
138 for ( r=0; r<gb->rows; ++r ) {
139 for ( c=0; c<gb->cols; ++c ) {
140 GGadget *g = gb->children[r*gb->cols+c];
141 if ( g==GG_Glue ) {
142 if ( c+1!=gb->cols && si->cols[c].min<gb->hpad ) si->cols[c].min = gb->hpad;
143 if ( r+1!=gb->rows && si->rows[r].min<gb->vpad ) si->rows[r].min = gb->vpad;
144 } else if ( g==GG_HPad10 ) {
145 if ( c+1!=gb->cols && si->cols[c].min<gb->hpad+ten ) si->cols[c].min = gb->hpad+ten;
146 if ( r+1!=gb->rows && si->rows[r].min<gb->vpad ) si->rows[r].min = gb->vpad+ten/2;
147 si->cols[c].allglue = false;
148 } else if ( g==GG_ColSpan || g==GG_RowSpan )
149 /* Skip it */;
150 else if ( (r+1<gb->rows && gb->children[(r+1)*gb->cols+c]==GG_RowSpan) ||
151 (c+1<gb->cols && gb->children[r*gb->cols+c+1]==GG_ColSpan))
152 /* This gadget spans some columns or rows. Come back later */;
153 else {
154 GGadgetGetDesiredSize(g,&outer,NULL);
155 es = GBoxExtraSpace(g);
156 if ( c+1!=gb->cols && g->state!=gs_invisible )
157 outer.width += gb->hpad;
158 if ( r+1!=gb->rows && g->state!=gs_invisible )
159 outer.height += gb->vpad;
160 si->cols[c].allglue = false;
161 if ( si->cols[c].extra_space<es ) si->cols[c].extra_space=es;
162 if ( si->cols[c].min<outer.width ) si->cols[c].min=outer.width;
163 si->rows[r].allglue = false;
164 if ( si->rows[r].min<outer.height ) si->rows[r].min=outer.height;
165 if ( si->rows[r].extra_space<es ) si->rows[r].extra_space=es;
166 }
167 }
168 }
169
170 for ( r=0; r<gb->rows; ++r ) {
171 for ( c=0; c<gb->cols; ++c ) {
172 GGadget *g = gb->children[r*gb->cols+c];
173 if ( g==GG_Glue || g==GG_ColSpan || g==GG_RowSpan || g==GG_HPad10 )
174 /* Skip it */;
175 else if ( (r+1<gb->rows && gb->children[(r+1)*gb->cols+c]==GG_RowSpan) ||
176 (c+1<gb->cols && gb->children[r*gb->cols+c+1]==GG_ColSpan)) {
177 si->rows[r].allglue = false;
178 totr = si->rows[r].min;
179 for ( spanr=1; r+spanr<gb->rows &&
180 gb->children[(r+spanr)*gb->cols+c]==GG_RowSpan; ++spanr ) {
181 si->rows[r+spanr].allglue = false;
182 totr += si->rows[r+spanr].min;
183 }
184 si->cols[c].allglue = false;
185 totc = si->cols[c].min;
186 for ( spanc=1; c+spanc<gb->cols &&
187 gb->children[r*gb->cols+c+spanc]==GG_ColSpan; ++spanc ) {
188 si->cols[c+spanc].allglue = false;
189 totc += si->cols[c+spanc].min;
190 }
191 GGadgetGetDesiredSize(g,&outer,NULL);
192 es = GBoxExtraSpace(g);
193 if ( c+spanc!=gb->cols && g->state!=gs_invisible )
194 outer.width += gb->hpad;
195 if ( r+spanr!=gb->rows && g->state!=gs_invisible )
196 outer.height += gb->vpad;
197 if ( outer.width>totc ) {
198 plus = (outer.width-totc)/spanc;
199 extra = (outer.width-totc-spanc*plus);
200 for ( i=0; i<spanc; ++i ) {
201 si->cols[c+i].min += plus + (extra>0);
202 --extra;
203 }
204 }
205 if ( outer.height>totr ) {
206 plus = (outer.height-totr)/spanr;
207 extra = (outer.height-totr-spanr*plus);
208 for ( i=0; i<spanr; ++i ) {
209 si->rows[r+i].min += plus + (extra>0);
210 --extra;
211 }
212 }
213 if ( es!=0 ) {
214 for ( i=0; i<spanc; ++i ) {
215 if ( es>si->cols[c+i].extra_space )
216 si->cols[c+i].extra_space = es;
217 }
218 for ( i=0; i<spanr; ++i ) {
219 if ( es>si->rows[r+i].extra_space )
220 si->rows[r+i].extra_space = es;
221 }
222 }
223 }
224 }
225 }
226
227 if ( gb->label!=NULL ) {
228 GGadgetGetDesiredSize(gb->label,&outer,NULL);
229 totc = 0;
230 for ( c=0; c<gb->cols ; ++c )
231 totc += si->cols[c].min;
232 outer.width += 20; /* Set back on each side */
233 if ( outer.width>totc ) {
234 plus = (outer.width-totc)/gb->cols;
235 extra = (outer.width-totc-gb->cols*plus);
236 for ( i=0; i<gb->cols; ++i ) {
237 si->cols[i].min += plus + (extra>0);
238 --extra;
239 }
240 }
241 si->label_height = outer.height;
242 si->label_width = outer.width;
243 }
244
245 for ( max=c=0; c<gb->cols; ++c )
246 si->cols[c].sized = si->cols[c].min;
247 for ( max=r=0; r<gb->rows; ++r )
248 si->rows[r].sized = si->rows[r].min;
249
250 if ( gb->grow_col==gb_samesize ) {
251 for ( max=c=0; c<gb->cols; ++c )
252 if ( max<si->cols[c].sized ) max = si->cols[c].sized;
253 for ( c=0; c<gb->cols; ++c )
254 if ( si->cols[c].min!=0 || si->cols[c].allglue )
255 si->cols[c].sized = max;
256 } else if ( gb->grow_col==gb_expandgluesame ) {
257 for ( max=c=0; c<gb->cols; ++c )
258 if ( max<si->cols[c].sized && !si->cols[c].allglue ) max = si->cols[c].sized;
259 for ( c=0; c<gb->cols; ++c )
260 if ( !si->cols[c].allglue && si->cols[c].min!=0 ) /* Must have at least one visible element */
261 si->cols[c].sized = max;
262 }
263
264 if ( gb->grow_row==gb_samesize ) {
265 for ( max=r=0; r<gb->rows; ++r )
266 if ( max<si->rows[r].sized ) max = si->rows[r].sized;
267 for ( r=0; r<gb->rows; ++r )
268 if ( si->rows[r].min!=0 || si->rows[r].allglue )
269 si->rows[r].sized = max;
270 } else if ( gb->grow_row==gb_expandgluesame ) {
271 for ( max=r=0; r<gb->rows; ++r )
272 if ( max<si->rows[r].sized && !si->rows[r].allglue ) max = si->rows[r].sized;
273 for ( r=0; r<gb->rows; ++r )
274 if ( !si->rows[r].allglue && si->rows[r].min>0 )
275 si->rows[r].sized = max;
276 }
277
278 for ( i=si->width = si->minwidth = 0; i<gb->cols; ++i ) {
279 si->width += si->cols[i].sized;
280 si->minwidth += si->cols[i].min;
281 }
282 for ( i=0, si->height=si->minheight = si->label_height; i<gb->rows; ++i ) {
283 si->height += si->rows[i].sized;
284 si->minheight += si->rows[i].min;
285 }
286 }
287
GHVBoxResize(GGadget * g,int32 width,int32 height)288 static void GHVBoxResize(GGadget *g, int32 width, int32 height) {
289 struct sizeinfo si;
290 GHVBox *gb = (GHVBox *) g;
291 int bp = GBoxBorderWidth(g->base,g->box);
292 int i,c,r,spanc, spanr, totc,totr, glue_cnt, plus, extra;
293 int x,y;
294 int old_enabled = GDrawEnableExposeRequests(g->base,false);
295
296 GHVBoxGatherSizeInfo(gb,&si);
297 width -= 2*bp; height -= 2*bp;
298
299 if(width < si.minwidth) width = si.minwidth;
300 if(height < si.minheight) height = si.minheight;
301
302 gb->g.inner.x = gb->g.r.x + bp; gb->g.inner.y = gb->g.r.y + bp;
303 if ( gb->label!=NULL ) {
304 gb->label_height = si.label_height;
305 g->inner.y += si.label_height;
306 }
307
308 if ( si.width!=width ) {
309 int vcols=0;
310 for ( i=0; i<gb->cols-1; ++i )
311 if ( si.cols[i].sized>0 )
312 ++vcols;
313 int vcols1 = vcols;
314 if(si.cols[gb->cols-1].sized > 0)
315 ++ vcols1;
316 if ( width<si.width ) {
317 for ( i=0; i<gb->cols; ++i )
318 si.cols[i].sized = si.cols[i].min;
319 si.width = si.minwidth;
320 if ( width<si.width && gb->hpad>1 && vcols>0 ) {
321 int reduce_pad = (si.width-width)/vcols + 1;
322 if ( reduce_pad>gb->hpad-1 ) reduce_pad = gb->hpad-1;
323 for ( i=0; i<gb->cols-1; ++i )
324 if ( si.cols[i].sized > 0 )
325 si.cols[i].sized -= reduce_pad;
326 si.width -= vcols*reduce_pad;
327 }
328 }
329 if((width > si.width) && (gb->grow_col==gb_expandglue || gb->grow_col==gb_expandgluesame )) {
330 for ( i=glue_cnt=0; i<gb->cols; ++i )
331 if ( si.cols[i].allglue )
332 ++glue_cnt;
333 if ( glue_cnt!=0 ) {
334 plus = (width-si.width)/glue_cnt;
335 extra = (width-si.width-glue_cnt*plus);
336 for ( i=0; i<gb->cols; ++i ) if ( si.cols[i].allglue ) {
337 si.cols[i].sized += plus + (extra>0);
338 si.width += plus + (extra>0);
339 --extra;
340 }
341 }
342 }
343 if ((width != si.width) && gb->grow_col>=0 ) {
344 int * ss = &(si.cols[gb->grow_col].sized);
345 int w = si.width - *ss;
346 *ss += (width-si.width);
347 if(*ss < gb->hpad + 3)
348 *ss = gb->hpad + 3;
349 si.width = w + *ss;
350 }
351 if ((width > si.width) && (vcols1!=0)) {
352 plus = (width-si.width)/vcols1;
353 extra = (width-si.width-vcols1*plus);
354 for ( i=0; i<gb->cols; ++i ) {
355 if ( si.cols[i].sized>0 ) {
356 si.cols[i].sized += plus + (extra>0);
357 si.width += plus + (extra>0);
358 --extra;
359 }
360 }
361 }
362 width = si.width;
363 }
364
365 if ( si.height!=height ) {
366 int vrows=0;
367 for ( i=0; i<gb->rows-1; ++i )
368 if ( si.rows[i].sized>0 )
369 ++vrows;
370 int vrows1 = vrows;
371 if(si.rows[gb->rows-1].sized > 0)
372 ++ vrows1;
373 if ( height<si.height ) {
374 for ( i=0; i<gb->rows; ++i )
375 si.rows[i].sized = si.rows[i].min;
376 si.height = si.minheight;
377 if ( height<si.height && gb->vpad>1 && vrows>0 ) {
378 int reduce_pad = (si.height-height)/vrows + 1;
379 if ( reduce_pad>gb->vpad-1 ) reduce_pad = gb->vpad-1;
380 for ( i=0; i<gb->rows-1; ++i )
381 if ( si.rows[i].sized > 0 )
382 si.rows[i].sized -= reduce_pad;
383 si.height -= vrows*reduce_pad;
384 }
385 }
386 if((height > si.height) && (gb->grow_row==gb_expandglue || gb->grow_row==gb_expandgluesame )) {
387 for ( i=glue_cnt=0; i<gb->rows; ++i )
388 if ( si.rows[i].allglue )
389 ++glue_cnt;
390 if ( glue_cnt!=0 ){
391 plus = (height-si.height)/glue_cnt;
392 extra = (height-si.height-glue_cnt*plus);
393 for ( i=0; i<gb->rows; ++i ) if ( si.rows[i].allglue ) {
394 si.rows[i].sized += plus + (extra>0);
395 si.height += plus + (extra>0);
396 --extra;
397 }
398 }
399 }
400 if ((height != si.height) && gb->grow_row>=0 ) {
401 int * ss = &(si.rows[gb->grow_row].sized);
402 int h = si.height - *ss;
403 *ss += (height-si.height);
404 if(*ss < gb->vpad + 3)
405 *ss = gb->vpad + 3;
406 si.height = h + *ss;
407 }
408 if ((height > si.height) && (vrows1!=0)) {
409 plus = (height-si.height)/vrows1;
410 extra = (height-si.height-vrows1*plus);
411 for ( i=0; i<gb->rows; ++i ) {
412 if ( si.rows[i].sized>0 ) {
413 si.rows[i].sized += plus + (extra>0);
414 si.height += plus + (extra>0);
415 --extra;
416 }
417 }
418 }
419 height = si.height;
420 }
421
422 y = gb->g.inner.y;
423 if ( gb->label!=NULL ) {
424 if ( gb->label->state!=gs_invisible )
425 GGadgetResize( gb->label, si.label_width, si.label_height);
426 GGadgetMove( gb->label, gb->g.inner.x+10, y-si.label_height-bp/2);
427 }
428 for ( r=0; r<gb->rows; ++r ) {
429 x = gb->g.inner.x;
430 for ( c=0; c<gb->cols; ++c ) {
431 GGadget *g = gb->children[r*gb->cols+c];
432 if ( g==GG_Glue || g==GG_ColSpan || g==GG_RowSpan || g==GG_HPad10 )
433 /* Skip it */;
434 else {
435 int xes, yes, es;
436 totr = si.rows[r].sized;
437 for ( spanr=1; r+spanr<gb->rows &&
438 gb->children[(r+spanr)*gb->cols+c]==GG_RowSpan; ++spanr )
439 totr += si.rows[r+spanr].sized;
440 totc = si.cols[c].sized;
441 for ( spanc=1; c+spanc<gb->cols &&
442 gb->children[r*gb->cols+c+spanc]==GG_ColSpan; ++spanc )
443 totc += si.cols[c+spanc].sized;
444 if ( r+spanr!=gb->rows ) totr -= gb->vpad;
445 if ( c+spanc!=gb->cols ) totc -= gb->hpad;
446 es = GBoxExtraSpace(g);
447 xes = si.cols[c].extra_space - es;
448 yes = si.rows[r].extra_space - es;
449 if ( g->state!=gs_invisible )
450 GGadgetResize(g,totc-2*xes,totr-2*yes);
451 GGadgetMove(g,x+xes,y+yes);
452 }
453 x += si.cols[c].sized;
454 }
455 y += si.rows[r].sized;
456 }
457
458 free(si.cols); free(si.rows);
459
460 gb->g.inner.width = width; gb->g.inner.height = height;
461 gb->g.r.width = width + 2*bp; gb->g.r.height = height + 2*bp;
462 GDrawEnableExposeRequests(g->base,old_enabled);
463 GDrawRequestExpose(g->base,&g->r,false);
464 }
465
GHVBoxGetDesiredSize(GGadget * g,GRect * outer,GRect * inner)466 static void GHVBoxGetDesiredSize(GGadget *g, GRect *outer, GRect *inner) {
467 struct sizeinfo si;
468 GHVBox *gb = (GHVBox *) g;
469 int bp = GBoxBorderWidth(g->base,g->box);
470
471 GHVBoxGatherSizeInfo(gb,&si);
472 if ( g->desired_width>0 ) si.width = g->desired_width;
473 if ( g->desired_height>0 ) si.height = g->desired_height;
474
475 if ( inner!=NULL ) {
476 inner->x = inner->y = 0;
477 inner->width = si.width; inner->height = si.height;
478 }
479 if ( outer!=NULL ) {
480 outer->x = outer->y = 0;
481 outer->width = si.width+2*bp; outer->height = si.height+2*bp;
482 }
483 free(si.cols); free(si.rows);
484 }
485
GHVBoxFillsWindow(GGadget * g)486 static int GHVBoxFillsWindow(GGadget *g) {
487 return( true );
488 }
489
expose_nothing(GWindow pixmap,GGadget * g,GEvent * event)490 static int expose_nothing(GWindow pixmap, GGadget *g, GEvent *event) {
491 GHVBox *gb = (GHVBox *) g;
492 GRect r;
493
494 if ( g->state==gs_invisible )
495 return( true );
496
497 if ( gb->label==NULL )
498 GBoxDrawBorder(pixmap,&g->r,g->box,g->state,false);
499 else {
500 r = g->r;
501 r.y += gb->label_height/2;
502 r.height -= gb->label_height/2;
503 GBoxDrawBorder(pixmap,&r,g->box,g->state,false);
504 /* Background is transperant */
505 (gb->label->funcs->handle_expose)(pixmap,gb->label,event);
506 }
507 return( true );
508 }
509
510 struct gfuncs ghvbox_funcs = {
511 0,
512 sizeof(struct gfuncs),
513
514 expose_nothing, /* Expose */
515 _ggadget_noop, /* Mouse */
516 _ggadget_noop, /* Key */
517 NULL,
518 NULL, /* Focus */
519 NULL,
520 NULL,
521
522 _ggadget_redraw,
523 GHVBoxMove,
524 GHVBoxResize,
525 _ggadget_setvisible,
526 _ggadget_setenabled,
527 _ggadget_getsize,
528 _ggadget_getinnersize,
529
530 GHVBox_destroy,
531
532 NULL,
533 NULL,
534 NULL,
535 NULL,
536 NULL,
537
538 NULL,
539 NULL,
540
541 NULL,
542 NULL,
543 NULL,
544 NULL,
545 NULL,
546 NULL,
547 NULL,
548 NULL,
549 NULL,
550 NULL,
551 NULL,
552
553 GHVBoxGetDesiredSize,
554 _ggadget_setDesiredSize,
555 GHVBoxFillsWindow,
556 NULL
557 };
558
GHVBoxSetExpandableCol(GGadget * g,int col)559 void GHVBoxSetExpandableCol(GGadget *g,int col) {
560 GHVBox *gb = (GHVBox *) g;
561 if ( col<gb->cols )
562 gb->grow_col = col;
563 }
564
GHVBoxSetExpandableRow(GGadget * g,int row)565 void GHVBoxSetExpandableRow(GGadget *g,int row) {
566 GHVBox *gb = (GHVBox *) g;
567 if ( row < gb->rows )
568 gb->grow_row = row;
569 }
570
GHVBoxSetPadding(GGadget * g,int hpad,int vpad)571 void GHVBoxSetPadding(GGadget *g,int hpad, int vpad) {
572 GHVBox *gb = (GHVBox *) g;
573 gb->hpad = hpad;
574 gb->vpad = vpad;
575 }
576
_GHVBoxCreate(struct gwindow * base,GGadgetData * gd,void * data,int hcnt,int vcnt,GBox * def_box)577 static GHVBox *_GHVBoxCreate(struct gwindow *base, GGadgetData *gd,void *data,
578 int hcnt, int vcnt, GBox *def_box) {
579 GHVBox *gb = calloc(1,sizeof(GHVBox));
580 int i, h, v;
581 GGadgetCreateData *label = (GGadgetCreateData *) (gd->label);
582
583 if ( !ghvbox_inited )
584 _GHVBox_Init();
585
586 gd->label = NULL;
587 gb->g.funcs = &ghvbox_funcs;
588 _GGadget_Create(&gb->g,base,gd,data,def_box);
589 gb->rows = vcnt; gb->cols = hcnt;
590 gb->grow_col = gb->grow_row = gb_expandall;
591 gb->hpad = gb->vpad = GDrawPointsToPixels(base,2);
592
593 gb->g.takes_input = false; gb->g.takes_keyboard = false; gb->g.focusable = false;
594
595 if ( label != NULL ) {
596 gb->label = label->ret =
597 (label->creator)(base,&label->gd,label->data);
598 gb->label->contained = true;
599 }
600
601 gb->children = malloc(vcnt*hcnt*sizeof(GGadget *));
602 for ( i=v=0; v<vcnt; ++v ) {
603 for ( h=0; h<hcnt && gd->u.boxelements[i]!=NULL; ++h, ++i ) {
604 GGadgetCreateData *gcd = gd->u.boxelements[i];
605 if ( gcd==GCD_Glue ||
606 gcd==GCD_ColSpan ||
607 gcd==GCD_RowSpan ||
608 gcd==GCD_HPad10 )
609 gb->children[v*hcnt+h] = (GGadget *) gcd;
610 else {
611 gcd->gd.pos.x = gcd->gd.pos.y = 1;
612 gb->children[v*hcnt+h] = gcd->ret =
613 (gcd->creator)(base,&gcd->gd,gcd->data);
614 gcd->ret->contained = true;
615 }
616 }
617 while ( h<hcnt )
618 gb->children[v*hcnt+h++] = GG_Glue;
619 if ( gd->u.boxelements[i]==NULL )
620 ++i;
621 }
622 return( gb );
623 }
624
GHBoxCreate(struct gwindow * base,GGadgetData * gd,void * data)625 GGadget *GHBoxCreate(struct gwindow *base, GGadgetData *gd,void *data) {
626 GHVBox *gb;
627 int hcnt;
628
629 for ( hcnt=0; gd->u.boxelements[hcnt]!=NULL; ++hcnt );
630 gb = _GHVBoxCreate(base,gd,data,hcnt,1,&hvbox_box);
631
632 return( &gb->g );
633 }
634
GVBoxCreate(struct gwindow * base,GGadgetData * gd,void * data)635 GGadget *GVBoxCreate(struct gwindow *base, GGadgetData *gd,void *data) {
636 GHVBox *gb;
637 int vcnt;
638
639 for ( vcnt=0; gd->u.boxelements[vcnt]!=NULL; ++vcnt );
640 gb = _GHVBoxCreate(base,gd,data,1,vcnt,&hvbox_box);
641
642 return( &gb->g );
643 }
644
GHVBoxCreate(struct gwindow * base,GGadgetData * gd,void * data)645 GGadget *GHVBoxCreate(struct gwindow *base, GGadgetData *gd,void *data) {
646 GHVBox *gb;
647 int hcnt, vcnt, i;
648
649 for ( hcnt=0; gd->u.boxelements[hcnt]!=NULL; ++hcnt );
650 for ( i=0, vcnt=1; gd->u.boxelements[i]!=NULL || gd->u.boxelements[i+1]!=NULL ; ++i )
651 if ( gd->u.boxelements[i]==NULL )
652 ++vcnt;
653 gb = _GHVBoxCreate(base,gd,data,hcnt,vcnt,&hvbox_box);
654
655 return( &gb->g );
656 }
657
GHVGroupCreate(struct gwindow * base,GGadgetData * gd,void * data)658 GGadget *GHVGroupCreate(struct gwindow *base, GGadgetData *gd,void *data) {
659 GHVBox *gb;
660 int hcnt, vcnt, i;
661
662 for ( hcnt=0; gd->u.boxelements[hcnt]!=NULL; ++hcnt );
663 for ( i=0, vcnt=1; gd->u.boxelements[i]!=NULL || gd->u.boxelements[i+1]!=NULL ; ++i )
664 if ( gd->u.boxelements[i]==NULL )
665 ++vcnt;
666 gb = _GHVBoxCreate(base,gd,data,hcnt,vcnt,&hvgroup_box);
667
668 return( &gb->g );
669 }
670
_GHVBoxFitWindow(GGadget * g,int center)671 static void _GHVBoxFitWindow(GGadget *g, int center) {
672 GRect outer, cur, screen;
673
674 if ( !GGadgetFillsWindow(g)) {
675 fprintf( stderr, "Call to GHVBoxFitWindow in something not an HVBox\n" );
676 return;
677 }
678 GHVBoxGetDesiredSize(g,&outer, NULL );
679 GDrawGetSize(GDrawGetRoot(NULL),&screen);
680 if ( outer.width > screen.width-20 ) outer.width = screen.width-20;
681 if ( outer.height > screen.height-40 ) outer.height = screen.height-40;
682 GDrawGetSize(g->base,&cur);
683 /* Make any offset simmetrical */
684 outer.width += 2*g->r.x;
685 outer.height += 2*g->r.y;
686 if ( cur.width!=outer.width || cur.height!=outer.height ) {
687 GDrawResize(g->base, outer.width, outer.height );
688 /* We want to get the resize before we set the window visible */
689 /* and window managers make synchronizing an issue... */
690 GDrawSync(GDrawGetDisplayOfWindow(g->base));
691 GDrawProcessPendingEvents(GDrawGetDisplayOfWindow(g->base));
692 GDrawSync(GDrawGetDisplayOfWindow(g->base));
693 GDrawProcessPendingEvents(GDrawGetDisplayOfWindow(g->base));
694 } else
695 GGadgetResize(g, outer.width-2*g->r.x, outer.height-2*g->r.y );
696 if ( center ) {
697 GDrawMove(g->base,(screen.width-outer.width)/2,(screen.height-outer.height)/2);
698 /* I don't think this one matters as much, but try a little */
699 GDrawSync(GDrawGetDisplayOfWindow(g->base));
700 GDrawProcessPendingEvents(GDrawGetDisplayOfWindow(g->base));
701 }
702 }
703
GHVBoxFitWindow(GGadget * g)704 void GHVBoxFitWindow(GGadget *g) {
705 _GHVBoxFitWindow(g,false);
706 }
707
GHVBoxFitWindowCentered(GGadget * g)708 void GHVBoxFitWindowCentered(GGadget *g) {
709 _GHVBoxFitWindow(g,true);
710 }
711
GHVBoxReflow(GGadget * g)712 void GHVBoxReflow(GGadget *g) {
713 GHVBoxResize(g, g->r.width, g->r.height);
714 }
715
_GHVBoxRIHead(void)716 GResInfo *_GHVBoxRIHead(void) {
717
718 _GHVBox_Init();
719 return( &ghvgroupbox_ri );
720 }
721