/* $Id: meters.c,v 10.1 92/10/06 23:03:27 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 #include #include #include #include #include #include "sim.h" #include "simx.h" #include "xtables.h" #include "xm-meters.h" #include "event.h" #include "xm-network.h" #include "xm-main_w.h" #include "xm-view.h" #include "xm-comp_trans.h" #include "xm-util.h" /* This file contains the routines to create, update, destroy, and paint meters. Meters are graphical representations of the paramters of components using bar graphs, colored boxes, etc. The user will be able to change the type, size, location ,etc. of the meter after its creation. Functions for creating and destroying meters: int CreateMeter(COMPONENT *scomponent, PARAM *parameter, char *name, int oldx, oldy, oldwidth, oldheight, draw_component); int DestroyMeter (COMPONENT *scomponent, PARAM *parameter); Functions for opening and closing meter information windows: void OpenMeterInfoWindow(METER *meter, int x, y, valid_coords); void CloseMeterInfoWindow(METER *meter); The following action routines for mars.meterTranslations are provided: move_meter() Drag the meter. resize_meter() Resize the meter. raise_meter() Raise the meter. lower_meter() Lower the meter. open_meter_info_w_tn() Open the meter's information window. close_meter_info_w_tn() Close the meter's information window. open_close_meter_info_w_tn() Open the meter's information window if not open, else close it. */ Widget BuildMeterWindow(METER *meter); void meter_expose_event_handler(Widget meter_window, METER *meter, XExposeEvent *xexpose); void do_memory_meter_initialization(METER *meter); /* check to see if it is a memory meter, and if so, create the TH structure */ void free_memory_meter_stuff(METER *meter); list *m_list; /**********************************************************************************************************************************************/ extern double rint (); extern double floor (); extern double ceil (); extern GC color_gc[]; extern int packet_colors[]; #define NUM_METER_TYPES 8 METERTYPE meter_types[] = { /* If you change this, you also have to change the Option Menu in build_meter_info_item(). */ { "METER TYPES :", 0, 0, 0}, /* This is a filler, so that the meter type numbers saved in the X version of mars will correspond to their #defines in simx1.h */ { "BINARY METER", BINARY, 1.0, 0.5 }, { "BAR GRAPH", BAR_GRAPH, 1.0, 1.0 }, { "LOG", LOG, 1.0, 1.0 }, { "TIME HISTORY-A", TIME_HISTORY, 2.0, 1.0}, { "TIME HISTORY-D", TIME_HISTORY_D, 2.0, 1.0}, { "DELTA METER", DELTA, 2.0, 1.0}, { "HISTOGRAM", HISTOGRAM, 2.0, 1.0}, { "TEXT METER", TEXT_METER, 1.0, 0.5 }, /* written at UMCP */ { "", -1} }; typedef struct { String binary_meter; String bar_graph; String log; String time_history_a; String time_history_d; String delta_meter; String histogram; String text_meter; } METER_GEOMETRY, *METER_GEOMETRY_PTR; METER_GEOMETRY meter_geometry; XtResource meter_geometry_resources[]={ {"BINARY_METERgeometry", "BINARY_METERgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, binary_meter), XtRString, "1.0x0.5"}, {"BAR_GRAPHgeometry", "BAR_GRAPHgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, bar_graph), XtRString, "1.0x1.0"}, {"LOGgeometry", "LOGgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, log), XtRString, "1.0x1.0"}, {"TIME_HISTORY_Ageometry", "TIME_HISTORY_Ageometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, time_history_a), XtRString,"2.0x1.0"}, {"TIME_HISTORY_Dgeometry", "TIME_HISTORY_Dgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, time_history_d), XtRString,"2.0x1.0"}, {"DELTA_METERgeometry", "DELTA_METERgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, delta_meter), XtRString, "2.0x1.0"}, {"HISTOGRAMgeometry", "HISTOGRAMgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, histogram), XtRString, "2.0x1.0"}, {"TEXT_METERgeometry", "TEXT_METERgeometry", XtRString, sizeof(String), XtOffset(METER_GEOMETRY_PTR, text_meter), XtRString, "1.0x0.5"}, }; /* Initialize meter geometries */ void initialize_meters() { int i; XtGetApplicationResources(main_w_shell, &meter_geometry, meter_geometry_resources, XtNumber(meter_geometry_resources), NULL, 0); i=0; sscanf(meter_geometry.binary_meter,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.bar_graph,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.log,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.time_history_a,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.time_history_d,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.delta_meter,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.histogram,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; sscanf(meter_geometry.text_meter,"%lfx%lf",&meter_types[i].width, &meter_types[i].height);i++; } /**********************************************************************************************************************************************/ void move_meter(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 METER *grabbed=NULL; Position mx,my; switch(which_string(argv[0],poss_args,XtNumber(poss_args))) { case 0: if (!grabbed) { GetWidgetUserData(w,grabbed); RWTranslateCoords((Position)event->x_root, (Position)event->y_root, meter_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: { int diff_x,diff_y; int new_mouse_x, new_mouse_y; if (!grabbed) return; RWTranslateCoords((Position)event->x_root, (Position)event->y_root, meter_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; grabbed->x+=diff_x; grabbed->y+=diff_y; mouse_x=new_mouse_x; mouse_y=new_mouse_y; SetWidgetCoordinates(grabbed->meter_window, grabbed->x, grabbed->y); XFlush(the_environment.the_display); } break; case 2: grabbed=NULL; break; default: WARNING("Unknown case in move_meter\n"); } } /**********************************************************************************************************************************************/ void raise_meter(Widget w) { METER *meter; GetWidgetUserData(w,meter); RaiseWidget(meter->meter_window); } /**********************************************************************************************************************************************/ void lower_meter(Widget w) { METER *meter; GetWidgetUserData(w,meter); LowerWidget(meter->meter_window); } /**********************************************************************************************************************************************/ void resize_meter(w,event,argv,argc) Widget w; XButtonEvent *event; String *argv; int *argc; { String poss_args[]={"grab","move","release"}; static METER *meter=NULL; static int prev_w,prev_h; Position pos_x, pos_y; switch(which_string(argv[0],poss_args,XtNumber(poss_args))) { case 0: /* grab */ if (meter!=NULL) return; GetWidgetUserData(w,meter); WWTranslateCoords(w, meter->meter_window, event->x, event->y, &pos_x, &pos_y); prev_w=(int)pos_x+1; prev_h=(int)pos_y+1; XDrawRectangle(XtDisplay(meter_w),XtWindow(meter_w),the_environment.rubberbox_gc,meter->x,meter->y,prev_w,prev_h); XDrawRectangle(XtDisplay(meter->draw_area),XtWindow(meter->draw_area),the_environment.rubberbox_gc,0,0,prev_w,prev_h); break; case 1: /* move */ if (meter==NULL) return; XDrawRectangle(XtDisplay(meter_w),XtWindow(meter_w),the_environment.rubberbox_gc,meter->x,meter->y,prev_w,prev_h); XDrawRectangle(XtDisplay(meter->draw_area),XtWindow(meter->draw_area),the_environment.rubberbox_gc,0,0,prev_w,prev_h); WWTranslateCoords(w, meter->meter_window, event->x, event->y, &pos_x, &pos_y); prev_w=(int)pos_x+1; prev_h=(int)pos_y+1; if (prev_w<1) prev_w=1; if (prev_h<1) prev_h=1; XDrawRectangle(XtDisplay(meter_w),XtWindow(meter_w),the_environment.rubberbox_gc,meter->x,meter->y,prev_w,prev_h); XDrawRectangle(XtDisplay(meter->draw_area),XtWindow(meter->draw_area),the_environment.rubberbox_gc,0,0,prev_w,prev_h); break; case 2: { /* release */ Position x,y; Dimension bw, main_width, main_height; Dimension draw_width, draw_height; int width, height; int i; double *temp_array; if (meter==NULL) return; XDrawRectangle(XtDisplay(meter_w),XtWindow(meter_w),the_environment.rubberbox_gc,meter->x,meter->y,prev_w,prev_h); XDrawRectangle(XtDisplay(meter->draw_area),XtWindow(meter->draw_area),the_environment.rubberbox_gc,0,0,prev_w,prev_h); x=meter->x; y=meter->y; main_height=prev_h; main_width=prev_w; XtVaSetValues(meter->meter_window, XmNheight, main_height, XmNwidth, main_width, NULL); XtVaGetValues(meter->draw_area, XmNheight, &draw_height, XmNwidth, &draw_width, NULL); width=(int)draw_width; height=(int)draw_height; if ((meter->th != NULL)) { temp_array = (double *) sim_calloc((unsigned) width, sizeof(double)); if (meter->th->data_length > width) { meter->th->data_tail += meter->th->data_length - width; if (meter->th->data_tail >= meter->width) meter->th->data_tail -= meter->width; } for (i =0; meter->th->data_tail != meter->th->data_head; ++i) { temp_array[i] = meter->th->data_array[meter->th->data_tail]; ++(meter->th->data_tail); if (meter->th->data_tail == meter->width) { if (meter->th->data_head == meter->width) break; meter->th->data_tail = 0; } } free ((char *) meter->th->data_array); meter->th->data_array = (double *) temp_array; meter->th->data_tail = 0; meter->th->data_head = i; meter->th->data_length = i; meter->th->time = ev_now(); meter->th->counter = 0; } meter->width = width; meter->height = height; meter->x = x; meter->y = y; XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(meter->scomponent, meter->parameter, meter, NULL); meter=NULL; break; } } } /**********************************************************************************************************************************************/ typedef struct { int position; METER *meter; } EditMeterCallbackData; Widget build_meter_info_item(Widget parent, METER *meter, int position, Widget *textfield_return); void meter_info_ok_action(Widget *w, METER *meter); void meter_info_kill_action(Widget *w, METER *meter); void change_meter_type(Widget w, int type, XmRowColumnCallbackStruct *cbs); /*void change_meter_type2(Widget w, METER *meter);*/ void edit_meter_parameter(Widget w, EditMeterCallbackData *data, XmAnyCallbackStruct *cbs); ActionAreaItem meter_info_action[]={ { "Ok", meter_info_ok_action, NULL, NULL}, {"Kill", meter_info_kill_action, NULL, NULL} }; /**********************************************************************************************************************************************/ void open_meter_info_w_tn(Widget w) { METER *meter; GetWidgetUserData(w,meter); if(meter->info_window == NULL) { OpenMeterInfoWindow(meter,0,0,FALSE); } else { RaiseWidget(meter->info_window); } } /**********************************************************************************************************************************************/ void open_close_meter_info_w_tn(Widget w) { METER *meter; GetWidgetUserData(w,meter); if(meter->info_window == NULL) { OpenMeterInfoWindow(meter,0,0,FALSE); } else { CloseMeterInfoWindow(meter); } } /**********************************************************************************************************************************************/ void close_meter_info_w_tn(Widget w) { METER *meter; GetWidgetUserData(w,meter); if (meter->info_window != NULL) { CloseMeterInfoWindow(meter); } } /**********************************************************************************************************************************************/ void OpenMeterInfoWindow(METER *meter, int given_x, int given_y, int valid_coords) { Widget meter_info_w; char geometry[20]; TRACE("OpenMeterInfoWindow"); if (meter->info_window != NULL) { /* Info window is already open */ return; } meter->info_window=meter_info_w=BuildMeterInfoWindow(meter); if (valid_coords) { SetWidgetCoordinates(meter_info_w, given_x, given_y); } else { Dimension height; XtVaGetValues(meter->meter_window, XmNheight, &height, NULL); SetWidgetCoordinates(meter_info_w, meter->x, meter->y+(int)height); } XtManageChild(meter_info_w); } /**********************************************************************************************************************************************/ void CloseMeterInfoWindow(METER *meter) { /* For now, we will forget about cancelling the changes. */ int i; if (meter->info_window != NULL) { for(i=0;inum_textfields;i++) { XtCallCallbacks(meter->textfields[i],XmNactivateCallback,meter); } XtDestroyWidget(meter->info_window); meter->info_window=NULL; } } /**********************************************************************************************************************************************/ Widget BuildMeterInfoWindow(METER *meter) { Widget meter_info_w, label, sep, row_column, action_area; int i; Pixel bg=the_environment.component_color[meter->scomponent->co_type]; TRACE("BuildMeterInfoWindow"); meter_info_w=XmCreateForm(meter_w, "meter_info_w", NULL, 0); XtVaSetValues(meter_info_w, XmNuserData, meter, /* Used by change_meter_type. */ XmNbackground, bg, NULL); /* TITLE LINE */ label=XtVaCreateManagedWidget("title",xmLabelWidgetClass, meter_info_w, XmNbackground,bg, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNuserData, meter_info_w, /* This is the widget moved by move_window_translations. */ NULL); XtOverrideTranslations(label, the_environment.move_window_translations); sep=CreateSeparator(meter_info_w, XmDOUBLE_LINE, label); /* Create a text field for each meter_info_name */ row_column=XtVaCreateWidget("parameter_rowcolumn", xmRowColumnWidgetClass, meter_info_w, XmNbackground, bg, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, NULL); meter->num_textfields=0; for (i = 0; i != the_environment.meter_info_window_entries; ++i) { Widget textfield_return; build_meter_info_item(row_column, meter, i, &textfield_return); if (textfield_return!=NULL) { if (meter->num_textfields==0) meter->textfields=(Widget *)sim_calloc(1,sizeof(Widget)); else meter->textfields=(Widget *)sim_realloc((Widget *)(meter->textfields), (unsigned) (sizeof(Widget)*(meter->num_textfields+1))); meter->textfields[meter->num_textfields]=textfield_return; meter->num_textfields+=1; } } XtManageChild(row_column); sep=CreateSeparator(meter_info_w, XmSINGLE_LINE, row_column); /* ACTION_AREA */ for (i=0;iscomponent, meter->parameter); } /**********************************************************************************************************************************************/ #define EDIT_NEVER 0 #define EDIT_ON_ACTIVATE 0x1 void popup_change_meter_type_menu(Widget w, Widget popup, XmPushButtonCallbackStruct *cbs); void edit_meter_name_parameter(Widget w, METER *meter); void edit_meter_scale_parameter(Widget w, METER *meter); void edit_meter_sampling_time_parameter(Widget w, METER *meter); void toggle_display_name (Widget w, METER *meter, XmToggleButtonCallbackStruct *cbs); void toggle_display_scale (Widget w, METER *meter, XmToggleButtonCallbackStruct *cbs); void edit_meter_hist_min_parameter(Widget w, METER *meter); void edit_meter_hist_max_parameter(Widget w, METER *meter); void edit_meter_hist_cells_parameter(Widget w, METER *meter); void edit_meter_hist_samples_parameter(Widget w, METER *meter); Widget build_textfield_item(Widget parent, char *prompt, char *value, int edit_flags, void (*edit_callback)(), void *edit_calldata, Widget *textfield_return); Widget build_toggle_item(Widget parent, char *label, int set, int changeable, void (*valuechanged_callback)(), void *valuechanged_calldata); Widget build_meter_info_item(Widget parent, METER *meter, int position, Widget *textfield_return) { Widget item; EditMeterCallbackData *calldata; PARAM *parameter; char temp_string[60]; int k; double f; switch(position) { case 0: item=build_textfield_item(parent, "Meter name", meter->name, EDIT_ON_ACTIVATE, edit_meter_name_parameter, meter, textfield_return); break; case 1: parameter = (PARAM *)meter->scomponent->co_params->q_head; item=build_textfield_item(parent, "Component name", (*(parameter->p_make_text))(meter->scomponent,parameter), EDIT_NEVER, NULL, NULL, textfield_return); *textfield_return=NULL; break; case 2: { int i,n; XmString buttons[NUM_METER_TYPES]; XmString str; Widget popup; Pixel bg; char buf[40]; XtVaGetValues(parent, XmNbackground, &bg, NULL); for (i=1,n=0;ntype].meter_name); str=XmStringCreateSimple(buf); item=XtVaCreateManagedWidget("meter_type_button",xmPushButtonWidgetClass, parent, XmNlabelString, str, XmNbackground, bg, NULL); XmStringFree(str); XtAddCallback(item, XmNactivateCallback, (XtCallbackProc)popup_change_meter_type_menu, popup); } *textfield_return=NULL; break; case 3: sprintf(temp_string, "%lg", (meter->parameter->p_scale > 0.0) ? meter->parameter->p_scale : 1.0); item=build_textfield_item(parent, "Scale", temp_string, EDIT_ON_ACTIVATE, edit_meter_scale_parameter, meter, textfield_return); break; case 4: { int editable; if (meter->th != NULL) sprintf(temp_string, "%.2lf", ((double) (meter->th->time_increment) / 100)); else strcpy(temp_string, "0"); if (((meter->parameter->p_display_type & MeterTypeMask) != TIME_HISTORY)) editable=FALSE; else editable=TRUE; item=build_textfield_item(parent, "Sampling time increment (ms)", temp_string, editable? EDIT_ON_ACTIVATE : EDIT_NEVER, editable? edit_meter_sampling_time_parameter : NULL, meter, textfield_return); if (!editable) *textfield_return=NULL; } break; case 5: item=build_toggle_item(parent, "Display meter name", meter->display_name, TRUE, toggle_display_name, meter); *textfield_return=NULL; break; case 6: item=build_toggle_item(parent, "Display scale", meter->display_scale, TRUE, toggle_display_scale, meter); *textfield_return=NULL; break; case 7: f = (meter->type == HISTOGRAM) ? meter->hist->hist_min : 0.0; sprintf(temp_string, "%lg", f); item=build_textfield_item(parent, "Histogram Min", temp_string, meter->type==HISTOGRAM? EDIT_ON_ACTIVATE : EDIT_NEVER, meter->type==HISTOGRAM? edit_meter_hist_min_parameter : NULL, meter, textfield_return); if (meter->type!=HISTOGRAM) *textfield_return=NULL; break; case 8: f = (meter->type == HISTOGRAM) ? meter->hist->hist_max : 0.0; sprintf(temp_string, "%lg", f); item=build_textfield_item(parent, "Histogram Max", temp_string, meter->type==HISTOGRAM? EDIT_ON_ACTIVATE : EDIT_NEVER, meter->type==HISTOGRAM? edit_meter_hist_max_parameter : NULL, meter, textfield_return); if (meter->type!=HISTOGRAM) *textfield_return=NULL; break; case 9: k = (meter->type == HISTOGRAM) ? meter->hist->hist_cells : 0; sprintf(temp_string, "%d", k); item=build_textfield_item(parent, "Histogram Cells", temp_string, meter->type==HISTOGRAM? EDIT_ON_ACTIVATE : EDIT_NEVER, meter->type==HISTOGRAM? edit_meter_hist_cells_parameter : NULL, meter, textfield_return); if (meter->type!=HISTOGRAM) *textfield_return=NULL; break; case 10: k = (meter->type == HISTOGRAM) ? meter->hist->data_samples : 0; sprintf(temp_string, "%d", k); item=build_textfield_item(parent, "Histogram Samples", temp_string, meter->type==HISTOGRAM? EDIT_ON_ACTIVATE : EDIT_NEVER, meter->type==HISTOGRAM? edit_meter_hist_samples_parameter : NULL, meter, textfield_return); if (meter->type!=HISTOGRAM) *textfield_return=NULL; break; } return(item); } /**********************************************************************************************************************************************/ void popup_change_meter_type_menu(Widget w, Widget popup, XmPushButtonCallbackStruct *cbs) { if (!XtIsManaged(popup)) { XmMenuPosition(popup, (XButtonPressedEvent *)cbs->event); XtManageChild(popup); } RaiseWidget(popup); } /**********************************************************************************************************************************************/ #define RESTORE_PREVIOUS_VALUE 0 #define SET_NEW_VALUE 1 typedef struct { int action; int value_changed; char *new_value; char *previous_value; } TextFieldData; void preview_textfield(Widget w); void update_textfield(Widget w); void free_TextFieldData(Widget w); /**************************************************************************************************************************************************/ Widget build_textfield_item(parent, prompt, value, edit_flags, edit_callback, edit_calldata, textfield_return) Widget parent; char *prompt; char *value; int edit_flags; void (*edit_callback)(); void *edit_calldata; Widget *textfield_return; { Widget item; Widget textfield; TextFieldData *data; item=CreateTextInput(parent,prompt,value,&textfield); if (edit_flags != EDIT_NEVER) { data=(TextFieldData *)sim_malloc(sizeof(TextFieldData)); data->previous_value=new_string(value); data->new_value=NULL; if (edit_flags & EDIT_ON_ACTIVATE) { XtAddCallback(textfield, XmNactivateCallback, (XtCallbackProc)preview_textfield, NULL); XtAddCallback(textfield, XmNactivateCallback, edit_callback, edit_calldata); XtAddCallback(textfield, XmNactivateCallback, (XtCallbackProc)update_textfield, NULL); XtAddCallback(textfield, XmNdestroyCallback, (XtCallbackProc)free_TextFieldData, NULL); } } else { data=NULL; XtVaSetValues(textfield, XmNeditable, False, NULL); } XtVaSetValues(textfield, XmNuserData, data, NULL); *textfield_return=textfield; return(item); } /*********************************************************************************************************************************************/ void preview_textfield(Widget w) { TextFieldData *data; XtVaGetValues(w, XmNuserData, &data, NULL); data->new_value=XmTextFieldGetString(w); data->value_changed=(strcmp(data->new_value,data->previous_value) != 0); data->action=SET_NEW_VALUE; } /**********************************************************************************************************************************************/ void update_textfield(Widget w) { TextFieldData *data; XtVaGetValues(w, XmNuserData, &data, NULL); if (data==NULL) { WARNING("update textfield called with NULL data"); return; } if (data->action==RESTORE_PREVIOUS_VALUE) { XmTextFieldSetString(w, data->previous_value); if (data->new_value!=NULL) XtFree(data->new_value); } else { /* set new value */ if (data->value_changed) { XmTextFieldSetString(w,data->new_value); } XtFree(data->previous_value); data->previous_value=data->new_value; } data->new_value=NULL; } /**********************************************************************************************************************************************/ void free_TextFieldData(Widget w) { TextFieldData *data; XtVaGetValues(w, XmNuserData, &data, NULL); if (data!=NULL) { if (data->previous_value!=NULL) XtFree(data->previous_value); if (data->new_value!=NULL) XtFree(data->new_value); } free(data); } /**********************************************************************************************************************************************/ Widget build_toggle_item(parent, label, set, changeable, valuechanged_callback, valuechanged_calldata) Widget parent; char *label; int set; int changeable; void (*valuechanged_callback)(); void *valuechanged_calldata; { Widget item; XmString str; str=XmStringCreateSimple(label); item=XtVaCreateManagedWidget("toggle_item", xmToggleButtonGadgetClass, parent, XmNlabelString, str, XmNset, set? True : False, NULL); if (changeable) { XtAddCallback(item, XmNvalueChangedCallback, valuechanged_callback, valuechanged_calldata); } XmStringFree(str); return(item); } /**********************************************************************************************************************************************/ void change_meter_type(Widget w, int type, XmRowColumnCallbackStruct *cbs) { /* Type is the index of the button pressed, which should correspond to the meter type selected. */ PARAM *parameter; METER *meter; XtVaGetValues(XtParent(w),XmNuserData,&meter,NULL); parameter = meter->parameter; type+=1; if (type != meter->type) { /* change meter type */ Position x,y; XtVaGetValues(XtParent(meter->info_window), XmNx, &x, XmNy, &y, NULL); CloseMeterInfoWindow(meter); free_memory_meter_stuff(meter); parameter->p_display_type = (type | (parameter->p_display_type & ~MeterTypeMask)); meter->type = type; if (parameter->p_scale < 0) parameter->p_scale = 0; do_memory_meter_initialization(meter); paint_meter(meter->scomponent, meter->parameter, meter, NULL); OpenMeterInfoWindow(meter,(int)x,(int)y,TRUE); } } /**********************************************************************************************************************************************/ TextFieldData *GetTextFieldData(Widget w) { TextFieldData *data; XtVaGetValues(w, XmNuserData, &data, NULL); return(data); } /**********************************************************************************************************************************************/ void edit_meter_name_parameter(Widget w, METER *meter) { TextFieldData *data; char buf[60]; data=GetTextFieldData(w); if (data->value_changed) { unsigned char resize_policy; strncpy(meter->name, data->new_value, 20); meter->name[19]='\0'; strncpy(buf,meter->scomponent->co_name,30); buf[30]='\0'; strcat(buf,": "); strcat(buf,meter->name); /* We don't want the meter to resize when we change it's label. */ XtVaGetValues(meter->meter_window, XmNresizePolicy, &resize_policy, NULL); XtVaSetValues(meter->meter_window, XmNresizePolicy, XmRESIZE_NONE, NULL); SetLabelString(meter->label, buf); XtVaSetValues(meter->meter_window, XmNresizePolicy, resize_policy, NULL); ChangeComponentName(meter->meter_comp, meter->name); } } /**********************************************************************************************************************************************/ void edit_meter_scale_parameter(Widget w, METER *meter) { TextFieldData *data; char output_string[30]; double scale; data=GetTextFieldData(w); if (data->value_changed) { if (!sscanf(data->new_value, "%lf", &scale)) { data->action=RESTORE_PREVIOUS_VALUE; return; } if (scale > 0.0) { meter->parameter->p_scale = scale; sprintf(output_string,"%lg",scale); XtFree(data->new_value); data->new_value=new_string(output_string); } else { meter->parameter->p_scale = 1.0; sprintf(output_string,"1"); XtFree(data->new_value); data->new_value=new_string(output_string); } } } /**********************************************************************************************************************************************/ void edit_meter_sampling_time_parameter(Widget w, METER *meter) { TextFieldData *data; char output_string[30]; double increment; data=GetTextFieldData(w); if (data->value_changed) { if (!sscanf(data->new_value, "%lf", &increment)) { data->action=RESTORE_PREVIOUS_VALUE; return; } meter->th->time_increment = (((int) (increment * 100))); sprintf(output_string,"%.2lf", ((double) (meter->th->time_increment) / 100)); XtFree(data->new_value); data->new_value=new_string(output_string); } } /**********************************************************************************************************************************************/ void toggle_display_name (Widget w, METER *meter, XmToggleButtonCallbackStruct *cbs) { Dimension h; if (cbs->set) meter->display_name=1; else meter->display_name=0; /* Destroy meter window and rebuild it. */ XtDestroyWidget(meter->meter_window); meter->meter_window = BuildMeterWindow(meter); } /**********************************************************************************************************************************************/ void toggle_display_scale (Widget w, METER *meter, XmToggleButtonCallbackStruct *cbs) { if (cbs->set) meter->display_scale=1; else meter->display_scale=0; } /**********************************************************************************************************************************************/ void edit_meter_hist_min_parameter(Widget w, METER *meter) { TextFieldData *data; char output_string[30]; float increment; double f; HISTO_METER *hist; data=GetTextFieldData(w); if (data->value_changed) { if (!sscanf(data->new_value, "%f", &increment)) { data->action=RESTORE_PREVIOUS_VALUE; return; } hist = meter->hist; f = (double) increment; if (f < hist->hist_max) { hist->hist_min = f; hist->data_obs = 0; hist->data_head = 0; hist->hist_intrvl = (hist->hist_max - hist->hist_min) / ((double) (hist->hist_cells)); bzero ((char *) hist->hist_array, hist->hist_cells * sizeof (int)); (void) paint_meter (meter->scomponent, meter->parameter, meter, (XExposeEvent *) 0); } sprintf(output_string,"%lg",hist->hist_min); XtFree(data->new_value); data->new_value=new_string(output_string); } } /**********************************************************************************************************************************************/ void edit_meter_hist_max_parameter(Widget w, METER *meter) { TextFieldData *data; char output_string[30]; float increment; double f; HISTO_METER *hist; data=GetTextFieldData(w); if (data->value_changed) { if (!sscanf(data->new_value, "%f", &increment)) { data->action=RESTORE_PREVIOUS_VALUE; return; } hist = meter->hist; f = (double) increment; if (f > hist->hist_min) { hist->hist_max = f; hist->data_obs = 0; hist->data_head = 0; hist->hist_intrvl = (hist->hist_max - hist->hist_min) / ((double) (hist->hist_cells)); bzero ((char *) hist->hist_array, hist->hist_cells * sizeof (int)); (void) paint_meter (meter->scomponent, meter->parameter, meter, (XExposeEvent *) 0); } sprintf(output_string,"%lg",hist->hist_max); XtFree(data->new_value); data->new_value=new_string(output_string); } } /**********************************************************************************************************************************************/ void edit_meter_hist_cells_parameter(Widget w, METER *meter) { TextFieldData *data; char output_string[30]; float increment; int k; HISTO_METER *hist; data=GetTextFieldData(w); if (data->value_changed) { if (!sscanf(data->new_value, "%f", &increment)) { data->action=RESTORE_PREVIOUS_VALUE; return; } hist = meter->hist; k = floor (increment); if (k > 0) { hist->hist_cells = k; hist->data_obs = 0; hist->data_head = 0; hist->hist_intrvl = (hist->hist_max - hist->hist_min) / ((double) (hist->hist_cells)); (void) free ((char *) hist->hist_array); hist->hist_array = (int *) sim_calloc (k, sizeof (int)); (void) paint_meter (meter->scomponent, meter->parameter, meter, (XExposeEvent *) 0); } sprintf(output_string,"%d",hist->hist_cells); XtFree(data->new_value); data->new_value=new_string(output_string); } } /**********************************************************************************************************************************************/ void edit_meter_hist_samples_parameter(Widget w, METER *meter) { TextFieldData *data; char output_string[30]; float increment; int k; HISTO_METER *hist; data=GetTextFieldData(w); if (data->value_changed) { if (!sscanf(data->new_value, "%f", &increment)) { data->action=RESTORE_PREVIOUS_VALUE; return; } hist = meter->hist; k = floor (increment); if (k > 0) { hist->data_samples = k; hist->data_obs = 0; hist->data_head = 0; (void) free ((char *) hist->data_array); hist->data_array = (double *) sim_calloc (k, sizeof (double)); bzero ((char *) hist->hist_array, hist->hist_cells * sizeof (int)); (void) paint_meter (meter->scomponent, meter->parameter, meter, (XExposeEvent *) 0); } sprintf(output_string,"%d",hist->data_samples); XtFree(data->new_value); data->new_value=new_string(output_string); } } /**********************************************************************************************************************************************/ /* This routine takes a pointer to a component and one of its parameters and creates a meter for it. */ int CreateMeter(COMPONENT *scomponent, PARAM *parameter, char *name, int oldx, int oldy, int oldwidth, int oldheight, int draw_component) { int width,height; int x,y; int num_classes; int i; XWindowAttributes xinfo; /* x information */ MComponent *comp, *meter_comp; PARAM *temp_parameter; /* pointer to the parameter */ METER *meter; /* Check to see that the parameter can be metered */ if (!the_environment.meter_window_open) { XtRealizeWidget(meter_w_shell); the_environment.meter_window_open=TRUE; } if (!(parameter->p_flags & CanHaveMeterMask)) { return (ERROR); } /* Create the new window for the meter and map it. */ height = (int) (the_environment.meter_window_height * meter_types[parameter->p_display_type & MeterTypeMask].height); width = (int) (the_environment.meter_window_width * meter_types[parameter->p_display_type & MeterTypeMask].width); if ((oldwidth > width) || (oldheight > height)) { width = oldwidth; height = oldheight; } if (m_list->l_len > 0 && oldwidth==0) { Dimension meter_w_height,meter_w_width; int max_x, max_y; METER *lowest_meter; Dimension lowest_width, lowest_height; l_elt *le; XtVaGetValues(meter_w, XmNwidth, &meter_w_width, XmNheight, &meter_w_height, NULL); le=m_list->l_head; le-le->le_next; lowest_meter=(METER *)(((PARAM *)le->le_data)->p_my_picture); XtVaGetValues(lowest_meter->meter_window, XmNwidth, &lowest_width, XmNheight, &lowest_height, NULL); max_x=0; max_y=0; /* Find the meter with the highest y-coordinate, and place the new meter either to the right or below that one. */ for (;le!=NULL;le=le->le_next) { METER *test_meter; Dimension test_width, test_height; test_meter=(METER *)(((PARAM *)le->le_data)->p_my_picture); XtVaGetValues(test_meter->meter_window, XmNwidth, &test_width, XmNheight, &test_height, NULL); if (test_meter->y > max_y) { lowest_meter=test_meter; max_y=test_meter->y; max_x=test_meter->x+test_width; } else if (test_meter->y==max_y && test_meter->x+test_width > max_x) { lowest_meter=test_meter; max_x=test_meter->x+test_width; } } XtVaGetValues(lowest_meter->meter_window, XmNwidth, &lowest_width, XmNheight, &lowest_height, NULL); x=lowest_meter->x+lowest_width+the_environment.meter_x_spacing; if (x+width>meter_w_width) { x=0; y=lowest_meter->y+lowest_height+the_environment.meter_y_spacing; } else y=max_y; } else { x=oldx; y=oldy; } /* Enter the information into the parameter's data structure */ parameter->p_flags |= MeterMask; if (parameter->p_scale < 0) parameter->p_scale = 0; /* Enter the information into the xcomponent structure */ comp=(MComponent *)scomponent->co_picture; if (CompParamWindowOpen(comp)) { FlipMeterToggle(comp->param_window, parameter, ON); } l_addt(m_list, parameter); comp->num_meters+=1; /* Enter the information into the meter structure */ meter = (METER *) sim_malloc(sizeof(METER)); meter->parameter = parameter; parameter->p_my_picture = (caddr_t) meter; meter->scomponent = scomponent; meter->th = (TH *) NULL; meter->hist = (HISTO_METER *) NULL; meter->type = parameter->p_display_type & MeterTypeMask; if (name==NULL) { strncpy(meter->name, (*(parameter->p_make_text)) (scomponent, parameter), 10); meter->name[10] = '\0'; } else { strncpy(meter->name, name, 20); meter->name[19]= '\0'; } meter->width = (unsigned)width; meter->height = (unsigned)height; meter->x = x; meter->y = y; meter->info_window = NULL; meter->display_name = 1; meter->display_scale = 1; meter->meter_window = BuildMeterWindow(meter); if (NULL==(meter_comp=NewComponent(meter->name, TYPE_METER, comp->x+the_environment.meter_component_x_offset, comp->y+the_environment.meter_component_y_offset))) { WARNING("Could not create meter component. \n"); } else { int meter_comp_w, meter_comp_h; meter_comp->scomponent=(COMPONENT *)meter; GetIconDimensions(meter_comp->icon, &meter_comp_w, &meter_comp_h); MoveComponent(meter_comp, 0, (comp->num_meters-1)*(meter_comp_h+the_environment.meter_component_spacing)); ConnectChild(meter_comp, comp); if (the_environment.draw_meter_component && draw_component) { MakeVisible(meter_comp); } } meter->meter_comp=meter_comp; /* check to see if it is a memory meter, and if so, create the TH structure */ do_memory_meter_initialization(meter); /* Return 1 */ return (OK); } /**********************************************************************************************************************************************/ void do_memory_meter_initialization(METER *meter) {/* check to see if it is a memory meter, and if so, create the TH structure */ PARAM *parameter=meter->parameter; int width=meter->width; TH *time_history; HISTO_METER *histogram; unsigned array_size; if (((parameter->p_display_type & MeterTypeMask) == TIME_HISTORY) || ((parameter->p_display_type & MeterTypeMask) == TIME_HISTORY_D) || ((parameter->p_display_type & MeterTypeMask) == DELTA)) { time_history = (TH *) sim_malloc(sizeof(TH)); array_size = (unsigned) width; time_history->data_array = (double *) sim_calloc(array_size, sizeof(double)); time_history->data_head = 0; time_history->data_tail = 0; time_history->data_length = 0; time_history->time = ev_now(); time_history->divider = 1; time_history->counter = 0; time_history->time_increment = 3000; meter->th = (TH *) time_history; } else if (((parameter->p_display_type & MeterTypeMask) == HISTOGRAM)) { histogram = (HISTO_METER *) sim_calloc(1, sizeof(HISTO_METER)); array_size = (unsigned) width; histogram->data_head = 0; histogram->data_samples = 100; histogram->data_obs = 0; histogram->hist_min = 0.0; histogram->hist_max = 10.0; histogram->hist_cells = 10; /* * Assume hist_max >= hist_min * Assume hist_cells != 0 */ histogram->hist_intrvl = (histogram->hist_max - histogram->hist_min) / ((double) (histogram->hist_cells)); histogram->data_array = (double *) sim_calloc (histogram->data_samples, sizeof (double)); histogram->hist_array = (int *) sim_calloc (histogram->hist_cells, sizeof (int)); meter->hist = histogram; } } /**********************************************************************************************************************************************/ /* This routine destroys a parameter's meter. It also takes care of resizing the component's window, altering the necessary flags in the parameter's data structure, and repainting the component window. */ int DestroyMeter (scomponent, parameter) COMPONENT *scomponent; /* component's data structure */ PARAM *parameter; /* pointer to the paramter */ { int counter; MComponent *comp; METER *meter; meter = (METER *) parameter->p_my_picture; /* Close the meter information window */ if (meter->info_window != NULL) CloseMeterInfoWindow(meter); if (meter->meter_window!=NULL) { XtDestroyWidget(meter->meter_window); meter->meter_window=NULL; } /* Kill the meter's network component. */ if (meter->meter_comp!=NULL) { if (CompSelected(meter->meter_comp)) UnselectComponent(meter->meter_comp); KillComponent(meter->meter_comp); } free_memory_meter_stuff(meter); free ((char *) meter); comp = (MComponent *)scomponent->co_picture; comp->num_meters--; /* Reset the toggle button in the parameter window. */ if (CompParamWindowOpen(comp)) { FlipMeterToggle(comp->param_window, parameter, OFF); } /* Change the values for the parameter */ parameter->p_my_picture = (caddr_t) NULL; parameter->p_flags &= ~MeterMask; /* eliminate the meter from the m_list */ l_del(m_list, parameter); /* return status */ return (OK); } /**********************************************************************************************************************************************/ void free_memory_meter_stuff(METER *meter) { /* if memory meter get rid of TH */ if (meter->th != NULL) { free((char *) meter->th->data_array); free((char *) meter->th); meter->th = (TH *) NULL; } /* if histogram meter get rid of private data */ if (meter->hist != (HISTO_METER *) NULL) { free((char *) meter->hist->data_array); free((char *) meter->hist->hist_array); free((char *) meter->hist); meter->hist = (HISTO_METER *) NULL; } } /********************************************************************************************************************************************/ Widget BuildMeterWindow(METER *meter) { Widget form, label, draw_area; XmString str; char buf[60]; Pixel bg; Position x,y; bg=the_environment.component_color[meter->scomponent->co_type]; form = XtVaCreateWidget("meter_window", xmFormWidgetClass, meter_w, XmNbackground, bg, XmNuserData, meter, XmNx, (Position)meter->x, XmNy, (Position)meter->y, NULL); XtOverrideTranslations(form, the_environment.meter_window_translations); if (meter->display_name) { strncpy(buf,meter->scomponent->co_name,30); buf[30]='\0'; strcat(buf,": "); strcat(buf,meter->name); str=XmStringCreateSimple(buf); label = XtVaCreateManagedWidget("meter_label", xmLabelGadgetClass, form, XmNbackground, bg, XmNlabelString, str, XmNuserData, meter, NULL); XmStringFree(str); } else { label=NULL; } draw_area = XtVaCreateManagedWidget("meter_draw_area",xmDrawingAreaWidgetClass, form, XmNbackground, bg, XmNuserData, meter, XmNtopWidget, label, XmNtopAttachment, meter->display_name? XmATTACH_WIDGET : XmATTACH_FORM, XmNwidth, (Dimension)meter->width, XmNheight, (Dimension)meter->height, NULL); XtOverrideTranslations(draw_area, the_environment.meter_window_translations); XtAddEventHandler(draw_area, ExposureMask, False, (XtEventHandler)meter_expose_event_handler, meter); XtVaSetValues(form, XmNwidth, (Dimension)meter->width, NULL); XtManageChild(form); /* In case the bulletin board didn't like the given meter position. */ XtVaGetValues(form, XmNx, &x, XmNy, &y, NULL); meter->x=(int)x; meter->y=(int)y; meter->label=label; meter->draw_area=draw_area; return(form); } /********************************************************************************************************************************************/ void meter_expose_event_handler(Widget meter_window, METER *meter, XExposeEvent *xexpose) { if (xexpose->count==0) { paint_meter(meter->scomponent, meter->parameter, meter, xexpose); } } /* This routine accepts a pointer to a parameter and redraws its meter */ void xprintf(meter, line, str) /* written at UMCP */ METER *meter; int line; char *str; { XTextItem xtext; xtext.chars = str; xtext.nchars = strlen(str); xtext.font = the_environment.meter_font; xtext.delta = 0; XDrawText(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, 2, (the_environment.meter_font_info->ascent + the_environment.meter_font_info->descent + 2) * line, &xtext, 1); } Status paint_meter(scomponent, parameter, meter, ev) COMPONENT *scomponent; /* pointer to component's datastructure */ PARAM *parameter; /* pointer to the parameter */ METER *meter; XExposeEvent *ev; /* event to figure out what needs to be painted*/ { int length, height, width; int color; /* color for binary graph */ TH *time_history; /* meter pointer for memory meter*/ HISTO_METER *histogram; register int window_position, data_position; register double value; int counter, i, line, j; XTextItem xtext; int y1, y2; Packet *packet; queue *q; double floor(), log(); int expose_x, expose_y, expose_width, expose_height; char *text, *remaining; unsigned int xwidth, xheight; if (meter == NULL) meter = (METER *) parameter->p_my_picture; /* If we are processing an expose event, and the meter is *not* one of the time history types, punt if there are more events to come (ev->count > 0). */ { int type = parameter->p_display_type & MeterTypeMask; if (ev && (type == BAR_GRAPH || type == LOG || type == BINARY) && ev->count > 0) return; } width = meter->width; height = meter->height; if (ev) { expose_x = ev->x; expose_y = ev->y; expose_width = ev->width; expose_height = ev->height; } else { expose_x = expose_y = 0; expose_width = width; expose_height = height; } /* Switch between the different meter types */ switch (parameter->p_display_type & MeterTypeMask) { case (BAR_GRAPH): /* meter is a colored bar */ /* Get length of bar and its height */ value = ((*parameter->p_calc_val) (scomponent, parameter)); /* Check needed because some older components do not initialize p_scale--it is zero. */ value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; if (value < 0) value = 0; length = (int) ((value / (floor(value-0.0001)+ 1)) * width); /* Draw the bar */ if (the_environment.monochrome == 0) XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.text_color); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, 0, 0, length, height); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.component_color[scomponent->co_type]); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, length, 0, (width - length), height); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); break; case (LOG): /* meter is a colored bar */ /* Get length of bar and its height */ value = ((*parameter->p_calc_val) (scomponent, parameter)); value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; if (value > 1) value = log(value); else value = 0; length = (int) ((value / (floor(value-0.0001)+ 1)) * width); /* Draw the bar */ if (the_environment.monochrome == 0) XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.text_color); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, 0, 0, length, height); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.component_color[scomponent->co_type]); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, length, 0, (width - length), height); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); break; case (BINARY): color = (int) ((*parameter->p_calc_val)(scomponent, parameter) + 0.5); if (color == 0) { if (the_environment.monochrome) color = BlackPixel(the_environment.the_display, the_environment.the_screen); else color = the_environment.fore_color; } else if (color == 1) color = WhitePixel(the_environment.the_display, the_environment.the_screen); XSetForeground(the_environment.the_display, the_environment.the_gc, color); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, 0, 0, width, height); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); break; case (TIME_HISTORY): time_history = (TH *) meter->th; data_position = time_history->data_tail + expose_x; if (data_position >= width) data_position -= width; { int xlimit = min(time_history->data_length, expose_x + expose_width); for (window_position = expose_x; window_position < xlimit; ++window_position) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, window_position, height, window_position, (height - ((int)((time_history->data_array[data_position] / time_history->divider) * height)))); ++data_position; if (data_position == width) data_position = 0; } } for (counter = 1; counter != time_history->divider; ++counter) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, expose_x, ((int) (counter * (height / time_history->divider))), expose_x + expose_width, ((int) (counter * (height / time_history->divider)))); } break; case (TIME_HISTORY_D): time_history = (TH *) meter->th; data_position = time_history->data_tail + expose_x; if (data_position >= width) data_position -= width; { int xlimit = min(time_history->data_length, expose_x + expose_width); for (window_position = expose_x; window_position < xlimit; ++window_position) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, window_position, height, window_position, (height - ((int)((time_history->data_array[data_position] / time_history->divider) * height)))); ++data_position; if (data_position == width) data_position = 0; } } for (counter = 1; counter != time_history->divider; ++counter) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, expose_x, ((int) (counter * (height / time_history->divider))), expose_x + expose_width, ((int) (counter * (height / time_history->divider)))); } break; case (DELTA): time_history = (TH *) meter->th; data_position = time_history->data_tail + expose_x; if (data_position >= width) data_position -= width; { int xlimit = min(time_history->data_length, expose_x + expose_width); for (window_position = expose_x; window_position < xlimit; ++window_position) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, window_position, height, window_position, (height - ((int)((time_history->data_array[data_position] / time_history->divider) * height)))); ++data_position; if (data_position == width) data_position = 0; } } for (counter = 1; counter != time_history->divider; ++counter) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, expose_x, ((int) (counter * (height / time_history->divider))), expose_x + expose_width, ((int) (counter * (height / time_history->divider)))); } break; /* case (QUEUE): parameter = meter->parameter; q = (queue *) parameter->u.p; packet = (Packet *) (q->q_head)->qe_data; break; */ case (HISTOGRAM): { extern void histogram_draw_cell (); int leftcell; int rightcell; int cell; HISTO_METER *hist; hist = meter->hist; /* * Assume meter->width != 0 */ leftcell = floor (((double) hist->hist_cells) * (((double) expose_x) / ((double) meter->width))); rightcell = leftcell + ceil (((double) hist->hist_cells) * (((double) expose_width) / ((double) meter->width))); if (rightcell > hist->hist_cells) { rightcell = hist->hist_cells; } for (cell = leftcell; cell < rightcell; cell++) { histogram_draw_cell (meter, hist, cell, expose_y, expose_height); } } break; case (TEXT_METER): default: XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); text = ((*parameter->p_make_short_text) (scomponent, parameter)); remaining = text; line = 1; xwidth = 0; while (remaining) { remaining = (char *) index(text, '$'); if (remaining) *remaining = '\0'; xprintf(meter, line, text); xwidth = max(xwidth, XTextWidth(the_environment.meter_font_info, text, strlen(text))); text = remaining + 1; line++; } xheight = (the_environment.meter_font_info->ascent + 2 + the_environment.meter_font_info->descent) * (line - 1) + 2; xwidth += 10; if (meter->height < xheight) meter->height = xheight; if (meter->width < xwidth) meter->width = xwidth; XtVaSetValues(meter->draw_area, XmNwidth, meter->width, XmNheight, meter->height, NULL); break; } /* eric I don't think we need this anymore if (meter->display_name) { xtext.chars = meter->name; xtext.nchars = strlen(meter->name); xtext.font = the_environment.meter_font; xtext.delta = 0; XDrawText(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, 2, the_environment.meter_font_info->ascent + the_environment.meter_font_info->descent + 2, &xtext, 1); } */ return (OK); } update_time_history_meter(scomponent,parameter) COMPONENT *scomponent; PARAM *parameter; { TH *time_history; METER *meter; register double value; register int height, width; int counter, main_counter; int number_of_pixels; double temp_value; meter = (METER *) parameter->p_my_picture; time_history = (TH *) meter->th; height = meter->height; width = meter->width; if (ev_now() - time_history->time < time_history->time_increment) { value = ((*parameter->p_calc_val) (scomponent, parameter)); value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; time_history->data_array[time_history->data_head] += value; time_history->counter += 1; return (TRUE); } number_of_pixels = (int) (ev_now() - time_history->time) / time_history->time_increment; if (number_of_pixels < 1) { number_of_pixels = 1; time_history->time = (double) ev_now(); } else { time_history->time += number_of_pixels * time_history->time_increment; } value = ((*parameter->p_calc_val) (scomponent, parameter)); value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; time_history->data_array[time_history->data_head] += value; /* Divide the sum by n to get average value for latest time increment. Then draw the line at the appropriate place. */ temp_value = time_history->data_array[time_history->data_head] / (time_history->counter +1); for (main_counter = 0; main_counter != number_of_pixels; ++main_counter) { time_history->data_array[time_history->data_head] = temp_value; if (time_history->data_array[time_history->data_head] > time_history->divider) { time_history->divider = floor(time_history->data_array[time_history->data_head]) + 1; if (the_environment.iconified == FALSE) { /* Need to clear the window here since paint_meter no longer does. */ XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(scomponent, parameter, meter, NULL); } } else { if (the_environment.iconified == FALSE) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, (time_history->data_length - 1), height, (time_history->data_length - 1), (height - ((int)(((time_history->data_array[time_history->data_head]) / time_history->divider) * height)))); } } time_history->counter = 0; /* Now increment the pointers and take care of special cases. */ ++(time_history->data_head); if (time_history->data_head >= width) time_history->data_head = 0; time_history->data_array[time_history->data_head] = 0; ++(time_history->data_length); if (time_history->data_length >= width) { time_history->data_length = (int) (0.75 * width); time_history->data_tail = (int) time_history->data_head - time_history->data_length; if (time_history->data_tail < 0) time_history->data_tail += width; time_history->divider = 1; counter = time_history->data_tail -1; do { ++counter; if (counter == width) counter = 0; if (time_history->data_array[counter] > time_history->divider) time_history->divider = floor(time_history->data_array[counter]) +1; } while (counter != time_history->data_head); XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(scomponent, parameter, meter, NULL); } } return (TRUE); } update_time_history_d_meter(scomponent, parameter) COMPONENT *scomponent; PARAM *parameter; { TH *time_history; METER *meter; register double value; register int height, width; int counter; meter = (METER *) parameter->p_my_picture; time_history = (TH *) meter->th; height = meter->height; width = meter->width; value = ((*parameter->p_calc_val) (scomponent, parameter)); value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; time_history->data_array[time_history->data_head] = value; if (time_history->data_array[time_history->data_head] > time_history->divider) { time_history->divider = floor(time_history->data_array[time_history->data_head]) +1; if (the_environment.iconified == FALSE) { XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(scomponent, parameter, meter, NULL); } } else { if (the_environment.iconified == FALSE) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, (time_history->data_length - 1), height, (time_history->data_length - 1), (height - ((int)(((time_history->data_array[time_history->data_head]) / time_history->divider) * height)))); } } /* Now increment the pointers and take care of special cases. */ ++(time_history->data_head); if (time_history->data_head >= width) time_history->data_head = 0; ++(time_history->data_length); if (time_history->data_length >= width) { time_history->data_length = (int) (0.75 * width); time_history->data_tail = (int) time_history->data_head - time_history->data_length; if (time_history->data_tail < 0) time_history->data_tail += width; time_history->divider = 1; counter = time_history->data_tail -1; do { ++counter; if (counter == width) counter = 0; if (time_history->data_array[counter] > time_history->divider) time_history->divider = floor(time_history->data_array[counter]) +1; } while (counter != time_history->data_head); XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(scomponent, parameter, meter, NULL); } return (TRUE); } update_delta_meter(scomponent, parameter) COMPONENT *scomponent; PARAM *parameter; { TH *time_history; METER *meter; register double value; register int height, width; int counter; meter = (METER *) parameter->p_my_picture; time_history = (TH *) meter->th; height = meter->height; width = meter->width; value = (double) ((*parameter->p_calc_val) (scomponent, parameter)); value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; time_history->data_array[time_history->data_head] = (double) value - time_history->counter; if(time_history->data_array[time_history->data_head] < 0) time_history->data_array[time_history->data_head] *= -1; time_history->counter = (double) value; if (time_history->data_array[time_history->data_head] > time_history->divider) { time_history->divider = floor(time_history->data_array[time_history->data_head]) +1; if (the_environment.iconified == FALSE) { XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(scomponent, parameter, meter, NULL); } } else { if (the_environment.iconified == FALSE) { XDrawLine(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, (time_history->data_length - 1), height, (time_history->data_length - 1), (height - ((int)(((time_history->data_array[time_history->data_head]) / time_history->divider) * height)))); } } /* Now increment the pointers and take care of special cases. */ ++(time_history->data_head); if (time_history->data_head >= width) time_history->data_head = 0; ++(time_history->data_length); if (time_history->data_length >= width) { time_history->data_length = (int) (0.75 * width); time_history->data_tail = (int) time_history->data_head - time_history->data_length; if (time_history->data_tail < 0) time_history->data_tail += width; time_history->divider = 1; counter = time_history->data_tail -1; do { ++counter; if (counter == width) counter = 0; if (time_history->data_array[counter] > time_history->divider) time_history->divider = floor(time_history->data_array[counter]) +1; } while (counter != time_history->data_head); XClearWindow(the_environment.the_display, XtWindow(meter->draw_area)); paint_meter(scomponent, parameter, meter, NULL); } return (TRUE); } /* This routine will accept a pointer to a meter and change its time_increment parameter to whatever the user wishes. */ int change_th_time_increment(time_history) TH *time_history; { char answer_string[20]; char dummy_string[20]; float increment; xprintclear(); printx("Please enter sampling time increment for meter (in milliseconds)["); sprintf(dummy_string, "%.2lf", ((double) (time_history->time_increment) / 100)); printx(dummy_string); printx("]: "); if (xinput(answer_string, 20) == 0) { xprintclear(); /* user just typed return */ return (0); } xprintclear(); return (1); } void histogram_draw_cell (meter, hist, cell, y, dy) METER *meter; HISTO_METER *hist; int cell; int y; int dy; { double f; int celly; int x; int dx; f = ((double) hist->hist_array [ cell ]) / ((double) hist->data_samples); celly = meter->height - rint (f * ((double) meter->height)); /* * Relative left edge of this cell */ f = ((double) cell) / ((double) hist->hist_cells); /* * Pixel horizontal position of this cell */ x = rint ((double) meter->width * f); /* * Relative right edge of this cell */ f = (double) (cell + 1) / (double) hist->hist_cells; /* * Pixel horizontal extent of this cell */ dx = rint ((double) meter->width * f) - x; if (y > celly) { /* * Color in entire area */ XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, x, y, dx, dy); } else if ((y + dy) > celly) { /* * Part empty and part full */ XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, x, celly, dx, (y + dy) - celly); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.component_color[meter->scomponent->co_type]); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, x, y, dx, celly - y); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); } else { /* * Draw some empty space */ XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.component_color[meter->scomponent->co_type]); XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, x, y, dx, dy); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); } } update_histogram_meter(scomponent,parameter) COMPONENT *scomponent; PARAM *parameter; { HISTO_METER *hist; METER *meter; double value; double oldvalue; void histogram_diminish (); void histogram_augment (); meter = (METER *) parameter->p_my_picture; hist = (HISTO_METER *) meter->hist; value = ((*parameter->p_calc_val) (scomponent, parameter)); value /= parameter->p_scale > 0.0 ? parameter->p_scale : 1.0; /* * If the sample value is out of the "interesting" * range, then ignore it. */ if ((value > hist->hist_max) || (value < hist->hist_min)) { return (TRUE); } if (hist->data_obs >= hist->data_samples) { /* * If the inn is full, remove the oldest sample and * diminish the histogram accordingly. */ oldvalue = hist->data_array [ hist->data_head ]; /* * Do nothing if the new and old samples are * the same. */ if (oldvalue != value) { histogram_diminish (meter, hist, oldvalue); /* * If the inn is full, replace the oldest sample by * this newest one. */ hist->data_array [ hist->data_head ] = value; /* * Augment the histogram */ histogram_augment (meter, hist, value); } hist->data_head++; if (hist->data_head >= hist->data_samples) { hist->data_head = 0; } } else { /* * If the inn is not full, then just add this sample * to the growing list. */ hist->data_array [ hist->data_obs ] = value; /* * Augment the histogram */ histogram_augment (meter, hist, value); } hist->data_obs++; return (TRUE); } void histogram_augment (meter, hist, value) METER *meter; HISTO_METER *hist; double value; { int cell; void histogram_mutate (); /* * Compute the cell into which this sample falls */ cell = floor ((value - hist->hist_min) / hist->hist_intrvl); /* * Augment the cell */ hist->hist_array [ cell ]++; /* * Draw this sample on the display */ XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); histogram_mutate (meter, hist, cell); } void histogram_diminish (meter, hist, value) METER *meter; HISTO_METER *hist; double value; { int cell; void histogram_mutate (); /* * Compute the cell into which this sample falls */ cell = floor ((value - hist->hist_min) / hist->hist_intrvl); /* * Erase this sample from the display */ XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.component_color[meter->scomponent->co_type]); histogram_mutate (meter, hist, cell); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); /* * Diminish the cell */ hist->hist_array [ cell ]--; } void histogram_mutate (meter, hist, cell) METER *meter; HISTO_METER *hist; int cell; { int x; int dx; int y; int dy; double mh; double mw; double hc; double hs; double cv; /* * Pre-convert common values */ mh = (double) meter->height; mw = (double) meter->width; hc = (double) hist->hist_cells; hs = (double) hist->data_samples; cv = (double) hist->hist_array [ cell ]; /* * Pixel horizontal position of this cell */ x = rint (mw * (((double) cell) / hc)); /* * Pixel horizontal extent of this cell */ dx = rint (mw * (((double) (cell + 1)) / hc)) - x; /* * Pixel top position of this sample */ y = meter->height - rint (mh * (cv / hs)); /* * Pixel vertical extent of this sample */ dy = meter->height - rint (mh * ((cv - 1.0) / hs)) - y; /* * Draw this sample on the display */ XFillRectangle(the_environment.the_display, XtWindow(meter->draw_area), the_environment.the_gc, x, y, dx, dy); }