WFDB Software Package 10.7.0
(15,178 bytes)
/* file: modepan.c G. Moody 30 April 1990
Last revised: 24 April 2020
Mode panel functions for WAVE
-------------------------------------------------------------------------------
WAVE: Waveform analyzer, viewer, and editor
Copyright (C) 1990-2009 George B. Moody
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, see <http://www.gnu.org/licenses/>.
You may contact the author by e-mail (wfdb@physionet.org) or postal mail
(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software,
please visit PhysioNet (http://www.physionet.org/).
_______________________________________________________________________________
*/
#include "wave.h"
#include "xvwave.h"
Panel_item grid_item, opt_item, sig_item, ann_item, ov_item, tim_item, ts_item,
vs_item, redraw_item;
Frame mode_frame;
Panel mode_panel;
/* Undo any mode changes. */
void mode_undo()
{
xv_set(ts_item, PANEL_VALUE, tsa_index, NULL);
xv_set(vs_item, PANEL_VALUE, vsa_index, NULL);
xv_set(sig_item, PANEL_VALUE, sig_mode, NULL);
xv_set(ann_item, PANEL_VALUE, ann_mode, NULL);
xv_set(ov_item, PANEL_VALUE, overlap, NULL);
xv_set(tim_item, PANEL_VALUE, time_mode, NULL);
xv_set(grid_item, PANEL_VALUE, grid_mode, NULL);
xv_set(opt_item, PANEL_VALUE,
(show_subtype & 1) |
((show_chan & 1) << 1) |
((show_num & 1) << 2) |
((show_aux & 1) << 3) |
((show_marker & 1) << 4) |
((show_signame & 1) << 5) |
((show_baseline& 1) << 6) |
((show_level & 1) << 7),
NULL);
}
/* Redraw and take down the window. */
static void redraw_proc(item, event)
Panel_item item;
Event *event;
{
dismiss_mode();
disp_proc(item, event);
}
int mode_popup_active = -1;
char *tchoice[] = {"0.25 mm/hour", "1 mm/hour", "5 mm/hour",
"0.25 mm/min", "1 mm/min", "5 mm/min", "25 mm/min",
"50 mm/min", "125 mm/min", "250 mm/min", "500 mm/min",
"12.5 mm/sec", "25 mm/sec", "50 mm/sec", "125 mm/sec", "250 mm/sec",
"500 mm/sec", "1000 mm/sec", "2000 mm/sec", "5000 mm/sec",
"10 mm/ms", "20 mm/ms", "50 mm/ms", "100 mm/ms", "200 mm/ms", "500 mm/ms"};
char *vchoice[] = { "1 mm/mV", "2.5 mm/mV", "5 mm/mV", "10 mm/mV", "20 mm/mV",
"40 mm/mV", "100 mm/mV" };
/* Set up popup window for adjusting display modes. */
void create_mode_popup()
{
extern void save_defaults(); /* in xvwave.c */
Icon icon;
icon = xv_create(XV_NULL, ICON,
ICON_IMAGE, icon_image,
ICON_LABEL, "View",
NULL);
mode_frame = xv_create(frame, FRAME_CMD,
XV_LABEL, "View",
FRAME_ICON, icon, 0);
mode_panel = xv_get(mode_frame, FRAME_CMD_PANEL, 0);
opt_item = xv_create(mode_panel, PANEL_CHOICE,
PANEL_CHOOSE_ONE, FALSE,
XV_HELP_DATA, "wave:view.show",
PANEL_LABEL_STRING, "Show: ",
PANEL_CHOICE_STRINGS,
"subtype", "`chan' field", "`num' field", "`aux' field",
"markers", "signal names", "baselines", "level", NULL,
PANEL_VALUE, 0,
0);
ts_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
XV_HELP_DATA, "wave:view.time_scale",
PANEL_LABEL_STRING, "Time scale: ",
PANEL_CHOICE_STRINGS,
tchoice[0], tchoice[1], tchoice[2], tchoice[3], tchoice[4],
tchoice[5], tchoice[6], tchoice[7], tchoice[8], tchoice[9],
tchoice[10],tchoice[11],tchoice[12],tchoice[13],tchoice[14],
tchoice[15],tchoice[16],tchoice[17],tchoice[18],tchoice[19],
tchoice[20],tchoice[21],tchoice[22],tchoice[23],tchoice[24],
tchoice[25],
NULL,
PANEL_VALUE, DEF_TSA_INDEX,
PANEL_DEFAULT_VALUE, DEF_TSA_INDEX,
0);
vs_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
XV_HELP_DATA, "wave:view.amplitude_scale",
PANEL_LABEL_STRING, "Amplitude scale: ",
PANEL_CHOICE_STRINGS,
vchoice[0], vchoice[1], vchoice[2], vchoice[3], vchoice[4],
vchoice[5], vchoice[6], NULL,
PANEL_VALUE, DEF_VSA_INDEX,
PANEL_DEFAULT_VALUE, DEF_VSA_INDEX,
0);
sig_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
XV_HELP_DATA, "wave:view.draw",
PANEL_LABEL_STRING, "Draw: ",
PANEL_CHOICE_STRINGS,
"all signals", "listed signals only", "valid signals only", NULL,
PANEL_VALUE, 0,
PANEL_DEFAULT_VALUE, 0,
0);
grid_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
XV_HELP_DATA, "wave:view.grid",
PANEL_LABEL_STRING, "Grid: ",
PANEL_CHOICE_STRINGS,"None", "0.2 s", "0.5 mV", "0.2 s x 0.5 mV",
"0.04 s x 0.1 mV", "1 m x 0.5 mV", "1 m x 0.1 mV",
NULL,
PANEL_VALUE, 0,
PANEL_DEFAULT_VALUE, 3,
0);
ann_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
PANEL_NEXT_ROW, -1,
XV_HELP_DATA, "wave:view.show_annotations",
PANEL_LABEL_STRING, "Show annotations: ",
PANEL_CHOICE_STRINGS,
"centered", "attached to signals", "as a signal", NULL,
PANEL_VALUE, 0,
PANEL_DEFAULT_VALUE, 0,
0);
ov_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
XV_HELP_DATA, "wave:view.overlap",
PANEL_CHOICE_STRINGS,
"avoid overlap", "allow overlap", NULL,
PANEL_VALUE, 0,
PANEL_DEFAULT_VALUE, 0,
0);
tim_item = xv_create(mode_panel, PANEL_CHOICE_STACK,
XV_HELP_DATA, "wave:view.time_display",
PANEL_LABEL_STRING, "Time display: ",
PANEL_CHOICE_STRINGS,
"elapsed", "absolute", "in sample intervals", NULL,
PANEL_VALUE, 0,
PANEL_DEFAULT_VALUE, 0,
0);
xv_create(mode_panel, PANEL_BUTTON,
PANEL_NEXT_ROW, -1,
XV_HELP_DATA, "wave:view.undo",
PANEL_LABEL_STRING, "Undo changes",
PANEL_NOTIFY_PROC, mode_undo,
0);
redraw_item = xv_create(mode_panel, PANEL_BUTTON,
XV_HELP_DATA, "wave:view.redraw",
PANEL_LABEL_STRING, "Redraw",
PANEL_NOTIFY_PROC, redraw_proc,
PANEL_CLIENT_DATA, (caddr_t) '.',
0);
xv_create(mode_panel, PANEL_BUTTON,
XV_HELP_DATA, "wave:view.save_as_new_defaults",
PANEL_LABEL_STRING, "Save as new defaults",
PANEL_NOTIFY_PROC, save_defaults,
0);
xv_set(mode_panel, PANEL_DEFAULT_ITEM, redraw_item, NULL);
window_fit(mode_panel);
window_fit(mode_frame);
mode_popup_active = 0;
}
/* Make the display mode popup window appear. */
void show_mode()
{
if (mode_popup_active < 0) create_mode_popup();
xv_set(mode_frame, WIN_SHOW, TRUE, 0);
mode_popup_active = 1;
}
void set_modes()
{
int i, otsai = tsa_index, ovsai = vsa_index;
double osh = canvas_height_mv, osw = canvas_width_sec;
static double vsa[] = { 1.0, 2.5, 5.0, 10.0, 20.0, 40.0, 100.0 };
/* If the panel has never been instantiated, there is nothing to do. */
if (mode_popup_active < 0) return;
/* Read the current panel settings, beginning with the grid option. */
switch (grid_mode = (int)xv_get(grid_item, PANEL_VALUE)) {
case 0: ghflag = gvflag = visible = 0; break;
case 1: ghflag = 0; gvflag = visible = 1; break;
case 2: ghflag = visible = 1; gvflag = 0; break;
case 3: ghflag = gvflag = visible = 1; break;
case 4: ghflag = gvflag = visible = 2; break;
case 5: ghflag = visible = 1; gvflag = 3; break;
case 6: ghflag = visible = 2; gvflag = 3; break;
}
/* Next, check the annotation display options. The bit mask assignments
below are determined by the order of the PANEL_CHOICE_STRINGS for
opt_item in create_mode_popup(), above. */
i = (int)xv_get(opt_item, PANEL_VALUE);
show_subtype = i & 1;
show_chan = (i >> 1) & 1;
show_num = (i >> 2) & 1;
show_aux = (i >> 3) & 1;
show_marker = (i >> 4) & 1;
show_signame = (i >> 5) & 1;
show_baseline= (i >> 6) & 1;
show_level = (i >> 7) & 1;
/* Check the signal display options next. */
i = sig_mode;
sig_mode = (int)xv_get(sig_item, PANEL_VALUE);
if (i != sig_mode || sig_mode == 2)
set_baselines();
/* Check the annotation display mode next. */
ann_mode = (int)xv_get(ann_item, PANEL_VALUE);
overlap = (int)xv_get(ov_item, PANEL_VALUE);
/* Check the time display mode next. */
i = time_mode;
time_mode = (int)xv_get(tim_item, PANEL_VALUE);
/* The `nsig > 0' test is a bit of a kludge -- we don't want to reset the
time_mode before the record has been opened, because we don't know if
absolute times are available until then. */
if (nsig > 0 && time_mode == 1)
(void)wtimstr(0L); /* check if absolute times are available --
if not, time_mode is reset to 0 */
if (i != time_mode) {
set_start_time(wtimstr(display_start_time));
set_end_time(wtimstr(display_start_time + nsamp));
reset_start();
reset_stop();
}
/* The purpose of the complex method of computing canvas_width_sec is to
obtain a "rational" value for it even if the frame has been resized.
First, we determine the number of 5 mm time-grid units in the window
(note that the resize procedure in xvwave.c guarantees that this will
be an integer; the odd calculation is intended to take care of
roundoff error in pixel-to-millimeter conversion). For each scale,
the multiplier of u is simply the number of seconds that would be
represented by 5 mm. Since u is usually a multiple of 5 (except on
small displays, or if the frame has been resized to a small size),
the calculated widths in seconds are usually integers, at worst
expressible as an integral number of tenths of seconds. */
if ((i = xv_get(ts_item, PANEL_VALUE)) >= 0) {
int u = ((int)(canvas_width/dmmx(1) + 1)/5); /* number of 5 mm
time-grid units */
switch (tsa_index = i) {
case 0: /* 0.25 mm/hour */
mmpersec = (0.25/3600.);
canvas_width_sec = 72000 * u; break;
case 1: /* 1 mm/hour */
mmpersec = (1./3600.);
canvas_width_sec = 18000 * u; break;
case 2: /* 5 mm/hour */
mmpersec = (5./3600.);
canvas_width_sec = 3600 * u; break;
case 3: /* 0.25 mm/min */
mmpersec = (0.25/60.);
canvas_width_sec = 1200 * u; break;
case 4: /* 1 mm/min */
mmpersec = (1./60.);
canvas_width_sec = 300 * u; break;
case 5: /* 5 mm/min */
mmpersec = (5./60.);
canvas_width_sec = 60 * u; break;
case 6: /* 25 mm/min */
mmpersec = (25./60.);
canvas_width_sec = 12 * u; break;
case 7: /* 50 mm/min */
mmpersec = (50./60.);
canvas_width_sec = 6 * u; break;
case 8: /* 125 mm/min */
mmpersec = (125./60.);
canvas_width_sec = (12 * u) / 5; break;
case 9: /* 250 mm/min */
mmpersec = (250./60.);
canvas_width_sec = (6 * u) / 5; break;
case 10: /* 500 mm/min */
mmpersec = (500./60.);
canvas_width_sec = (3 * u) / 5; break;
case 11: /* 12.5 mm/sec */
mmpersec = 12.5;
canvas_width_sec = (2 * u) / 5; break;
case 12: /* 25 mm/sec */
mmpersec = 25.;
canvas_width_sec = u / 5; break;
case 13: /* 50 mm/sec */
mmpersec = 50.;
canvas_width_sec = u / 10; break;
case 14: /* 125 mm/sec */
mmpersec = 125.;
canvas_width_sec = u / 25; break;
case 15: /* 250 mm/sec */
mmpersec = 250.;
canvas_width_sec = u / 50.0; break;
case 16: /* 500 mm/sec */
mmpersec = 500.;
canvas_width_sec = u / 100.0; break;
case 17: /* 1000 mm/sec */
mmpersec = 1000.;
canvas_width_sec = u / 200.0; break;
case 18: /* 2000 mm/sec */
mmpersec = 2000.;
canvas_width_sec = u / 400.0; break;
case 19: /* 5000 mm/sec */
mmpersec = 5000.;
canvas_width_sec = u / 1000.0; break;
case 20: /* 10 mm/ms */
mmpersec = 10000.;
canvas_width_sec = u / 2000.0; break;
case 21: /* 20 mm/ms */
mmpersec = 20000.;
canvas_width_sec = u / 4000.0; break;
case 22: /* 50 mm/ms */
mmpersec = 50000.;
canvas_width_sec = u / 10000.0; break;
case 23: /* 100 mm/ms */
mmpersec = 100000.;
canvas_width_sec = u / 20000.0; break;
case 24: /* 200 mm/ms */
mmpersec = 200000.;
canvas_width_sec = u / 40000.0; break;
case 25: /* 500 mm/ms */
mmpersec = 500000.;
canvas_width_sec = u / 100000.0; break;
}
}
/* Computation of canvas_height_mv could be as complex as above, but
it doesn't seem so important to obtain a "rational" value here. */
if ((i = xv_get(vs_item, PANEL_VALUE)) >= 0 && i < 7) {
mmpermv = vsa[i];
canvas_height_mv = canvas_height/dmmy(vsa[vsa_index = i]);
}
if (osh != canvas_height_mv || osw != canvas_width_sec ||
otsai != tsa_index || ovsai != vsa_index) {
vscale[0] = 0.0;
calibrate();
}
}
/* Effect any mode changes that were selected and make the popup disappear. */
void dismiss_mode()
{
/* If the panel is currently visible, make it go away. */
if (mode_popup_active > 0 &&
(int)xv_get(mode_frame, FRAME_CMD_PUSHPIN_IN) == FALSE) {
xv_set(mode_frame, WIN_SHOW, FALSE, 0);
mode_popup_active = 0;
}
set_modes();
}
/* Time-to-string conversion functions. These functions use those in the
WFDB library, but ensure that (1) elapsed times are displayed if time_mode
is 0, and (2) absolute times (if available) are displayed without brackets
if time_mode is non-zero. */
WFDB_Time wstrtim(s)
char *s;
{
WFDB_Time t;
while (*s == ' ' || *s == '\t') s++;
if (time_mode == 1 && *s != '[' && *s != 's' && *s != 'c' && *s != 'e') {
char buf[80];
sprintf(buf, "[%s]", s);
s = buf;
}
t = strtim(s);
if (*s == '[') { /* absolute time specified - strtim returns a negated
sample number if s is valid */
if (t > 0L) t = 0L; /* invalid s (before sample 0) -- reset t */
else t = -t; /* valid s -- convert t to a positive sample number */
}
return (t);
}
char *wtimstr(t)
WFDB_Time t;
{
switch (time_mode) {
case 0:
default:
if (t == 0L) return ("0:00");
else if (t < 0L) t = -t;
return (timstr(t));
case 1:
{
char *p, *q;
if (t > 0L) t = -t;
p = timstr(t);
if (*p == '[') {
p++;
q = p + strlen(p) - 1;
if (*q == ']') *q = '\0';
}
else {
time_mode = 0;
if (tim_item) xv_set(tim_item, PANEL_VALUE, time_mode, NULL);
}
return (p);
}
case 2:
{
static char buf[100];
if (t < 0L) t = -t;
sprintf(buf, "s%"WFDB_Pd_TIME, t);
return (buf);
}
}
}
char *wmstimstr(t)
WFDB_Time t;
{
switch (time_mode) {
case 0:
default:
if (t == 0L) return ("0:00");
else if (t < 0L) t = -t;
return (mstimstr(t));
case 1:
{
char *p, *q;
if (t > 0L) t = -t;
p = mstimstr(t);
if (*p == '[') {
p++;
q = p + strlen(p) - 1;
if (*q == ']') *q = '\0';
}
else {
time_mode = 0;
if (tim_item) xv_set(tim_item, PANEL_VALUE, time_mode, NULL);
}
return (p);
}
case 2:
{
static char buf[100];
if (t < 0L) t = -t;
sprintf(buf, "s%"WFDB_Pd_TIME, t);
return (buf);
}
}
}