/* r4area.c (c)Copyright Sequiter Software Inc., 1990-1994. All rights reserved. */ #include "d4all.h" /************************************************************ ** Function: area4create() * * PARAMETERS: * GROUP4* group - pointer to the containing GROUP4 * long height - height of the area in 1000's of an inch * short is_header - flag indicating whether area is header or footer * char* expression - character string for suppression condition * * DESCRIPTION: allocates the memory for an AREA4 and does initial setup * of internal members, then adds to appropriate list in containing group * * RETURNS: an AREA4 pointer on success, NULL on failure * * By: Raymond Cypher * * HISTORY: * */ AREA4 * S4FUNCTION area4create( GROUP4 *group, long height, short is_header, char *expression ) { AREA4 *area, *area_on; EXPR4 *expr; int i; if( !group ) return NULL; if( height < 0 ) { e4describe( group->report->code_base, e4parm, E4_REP_AHEIGHT, 0, 0 ); return 0; } /* is suppression condition is provided, parse and check */ if( expression ) { expr = expr4parse( group->report->relate->data, expression ); if( expr == 0 ) { e4describe( group->report->code_base, e4area_create, E4_REP_AEXPR, 0, 0 ); return 0; } } else expr = NULL; /* allocate AREA4 */ area = (AREA4 *) u4alloc_free( group->report->code_base, sizeof(AREA4) ); if(area == 0) { e4describe( group->report->code_base, e4area_create, E4_REP_AMEM, 0, 0 ); return 0; } /* set internal members */ area->height = height; area->suppression_condition = expr; area->group = group; area->allow_pagebreaks = 1; area->report = group->report; area->is_header = is_header; /* insert AREA4 into appropriate list in GROUP4 struct and then re-number the areas */ if( is_header ) { l4add( &group->header_areas, area ); } else { l4add( &group->footer_areas, area ); } i = 1; if( is_header ) area_on = (AREA4 *) l4first( &group->header_areas ); else area_on = (AREA4 *) l4first( &group->footer_areas ); while(area_on ) { area_on->position = i; if( is_header ) area_on = (AREA4 *) l4next( &group->header_areas, area_on ); else area_on = (AREA4 *) l4next( &group->footer_areas, area_on ); i++; } return area; } /************************************************************ ** Function: area4free() * * PARAMETERS: AREA4* area - pointer to area to be freed * * DESCRIPTION: frees the specified area, including any contained objects * * By: Raymond Cypher * * HISTORY: * */ void S4FUNCTION area4free( AREA4 *area ) { OBJ4 *obj_on; /* free the supppression condition */ if( area->suppression_condition != NULL ) { expr4free( area->suppression_condition ); } /* free the contained objects */ while( (obj_on=(POBJ4)l4first(&area->objects)) != NULL ) { obj4delete( obj_on ); } /* Destroy the associated window */ #ifdef S4WINDOWS if( area->hWnd ) { DestroyWindow( area->hWnd ); area->hWnd = 0; } #endif /* remove from the groups list */ if( area->is_header ) l4remove( &area->group->header_areas, area ); else l4remove( &area->group->footer_areas, area ); /* free the memory */ u4free( area ); } /************************************************************ ** Function: area4insert_object() * * PARAMETERS: LIST4* list - list to insert the object into * POBJ4 obj - object to be inserted * * DESCRIPTION: inserts the object into the list, if the * object falls within the boundaries of another object it * is inserted into the bounding objects list * * By: Raymond Cypher * * HISTORY: * */ void area4insert_object( LIST4 *list, POBJ4 obj ) { POBJ4 obj_on; obj_on = (POBJ4)l4first( list ); while( obj_on ) { /* if the object is inside another object */ if( obj->x > obj_on->x && obj->y > obj_on->y && obj->w+obj->x < obj_on->w+obj_on->x && obj->h+obj->y < obj_on->h+obj_on->y ) { obj->container = obj_on; area4insert_object( &obj_on->contained, obj ); return; } obj_on = (POBJ4)l4next( list, obj_on ); } /* add at beginning or end of list */ if( !obj->background ) l4add( list, obj ); else l4add_before( list, l4first(list), obj ); return; } /************************************************************ ** Function: area4insert_y() * * PARAMETERS: LIST4* list - list to insert object into * POBJ4 obj_out - object to be inserted * * DESCRIPTION: inserts the specified object into the list * on the basis of the y coordinate * * By: Raymond Cypher * * HISTORY: * */ void area4insert_y( LIST4 *list, POBJ4 obj_out ) { POBJ4 obj_on; int add_flag; obj_on = (POBJ4)l4first( list ); if( !obj_on ) { l4add( list, obj_out ); } else { add_flag = 0; while( obj_on ) { if( obj_out->y < obj_on->y ) { l4add_before( list, obj_on, obj_out ); add_flag = 1; } if( !add_flag ) obj_on = (POBJ4)l4next( list, obj_on ); else obj_on = NULL; } if( !add_flag ) l4add( list, obj_out ); } } /************************************************************ ** Function: area4insert_xrev() * * PARAMETERS: LIST4* list - list to insert object into * POBJ4 obj_out - object to be inserted * * DESCRIPTION: inserts the specified object into the list * on the basis of the x coordinate * * By: Raymond Cypher * * HISTORY: * */ void area4insert_xrev( LIST4 *list, POBJ4 obj_out ) { POBJ4 obj_on; int add_flag; obj_on = (POBJ4)l4first( list ); if( !obj_on ) { l4add( list, obj_out ); } else { add_flag = 0; while( obj_on ) { if( obj_out->x > obj_on->x ) { l4add_before( list, obj_on, obj_out ); add_flag = 1; } if( !add_flag ) obj_on = (POBJ4)l4next( list, obj_on ); else obj_on = NULL; } if( !add_flag ) l4add( list, obj_out ); } } /************************************************************ ** Function: area4sort_list() * * PARAMETERS: LIST4 *list - list containing OBJ4 structures * * DESCRIPTION: sorts the list of objects * * By: Raymond Cypher * * HISTORY: * */ void area4sort_list( LIST4 *list ) { LIST4 hold_list, int_list; POBJ4 obj_on, obj_out, obj_bound; long ybound; memset( &hold_list, 0, sizeof(LIST4) ); memset( &int_list, 0, sizeof(LIST4) ); while( (obj_out = (POBJ4)l4pop(list)) != NULL ) { area4insert_y( &hold_list, obj_out ); } while( hold_list.n_link > 0 ) { obj_bound = (POBJ4)l4first( &hold_list ); l4remove( &hold_list, obj_bound ); area4insert_xrev( &int_list, obj_bound ); ybound = obj_bound->y; obj_on = (POBJ4)l4first( &hold_list ); while( obj_on && obj_on->y == ybound ) { l4remove( &hold_list, obj_on ); area4insert_xrev( &int_list, obj_on ); obj_on = (POBJ4)l4first( &hold_list ); } while( (obj_out = (POBJ4)l4pop( &int_list)) != NULL ) l4add( list, obj_out ); } } /************************************************************ ** Function: area4add_object() * * PARAMETERS: AREA4* area - area to which an object is to be added * OBJ4* obj_add - object to be added to the area * * DESCRIPTION: adds an object to the specified area * * By: Raymond Cypher * * HISTORY: * */ void S4FUNCTION area4add_object( AREA4 *area, OBJ4 *obj_add ) { POBJ4 pObj, pObjnext; int i, j; if( !area || !obj_add ) return; obj_add->container = NULL; area4insert_object( &area->objects, obj_add ); if( obj_add->x == 0 && obj_add->y == 0 && obj_add->w == 0 && obj_add->h == 0 ) return; pObj = (POBJ4)l4first( &area->objects ); j = area->objects.n_link; i = 0; while( pObj && i < j ) { pObjnext = (POBJ4)l4next( &area->objects, pObj ); if( pObj->x > obj_add->x && pObj->y > obj_add->y && pObj->w + pObj->x < obj_add->w + obj_add->x && pObj->h + pObj->y < obj_add->h + obj_add->y ) { l4remove( &area->objects, pObj ); area4insert_object( &area->objects, pObj ); } pObj = pObjnext; i++; } } /************************************************************ ** Function: area4sort_obj_tree() * * PARAMETERS: PAREA4 area - pointer to the AREA4 struct containing the * objects to be sorted * * DESCRIPTION: sorts the objects in the areas object tree * * By: Raymond Cypher * * HISTORY: * */ void S4FUNCTION area4sort_obj_tree( PAREA4 area ) { POBJ4 obj_on; area4sort_list( &area->objects ); obj_on = (POBJ4)l4first( &area->objects ); while( obj_on ) { if( obj_on->contained.n_link > 0 ) area4sort_list( &obj_on->contained ); obj_on = (POBJ4)l4next( &area->objects, obj_on ); } } /************************************************************ ** Function: area4pageBreak() * * PARAMETERS: PAREA4 area - area to toggle break flag of * int breaks - new value for flag * * DESCRIPTION: toggles the flag allowing page breaks within the area * * RETURNS: the previous value of the flag * * By: Raymond Cypher * * HISTORY: * */ int S4FUNCTION area4pageBreak( PAREA4 area, int breaks ) { int temp; if( area == NULL || breaks < 0 ) { if( area ) e4describe( area->report->code_base, e4parm, E4_REP_PGBRK, 0, 0 ); return -1; } temp = area->allow_pagebreaks; area->allow_pagebreaks = breaks; return temp; } /**************************************************************************** The rest of the functions contained in this file are documented in the CodeReporter manual. */ PAREA4 S4FUNCTION group4headerFirst( PGROUP4 group ) { if( !group ) return NULL; return (PAREA4)l4first( &group->header_areas ); } PAREA4 S4FUNCTION group4headerNext( PGROUP4 group, PAREA4 area ) { if( !group ) return NULL; return (PAREA4)l4next( &group->header_areas, area ); } PAREA4 S4FUNCTION group4headerLast( PGROUP4 group ) { if( !group ) return NULL; return (PAREA4)l4last( &group->header_areas ); } PAREA4 S4FUNCTION group4headerPrev( PGROUP4 group, PAREA4 area ) { if( !group ) return NULL; return (PAREA4)l4prev( &group->header_areas, area ); } int S4FUNCTION group4numHeaders( PGROUP4 group ) { if( !group ) return 0; return group->header_areas.n_link; } PAREA4 S4FUNCTION group4footerFirst( PGROUP4 group ) { if( !group ) return NULL; return (PAREA4)l4first( &group->footer_areas ); } PAREA4 S4FUNCTION group4footerNext( PGROUP4 group, PAREA4 area ) { if( !group ) return NULL; return (PAREA4)l4next( &group->footer_areas, area ); } PAREA4 S4FUNCTION group4footerLast( PGROUP4 group ) { if( !group ) return NULL; return (PAREA4)l4last( &group->footer_areas ); } PAREA4 S4FUNCTION group4footerPrev( PGROUP4 group, PAREA4 area ) { if( !group ) return NULL; return (PAREA4)l4prev( &group->footer_areas, area ); } int S4FUNCTION group4numFooters( PGROUP4 group ) { if( !group ) return 0; return group->footer_areas.n_link; } POBJ4 S4FUNCTION area4objFirst( PAREA4 area ) { if( !area ) { return NULL; } return (POBJ4)l4first( &area->objects ); } POBJ4 S4FUNCTION area4objNext( PAREA4 area, POBJ4 aobj ) { POBJ4 next_obj, obj; if( !area || !aobj ) { if( area && !aobj ) e4describe( area->report->code_base, e4parm, E4_REP_OBJNXT, 0, 0 ); return NULL; } obj = aobj; if( obj->contained.n_link > 0 ) { return (POBJ4)l4first( &obj->contained ); } for( ;; ) { if( !obj ) return obj; if( obj->container == 0 ) { return (POBJ4)l4next( &area->objects, obj ); } next_obj = (POBJ4)l4next( &obj->container->contained, obj ); if( next_obj ) return next_obj; obj = obj->container; } } POBJ4 S4FUNCTION area4objPrev( PAREA4 area, POBJ4 aobj ) { POBJ4 prev_obj, obj; if( !area || !aobj ) { if( area && !aobj ) e4describe( area->report->code_base, e4parm, E4_REP_OBJPRV, 0, 0 ); return NULL; } prev_obj = area4objFirst( area ); if( prev_obj == aobj ) return NULL; obj = area4objNext( area, prev_obj ); while( obj && obj != aobj ) { prev_obj = obj; obj = area4objNext( area, prev_obj ); } return prev_obj; } POBJ4 S4FUNCTION area4objLast( PAREA4 area ) { POBJ4 obj, prev_obj; if( !area ) { return NULL; } prev_obj = area4objFirst( area ); obj = area4objNext( area, prev_obj ); while( obj != NULL ) { prev_obj = obj; obj = area4objNext( area, prev_obj ); } return prev_obj; } int S4FUNCTION area4numObjects( PAREA4 area ) { int objcount; POBJ4 obj; if( !area ) { return -1; } objcount = 0; obj = area4objFirst( area ); while( obj ) { objcount++; obj = area4objNext( area, obj ); } return objcount; }