PageRenderTime 48ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/ecg/third/wfdb-10.5.4/wave/scope.c

https://github.com/kastur/ECGCS
C | 883 lines | 742 code | 70 blank | 71 comment | 171 complexity | bd2a8e301cc69c902b51ded2be46ef6a MD5 | raw file
  1. /* file: scope.c G. Moody 31 July 1991
  2. Last revised: 10 June 2005
  3. Scope window functions for WAVE
  4. -------------------------------------------------------------------------------
  5. WAVE: Waveform analyzer, viewer, and editor
  6. Copyright (C) 1991-2005 George B. Moody
  7. This program is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free Software
  9. Foundation; either version 2 of the License, or (at your option) any later
  10. version.
  11. This program is distributed in the hope that it will be useful, but WITHOUT ANY
  12. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  13. PARTICULAR PURPOSE. See the GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License along with
  15. this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  16. Place - Suite 330, Boston, MA 02111-1307, USA.
  17. You may contact the author by e-mail (george@mit.edu) or postal mail
  18. (MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software,
  19. please visit PhysioNet (http://www.physionet.org/).
  20. _______________________________________________________________________________
  21. */
  22. #include "wave.h"
  23. #include "xvwave.h"
  24. #include <wfdb/ecgmap.h>
  25. #include <X11/Xos.h>
  26. #include <xview/canvas.h>
  27. #include <xview/cms.h>
  28. #include <xview/cursor.h>
  29. #include <xview/defaults.h>
  30. #include <xview/notice.h>
  31. #include <xview/notify.h>
  32. #define SQRTMAXSPEED (30)
  33. #define MAXSPEED (SQRTMAXSPEED*SQRTMAXSPEED)
  34. static int scope_use_overlays, use_color, grey;
  35. static void scan(), create_scope_panel(), set_dt();
  36. static void scope_proc(Panel_item item, Event *event);
  37. void save_scope_params(a, b, c)
  38. int a, b, c;
  39. {
  40. scope_use_overlays = a;
  41. use_color = b;
  42. grey = c;
  43. }
  44. static void scope_repaint(canvas, paint_window, repaint_area)
  45. Canvas canvas;
  46. Xv_Window paint_window;
  47. Rectlist *repaint_area;
  48. {
  49. ;
  50. }
  51. static unsigned int scope_height, scope_width;
  52. static XPoint *sbuf;
  53. static int v0n, v0f, v0v, xt, yt;
  54. static long scope_dt;
  55. static Display *scope_display;
  56. static XID scope_xid;
  57. static GC clear_plane[4], plot_sig;
  58. static void scope_resize(canvas, w, h)
  59. Canvas canvas;
  60. int w, h;
  61. {
  62. int i;
  63. xt = mmx(2);
  64. if (w > scope_width) {
  65. XPoint *sbt;
  66. if (sbuf == NULL &&
  67. (sbt = (XPoint *)malloc(w * sizeof(XPoint))) == NULL) {
  68. #ifdef NOTICE
  69. Xv_notice notice = xv_create((Frame)frame, NOTICE,
  70. XV_SHOW, TRUE,
  71. #else
  72. (void)notice_prompt((Frame)frame, (Event *)NULL,
  73. #endif
  74. NOTICE_MESSAGE_STRINGS,
  75. "Error in allocating memory for scope\n", 0,
  76. NOTICE_BUTTON_YES, "Continue", 0);
  77. #ifdef NOTICE
  78. xv_destroy_safe(notice);
  79. #endif
  80. return;
  81. }
  82. else if (sbuf != NULL &&
  83. (sbt = (XPoint *)realloc(sbuf, w * sizeof(XPoint))) == NULL) {
  84. #ifdef NOTICE
  85. Xv_notice notice = xv_create((Frame)frame, NOTICE,
  86. XV_SHOW, TRUE,
  87. #else
  88. (void)notice_prompt((Frame)frame, (Event *)NULL,
  89. #endif
  90. NOTICE_MESSAGE_STRINGS,
  91. "Error in allocating memory for scope\n", 0,
  92. NOTICE_BUTTON_YES, "Continue", 0);
  93. #ifdef NOTICE
  94. xv_destroy_safe(notice);
  95. #endif
  96. return;
  97. }
  98. sbuf = sbt;
  99. }
  100. if (w != scope_width-1) {
  101. if (scope_width == 0)
  102. scope_dt = strtim("0.5");
  103. scope_width = w-1;
  104. if (tscale <= 1.0) /* resolution limited by display */
  105. for (i = 0; i <= scope_width; i++)
  106. sbuf[i].x = i;
  107. else { /* resolution limited by input data */
  108. for (i = 0; i <= scope_width; i++)
  109. sbuf[i].x = i*tscale;
  110. }
  111. }
  112. if (h != scope_height) {
  113. scope_height = h;
  114. yt = scope_height - mmy(2);
  115. v0n = scope_height/3;
  116. v0f = scope_height/2;
  117. v0v = 2*scope_height/3;
  118. }
  119. if (scope_xid) {
  120. if (scope_use_overlays) {
  121. static XPoint tbuf[2];
  122. tbuf[0].y = 0; tbuf[1].y = scope_height-1;
  123. for (i = 0; i <scope_width; i++) {
  124. tbuf[0].x = tbuf[1].x = i;
  125. XDrawLines(scope_display, scope_xid, plot_sig, tbuf, 2,
  126. CoordModeOrigin);
  127. }
  128. }
  129. for (i = 0; i < 4; i++)
  130. XFillRectangle(scope_display, scope_xid, clear_plane[i],
  131. 0, 0, scope_width, scope_height);
  132. }
  133. }
  134. /* Handle events in the scope window. */
  135. void scope_window_event_proc(window, event, arg)
  136. Xv_Window window;
  137. Event *event;
  138. Notify_arg arg;
  139. {
  140. int e, x, y;
  141. static int handling_event;
  142. e = (int)event_id(event);
  143. x = (int)event_x(event);
  144. y = (int)event_y(event);
  145. if (handling_event) return;
  146. handling_event = 1;
  147. if (event_action(event) == ACTION_HELP)
  148. xv_help_show(window, "wave:scope_canvas", event);
  149. else switch (e) {
  150. case KEY_RIGHT(10): /* left-arrow: simulate left mouse button */
  151. case MS_LEFT:
  152. if (event_is_down(event)) {
  153. if (event_ctrl_is_down(event))
  154. scope_proc(XV_NULL, (Event *) '['); /* scan backward */
  155. else
  156. scope_proc(XV_NULL, (Event *) '<'); /* single step back */
  157. }
  158. break;
  159. case KEY_RIGHT(8): /* up-arrow: simulate middle mouse button */
  160. case KEY_RIGHT(11): /* <5> on numeric keypad: simulate middle
  161. mouse button */
  162. case MS_MIDDLE:
  163. if (event_is_down(event)) {
  164. if (event_ctrl_is_down(event))
  165. set_dt(x);
  166. else
  167. scope_proc(XV_NULL, (Event *) '*'); /* interrupt scan */
  168. }
  169. break;
  170. case KEY_RIGHT(12): /* right-arrow: simulate right mouse button */
  171. case MS_RIGHT:
  172. if (event_is_down(event)) {
  173. if (event_ctrl_is_down(event))
  174. scope_proc(XV_NULL, (Event *) ']'); /* scan forward */
  175. else
  176. scope_proc(XV_NULL, (Event *) '>'); /* single step */
  177. }
  178. break;
  179. }
  180. handling_event = 0;
  181. }
  182. static Colormap colormap;
  183. static XColor color[16];
  184. static unsigned long pixel_table[16];
  185. static Canvas canvas;
  186. static Frame scope_frame;
  187. static Panel scope_panel;
  188. #ifndef USE_OLC_PLUS
  189. extern Server_image cursor_image;
  190. #endif
  191. void create_scope_popup(overlay_flag, use_color, grey)
  192. int overlay_flag, use_color, grey;
  193. {
  194. char *bgcname, *fgcname;
  195. int i, ncolors;
  196. static unsigned long mask[4];
  197. static XGCValues gcvalues;
  198. Icon icon;
  199. Xv_Cursor scope_c;
  200. Xv_singlecolor scope_c_bg, scope_c_fg;
  201. Xv_Window window;
  202. icon = xv_create(frame, ICON,
  203. ICON_IMAGE, icon_image,
  204. ICON_LABEL, "Scope",
  205. NULL);
  206. scope_frame = xv_create(frame, FRAME,
  207. XV_LABEL, "Scope",
  208. XV_WIDTH, mmx(25)+4,
  209. XV_HEIGHT, mmy(150),
  210. FRAME_ICON, icon,
  211. NULL);
  212. create_scope_panel();
  213. window_fit_height(scope_panel);
  214. canvas = xv_create(scope_frame, CANVAS,
  215. CANVAS_REPAINT_PROC, scope_repaint,
  216. CANVAS_RESIZE_PROC, scope_resize,
  217. CANVAS_WIDTH, mmx(25),
  218. CANVAS_HEIGHT, mmy(100),
  219. CANVAS_MIN_PAINT_WIDTH, mmx(25),
  220. CANVAS_MIN_PAINT_HEIGHT, mmy(20),
  221. CANVAS_AUTO_CLEAR, TRUE,
  222. WIN_X, 0,
  223. WIN_BELOW, scope_panel,
  224. WIN_DYNAMIC_VISUAL, overlay_flag,
  225. 0);
  226. scope_resize(canvas, (int)xv_get(canvas, CANVAS_WIDTH),
  227. (int)xv_get(canvas, CANVAS_HEIGHT));
  228. window_fit(canvas);
  229. window_fit(scope_frame);
  230. scope_display = (Display *)xv_get(canvas, XV_DISPLAY);
  231. window = (Xv_Window)xv_get(canvas, CANVAS_NTH_PAINT_WINDOW, 0);
  232. scope_xid = (Window)xv_get(window, XV_XID);
  233. mask[0] = mask[1] = mask[2] = mask[3] = ~0;
  234. /* Get the appropriate foreground and background colors. */
  235. if (use_color && !grey) {
  236. bgcname = defaults_get_string("wave.scope.color.background",
  237. "Wave.Scope.Color.background",
  238. "white");
  239. fgcname = defaults_get_string("wave.scope.color.foreground",
  240. "Wave.Scope.Color.Foreground",
  241. "blue");
  242. }
  243. else if (grey) {
  244. bgcname = defaults_get_string("wave.scope.grey.background",
  245. "Wave.Scope.Grey.background",
  246. "white");
  247. fgcname = defaults_get_string("wave.scope.grey.foreground",
  248. "Wave.Scope.Grey.Foreground",
  249. "black");
  250. }
  251. else {
  252. bgcname = defaults_get_string("wave.scope.mono.background",
  253. "Wave.Scope.Mono.background",
  254. "white");
  255. if (strcmp(bgcname, "black") && strcmp(bgcname, "Black"))
  256. fgcname = "black";
  257. else
  258. fgcname = "white";
  259. }
  260. /* Allocate a colormap for the scope display area. */
  261. colormap = DefaultColormap(scope_display, DefaultScreen(scope_display));
  262. /* Determine how to "fade" the display (i.e., how to make the oldest data
  263. disappear into the background). There are two techniques:
  264. A. If 16 read/write color cells in 4 plane groups are available, we
  265. number them 0 to 15. Color 0 is pure background, and color 15 is
  266. pure foreground. The remainder are blends of foreground and
  267. background, and the amount of foreground in the mix is determined
  268. by the number of non-zero bits in the color number. Before writing
  269. new data, one of the four planes is cleared (the choice of which
  270. plane is made by circulating through the 4 in a fixed order). New
  271. data are always written in color 15. Thus new data are 100%
  272. foreground, data one cycle old are 75%, data two cycles old are 50%,
  273. data three cycles old are 25%, and all older data are erased (i.e.,
  274. set to the background color).
  275. B. Otherwise, before writing new data, we set one of every four pixels
  276. in the window to the background color using one of four bitmasks
  277. (each of which includes one-fourth of the pixels, with no overlap
  278. between the bitmasks). Thus 100% of all the pixels in new data are
  279. in the foreground color, data one cycle old are 75% visible (on
  280. average), data two cycles old are 50% visible, data three cycles old
  281. are 25% visible, and all older data are erased.
  282. It might be even better to combine these techniques if both can be
  283. used on a given display, to give 16 levels of fading; this would also
  284. require 16 GCs, however, which might pose a problem for the server.
  285. */
  286. if (overlay_flag) {
  287. /* Try to get read/write color cells if possible. */
  288. if (!XAllocColorCells(scope_display, colormap, 0, mask, 4,
  289. pixel_table, 1))
  290. overlay_flag = 0; /* impossible -- use plan B */
  291. else { /* execute plan A */
  292. /* Color 0: background */
  293. XParseColor(scope_display, colormap, bgcname, &color[0]);
  294. /* Color 15: foreground */
  295. XParseColor(scope_display, colormap, fgcname, &color[15]);
  296. /* Color numbers with one non-zero bit: 1, 2, 4, 8 */
  297. color[1].red = color[2].red = color[4].red = color[8].red =
  298. (color[15].red + 3*color[0].red ) / 4;
  299. color[1].green = color[2].green = color[4].green = color[8].green =
  300. (color[15].green + 3*color[0].green) / 4;
  301. color[1].blue = color[2].blue = color[4].blue = color[8].blue =
  302. (color[15].blue + 3*color[0].blue ) / 4;
  303. /* Color numbers with two non-zero bits: 3, 5, 6, 9, 10, 12 */
  304. color[3].red = color[5].red = color[6].red = color[9].red =
  305. color[10].red = color[12].red =
  306. (color[15].red + color[0].red ) / 2;
  307. color[3].green = color[5].green = color[6].green = color[9].green =
  308. color[10].green = color[12].green =
  309. (color[15].green + color[0].green) / 2;
  310. color[3].blue = color[5].blue = color[6].blue = color[9].blue =
  311. color[10].blue = color[12].blue =
  312. (color[15].blue + color[0].blue ) / 2;
  313. /* Color numbers with three non-zero bits: 7, 11, 13, 14 */
  314. color[7].red = color[11].red = color[13].red =
  315. color[14].red = (3*color[15].red + color[0].red )/4;
  316. color[7].green = color[11].green = color[13].green =
  317. color[14].green = (3*color[15].green + color[0].green)/4;
  318. color[7].blue = color[11].blue = color[13].blue =
  319. color[14].blue = (3*color[15].blue + color[0].blue )/4;
  320. for (i = 0; i < 16; i++) {
  321. color[i].pixel = pixel_table[0];
  322. if (i & 1) color[i].pixel |= mask[0];
  323. if (i & 2) color[i].pixel |= mask[1];
  324. if (i & 4) color[i].pixel |= mask[2];
  325. if (i & 8) color[i].pixel |= mask[3];
  326. color[i].flags = DoRed | DoGreen | DoBlue;
  327. pixel_table[i] = color[i].pixel;
  328. }
  329. ncolors = 16;
  330. XStoreColors(scope_display, colormap, color, ncolors);
  331. /* Create plan A graphics contexts. */
  332. gcvalues.foreground = pixel_table[15];
  333. gcvalues.background = pixel_table[0];
  334. plot_sig = XCreateGC(scope_display, scope_xid,
  335. GCForeground | GCBackground,
  336. &gcvalues);
  337. gcvalues.foreground = gcvalues.background;
  338. for (i = 0; i < 4; i++) {
  339. gcvalues.plane_mask = mask[i];
  340. clear_plane[i] = XCreateGC(scope_display, scope_xid,
  341. GCBackground | GCForeground |
  342. GCPlaneMask,
  343. &gcvalues);
  344. }
  345. }
  346. }
  347. if (!overlay_flag) { /* execute plan B */
  348. int j;
  349. unsigned int stipple_height, stipple_width;
  350. GC set_stipple, clear_stipple;
  351. Pixmap stipple;
  352. XParseColor(scope_display, colormap, bgcname, &color[0]);
  353. XParseColor(scope_display, colormap, fgcname, &color[1]);
  354. (void)XAllocColor(scope_display, colormap, &color[0]);
  355. (void)XAllocColor(scope_display, colormap, &color[1]);
  356. pixel_table[0] = color[0].pixel;
  357. pixel_table[1] = color[1].pixel;
  358. ncolors = 2;
  359. /* Create plan B graphics contexts. */
  360. XQueryBestStipple(scope_display, scope_xid,
  361. scope_width, scope_height,
  362. &stipple_width, &stipple_height);
  363. stipple = XCreatePixmap(scope_display, scope_xid,
  364. stipple_width, stipple_height, 1);
  365. gcvalues.foreground = gcvalues.background =
  366. BlackPixel(scope_display, DefaultScreen(scope_display));
  367. clear_stipple = XCreateGC(scope_display, stipple,
  368. GCForeground, &gcvalues);
  369. gcvalues.foreground =
  370. WhitePixel(scope_display, DefaultScreen(scope_display));
  371. set_stipple = XCreateGC(scope_display, stipple,
  372. GCForeground | GCBackground, &gcvalues);
  373. for (j = 0; j < stipple_height-1; j += 2)
  374. for (i = 0; i < stipple_width-1; i += 2) {
  375. XDrawPoint(scope_display, stipple, set_stipple, i, j);
  376. XDrawPoint(scope_display, stipple, clear_stipple, i+1, j);
  377. XDrawPoint(scope_display, stipple, clear_stipple, i+1, j+1);
  378. XDrawPoint(scope_display, stipple, clear_stipple, i, j+1);
  379. }
  380. gcvalues.stipple = stipple;
  381. gcvalues.fill_style = FillStippled;
  382. for (i = 0; i < 4; i++) {
  383. gcvalues.ts_x_origin = (i & 1);
  384. gcvalues.ts_y_origin = (i == 1 || i == 2);
  385. clear_plane[i] = XCreateGC(scope_display, scope_xid,
  386. GCForeground | GCStipple | GCFillStyle |
  387. GCTileStipXOrigin | GCTileStipYOrigin,
  388. &gcvalues);
  389. }
  390. gcvalues.foreground = pixel_table[1];
  391. gcvalues.background = pixel_table[0];
  392. plot_sig = XCreateGC(scope_display, scope_xid,
  393. GCForeground | GCBackground,
  394. &gcvalues);
  395. gcvalues.foreground = gcvalues.background;
  396. }
  397. /* Create and install a cursor for the scope window. Record the cursor
  398. colors in terms of the XView color model (8 bits for each of red, green,
  399. blue, rather than 16 as in the X model). */
  400. scope_c_fg.red = color[ncolors - 1].red >> 8;
  401. scope_c_fg.green = color[ncolors - 1].green >> 8;
  402. scope_c_fg.blue = color[ncolors - 1].blue >> 8;
  403. scope_c_bg.red = color[0].red >> 8;
  404. scope_c_bg.green = color[0].green >> 8;
  405. scope_c_bg.blue = color[0].blue >> 8;
  406. scope_c = (Xv_Cursor)xv_create(scope_frame, CURSOR,
  407. #ifndef USE_OLC_PLUS
  408. /* See xvwave.c for details on the alternative cursors. */
  409. CURSOR_IMAGE, cursor_image,
  410. CURSOR_XHOT, 7,
  411. CURSOR_YHOT, 7,
  412. #else
  413. CURSOR_SRC_CHAR, OLC_PLUS,
  414. #endif
  415. CURSOR_FOREGROUND_COLOR, &scope_c_fg,
  416. CURSOR_BACKGROUND_COLOR, &scope_c_bg,
  417. NULL);
  418. xv_set(window, WIN_CURSOR, scope_c, NULL);
  419. /* Register the event handler for the scope window. */
  420. xv_set(window, WIN_EVENT_PROC, scope_window_event_proc,
  421. WIN_CONSUME_EVENTS, WIN_NO_EVENTS, LOC_WINENTER, ACTION_HELP,
  422. WIN_ASCII_EVENTS, WIN_MOUSE_BUTTONS, LOC_DRAG, NULL,
  423. NULL);
  424. xv_set(window, WIN_IGNORE_EVENTS, WIN_UP_ASCII_EVENTS, NULL, NULL);
  425. for (i = 0; i < 4; i++)
  426. XFillRectangle(scope_display, scope_xid, clear_plane[i],
  427. 0, 0, scope_width, scope_height);
  428. scope_resize(canvas, (int)xv_get(canvas, CANVAS_WIDTH),
  429. (int)xv_get(canvas, CANVAS_HEIGHT));
  430. }
  431. static int show_this_frame()
  432. {
  433. static char plane = 3, first_frame = 1;
  434. int i, i0, tt, tt0 = 0, v0;
  435. long t;
  436. if (first_frame && scope_use_overlays) {
  437. first_frame = 0;
  438. scope_resize(canvas, (int)xv_get(canvas, CANVAS_WIDTH),
  439. (int)xv_get(canvas, CANVAS_HEIGHT));
  440. }
  441. if (scope_annp == NULL) return(0);
  442. if ((t = scope_annp->this.time - scope_dt) < 0L) {
  443. tt0 = (int)(-t);
  444. t = 0L;
  445. }
  446. if (isigsettime(t) < 0 || getvec(scope_v) < 0) return (0);
  447. switch (map2(scope_annp->this.anntyp)) {
  448. case NORMAL:
  449. case LEARN:
  450. v0 = scope_v[signal_choice] * vscale[signal_choice] - v0n;
  451. break;
  452. case FUSION:
  453. v0 = scope_v[signal_choice] * vscale[signal_choice] - v0f;
  454. break;
  455. case PVC:
  456. v0 = scope_v[signal_choice] * vscale[signal_choice] - v0v;
  457. break;
  458. }
  459. if (tscale >= 1.0) { /* resolution limited by input data */
  460. for (i = i0 = tt0; i < scope_width; i++) {
  461. if (getvec(scope_v) <= 0) break;
  462. sbuf[i].y = scope_v[signal_choice] * vscale[signal_choice] - v0;
  463. }
  464. i--;
  465. }
  466. else { /* resolution limited by display */
  467. int vmax, vmin, vv, x;
  468. (void)getvec(scope_v);
  469. vmax = vmin = scope_v[signal_choice];
  470. i = i0 = tt0*tscale;
  471. if (i < scope_width)
  472. sbuf[i].y = scope_v[signal_choice] * vscale[signal_choice] - v0;
  473. for (tt = tt0 + 1; i < scope_width && getvec(scope_v) > 0; tt++) {
  474. if (scope_v[signal_choice] > vmax) vmax = scope_v[signal_choice];
  475. else if (scope_v[signal_choice]<vmin) vmin=scope_v[signal_choice];
  476. if ((x = tt*tscale) > i) {
  477. i = x;
  478. if (vmax - vv > vv - vmin)
  479. vv = vmin = vmax;
  480. else
  481. vv = vmax = vmin;
  482. sbuf[i].y = vv * vscale[signal_choice] - v0;
  483. }
  484. }
  485. }
  486. XFillRectangle(scope_display, scope_xid, clear_plane[plane],
  487. 0, 0, scope_width, scope_height);
  488. if (++plane > 3) {
  489. char *tp;
  490. plane = 0;
  491. tp = wtimstr(t);
  492. XDrawString(scope_display,scope_xid,plot_sig,xt,yt,tp,strlen(tp));
  493. }
  494. if (i > i0)
  495. XDrawLines(scope_display, scope_xid, plot_sig,
  496. sbuf + i0, i - i0, CoordModeOrigin);
  497. return (1);
  498. }
  499. static void refresh_time()
  500. {
  501. char *tp;
  502. int i, ytt;
  503. long t;
  504. ytt = scope_height - mmy(5);
  505. for (i = 0; i < 4; i++)
  506. XFillRectangle(scope_display, scope_xid, clear_plane[i],
  507. 0, ytt, scope_width, scope_height);
  508. if (scope_annp) {
  509. t = scope_annp->this.time - scope_width/2;
  510. tp = wtimstr(t);
  511. XDrawString(scope_display,scope_xid,plot_sig,xt,yt,tp,strlen(tp));
  512. }
  513. }
  514. static int show_next_frame()
  515. {
  516. if (scope_annp == NULL) {
  517. scan(0);
  518. return (0);
  519. }
  520. while (scope_annp->this.time < begin_analysis_time) {
  521. if (scope_annp->next == NULL)
  522. break;
  523. scope_annp = scope_annp->next;
  524. }
  525. do {
  526. if (((scope_annp = scope_annp->next) == NULL) ||
  527. (scope_annp->this.anntyp == INDEX_MARK) ||
  528. (end_analysis_time > 0L &&
  529. scope_annp->this.time > end_analysis_time)) {
  530. if (scope_annp == NULL) scope_annp = ap_end;
  531. else if (scope_annp->this.anntyp == INDEX_MARK &&
  532. scope_annp->next != NULL)
  533. scope_annp = scope_annp->next;
  534. else scope_annp = scope_annp->previous;
  535. scan(0);
  536. return (0);
  537. }
  538. } while (!isqrs(scope_annp->this.anntyp) ||
  539. (ann_mode == 1 && scope_annp->this.chan != signal_choice));
  540. return (show_this_frame());
  541. }
  542. static int show_prev_frame()
  543. {
  544. if (scope_annp == NULL) {
  545. scan(0);
  546. return (0);
  547. }
  548. while (end_analysis_time > 0L &&
  549. scope_annp->this.time > end_analysis_time) {
  550. if (scope_annp->previous == NULL)
  551. break;
  552. scope_annp = scope_annp->previous;
  553. }
  554. do {
  555. if (((scope_annp = scope_annp->previous) == NULL) ||
  556. (scope_annp->this.anntyp == INDEX_MARK) ||
  557. (scope_annp->this.time < begin_analysis_time)) {
  558. if (scope_annp == NULL) scope_annp = ap_start;
  559. else if (scope_annp->this.anntyp == INDEX_MARK &&
  560. scope_annp->previous != NULL)
  561. scope_annp = scope_annp->previous;
  562. else scope_annp = scope_annp->next;
  563. scan(0);
  564. return (0);
  565. }
  566. } while (!isqrs(scope_annp->this.anntyp) ||
  567. (ann_mode == 1 && scope_annp->this.chan != signal_choice));
  568. return (show_this_frame());
  569. }
  570. static int speed = MAXSPEED;
  571. static Notify_value show_next_n_frames()
  572. {
  573. int i;
  574. for (i = speed/10 + 1; i > 0 ; i--)
  575. if (show_next_frame() == 0) break;
  576. refresh_time();
  577. return (NOTIFY_DONE);
  578. }
  579. static Notify_value show_prev_n_frames()
  580. {
  581. int i;
  582. for (i = speed/10 + 1; i > 0 ; i--)
  583. if (show_prev_frame() == 0) break;
  584. refresh_time();
  585. return (NOTIFY_DONE);
  586. }
  587. static struct itimerval sc_timer;
  588. static void scan(speed)
  589. int speed;
  590. {
  591. if (speed > 0) {
  592. if (speed > MAXSPEED) speed = MAXSPEED;
  593. sc_timer.it_value.tv_usec = sc_timer.it_interval.tv_usec =
  594. 1000000L/speed;
  595. notify_set_itimer_func(scope_frame, show_next_n_frames, ITIMER_REAL,
  596. &sc_timer, NULL);
  597. scan_active = 1;
  598. }
  599. else if (speed == 0) {
  600. notify_set_itimer_func(scope_frame, NOTIFY_FUNC_NULL, ITIMER_REAL,
  601. NULL, NULL);
  602. scan_active = 0;
  603. }
  604. else {
  605. if (speed < -MAXSPEED) speed = -MAXSPEED;
  606. sc_timer.it_value.tv_usec = sc_timer.it_interval.tv_usec =
  607. -1000000L/speed;
  608. notify_set_itimer_func(scope_frame, show_prev_n_frames, ITIMER_REAL,
  609. &sc_timer, NULL);
  610. scan_active = -1;
  611. }
  612. }
  613. static void scope_proc(Panel_item item, Event *event)
  614. {
  615. int client_data;
  616. long t0;
  617. if (item) client_data = (int)xv_get(item, PANEL_CLIENT_DATA);
  618. else client_data = (int)event;
  619. if (ap_start == NULL) {
  620. #ifdef NOTICE
  621. Xv_notice notice = xv_create((Frame)frame, NOTICE,
  622. XV_SHOW, TRUE,
  623. #else
  624. (void)notice_prompt((Frame)frame, (Event *)NULL,
  625. #endif
  626. NOTICE_MESSAGE_STRINGS,
  627. "Scope functions cannot be used while the",
  628. "annotation list is empty.", 0,
  629. NOTICE_BUTTON_YES, "Continue", 0);
  630. #ifdef NOTICE
  631. xv_destroy_safe(notice);
  632. #endif
  633. return;
  634. }
  635. if (attached &&
  636. (begin_analysis_time <= attached->this.time &&
  637. (attached->this.time <= end_analysis_time || end_analysis_time<0L))) {
  638. scope_annp = attached;
  639. attached = NULL;
  640. }
  641. else if (scope_annp == NULL) {
  642. (void)locate_annotation(display_start_time, -128);
  643. scope_annp = annp;
  644. }
  645. switch (client_data) {
  646. case '[': /* scan backwards */
  647. box(0, 0, 0);
  648. scan(-speed);
  649. break;
  650. case '<': /* single-step backwards */
  651. show_prev_frame();
  652. refresh_time();
  653. if (display_start_time < scope_annp->this.time &&
  654. scope_annp->this.time < display_start_time + nsamp)
  655. box((int)((scope_annp->this.time - display_start_time)*tscale),
  656. (ann_mode==1 && (unsigned)scope_annp->this.chan < nsig) ?
  657. (int)(base[(unsigned)scope_annp->this.chan] + mmy(2)) : abase,
  658. 1);
  659. else
  660. box(0, 0, 0);
  661. break;
  662. case '*': /* interrupt scan */
  663. scan(0);
  664. refresh_time();
  665. if ((t0 = scope_annp->this.time - nsamp/2) < 0L) t0 = 0L;
  666. find_display_list(t0);
  667. set_start_time(wtimstr(t0));
  668. set_end_time(wtimstr(t0 + nsamp));
  669. if (item)
  670. disp_proc(item, (Event *)NULL);
  671. else
  672. disp_proc(XV_NULL, event);
  673. box((int)((scope_annp->this.time - display_start_time)*tscale),
  674. (ann_mode==1 && (unsigned)scope_annp->this.chan < nsig) ?
  675. (int)(base[(unsigned)scope_annp->this.chan] + mmy(2)) : abase,
  676. 1);
  677. break;
  678. case '>': /* single-step forwards */
  679. show_next_frame();
  680. refresh_time();
  681. if (display_start_time < scope_annp->this.time &&
  682. scope_annp->this.time < display_start_time + nsamp)
  683. box((int)((scope_annp->this.time - display_start_time)*tscale),
  684. (ann_mode==1 && (unsigned)scope_annp->this.chan < nsig) ?
  685. (int)(base[(unsigned)scope_annp->this.chan] + mmy(2)) : abase,
  686. 1);
  687. else
  688. box(0, 0, 0);
  689. break;
  690. case ']': /* scan forwards */
  691. default:
  692. box(0, 0, 0);
  693. scan(speed);
  694. break;
  695. }
  696. }
  697. static void adjust_speed(item, value)
  698. Panel_item item;
  699. int value;
  700. {
  701. speed = value*value;
  702. if (scan_active) scan(scan_active*speed);
  703. }
  704. static char *lmstimstr(t)
  705. long t;
  706. {
  707. char *p, *p0;
  708. if (t == 0L)
  709. return ("0");
  710. else if (t > 0L)
  711. p = mstimstr(t);
  712. else
  713. p = p0 = mstimstr(-t);
  714. while (*p == ' ' || *p == '0' || *p == ':')
  715. p++;
  716. if (*p == '.') p--;
  717. if (t < 0L && p > p0)
  718. *(--p) = '-';
  719. return (p);
  720. }
  721. Panel_item dt_item;
  722. static void adjust_dt(item, value)
  723. Panel_item item;
  724. int value;
  725. {
  726. char *dt_string = (char *) xv_get(item, PANEL_VALUE);
  727. while (*dt_string == ' ' || *dt_string == '\t')
  728. dt_string++;
  729. if (*dt_string != '-')
  730. scope_dt = strtim(dt_string);
  731. else
  732. scope_dt = -strtim(dt_string+1);
  733. xv_set(item, PANEL_VALUE, lmstimstr(scope_dt));
  734. }
  735. static void set_dt(x)
  736. int x;
  737. {
  738. scope_dt = x;
  739. scope_dt /= tscale;
  740. xv_set(dt_item, PANEL_VALUE, lmstimstr(scope_dt));
  741. }
  742. static void create_scope_panel()
  743. {
  744. scope_panel = xv_create(scope_frame, PANEL,
  745. XV_X, 0,
  746. XV_HELP_DATA, "wave:scope_panel",
  747. 0);
  748. xv_create(scope_panel, PANEL_SLIDER,
  749. XV_HELP_DATA, "wave:scope_panel.speed",
  750. PANEL_LABEL_STRING, "Speed",
  751. PANEL_DIRECTION, PANEL_VERTICAL,
  752. PANEL_VALUE, SQRTMAXSPEED,
  753. PANEL_MAX_VALUE, SQRTMAXSPEED,
  754. PANEL_SHOW_RANGE, FALSE,
  755. PANEL_SHOW_VALUE, FALSE,
  756. PANEL_NOTIFY_PROC, adjust_speed,
  757. NULL);
  758. dt_item = xv_create(scope_panel, PANEL_TEXT,
  759. XV_HELP_DATA, "wave:scope_panel.dt",
  760. PANEL_LABEL_STRING, "dt: ",
  761. PANEL_VALUE_DISPLAY_LENGTH, 6,
  762. PANEL_VALUE, "0.500",
  763. PANEL_NOTIFY_PROC, adjust_dt,
  764. NULL);
  765. xv_create(scope_panel, PANEL_BUTTON,
  766. XV_HELP_DATA, "wave:scope_panel.<<",
  767. PANEL_LABEL_STRING, "<<",
  768. PANEL_NOTIFY_PROC, scope_proc,
  769. PANEL_CLIENT_DATA, (caddr_t) '[',
  770. NULL);
  771. xv_create(scope_panel, PANEL_BUTTON,
  772. XV_HELP_DATA, "wave:scope_panel.<",
  773. PANEL_LABEL_STRING, "<",
  774. PANEL_NOTIFY_PROC, scope_proc,
  775. PANEL_CLIENT_DATA, (caddr_t) '<',
  776. NULL);
  777. xv_create(scope_panel, PANEL_BUTTON,
  778. XV_HELP_DATA, "wave:scope_panel.pause",
  779. PANEL_LABEL_STRING, " Pause ",
  780. PANEL_NOTIFY_PROC, scope_proc,
  781. PANEL_CLIENT_DATA, (caddr_t) '*',
  782. NULL);
  783. xv_create(scope_panel, PANEL_BUTTON,
  784. XV_HELP_DATA, "wave:scope_panel.>",
  785. PANEL_LABEL_STRING, ">",
  786. PANEL_NOTIFY_PROC, scope_proc,
  787. PANEL_CLIENT_DATA, (caddr_t) '>',
  788. NULL);
  789. xv_create(scope_panel, PANEL_BUTTON,
  790. XV_HELP_DATA, "wave:scope_panel.>>",
  791. PANEL_LABEL_STRING, ">>",
  792. PANEL_NOTIFY_PROC, scope_proc,
  793. PANEL_CLIENT_DATA, (caddr_t) ']',
  794. NULL);
  795. }
  796. static int scope_popup_active = -1;
  797. void show_scope_window()
  798. {
  799. if (scope_popup_active < 0)
  800. create_scope_popup(scope_use_overlays, use_color, grey);
  801. wmgr_top(scope_frame);
  802. xv_set(scope_frame, WIN_MAP, TRUE, 0);
  803. scope_popup_active = 1;
  804. }