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