/* $Id: edit.c,v 10.1 92/10/06 23:03:15 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 #include #include #include #include #include #include #include #include #include "xm-edit.h" #include "comptypes.h" #include "xm-comp_trans.h" #include "xm-util.h" #include "list.h" #include "xm-network.h" #include "xm-icon.h" #include "xm-main_w.h" #include "xm-meters.h" #define E_CREATE_COMPONENT 1 #define E_REMOVE_SELECTION 2 #define E_GROUP_SELECTION 3 #define E_UNSELECT_ALL 4 /* This file contains routines associated with the edit submenu heading on the main menu. It also contains the following routines for creating and destoying components: pop_comp_window(COMPONENT *scomponent, int x, int y) Create the graphic object for a simulator component. unpop_comp_window(COMPONENT *scomponent); Destroy the graphic object for a simulator component. CreateComponent(MComponent *comp); Create the simulator component and it's graphic object. DestroyComponent(MComponent *comp); Destroy the simulator component and it's graphic object (this destroys meters and groups too). RecursiveDestroyComponent(MComponent *comp); Destroy the component and all it's children. */ int CreateComponent(int type, int x, int y); void edit_create_cb(Widget); void edit_remove_cb(Widget); void edit_group_cb(Widget); void edit_unsel_cb(Widget); void create_comp_done_cb(Widget w, Widget form); void selection_confirm_kill_cb(Widget widget); MenuItem edit_items[] = { {"Create Component",&xmPushButtonGadgetClass,'\0',NULL,NULL,XmNactivateCallback,edit_create_cb,(XtPointer)E_CREATE_COMPONENT,(MenuItem *)NULL,NULL}, {"",&xmSeparatorGadgetClass,'\0',NULL,NULL,NULL,NULL,NULL,(MenuItem *)NULL,NULL}, {"Kill Selection",&xmPushButtonGadgetClass,'\0',NULL,NULL,XmNactivateCallback,selection_confirm_kill_cb,(XtPointer)E_REMOVE_SELECTION,(MenuItem *)NULL,NULL}, {"Group Selection",&xmPushButtonGadgetClass,'\0',NULL,NULL,XmNactivateCallback,edit_group_cb,(XtPointer)E_GROUP_SELECTION,(MenuItem *)NULL,NULL}, {"Unselect All",&xmPushButtonGadgetClass,'\0',NULL,NULL,XmNactivateCallback,edit_unsel_cb,(XtPointer)E_UNSELECT_ALL,(MenuItem *)NULL,NULL}, NULL }; Widget create_component_box=NULL; /*************************************************************************************************************************/ /* The callback called when the group selection button is pressed. */ void edit_group_cb(widget) Widget widget; { /* Note: Only direct children of the same group may be grouped into a new group. Make a temporary list of selected children to be grouped (ie., direct children of group components.) If any components are direct children of different groups, fail. Else, call NewGroup on templist. */ /* Extract the components from the selected list which are direct children of a group and put them in templist. */ l_elt *le; TRACE("edit_group_cb"); if (!l_empty(selected)) { MComponentList templist; int first_group=1; int fail=0; if (!(templist=l_create())) {WARNING("Failure to create temporary list."); return;} for (le=selected->l_head; le!=NULL; le=le->le_next) { MComponent *comp,*parent_group; comp=(MComponent *)le->le_data; if (ParentType(comp)==TYPE_GROUP) { /* If it's a child of a group we add it to the templist. */ if (first_group) { first_group=0; parent_group=GetGroup(comp); } else { /* Check that this component is in the same group as all others. */ if (GetGroup(comp)!=parent_group) { printx("You may not group components belonging to two separate groups.\n"); sleep(2); xprintclear(); fail=1; break; } } l_addh(templist,comp); } } if (fail) { lq_delete(templist); return; /* Group selection failed, we leave all the selected components as they are. */ } /* Create a new group with templist. */ if (!l_empty(templist)) { MComponent *comp; char *default_name; default_name=GetNextDefaultName(GetTypeName(TYPE_GROUP)); if ((comp=NewGroup(default_name,templist))!=NULL) { comp->scomponent=NULL; /* Groups have no corresponding simulator component. */ CloseGroup(comp); } else WARNING("Failure to create a new group.\n"); } lq_delete(templist); /* Unselect all selected components. */ UnselectAll(); } return; } /*******************************************************************************************************************************************/ /* The callback called when the kill selection button is pressed. */ void selection_confirm_kill_cb(widget) Widget widget; { static Widget question_dialog=NULL; Position x,y; if (l_empty(selected)) return; if (!question_dialog) { question_dialog=XmCreateQuestionDialog(main_w,"confirm_kill_selection_dialog",NULL,0); XtAddCallback(question_dialog,XmNokCallback,(XtCallbackProc)edit_remove_cb,NULL); XtAddCallback(question_dialog,XmNokCallback,(XtCallbackProc)XtUnmanageChild,NULL); XtAddCallback(question_dialog,XmNcancelCallback,(XtCallbackProc)XtUnmanageChild,NULL); } else { XRaiseWindow(XtDisplay(question_dialog),XtWindow(XtParent(question_dialog))); } /* WWTranslateCoords(widget,network_w,(Position)0,(Position)0,&x,&y); SetWidgetCoordinates(question_dialog,(int)x,(int)y);*/ XtManageChild(question_dialog); } /*************************************************************************************************************************/ /* The callback called by the ok button in the confirm kill selection dialog. */ void edit_remove_cb(widget) Widget widget; { /* For each element in the selected list, call DestroyComponent. Clear the selected list. Note: We need to use a temporary list to avoid traversing the same list which we are removing components from. */ list *temp_list; l_elt *le; temp_list=l_duplicate(selected); for (le=temp_list->l_head; le!=NULL; le=le->le_next) { MComponent *comp; comp=(MComponent *)le->le_data; DestroyComponent(comp); } lq_delete(temp_list); lq_clear(selected); } /*************************************************************************************************************************/ /* The following routine build the create components box, that is popped up when Create Component is selected from the edit submenu. */ #define COL_SPACING 100 /* Should be maximum icon width. */ #define ROW_SPACING 20 /* " " " " height. */ #define X_OFFSET 50 #define Y_OFFSET 10 #define ICON_COLUMNS 5 Widget BuildCreateComponentsBox(Widget parent) { Widget form; Widget icon_box,label; Widget done_button; int count,i; unsigned row,col,box_w,box_h; int x,y; form=XtVaCreateWidget("component_selection_box", xmFormWidgetClass, parent, NULL); icon_box=XtVaCreateManagedWidget("icon_box",xmBulletinBoardWidgetClass,form, NULL); /* Fill in all the possible component icons */ row=0; col=0; box_w=0; box_h=0; for(i=0;component_types[i].class!=0;i++) { Widget icon; x=X_OFFSET+col*COL_SPACING; y=Y_OFFSET+row*ROW_SPACING; icon=CreateIcon(icon_box, component_types[i].typename, i, &x, &y); col=(col + 1) % ICON_COLUMNS; if (col==0) { row+=1; } XtVaSetValues(icon, XmNuserData, i, XmNtranslations, the_environment.create_component_translations, NULL); DrawIcon(icon); } if (row>0) box_w=X_OFFSET*2+COL_SPACING*ICON_COLUMNS; else box_w=X_OFFSET*2+COL_SPACING*col; box_h=Y_OFFSET*2+ROW_SPACING*row; XtVaSetValues(icon_box,XmNwidth,box_w,XmNheight,box_h,NULL); XtManageChild(icon_box); done_button=XtVaCreateManagedWidget("done_button",xmPushButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, icon_box, NULL); XtAddCallback(done_button,XmNactivateCallback,(XtCallbackProc)create_comp_done_cb,form); return(form); } /*************************************************************************************************************************/ /* This is the callback called when Create Component is selected. */ void edit_create_cb(widget) Widget widget; { XtManageChild(create_component_box); RaiseWidget(create_component_box); } /*************************************************************************************************************************/ /* This is called from the destroy_world routine to close the create components box. */ void CloseCreateComponentBox() { if (create_component_box) XtUnmanageChild(create_component_box); } /*************************************************************************************************************************/ /* The callback called when the close button in the create components box is pressed. */ void create_comp_done_cb(Widget w, Widget form) { XtUnmanageChild(form); } /*************************************************************************************************************************/ /* The translation routine for mars.createComponentTranslations which drags a component icon out of the create components box and drops it into the network window. */ void create_comp_drag_icon(icon,event,argv,argc) Widget icon; XButtonEvent *event; String *argv; int *argc; { static Widget grab_icon=NULL; static int grab_icon_x,grab_icon_y; static int mouse_x,mouse_y; static int type; static String poss_args[]={"grab","drag","release"}; Position mx,my; switch(which_string(argv[0],poss_args,XtNumber(poss_args))) { case 0: { int network_x,network_y; Position netrootrel_x,netrootrel_y; int icon_x,icon_y; Position icx,icy; Position iconrootrel_x,iconrootrel_y; if (grab_icon) return; 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; XtTranslateCoords(network_w,(Position)0,(Position)0,&netrootrel_x,&netrootrel_y); TranslateIconCoords(icon,(Position)0,(Position)0,&iconrootrel_x,&iconrootrel_y); grab_icon_x=(int)iconrootrel_x-(int)netrootrel_x; grab_icon_y=(int)iconrootrel_y-(int)netrootrel_y; GetWidgetUserData(icon,type); grab_icon=CreateIcon(network_w, component_types[type].typename, type, &grab_icon_x, &grab_icon_y); DrawIcon(grab_icon); RaiseWidget(scroll_w); } break; case 1: { int diff_x,diff_y; int new_mouse_x, new_mouse_y; if (!grab_icon) 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; grab_icon_x+=diff_x; grab_icon_y+=diff_y; MoveIcon(grab_icon,&grab_icon_x,&grab_icon_y); } break; case 2: { MComponent *comp; COMPONENT *the_component; PFP the_action; char *default_name; if (!grab_icon) return; CreateComponent(type,grab_icon_x,grab_icon_y); DestroyIcon(grab_icon); /* Drop the icon. */ grab_icon=NULL; RaiseWidget(create_component_box); } break; default: WARNING("Unknown case in create_comp_drag_icon"); } } /***********************************************************************************************************************************************/ /* This routine creates a simulator component of the given type, and its graphic object. */ int CreateComponent(int type, int x, int y) { /* Create a new component of the given type. This is only used for creating simulator components (not groups or meters). It creates a component with EV_CREATE and adds it to 'comps'. Pop_comp_window does not draw the component. To make the component visible, call MakeVisible(scomponent->co_picture) */ char name_string[30]; COMPONENT *the_component; PFP the_action; char *default_name; default_name=GetNextDefaultName(GetTypeName(type)); the_action=component_types[type].action; the_component=(COMPONENT *) the_action(NULL, NULL, EV_CREATE, NULL, default_name); if (the_component!=NULL) { le_addt(comps,the_component); if (NULL==(the_component->co_picture=(COMP_OBJECT)pop_comp_window(the_component,x,y))) { WARNING("Failure to create a network component."); return(FALSE); } MakeVisible((MComponent *)the_component->co_picture); } return(TRUE); } /***********************************************************************************************************************************************/ /* This will destroy any network component and its simulator counterpart. */ void DestroyComponent(MComponent *comp) { if (comp->type==TYPE_GROUP) { l_traverse(comp->children, RecursiveDestroyComponent); /* This should destroy all group members and the group too.*/ } else if (comp->type==TYPE_METER) { METER *meter; meter=(METER *)comp->scomponent; DestroyMeter(meter->scomponent, meter->parameter); } else { PFP the_action; COMPONENT *scomponent; scomponent=(COMPONENT *)comp->scomponent; unpop_comp_window(scomponent); /* Delete component from comps. */ the_action = component_types[scomponent->co_type].action; le_del(comps, scomponent); the_action(NULL, scomponent, EV_DEL, NULL, NULL); reset_components=1; } } /***********************************************************************************************************************************************/ /* This creates the graphic object for the given scomponent. */ MComponent *pop_comp_window(COMPONENT *scomponent, int x, int y) { char *name_string; MComponent *comp; PARAM *parameter; /* First parameter in list is always the name of comp. */ parameter = (Param *)scomponent->co_params->q_head; name_string=parameter->p_make_text(scomponent, parameter); if ((comp=NewComponent(name_string, scomponent->co_type, x, y))!=NULL) { comp->scomponent=scomponent; comp->num_meters=0; if (!the_environment.draw_meter_component) { SetStatusMetersHidden(comp); } return(comp); } return(NULL); } /***********************************************************************************************************************************************/ /* This destroys the graphic object associated with the given simulator component. */ void unpop_comp_window(COMPONENT *scomponent) { MComponent *comp; int i; comp=(MComponent *)scomponent->co_picture; /* Get rid of meters */ if (comp->num_meters > 0) { METER **temp_m_list; int count; l_elt *le; temp_m_list=(METER **)sim_malloc(sizeof(METER *)*comp->num_meters); count=0; for (le=m_list->l_head; le!=NULL; le=le->le_next) { Param *parameter; COMPONENT *meter_scomponent; METER *meter; parameter = (PARAM *)le->le_data; meter=(METER *)parameter->p_my_picture; meter_scomponent=(COMPONENT *)meter->scomponent; if (meter_scomponent==scomponent) { temp_m_list[count]=meter; count++; } } /* Sanity check */ if (count != comp->num_meters) WARNING("Component has the wrong number of meters."); for(i=0; iscomponent, temp_m_list[i]->parameter); } free(temp_m_list); } /* Sanity check */ if (comp->num_meters!=0) WARNING("Not all component meters have been deleted."); KillComponent(comp); } /***********************************************************************************************************************************************/ void RecursiveDestroyComponent(MComponent *comp) { /* Destroy all the component's children, Destroy the component. */ MComponentList templist; /* We need a temporary list because DestroyComponent 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 RecursiveDestroyComponent."); return;} l_traverse(templist,RecursiveDestroyComponent); lq_delete(templist); } DestroyComponent(comp); } /***********************************************************************************************************************************************/ /* The callback called when Unselect All is pressed. */ void edit_unsel_cb(w) Widget w; { int done=0; l_elt *le; TRACE("edit_unsel_cb"); /* Unselect all selected components. */ UnselectAll(); }