/* $Id: network.c,v 10.1 92/10/06 23:03:32 ca Exp $ */ /* * MaRS Maryland Routing Simulator * Copyright (c) 1991 University of Maryland * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Eric Bull * Systems Design and Analysis Group * Department of Computer Science * University of Maryland at College Park. */ /******************************************************************************************************************** The network object module contains functions for manipulating the network data structure and drawing network components. The network data structure consists of a list of a top level group of components. Top level components are connected by way of their sister lists. Top level components may have children which are connected to them by way of a child list. MComponent *NewComponent(char *name, int type, int x, int y); Create a component. void KillComponent(MComponent *comp); Destroy a component. MComponent *NewGroup(char *name, MComponentList l); Create a new group containing the listed components. void KillGroup(MComponent *group); Destroy a group and all the group members. void OpenGroup(MComponent *group); Open a group. void CloseGroup(MComponent *group); Close a group. void UnGroup(MComponent *group); Destroy a group but not it's members. void ConnectChild(MComponent *child, MComponent *parent); Connect a component as a child. void DisconnectChild(MComponent *comp); Disconnect the child from it's parent. void ConnectSisters(MComponent *sister1, MComponent *sister2); Connect components as sisters. void DisconnectSisters(MComponent *sister1, MComponent *sister2); Disconnect two sisters. void DisconnectAllSisters(MComponent *comp); Disconnect a component from all it's sisters. void MakeInvisible(MComponent *comp); Make a component invisible. void MakeVisible(MComponent *comp); Make a component visible. void MoveComponent(MComponent *comp, int new_x, int new_y); Move a component. void TraverseNetwork(int order,void (*func)()); Call a function on each component in the network. void TraverseNetworkWithArguments(int order,void (*func)(), void *args); Call a function, passing an argument. void UnselectComponent(MComponent *comp); Unselect the component. void SelectComponent(MComponent *comp); Select the component. void UnselectGroupMembers(MComponent *group); Unselect all members of the group. void ChangeComponentName(MComponent *comp,char *new_name); Change the component's name. int ParentType(MComponent *comp); Returns the type of the component's parent. No parent returns TYPE_GROUP. MComponent *GetGroup (MComponent *comp); Returns the group containing the component. MComponent *GetComponentOfIcon(Widget icon); Returns component associated with the icon. int GroupMemberp(MComponent *comp, MComponent *group); Is the component a member of the group? *********************************************************************************************************************/ #include #include #include "xm-network.h" #include "xm-util.h" #include "list.h" #include "xm-icon.h" #include "xm-comp_trans.h" #include "xm-param_w.h" #include "comptypes.h" #include "xm-main_w.h" #include "xm-meters.h" #include "xm-lines.h" /* These are private functions, not to be called outside this module. Public functions are declared in network.h */ void GetCoordinateRange(MComponentList list,int *min_x,int *min_y,int *max_x,int *max_y); int AllParentsOpenp(MComponent *comp); void RecursiveKill(MComponent *comp); int FixRelativePosition (MComponent *comp); void DrawComponent(MComponent *comp); void UndrawComponent(MComponent *comp); void DrawComponents(MComponentList l); void UndrawComponents(MComponentList l); MComponent *DetachChild(MComponent *child); void AttachChild(MComponent *child, MComponent *parent); void AttachSisters(MComponent *sister1, MComponent *sister2); void DetachSisters(MComponent *sister1, MComponent *sister2); void DetachAllSisters(MComponent *comp); void DrawParentLine(MComponent *child); void DrawSisterLine(void *sister1, void *sister2); void EraseSisterLine(void *sister1, void *sister2); void EraseParentLine(MComponent *child); void EraseDrawnSisterLines(MComponent *comp); void DrawDrawnSisterLines(MComponent *comp); void MoveChild(MComponent *comp,int diff_x,int diff_y); void TraverseChildrenWithArguments(int order,MComponentList l,void (*func)(), void *args); void TraverseChildren(int order,MComponentList l,void (*func)()); /*============================================ Global Variables ================================================*/ MComponentList network_components; /* The list of all network components. */ MComponentList selected; /* This is the list of selected components. */ /*=========================================== Function Definitions ============================================*/ #define ComputeCenter(cx,cy,x,y,w,h) {(cx)=(x)+(w)/2;(cy)=(y)+(h)/2;} #define ComputeRelativePosition(rx,ry,x,y,cx,cy) {(rx)=(x)-(cx);(ry)=(y)-(cy);} #define SetRelativePosition(comp,parent) \ { \ if ((parent)!=NULL) \ ComputeRelativePosition((comp)->rel_x,(comp)->rel_y,(comp)->x,(comp)->y,(parent)->x,(parent)->y) \ else \ (comp)->rel_x=0; (comp)->rel_y=0; \ } #define ChangeParent(comp,new_parent) AttachChild(DetachChild(comp),new_parent); #define ComputeCenterOfList(list,x,y) \ {\ int min_x,min_y,max_x,max_y; \ GetCoordinateRange(list,&min_x,&min_y,&max_x,&max_y); \ ComputeCenter(x,y,min_x,min_y,max_x-min_x+1,max_y-min_y+1);\ } /*****************************************************************************************************************************************/ component_xy(scomponent, x, y) /* Return the component's coordinates. */ COMPONENT *scomponent; int *x, *y; { MComponent *comp; comp = (MComponent *) scomponent->co_picture; if (comp) { *x = comp->x; *y = comp->y; } else { *x = 0; *y = 0; } return (TRUE); } /*****************************************************************************************************************************************/ int GroupMemberp(MComponent *comp, MComponent *group) { /* Is the component a member of the group? */ if (comp==NULL) return(0); else return(comp->parent==group || GroupMemberp(comp->parent,group)); } /*********************************************************************************************************************************************/ int AllParentsOpenp(MComponent *comp) { /* Are all groups containing this component open? */ if (comp->parent==NULL) return(1); if (comp->parent->type!=TYPE_GROUP) return(AllParentsOpenp(comp->parent)); return(CompGroupOpen(comp->parent) && AllParentsOpenp(comp->parent)); } /*****************************************************************************************************************************************/ int ParentType(MComponent *comp) { /* Returns the type of the component's parent. A component with no parent is consider a member of a group (the top-level). */ if (comp->parent==NULL) { return(TYPE_GROUP); } return(comp->parent->type); } /**************************************************************************************************************************************/ void ChangeComponentName(comp,new_name) MComponent *comp; char *new_name; { char *new; if (comp->type==TYPE_GROUP) { new=new_string(new_name); if (new==NULL) return; free(comp->name); comp->name=new; } ChangeComponentIconName(comp,new_name); } /*********************************************************************************************************************************************/ MComponent *GetComponentOfIcon(w) Widget w; { MComponent *comp; GetWidgetUserData(w,comp); return(comp); } /*********************************************************************************************************************************************/ MComponent *GetGroup(comp) /* Get the group containing this component. */ MComponent *comp; { MComponent *next; TRACE("GetGroup"); next=comp->parent; if (next==NULL) return(NULL); do { if (next->type==TYPE_GROUP) {return(next);} next=next->parent; } while (next!=NULL); return(NULL); } /*********************************************************************************************************************************************/ void GetCoordinateRange(l,min_x,min_y,max_x,max_y) /* Get the range of coordinates spanned by the components in the list. This is used by NewGroup to find the center of the group. */ MComponentList l; int *min_x,*min_y,*max_x,*max_y; { int first=1; l_elt *le; for (le=l->l_head; le!=NULL; le=le->le_next) { int x,y; MComponent *comp; comp=(MComponent *)le->le_data; x=comp->x; y=comp->y; if (first) { first=0; *max_x=*min_x=x;*max_y=*min_y=y; } else { if (x>*max_x) *max_x=x; else if (x<*min_x) *min_x=x; if (y>*max_y) *max_y=y; else if (y<*min_y) *min_y=y; } } } /**************************************************************************************************************************************/ MComponent *NewComponent(name,type,x,y) /* New components are initailly not visible. To make the component visible, call MakeVisible(comp) */ char *name; int x,y; { extern Widget network_w; MComponent *new; Widget w; TRACE("NewComponent"); /* Allocate space for new component return NULL allocation if fails. */ if ((new=(MComponent *)sim_malloc(sizeof(MComponent)))==NULL) return(NULL); new->name=NULL; /* We don't need an extra copy of the component's name. */ if (!(new->sisters=l_create())) {free(new); return(NULL);} if (!(new->children=l_create())) {lq_delete(new->sisters); free(new); return(NULL);} new->type=type; new->x=x; new->y=y; new->icon=CreateIcon(network_w,name,type,&new->x,&new->y); new->min_x=new->max_x=new->min_y=new->max_y=0; /* The min and max coordinates of the component's children */ XtVaSetValues(new->icon, XmNtranslations, the_environment.component_translations, XmNuserData, new, NULL); new->parent_linetype=0; new->sister_linetype=0; ClearStatus(new); /* Sets all status bits to a 'negative' value. (ie, not selected, not visible, closed, etc.) */ AttachChild(new,NULL); return(new); } /*******************************************************************************************************************************************/ void FreeComponent(comp_arg) /* Frees all storage associated with the component. */ void *comp_arg; { MComponent *comp=comp_arg; TRACE("FreeComponent"); if (comp->name!=NULL) free(comp->name); if (comp->sisters->l_head!=NULL) WARNING("In FreeComponent! Sister list is not empty."); lq_delete(comp->sisters); if (comp->children->l_head!=NULL) WARNING("In FreeComponent! Child list is not empty."); lq_delete(comp->children); DestroyIcon(comp->icon); free(comp); } /*********************************************************************************************************************************************/ void KillComponent(comp) /* Detach all children and attach them to the group containing the component. If any children are invisible or not drawn, make them visible and draw them. Detach component from all sisters. Detach component from parent. UndrawComponent; FreeComponent's storage and destroy it's widget. */ MComponent *comp; { MComponent *group; MComponent *parent; list *templist; l_elt *le; TRACE("KillComponent"); parent=comp->parent; group=GetGroup(comp); if (!l_empty(comp->children)) { templist=l_duplicate(comp->children); /* We use a temporary list so that change parent doesn't remove elements from the list we are traversing. */ for (le=templist->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; ChangeParent(child,group); /* Removes child from comp->children and adds it to group->children. */ if (!CompVisible(child)) { SetStatusVisible(child); } if (!CompDrawn(child)) { DrawComponent(child); } } lq_delete(templist); } DisconnectAllSisters(comp); DetachChild(comp); UndrawComponent(comp); if (CompInfoWindowOpen(comp)) CloseInformationWindow(comp); if (CompParamWindowOpen(comp)) CloseParameterWindow(comp); FreeComponent(comp); /* If this is the last component in a group, Kill the group. */ if (parent!=NULL) { if (parent->type==TYPE_GROUP) { if (parent->children->l_len==0) { KillGroup(parent); return; } } } } /*****************************************************************************************************************************************/ /* note: all members of 'list' must be direct children of the same group. */ MComponent *NewGroup(name,l) /* Create non-visible, not-drawn, open group icon positioned in the center of list. Change the parent of each list member to newgroup. Attach outside sisters as sisters of newgroup. Attach the newgroup as a child of the list parent. */ char *name; MComponentList l; { extern Widget network_w; MComponent *newgroup; TRACE("NewGroup"); if (l==NULL) {WARNING("NULL list. You may not create a group with no children"); return(NULL);} if (l_empty(l)) {WARNING("Empty list. You may not create a group with no children"); return(NULL);} /* Allocate space for new component return NULL if allocation fails. */ if ((newgroup=(MComponent *)sim_malloc(sizeof(MComponent)))==NULL) return(NULL); if ((newgroup->name=new_string(name))==NULL) {free(newgroup); return(NULL);} if (!(newgroup->sisters=l_create())) {free(newgroup->name); free(newgroup); return(NULL);} if (!(newgroup->children=l_create())) { lq_delete(newgroup->sisters); free(newgroup); return(NULL);} newgroup->type=TYPE_GROUP; ComputeCenterOfList(l,newgroup->x,newgroup->y); /* Set newgoup's position in the middle of its children. */ newgroup->icon=CreateIcon(network_w,name,TYPE_GROUP, &newgroup->x, &newgroup->y); newgroup->min_x=newgroup->max_x=newgroup->min_y=newgroup->max_y=0; /* The min and max coordinates of the component's children */ XtVaSetValues(newgroup->icon, XmNtranslations, the_environment.component_translations, XmNuserData, newgroup, NULL); ClearStatus(newgroup); /* Set all status flags to the negative condition. */ SetStatusGroupOpen(newgroup); { MComponent *parent_group; MComponentList parent_list; l_elt *le; parent_group=((MComponent *)l->l_head->le_data)->parent; /* Get the parent of the list members. */ if (parent_group!=NULL) { if (parent_group->type!=TYPE_GROUP) WARNING("In NewGroup(), the parent of the new group members is not a group."); } for (le=l->l_head; le!=NULL; le=le->le_next) { MComponent *comp; l_elt *le_sister; comp=(MComponent *)le->le_data; if (comp->parent!=parent_group) WARNING("In NewGroup(), a group member has a different parent than the others."); ChangeParent(comp,newgroup); /* Changes the pointers and sets relative position. */ /* Any sisters of the component which are not members of the new group are made sisters of the group component. */ for (le_sister=comp->sisters->l_head; le_sister!=NULL; le_sister=le_sister->le_next) { MComponent *sister; sister=(MComponent *)le_sister->le_data; if (!l_find(l,sister)) { AttachSisters(newgroup,sister); } } } AttachChild(newgroup,parent_group); /* Also sets relative position. */ } return(newgroup); } /*********************************************************************************************************************************************/ void RecursiveKill(MComponent *comp) { /* Kill all the component's children, kill the component. */ MComponentList templist; /* We need a temporary list because KillComponent removes items from the parent's list, which is the list we are traversing. */ if (!l_empty(comp->children)) { if ((templist=l_duplicate(comp->children))==NULL) {WARNING("Unable to create temporary list in Recursive Kill."); return;} l_traverse(templist,RecursiveKill); lq_delete(templist); } KillComponent(comp); } /*********************************************************************************************************************************************/ void KillGroup(MComponent *group) {/* Recursively kill the group and all it's children. */ RecursiveKill(group); } /*********************************************************************************************************************************************/ void CloseGroup(group) /* Undraw children if all parents of the group are open (Otherwise the children are already undrawn.) Set the group to visible and closed. (Draw the group icon, it's sister connections, and it's parent connection) only if all parents are open. */ MComponent *group; { int new_x, new_y; int min_x=the_environment.network_width; int min_y=the_environment.network_height; int max_x=0; int max_y=0; int parents_open; TRACE("CloseGroup"); if (group==NULL) {WARNING("You may not close the network components group."); return;} if (group->type!=TYPE_GROUP) {WARNING("Attempt to close a non-group component."); return;} if (!CompGroupOpen(group)) {WARNING("Attempt to close an already closed group."); return;} parents_open=AllParentsOpenp(group); if (l_empty(group->children)) { WARNING("Attempt to close and empty group."); return; } else { l_elt *le; for (le=group->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; max_x=max(group->x+child->rel_x, max_x); /* Compute the minimun and maximum coordinates of the */ max_y=max(group->y+child->rel_y, max_y); /* children, to center the group's icon. */ min_x=min(group->x+child->rel_x, min_x); min_y=min(group->y+child->rel_y, min_y); if (parents_open) UndrawComponent(child); } } /* Recenter the group icon over it's children. */ new_x=(max_x+min_x)/2; new_y=(max_y+min_y)/2; if (new_x != group->x || new_y != group->y) { l_elt *le; int old_groupx,old_groupy; old_groupx=group->x; old_groupy=group->y; MoveIcon(group->icon, &new_x, &new_y); group->x=new_x; group->y=new_y; /* Adjust the children's relative positions. */ for (le=group->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; child->rel_x=old_groupx+child->rel_x-new_x; child->rel_y=old_groupy+child->rel_y-new_y; } } SetStatusVisible(group); SetStatusGroupClosed(group); if (parents_open) { DrawIcon(group->icon); SetStatusDrawn(group); DrawDrawnSisterLines(group); if (group->parent!=NULL) { if (CompDrawn(group->parent)) { DrawParentLine(group); } } } } /*********************************************************************************************************************************************/ void OpenGroup(group) /* (Erase the parent connection, sister connections, and group icon) only if all parents are open. Set the group to not visible and open. draw the children only if all parent groups are open. */ MComponent *group; { int parents_open; l_elt *le; TRACE("OpenGroup"); if (group->type!=TYPE_GROUP) {WARNING("Attempt to open a non-group component."); return;} if (CompGroupOpen(group)) {WARNING("Attempt to open an already open group."); return;} parents_open=AllParentsOpenp(group); if (parents_open) { if (group->parent!=NULL) { if (CompDrawn(group->parent)) { EraseParentLine(group); } } EraseDrawnSisterLines(group); EraseIcon(group->icon); SetStatusUndrawn(group); } SetStatusInvisible(group); SetStatusGroupOpen(group); for (le=group->children->l_head; le!=NULL; le=le->le_next) { MComponent *comp; comp=(MComponent *)le->le_data; if (parents_open) DrawComponent(comp); } } /********************************************************************************************************************************************/ void Ungroup(MComponent *group) { /* Detach the group from all it's sister connections Detach from all child connections Detach from parent Free the group's storage and destroy it's widget. Note: This is exactly what KillComponent() does. */ if (group->type!=TYPE_GROUP) {WARNING("Attempt to ungroup a non-group component."); return;} KillComponent(group); } /*********************************************************************************************************************************************/ void UndrawComponents(MComponentList l) { /* TRACE("UndrawComponents"); */ l_traverse(l, UndrawComponent); } /*******************************************************************************************************************************************/ void UndrawComponent(comp) /* If the component is an open group then undraw it's children else if component is marked as drawn (go ahead and erase it) if the component is not a group, recursively undraw all Children (note: If it's a group, it's closed so the children aren't drawn anyway.) Erase line to all drawn sisters. Erase component's icon, unselect it if it is selected. Erase line to parent, if parent is drawn. */ MComponent *comp; { /* TRACE("UndrawComponent"); */ l_elt *le; if (comp->type==TYPE_GROUP && CompGroupOpen(comp)) { UndrawComponents(comp->children); } else { if (CompDrawn(comp)) { if (comp->type!=TYPE_GROUP) { for (le=comp->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; UndrawComponent(child); } } EraseDrawnSisterLines(comp); SetStatusUndrawn(comp); EraseIcon(comp->icon); if (comp->parent!=NULL) { if (CompDrawn(comp->parent)) { EraseParentLine(comp); } } } } } /****************************************************************************************************************************************/ void DrawComponents(MComponentList l) { TRACE("DrawComponents"); l_traverse(l,DrawComponent); } /*****************************************************************************************************************************************/ int FixRelativePosition (comp) /* Adjust the component's actual coordinates to reflect the component's parent-relative coordinates. Return 1 if the coordinates needed to be changed. */ MComponent *comp; { int pos_change; int parent_x,parent_y; pos_change=0; if (comp->parent==NULL) return(0); else { parent_x=comp->parent->x; parent_y=comp->parent->y; } if (parent_x+comp->rel_x!=comp->x) { comp->x=parent_x+comp->rel_x; pos_change=1; } if (parent_y+comp->rel_y!=comp->y) { comp->y=parent_y+comp->rel_y; pos_change=1; } return(pos_change); } /****************************************************************************************************************************************/ void DrawComponent(comp) /* Fix real position of comp according to it's relative position, if it's not correct. if the component is an open group, then draw it's children else, if component is marked as visible (go ahead and draw it) if parent drawn, draw line to parent. Draw component's icon. Draw a line to all drawn sisters. if the component is not a group, recursively draw all children. (note: if the component is a group, it's closed, so the children aren't visible anyway.*/ MComponent *comp; { l_elt *le; TRACE("DrawComponent"); if (CompDrawn(comp)) WARNING("DrawComponent called on an already drawn component"); if (FixRelativePosition(comp)) { /* The component's real position (comp->x,comp->y) should correspond to it's parent's real position and it's relative position (comp->rel_x,comp->rel_y). If these don't correspond we have to reset the component's relative position, and move it's widget. Note: This inconsistency is normal. It will occur whenever the parent of an undrawn child is moved. */ MoveIcon(comp->icon,&comp->x,&comp->y); } if (comp->type==TYPE_GROUP && CompGroupOpen(comp)) { DrawComponents(comp->children); } else { if (CompVisible(comp)) { if (comp->parent!=NULL) { if (CompDrawn(comp->parent)) { DrawParentLine(comp); } } DrawIcon(comp->icon); SetStatusDrawn(comp); DrawDrawnSisterLines(comp); if (comp->type!=TYPE_GROUP) { for (le=comp->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; DrawComponent(child); } } } } } /*********************************************************************************************************************************************/ void MakeInvisible(MComponent *comp) /* Unselect the component and all children. Undraw component. Set the component to not visible. */ { TRACE("MakeInvisible"); if (CompSelected(comp)) /* Unselect the component and it's children, since they are all about to become invisible. */ UnselectComponent(comp); TraverseChildren(PRE_ORDER, comp->children, UnselectComponent); UndrawComponent(comp); SetStatusInvisible((MComponent *)comp); } /********************************************************************************************************************************************/ void MakeVisible(MComponent *comp) /* Set the component to visible. If the component's parent is a group, then if all parent groups are open, draw the component. else, the component is a child of a non-group component, so draw it if it's parent is drawn. */ { TRACE("MakeVisible"); SetStatusVisible(comp); if (ParentType(comp)==TYPE_GROUP) { if (AllParentsOpenp(comp)) DrawComponent(comp); } else { if (CompDrawn(comp->parent)) DrawComponent(comp); } } /*********************************************************************************************************************************************/ void AttachChild(child,parent) /* Set pointers connecting child and parent. Set rel_x,rel_y to reflect position of child relative to parent. If child and parent are drawn, draw a connecting line. If the parent is not drawn, but the child is, erase the child. note: AttachChild to NULL means attach the child to the toplevel network components list. */ MComponent *child; MComponent *parent; { TRACE("AttachChild"); child->parent=parent; if (parent==NULL) { l_addh(network_components,child); child->rel_x=0; child->rel_y=0; } else { l_addh(parent->children,child); ComputeRelativePosition(child->rel_x,child->rel_y,child->x,child->y,parent->x,parent->y); if (CompDrawn(parent) && CompDrawn(child)) { DrawParentLine(child); } else { if (CompDrawn(child)) { UndrawComponent(child); } } } } /*********************************************************************************************************************************************/ void AttachSisters(sister1,sister2) /* Set up pointers connecting sisters. If both sisters are drawn, draw a line connecting them. */ MComponent *sister1; MComponent *sister2; { TRACE("AttachSisters"); l_addh(sister2->sisters, sister1); l_addh(sister1->sisters, sister2); if (CompDrawn(sister1) && CompDrawn(sister2)) { DrawSisterLine(sister1,sister2); } } /*********************************************************************************************************************************************/ void DetachSisters(sister1,sister2) /* Clear pointers connecting sisters. If both sisters are drawn, erase the line between them. */ MComponent *sister1,*sister2; { TRACE("DetachSisters"); l_del(sister1->sisters,sister2); l_del(sister2->sisters,sister1); if (CompDrawn(sister1) && CompDrawn(sister2)) { EraseSisterLine(sister1,sister2); } } /**********************************************************************************************************************************************/ void DetachAllSisters(comp) /* Clear pointers connecting all sisters of comp. If comp is drawn, erase the line between comp and all drawn sisters. */ MComponent *comp; { l_elt *le; TRACE("DetachAllSisters"); for (le=comp->sisters->l_head; le!=NULL; le=le->le_next) { MComponent *sister; sister=(MComponent *)le->le_data; l_del(sister->sisters,comp); if (CompDrawn(comp) && CompDrawn(sister)) { EraseSisterLine(comp,sister); } } lq_clear(comp->sisters); } /*********************************************************************************************************************************************/ MComponent *DetachChild(child) /* Clear pointers connecting child and its parent. If child and parent are drawn, erase the line connecting them.*/ MComponent *child; { TRACE("DetachChild"); if (child->parent!=NULL) { l_del(child->parent->children,child); if (CompDrawn(child->parent) && CompDrawn(child)) { EraseParentLine(child); } } else { l_del(network_components,child); } child->parent=NULL; /* This does not mean the child is now attached to the top level, since the child is not on the network components list. */ return(child); } /*********************************************************************************************************************************************/ void DrawSisterLine(sister1_arg,sister2_arg) void *sister1_arg,*sister2_arg; { GC *gc; MComponent *sister1,*sister2; extern Widget network_w; sister1=sister1_arg; sister2=sister2_arg; TRACE("DrawSisterLine"); /* gc=SelectSisterDrawLineGC(sister1->type,sister2->type); */ if (add_segment(network_segmentlist,sister1,sister2)) /* The drawing function is Xor. So if the segment is already in the list, we don't want to draw it again. */ XDrawLine(XtDisplay(network_w),XtWindow(network_w),the_environment.draw_gc,sister1->x,sister1->y,sister2->x,sister2->y); } /*********************************************************************************************************************************************/ void DrawParentLine(child) MComponent *child; { GC *gc; MComponent *parent; extern Widget network_w; extern Pixmap network_pixmap; /* TRACE("DrawParentLine"); */ if (child->parent!=NULL) { parent=child->parent; /* gc=SelectParentDrawLineGC(child->type); */ if (add_segment(network_segmentlist,child,parent)) XDrawLine(XtDisplay(network_w),XtWindow(network_w),the_environment.draw_gc,child->x,child->y,parent->x,parent->y); } } /*********************************************************************************************************************************************/ void EraseSisterLine(sister1_arg,sister2_arg) void *sister1_arg,*sister2_arg; { GC *gc; MComponent *sister1,*sister2; extern Widget network_w; extern Pixmap network_pixmap; sister1=sister1_arg; sister2=sister2_arg; TRACE("EraseSisterLine"); /* gc=SelectSisterEraseLineGC(sister1->type,sister2->type); */ if (delete_segment(network_segmentlist,sister1, sister2)) XDrawLine(XtDisplay(network_w),XtWindow(network_w),the_environment.erase_gc,sister1->x,sister1->y,sister2->x,sister2->y); } /*********************************************************************************************************************************************/ void EraseParentLine(child) MComponent *child; { GC *gc; MComponent *parent; extern Widget network_w; extern Pixmap network_pixmap; /* TRACE("EraseParentLine"); */ if (child->parent!=NULL) { parent=child->parent; /* gc=SelectParentEraseLineGC(child->type); */ if (delete_segment(network_segmentlist,child, parent)) XDrawLine(XtDisplay(network_w),XtWindow(network_w),the_environment.erase_gc,child->x,child->y,parent->x,parent->y); } } /******************************************************************************************************************************************/ void ConnectChild(MComponent *child, MComponent *parent) { TRACE("ConnectChild"); DetachChild(child); AttachChild(child,parent); } /*******************************************************************************************************************************************/ void DisconnectChild(MComponent *child) { MComponent *parent; TRACE("DisconnectChild"); parent=GetGroup(child->parent); DetachChild(child); AttachChild(child,parent); } /*******************************************************************************************************************************************/ void ConnectSisters(MComponent *sister1, MComponent *sister2) { /* AttachSisters(sister1,sister2) If the sisters are members of different groups then the group icons must be made sisters of the other sister, unless the group is the toplevel. The toplevel has no sisters since it is never closed. Note: This function assumes that sisters are direct members of a group. Anything which is a child of a non-group component should not have any sisters. */ MComponent *group1,*group2; TRACE("ConnectSisters"); AttachSisters(sister1,sister2); group1=GetGroup(sister1); group2=GetGroup(sister2); if (group1!=group2) { if (group1!=NULL) { ConnectSisters(group1,sister2); } if (group2!=NULL) { ConnectSisters(group2,sister1); } } } /*********************************************************************************************************************************************/ void DisconnectSisters(MComponent *sister1, MComponent *sister2) { /* DetachSisters(sister1,sister2) If the sisters are members of different groups, then we must detach their parent group icons as well. Note: This function assumes that sisters are direct members of a group. Anything which is a child of a non-group component should not have any sisters. */ MComponent *group1,*group2; TRACE("DisconnectSisters"); DetachSisters(sister1,sister2); group1=GetGroup(sister1); group2=GetGroup(sister2); if (group1!=group2) { if (group1!=NULL) { DisconnectSisters(group1,sister2); } if (group2!=NULL) { DisconnectSisters(group2,sister1); } } } /******************************************************************************************************************************************/ void DisconnectAllSisters(MComponent *comp) { MComponentList temp; l_elt *le; TRACE("DisconnectAllSisters"); temp=l_duplicate(comp->sisters); /* We need a temporary list because DisconectSisters will delete elements from comp->sisters. */ for (le=temp->l_head; le!=NULL; le=le->le_next) { MComponent *sister; sister=(MComponent *)le->le_data; DisconnectSisters(comp,sister); } lq_delete(temp); } /******************************************************************************************************************************************/ void EraseDrawnSisterLines(comp) MComponent *comp; { l_elt *le; /* TRACE("EraseDrawnSistersLines");*/ for (le=comp->sisters->l_head; le!=NULL; le=le->le_next) { MComponent *sister; sister=(MComponent *)le->le_data; if (CompDrawn(sister)) { EraseSisterLine(comp,sister); } } } /********************************************************************************************************************************************/ void DrawDrawnSisterLines(comp) MComponent *comp; { l_elt *le; /* TRACE("DrawDrawnSisterLines");*/ for (le=comp->sisters->l_head; le!=NULL; le=le->le_next) { MComponent *sister; sister=(MComponent *)le->le_data; if (CompDrawn(sister)) { DrawSisterLine(comp,sister); } } } /********************************************************************************************************************************************/ get_extreme_coords(MComponentList complist, int x, int y, MComponent *comp) { /* x and y are the correct x,y coords of complist's parent.*/ int compx,compy; l_elt *le; compx=comp->x; compy=comp->y; for (le=complist->l_head; le!=NULL; le=le->le_next) { MComponent *test; int testx,testy; int testw,testh; test=(MComponent *)le->le_data; testx=x+test->rel_x; testy=y+test->rel_y; GetIconDimensions(test->icon, &testw, &testh); comp->min_x=min((testx-testw/2)-compx,comp->min_x); comp->min_y=min((testy-testh/2)-compy,comp->min_y); comp->max_x=max((testx+testw/2)-compx,comp->max_x); comp->max_y=max((testy+testh/2)-compy,comp->max_y); if (!l_empty(test->children)) get_extreme_coords(test->children, testx, testy, comp); } } /********************************************************************************************************************************************/ void ComputeBorders(MComponent *comp) /* This computes the minimum and maximum relative coordinates of all the component's children and leaves the result in comp->min_x, comp->min_y, comp->max_x, comp->max_y. */ { int w,h; GetIconDimensions(comp->icon, &w, &h); comp->min_x=-w/2; comp->max_x=w/2; comp->min_y=-h/2; comp->max_y=h/2; if (!l_empty(comp->children)) { get_extreme_coords(comp->children, comp->x, comp->y, comp); } } /********************************************************************************************************************************************/ SegmentList *child_segmentlist; SegmentList *sister_segmentlist; void GetChildSegments(SegmentList *sl,MComponent *comp); void GetSisterSegments(SegmentList *sl, MComponent *comp); /********************************************************************************************************************************************/ void InitializeSegmentArrays(MComponent *comp) { child_segmentlist=create_segmentlist(); sister_segmentlist=create_segmentlist(); GetChildSegments(child_segmentlist, comp); GetSisterSegments(sister_segmentlist, comp); } /********************************************************************************************************************************************/ void UpdateNetworkSegmentArray() { add_segments(network_segmentlist, child_segmentlist); add_segments(network_segmentlist, sister_segmentlist); destroy_segmentlist(child_segmentlist); destroy_segmentlist(sister_segmentlist); XClearWindow(the_environment.the_display, XtWindow(network_w)); draw_segments(network_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.draw_gc); } /********************************************************************************************************************************************/ void GetChildSegments(SegmentList *sl,MComponent *comp) { /* Child segment adjust both coordinates when moved. */ l_elt *le; for (le=comp->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; if (CompDrawn(child)) { delete_segment(network_segmentlist, comp, child); add_segment(sl, comp, child); GetChildSegments(sl,child); } } } /********************************************************************************************************************************************/ void GetSisterSegments(SegmentList *sl, MComponent *comp) { /* Sister segments only adjust their first coordinate when moved. */ l_elt *le; if (comp->parent!=NULL) { if (CompDrawn(comp->parent)) { delete_segment(network_segmentlist, comp, comp->parent); add_segment(sl, comp, comp->parent); } } for (le=comp->sisters->l_head; le!=NULL; le=le->le_next) { MComponent *sister; sister=(MComponent *)le->le_data; if (CompDrawn(sister)) { delete_segment(network_segmentlist, comp, sister); add_segment(sl, comp, sister); } } } /********************************************************************************************************************************************/ void AdjustChildSegments(SegmentList *sl, int diff_x, int diff_y) { XSegment *line_array=sl->line_array; int i; for (i=0;inum_lines;i++) { line_array[i].x1+=diff_x; line_array[i].x2+=diff_x; line_array[i].y1+=diff_y; line_array[i].y2+=diff_y; } } /********************************************************************************************************************************************/ void AdjustSisterSegments(SegmentList *sl, int diff_x, int diff_y) { XSegment *line_array=sl->line_array; int i; for (i=0;inum_lines;i++) { line_array[i].x1+=diff_x; line_array[i].y1+=diff_y; } } /********************************************************************************************************************************************/ /* MoveComponentSpecial assumes that ComputeBorders and InitializeSegment arrays have already been call, and UpdateSegmentArrays will be called later. MoveComponent does not assume this. This function is useful for processing a continuous stream of moves on a single component, which occurs when a component is dragged. For a single isolated component move, MoveComponent should be called. Both MoveComponent and MoveComponentSpecial rely on the same global variables: child_segmentlist, sister_segmentlist */ void MoveComponentSpecial(comp, diff_x, diff_y) MComponent *comp; { l_elt *le; /* TRACE("MoveComponent"); */ /* Check that we are not moving any of the component's children off the edge of the network. */ /* if (diff_x>0) if (comp->x+comp->max_x+diff_x>the_environment.network_width-1) diff_x=the_environment.network_width-1-comp->x-comp->max_x;*/ if (diff_x<0) if (comp->x+comp->min_x+diff_x<0) diff_x=-comp->x-comp->min_x; /* if (diff_y>0) if (comp->y+comp->max_y+diff_y>the_environment.network_height-1) diff_y=the_environment.network_height-1-comp->y-comp->max_y;*/ if (diff_y<0) if (comp->y+comp->min_y+diff_y<0) diff_y=-comp->y-comp->min_y; if (diff_x==0 && diff_y==0) return; draw_segments(child_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.erase_gc); draw_segments(sister_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.erase_gc); for (le=comp->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; if (CompDrawn(child)) { MoveChild(child,diff_x,diff_y); } } comp->x+=diff_x; comp->y+=diff_y; MoveIcon(comp->icon,&comp->x,&comp->y); comp->rel_x+=diff_x; comp->rel_y+=diff_y; AdjustChildSegments(child_segmentlist, diff_x, diff_y); AdjustSisterSegments(sister_segmentlist, diff_x, diff_y); draw_segments(child_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.draw_gc); draw_segments(sister_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.draw_gc); XFlush(the_environment.the_display); } /********************************************************************************************************************************************/ void MoveComponent(comp, diff_x, diff_y) MComponent *comp; { l_elt *le; /* TRACE("MoveComponent"); */ ComputeBorders(comp); InitializeSegmentArrays(comp); /* Check that we are not moving any of the component's children off the edge of the network. */ /* if (diff_x>0) if (comp->x+comp->max_x+diff_x>the_environment.network_width-1) diff_x=the_environment.network_width-1-comp->x-comp->max_x;*/ if (diff_x<0) if (comp->x+comp->min_x+diff_x<0) diff_x=-comp->x-comp->min_x; /* if (diff_y>0) if (comp->y+comp->max_y+diff_y>the_environment.network_height-1) diff_y=the_environment.network_height-1-comp->y-comp->max_y;*/ if (diff_y<0) if (comp->y+comp->min_y+diff_y<0) diff_y=-comp->y-comp->min_y; if (diff_x==0 && diff_y==0) return; draw_segments(child_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.erase_gc); draw_segments(sister_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.erase_gc); for (le=comp->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; if (CompDrawn(child)) { MoveChild(child,diff_x,diff_y); } } comp->x+=diff_x; comp->y+=diff_y; MoveIcon(comp->icon,&comp->x,&comp->y); comp->rel_x+=diff_x; comp->rel_y+=diff_y; AdjustChildSegments(child_segmentlist, diff_x, diff_y); AdjustSisterSegments(sister_segmentlist, diff_x, diff_y); draw_segments(child_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.draw_gc); draw_segments(sister_segmentlist, the_environment.the_display, XtWindow(network_w), the_environment.draw_gc); XFlush(the_environment.the_display); UpdateNetworkSegmentArray(); } /*******************************************************************************************************************************************/ void MoveChild(comp,diff_x,diff_y) /* if MoveIcon of self is successful; Recursively move drawn children. */ MComponent *comp; { l_elt *le; comp->x+=diff_x; comp->y+=diff_y; MoveIcon(comp->icon,&comp->x,&comp->y); for (le=comp->children->l_head; le!=NULL; le=le->le_next) { MComponent *child; child=(MComponent *)le->le_data; if (CompDrawn(child)) { MoveChild(child,diff_x,diff_y); } } } /*********************************************************************************************************************************************/ void TraverseNetworkWithArguments(order,func,args) int order; /* POST_ORDER or PRE_ORDER */ void (*func)(); void *args; { TRACE("TraverseNetworkWithArguments"); if (!l_empty(network_components)) { TraverseChildrenWithArguments(order,network_components,func,args); } } /*********************************************************************************************************************************************/ void TraverseChildrenWithArguments(order,l,func,args) /* IMPORTANT: The traversal must be done in pre-order for MakeVisible to work, MakeVisible checks to see if the parents are drawn before drawing the children. */ int order; MComponentList l; void (*func)(); void *args; { l_elt *le; TRACE("TraverseChildrenWithArguments"); for (le=l->l_head; le!=NULL; le=le->le_next) { MComponent *comp; comp=(MComponent *)le->le_data; if (order==PRE_ORDER) { /* node first */ func(comp,args); if (!l_empty(comp->children)) TraverseChildrenWithArguments(order,comp->children,func,args); } else { /* children first */ if (!l_empty(comp->children)) TraverseChildrenWithArguments(order,comp->children,func,args); func(comp,args); } } } /*********************************************************************************************************************************************/ void TraverseNetwork(order,func) int order; void (*func)(void *); { TRACE("TraverseNetwork"); if (!l_empty(network_components)) { TraverseChildren(order,network_components,func); } } /*********************************************************************************************************************************************/ void TraverseChildren(order,l,func) /* IMPORTANT: Traversal needs to be done in pre-order. */ int order; MComponentList l; void (*func)(); { l_elt *le; TRACE("TraverseChildren"); for (le=l->l_head; le!=NULL; le=le->le_next) { MComponent *comp; comp=(MComponent *)le->le_data; if (order==PRE_ORDER) { /* node first */ func(comp); if (!l_empty(comp->children)) TraverseChildren(order,comp->children,func); } else { /* children first */ if (!l_empty(comp->children)) TraverseChildren(order,comp->children,func); func(comp); } } } /* The following are routines for selecting and unselecting components. */ /*******************************************************************************************************************************************/ void UnselectComponent(MComponent *comp) { if (CompSelected(comp)) { l_del(selected,comp); SetStatusUnselected(comp); UnselectComponentIcon(comp); } } /*******************************************************************************************************************************************/ void SelectComponent(MComponent *comp) { if (!CompSelected(comp)) { SelectComponentIcon(comp); SetStatusSelected(comp); l_addh(selected,comp); } } /******************************************************************************************************************************************/ void UnselectAll() { l_elt *le; for(le=selected->l_head; le!=NULL; le=le->le_next) { MComponent *comp; comp=(MComponent *)le->le_data; SetStatusUnselected(comp); UnselectComponentIcon(comp); } lq_clear(selected); } /*******************************************************************************************************************************************/ void UnselectGroupMembers(MComponent *group) /* Unselect all members of the group. This is called when a group is closed, so that we don't have non-visible selected components. */ { l_elt *le; list *templist; if (!l_empty(selected)) { templist=l_duplicate(selected); for(le=templist->l_head; le!=NULL; le=le->le_next) { MComponent *comp; comp=(MComponent *)le->le_data; if (GroupMemberp(comp,group)) { l_del(selected,comp); SetStatusUnselected(comp); UnselectComponentIcon(comp); } } lq_delete(templist); } }