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