PageRenderTime 64ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/spec/xmtv/selectpt.c

https://github.com/pkgw/atnf-miriad
C | 467 lines | 332 code | 49 blank | 86 comment | 65 complexity | c0ab87b01e60bfc772194b39d658b5c8 MD5 | raw file
  1. /*
  2. * <rubberband.c>
  3. */
  4. #include "xmtv.h"
  5. /*
  6. * If the user moves the mouse out of the window, the line is erased
  7. * and the routine resets so that the initial point must be chosen
  8. * again. This is the method a user would use if it were decided
  9. * that the initial point was incorrect.
  10. */
  11. /*
  12. * Input format for SLCT:
  13. *
  14. * OPCODE SLCT
  15. *
  16. * PARMS[0] Channel -- Ignored for now.
  17. * (X,Y positions are relative to this memory channel.)
  18. * PARMS[1] Select point type:
  19. * 0 - Point and click to choose 1 point.
  20. * Rubber band types:
  21. * 1 - line from point 1 to point 2.
  22. * 2 - rectangle with center at point 1.
  23. * 3 - rectangle with corner at point 1.
  24. * 4 - 'V' Draws a line from start point to mouse and from
  25. * mouse to end point. BUF holds start and end points.
  26. * Returns start point and middle point.
  27. * PARMS[2] Click mode.
  28. * PARMS[3] Unused.
  29. *
  30. * DATA_LENGTH 0 or 8 (characters).
  31. *
  32. * DATA If type is 'VBAND', 4 short integers are read to supply
  33. * start and end points.
  34. */
  35. /*
  36. * Input format for SLCT:
  37. *
  38. * STATUS <0 if routine could not enable rubber band drawing;
  39. * 0 for a normal function exit.
  40. *
  41. * RETURN_DATA_LENGTH = 5 (short ints).
  42. *
  43. * DATA 5 short integers are returned:
  44. * x0 -- the x position of the first point selected;
  45. * y0 -- the y position of the first point selected;
  46. * x1 -- the x position of the final point selected;
  47. * y1 -- the y position of the final point selected;
  48. * ch -- the character typed or (A,D,X for Mouse 1,2,3).
  49. * For single point select mode, x1 = x0 and y1 = y0.
  50. */
  51. /* Internal Declarations. */
  52. #define SelectTypeSingle 0 /* Choose a single point. */
  53. #define SelectTypeRband 1 /* Simple rubber band line. */
  54. #define SelectTypeCrect 2 /* Rectangle centered on initial point. */
  55. #define SelectTypeRect 3 /* Rectangle drawn from initial point. */
  56. #define SelectTypeVband 4 /* 'V' form of rubber band. */
  57. #define NumberofTypes 5 /* Maximum number of types. */
  58. #define SelectPushDrag 0 /* Push-Drag-Release mode. */
  59. #define SelectPushPush 1 /* Push-Release-Move-Push mode. */
  60. #define SelectPushPush2 2 /* Push-Drag-Release-Move-Push mode. */
  61. #define NumberofPushes 3 /* Maximum number of Push modes. */
  62. typedef struct rubberband {
  63. int channel; /* Unused at this point. */
  64. unsigned int buttonPushed; /* Number of Button pushed. */
  65. short int currentMode;
  66. short int currentType;
  67. short int pushMode;
  68. int firstx, firsty; /* First point selected. */
  69. int currentx, currenty; /* Current position of the pointer. */
  70. int vbandx, vbandy; /* Last point selected for "VBand". */
  71. GC SelectGC; /* GC used for drawing. */
  72. Cursor savedCursor; /* Cursor widget had when started. */
  73. Widget widget; /* Widget drawing will appear. */
  74. } RubberBand;
  75. #define NumberofCursors 2 /* Maximum number of cursors defined. */
  76. #define RESETCURSOR -1
  77. static String cursorNames[] = {
  78. "ll_angle",
  79. "ur_angle",
  80. };
  81. /* Routines. */
  82. /*
  83. * Draw rubber band line or rectangle from initial point to current
  84. * point. (and end point for 'Vband'). Uses XOR drawing so calling
  85. * this routine twice will result in the line being erased.
  86. */
  87. static void drawLine(r)
  88. RubberBand *r;
  89. {
  90. int x0, y0, x1, y1, xv, yv;
  91. unsigned int width, height;
  92. Display *dpy;
  93. GC xorgc;
  94. Window window;
  95. if (r == (RubberBand *)NULL) return;
  96. x0 = r->firstx; /* Starting point. */
  97. y0 = r->firsty;
  98. x1 = r->currentx; /* Ending point. */
  99. y1 = r->currenty;
  100. dpy = XtDisplay(r->widget);
  101. xorgc = r->SelectGC;
  102. window = XtWindow(r->widget);
  103. switch (r->currentType){
  104. case SelectTypeSingle: /* Single point. */
  105. XDrawPoint(dpy, window, xorgc, x1, y1);
  106. break;
  107. case SelectTypeRband: /* Rubber band line. */
  108. XDrawLine(dpy, window, xorgc, x0, y0, x1, y1);
  109. break;
  110. case SelectTypeCrect: /* Rectangle centered at x0/y0. */
  111. x0 -= (x1 - x0);
  112. y0 -= (y1 - y0); /* Fall through to TypeRect code to draw. */
  113. case SelectTypeRect: /* Rectangle from x0/y0. */
  114. width = max(x0, x1) - min(x0, x1);
  115. height = max(y0, y1) - min(y0, y1);
  116. x0 = min(x0, x1);
  117. y0 = min(y0, y1);
  118. XDrawRectangle(dpy, window, xorgc, x0, y0, width, height);
  119. break;
  120. case SelectTypeVband: /* 'V' - Start to variable midpoint to end. */
  121. xv = r->vbandx;
  122. yv = r->vbandy;
  123. XDrawLine(dpy, window, xorgc, x0, y0, x1, y1);
  124. XDrawLine(dpy, window, xorgc, x1, y1, xv, yv);
  125. break;
  126. default: /* Ignore unknown since there isn't much to be done. */
  127. break;
  128. }
  129. }
  130. /* This routine simply updates the current point position. */
  131. static void selectDone(r, cx, cy)
  132. RubberBand *r;
  133. int cx, cy;
  134. {
  135. drawLine(r); /* Erase old line before the current x/y are updated. */
  136. r->currentx = cx; /* Update the current mouse position. */
  137. r->currenty = cy;
  138. /*
  139. * If SelectType is single, force the first position to match the
  140. * current position.
  141. */
  142. if (r->currentType == SelectTypeSingle) {
  143. r->firstx = r->currentx;
  144. r->firsty = r->currenty;
  145. }
  146. }
  147. /* Set up the appropriate cursor. */
  148. static void changeCursor(r, newentry)
  149. RubberBand *r;
  150. short int newentry;
  151. {
  152. Arg args[10];
  153. Cardinal i;
  154. if ((newentry >= 0) && (newentry < NumberofCursors)) {
  155. i = 0;
  156. XtSetArg(args[i], XtNcursorName, (XtArgVal)cursorNames[newentry]); i++;
  157. XtSetValues(r->widget, args, i);
  158. } else if (newentry == RESETCURSOR) {
  159. i = 0;
  160. XtSetArg(args[i], XtNcursor, (XtArgVal)r->savedCursor); i++;
  161. XtSetValues(r->widget, args, i);
  162. }
  163. }
  164. /*
  165. * When the first point is selected, this is called to remember it.
  166. * It is also called when a reset to the current point is desired.
  167. * This sets the current and initial points to the current point.
  168. */
  169. static void setPosition(r, cx, cy)
  170. RubberBand *r;
  171. int cx, cy;
  172. {
  173. r->currentx = cx; /* Set the current position. */
  174. r->currenty = cy;
  175. /* If not drawing a V, remember the current position as the start position. */
  176. if (r->currentType != SelectTypeVband) {
  177. r->firstx = cx;
  178. r->firsty = cy;
  179. }
  180. }
  181. /* Convert the cursor position to screen coordinates (from cursor.c). */
  182. static void scaleCursor(xin, yin, xout, yout)
  183. int xin, yin, *xout, *yout;
  184. {
  185. if (movecursor(xin, yin) == 0) {
  186. currentCursor(xout, yout);
  187. } else {
  188. *xout = 0;
  189. *yout = 0;
  190. }
  191. }
  192. /* Returns 1 if finished selecting; 0 otherwise... meaning call this again. */
  193. static int EventCycle(r)
  194. RubberBand *r;
  195. {
  196. Boolean domore;
  197. Cardinal nparams = 0;
  198. Display *dpy;
  199. String params = NULL;
  200. Window window;
  201. Widget w;
  202. XEvent event;
  203. XtAppContext context;
  204. dpy = XtDisplay(r->widget);
  205. window = XtWindow(r->widget);
  206. context = XtDisplayToApplicationContext(dpy);
  207. changeCursor(r, 0);
  208. domore = True;
  209. while (domore == True) { /* Select the first point. */
  210. XtAppNextEvent(context, &event);
  211. if (XDebug)
  212. (void)fprintf(stderr, " %s\n", event_names[event.type]);
  213. if (event.xany.window != window) {
  214. XtDispatchEvent(&event);
  215. continue; /* Return to the start of the domore loop. */
  216. }
  217. r->buttonPushed = 0;
  218. switch (event.type) {
  219. case ButtonPress:
  220. if (r->pushMode == SelectPushDrag) {
  221. r->buttonPushed = event.xbutton.button;
  222. setPosition(r, event.xbutton.x, event.xbutton.y);
  223. drawLine(r); /* Set and draw the initial point. */
  224. domore = False;
  225. }
  226. break;
  227. case ButtonRelease:
  228. if (r->pushMode != SelectPushDrag) {
  229. r->buttonPushed = event.xbutton.button;
  230. setPosition(r, event.xbutton.x, event.xbutton.y);
  231. drawLine(r); /* Set and draw the initial point. */
  232. domore = False;
  233. }
  234. break;
  235. case Expose:
  236. w = XtWindowToWidget(event.xany.display, event.xany.window);
  237. (void)canvasExpose(w, &event, &params, &nparams);
  238. break;
  239. case MotionNotify:
  240. (void)cursorMotionEvent(w, &event, &params, &nparams);
  241. /* Ignore all Motion events until a button is pressed/released. */
  242. break;
  243. case EnterNotify:
  244. XSetInputFocus(dpy, window, RevertToPointerRoot, CurrentTime);
  245. break;
  246. case LeaveNotify:
  247. XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  248. break;
  249. default:
  250. XtDispatchEvent(&event);
  251. break;
  252. } /* end switch */
  253. } /* end while(domore) */
  254. if (r->currentType == SelectTypeSingle) { /* ...then we are finished. */
  255. selectDone(r, event.xbutton.x, event.xbutton.y);
  256. } else {
  257. changeCursor(r, 1);
  258. }
  259. /* Set up loop only if we need more events; */
  260. /* otherwise, fall through to the end of the routine. */
  261. domore = (r->currentType != SelectTypeSingle) ? True : False;
  262. while (domore == True) { /* Drawing stage. */
  263. XtAppNextEvent(context, &event);
  264. if (XDebug)
  265. (void)fprintf(stderr, " %s", event_names[event.type]);
  266. if (event.xany.window != window) {
  267. XtDispatchEvent(&event);
  268. if (XDebug) (void)fprintf(stderr, "\n");
  269. continue; /* Return to the start of the domore loop. */
  270. }
  271. switch (event.type) {
  272. case ButtonPress:
  273. if (XDebug)
  274. (void)fprintf(stderr, " button=%d x,y=%d,%d",
  275. event.xbutton.button, event.xbutton.x, event.xbutton.y);
  276. if (event.xbutton.button == r->buttonPushed) {
  277. if (r->pushMode != SelectPushDrag) {
  278. selectDone(r, event.xbutton.x, event.xbutton.y);
  279. domore = False;
  280. }
  281. }
  282. break;
  283. case ButtonRelease:
  284. if (XDebug)
  285. (void)fprintf(stderr, " button=%d x,y=%d,%d",
  286. event.xbutton.button, event.xbutton.x, event.xbutton.y);
  287. if (event.xbutton.button == r->buttonPushed) {
  288. if (r->pushMode == SelectPushDrag) {
  289. selectDone(r, event.xbutton.x, event.xbutton.y);
  290. domore = False;
  291. }
  292. }
  293. break;
  294. case Expose:
  295. w = XtWindowToWidget(event.xany.display, event.xany.window);
  296. (void)canvasExpose(w, &event, &params, &nparams);
  297. drawLine(r); /* Erase old figure. */
  298. break;
  299. case MotionNotify:
  300. w = XtWindowToWidget(event.xany.display, event.xany.window);
  301. (void)cursorMotionEvent(w, &event, &params, &nparams);
  302. if (XDebug)
  303. (void)fprintf(stderr, " state=%d x,y=%d,%d",
  304. event.xmotion.state, event.xmotion.x, event.xmotion.y);
  305. drawLine(r); /* Erase old figure. */
  306. r->currentx = event.xmotion.x; /* Update current position. */
  307. r->currenty = event.xmotion.y;
  308. drawLine(r); /* Draw new figure. */
  309. break;
  310. case EnterNotify:
  311. XSetInputFocus(dpy, window, RevertToPointerRoot, CurrentTime);
  312. break;
  313. case LeaveNotify:
  314. drawLine(r); /* Erase old figure. */
  315. XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  316. if (XDebug) (void)fprintf(stderr, "\n");
  317. return(0); /* Force a return back to the start of this routine. */
  318. break;
  319. default: /* Dispatch any other events. */
  320. XtDispatchEvent(&event);
  321. break;
  322. } /* end switch */
  323. if (XDebug) (void)fprintf(stderr, "\n");
  324. } /* end while(domore) */
  325. /* Finished selecting. */
  326. changeCursor(r, RESETCURSOR);
  327. return(1);
  328. }
  329. static void getPoints(r)
  330. RubberBand *r;
  331. {
  332. Arg args[10];
  333. Cardinal i;
  334. Display *dpy = XtDisplay(r->widget);
  335. XEvent event;
  336. /* Create a graphics context for the Select drawing routines. */
  337. r->SelectGC = XCreateGC(dpy, XtWindow(r->widget), 0, (XGCValues *)NULL);
  338. XSetForeground(dpy, r->SelectGC, (((unsigned long)1) << depth) - 1);
  339. XSetFunction(dpy, r->SelectGC, GXxor);
  340. XSetPlaneMask(dpy, r->SelectGC, AllPlanes);
  341. /* Use r->channel to fix the PlaneMask?? */
  342. XSetSubwindowMode(dpy, r->SelectGC, IncludeInferiors);
  343. i = 0;
  344. XtSetArg(args[i], XtNcursor, (XtArgVal)&r->savedCursor); i++;
  345. XtGetValues(r->widget, args, i);
  346. /* Discard any ButtonPress or ButtonRelease events encountered until now. */
  347. while (XCheckTypedEvent(dpy, ButtonPress, &event))
  348. /* NULL */ ;
  349. while (XCheckTypedEvent(dpy, ButtonRelease, &event))
  350. /* NULL */ ;
  351. while (EventCycle(r) == 0)/* Event loop; where everything gets done. */
  352. /* NULL */ ;
  353. XFreeGC(dpy, r->SelectGC); /* Release this GC. */
  354. return;
  355. }
  356. /*------------------------------------------------------------------------
  357. * This routine responds to opcode 71.
  358. *------------------------------------------------------------------------*/
  359. int selectPoints(w, nwords)
  360. Widget w;
  361. short int *nwords;
  362. {
  363. short int *ip;
  364. int x, y;
  365. RubberBand *r;
  366. RubberBand rdata;
  367. static Boolean inUse = False;
  368. r = &rdata;
  369. /* Will only happen if more than one connection at a time is supported. */
  370. if (inUse == True) {
  371. (void)fprintf(stderr, "Can't have more than one select at once!\n");
  372. return(-1);
  373. }
  374. r->channel = xbuf.parms[0]; /* Memory channel to draw on. */
  375. if ((r->channel < 1) || (r->channel > NGRTOT)) {
  376. /* Ignore any bad channels for now...
  377. (void)fprintf(stderr, "Bad select channel = %d\n", r->channel);
  378. return(-2);
  379. ... */
  380. }
  381. r->currentType = (short int)xbuf.parms[1]; /* Point type. */
  382. if ((r->currentType < 0) || (r->currentType >= NumberofTypes)) {
  383. (void)fprintf(stderr, "Bad point type = %d\n", r->currentType);
  384. return(-3);
  385. }
  386. r->pushMode = (short int)xbuf.parms[2]; /* Push mode. */
  387. if ((r->pushMode < 0) || (r->pushMode >= NumberofPushes)) {
  388. (void)fprintf(stderr, "Bad choice of push mode = %d\n", r->pushMode);
  389. return(-4);
  390. }
  391. if (r->currentType == SelectTypeVband) { /* Get start and end points. */
  392. if (xbuf.data_length != (4 * sizeof(short int))) {/* Need 4 shorts. */
  393. (void)fprintf(stderr,
  394. "Bad number of input positions: input %d (bytes) != required %d\n",
  395. xbuf.data_length, 4 * sizeof(short int));
  396. return(-5);
  397. }
  398. ip = (short *)xbuf.data;
  399. x = (int)*ip++;
  400. y = (int)*ip++;
  401. scaleCursor(x, y, &r->firstx, &r->firsty);
  402. x = (int)*ip++;
  403. y = (int)*ip++;
  404. scaleCursor(x, y, &r->vbandx, &r->vbandy);
  405. }
  406. r->widget = w;
  407. inUse = True;
  408. getPoints(r);
  409. /* Convert to external coordinate system and then return the data. */
  410. RecordCursor(r->firstx, r->firsty);
  411. GetCursor(&ybuf.data[0], &ybuf.data[1]);
  412. RecordCursor(r->currentx, r->currenty);
  413. GetCursor(&ybuf.data[2], &ybuf.data[3]);
  414. ybuf.data[4] = (short int)r->buttonPushed;
  415. *nwords = 5;
  416. inUse = False;
  417. return(0);
  418. }