/* * Copyright (c) 2000 Sasha Vasko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /*#define LOCAL_DEBUG*/ #include "config.h" #include #include #include #include "astypes.h" #include "audit.h" #include "safemalloc.h" #include "output.h" #include "layout.h" /* these are used to perform different size/position adjustments in order * to avoid dynamic memory allocations : */ static int as_layout_fixed_width[ASLAYOUT_MAX_SIZE], as_layout_fixed_height[ASLAYOUT_MAX_SIZE] ; static int as_layout_width[ASLAYOUT_MAX_SIZE], as_layout_height[ASLAYOUT_MAX_SIZE] ; static int as_layout_x[ASLAYOUT_MAX_SIZE], as_layout_y[ASLAYOUT_MAX_SIZE] ; /**********************************************************************/ /* Creation/Destruction */ ASLayout * create_aslayout( unsigned int dim_x, unsigned int dim_y ) { ASLayout *layout = NULL ; if( dim_x && dim_y ) { layout = safecalloc( 1, sizeof(ASLayout)); layout->dim_x = dim_x ; layout->dim_y = dim_y ; if( dim_x > 0 ) layout->cols = safecalloc( dim_x, sizeof(ASLayoutElem*)); if( dim_y > 0 ) layout->rows = safecalloc( dim_y, sizeof(ASLayoutElem*)); } return layout; } static inline int destroy_layout_row( ASLayoutElem **prow ) { register ASLayoutElem *pelem = *prow; int count = 0 ; while( pelem ) { register ASLayoutElem *tmp = pelem->right ; free( pelem ); pelem = tmp ; ++count; } *prow = NULL ; return count; } void destroy_aslayout( ASLayout **playout ) { if( playout ) { register ASLayout *layout = *playout ; if( layout ) { register int i ; for( i = 0 ; i < layout->dim_y ; i++ ) destroy_layout_row( &(layout->rows[i])); destroy_layout_row( &(layout->disabled) ); if( layout->rows ) free( layout->rows ); if( layout->cols ) free( layout->cols ); layout->dim_x = layout->dim_y = 0 ; free( layout ); *playout = NULL ; } } } /**********************************************************************/ /* addition/extraction of elements : */ void insert_layout_elem( ASLayout *layout, ASLayoutElem *elem, unsigned int h_slot, unsigned int v_slot, unsigned int h_span, unsigned int v_span ) { if( layout ) { ASLayoutElem **pelem, **pelem2 ; if( h_slot >= ASLAYOUT_MAX_SIZE ) h_slot = ASLAYOUT_MAX_SIZE-1 ; if( v_slot >= ASLAYOUT_MAX_SIZE ) v_slot = ASLAYOUT_MAX_SIZE-1 ; if( h_span > ASLAYOUT_MAX_SIZE-h_slot ) h_span = ASLAYOUT_MAX_SIZE-h_slot ; if( v_span > ASLAYOUT_MAX_SIZE-v_slot ) v_span = ASLAYOUT_MAX_SIZE-v_slot ; if( layout->dim_x < h_slot+h_span ) { layout->cols = realloc( layout->cols, (h_slot+h_span)*sizeof(ASLayoutElem*) ); memset( layout->cols+ layout->dim_x, 0x00, ((h_slot+h_span) - layout->dim_x) *sizeof( ASLayoutElem*) ); layout->dim_x = h_slot+h_span ; } if( layout->dim_y < v_slot+v_span ) { layout->rows = realloc( layout->rows, (v_slot+v_span)*sizeof(ASLayoutElem*) ); memset( layout->rows+ layout->dim_y, 0x00, ((v_slot+v_span) - layout->dim_y) *sizeof( ASLayoutElem*) ); layout->dim_y = v_slot+v_span ; } for( pelem = &(layout->rows[v_slot]); *pelem ; pelem = &((*pelem)->right) ) if( (*pelem)->column >= h_slot ) break ; for( pelem2 = &(layout->cols[h_slot]); *pelem2 ; pelem2 = &((*pelem2)->below) ) { if( (*pelem2)->row >= v_slot ) break ; } if( *pelem && *pelem == *pelem2 ) { elem->right = (*pelem)->right ; elem->below = (*pelem)->below ; (*pelem)->right = (*pelem)->below = NULL ; free( *pelem ); }else { elem->right = *pelem ; elem->below = *pelem2 ; ++(layout->count); } *pelem = elem ; *pelem2 = elem ; elem->h_span = h_span ; elem->v_span = v_span ; elem->row = v_slot ; elem->column = h_slot ; } } ASLayoutElem * gather_layout_elems( ASLayout *layout ) { ASLayoutElem *head = NULL; if( layout && layout->count > 0 ) { register int i ; head = layout->disabled ; layout->disabled = NULL ; for( i = 0 ; i < layout->dim_y ; ++i ) { register ASLayoutElem *pelem = layout->rows[i] ; if( pelem ) { while( pelem->right ) { pelem->below = NULL ; pelem = pelem->right ; } pelem->below = NULL ; pelem->right = head ; head = layout->rows[i] ; layout->rows[i] = NULL ; } } for( i = 0 ; i < layout->dim_x ; i++ ) layout->cols[i] = NULL ; layout->count = 0 ; } return head ; } void flush_layout_elems( ASLayout *layout ) { if( layout && layout->count > 0 ) { register int i ; for( i = 0 ; i < layout->dim_y ; i++ ) destroy_layout_row( &(layout->rows[i])); destroy_layout_row( &(layout->disabled) ); layout->count = 0 ; } } static ASLayoutElem ** get_layout_context_ptr( ASLayout *layout, int context ) { register ASLayoutElem **pelem = NULL ; register int i ; for( i = 0 ; i < layout->dim_y ; ++i ) for( pelem = &(layout->rows[i]) ; *pelem ; pelem = &((*pelem)->right) ) if( (*pelem)->context == context ) return pelem ; return NULL; } ASLayoutElem * extract_layout_context( ASLayout *layout, int context ) { ASLayoutElem *elem = NULL; if( layout && layout->count ) { register ASLayoutElem **pelem = NULL ; if((pelem = get_layout_context_ptr( layout, context )) != NULL ) { elem = *pelem ; *pelem = elem->right ; for( pelem = &(layout->cols[elem->column]) ; *pelem ; pelem = &((*pelem)->below) ) if( *pelem == elem ) { *pelem = elem->below; break; } --(layout->count) ; } } return elem ; } ASLayoutElem * find_layout_context( ASLayout *layout, int context ) { if( layout && layout->count ) { register ASLayoutElem **pelem = NULL ; if((pelem = get_layout_context_ptr( layout, context )) != NULL ) return *pelem ; } return NULL ; } /**********************************************************************/ /* enable/disable element */ void disable_layout_elem( ASLayout *layout, ASLayoutElem **pelem ) { if( layout && pelem && *pelem ) { ASLayoutElem *elem = *pelem ; /* step one - taking out of horisontal circulation : */ *pelem = elem->right ; /* step two - taking out of vertical circulation :) */ for( pelem = &(layout->cols[elem->column]) ; *pelem ; pelem = &((*pelem)->below) ) if( *pelem == elem ) break; if( *pelem ) *pelem = elem->below ; elem->below = NULL; /* step three - stashing away for later reuse :*/ elem->right = layout->disabled ; layout->disabled = elem ; --(layout->count); } } void enable_layout_elem( ASLayout *layout, ASLayoutElem **pelem ) { if( layout && pelem && *pelem ) { ASLayoutElem *elem = *pelem ; /* step one - taking out of disabled list : */ *pelem = elem->right ; /* step two - reinserting us into The MATRIX !!!! BWUHAHAHA */ elem->right = NULL ; if( elem->column+elem->h_span <= layout->dim_x && elem->row+elem->v_span <= layout->dim_y) insert_layout_elem( layout, elem, elem->column, elem->row, elem->h_span, elem->v_span ); else free( elem ); } } int disable_layout_context( ASLayout *layout, int context, Bool batch ) { int found = 0 ; if( layout ) { register ASLayoutElem **pelem = NULL ; register int i ; for( i = 0 ; i < layout->dim_y ; i++ ) for( pelem = &(layout->rows[i]) ; *pelem ; pelem = &((*pelem)->right) ) { if( (*pelem)->context == context ) { disable_layout_elem( layout, pelem ); found++; } } } if( found > 0 && !batch ) { /* mylayout_moveresize( widget->layout, widget->width, widget->height, True ); mywidget_update_fixed_size( widget, False ); */ } return found ; } int enable_layout_context( ASLayout *layout, int context, Bool batch ) { int found = 0 ; if( layout ) { register ASLayoutElem **pelem = NULL ; for( pelem = &(layout->disabled) ; *pelem ; pelem = &((*pelem)->right) ) if( (*pelem)->context == context ) { enable_layout_elem( layout, pelem ); found++; } } if( found > 0 && !batch ) { /* mylayout_moveresize( widget->layout, widget->width, widget->height, True ); mywidget_update_fixed_size( widget, False ); */ } return found ; } /**********************************************************************/ /* spacing and side offset management */ Bool set_layout_spacing( ASLayout *layout, unsigned int h_border, unsigned int v_border, unsigned int h_spacing, unsigned int v_spacing ) { Bool changed = False ; if( layout ) { changed = ( layout->h_border != h_border || layout->v_border != v_border || layout->h_spacing != h_spacing || layout->v_spacing != v_spacing ); if( changed ) { layout->h_border = h_border ; layout->v_border = v_border ; layout->h_spacing = h_spacing ; layout->v_spacing = v_spacing ; } } return changed; } Bool set_layout_offsets( ASLayout *layout, int east, int north, int west, int south ) { Bool changed = False ; if( layout ) { changed = ( layout->offset_east != east || layout->offset_north != north || layout->offset_west != west || layout->offset_south != south ); if( changed ) { layout->offset_east = east ; layout->offset_north = north ; layout->offset_west = west ; layout->offset_south = south ; } } return changed; } /**********************************************************************/ /* fixed size handling : */ static unsigned int get_layout_fixed_width( ASLayout *layout, unsigned int start_col, unsigned int end_col ) { register int i ; unsigned int width = 0 ; for( i = start_col ; i < end_col ; ++i ) { register ASLayoutElem *pelem = layout->cols[i]; register int fw = 0 ; while ( pelem ) { if( get_flags( pelem->flags, LF_FixedWidth ) ) { LOCAL_DEBUG_OUT( " layout %lX found item with fixed width %d at %dx%d", (unsigned long)layout, pelem->fixed_width, pelem->row, pelem->column ); if( pelem->fixed_width+pelem->bw > fw ) fw = pelem->fixed_width+pelem->bw ; } pelem = pelem->below ; } if( fw > 0 ) width += fw+layout->v_spacing ; } if( width > 0 ) width -= (int)layout->v_spacing ; return width ; } static unsigned int get_layout_fixed_height( ASLayout *layout, unsigned int start_row, unsigned int end_row ) { register int i ; unsigned int height = 0 ; for( i = start_row ; i < end_row ; i++ ) { register ASLayoutElem *pelem = layout->rows[i]; register int fh = 0 ; while ( pelem ) { if( get_flags( pelem->flags, LF_FixedHeight ) ) { LOCAL_DEBUG_OUT( " layout %lX found item with fixed height %d at %dx%d", (unsigned long)layout, pelem->fixed_height, pelem->row, pelem->column ); if( pelem->fixed_height+pelem->bw > fh ) fh = pelem->fixed_height+pelem->bw ; } pelem = pelem->right ; } if( fh > 0 ) height += fh+layout->h_spacing ; } if( height >0 ) height -= layout->h_spacing ; return height; } void get_layout_fixed_size( ASLayout *layout, CARD32 *fixed_width, CARD32 *fixed_height ) { int width = 0, height = 0; if( layout && layout->count > 0 ) { if( fixed_width ) { width = get_layout_fixed_width( layout, 0, layout->dim_x ); if( width > 0 ) width += layout->v_border + layout->v_border + layout->offset_east + layout->offset_west ; } if( fixed_height ) { height = get_layout_fixed_height( layout, 0, layout->dim_y ); if( height >0 ) height += layout->h_border+ layout->h_border + layout->offset_north+ layout->offset_south ; } } LOCAL_DEBUG_OUT( " layout %lX FIXED WIDTH is %d FIXED HEIGHT is %d", (unsigned long)layout, width, height ); if( fixed_width ) *fixed_width = width < 0 ? 0 : width ; if( fixed_height ) *fixed_height = height < 0 ? 0 : height ; } Bool get_layout_context_fixed_frame( ASLayout *layout, int context, int *north, int *east, int *south, int *west ) { int size ; if( layout && layout->count > 0 ) { ASLayoutElem **pelem = get_layout_context_ptr( layout, context ); if( pelem != NULL ) { register ASLayoutElem *elem = *pelem ; if( north ) { size = 0 ; if( elem->row > 0 ) { size = get_layout_fixed_height( layout, 0, elem->row ); if( size > 0 ) size += layout->v_spacing ; } *north = size+layout->h_border; } if( east ) { size = 0 ; if( elem->column+elem->h_span < layout->dim_x ) { size = get_layout_fixed_width( layout, elem->column+elem->h_span, layout->dim_x ); if( size > 0 ) size += layout->h_spacing ; } *east = size+layout->v_border; } if( south ) { size = 0 ; if( elem->row+elem->v_span < layout->dim_y ) { size = get_layout_fixed_height( layout, elem->row+elem->v_span, layout->dim_y ); if( size > 0 ) size += layout->v_spacing ; } *south = size+layout->h_border; } if( west ) { size = 0 ; if( elem->column > 0 ) { size = get_layout_fixed_width( layout, 0, elem->column ); if( size > 0 ) size += layout->v_spacing ; } *west = size+layout->v_border; } return True; } } return False; } ASFlagType set_layout_context_fixed_size( ASLayout *layout, int context, unsigned int width, unsigned int height, unsigned short flags ) { if( layout && layout->count > 0 ) { ASLayoutElem **pelem = get_layout_context_ptr( layout, context ); LOCAL_DEBUG_OUT( "setting fixedsize of context %d(%p) to %dx%d", context, pelem?*pelem:NULL, width, height ); if( pelem != NULL ) { register ASLayoutElem *elem = *pelem ; if( get_flags( flags, LF_FixedWidth ) ) elem->fixed_width = width ; if( get_flags( flags, LF_FixedHeight ) ) elem->fixed_height = height ; return elem->flags&LF_FixedSize&flags; } } return 0; } Bool get_layout_context_size( ASLayout *layout, int context, int *x, int *y, unsigned int *width, unsigned int *height ) { if( layout && layout->count > 0 ) { ASLayoutElem **pelem = get_layout_context_ptr( layout, context ); if( pelem != NULL ) { register ASLayoutElem *elem = *pelem ; if( x ) *x = elem->x ; if( y ) *y = elem->y ; if( width ) *width = elem->width ; if( height ) *height = elem->height ; return True; } } return False; } ASLayoutElem * find_layout_point( ASLayout *layout, int x, int y, ASLayoutElem *start ) { if( layout && layout->count > 0 ) { register int col = start? start->column : 0 ; x -= layout->x ; y -= layout->y ; for( ; col < layout->dim_x ; ++col ) { register ASLayoutElem *pelem = layout->cols[col] ; if( start && start->column == col ) pelem = start->below ; if( pelem ) { if( pelem->x > x ) return NULL; for( ; pelem != NULL ; pelem = pelem->below ) { if( pelem->y > y ) break; if( pelem->x+pelem->width > x && pelem->y+pelem->height > y ) return pelem; } } } } return NULL ; } /**************************************************************************************** * The following are dynamic methods and return value that indicates if any of the cached * pixmaps has to be rebuild ****************************************************************************************/ static int collect_sizes( ASLayout *layout, int *layout_size, int *layout_fixed_size, Bool h_direction ) { int dim ; ASLayoutElem **chains ; register int i ; int spacing_needed = 0 ; int max_span; ASFlagType fixed_flag ; unsigned int spacing ; if( h_direction ) { dim = layout->dim_x ; chains = layout->cols ; fixed_flag = LF_FixedWidth ; spacing = layout->h_spacing ; }else { dim = layout->dim_y ; chains = layout->rows ; fixed_flag = LF_FixedHeight ; spacing = layout->v_spacing ; } /* PASS 1 : we mark all the dead columns with fixed width -1 */ for( i = 0 ; i < dim ; ++i ) layout_fixed_size[i] = chains[i]?0:-1 ; /* PASS 2 : we calculate fixed size for columns tarting with elements that has span on 1 * and increasing it untill it reaches up to DIM : */ for( max_span = 1; max_span <= dim ; max_span++ ) { for( i = dim-max_span ; i >= 0 ; --i ) { register ASLayoutElem *pelem = chains[i]; while( pelem ) { unsigned int span ; int fixed_size ; ASLayoutElem *pnext ; if( h_direction ) { span = pelem->h_span; pnext = pelem->below; fixed_size = get_flags( pelem->flags, LF_FixedWidth )?pelem->fixed_width+(pelem->bw<<1)+spacing:0 ; }else { span = pelem->v_span; pnext = pelem->right; fixed_size = get_flags( pelem->flags, LF_FixedHeight )?pelem->fixed_height+(pelem->bw<<1)+spacing:0 ; } if( span == max_span && fixed_size > 0 ) { register int k ; for( k = i + span - 1 ; k > i ; --k )/* working around span: width = width - spanned_width */ if( layout_fixed_size[k] > 0 ) fixed_size -= layout_fixed_size[k]+spacing; if( fixed_size > 0 ) { if( layout_fixed_size[i] == 0 ) layout_fixed_size[i] = fixed_size ; else if( fixed_size > layout_fixed_size[i] ) { int limit = i+span ; for( k = i+1 ; k < limit ; ++k ) if( layout_fixed_size[k] == 0 ) { layout_fixed_size[k] = layout_fixed_size[i]-(fixed_size+spacing) ; fixed_size = layout_fixed_size[i] ; } if( fixed_size > layout_fixed_size[i] ) layout_fixed_size[i] = fixed_size ; } } } pelem = pnext ; } } } /* PASS 3 : we collect all the existing sizes */ if( layout_size != NULL ) { for( i = dim-1 ; i >=0 ; --i ) { register ASLayoutElem *pelem = chains[i]; layout_size[i] = 0 ; while( pelem ) { unsigned int span ; int size ; ASLayoutElem *pnext ; if( h_direction ) { span = pelem->h_span; size = pelem->width ; pnext = pelem->below; }else { span = pelem->v_span; size = pelem->height ; pnext = pelem->right; } size += (pelem->bw<<1) ; if( size > 0 ) { register int k ; for( k = i + span - 1 ; k > i ; --k )/* working around span: width = width - spanned_width */ if( layout_fixed_size[k] > 0 ) size -= layout_size[k]+spacing; if( layout_size[i] < size ) /* this really should be the same in all rows */ layout_size[i] = size ; } pelem = pnext ; } } } /* PASS 4 : we mark all the columns that has fixed size 0 yet are overlapped * by any fixed item as hidden (-1) */ for( i = dim-1 ; i >= 0 ; --i ) { register ASLayoutElem *pelem = chains[i]; while( pelem ) { unsigned int span ; ASLayoutElem *pnext ; if( h_direction ) { span = pelem->h_span; pnext = pelem->below; }else { span = pelem->v_span; pnext = pelem->right; } if( get_flags( pelem->flags, fixed_flag ) ) { register int k ; for( k = i + span - 1 ; k >= i ; --k )/* working around span: width = width - spanned_width */ if( layout_fixed_size[k] == 0 ) layout_fixed_size[k] = -1 ; } pelem = pnext ; } } /* PASS 5 : we collect interelement spacing used */ for( i = dim-1 ; i > 0 ; --i ) if( layout_fixed_size[i] >= 0 ) spacing_needed += spacing ; return spacing_needed; } static void adjust_sizes( unsigned int old_total, unsigned int new_total, unsigned int dim, int *sizes, int *fixed_items ) { register int i; int available = new_total ; int empty_count = 0, non_fixed_count = 0 ; int new_size, old_size ; /* first allocating space for fixed items */ for( i = 0 ; i < dim ; i++ ) { if( fixed_items[i] < 0 ) sizes[i] = 0 ; else if( fixed_items[i] > 0 ) { if( available <= 0 ) sizes[i] = 0 ; else { sizes[i] = MIN( available, fixed_items[i]); available -= sizes[i] ; } } } /* then allocating space for non-fixed items */ for( i = 0 ; i < dim ; i++ ) if( fixed_items[i] == 0 ) { non_fixed_count++; if( (old_size = sizes[i]) == 0 ) empty_count++ ; else if( available <= 0 || old_total == 0 ) { sizes[i] = 0 ; }else { new_size = (old_size*new_total)/old_total ; /* trying to keep the ratio */ sizes[i] = MIN( new_size, available ); } available -= sizes[i] ; } if( available > 0 && empty_count > 0) /* we have to spread available space among empty non-fixed columns */ { new_size = available/empty_count ; if( new_size <= 0 ) new_size = 1 ; for( i = 0 ; i < dim && empty_count ; i++ ) if( sizes[i] == 0 && fixed_items[i] == 0 ) { sizes[i] = new_size ; empty_count-- ; if( (available -= new_size ) <= 0 ) break; } } if( available > 0 && non_fixed_count > 0 ) /* we have to spread available space among any non-fixed column */ { new_size = available/non_fixed_count ; if( new_size <= 0 ) new_size = 1 ; for( i = 0 ; i < dim && non_fixed_count > 0 ; i++ ) if( fixed_items[i] == 0 ) { if( non_fixed_count == 1 ) sizes[i] += available ; else sizes[i] += new_size ; available -= new_size ; non_fixed_count-- ; } } } static void apply_sizes( int spacing, int start_margin, int dim, int *layout_size, int *layout_fixed_size, int *layout_pos ) { register int i ; layout_pos[0] = start_margin ; for( i = 1 ; i < dim ; i++ ) { layout_pos[i] = layout_pos[i-1]+layout_size[i-1]; if( layout_size[i] > 0 && layout_pos[i] > start_margin ) { layout_pos[i] += spacing; layout_size[i] -= spacing; } } } Bool moveresize_layout( ASLayout *layout, unsigned int width, unsigned int height, Bool force ) { register int i ; int spacing_needed = 0 ; if( layout == NULL ) return False; width -= layout->offset_east+layout->offset_west+(layout->v_border<<1) ; height -= layout->offset_north+layout->offset_south+(layout->h_border<<1) ; if( width == layout->width && height == layout->height && !force ) return False; /* first working on width/x position */ spacing_needed = collect_sizes( layout, &(as_layout_width[0]), &(as_layout_fixed_width[0]), True ); adjust_sizes( layout->width, width, layout->dim_x, &(as_layout_width[0]), &(as_layout_fixed_width[0]) ); 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]) ); #ifdef LOCAL_DEBUG fprintf( stderr, "\n" ); for( i = 0 ; i < layout->dim_x ; ++i ) fprintf( stderr, "\t%d", as_layout_fixed_width[i]); fprintf( stderr, "\n" ); for( i = 0 ; i < layout->dim_x ; ++i ) fprintf( stderr, "\t%d", as_layout_width[i]); fprintf( stderr, "\n" ); for( i = 0 ; i < layout->dim_x ; ++i ) fprintf( stderr, "\t%d", as_layout_x[i] ); fprintf( stderr, "\n" ); #endif /* then working on height/y position */ spacing_needed = collect_sizes( layout, &(as_layout_height[0]), &(as_layout_fixed_height[0]), False ); adjust_sizes( layout->height, height, layout->dim_y, &(as_layout_height[0]), &(as_layout_fixed_height[0]) ); 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]) ); #ifdef LOCAL_DEBUG 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 ); for( i = 0 ; i < layout->dim_y ; ++i ) fprintf( stderr, "\t%d", as_layout_fixed_height[i]); fprintf( stderr, "\n" ); for( i = 0 ; i < layout->dim_y ; ++i ) fprintf( stderr, "\t%d", as_layout_height[i]); fprintf( stderr, "\n" ); for( i = 0 ; i < layout->dim_y ; ++i ) fprintf( stderr, "\t%d", as_layout_y[i] ); fprintf( stderr, "\n" ); #endif /* now we can actually apply our calculations : */ /* becouse of the static arrays we cann not recurse while we need * info in those arrays. So on the first pass we set all the x/y/w/h * of our elements, and on the second pass - we resize subwidgets */ /* Pass 1: */ for( i = 0 ; i < layout->dim_y ; i++ ) if( layout->rows[i] ) { register ASLayoutElem *pelem = layout->rows[i]; int elem_y = as_layout_y[i] ; do { register int k ; unsigned int w = as_layout_width[pelem->column] ; unsigned int h = as_layout_height[i] ; int elem_x = as_layout_x[pelem->column] ; k = pelem->column+pelem->h_span-1 ; w = (as_layout_x[k]+as_layout_width [k]) - elem_x; k = pelem->row+pelem->v_span-1; h = (as_layout_y[k]+as_layout_height[k]) - elem_y; 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 ); pelem->x = elem_x; pelem->y = elem_y; pelem->width = w - (pelem->bw<<1); pelem->height = h - (pelem->bw<<1); }while( (pelem = pelem->right) != NULL ); } layout->width = width; layout->height = height; return True; } /***********************************************************************/ /* Grid stuff : */ /***********************************************************************/ ASGridLine * add_gridline( ASGridLine **list, short band, short start, short end, short gravity_above, short gravity_below ) { ASGridLine *l; if( AS_ASSERT(list) ) return NULL; for( l = *list ; l != NULL ; l = l->next ) {/* eliminating duplicates and sorting in ascending order : */ if( l->band <= band ) list = &(l->next); if( l->band == band ) { if( l->start < end && l->end > start ) { /* at least intersecting : */ if( l->gravity_above == gravity_above && l->gravity_below == gravity_below ) { l->start = MIN( l->start, start ); l->end = MAX( l->end, end ); return NULL; } if( l->start == start && l->end == end ) { l->gravity_above = ( l->gravity_above < 0 )? MIN(l->gravity_above, gravity_above): ((gravity_above < 0 )? gravity_above: MAX(l->gravity_above, gravity_above)); l->gravity_below = ( l->gravity_below < 0 )? MIN(l->gravity_below, gravity_below): ((gravity_below < 0 )? gravity_below: MAX(l->gravity_below, gravity_below)); return NULL; } } }else if( l->band > band ) break; } l = safecalloc( 1, sizeof(ASGridLine)); l->band = band ; l->start = start ; l->end = end ; l->gravity_above = gravity_above; l->gravity_below = gravity_below; l->next = *list ; *list = l ; return l; } void make_layout_grid( ASLayout *layout, ASGrid *grid, int origin_x, int origin_y, short gravity ) { int i ; if( layout == NULL || grid == NULL ) return ; /* horizontal lines : */ for( i = 0 ; i < layout->dim_y ; i++ ) { register ASLayoutElem *pelem = layout->rows[i]; int y = (pelem?pelem->y:0) + layout->offset_north ; LOCAL_DEBUG_OUT( "y = %d, lheight = %d", y, layout->height ); if( pelem && y >= 0 && y < layout->height ) { int start = 0, end = 0; do { int x = pelem->x + layout->offset_west ; LOCAL_DEBUG_OUT( "start = %d, end = %d, x = %d, width = %d, lwidth = %d", start, end, x, pelem->width, layout->width ); if( x+pelem->width > 0 && pelem->x < layout->width ) { if( x > end + layout->v_spacing + 1 ) { if( end > start ) add_gridline( &(grid->h_lines), y+origin_y, start+origin_x, end+origin_x, gravity, gravity ); end = start = x ; }else if( x > start && start == end ) { start = end = x ; } if( end < x+pelem->width ) end = x+pelem->width ; } }while( (pelem = pelem->right) != NULL ); if( end > start ) add_gridline( &(grid->h_lines), y+origin_y, start+origin_x, end+origin_x, gravity, gravity ); } } /* vertical lines : */ for( i = 0 ; i < layout->dim_x ; i++ ) { register ASLayoutElem *pelem = layout->cols[i]; int x = (pelem?pelem->x:0) + layout->offset_west ; LOCAL_DEBUG_OUT( "x = %d, lwidth = %d", x, layout->width ); if( pelem && x >= 0 && x < layout->width ) { int start = 0, end = 0; do { int y = pelem->y + layout->offset_north ; LOCAL_DEBUG_OUT( "start = %d, end = %d, y = %d, height = %d, lheight = %d", start, end, y, pelem->height, layout->height ); if( y+pelem->height > 0 && pelem->y < layout->height ) { if( y > end + layout->h_spacing + 1 ) { if( end > start ) add_gridline( &(grid->v_lines), x+origin_x, start+origin_y, end+origin_y, gravity, gravity ); end = start = y ; }else if( y > start && start == end ) start = end = y ; if( end < y+pelem->height ) end = y+pelem->height ; } }while( (pelem = pelem->below) != NULL ); if( end > start ) add_gridline( &(grid->v_lines), x+origin_x, start+origin_y, end+origin_y, gravity, gravity ); } } } static void destroy_gridlines( register ASGridLine *list ) { while( list ) { register ASGridLine *todel = list; list = todel->next ; free( todel ); } } void destroy_asgrid( ASGrid *grid, Bool reusable ) { if( grid ) { destroy_gridlines( grid->h_lines ); destroy_gridlines( grid->v_lines ); if( reusable ) memset( grid, 0x00, sizeof(ASGrid)); else free( grid ); } } void print_asgrid( ASGrid *grid ) { fprintf( stderr, "Printing out the grid %p\n", grid ); if( grid ) { ASGridLine *l ; fprintf( stderr, "Horizontal grid lines :\n" ); fprintf( stderr, "\t band \t start \t end \t above \t below\n" ); for( l = grid->h_lines ; l != NULL ; l = l->next ) 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 ); fprintf( stderr, "Vertical grid lines :\n" ); fprintf( stderr, "\t band \t start \t end \t above \t below\n" ); for( l = grid->v_lines ; l != NULL ; l = l->next ) 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 ); } fprintf( stderr, "Done printing grid %p\n", grid ); }