1 /*
2 * Copyright (c) 2000 Sasha Vasko <sasha at aftercode.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 */
19
20 /*#define LOCAL_DEBUG*/
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <string.h>
25
26 #include <unistd.h>
27
28 #include "astypes.h"
29 #include "audit.h"
30 #include "safemalloc.h"
31 #include "output.h"
32 #include "layout.h"
33
34
35 /* these are used to perform different size/position adjustments in order
36 * to avoid dynamic memory allocations :
37 */
38 static int as_layout_fixed_width[ASLAYOUT_MAX_SIZE], as_layout_fixed_height[ASLAYOUT_MAX_SIZE] ;
39 static int as_layout_width[ASLAYOUT_MAX_SIZE], as_layout_height[ASLAYOUT_MAX_SIZE] ;
40 static int as_layout_x[ASLAYOUT_MAX_SIZE], as_layout_y[ASLAYOUT_MAX_SIZE] ;
41
42
43 /**********************************************************************/
44 /* Creation/Destruction */
45 ASLayout *
create_aslayout(unsigned int dim_x,unsigned int dim_y)46 create_aslayout( unsigned int dim_x, unsigned int dim_y )
47 {
48 ASLayout *layout = NULL ;
49
50 if( dim_x && dim_y )
51 {
52 layout = safecalloc( 1, sizeof(ASLayout));
53 layout->dim_x = dim_x ;
54 layout->dim_y = dim_y ;
55 if( dim_x > 0 )
56 layout->cols = safecalloc( dim_x, sizeof(ASLayoutElem*));
57 if( dim_y > 0 )
58 layout->rows = safecalloc( dim_y, sizeof(ASLayoutElem*));
59 }
60 return layout;
61 }
62
63 static inline int
destroy_layout_row(ASLayoutElem ** prow)64 destroy_layout_row( ASLayoutElem **prow )
65 {
66 register ASLayoutElem *pelem = *prow;
67 int count = 0 ;
68 while( pelem )
69 {
70 register ASLayoutElem *tmp = pelem->right ;
71 free( pelem );
72 pelem = tmp ;
73 ++count;
74 }
75 *prow = NULL ;
76 return count;
77 }
78
79 void
destroy_aslayout(ASLayout ** playout)80 destroy_aslayout( ASLayout **playout )
81 {
82 if( playout )
83 {
84 register ASLayout *layout = *playout ;
85 if( layout )
86 {
87 register int i ;
88 for( i = 0 ; i < layout->dim_y ; i++ )
89 destroy_layout_row( &(layout->rows[i]));
90 destroy_layout_row( &(layout->disabled) );
91
92 if( layout->rows )
93 free( layout->rows );
94 if( layout->cols )
95 free( layout->cols );
96 layout->dim_x = layout->dim_y = 0 ;
97 free( layout );
98 *playout = NULL ;
99 }
100 }
101 }
102
103 /**********************************************************************/
104 /* addition/extraction of elements : */
105 void
insert_layout_elem(ASLayout * layout,ASLayoutElem * elem,unsigned int h_slot,unsigned int v_slot,unsigned int h_span,unsigned int v_span)106 insert_layout_elem( ASLayout *layout,
107 ASLayoutElem *elem,
108 unsigned int h_slot, unsigned int v_slot,
109 unsigned int h_span, unsigned int v_span )
110 {
111 if( layout )
112 {
113 ASLayoutElem **pelem, **pelem2 ;
114
115 if( h_slot >= ASLAYOUT_MAX_SIZE )
116 h_slot = ASLAYOUT_MAX_SIZE-1 ;
117 if( v_slot >= ASLAYOUT_MAX_SIZE )
118 v_slot = ASLAYOUT_MAX_SIZE-1 ;
119 if( h_span > ASLAYOUT_MAX_SIZE-h_slot )
120 h_span = ASLAYOUT_MAX_SIZE-h_slot ;
121 if( v_span > ASLAYOUT_MAX_SIZE-v_slot )
122 v_span = ASLAYOUT_MAX_SIZE-v_slot ;
123
124 if( layout->dim_x < h_slot+h_span )
125 {
126 layout->cols = realloc( layout->cols, (h_slot+h_span)*sizeof(ASLayoutElem*) );
127 memset( layout->cols+ layout->dim_x, 0x00, ((h_slot+h_span) - layout->dim_x) *sizeof( ASLayoutElem*) );
128 layout->dim_x = h_slot+h_span ;
129 }
130 if( layout->dim_y < v_slot+v_span )
131 {
132 layout->rows = realloc( layout->rows, (v_slot+v_span)*sizeof(ASLayoutElem*) );
133 memset( layout->rows+ layout->dim_y, 0x00, ((v_slot+v_span) - layout->dim_y) *sizeof( ASLayoutElem*) );
134 layout->dim_y = v_slot+v_span ;
135 }
136
137 for( pelem = &(layout->rows[v_slot]); *pelem ; pelem = &((*pelem)->right) )
138 if( (*pelem)->column >= h_slot )
139 break ;
140 for( pelem2 = &(layout->cols[h_slot]); *pelem2 ; pelem2 = &((*pelem2)->below) )
141 {
142 if( (*pelem2)->row >= v_slot )
143 break ;
144 }
145 if( *pelem && *pelem == *pelem2 )
146 {
147 elem->right = (*pelem)->right ;
148 elem->below = (*pelem)->below ;
149 (*pelem)->right = (*pelem)->below = NULL ;
150 free( *pelem );
151 }else
152 {
153 elem->right = *pelem ;
154 elem->below = *pelem2 ;
155 ++(layout->count);
156 }
157 *pelem = elem ;
158 *pelem2 = elem ;
159 elem->h_span = h_span ;
160 elem->v_span = v_span ;
161 elem->row = v_slot ;
162 elem->column = h_slot ;
163 }
164 }
165
166 ASLayoutElem *
gather_layout_elems(ASLayout * layout)167 gather_layout_elems( ASLayout *layout )
168 {
169 ASLayoutElem *head = NULL;
170 if( layout && layout->count > 0 )
171 {
172 register int i ;
173
174 head = layout->disabled ;
175 layout->disabled = NULL ;
176 for( i = 0 ; i < layout->dim_y ; ++i )
177 {
178 register ASLayoutElem *pelem = layout->rows[i] ;
179 if( pelem )
180 {
181 while( pelem->right )
182 {
183 pelem->below = NULL ;
184 pelem = pelem->right ;
185 }
186 pelem->below = NULL ;
187 pelem->right = head ;
188 head = layout->rows[i] ;
189 layout->rows[i] = NULL ;
190 }
191 }
192 for( i = 0 ; i < layout->dim_x ; i++ )
193 layout->cols[i] = NULL ;
194 layout->count = 0 ;
195 }
196 return head ;
197 }
198
199 void
flush_layout_elems(ASLayout * layout)200 flush_layout_elems( ASLayout *layout )
201 {
202 if( layout && layout->count > 0 )
203 {
204 register int i ;
205 for( i = 0 ; i < layout->dim_y ; i++ )
206 destroy_layout_row( &(layout->rows[i]));
207 destroy_layout_row( &(layout->disabled) );
208 layout->count = 0 ;
209 }
210 }
211
212 static ASLayoutElem **
get_layout_context_ptr(ASLayout * layout,int context)213 get_layout_context_ptr( ASLayout *layout, int context )
214 {
215 register ASLayoutElem **pelem = NULL ;
216 register int i ;
217 for( i = 0 ; i < layout->dim_y ; ++i )
218 for( pelem = &(layout->rows[i]) ; *pelem ; pelem = &((*pelem)->right) )
219 if( (*pelem)->context == context )
220 return pelem ;
221 return NULL;
222 }
223
224 ASLayoutElem *
extract_layout_context(ASLayout * layout,int context)225 extract_layout_context( ASLayout *layout, int context )
226 {
227 ASLayoutElem *elem = NULL;
228 if( layout && layout->count )
229 {
230 register ASLayoutElem **pelem = NULL ;
231 if((pelem = get_layout_context_ptr( layout, context )) != NULL )
232 {
233 elem = *pelem ;
234 *pelem = elem->right ;
235 for( pelem = &(layout->cols[elem->column]) ; *pelem ; pelem = &((*pelem)->below) )
236 if( *pelem == elem )
237 {
238 *pelem = elem->below;
239 break;
240 }
241 --(layout->count) ;
242 }
243 }
244 return elem ;
245 }
246
247 ASLayoutElem *
find_layout_context(ASLayout * layout,int context)248 find_layout_context( ASLayout *layout, int context )
249 {
250 if( layout && layout->count )
251 {
252 register ASLayoutElem **pelem = NULL ;
253 if((pelem = get_layout_context_ptr( layout, context )) != NULL )
254 return *pelem ;
255 }
256 return NULL ;
257 }
258 /**********************************************************************/
259 /* enable/disable element */
260 void
disable_layout_elem(ASLayout * layout,ASLayoutElem ** pelem)261 disable_layout_elem( ASLayout *layout, ASLayoutElem **pelem )
262 {
263 if( layout && pelem && *pelem )
264 {
265 ASLayoutElem *elem = *pelem ;
266
267 /* step one - taking out of horisontal circulation : */
268 *pelem = elem->right ;
269 /* step two - taking out of vertical circulation :) */
270 for( pelem = &(layout->cols[elem->column]) ; *pelem ; pelem = &((*pelem)->below) )
271 if( *pelem == elem )
272 break;
273 if( *pelem )
274 *pelem = elem->below ;
275 elem->below = NULL;
276 /* step three - stashing away for later reuse :*/
277 elem->right = layout->disabled ;
278 layout->disabled = elem ;
279 --(layout->count);
280 }
281 }
282
283 void
enable_layout_elem(ASLayout * layout,ASLayoutElem ** pelem)284 enable_layout_elem( ASLayout *layout, ASLayoutElem **pelem )
285 {
286 if( layout && pelem && *pelem )
287 {
288 ASLayoutElem *elem = *pelem ;
289
290 /* step one - taking out of disabled list : */
291 *pelem = elem->right ;
292 /* step two - reinserting us into The MATRIX !!!! BWUHAHAHA */
293 elem->right = NULL ;
294 if( elem->column+elem->h_span <= layout->dim_x &&
295 elem->row+elem->v_span <= layout->dim_y)
296 insert_layout_elem( layout, elem, elem->column, elem->row, elem->h_span, elem->v_span );
297 else
298 free( elem );
299 }
300 }
301
302 int
disable_layout_context(ASLayout * layout,int context,Bool batch)303 disable_layout_context( ASLayout *layout, int context, Bool batch )
304 {
305 int found = 0 ;
306 if( layout )
307 {
308 register ASLayoutElem **pelem = NULL ;
309 register int i ;
310 for( i = 0 ; i < layout->dim_y ; i++ )
311 for( pelem = &(layout->rows[i]) ; *pelem ; pelem = &((*pelem)->right) )
312 {
313 if( (*pelem)->context == context )
314 {
315 disable_layout_elem( layout, pelem );
316 found++;
317 }
318 }
319 }
320 if( found > 0 && !batch )
321 {
322 /*
323 mylayout_moveresize( widget->layout, widget->width, widget->height, True );
324 mywidget_update_fixed_size( widget, False );
325 */
326 }
327 return found ;
328 }
329
330 int
enable_layout_context(ASLayout * layout,int context,Bool batch)331 enable_layout_context( ASLayout *layout, int context, Bool batch )
332 {
333 int found = 0 ;
334 if( layout )
335 {
336 register ASLayoutElem **pelem = NULL ;
337 for( pelem = &(layout->disabled) ; *pelem ; pelem = &((*pelem)->right) )
338 if( (*pelem)->context == context )
339 {
340 enable_layout_elem( layout, pelem );
341 found++;
342 }
343 }
344 if( found > 0 && !batch )
345 {
346 /* mylayout_moveresize( widget->layout, widget->width, widget->height, True );
347 mywidget_update_fixed_size( widget, False );
348 */
349 }
350 return found ;
351 }
352
353
354 /**********************************************************************/
355 /* spacing and side offset management */
356 Bool
set_layout_spacing(ASLayout * layout,unsigned int h_border,unsigned int v_border,unsigned int h_spacing,unsigned int v_spacing)357 set_layout_spacing( ASLayout *layout, unsigned int h_border, unsigned int v_border, unsigned int h_spacing, unsigned int v_spacing )
358 {
359 Bool changed = False ;
360 if( layout )
361 {
362 changed = ( layout->h_border != h_border ||
363 layout->v_border != v_border ||
364 layout->h_spacing != h_spacing ||
365 layout->v_spacing != v_spacing );
366 if( changed )
367 {
368 layout->h_border = h_border ;
369 layout->v_border = v_border ;
370 layout->h_spacing = h_spacing ;
371 layout->v_spacing = v_spacing ;
372 }
373 }
374 return changed;
375 }
376
377 Bool
set_layout_offsets(ASLayout * layout,int east,int north,int west,int south)378 set_layout_offsets( ASLayout *layout, int east, int north, int west, int south )
379 {
380 Bool changed = False ;
381 if( layout )
382 {
383 changed = ( layout->offset_east != east ||
384 layout->offset_north != north ||
385 layout->offset_west != west ||
386 layout->offset_south != south );
387 if( changed )
388 {
389 layout->offset_east = east ;
390 layout->offset_north = north ;
391 layout->offset_west = west ;
392 layout->offset_south = south ;
393 }
394 }
395 return changed;
396 }
397
398 /**********************************************************************/
399 /* fixed size handling : */
400 static unsigned int
get_layout_fixed_width(ASLayout * layout,unsigned int start_col,unsigned int end_col)401 get_layout_fixed_width( ASLayout *layout, unsigned int start_col, unsigned int end_col )
402 {
403 register int i ;
404 unsigned int width = 0 ;
405
406 for( i = start_col ; i < end_col ; ++i )
407 {
408 register ASLayoutElem *pelem = layout->cols[i];
409 register int fw = 0 ;
410 while ( pelem )
411 {
412 if( get_flags( pelem->flags, LF_FixedWidth ) )
413 {
414 LOCAL_DEBUG_OUT( " layout %lX found item with fixed width %d at %dx%d",
415 (unsigned long)layout, pelem->fixed_width, pelem->row, pelem->column );
416 if( pelem->fixed_width+pelem->bw > fw )
417 fw = pelem->fixed_width+pelem->bw ;
418 }
419 pelem = pelem->below ;
420 }
421 if( fw > 0 )
422 width += fw+layout->v_spacing ;
423 }
424 if( width > 0 )
425 width -= (int)layout->v_spacing ;
426 return width ;
427 }
428
429 static unsigned int
get_layout_fixed_height(ASLayout * layout,unsigned int start_row,unsigned int end_row)430 get_layout_fixed_height( ASLayout *layout, unsigned int start_row, unsigned int end_row )
431 {
432 register int i ;
433 unsigned int height = 0 ;
434
435 for( i = start_row ; i < end_row ; i++ )
436 {
437 register ASLayoutElem *pelem = layout->rows[i];
438 register int fh = 0 ;
439 while ( pelem )
440 {
441 if( get_flags( pelem->flags, LF_FixedHeight ) )
442 {
443 LOCAL_DEBUG_OUT( " layout %lX found item with fixed height %d at %dx%d", (unsigned long)layout, pelem->fixed_height, pelem->row, pelem->column );
444 if( pelem->fixed_height+pelem->bw > fh )
445 fh = pelem->fixed_height+pelem->bw ;
446 }
447 pelem = pelem->right ;
448 }
449 if( fh > 0 )
450 height += fh+layout->h_spacing ;
451 }
452 if( height >0 )
453 height -= layout->h_spacing ;
454 return height;
455 }
456
457 void
get_layout_fixed_size(ASLayout * layout,CARD32 * fixed_width,CARD32 * fixed_height)458 get_layout_fixed_size( ASLayout *layout, CARD32 *fixed_width, CARD32 *fixed_height )
459 {
460 int width = 0, height = 0;
461 if( layout && layout->count > 0 )
462 {
463 if( fixed_width )
464 {
465 width = get_layout_fixed_width( layout, 0, layout->dim_x );
466 if( width > 0 )
467 width += layout->v_border + layout->v_border + layout->offset_east + layout->offset_west ;
468 }
469 if( fixed_height )
470 {
471 height = get_layout_fixed_height( layout, 0, layout->dim_y );
472 if( height >0 )
473 height += layout->h_border+ layout->h_border + layout->offset_north+ layout->offset_south ;
474 }
475 }
476 LOCAL_DEBUG_OUT( " layout %lX FIXED WIDTH is %d FIXED HEIGHT is %d", (unsigned long)layout, width, height );
477 if( fixed_width )
478 *fixed_width = width < 0 ? 0 : width ;
479 if( fixed_height )
480 *fixed_height = height < 0 ? 0 : height ;
481 }
482
483 Bool
get_layout_context_fixed_frame(ASLayout * layout,int context,int * north,int * east,int * south,int * west)484 get_layout_context_fixed_frame( ASLayout *layout, int context, int *north, int *east, int *south, int *west )
485 {
486 int size ;
487 if( layout && layout->count > 0 )
488 {
489 ASLayoutElem **pelem = get_layout_context_ptr( layout, context );
490 if( pelem != NULL )
491 {
492 register ASLayoutElem *elem = *pelem ;
493
494 if( north )
495 {
496 size = 0 ;
497 if( elem->row > 0 )
498 {
499 size = get_layout_fixed_height( layout, 0, elem->row );
500 if( size > 0 )
501 size += layout->v_spacing ;
502 }
503 *north = size+layout->h_border;
504 }
505 if( east )
506 {
507 size = 0 ;
508 if( elem->column+elem->h_span < layout->dim_x )
509 {
510 size = get_layout_fixed_width( layout, elem->column+elem->h_span, layout->dim_x );
511 if( size > 0 )
512 size += layout->h_spacing ;
513 }
514 *east = size+layout->v_border;
515 }
516 if( south )
517 {
518 size = 0 ;
519 if( elem->row+elem->v_span < layout->dim_y )
520 {
521 size = get_layout_fixed_height( layout, elem->row+elem->v_span, layout->dim_y );
522 if( size > 0 )
523 size += layout->v_spacing ;
524 }
525 *south = size+layout->h_border;
526 }
527 if( west )
528 {
529 size = 0 ;
530 if( elem->column > 0 )
531 {
532 size = get_layout_fixed_width( layout, 0, elem->column );
533 if( size > 0 )
534 size += layout->v_spacing ;
535 }
536 *west = size+layout->v_border;
537 }
538 return True;
539 }
540 }
541 return False;
542 }
543
544 ASFlagType
set_layout_context_fixed_size(ASLayout * layout,int context,unsigned int width,unsigned int height,unsigned short flags)545 set_layout_context_fixed_size( ASLayout *layout, int context, unsigned int width, unsigned int height, unsigned short flags )
546 {
547 if( layout && layout->count > 0 )
548 {
549 ASLayoutElem **pelem = get_layout_context_ptr( layout, context );
550 LOCAL_DEBUG_OUT( "setting fixedsize of context %d(%p) to %dx%d", context, pelem?*pelem:NULL, width, height );
551 if( pelem != NULL )
552 {
553 register ASLayoutElem *elem = *pelem ;
554 if( get_flags( flags, LF_FixedWidth ) )
555 elem->fixed_width = width ;
556 if( get_flags( flags, LF_FixedHeight ) )
557 elem->fixed_height = height ;
558 return elem->flags&LF_FixedSize&flags;
559 }
560 }
561 return 0;
562 }
563
564 Bool
get_layout_context_size(ASLayout * layout,int context,int * x,int * y,unsigned int * width,unsigned int * height)565 get_layout_context_size( ASLayout *layout, int context, int *x, int *y, unsigned int *width, unsigned int *height )
566 {
567 if( layout && layout->count > 0 )
568 {
569 ASLayoutElem **pelem = get_layout_context_ptr( layout, context );
570 if( pelem != NULL )
571 {
572 register ASLayoutElem *elem = *pelem ;
573 if( x )
574 *x = elem->x ;
575 if( y )
576 *y = elem->y ;
577 if( width )
578 *width = elem->width ;
579 if( height )
580 *height = elem->height ;
581 return True;
582 }
583 }
584 return False;
585 }
586
587 ASLayoutElem *
find_layout_point(ASLayout * layout,int x,int y,ASLayoutElem * start)588 find_layout_point( ASLayout *layout, int x, int y, ASLayoutElem *start )
589 {
590 if( layout && layout->count > 0 )
591 {
592 register int col = start? start->column : 0 ;
593
594 x -= layout->x ;
595 y -= layout->y ;
596
597 for( ; col < layout->dim_x ; ++col )
598 {
599 register ASLayoutElem *pelem = layout->cols[col] ;
600 if( start && start->column == col )
601 pelem = start->below ;
602 if( pelem )
603 {
604 if( pelem->x > x )
605 return NULL;
606 for( ; pelem != NULL ; pelem = pelem->below )
607 {
608 if( pelem->y > y )
609 break;
610 if( pelem->x+pelem->width > x && pelem->y+pelem->height > y )
611 return pelem;
612 }
613 }
614 }
615 }
616 return NULL ;
617 }
618 /****************************************************************************************
619 * The following are dynamic methods and return value that indicates if any of the cached
620 * pixmaps has to be rebuild
621 ****************************************************************************************/
622 static int
collect_sizes(ASLayout * layout,int * layout_size,int * layout_fixed_size,Bool h_direction)623 collect_sizes( ASLayout *layout, int *layout_size, int *layout_fixed_size, Bool h_direction )
624 {
625 int dim ;
626 ASLayoutElem **chains ;
627 register int i ;
628 int spacing_needed = 0 ;
629 int max_span;
630 ASFlagType fixed_flag ;
631 unsigned int spacing ;
632
633 if( h_direction )
634 {
635 dim = layout->dim_x ;
636 chains = layout->cols ;
637 fixed_flag = LF_FixedWidth ;
638 spacing = layout->h_spacing ;
639 }else
640 {
641 dim = layout->dim_y ;
642 chains = layout->rows ;
643 fixed_flag = LF_FixedHeight ;
644 spacing = layout->v_spacing ;
645 }
646
647 /* PASS 1 : we mark all the dead columns with fixed width -1 */
648 for( i = 0 ; i < dim ; ++i )
649 layout_fixed_size[i] = chains[i]?0:-1 ;
650 /* PASS 2 : we calculate fixed size for columns tarting with elements that has span on 1
651 * and increasing it untill it reaches up to DIM : */
652 for( max_span = 1; max_span <= dim ; max_span++ )
653 {
654 for( i = dim-max_span ; i >= 0 ; --i )
655 {
656 register ASLayoutElem *pelem = chains[i];
657 while( pelem )
658 {
659 unsigned int span ;
660 int fixed_size ;
661 ASLayoutElem *pnext ;
662
663 if( h_direction )
664 {
665 span = pelem->h_span;
666 pnext = pelem->below;
667 fixed_size = get_flags( pelem->flags, LF_FixedWidth )?pelem->fixed_width+(pelem->bw<<1)+spacing:0 ;
668 }else
669 {
670 span = pelem->v_span;
671 pnext = pelem->right;
672 fixed_size = get_flags( pelem->flags, LF_FixedHeight )?pelem->fixed_height+(pelem->bw<<1)+spacing:0 ;
673 }
674
675 if( span == max_span && fixed_size > 0 )
676 {
677 register int k ;
678 for( k = i + span - 1 ; k > i ; --k )/* working around span: width = width - spanned_width */
679 if( layout_fixed_size[k] > 0 )
680 fixed_size -= layout_fixed_size[k]+spacing;
681 if( fixed_size > 0 )
682 {
683 if( layout_fixed_size[i] == 0 )
684 layout_fixed_size[i] = fixed_size ;
685 else if( fixed_size > layout_fixed_size[i] )
686 {
687 int limit = i+span ;
688 for( k = i+1 ; k < limit ; ++k )
689 if( layout_fixed_size[k] == 0 )
690 {
691 layout_fixed_size[k] = layout_fixed_size[i]-(fixed_size+spacing) ;
692 fixed_size = layout_fixed_size[i] ;
693 }
694 if( fixed_size > layout_fixed_size[i] )
695 layout_fixed_size[i] = fixed_size ;
696 }
697 }
698 }
699 pelem = pnext ;
700 }
701 }
702 }
703 /* PASS 3 : we collect all the existing sizes */
704 if( layout_size != NULL )
705 {
706 for( i = dim-1 ; i >=0 ; --i )
707 {
708 register ASLayoutElem *pelem = chains[i];
709 layout_size[i] = 0 ;
710 while( pelem )
711 {
712 unsigned int span ;
713 int size ;
714 ASLayoutElem *pnext ;
715 if( h_direction )
716 {
717 span = pelem->h_span;
718 size = pelem->width ;
719 pnext = pelem->below;
720 }else
721 {
722 span = pelem->v_span;
723 size = pelem->height ;
724 pnext = pelem->right;
725 }
726 size += (pelem->bw<<1) ;
727 if( size > 0 )
728 {
729 register int k ;
730 for( k = i + span - 1 ; k > i ; --k )/* working around span: width = width - spanned_width */
731 if( layout_fixed_size[k] > 0 )
732 size -= layout_size[k]+spacing;
733 if( layout_size[i] < size ) /* this really should be the same in all rows */
734 layout_size[i] = size ;
735 }
736 pelem = pnext ;
737 }
738 }
739 }
740 /* PASS 4 : we mark all the columns that has fixed size 0 yet are overlapped
741 * by any fixed item as hidden (-1) */
742 for( i = dim-1 ; i >= 0 ; --i )
743 {
744 register ASLayoutElem *pelem = chains[i];
745 while( pelem )
746 {
747 unsigned int span ;
748 ASLayoutElem *pnext ;
749 if( h_direction )
750 {
751 span = pelem->h_span;
752 pnext = pelem->below;
753 }else
754 {
755 span = pelem->v_span;
756 pnext = pelem->right;
757 }
758 if( get_flags( pelem->flags, fixed_flag ) )
759 {
760 register int k ;
761 for( k = i + span - 1 ; k >= i ; --k )/* working around span: width = width - spanned_width */
762 if( layout_fixed_size[k] == 0 )
763 layout_fixed_size[k] = -1 ;
764 }
765 pelem = pnext ;
766 }
767 }
768 /* PASS 5 : we collect interelement spacing used */
769 for( i = dim-1 ; i > 0 ; --i )
770 if( layout_fixed_size[i] >= 0 )
771 spacing_needed += spacing ;
772
773 return spacing_needed;
774 }
775
776 static void
adjust_sizes(unsigned int old_total,unsigned int new_total,unsigned int dim,int * sizes,int * fixed_items)777 adjust_sizes( unsigned int old_total, unsigned int new_total, unsigned int dim, int *sizes, int *fixed_items )
778 {
779 register int i;
780 int available = new_total ;
781 int empty_count = 0, non_fixed_count = 0 ;
782 int new_size, old_size ;
783
784 /* first allocating space for fixed items */
785 for( i = 0 ; i < dim ; i++ )
786 {
787 if( fixed_items[i] < 0 )
788 sizes[i] = 0 ;
789 else if( fixed_items[i] > 0 )
790 {
791 if( available <= 0 )
792 sizes[i] = 0 ;
793 else
794 {
795 sizes[i] = MIN( available, fixed_items[i]);
796 available -= sizes[i] ;
797 }
798 }
799 }
800 /* then allocating space for non-fixed items */
801 for( i = 0 ; i < dim ; i++ )
802 if( fixed_items[i] == 0 )
803 {
804 non_fixed_count++;
805 if( (old_size = sizes[i]) == 0 )
806 empty_count++ ;
807 else if( available <= 0 || old_total == 0 )
808 {
809 sizes[i] = 0 ;
810 }else
811 {
812 new_size = (old_size*new_total)/old_total ; /* trying to keep the ratio */
813 sizes[i] = MIN( new_size, available );
814 }
815 available -= sizes[i] ;
816 }
817 if( available > 0 && empty_count > 0) /* we have to spread available space among empty non-fixed columns */
818 {
819 new_size = available/empty_count ;
820 if( new_size <= 0 )
821 new_size = 1 ;
822
823 for( i = 0 ; i < dim && empty_count ; i++ )
824 if( sizes[i] == 0 && fixed_items[i] == 0 )
825 {
826 sizes[i] = new_size ;
827 empty_count-- ;
828 if( (available -= new_size ) <= 0 )
829 break;
830 }
831 }
832 if( available > 0 && non_fixed_count > 0 ) /* we have to spread available space among any non-fixed column */
833 {
834 new_size = available/non_fixed_count ;
835 if( new_size <= 0 )
836 new_size = 1 ;
837
838 for( i = 0 ; i < dim && non_fixed_count > 0 ; i++ )
839 if( fixed_items[i] == 0 )
840 {
841 if( non_fixed_count == 1 )
842 sizes[i] += available ;
843 else
844 sizes[i] += new_size ;
845 available -= new_size ;
846 non_fixed_count-- ;
847 }
848 }
849 }
850
851 static void
apply_sizes(int spacing,int start_margin,int dim,int * layout_size,int * layout_fixed_size,int * layout_pos)852 apply_sizes( int spacing, int start_margin, int dim, int *layout_size, int *layout_fixed_size, int *layout_pos )
853 {
854 register int i ;
855
856 layout_pos[0] = start_margin ;
857 for( i = 1 ; i < dim ; i++ )
858 {
859 layout_pos[i] = layout_pos[i-1]+layout_size[i-1];
860 if( layout_size[i] > 0 && layout_pos[i] > start_margin )
861 {
862 layout_pos[i] += spacing;
863 layout_size[i] -= spacing;
864 }
865 }
866 }
867
868 Bool
moveresize_layout(ASLayout * layout,unsigned int width,unsigned int height,Bool force)869 moveresize_layout( ASLayout *layout, unsigned int width, unsigned int height, Bool force )
870 {
871 register int i ;
872 int spacing_needed = 0 ;
873
874 if( layout == NULL )
875 return False;
876
877 width -= layout->offset_east+layout->offset_west+(layout->v_border<<1) ;
878 height -= layout->offset_north+layout->offset_south+(layout->h_border<<1) ;
879
880 if( width == layout->width && height == layout->height && !force )
881 return False;
882 /* first working on width/x position */
883 spacing_needed = collect_sizes( layout, &(as_layout_width[0]), &(as_layout_fixed_width[0]), True );
884 adjust_sizes( layout->width, width, layout->dim_x, &(as_layout_width[0]), &(as_layout_fixed_width[0]) );
885 apply_sizes(layout->h_spacing, layout->offset_west+layout->v_border, layout->dim_x, &(as_layout_width[0]), &(as_layout_fixed_width[0]), &(as_layout_x[0]) );
886
887 #ifdef LOCAL_DEBUG
888 fprintf( stderr, "\n" );
889 for( i = 0 ; i < layout->dim_x ; ++i )
890 fprintf( stderr, "\t%d", as_layout_fixed_width[i]);
891 fprintf( stderr, "\n" );
892 for( i = 0 ; i < layout->dim_x ; ++i )
893 fprintf( stderr, "\t%d", as_layout_width[i]);
894 fprintf( stderr, "\n" );
895 for( i = 0 ; i < layout->dim_x ; ++i )
896 fprintf( stderr, "\t%d", as_layout_x[i] );
897 fprintf( stderr, "\n" );
898 #endif
899 /* then working on height/y position */
900 spacing_needed = collect_sizes( layout, &(as_layout_height[0]), &(as_layout_fixed_height[0]), False );
901 adjust_sizes( layout->height, height, layout->dim_y, &(as_layout_height[0]), &(as_layout_fixed_height[0]) );
902 apply_sizes(layout->v_spacing, layout->offset_north+layout->h_border, layout->dim_y, &(as_layout_height[0]), &(as_layout_fixed_height[0]), &(as_layout_y[0]) );
903 #ifdef LOCAL_DEBUG
904 fprintf( stderr, "\nHeights adjustmmnt : height=%d/%d, spacing = %d, border %d, offset = %d\n", layout->height, height, layout->v_spacing, layout->h_border, layout->offset_north );
905 for( i = 0 ; i < layout->dim_y ; ++i )
906 fprintf( stderr, "\t%d", as_layout_fixed_height[i]);
907 fprintf( stderr, "\n" );
908 for( i = 0 ; i < layout->dim_y ; ++i )
909 fprintf( stderr, "\t%d", as_layout_height[i]);
910 fprintf( stderr, "\n" );
911 for( i = 0 ; i < layout->dim_y ; ++i )
912 fprintf( stderr, "\t%d", as_layout_y[i] );
913 fprintf( stderr, "\n" );
914 #endif
915
916 /* now we can actually apply our calculations : */
917 /* becouse of the static arrays we cann not recurse while we need
918 * info in those arrays. So on the first pass we set all the x/y/w/h
919 * of our elements, and on the second pass - we resize subwidgets
920 */
921 /* Pass 1: */
922 for( i = 0 ; i < layout->dim_y ; i++ )
923 if( layout->rows[i] )
924 {
925 register ASLayoutElem *pelem = layout->rows[i];
926 int elem_y = as_layout_y[i] ;
927
928 do
929 {
930 register int k ;
931 unsigned int w = as_layout_width[pelem->column] ;
932 unsigned int h = as_layout_height[i] ;
933 int elem_x = as_layout_x[pelem->column] ;
934
935 k = pelem->column+pelem->h_span-1 ;
936 w = (as_layout_x[k]+as_layout_width [k]) - elem_x;
937
938 k = pelem->row+pelem->v_span-1;
939 h = (as_layout_y[k]+as_layout_height[k]) - elem_y;
940
941 LOCAL_DEBUG_OUT( "resizing context %d at [%d+%d:%d+%d] to %dx%d%+d%+d (fixed = %dx%d)", pelem->context, pelem->column, pelem->h_span, pelem->row, pelem->v_span, w, h, elem_x, elem_y, pelem->fixed_width, pelem->fixed_height );
942 pelem->x = elem_x;
943 pelem->y = elem_y;
944 pelem->width = w - (pelem->bw<<1);
945 pelem->height = h - (pelem->bw<<1);
946 }while( (pelem = pelem->right) != NULL );
947 }
948
949 layout->width = width;
950 layout->height = height;
951 return True;
952 }
953
954 /***********************************************************************/
955 /* Grid stuff : */
956 /***********************************************************************/
957
958 ASGridLine *
add_gridline(ASGridLine ** list,short band,short start,short end,short gravity_above,short gravity_below)959 add_gridline( ASGridLine **list, short band, short start, short end,
960 short gravity_above, short gravity_below )
961 {
962 ASGridLine *l;
963
964 if( AS_ASSERT(list) )
965 return NULL;
966
967 for( l = *list ; l != NULL ; l = l->next )
968 {/* eliminating duplicates and sorting in ascending order : */
969 if( l->band <= band )
970 list = &(l->next);
971 if( l->band == band )
972 {
973 if( l->start < end && l->end > start )
974 { /* at least intersecting : */
975 if( l->gravity_above == gravity_above &&
976 l->gravity_below == gravity_below )
977 {
978 l->start = MIN( l->start, start );
979 l->end = MAX( l->end, end );
980 return NULL;
981 }
982 if( l->start == start && l->end == end )
983 {
984 l->gravity_above = ( l->gravity_above < 0 )?
985 MIN(l->gravity_above, gravity_above):
986 ((gravity_above < 0 )? gravity_above:
987 MAX(l->gravity_above, gravity_above));
988 l->gravity_below = ( l->gravity_below < 0 )?
989 MIN(l->gravity_below, gravity_below):
990 ((gravity_below < 0 )? gravity_below:
991 MAX(l->gravity_below, gravity_below));
992 return NULL;
993 }
994 }
995 }else if( l->band > band )
996 break;
997 }
998
999 l = safecalloc( 1, sizeof(ASGridLine));
1000 l->band = band ;
1001 l->start = start ;
1002 l->end = end ;
1003 l->gravity_above = gravity_above;
1004 l->gravity_below = gravity_below;
1005
1006 l->next = *list ;
1007 *list = l ;
1008 return l;
1009 }
1010
1011
make_layout_grid(ASLayout * layout,ASGrid * grid,int origin_x,int origin_y,short gravity)1012 void make_layout_grid( ASLayout *layout, ASGrid *grid,
1013 int origin_x, int origin_y,
1014 short gravity )
1015 {
1016 int i ;
1017
1018 if( layout == NULL || grid == NULL )
1019 return ;
1020 /* horizontal lines : */
1021 for( i = 0 ; i < layout->dim_y ; i++ )
1022 {
1023 register ASLayoutElem *pelem = layout->rows[i];
1024 int y = (pelem?pelem->y:0) + layout->offset_north ;
1025 LOCAL_DEBUG_OUT( "y = %d, lheight = %d", y, layout->height );
1026 if( pelem && y >= 0 && y < layout->height )
1027 {
1028 int start = 0, end = 0;
1029 do
1030 {
1031 int x = pelem->x + layout->offset_west ;
1032 LOCAL_DEBUG_OUT( "start = %d, end = %d, x = %d, width = %d, lwidth = %d", start, end, x, pelem->width, layout->width );
1033 if( x+pelem->width > 0 && pelem->x < layout->width )
1034 {
1035 if( x > end + layout->v_spacing + 1 )
1036 {
1037 if( end > start )
1038 add_gridline( &(grid->h_lines), y+origin_y, start+origin_x, end+origin_x, gravity, gravity );
1039 end = start = x ;
1040 }else if( x > start && start == end )
1041 {
1042 start = end = x ;
1043 }
1044 if( end < x+pelem->width )
1045 end = x+pelem->width ;
1046 }
1047 }while( (pelem = pelem->right) != NULL );
1048 if( end > start )
1049 add_gridline( &(grid->h_lines), y+origin_y, start+origin_x, end+origin_x, gravity, gravity );
1050 }
1051 }
1052 /* vertical lines : */
1053 for( i = 0 ; i < layout->dim_x ; i++ )
1054 {
1055 register ASLayoutElem *pelem = layout->cols[i];
1056 int x = (pelem?pelem->x:0) + layout->offset_west ;
1057 LOCAL_DEBUG_OUT( "x = %d, lwidth = %d", x, layout->width );
1058 if( pelem && x >= 0 && x < layout->width )
1059 {
1060 int start = 0, end = 0;
1061 do
1062 {
1063 int y = pelem->y + layout->offset_north ;
1064 LOCAL_DEBUG_OUT( "start = %d, end = %d, y = %d, height = %d, lheight = %d", start, end, y, pelem->height, layout->height );
1065 if( y+pelem->height > 0 && pelem->y < layout->height )
1066 {
1067 if( y > end + layout->h_spacing + 1 )
1068 {
1069 if( end > start )
1070 add_gridline( &(grid->v_lines), x+origin_x, start+origin_y, end+origin_y, gravity, gravity );
1071 end = start = y ;
1072 }else if( y > start && start == end )
1073 start = end = y ;
1074 if( end < y+pelem->height )
1075 end = y+pelem->height ;
1076 }
1077 }while( (pelem = pelem->below) != NULL );
1078 if( end > start )
1079 add_gridline( &(grid->v_lines), x+origin_x, start+origin_y, end+origin_y, gravity, gravity );
1080 }
1081 }
1082 }
1083
1084 static void
destroy_gridlines(register ASGridLine * list)1085 destroy_gridlines( register ASGridLine *list )
1086 {
1087 while( list )
1088 {
1089 register ASGridLine *todel = list;
1090 list = todel->next ;
1091 free( todel );
1092 }
1093 }
1094
1095 void
destroy_asgrid(ASGrid * grid,Bool reusable)1096 destroy_asgrid( ASGrid *grid, Bool reusable )
1097 {
1098 if( grid )
1099 {
1100 destroy_gridlines( grid->h_lines );
1101 destroy_gridlines( grid->v_lines );
1102 if( reusable )
1103 memset( grid, 0x00, sizeof(ASGrid));
1104 else
1105 free( grid );
1106 }
1107 }
1108
print_asgrid(ASGrid * grid)1109 void print_asgrid( ASGrid *grid )
1110 {
1111 fprintf( stderr, "Printing out the grid %p\n", grid );
1112 if( grid )
1113 {
1114 ASGridLine *l ;
1115 fprintf( stderr, "Horizontal grid lines :\n" );
1116 fprintf( stderr, "\t band \t start \t end \t above \t below\n" );
1117 for( l = grid->h_lines ; l != NULL ; l = l->next )
1118 fprintf( stderr, "\t % 4.4d \t % 5.5d \t % 5.5d \t % 5.5d \t % 5.5d\n", l->band, l->start, l->end, l->gravity_above, l->gravity_below );
1119 fprintf( stderr, "Vertical grid lines :\n" );
1120 fprintf( stderr, "\t band \t start \t end \t above \t below\n" );
1121 for( l = grid->v_lines ; l != NULL ; l = l->next )
1122 fprintf( stderr, "\t % 4.4d \t % 5.5d \t % 5.5d \t % 5.5d \t % 5.5d\n", l->band, l->start, l->end, l->gravity_above, l->gravity_below );
1123 }
1124 fprintf( stderr, "Done printing grid %p\n", grid );
1125 }
1126
1127