/* $Id: param_w.c,v 10.1 92/10/06 23:03: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 #include #include #include #include #include #include #include "string.h" #include "xm-param_w.h" #include "sim.h" #include "simx.h" #include "xm-util.h" #include "comptypes.h" #include "xm-comp_trans.h" #include "xm-main_w.h" #include "xm-meters.h" /* This file contains routines for creating component parameter windows. Routines for opening and closing parameter windows: void OpenParameterWindow(MComponent *comp, int given_x, int given_y, int valid_coords); void CloseParameterWindow(MComponent *comp); Translation functions for mars.componentTranslations: open_param_w_tn() Open a component's parameter window. close_param_w_tn() Close a component's parameter window. open_close_param_w_tn() Open the window if not open, else close it. */ Widget BuildParameterWindow(ParamWinData *data) ; void comp_param_ok_action(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs); void comp_param_cancel_action(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs); void comp_param_kill_action(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs); void comp_param_meter_toggle(Widget w, ParamWinData *window_data, XmToggleButtonCallbackStruct *cbs); void comp_param_log_toggle(Widget w, ParamWinData *window_data, XmToggleButtonCallbackStruct *cbs); /**********************************************************************************************************************************************/ /* A translation function to open the component parameter window. This is called in response to a button-key event on the component icon. */ void open_param_w_tn(Widget w, XEvent *event, String *args, int *num_args) { MComponent *comp; TRACE("open_info_w_tn"); comp=GetComponentOfIcon(w); if ((comp->type==TYPE_GROUP) || (comp->type==TYPE_METER)) return; if (!CompParamWindowOpen(comp)) { OpenParameterWindow(comp,0,0,FALSE); } else RaiseWidget(((ParamWinData *)comp->param_window)->dialog_widget); } /**********************************************************************************************************************************************/ /* A translation function to open the component parameter window. This is called in response to a button-key event on the component icon. */ /* Open the param_w if not open, else close the param_w. */ void open_close_param_w_tn(Widget w, XEvent *event, String *args, int *num_args) { MComponent *comp; TRACE("open_info_w_tn"); comp=GetComponentOfIcon(w); if ((comp->type==TYPE_GROUP) || (comp->type==TYPE_METER)) return; if (!CompParamWindowOpen(comp)) { OpenParameterWindow(comp,0,0,FALSE); } else { CloseParameterWindow(comp); } } /**********************************************************************************************************************************************/ /* A translation function to close the component parameter window. This is called in response to a button-key event on the component icon. */ void close_param_w_tn(Widget w, XEvent *event, String *args, int *num_args) { MComponent *comp; TRACE("open_info_w_tn"); comp=GetComponentOfIcon(w); if ((comp->type==TYPE_GROUP) || (comp->type==TYPE_METER)) return; if (CompParamWindowOpen(comp)) { CloseParameterWindow(comp); } } /**********************************************************************************************************************************************/ /* The callback from the parameter button in the component information window. */ void open_param_w_cb(Widget w, void *info_win_data, XmAnyCallbackStruct *cbs) { MComponent *comp=((InfoWinData *)info_win_data)->comp; int x,y; Position nx,ny; TRACE ("open_param_w_cb"); if (!CompParamWindowOpen(comp)) { x=((XButtonEvent *)cbs->event)->x_root; y=((XButtonEvent *)cbs->event)->y_root; RWTranslateCoords((Position)x, (Position)y, network_w, &nx, &ny); OpenParameterWindow(comp,(int)nx,(int)ny,TRUE); /* FALSE means ingnore the coordinates. */ } else RaiseWidget(((ParamWinData *)comp->param_window)->dialog_widget); } /**********************************************************************************************************************************************/ /* This is a callback routine called when the user presses enter in a textfield. It calls p_input to give the new value to the simulator. If the parameter is the component's name, then the name on the component's icon is updated. */ void change_parameter_cb(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs) { COMPONENT *scomponent; MComponent *comp; ParameterTextfield *p_textf; String new_value; TRACE("change_parameter_cb"); GetWidgetUserData(w,p_textf); p_textf->new_value_entered=0; comp=(MComponent *)window_data->comp; scomponent=comp->scomponent; new_value=XmTextFieldGetString(p_textf->textfield); if (0!=strcmp(new_value, p_textf->current_value)) { /* If the value has changed, give the new value to the simulator. */ if (p_textf->parameter->p_input(p_textf->parameter, new_value, scomponent)) { free(p_textf->current_value); p_textf->current_value=new_string(new_value); if (p_textf->parameter==(PARAM *)scomponent->co_params->q_head) { /* Then this is the component name, so change it's icon name. Note: This only occurs when the change_parameter is called from the information window (not the parameter window) */ ChangeComponentName(comp, new_value); } p_textf->changed_by_user=1; } else { XmTextFieldSetString(p_textf->textfield,p_textf->current_value); /* If the new value is not accepted, restore the old value. */ } } XtFree(new_value); UpdateParameterWindow(comp); /* This redraws the window if the number of displayable parameters have changed. */ } /**********************************************************************************************************************************************/ void UpdateParameterWindow(MComponent *comp) { /* If number of params has changed, redo the paramwindow */ COMPONENT *scomponent=comp->scomponent; int num_display=0; PARAM *parameter; if (!CompParamWindowOpen(comp)) return; for (parameter = (PARAM *)scomponent->co_params->q_head; parameter; parameter = parameter->p_next) if (parameter->p_flags & DisplayMask) num_display++; if (num_display != ((ParamWinData *)comp->param_window)->num_params) { Position x,y; XtVaGetValues(((ParamWinData *)comp->param_window)->dialog_widget, XmNx, &x, XmNy, &y, NULL); CloseParameterWindow(comp); OpenParameterWindow(comp, (int)x, (int)y, TRUE); } } /**********************************************************************************************************************************************/ int restore_initial_parameter_value(ParameterTextfield *p_textf, COMPONENT *scomponent) { TRACE("restore_initial_paramter_value"); if (0!=strcmp(p_textf->current_value, p_textf->initial_value)) { /* If the value has changed, restore the old value. */ if (p_textf->parameter->p_input(p_textf->parameter, p_textf->initial_value, scomponent)) { free(p_textf->current_value); p_textf->current_value=new_string(p_textf->initial_value); if (p_textf->parameter==(PARAM *)scomponent->co_params->q_head) { /* Then this is the component name, so change it's icon name. Note: This only occurs when the change_parameter is called from the information window (not the parameter window) */ ChangeComponentName((MComponent *)scomponent->co_picture, p_textf->initial_value); } return(1); } } return(0); } /**********************************************************************************************************************************************/ /* This is called just before the parameter window is closed. If window_data->cancel changes is set, then the parameter values are restored to their initial settings. Otherwise, the new values are set with p_input. All storage allocated for the textfields is freed. */ void destroy_parameter_textfields(ParamWinData *window_data) { COMPONENT *scomponent; MComponent *comp; ParameterTextfield **textfields; ParameterTextfield *p_textf; String new_value; int i; textfields=window_data->textfields; comp=(MComponent *)window_data->comp; scomponent=comp->scomponent; for (i=0;inum_params;i++) { p_textf=textfields[i]; if ((p_textf->parameter->p_flags & (InputMask | ModifyMask)) && i!=0) { if (window_data->cancel_changes) { if (p_textf->changed_by_user) { restore_initial_parameter_value(p_textf, scomponent); } } else { /* User pushed ok */ if (p_textf->new_value_entered) { new_value=XmTextFieldGetString(p_textf->textfield); if (0!=strcmp(new_value, p_textf->current_value)) { /* If the value has changed, give the new value to the simulator. */ p_textf->parameter->p_input(p_textf->parameter, new_value, scomponent); } XtFree(new_value); } } free(p_textf->current_value); free(p_textf->initial_value); } free(p_textf); } } /*******************************************************************************************************************************************/ /* This callback routine is called whenever the user types in the textfield. The flag p_textf->new_value_entered indicates that a new parameter value has been entered, but the value has not yet been sent to the simulator. */ void set_changed_by_user_flag(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs) { ParameterTextfield *p_textf; GetWidgetUserData(w,p_textf); p_textf->new_value_entered=1; } /**********************************************************************************************************************************************/ void OpenParameterWindow(MComponent *comp, int given_x, int given_y, int valid_coords) { unsigned num_display=0; Widget comp_param_w; ParamWinData *window_data; PARAM *parameter; COMPONENT *scomponent=comp->scomponent; TRACE("OpenParameterWindow"); if (CompParamWindowOpen(comp)) { WARNING("Attempting to open an already open window"); return; } window_data=(ParamWinData *)sim_malloc(sizeof(ParamWinData)); window_data->comp=comp; window_data->cancel_changes=0; /* By default we don't cancel the changes. */ /*Count the number of displayable parameters.*/ for (parameter = (PARAM *)scomponent->co_params->q_head; parameter; parameter = parameter->p_next) { if (parameter->p_flags & DisplayMask) num_display++; } window_data->num_params=num_display; window_data->textfields=(ParameterTextfield **)sim_malloc(num_display*sizeof(ParameterTextfield *)); window_data->dialog_widget=comp_param_w=BuildParameterWindow(window_data); /* Set the shell position. */ if (valid_coords) { if (given_x<0) given_x=0; if (given_y<0) given_y=0; SetWidgetCoordinates(comp_param_w, given_x, given_y); } else { SetWidgetCoordinates(comp_param_w, comp->x, comp->y); } window_data->comp->param_window=window_data; XtManageChild(comp_param_w); RaiseWidget(comp_param_w); SetStatusParamWindowOpen(comp); } static ActionAreaItem param_w_action_area[]={ { "Ok", comp_param_ok_action, NULL, NULL}, { "Cancel", comp_param_cancel_action, NULL, NULL} }; /*******************************************************************************************************************************************/ Widget BuildParameterWindow(window_data) /* Create a form dialog as follows: Label ' Information Window' Double Separator TextInputField(data->name); Separator ToggleBox and TextFields Separator Action Area */ ParamWinData *window_data; { Widget param_w, param_box, label, sep, rowcolumn, action_area, param_w_form; unsigned num_params_display=0; static char buf[50]; XmString str; int i; Pixel bg; MComponent *comp=window_data->comp; TRACE("BuildParameterWindow"); bg=the_environment.component_color[comp->type]; param_w=XmCreateForm(network_w, "param_w", NULL, 0); XtVaSetValues(param_w,XmNbackground, bg, NULL); /* TITLE LINE */ sprintf(buf,"%s Parameters",component_types[((MComponent *)(window_data->comp))->type].typename); str=XmStringCreateSimple(buf); label=XtVaCreateManagedWidget("title",xmLabelWidgetClass,param_w, XmNbackground, bg, XmNlabelString, str, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNtranslations, the_environment.move_window_translations, XmNuserData, param_w, NULL); XmStringFree(str); sep=CreateSeparator(param_w, XmDOUBLE_LINE, label); /* PARAMETERS BOX */ { Widget form, log_label, meter_label; COMPONENT *scomponent=window_data->comp->scomponent; PARAM *parameter; ParameterTextfield *p_textf; String prompt; String value; rowcolumn=XtVaCreateWidget("text_input_rowcol",xmRowColumnWidgetClass, param_w, XmNbackground, bg, XmNorientation, XmVERTICAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); /* First I'll add a dummy parameter entry to label the Log and Meter toggle switch columns. */ form=XtVaCreateWidget("form",xmFormWidgetClass,rowcolumn, XmNbackground, bg, NULL); log_label=XtVaCreateManagedWidget("log_label",xmLabelWidgetClass, form, XmNbackground, bg, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNalignment, XmALIGNMENT_CENTER, NULL); meter_label=XtVaCreateManagedWidget("meter_label",xmLabelWidgetClass, form, XmNbackground, bg, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNalignment, XmALIGNMENT_CENTER, NULL); XtManageChild(form); i=0; for (parameter = (PARAM *)scomponent->co_params->q_head; parameter; parameter = (PARAM *)parameter->p_next) { /* All parameters will have a pointer to the widget, and a pointer to the parameter, only changeable parameters need to store an initial value and a current value. */ if (parameter->p_flags & DisplayMask) { /* Create the textfield */ Widget log_toggle=NULL, meter_toggle=NULL, text_input=NULL; p_textf=(ParameterTextfield *)sim_malloc(sizeof(ParameterTextfield)); p_textf->parameter=parameter; form=XtVaCreateWidget("form",xmFormWidgetClass,rowcolumn, XmNbackground, bg, NULL); /* Create the log toggle switch. */ if (parameter->p_flags & CanHaveLogMask) { log_toggle=XtVaCreateManagedWidget("log_toggle",xmToggleButtonWidgetClass, form, XmNbackground, bg, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_POSITION, XmNset, (parameter->p_flags & LogMask)? True : False, NULL); XtAddCallback(log_toggle, XmNvalueChangedCallback, (XtCallbackProc)comp_param_log_toggle, window_data); SetWidgetUserData(log_toggle,p_textf); p_textf->log_toggle=log_toggle; } /* Create the Meter toggle switch. */ if (parameter->p_flags & CanHaveMeterMask) { meter_toggle=XtVaCreateManagedWidget("meter_toggle",xmToggleButtonWidgetClass, form, XmNbackground, bg, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_POSITION, XmNset, (parameter->p_flags & MeterMask)? True : False, NULL); XtAddCallback(meter_toggle, XmNvalueChangedCallback, (XtCallbackProc)comp_param_meter_toggle, window_data); SetWidgetUserData(meter_toggle,p_textf); p_textf->meter_toggle=meter_toggle; } /* Create the textfield. */ prompt=parameter->p_name; value=parameter->p_make_short_text(scomponent, parameter); remove_quotes(value); text_input=CreateTextInput(form,prompt,value,&p_textf->textfield); SetWidgetUserData(p_textf->textfield,p_textf); XtVaSetValues(text_input, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNrightAttachment, XmATTACH_FORM, NULL); if (parameter->p_flags & (InputMask | ModifyMask) && i!=0) { /* The name parameter is not editable from this window. */ XtAddCallback(p_textf->textfield,XmNvalueChangedCallback,(XtCallbackProc)set_changed_by_user_flag,window_data); XtAddCallback(p_textf->textfield,XmNactivateCallback,(XtCallbackProc)change_parameter_cb,window_data); p_textf->initial_value=new_string(value); p_textf->current_value=new_string(value); } else { XtVaSetValues(p_textf->textfield,XmNeditable,False,NULL); p_textf->initial_value=NULL; p_textf->current_value=NULL; } p_textf->changed_by_user=0; p_textf->new_value_entered=0; window_data->textfields[i++]=p_textf; XtManageChild(form); } } XtManageChild(rowcolumn); } sep=CreateSeparator(param_w, XmSINGLE_LINE, rowcolumn); /* ACTION AREA */ for (i=0;iparam_window; TRACE("CloseParameterWindow"); if (!CompParamWindowOpen(comp)) { WARNING("Attempting to close an already closed window"); return; } destroy_parameter_textfields(window_data); XtUnmanageChild(window_data->dialog_widget); XtDestroyWidget(window_data->dialog_widget); SetStatusParamWindowClosed(comp); comp->param_window=NULL; free(window_data); } /**********************************************************************************************************************************************/ void comp_param_ok_action(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs) /* Close the parameter_window */ { TRACE("comp_param_ok_action"); window_data->cancel_changes=0; CloseParameterWindow(window_data->comp); } /**********************************************************************************************************************************************/ void comp_param_cancel_action(Widget w, ParamWinData *window_data, XmAnyCallbackStruct *cbs) /* Restore parameter values. Close the window. */ { TRACE("comp_param_cancel_action"); window_data->cancel_changes=1; CloseParameterWindow(window_data->comp); } /**********************************************************************************************************************************************/ /* The callback called when a log toggle button is pressed. */ void comp_param_log_toggle(Widget w, ParamWinData *window_data, XmToggleButtonCallbackStruct *cbs) { ParameterTextfield *p_textf; PARAM *parameter; COMPONENT *scomponent=window_data->comp->scomponent; TRACE("comp_param_log_toggle"); GetWidgetUserData(w,p_textf); parameter=p_textf->parameter; if (cbs->set) { /* The toggle's value changed to set. Start logging */ if (log_param_create(scomponent, parameter) == TRUE) { parameter->p_flags |= LogMask; } else { /* If logging is not allowed, then reset the toggle to off. */ XtVaSetValues(w,XmNset,False,NULL); } } else { /* Stop logging. */ log_param_close(parameter); parameter->p_flags &= ~LogMask; } } /**********************************************************************************************************************************************/ /* The callback called when a meter toggle button is pressed. */ void comp_param_meter_toggle(Widget w, ParamWinData *window_data, XmToggleButtonCallbackStruct *cbs) { ParameterTextfield *p_textf; PARAM *parameter; COMPONENT *scomponent=window_data->comp->scomponent; METER *meter; TRACE("comp_param_meter_toggle"); GetWidgetUserData(w,p_textf); parameter=p_textf->parameter; if (cbs->set) { /* The toggle's value changed to set. Create meter */ if (OK!=CreateMeter(scomponent,parameter,NULL,0,0,0,0,TRUE)) { /* meter could not be created, so reset the toggle button. */ XtVaSetValues(w,XmNset,False,NULL); } } else { /* Destroy meter */ DestroyMeter(scomponent, parameter); } } /**********************************************************************************************************************************************/ /* Given a parameter window, and a parameter, this routine sets the meter toggle button for that parameter. If on==1, the button is set(depressed), else the button is cleared(rises up). */ void FlipMeterToggle(ParamWinData *window_data, PARAM *parameter, int on) { ParameterTextfield **textfields; int i; textfields=window_data->textfields; for (i=0;inum_params;i++) { if (parameter==textfields[i]->parameter) { XtVaSetValues(textfields[i]->meter_toggle, XmNset, (on==ON)? True : False, NULL); break; } } if (i==window_data->num_params) { WARNING("Parameter not found in FlipMeterToggle."); } } /**********************************************************************************************************************************************/ /* Given a parameter window, and a parameter, this routine sets the log toggle button for that parameter. If on==1, the button is set(depressed), else the button is cleared(rises up). */ void FlipLogToggle(ParamWinData *window_data, PARAM *parameter, int on) { ParameterTextfield **textfields; int i; textfields=window_data->textfields; for (i=0;inum_params;i++) { if (parameter==textfields[i]->parameter) { XtVaSetValues(textfields[i]->log_toggle, XmNset, (on==ON)? True : False, NULL); break; } } if (i==window_data->num_params) { WARNING("Parameter not found in FliplogToggle."); } }