/* $Id: comp_trans.c,v 10.1 92/10/06 23:02:36 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. */ #include #include "xm-comp_trans.h" #include "comptypes.h" #include "list.h" #include "xm-network.h" #include "xm-util.h" #include "xm-icon.h" #include "xm-param_w.h" #include "xm-info_w.h" #include "xm-lines.h" #include "xm-main_w.h" /* This file contains the following translation routines: mars.networkWTranslations: rubberbox() draws a rubber box to select components mars.moveWindowTranslations: move_window(); drag a window raise_window(); raise a window lower_window(); lower a window mars.componentTranslations: move_component(); drag a component raise_component(); raise a component lower_component(); lower a component join_components(); make components neighbors select_component(); select a components open_group(); open a group close_group(); close a group make_peer(); make peers */ /**************************************************** Translation Routines **********************************************************/ /*=================================== Action Routines for mars.networkWindowTranslations =========================================*/ void SelectByCoordinates(MComponent *comp, void *arg); typedef struct { int x1,y1,x2,y2; } box; /*************************************************************************************************************************************/ /* This is the translation routine used to draw a rubber box in the network window.*/ void rubberbox(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { static String poss_args[]={"start","move","release"}; static start_x,start_y,prev_w,prev_h; box c; switch(which_string(argv[0],poss_args,3)) { case 0: start_x=event->x; start_y=event->y; prev_w=0; prev_h=0; XDrawRectangle(XtDisplay(w),XtWindow(w),the_environment.rubberbox_gc,start_x,start_y,prev_w,prev_h); break; case 1: XDrawRectangle(XtDisplay(w),XtWindow(w),the_environment.rubberbox_gc,start_x,start_y,prev_w,prev_h); prev_w=event->x-start_x; prev_h=event->y-start_y; if (prev_w<1) prev_w=1; if (prev_h<1) prev_h=1; XDrawRectangle(XtDisplay(w),XtWindow(w),the_environment.rubberbox_gc,start_x,start_y,prev_w,prev_h); break; case 2: XDrawRectangle(XtDisplay(w),XtWindow(w),the_environment.rubberbox_gc,start_x,start_y,prev_w,prev_h); /* Find all visible components whose coordinates lie in the region, and selected them. */ if (start_x(b).x1 && x<(b).x2 && y>(b).y1 &&y<(b).y2) void SelectByCoordinates(MComponent *comp, void *arg) { /* Select the component if it's within the box passed in 'arg'. */ box *b=arg; if (CompVisible(comp) && AllParentsOpenp(comp)) { if (inbox(*b,comp->x,comp->y)) SelectComponent(comp); } } /******************************************************************************************************************************************/ /* This routine is a translation function called when the user moves an information window. */ void move_window(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { String poss_args[]={"grab","move","release"}; static int window_x,window_y; static int mouse_x,mouse_y; static Widget grabbed=NULL; Position mx,my; switch(which_string(argv[0],poss_args,XtNumber(poss_args))) { case 0: if (!grabbed) { GetWidgetUserData(w,grabbed); GetWidgetCoordinates(grabbed,window_x,window_y); mouse_x=event->x_root; mouse_y=event->y_root; RWTranslateCoords((Position)event->x_root, (Position)event->y_root, XtParent(grabbed), &mx, &my); mouse_x=(int)mx; mouse_y=(int)my; if (mouse_x<0) mouse_x=0; if (mouse_y<0) mouse_y=0; } break; case 1: { int diff_x,diff_y; int new_mouse_x, new_mouse_y; if (!grabbed) return; new_mouse_x=event->x_root; new_mouse_y=event->y_root; RWTranslateCoords((Position)event->x_root, (Position)event->y_root, XtParent(grabbed), &mx, &my); new_mouse_x=(int)mx; new_mouse_y=(int)my; if (new_mouse_x<0) new_mouse_x=0; if (new_mouse_y<0) new_mouse_y=0; diff_x=new_mouse_x-mouse_x; diff_y=new_mouse_y-mouse_y; window_x+=diff_x; window_y+=diff_y; mouse_x=new_mouse_x; mouse_y=new_mouse_y; SetWidgetCoordinates(grabbed, window_x, window_y); } break; case 2: grabbed=NULL; break; default: WARNING("Unknown case in move_window\n"); } } /*******************************************************************************************************************************************/ /* This is a translation routine to raise a window. It is used in mars.moveWindowTranslations. */ void raise_window(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { Widget window; GetWidgetUserData(w,window); RaiseWidget(window); } /*******************************************************************************************************************************************/ /* This is a translation routine to lower a window. It is used in mars.moveWindowTranslations. */ void lower_window(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { Widget window; GetWidgetUserData(w,window); LowerWidget(window); } /*******************************************************************************************************************************************/ /*====================================== Action Routines for mars.componentTranslations =============================================*/ void lower_component(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { LowerWidget(w); } /*******************************************************************************************************************************************/ void raise_component(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { RaiseWidget(w); } /*******************************************************************************************************************************************/ /* The translation routine called when the user pressed the button-key combination to close a group. */ void close_group(w,event,args,num_args) Widget w; XButtonEvent *event; String *args; int *num_args; { MComponent *comp,*group; comp=GetComponentOfIcon(w); group=GetGroup(comp); if (group!=NULL) { /* Don't close the top level group. */ UnselectGroupMembers(group); CloseGroup(group); if (CompInfoWindowOpen(group)) SetGroupOpenCloseButton(group); } } /*******************************************************************************************************************************************/ /* The translation routine called when the user pressed the button-key combination to open a group. */ void open_group(w,event,args,num_args) Widget w; XButtonEvent *event; String *args; int *num_args; { MComponent *comp; comp=GetComponentOfIcon(w); if (comp->type!=TYPE_GROUP) { printx("Not a group!"); sleep(2); xprintclear(); } else { if (CompSelected(comp)) UnselectComponent(comp); OpenGroup(comp); if (CompInfoWindowOpen(comp)) SetGroupOpenCloseButton(comp); } } /*******************************************************************************************************************************************/ /* The translation routine called when a user selects a component. */ void select_component(w,event,args,num_args) Widget w; XButtonEvent *event; String *args; int *num_args; { MComponent *comp; comp=GetComponentOfIcon(w); if (CompSelected(comp)) { UnselectComponent(comp); } else { SelectComponent(comp); } } /*******************************************************************************************************************************************/ MComponent *comp_grabbed=NULL; /* The component grabbed by the move component routine. */ /* This routine moves a component when the user clicks on it and drags the mouse. I use the MoveComponentSpecial routine to take advantage of the fact that this component will probably be moved a number of times before it is dropped. With MoveComponentSpecial, the ComputeBorders and InitializeSegmentArrays, are only called once, when the component is grabbed. UpdateSegmentArrays is called only once, when the component is released. */ void move_component(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { static String poss_args[]={"grab","move","release"}; static int mouse_x,mouse_y; int diff_x,diff_y; int new_mouse_x, new_mouse_y; Position mx,my; switch(which_string(argv[0],poss_args,3)) { case 0: /* grab */ if (comp_grabbed) return; comp_grabbed=GetComponentOfIcon(w); ComputeBorders(comp_grabbed); /* Set the max and min coordinates of the component's children, so that we don't push any children off the edge of the network. */ InitializeSegmentArrays(comp_grabbed); /* Make a list of all the segments that will be affected by moving this component and remove them from the network_segmentlist. */ RWTranslateCoords((Position)event->x_root, (Position)event->y_root, network_w, &mx, &my); mouse_x=(int)mx; mouse_y=(int)my; if (mouse_x<0) mouse_x=0; if (mouse_y<0) mouse_y=0; break; case 1: /* move */ if (!comp_grabbed) return; RWTranslateCoords((Position)event->x_root, (Position)event->y_root, network_w, &mx, &my); new_mouse_x=(int)mx; new_mouse_y=(int)my; if (new_mouse_x<0) new_mouse_x=0; if (new_mouse_y<0) new_mouse_y=0; diff_x=new_mouse_x-mouse_x; diff_y=new_mouse_y-mouse_y; mouse_x=new_mouse_x; mouse_y=new_mouse_y; MoveComponentSpecial(comp_grabbed,diff_x,diff_y); /* The regular MoveComponent routine calls ComputeBorders, InitializeSegmentArrays, and UpdateSegmentArrays within the routine. MoveComponentSpecial does not. */ break; case 2: /* release */ if (!comp_grabbed) return; UpdateNetworkSegmentArray(); /* Put the moved segments back into the network_segmentlist. */ comp_grabbed=NULL; break; } } /*******************************************************************************************************************************************/ /* The translation routine for making two component neighbors (connecting them by a line). */ void join_components(w,event,args,num_args) Widget w; XButtonEvent *event; String *args; int *num_args; { static MComponent *selection1=NULL; MComponent *selection2; if (!selection1) { selection1=GetComponentOfIcon(w); if (selection1->type==TYPE_GROUP || selection1->type==TYPE_METER) { /* Meters and groups don't have neighbors. */ selection1=NULL; return; } } else { int they_are_neigh; caddr_t result_flag; NEIGHBOR *neighbor; COMPONENT *scomponent1,*scomponent2; selection2=GetComponentOfIcon(w); if (selection1==selection2 || selection2->type==TYPE_GROUP || selection2->type==TYPE_METER) { selection2=NULL; return; } scomponent1=selection1->scomponent; scomponent2=selection2->scomponent; they_are_neigh = FALSE; for (neighbor = (NEIGHBOR *) scomponent1->co_neighbors->l_head; neighbor != NULL; neighbor = neighbor->n_next) { if (neighbor->n_c == scomponent2) { they_are_neigh = TRUE; break; } } if (they_are_neigh) { scomponent1->co_action(NULL,scomponent1, EV_UNEIGHBOR, NULL, scomponent2); scomponent2->co_action(NULL,scomponent2, EV_UNEIGHBOR, NULL, scomponent1); disconnect_two_components(selection1,selection2); } else { if (scomponent1->co_action(NULL, scomponent1, EV_NEIGHBOR, NULL, scomponent2)) { if (scomponent2->co_action(NULL, scomponent2, EV_NEIGHBOR, NULL, scomponent1)) connect_two_components(selection1,selection2); else scomponent1->co_action(NULL, scomponent1, EV_UNEIGHBOR, NULL, scomponent2); } } /* Update the component's parameters windows, in case the parameters were changed when we connected them. */ UpdateParameterWindow(selection1); UpdateParameterWindow(selection2); selection1=NULL; selection2=NULL; } } /*******************************************************************************************************************************************/ /* This routine uses the parent_types specified in comptypes.h to figure out whether the components should be sisters or parent-child. The return values are as follows: 0 = SISTERS 1 = CHILD:COMP1, PARENT:COMP2 -1 = PARENT:COMP1, CHILD:COMP2 */ int get_relationship(MComponent *comp1, MComponent *comp2) { int *pt1,*pt2; int t1,t2; t1=comp1->type; t2=comp2->type; for (pt1=component_types[t1].parent_types; *pt1>=0; pt1++) { if (*pt1==t2) { /* comp1 is a child of comp2 */ return(1); } } for (pt2=component_types[t2].parent_types; *pt2>=0; pt2++) { if (*pt2==t1) { /* comp2 is a child of comp1 */ return(-1); } } return(0); } /*******************************************************************************************************************************************/ /* This routine draws a line between two components after they are made neighbors. */ void connect_two_components(MComponent *comp1, MComponent *comp2) { TRACE("connect_two_components"); switch(get_relationship(comp1,comp2)) { case -1: ConnectChild(comp2,comp1); break; case 0: ConnectSisters(comp1,comp2); break; case 1: ConnectChild(comp1,comp2); break; } } /*******************************************************************************************************************************************/ /* This routine is used to erase the line between two components after they have been unneighbored. */ void disconnect_two_components(MComponent *comp1, MComponent *comp2) { TRACE("disconnect_two_components"); switch(get_relationship(comp1,comp2)) { case -1: DisconnectChild(comp2); break; case 0: DisconnectSisters(comp1,comp2); break; case 1: DisconnectChild(comp1); break; } } /*******************************************************************************************************************************************/ /* The translation routine for making peers. */ void make_peer(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { static MComponent *selection1=NULL; MComponent *selection2; if (!selection1) { selection1=GetComponentOfIcon(w); if (selection1->type==TYPE_GROUP || selection1->type==TYPE_METER) { selection1=NULL; return; } } else { caddr_t result_flag; COMPONENT *scomponent1,*scomponent2; selection2=GetComponentOfIcon(w); if (selection1==selection2 || selection2->type==TYPE_GROUP || selection2->type==TYPE_METER) { selection2=NULL; return; } scomponent1=selection1->scomponent; scomponent2=selection2->scomponent; result_flag = (caddr_t) (scomponent1->co_action)(NULL,scomponent1, EV_MK_PEER, NULL,scomponent2); if (result_flag) { (scomponent2->co_action)(NULL,scomponent2, EV_MK_PEER, NULL,scomponent1); peer_add(scomponent2, scomponent1); /* If the parameter windows are open, we have to update the peer parameter. */ if (CompParamWindowOpen(selection1) || (CompParamWindowOpen(selection2))) { update_meters_and_info_windows(); } selection1=NULL; selection2=NULL; } } }