/* $Id: meters.c,v 10.1 92/10/06 22:58:23 ca Exp $ */ #include #include #include #include #include "sim.h" #include "simx.h" #include "xtables.h" #include "meters.h" #include "event.h" extern double rint (); extern double floor (); extern double ceil (); extern GC color_gc[]; extern int packet_colors[]; METERTYPE meter_types[] = { { "METER TYPES :", 0, 0, 0}, { "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} }; METERINFOSTRING meter_info_names[] = { { "Meter name" }, { "Component name" }, { "Meter type" }, { "Scale" }, { "Sampling time increment" }, { "Display meter name" }, { "Display scale" }, { "Histogram Min" }, { "Histogram Max" }, { "Histogram Cells" }, { "Histogram Samples" } }; /* 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. They are initially attached to the bottom of a conmponent's window and will initially probably have the same width as the component's window. The user will be able to change the type, size, location ,etc. of the meter after its craetion */ /* This routine takes a pointer to a component and one of its parameters and creates a meter for it. */ int pop_meter(scomponent, parameter, oldx, oldy, oldwidth, oldheight) COMPONENT *scomponent; /* pointer to the component */ PARAM *parameter; int oldx, oldy, oldwidth, oldheight; { Window meter_window; /* window created for meter */ short height, width; /* new height of component window */ short x, y; unsigned array_size; int num_classes; int i; XWindowAttributes xinfo; /* x information */ XCOMPONENT *xcomponent; /* xcomponent structure of component */ PARAM *temp_parameter; /* pointer to the parameter */ TH *time_history; METER *meter; HISTO_METER *histogram; /* Check to see that the parameter can be metered */ if (!(parameter->p_flags & CanHaveMeterMask)) { return (-1); } /* * Get dimensions for meter window */ xcomponent = (XCOMPONENT *) scomponent->co_picture; if (xcomponent->num_meters == 0) { x = xcomponent->x; y = xcomponent->y + xcomponent->height + 2; } else { temp_parameter = xcomponent->m_list[xcomponent->num_meters - 1]; meter = (METER *) temp_parameter->p_my_picture; x = meter->x; y = meter->y + meter->height + 2; } /* get width and height for meter window */ 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 (oldwidth != 0) { x = oldx; y = oldy; } /* Create the new window for the meter and map it. */ meter_window = XCreateSimpleWindow(the_environment.the_display, the_environment.back_window, x, y, width, height, the_environment.border_width, the_environment.fore_color, the_environment.component_color[scomponent->co_type]); XSelectInput(the_environment.the_display, meter_window, ExposureMask); XMapWindow(the_environment.the_display, meter_window); /* 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 */ if (xcomponent->num_meters == 0) { xcomponent->m_list = (PARAM **) sim_calloc(1, sizeof(PARAM)); } else { xcomponent->m_list= (PARAM **) realloc((char *) xcomponent->m_list, (unsigned) sizeof(PARAM) * (xcomponent->num_meters + 1)); } xcomponent->m_list[xcomponent->num_meters] = parameter; xcomponent->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; strncpy(meter->name, (*(parameter->p_make_text)) (scomponent, parameter), 10); meter->name[10] = '\0'; meter->type = parameter->p_display_type & MeterTypeMask; meter->width = width; meter->height = height; meter->x = x; meter->y = y; meter->info_window = (int) NULL; meter->meter_window = meter_window; meter->display_name = 1; meter->display_scale = 1; XSaveContext(the_environment.the_display, meter_window, meter_xtable, (caddr_t) meter); /* check to see if it is a memory meter, and if so, create the TH structure */ 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; XSaveContext(the_environment.the_display, meter->meter_window, th_xtable, (caddr_t) time_history); 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)); XSaveContext(the_environment.the_display, meter->meter_window, th_xtable, (caddr_t) time_history); meter->hist = histogram; } /* Return 1 */ return (1); } /* 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window); 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->width != xwidth) { meter->height = xheight; meter->width = xwidth; XResizeWindow(the_environment.the_display, meter->meter_window, xwidth, xheight); } break; } 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, meter->meter_window, the_environment.the_gc, 2, the_environment.meter_font_info->ascent + the_environment.meter_font_info->descent + 2, &xtext, 1); } return (OK); } /* 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. */ unpop_meter(scomponent, parameter) COMPONENT *scomponent; /* component's data structure */ PARAM *parameter; /* pointer to the paramter */ { int counter; XCOMPONENT *xcomponent; METER *meter; meter = (METER *) parameter->p_my_picture; if (meter->info_window != (int) NULL) unpop_meter_info_window(meter); /* if memory meter get rid of TH */ if (meter->th != NULL) { free((char *) meter->th->data_array); free((char *) meter->th); XDeleteContext(the_environment.the_display, meter->meter_window, th_xtable); } /* 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); XDeleteContext(the_environment.the_display, meter->meter_window, th_xtable); } /* Change the values for the parameter */ free ((char *) meter); XDeleteContext(the_environment.the_display, meter->meter_window, meter_xtable); XDestroyWindow(the_environment.the_display, meter->meter_window); parameter->p_my_picture = (caddr_t) NULL; parameter->p_flags &= ~MeterMask; /* eliminate the meter from the xcomponent m_list, do a sanity check */ xcomponent = (XCOMPONENT *) scomponent->co_picture; for (counter = 0; counter != (xcomponent->num_meters); ++counter) if (xcomponent->m_list[counter] == parameter) break; if (counter == (--(xcomponent->num_meters))) /* i.e. last */ { xcomponent->m_list = (PARAM **) realloc((char *) xcomponent->m_list, (unsigned) sizeof(PARAM) * xcomponent->num_meters); return (OK); } /* repack the pointers */ while (counter != xcomponent->num_meters) { xcomponent->m_list[counter] = xcomponent->m_list[1 + counter]; ++counter; } /* return status */ 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, meter->meter_window); paint_meter(scomponent, parameter, meter, NULL); } } else { if (the_environment.iconified == FALSE) { XDrawLine(the_environment.the_display, meter->meter_window, 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, meter->meter_window); 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, meter->meter_window); paint_meter(scomponent, parameter, meter, NULL); } } else { if (the_environment.iconified == FALSE) { XDrawLine(the_environment.the_display, meter->meter_window, 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, meter->meter_window); 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, meter->meter_window); paint_meter(scomponent, parameter, meter, NULL); } } else { if (the_environment.iconified == FALSE) { XDrawLine(the_environment.the_display, meter->meter_window, 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, meter->meter_window); paint_meter(scomponent, parameter, meter, NULL); } return (TRUE); } toggle_meter(xcomponent, position) XCOMPONENT *xcomponent; int position; { PARAM *parameter; int y; parameter = xcomponent->p_list[position]; if ( ! (parameter->p_flags & CanHaveMeterMask)) return; if (parameter->p_flags & MeterMask) { unpop_meter(xcomponent->scomponent, parameter); /* paint_info_window(xcomponent->scomponent, xcomponent, NULL);*/ } else { pop_meter(xcomponent->scomponent, parameter, 0, 0, 0, 0); /* paint_info_window(xcomponent->scomponent, xcomponent, NULL);*/ } y = position * the_environment.info_window_height; XFillRectangle(the_environment.the_display, xcomponent->info_window, (parameter->p_flags & MeterMask ? the_environment.meter_or_log_indicator_gc : xcomponent->back_gc), 0, (y > 0 ? y+1 : 0), the_environment.meter_indicator_width-1, the_environment.info_window_height - (y > 0 ? 1 : 0)); } /* This routine is a user interface allowing the user to choose his choice of meter type. */ int get_meter_type_info(parameter) PARAM *parameter; { int num_meters; int counter, position; Window the_window; XEvent event; XButtonPressedEvent *bevent; XExposeEvent *xevent; XTextItem xtext; for (num_meters = 0; meter_types[num_meters].meter_type != -1; ++num_meters) ; the_window = XCreateSimpleWindow(the_environment.the_display, the_environment.back_window, METER_X, METER_Y, METER_WIDTH, (num_meters * METER_HEIGHT), the_environment.border_width, the_environment.fore_color, the_environment.edit_color); XSelectInput(the_environment.the_display, the_window, ExposureMask); XMapWindow(the_environment.the_display, the_window); for(;;) { XNextEvent(the_environment.the_display, &event); if (event.type == ButtonPress) { bevent = (XButtonPressedEvent *) &event; if (bevent->subwindow == the_window) { position = (bevent->y - METER_Y)/ METER_HEIGHT; if (position != 0) { if ((meter_types[position].meter_type != LOG) || (parameter->p_flags & CanHaveLogMask)) { XDestroyWindow(the_environment.the_display, the_window); return (meter_types[position].meter_type); } } } } else if (event.type == Expose) { xevent = (XExposeEvent *) &event; if (xevent->window == the_window) { for (counter = 0; counter != num_meters; ++counter) { if (meter_types[counter].meter_type == (parameter->p_display_type & MeterTypeMask)) { XFillRectangle(the_environment.the_display, the_window, the_environment.the_gc, 0, (counter * METER_HEIGHT), METER_WIDTH, METER_HEIGHT); xtext.chars = meter_types[counter].meter_name; xtext.nchars = strlen(meter_types[counter].meter_name); xtext.font = the_environment.info_font; xtext.delta = 0; XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.edit_color); XDrawText(the_environment.the_display, the_window, the_environment.the_gc, 7, the_environment.info_font_info->ascent + the_environment.info_font_info->descent + (counter * METER_HEIGHT) + 7, &xtext, 1); XSetForeground(the_environment.the_display, the_environment.the_gc, the_environment.fore_color); } else { xtext.chars = meter_types[counter].meter_name; xtext.nchars = strlen(meter_types[counter].meter_name); xtext.font = the_environment.info_font; xtext.delta = 0; XDrawText(the_environment.the_display, the_window, the_environment.the_gc, 7, the_environment.info_font_info->ascent + the_environment.info_font_info->descent + (counter * METER_HEIGHT) + 7, &xtext, 1); } if (counter != 0) XDrawLine(the_environment.the_display, the_window, the_environment.the_gc, 0, (counter * METER_HEIGHT), METER_WIDTH, (counter * METER_HEIGHT)); } } else { general_expose_event_handler(xevent); } } } } /* 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, "%.2f", ((double) (time_history->time_increment) / 100)); printx(dummy_string); printx("]: "); if (xinput(answer_string, 20) == 0) { xprintclear(); /* user just typed return */ return ((int) NULL); } xprintclear(); if (sscanf(answer_string, "%f", &increment) == (int) NULL) return ((int) NULL); time_history->time_increment = (((int) (increment * 100))); return (1); } pop_meter_info_window(meter) METER *meter; { int x,y; int window_height; XWindowAttributes xinfo; if (meter->info_window != (int) NULL) return (-1); window_height = the_environment.meter_info_window_entries * the_environment.info_window_height; /* Next, find x and y coordinates, this will be messy */ /* First, get x value */ if ((meter->x + (meter->width /2)) < the_environment.x_center) x = meter->x + meter->width + the_environment.info_window_horizontal_padding; else x = meter->x - the_environment.info_window_horizontal_padding - the_environment.info_window_width; /* Next, get y value */ if ((meter->y + ( meter->height / 2)) < the_environment.y_center) y = meter->y + meter->height + the_environment.info_window_horizontal_padding; else y = meter->y - the_environment.info_window_horizontal_padding - window_height; meter->info_window = XCreateSimpleWindow(the_environment.the_display, the_environment.back_window, x, y, the_environment.info_window_width, window_height, the_environment.border_width, the_environment.fore_color, the_environment.component_color[meter->scomponent->co_type]); meter->info_x = x; meter->info_y = y; meter->info_width = the_environment.info_window_width; meter->info_height = window_height; XSelectInput(the_environment.the_display, meter->info_window, ExposureMask); XMapWindow(the_environment.the_display, meter->info_window); XSaveContext(the_environment.the_display, meter->info_window, meterinfo_xtable, (caddr_t) meter); return (1); } unpop_meter_info_window(meter) METER *meter; { if (meter->info_window == (int) NULL) return (-1); XDeleteContext(the_environment.the_display, meter->info_window, meterinfo_xtable); XDestroyWindow(the_environment.the_display, meter->info_window); meter->info_window = (int) NULL; return (OK); } toggle_meter_info_window(meter) METER *meter; { if (meter->info_window == (int) NULL) pop_meter_info_window(meter); else unpop_meter_info_window(meter); } paint_meter_info_window(meter) METER *meter; { int i; int y; Window info_window; char *a_string; char output_string[50]; char *meter_info_make_name_string(); char *meter_info_make_value_string(); XTextItem xtext; info_window = meter->info_window; for (i = 0; i != the_environment.meter_info_window_entries; ++i) { y = i * the_environment.info_window_height; a_string = (char *) meter_info_make_name_string(i); strcpy(output_string, a_string); strcat(output_string, ": "); a_string = (char *) meter_info_make_value_string(meter, i); strcat(output_string, a_string); xtext.chars = output_string; xtext.nchars = strlen(output_string); xtext.font = the_environment.info_font; xtext.delta = 0; XDrawText(the_environment.the_display, info_window, the_environment.the_gc, the_environment.info_window_horizontal_padding, y + the_environment.info_window_vertical_padding, &xtext, 1); if (i != 0) XDrawLine(the_environment.the_display, info_window, the_environment.the_gc, 0, y, the_environment.info_window_width, y); } } char *meter_info_make_name_string(position) int position; { if ((position < 0) || (position > 10)) { return ('\0'); } else { return meter_info_names[position].string; } } char *meter_info_make_value_string(meter, position) METER *meter; int position; { static char result_string[60]; char temp_string[30]; char *string_pointer; PARAM *parameter; double f; int k; if (position == 0) { strcpy(result_string, meter->name); return(result_string); } if (position == 1) { parameter = (PARAM *)meter->scomponent->co_params->q_head; string_pointer = (*(parameter->p_make_text))(meter->scomponent, parameter); strcpy(result_string, string_pointer); return(result_string); } if (position == 2) { strcpy(result_string, meter_types[meter->parameter->p_display_type & MeterTypeMask].meter_name); return(result_string); } if (position == 3) { sprintf(temp_string, "%g", meter->parameter->p_scale > 0.0 ? meter->parameter->p_scale : 1.0); strcpy(result_string, temp_string); return (result_string); } if (position == 4) { if (meter->th != NULL) { sprintf(temp_string, "%.2f", ((double) (meter->th->time_increment) / 100)); strcpy(result_string, temp_string); } else { strcpy(result_string, "0"); } strcat(result_string, " milliseconds"); return (result_string); } if (position == 5) { if (meter->display_name) strcpy(result_string, "on"); else strcpy(result_string, "off"); return (result_string); } if (position == 6) { if (meter->display_scale) strcpy(result_string, "on"); else strcpy(result_string, "off"); return (result_string); } if (position == 7) { f = (meter->type == HISTOGRAM) ? meter->hist->hist_min : 0.0; sprintf(temp_string, "%g", f); strcpy(result_string, temp_string); return (result_string); } if (position == 8) { f = (meter->type == HISTOGRAM) ? meter->hist->hist_max : 0.0; sprintf(temp_string, "%g", f); strcpy(result_string, temp_string); return (result_string); } if (position == 9) { k = (meter->type == HISTOGRAM) ? meter->hist->hist_cells : 0; sprintf(temp_string, "%d", k); strcpy(result_string, temp_string); return (result_string); } if (position == 10) { k = (meter->type == HISTOGRAM) ? meter->hist->data_samples : 0; sprintf(temp_string, "%d", k); strcpy(result_string, temp_string); return (result_string); } return ('\0'); /* The program should never get here */ } meter_button_event_handler(meter, bevent, c_m_r) METER *meter; XButtonPressedEvent *bevent; int c_m_r; { PARAM *parameter; int x,y,height,width; int i, counter; double *temp_array; XWindowAttributes xinfo; parameter = meter->parameter; if ((bevent->button == user_bindings.resize.button) && (bevent->state == user_bindings.resize.key) && (c_m_r == 1)) { x = meter->x; y = meter->y; width = meter->width; height = meter->height; if (resize_window(&x, &y, &width, &height, bevent->x, bevent->y, (int) (meter_types[parameter->p_display_type & MeterTypeMask].width * the_environment.meter_window_width), (int) (meter_types[parameter->p_display_type & MeterTypeMask].height * the_environment.meter_window_height)) != -1 && (width != meter->width || height != height)) { XMoveResizeWindow(the_environment.the_display, meter->meter_window, x, y, width, 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, meter->meter_window); paint_meter(meter->scomponent, parameter, meter, NULL); } } else if ((bevent->button == user_bindings.select.button) && (bevent->state == user_bindings.select.key) && (c_m_r == 0)) { toggle_meter_info_window(meter); } else if ((bevent->button == user_bindings.move.button) && (bevent->state == user_bindings.move.key) && (c_m_r == 1)) { /* XGetWindowAttributes(the_environment.the_display, meter->meter_window, &xinfo);*/ x = bevent->x; y = bevent->y; move_window(&x, &y, meter->width, meter->height, x - meter->x, y - meter->y); XMoveWindow(the_environment.the_display, meter->meter_window, x, y); meter->x = x; meter->y = y; } } meter_info_window_button_event_handler(meter, bevent, c_m_r) METER *meter; XButtonPressedEvent *bevent; int c_m_r; { XWindowAttributes xinfo; int x,y; if ((bevent->button == user_bindings.select.button) && (bevent->state == user_bindings.select.key) && (c_m_r == 0)) { if ((meter = (METER *) edit_meter(meter, (int) (bevent->y - meter->info_y) / the_environment.info_window_height)) != NULL) { /* Ugly, but in general everything may have to be repainted. */ XClearWindow(the_environment.the_display, meter->meter_window); paint_meter(meter->scomponent, meter->parameter, meter, NULL); /* We'll allow uglyness here as well, as these windows are fairly small and are not used that often. Just clear the whole thing and redraw it. */ XClearWindow(the_environment.the_display, meter->info_window); paint_meter_info_window(meter); } } else if ((bevent->button == user_bindings.move.button) && (bevent->state == user_bindings.move.key) && (c_m_r == 1)) { x = bevent->x; y = bevent->y; move_window(&x, &y, meter->info_width, meter->info_height, x - meter->info_x, y - meter->info_y); XMoveWindow(the_environment.the_display, meter->info_window, x, y); meter->info_x = x; meter->info_y = y; } } 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, 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, meter->meter_window, the_environment.the_gc, x, y, dx, dy); } METER *histogram_adjust_knob (meter, pos) METER *meter; int pos; { char answer_string[20]; float increment; int k; double f; HISTO_METER *hist; char *prompt; char *dummy_string; if (meter->type != HISTOGRAM) { return ((METER *) 0); } hist = meter->hist; xprintclear(); switch (pos) { case 7: prompt = "lower limit on tabulated values"; break; case 8: prompt = "upper limit on tabulated values"; break; case 9: prompt = "number of histogram cells"; break; case 10: prompt = "number of retained histogram samples"; break; default: prompt = "Panic!"; break; } printx("Please enter "); printx(prompt); printx(" ["); dummy_string = meter_info_make_value_string (meter, pos); printx(dummy_string); printx("]: "); if (xinput(answer_string, 20) == 0) { xprintclear(); /* user just typed return */ return (NULL); } xprintclear(); if (sscanf(answer_string, "%f", &increment) == (int) NULL) return (NULL); k = floor (increment); f = (double) increment; switch (pos) { case 7: 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); } break; case 8: 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); } break; case 9: 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); } break; case 10: 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); } break; default: break; } return (meter); }