2 static char *RCSid() { return RCSid("$Id: mouse.c,v 1.85.2.8 2009/06/05 00:32:52 sfeam Exp $"); }
5 /* GNUPLOT - mouse.c */
7 /* driver independent mouse part. */
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
40 * Original Software (October 1999 - January 2000):
41 * Pieter-Tjerk de Boer <ptdeboer@cs.utwente.nl>
42 * Petr Mikulik <mikulik@physics.muni.cz>
43 * Johannes Zellner <johannes@zellner.org>
50 #define _MOUSE_C /* FIXME HBB 20010207: violates Codestyle */
51 #ifdef USE_MOUSE /* comment out whole file, otherwise... */
70 # include "win/winmain.h"
74 #include "os2/pm_msgs.h"
77 /********************** variables ***********************************************************/
79 mouse_setting_t mouse_setting = {
81 0 /* don't start with mouse on default -- clashes with arrow keys on command line */,
83 1 /* start with mouse on by default */,
91 /* "usual well-known" keycodes, i.e. those not listed in special_keys in mouse.h
93 static const struct gen_table usual_special_keys[] =
95 { "BackSpace", GP_BackSpace},
97 { "KP_Enter", GP_KP_Enter},
98 { "Return", GP_Return},
99 { "Escape", GP_Escape},
100 { "Delete", GP_Delete},
104 /* the status of the shift, ctrl and alt keys
106 static int modifier_mask = 0;
108 /* Structure for the ruler: on/off, position,...
112 double x, y, x2, y2; /* ruler position in real units of the graph */
113 long px, py; /* ruler position in the viewport units */
115 FALSE, 0, 0, 0, 0, 0, 0
119 /* the coordinates of the mouse cursor in gnuplot's internal coordinate system
121 static int mouse_x = -1, mouse_y = -1;
124 /* the "real" coordinates of the mouse cursor, i.e., in the user's coordinate
127 static double real_x, real_y, real_x2, real_y2;
130 /* mouse_polar_distance is set to TRUE if user wants to see the
131 * distance between the ruler and mouse pointer in polar coordinates
132 * too (otherwise, distance in cartesian coordinates only is shown) */
133 /* int mouse_polar_distance = FALSE; */
134 /* moved to the struct mouse_setting_t (joze) */
137 /* status of buttons; button i corresponds to bit (1<<i) of this variable
139 static int button = 0;
142 /* variables for setting the zoom region:
144 /* flag, TRUE while user is outlining the zoom region */
145 static TBOOLEAN setting_zoom_region = FALSE;
146 /* coordinates of the first corner of the zoom region, in the internal
147 * coordinate system */
148 static int setting_zoom_x, setting_zoom_y;
151 /* variables for changing the 3D view:
153 /* do we allow motion to result in a replot right now? */
154 TBOOLEAN allowmotion = TRUE; /* used by pm.trm, too */
155 /* did we already postpone a replot because allowmotion was FALSE ? */
156 static TBOOLEAN needreplot = FALSE;
157 /* mouse position when dragging started */
158 static int start_x, start_y;
159 /* ButtonPress sets this to 0, ButtonMotion to 1 */
160 static int motion = 0;
161 /* values for rot_x and rot_z corresponding to zero position of mouse */
162 static float zero_rot_x, zero_rot_z;
165 /* bind related stuff */
167 typedef struct bind_t {
172 char *(*builtin) (struct gp_event_t * ge);
177 static bind_t *bindings = (bind_t *) 0;
178 static const int NO_KEY = -1;
179 static TBOOLEAN trap_release = FALSE;
181 /* forward declarations */
182 static void alert __PROTO((void));
183 static void MousePosToGraphPosReal __PROTO((int xx, int yy, double *x, double *y, double *x2, double *y2));
184 static char *xy_format __PROTO((void));
185 static char *zoombox_format __PROTO((void));
186 static char *xy1_format __PROTO((char *leader));
187 static char *GetAnnotateString __PROTO((char *s, double x, double y, int mode, char *fmt));
188 static char *xDateTimeFormat __PROTO((double x, char *b, int mode));
189 #ifdef OLD_STATUS_LINE
190 static char *GetCoordinateString __PROTO((char *s, double x, double y));
192 static void GetRulerString __PROTO((char *p, double x, double y));
193 static void apply_zoom __PROTO((struct t_zoom * z));
194 static void do_zoom __PROTO((double xmin, double ymin, double x2min,
195 double y2min, double xmax, double ymax, double x2max, double y2max));
196 static void ZoomNext __PROTO((void));
197 static void ZoomPrevious __PROTO((void));
198 static void ZoomUnzoom __PROTO((void));
199 static void incr_mousemode __PROTO((const int amount));
200 static void incr_clipboardmode __PROTO((const int amount));
201 static void UpdateStatuslineWithMouseSetting __PROTO((mouse_setting_t * ms));
203 static void event_keypress __PROTO((struct gp_event_t * ge, TBOOLEAN current));
204 static void ChangeView __PROTO((int x, int z));
205 static void event_buttonpress __PROTO((struct gp_event_t * ge));
206 static void event_buttonrelease __PROTO((struct gp_event_t * ge));
207 static void event_motion __PROTO((struct gp_event_t * ge));
208 static void event_modifier __PROTO((struct gp_event_t * ge));
209 static void do_save_3dplot __PROTO((struct surface_points *, int, int));
210 static void load_mouse_variables __PROTO((double, double, TBOOLEAN, int));
213 static char *builtin_autoscale __PROTO((struct gp_event_t * ge));
214 static char *builtin_toggle_border __PROTO((struct gp_event_t * ge));
215 static char *builtin_replot __PROTO((struct gp_event_t * ge));
216 static char *builtin_toggle_grid __PROTO((struct gp_event_t * ge));
217 static char *builtin_help __PROTO((struct gp_event_t * ge));
218 static char *builtin_toggle_log __PROTO((struct gp_event_t * ge));
219 static char *builtin_nearest_log __PROTO((struct gp_event_t * ge));
220 static char *builtin_toggle_mouse __PROTO((struct gp_event_t * ge));
221 static char *builtin_toggle_ruler __PROTO((struct gp_event_t * ge));
222 static char *builtin_decrement_mousemode __PROTO((struct gp_event_t * ge));
223 static char *builtin_increment_mousemode __PROTO((struct gp_event_t * ge));
224 static char *builtin_decrement_clipboardmode __PROTO((struct gp_event_t * ge));
225 static char *builtin_increment_clipboardmode __PROTO((struct gp_event_t * ge));
226 static char *builtin_toggle_polardistance __PROTO((struct gp_event_t * ge));
227 static char *builtin_toggle_verbose __PROTO((struct gp_event_t * ge));
228 static char *builtin_toggle_ratio __PROTO((struct gp_event_t * ge));
229 static char *builtin_zoom_next __PROTO((struct gp_event_t * ge));
230 static char *builtin_zoom_previous __PROTO((struct gp_event_t * ge));
231 static char *builtin_unzoom __PROTO((struct gp_event_t * ge));
232 static char *builtin_rotate_right __PROTO((struct gp_event_t * ge));
233 static char *builtin_rotate_up __PROTO((struct gp_event_t * ge));
234 static char *builtin_rotate_left __PROTO((struct gp_event_t * ge));
235 static char *builtin_rotate_down __PROTO((struct gp_event_t * ge));
236 static char *builtin_cancel_zoom __PROTO((struct gp_event_t * ge));
238 /* prototypes for bind stuff
239 * which are used only here. */
240 static void bind_install_default_bindings __PROTO((void));
241 static void bind_clear __PROTO((bind_t * b));
242 static int lookup_key __PROTO((char *ptr, int *len));
243 static int bind_scan_lhs __PROTO((bind_t * out, const char *in));
244 static char *bind_fmt_lhs __PROTO((const bind_t * in));
245 static int bind_matches __PROTO((const bind_t * a, const bind_t * b));
246 static void bind_display_one __PROTO((bind_t * ptr));
247 static void bind_display __PROTO((char *lhs));
248 static void bind_all __PROTO((char *lhs));
249 static void bind_remove __PROTO((bind_t * b));
250 static void bind_append __PROTO((char *lhs, char *rhs, char *(*builtin) (struct gp_event_t * ge)));
251 static void recalc_ruler_pos __PROTO((void));
252 static void turn_ruler_off __PROTO((void));
253 static int nearest_label_tag __PROTO((int x, int y, struct termentry * t));
254 static void remove_label __PROTO((int x, int y));
255 static void put_label __PROTO((char *label, double x, double y));
257 /********* functions ********************************************/
266 # ifdef HAVE_LIBREADLINE
268 fflush(rl_outstream);
270 fprintf(stderr, "\a");
275 /* always include the prototype. The prototype might even not be
276 * declared if the system supports stpcpy(). E.g. on Linux I would
277 * have to define __USE_GNU before including string.h to get the
278 * prototype (joze) */
279 /* HBB 20001109: *BUT* if a prototype is there, this one may easily
280 * conflict with it... */
281 char *stpcpy __PROTO((char *s, const char *p));
284 /* handy function for composing strings; note: some platforms may
285 * already provide it, how should we handle that? autoconf? -- ptdb */
287 stpcpy(char *s, const char *p)
290 return s + strlen(p);
295 /* main job of transformation, which is not device dependent
298 MousePosToGraphPosReal(int xx, int yy, double *x, double *y, double *x2, double *y2)
302 printf("POS: plot_bounds.xleft=%i, plot_bounds.xright=%i, plot_bounds.ybot=%i, plot_bounds.ytop=%i\n", plot_bounds.xleft, plot_bounds.xright, plot_bounds.ybot, plot_bounds.ytop);
304 if (plot_bounds.xright == plot_bounds.xleft)
305 *x = *x2 = VERYLARGE; /* protection */
307 *x = AXIS_MAPBACK(FIRST_X_AXIS, xx);
308 *x2 = AXIS_MAPBACK(SECOND_X_AXIS, xx);
310 if (plot_bounds.ytop == plot_bounds.ybot)
311 *y = *y2 = VERYLARGE; /* protection */
313 *y = AXIS_MAPBACK(FIRST_Y_AXIS, yy);
314 *y2 = AXIS_MAPBACK(SECOND_Y_AXIS, yy);
317 printf("POS: xx=%i, yy=%i => x=%g y=%g\n", xx, yy, *x, *y);
320 /* for 3D plots, we treat the mouse position as if it is
321 * in the bottom plane, i.e., the plane of the x and y axis */
322 /* note: at present, this projection is only correct if
323 * surface_rot_z is a multiple of 90 degrees! */
324 /* HBB 20010522: added protection against division by zero
325 * for cases like 'set view 90,0' */
328 if (abs(axis3d_x_dx) > abs(axis3d_x_dy)) {
329 *x = axis_array[FIRST_X_AXIS].min
330 + ((double) xx) / axis3d_x_dx * (axis_array[FIRST_X_AXIS].max -
331 axis_array[FIRST_X_AXIS].min);
332 } else if (axis3d_x_dy != 0) {
333 *x = axis_array[FIRST_X_AXIS].min
334 + ((double) yy) / axis3d_x_dy * (axis_array[FIRST_X_AXIS].max -
335 axis_array[FIRST_X_AXIS].min);
337 /* both diffs are zero (x axis points into the screen */
341 if (abs(axis3d_y_dx) > abs(axis3d_y_dy)) {
342 *y = axis_array[FIRST_Y_AXIS].min
343 + ((double) xx) / axis3d_y_dx * (axis_array[FIRST_Y_AXIS].max -
344 axis_array[FIRST_Y_AXIS].min);
345 } else if (axis3d_y_dy != 0) {
346 *y = axis_array[FIRST_Y_AXIS].min
347 + ((double) yy) / axis3d_y_dy * (axis_array[FIRST_Y_AXIS].max -
348 axis_array[FIRST_Y_AXIS].min);
350 /* both diffs are zero (y axis points into the screen */
354 *x2 = *y2 = VERYLARGE; /* protection */
357 Note: there is plot_bounds.xleft+0.5 in "#define map_x" in graphics.c, which
358 makes no major impact here. It seems that the mistake of the real
359 coordinate is at about 0.5%, which corresponds to the screen resolution.
360 It would be better to round the distance to this resolution, and thus
361 *x = xmin + rounded-to-screen-resolution (xdistance)
364 /* Now take into account possible log scales of x and y axes */
365 *x = AXIS_DE_LOG_VALUE(FIRST_X_AXIS, *x);
366 *y = AXIS_DE_LOG_VALUE(FIRST_Y_AXIS, *y);
368 *x2 = AXIS_DE_LOG_VALUE(SECOND_X_AXIS, *x2);
369 *y2 = AXIS_DE_LOG_VALUE(SECOND_Y_AXIS, *y2);
376 static char format[0xff];
378 strcat(format, mouse_setting.fmt);
379 strcat(format, ", ");
380 strcat(format, mouse_setting.fmt);
387 static char format[0xff];
389 strcat(format, mouse_setting.fmt);
390 strcat(format, "\r");
391 strcat(format, mouse_setting.fmt);
396 xy1_format(char *leader)
398 static char format[0xff];
400 strcat(format, leader);
401 strcat(format, mouse_setting.fmt);
405 /* formats the information for an annotation (middle mouse button clicked)
408 GetAnnotateString(char *s, double x, double y, int mode, char *fmt)
410 if (mode == MOUSE_COORDINATES_XDATE || mode == MOUSE_COORDINATES_XTIME || mode == MOUSE_COORDINATES_XDATETIME || mode == MOUSE_COORDINATES_TIMEFMT) { /* time is on the x axis */
412 char format[0xff] = "[%s, ";
413 strcat(format, mouse_setting.fmt);
415 s += sprintf(s, format, xDateTimeFormat(x, buf, mode), y);
416 } else if (mode == MOUSE_COORDINATES_FRACTIONAL) {
417 double xrange = axis_array[FIRST_X_AXIS].max - axis_array[FIRST_X_AXIS].min;
418 double yrange = axis_array[FIRST_Y_AXIS].max - axis_array[FIRST_Y_AXIS].min;
419 /* calculate fractional coordinates.
420 * prevent division by zero */
422 char format[0xff] = "/";
423 strcat(format, mouse_setting.fmt);
424 s += sprintf(s, format, (x - axis_array[FIRST_X_AXIS].min) / xrange);
426 s += sprintf(s, "/(undefined)");
429 char format[0xff] = ", ";
430 strcat(format, mouse_setting.fmt);
432 s += sprintf(s, format, (y - axis_array[FIRST_Y_AXIS].min) / yrange);
434 s += sprintf(s, ", (undefined)/");
436 } else if (mode == MOUSE_COORDINATES_REAL1) {
437 s += sprintf(s, xy_format(), x, y); /* w/o brackets */
438 } else if (mode == MOUSE_COORDINATES_ALT && fmt) {
439 s += sprintf(s, fmt, x, y); /* user defined format */
441 s += sprintf(s, xy_format(), x, y); /* usual x,y values */
447 /* Format x according to the date/time mouse mode. Uses and returns b as
451 xDateTimeFormat(double x, char *b, int mode)
453 # ifndef SEC_OFFS_SYS
454 # define SEC_OFFS_SYS 946684800
456 time_t xtime_position = SEC_OFFS_SYS + x;
457 struct tm *pxtime_position = gmtime(&xtime_position);
459 case MOUSE_COORDINATES_XDATE:
460 sprintf(b, "%d. %d. %04d", pxtime_position->tm_mday, (pxtime_position->tm_mon) + 1,
462 (pxtime_position->tm_year) + ((pxtime_position->tm_year <= 68) ? 2000 : 1900)
464 ((pxtime_position->tm_year) < 100) ? (pxtime_position->tm_year) : (pxtime_position->tm_year) - 100
465 /* (pxtime_position->tm_year)+1900 */
469 case MOUSE_COORDINATES_XTIME:
470 sprintf(b, "%d:%02d", pxtime_position->tm_hour, pxtime_position->tm_min);
472 case MOUSE_COORDINATES_XDATETIME:
473 sprintf(b, "%d. %d. %04d %d:%02d", pxtime_position->tm_mday, (pxtime_position->tm_mon) + 1,
475 (pxtime_position->tm_year) + ((pxtime_position->tm_year <= 68) ? 2000 : 1900),
477 ((pxtime_position->tm_year) < 100) ? (pxtime_position->tm_year) : (pxtime_position->tm_year) - 100,
478 /* (pxtime_position->tm_year)+1900, */
480 pxtime_position->tm_hour, pxtime_position->tm_min);
482 case MOUSE_COORDINATES_TIMEFMT:
483 /* FIXME HBB 20000507: timefmt is for *reading* timedata, not
484 * for writing them! */
485 gstrftime(b, 0xff, axis_array[FIRST_X_AXIS].timefmt, x);
488 sprintf(b, mouse_setting.fmt, x);
495 /* HBB 20000507: fixed a construction error. Was using the 'timefmt'
496 * string (which is for reading, not writing time data) to output the
497 * value. Code is now closer to what setup_tics does. */
498 #define MKSTR(sp,x,axis) \
500 if (x >= VERYLARGE) break; \
501 if (axis_array[axis].is_timedata) { \
502 char *format = copy_or_invent_formatstring(axis); \
503 while (strchr(format,'\n')) \
504 *(strchr(format,'\n')) = ' '; \
505 sp+=gstrftime(sp, 40, format, x); \
507 sp+=sprintf(sp, mouse_setting.fmt ,x); \
511 /* formats the information for an annotation (middle mouse button clicked)
512 * returns pointer to the end of the string, for easy concatenation
514 # ifdef OLD_STATUS_LINE
516 GetCoordinateString(char *s, double x, double y)
521 MKSTR(sp, x, FIRST_X_AXIS);
524 MKSTR(sp, y, FIRST_Y_AXIS);
532 /* ratio for log, distance for linear */
533 # define DIST(x,rx,axis) \
534 (axis_array[axis].log) \
535 ? ( (rx==0) ? 99999 : x / rx ) \
539 /* formats the ruler information (position, distance,...) into string p
540 (it must be sufficiently long)
541 x, y is the current mouse position in real coords (for the calculation
545 GetRulerString(char *p, double x, double y)
549 char format[0xff] = " ruler: [";
550 strcat(format, mouse_setting.fmt);
551 strcat(format, ", ");
552 strcat(format, mouse_setting.fmt);
553 strcat(format, "] distance: ");
554 strcat(format, mouse_setting.fmt);
555 strcat(format, ", ");
556 strcat(format, mouse_setting.fmt);
558 dx = DIST(x, ruler.x, FIRST_X_AXIS);
559 dy = DIST(y, ruler.y, FIRST_Y_AXIS);
560 sprintf(p, format, ruler.x, ruler.y, dx, dy);
562 /* Previously, the following "if" let the polar coordinates to be shown only
564 if (mouse_setting.polardistance && !axis_array[FIRST_X_AXIS].log && !axis_array[FIRST_Y_AXIS].log) ...
565 Now, let us support also semilog and log-log plots.
566 Values of mouse_setting.polardistance are:
567 0 (no polar coordinates), 1 (polar coordinates), 2 (tangent instead of angle).
569 if (mouse_setting.polardistance) {
570 double rho, phi, rx, ry;
572 x = AXIS_LOG_VALUE(FIRST_X_AXIS, x);
573 y = AXIS_LOG_VALUE(FIRST_Y_AXIS, y);
574 rx = AXIS_LOG_VALUE(FIRST_X_AXIS, ruler.x);
575 ry = AXIS_LOG_VALUE(FIRST_Y_AXIS, ruler.y);
577 strcat(format, " (");
578 strcat(format, mouse_setting.fmt);
579 rho = sqrt((x - rx) * (x - rx) + (y - ry) * (y - ry)); /* distance */
580 if (mouse_setting.polardistance == 1) { /* (distance, angle) */
581 phi = (180 / M_PI) * atan2(y - ry, x - rx);
583 strcat(format, ";% #.4gø)");
585 strcat(format, ", % #.4gdeg)");
587 } else { /* mouse_setting.polardistance==2: (distance, tangent) */
589 phi = (phi == 0) ? ((y-ry>0) ? VERYLARGE : -VERYLARGE) : (y - ry)/phi;
590 sprintf(format+strlen(format), ", tangent=%s)", mouse_setting.fmt);
592 sprintf(ptmp, format, rho, phi);
598 static struct t_zoom *zoom_head = NULL, *zoom_now = NULL;
599 /* Applies the zoom rectangle of z by sending the appropriate command
604 apply_zoom(struct t_zoom *z)
606 char s[1024]; /* HBB 20011005: made larger */
607 /* HBB 20011004: new variable, fixing 'unzoom' back to autoscaled range */
608 static t_autoscale autoscale_copies[AXIS_ARRAY_SIZE];
609 int is_splot_map = (is_3d_plot && (splot_map == TRUE));
612 if (zoom_now != NULL) { /* remember the current zoom */
613 zoom_now->xmin = axis_array[FIRST_X_AXIS].set_min;
614 zoom_now->xmax = axis_array[FIRST_X_AXIS].set_max;
615 zoom_now->x2min = axis_array[SECOND_X_AXIS].set_min;
616 zoom_now->x2max = axis_array[SECOND_X_AXIS].set_max;
617 zoom_now->was_splot_map = is_splot_map;
618 if (!is_splot_map) { /* 2D plot */
619 zoom_now->ymin = axis_array[FIRST_Y_AXIS].set_min;
620 zoom_now->ymax = axis_array[FIRST_Y_AXIS].set_max;
621 zoom_now->y2min = axis_array[SECOND_Y_AXIS].set_min;
622 zoom_now->y2max = axis_array[SECOND_Y_AXIS].set_max;
623 } else { /* the opposite, i.e. case 'set view map' */
624 zoom_now->ymin = axis_array[FIRST_Y_AXIS].set_max;
625 zoom_now->ymax = axis_array[FIRST_Y_AXIS].set_min;
626 zoom_now->y2min = axis_array[SECOND_Y_AXIS].set_max;
627 zoom_now->y2max = axis_array[SECOND_Y_AXIS].set_min;
632 /* HBB 20011004: implement save/restore of autoscaling if returning to
633 * original setting */
634 if (zoom_now == zoom_head) {
635 /* previous current zoom is the head --> we're leaving
636 * original non-moused status --> save autoscales */
638 for (i = 0; i < AXIS_ARRAY_SIZE; i++)
639 autoscale_copies[i] = axis_array[i].set_autoscale;
643 if (zoom_now == NULL) {
648 flip = (is_splot_map && zoom_now->was_splot_map);
650 if (strcmp(localeconv()->decimal_point,".")) {
651 char *save_locale = gp_strdup(setlocale(LC_NUMERIC,NULL));
652 setlocale(LC_NUMERIC,"C");
653 sprintf(s, "set xr[%.12g:%.12g]; set yr[%.12g:%.12g]",
654 zoom_now->xmin, zoom_now->xmax,
655 (flip) ? zoom_now->ymax : zoom_now->ymin,
656 (flip) ? zoom_now->ymin : zoom_now->ymax);
657 setlocale(LC_NUMERIC,save_locale);
661 sprintf(s, "set xr[%.12g:%.12g]; set yr[%.12g:%.12g]",
662 zoom_now->xmin, zoom_now->xmax,
663 (flip) ? zoom_now->ymax : zoom_now->ymin,
664 (flip) ? zoom_now->ymin : zoom_now->ymax);
666 /* HBB 20011004: the final part of 'unzoom to autoscale mode'.
667 * Optionally appends 'set autoscale' commands to the string to be
668 * sent, to restore the saved settings. */
669 #define OUTPUT_AUTOSCALE(axis) \
671 t_autoscale autoscale = autoscale_copies[axis]; \
672 t_autoscale fix = autoscale & (AUTOSCALE_FIXMIN | AUTOSCALE_FIXMAX); \
674 autoscale &= AUTOSCALE_BOTH; \
677 sprintf(s + strlen(s), "; set au %s%s", \
678 axis_defaults[axis].name, \
679 autoscale == AUTOSCALE_MIN ? "min" \
680 : autoscale == AUTOSCALE_MAX ? "max" \
683 sprintf(s + strlen(s), "; set au %sfix%s", \
684 axis_defaults[axis].name, \
685 fix == AUTOSCALE_FIXMIN ? "min" \
686 : fix == AUTOSCALE_FIXMAX ? "max" \
691 if (zoom_now == zoom_head) {
692 /* new current zoom is the head --> returning to unzoomed
693 * settings --> restore autoscale */
694 OUTPUT_AUTOSCALE(FIRST_X_AXIS);
695 OUTPUT_AUTOSCALE(FIRST_Y_AXIS);
700 if (strcmp(localeconv()->decimal_point,".")) {
701 char *save_locale = gp_strdup(setlocale(LC_NUMERIC,NULL));
702 setlocale(LC_NUMERIC,"C");
703 sprintf(s + strlen(s), "; set x2r[% #g:% #g]; set y2r[% #g:% #g]",
704 zoom_now->x2min, zoom_now->x2max,
705 zoom_now->y2min, zoom_now->y2max);
706 setlocale(LC_NUMERIC,save_locale);
710 sprintf(s + strlen(s), "; set x2r[% #g:% #g]; set y2r[% #g:% #g]",
711 zoom_now->x2min, zoom_now->x2max,
712 zoom_now->y2min, zoom_now->y2max);
713 if (zoom_now == zoom_head) {
714 /* new current zoom is the head --> returning to unzoomed
715 * settings --> restore autoscale */
716 OUTPUT_AUTOSCALE(SECOND_X_AXIS);
717 OUTPUT_AUTOSCALE(SECOND_Y_AXIS);
719 #undef OUTPUT_AUTOSCALE
725 /* makes a zoom: update zoom history, call gnuplot to set ranges + replot
729 do_zoom(double xmin, double ymin, double x2min, double y2min, double xmax, double ymax, double x2max, double y2max)
732 if (zoom_head == NULL) { /* queue not yet created, thus make its head */
733 zoom_head = gp_alloc(sizeof(struct t_zoom), "mouse zoom history head");
734 zoom_head->prev = NULL;
735 zoom_head->next = NULL;
737 if (zoom_now == NULL)
738 zoom_now = zoom_head;
739 if (zoom_now->next == NULL) { /* allocate new item */
740 z = gp_alloc(sizeof(struct t_zoom), "mouse zoom history element");
745 } else /* overwrite next item */
755 z->was_splot_map = (is_3d_plot && (splot_map == TRUE)); /* see is_splot_map in apply_zoom() */
763 if (zoom_now == NULL || zoom_now->next == NULL)
766 apply_zoom(zoom_now->next);
767 if (display_ipc_commands()) {
768 fprintf(stderr, "next zoom.\n");
775 if (zoom_now == NULL || zoom_now->prev == NULL)
778 apply_zoom(zoom_now->prev);
779 if (display_ipc_commands()) {
780 fprintf(stderr, "previous zoom.\n");
787 if (zoom_head == NULL || zoom_now == zoom_head)
790 apply_zoom(zoom_head);
791 if (display_ipc_commands()) {
792 fprintf(stderr, "unzoom.\n");
797 incr_mousemode(const int amount)
799 long int old = mouse_mode;
800 mouse_mode += amount;
801 if (MOUSE_COORDINATES_ALT == mouse_mode && !mouse_alt_string) {
802 mouse_mode += amount; /* stepping over */
804 if (mouse_mode > MOUSE_COORDINATES_ALT) {
805 mouse_mode = MOUSE_COORDINATES_REAL;
806 } else if (mouse_mode < MOUSE_COORDINATES_REAL) {
807 mouse_mode = MOUSE_COORDINATES_ALT;
808 if (MOUSE_COORDINATES_ALT == mouse_mode && !mouse_alt_string) {
809 mouse_mode--; /* stepping over */
813 if (display_ipc_commands()) {
814 fprintf(stderr, "switched mouse format from %ld to %ld\n", old, mouse_mode);
819 incr_clipboardmode(const int amount)
821 long int old = clipboard_mode;
822 clipboard_mode += amount;
823 if (MOUSE_COORDINATES_ALT == clipboard_mode && !clipboard_alt_string) {
824 clipboard_mode += amount; /* stepping over */
826 if (clipboard_mode > MOUSE_COORDINATES_ALT) {
827 clipboard_mode = MOUSE_COORDINATES_REAL;
828 } else if (clipboard_mode < MOUSE_COORDINATES_REAL) {
829 clipboard_mode = MOUSE_COORDINATES_ALT;
830 if (MOUSE_COORDINATES_ALT == clipboard_mode && !clipboard_alt_string) {
831 clipboard_mode--; /* stepping over */
834 if (display_ipc_commands()) {
835 fprintf(stderr, "switched clipboard format from %ld to %ld\n", old, clipboard_mode);
839 # define TICS_ON(ti) (((ti)&TICS_MASK)!=NO_TICS)
844 UpdateStatuslineWithMouseSetting(&mouse_setting);
848 UpdateStatuslineWithMouseSetting(mouse_setting_t * ms)
851 if (!term_initialised)
855 } else if (!ALMOST2D) {
858 strcat(format, "view: ");
859 strcat(format, ms->fmt);
860 strcat(format, ", ");
861 strcat(format, ms->fmt);
862 strcat(format, " scale: ");
863 strcat(format, ms->fmt);
864 strcat(format, ", ");
865 strcat(format, ms->fmt);
866 sprintf(s0, format, surface_rot_x, surface_rot_z, surface_scale, surface_zscale);
867 } else if (!TICS_ON(axis_array[SECOND_X_AXIS].ticmode) && !TICS_ON(axis_array[SECOND_Y_AXIS].ticmode)) {
868 /* only first X and Y axis are in use */
869 # ifdef OLD_STATUS_LINE
870 sp = GetCoordinateString(s0, real_x, real_y);
872 sp = GetAnnotateString(s0, real_x, real_y, mouse_mode, mouse_alt_string);
876 MousePosToGraphPosReal(ruler.px, ruler.py, &ruler.x, &ruler.y, &ruler.x2, &ruler.y2);
878 GetRulerString(sp, real_x, real_y);
881 /* X2 and/or Y2 are in use: use more verbose format */
883 if (TICS_ON(axis_array[FIRST_X_AXIS].ticmode)) {
884 sp = stpcpy(sp, "x=");
885 MKSTR(sp, real_x, FIRST_X_AXIS);
888 if (TICS_ON(axis_array[FIRST_Y_AXIS].ticmode)) {
889 sp = stpcpy(sp, "y=");
890 MKSTR(sp, real_y, FIRST_Y_AXIS);
893 if (TICS_ON(axis_array[SECOND_X_AXIS].ticmode)) {
894 sp = stpcpy(sp, "x2=");
895 MKSTR(sp, real_x2, SECOND_X_AXIS);
898 if (TICS_ON(axis_array[SECOND_Y_AXIS].ticmode)) {
899 sp = stpcpy(sp, "y2=");
900 MKSTR(sp, real_y2, SECOND_Y_AXIS);
904 /* ruler on? then also print distances to ruler */
906 MousePosToGraphPosReal(ruler.px, ruler.py, &ruler.x, &ruler.y, &ruler.x2, &ruler.y2);
908 if (TICS_ON(axis_array[FIRST_X_AXIS].ticmode))
909 sp += sprintf(sp, xy1_format("dx="), DIST(real_x, ruler.x, FIRST_X_AXIS));
910 if (TICS_ON(axis_array[FIRST_Y_AXIS].ticmode))
911 sp += sprintf(sp, xy1_format("dy="), DIST(real_y, ruler.y, FIRST_Y_AXIS));
912 if (TICS_ON(axis_array[SECOND_X_AXIS].ticmode))
913 sp += sprintf(sp, xy1_format("dx2="), DIST(real_x2, ruler.x2, SECOND_X_AXIS));
914 if (TICS_ON(axis_array[SECOND_Y_AXIS].ticmode))
915 sp += sprintf(sp, xy1_format("dy2="), DIST(real_y2, ruler.y2, SECOND_Y_AXIS));
917 *--sp = 0; /* delete trailing space */
919 if (term->put_tmptext) {
920 (term->put_tmptext) (0, s0);
929 MousePosToGraphPosReal(mouse_x, mouse_y, &real_x, &real_y, &real_x2, &real_y2);
933 /****************** handlers for user's actions ******************/
936 builtin_autoscale(struct gp_event_t *ge)
939 return "`builtin-autoscale` (set autoscale keepfix; replot)";
941 do_string_replot("set autoscale keepfix");
946 builtin_toggle_border(struct gp_event_t *ge)
949 return "`builtin-toggle-border`";
952 if (draw_border == 4095)
953 do_string_replot("set border");
955 do_string_replot("set border 4095 lw 0.5");
957 if (draw_border == 15)
958 do_string_replot("set border");
960 do_string_replot("set border 15 lw 0.5");
966 builtin_replot(struct gp_event_t *ge)
969 return "`builtin-replot`";
971 do_string_replot("");
976 builtin_toggle_grid(struct gp_event_t *ge)
979 return "`builtin-toggle-grid`";
981 if (! some_grid_selected())
982 do_string_replot("set grid");
984 do_string_replot("unset grid");
989 builtin_help(struct gp_event_t *ge)
992 return "`builtin-help`";
994 fprintf(stderr, "\n");
995 bind_display((char *) 0); /* display all bindings */
1001 builtin_toggle_log(struct gp_event_t *ge)
1004 return "`builtin-toggle-log` y logscale for plots, z and cb logscale for splots";
1006 if (Z_AXIS.log || CB_AXIS.log)
1007 do_string_replot("unset log zcb");
1009 do_string_replot("set log zcb");
1012 /* set log cb or log y whether using "with (rgb)image" plot or not */
1015 do_string_replot("unset log cb");
1017 do_string_replot("set log cb");
1020 if (axis_array[FIRST_Y_AXIS].log)
1021 do_string_replot("unset log y");
1023 do_string_replot("set log y");
1032 builtin_nearest_log(struct gp_event_t *ge)
1035 return "`builtin-nearest-log` toggle logscale of axis nearest cursor";
1038 /* 3D-plot: toggle lin/log z axis */
1039 if (Z_AXIS.log || CB_AXIS.log)
1040 do_string_replot("unset log zcb");
1042 do_string_replot("set log zcb");
1044 /* 2D-plot: figure out which axis/axes is/are
1045 * close to the mouse cursor, and toggle those lin/log */
1046 /* note: here it is assumed that the x axis is at
1047 * the bottom, x2 at top, y left and y2 right; it
1048 * would be better to derive that from the ..tics settings */
1049 TBOOLEAN change = FALSE;
1050 if (mouse_y < plot_bounds.ybot + (plot_bounds.ytop - plot_bounds.ybot) / 4 && mouse_x > plot_bounds.xleft && mouse_x < plot_bounds.xright) {
1051 do_string(axis_array[FIRST_X_AXIS].log ? "unset log x" : "set log x");
1054 if (mouse_y > plot_bounds.ytop - (plot_bounds.ytop - plot_bounds.ybot) / 4 && mouse_x > plot_bounds.xleft && mouse_x < plot_bounds.xright) {
1055 do_string(axis_array[SECOND_X_AXIS].log ? "unset log x2" : "set log x2");
1058 if (mouse_x < plot_bounds.xleft + (plot_bounds.xright - plot_bounds.xleft) / 4 && mouse_y > plot_bounds.ybot && mouse_y < plot_bounds.ytop) {
1059 do_string(axis_array[FIRST_Y_AXIS].log ? "unset log y" : "set log y");
1062 if (mouse_x > plot_bounds.xright - (plot_bounds.xright - plot_bounds.xleft) / 4 && mouse_y > plot_bounds.ybot && mouse_y < plot_bounds.ytop) {
1063 do_string(axis_array[SECOND_Y_AXIS].log ? "unset log y2" : "set log y2");
1067 do_string_replot("");
1073 builtin_toggle_mouse(struct gp_event_t *ge)
1076 return "`builtin-toggle-mouse`";
1078 if (!mouse_setting.on) {
1079 mouse_setting.on = 1;
1080 if (display_ipc_commands()) {
1081 fprintf(stderr, "turning mouse on.\n");
1084 mouse_setting.on = 0;
1085 if (display_ipc_commands()) {
1086 fprintf(stderr, "turning mouse off.\n");
1091 (*term->set_ruler) (-1, -1);
1096 PM_update_menu_items();
1103 builtin_toggle_ruler(struct gp_event_t *ge)
1106 return "`builtin-toggle-ruler`";
1108 if (!term->set_ruler)
1112 if (display_ipc_commands())
1113 fprintf(stderr, "turning ruler off.\n");
1114 } else if (ALMOST2D) {
1115 /* only allow ruler, if the plot
1116 * is 2d or a 3d `map' */
1117 struct udvt_entry *u;
1121 MousePosToGraphPosReal(ruler.px, ruler.py, &ruler.x, &ruler.y, &ruler.x2, &ruler.y2);
1122 (*term->set_ruler) (ruler.px, ruler.py);
1123 if ((u = add_udv_by_name("MOUSE_RULER_X"))) {
1124 u->udv_undef = FALSE;
1125 Gcomplex(&u->udv_value,ruler.x,0);
1127 if ((u = add_udv_by_name("MOUSE_RULER_Y"))) {
1128 u->udv_undef = FALSE;
1129 Gcomplex(&u->udv_value,ruler.y,0);
1131 if (display_ipc_commands()) {
1132 fprintf(stderr, "turning ruler on.\n");
1140 builtin_decrement_mousemode(struct gp_event_t *ge)
1143 return "`builtin-decrement-mousemode`";
1150 builtin_increment_mousemode(struct gp_event_t *ge)
1153 return "`builtin-increment-mousemode`";
1160 builtin_decrement_clipboardmode(struct gp_event_t *ge)
1163 return "`builtin-decrement-clipboardmode`";
1165 incr_clipboardmode(-1);
1170 builtin_increment_clipboardmode(struct gp_event_t *ge)
1173 return "`builtin-increment-clipboardmode`";
1175 incr_clipboardmode(1);
1180 builtin_toggle_polardistance(struct gp_event_t *ge)
1183 return "`builtin-toggle-polardistance`";
1185 if (++mouse_setting.polardistance > 2) mouse_setting.polardistance = 0;
1186 /* values: 0 (no polar coordinates), 1 (polar coordinates), 2 (tangent instead of angle) */
1187 term->set_cursor((mouse_setting.polardistance ? -3:-4), ge->mx, ge->my); /* change cursor type */
1189 PM_update_menu_items();
1192 if (display_ipc_commands()) {
1193 fprintf(stderr, "distance to ruler will %s be shown in polar coordinates.\n", mouse_setting.polardistance ? "" : "not");
1199 builtin_toggle_verbose(struct gp_event_t *ge)
1202 return "`builtin-toggle-verbose`";
1204 /* this is tricky as the command itself modifies
1205 * the state of display_ipc_commands() */
1206 if (display_ipc_commands()) {
1207 fprintf(stderr, "echoing of communication commands is turned off.\n");
1209 toggle_display_of_ipc_commands();
1210 if (display_ipc_commands()) {
1211 fprintf(stderr, "communication commands will be echoed.\n");
1217 builtin_toggle_ratio(struct gp_event_t *ge)
1220 return "`builtin-toggle-ratio`";
1222 if (aspect_ratio == 0)
1223 do_string_replot("set size ratio -1");
1224 else if (aspect_ratio == 1)
1225 do_string_replot("set size nosquare");
1227 do_string_replot("set size square");
1232 builtin_zoom_next(struct gp_event_t *ge)
1235 return "`builtin-zoom-next` go to next zoom in the zoom stack";
1242 builtin_zoom_previous(struct gp_event_t *ge)
1245 return "`builtin-zoom-previous` go to previous zoom in the zoom stack";
1252 builtin_unzoom(struct gp_event_t *ge)
1255 return "`builtin-unzoom`";
1262 builtin_rotate_right(struct gp_event_t *ge)
1265 return "`builtin-rotate-right` only for splots; <shift> increases amount";
1273 builtin_rotate_left(struct gp_event_t *ge)
1276 return "`builtin-rotate-left` only for splots; <shift> increases amount";
1284 builtin_rotate_up(struct gp_event_t *ge)
1287 return "`builtin-rotate-up` only for splots; <shift> increases amount";
1295 builtin_rotate_down(struct gp_event_t *ge)
1298 return "`builtin-rotate-down` only for splots; <shift> increases amount";
1306 builtin_cancel_zoom(struct gp_event_t *ge)
1309 return "`builtin-cancel-zoom` cancel zoom region";
1311 if (!setting_zoom_region)
1313 if (term->set_cursor)
1314 term->set_cursor(0, 0, 0);
1315 setting_zoom_region = FALSE;
1316 if (display_ipc_commands()) {
1317 fprintf(stderr, "zooming cancelled.\n");
1323 event_keypress(struct gp_event_t *ge, TBOOLEAN current)
1336 bind_install_default_bindings();
1339 if (modifier_mask & Mod_Shift) {
1343 bind_clear(&keypress);
1345 keypress.modifier = modifier_mask;
1348 * On 'pause mouse keypress' in active window export current keypress
1349 * and mouse coords to user variables. A key with 'bind all' terminates
1350 * a pause even from non-active windows.
1351 * Ignore NULL keypress.
1353 * If we are paused for a keystroke, this takes precendence over normal
1354 * key bindings. Otherwise, for example typing 'm' would turn off mousing,
1355 * which is a bad thing if you are in the middle of a mousing operation.
1359 if (paused_for_mouse & PAUSE_KEYSTROKE)
1360 kill_pending_Pause_dialog();
1363 if ((paused_for_mouse & PAUSE_KEYSTROKE) && (c > '\0') && current) {
1364 load_mouse_variables(x, y, FALSE, c);
1368 for (ptr = bindings; ptr; ptr = ptr->next) {
1369 if (bind_matches(&keypress, ptr)) {
1370 struct udvt_entry *keywin;
1371 if ((keywin = add_udv_by_name("MOUSE_KEY_WINDOW"))) {
1372 keywin->udv_undef = FALSE;
1373 Ginteger(&keywin->udv_value, ge->winid);
1375 /* Always honor keys set with "bind all" */
1376 if (ptr->allwindows && ptr->command) {
1378 load_mouse_variables(x, y, FALSE, c);
1380 /* FIXME - Better to clear MOUSE_[XY] than to set it wrongly. */
1381 /* This may be worth a separate subroutine. */
1382 load_mouse_variables(0, 0, FALSE, c);
1383 do_string(ptr->command);
1384 /* Treat as a current event after we return to x11.trm */
1385 ge->type = GE_keypress;
1387 /* But otherwise ignore inactive windows */
1388 } else if (!current) {
1390 /* Let user defined bindings overwrite the builtin bindings */
1391 } else if ((par2 & 1) == 0 && ptr->command) {
1392 do_string(ptr->command);
1394 } else if (ptr->builtin) {
1397 fprintf(stderr, "%s:%d protocol error\n", __FILE__, __LINE__);
1406 ChangeView(int x, int z)
1408 if (modifier_mask & Mod_Shift) {
1415 if (surface_rot_x < 0)
1417 if (surface_rot_x > 180)
1418 surface_rot_x = 180;
1422 if (surface_rot_z < 0)
1423 surface_rot_z += 360;
1424 if (surface_rot_z > 360)
1425 surface_rot_z -= 360;
1428 if (display_ipc_commands()) {
1429 fprintf(stderr, "changing view to %f, %f.\n", surface_rot_x, surface_rot_z);
1432 do_save_3dplot(first_3dplot, plot3d_num, 0 /* not quick */ );
1435 /* 2D plot, or suitably aligned 3D plot: update statusline */
1436 if (!term->put_tmptext)
1438 recalc_statusline();
1444 event_buttonpress(struct gp_event_t *ge)
1456 FPRINTF((stderr, "(event_buttonpress) mouse_x = %d\tmouse_y = %d\n", mouse_x, mouse_y));
1458 MousePosToGraphPosReal(mouse_x, mouse_y, &real_x, &real_y, &real_x2, &real_y2);
1461 if (!setting_zoom_region) {
1463 /* not bound in 2d graphs */
1464 } else if (2 == b) {
1465 /* not bound in 2d graphs */
1466 } else if (3 == b && !replot_disabled && !(paused_for_mouse & PAUSE_BUTTON3)) {
1467 /* start zoom; but ignore it when
1468 * - replot is disabled, e.g. with inline data, or
1469 * - during 'pause mouse'
1470 * allow zooming during 'pause mouse key' */
1471 setting_zoom_x = mouse_x;
1472 setting_zoom_y = mouse_y;
1473 setting_zoom_region = TRUE;
1474 if (term->set_cursor) {
1475 int mv_mouse_x, mv_mouse_y;
1476 if (mouse_setting.annotate_zoom_box && term->put_tmptext) {
1477 double real_x, real_y, real_x2, real_y2;
1479 /* tell driver annotations */
1480 MousePosToGraphPosReal(mouse_x, mouse_y, &real_x, &real_y, &real_x2, &real_y2);
1481 sprintf(s, zoombox_format(), real_x, real_y);
1482 term->put_tmptext(1, s);
1483 term->put_tmptext(2, s);
1485 /* displace mouse in order not to start with an empty zoom box */
1486 mv_mouse_x = term->xmax / 20;
1487 mv_mouse_y = (term->xmax == term->ymax) ? mv_mouse_x : (int) ((mv_mouse_x * (double) term->ymax) / term->xmax);
1488 mv_mouse_x += mouse_x;
1489 mv_mouse_y += mouse_y;
1491 /* change cursor type */
1492 term->set_cursor(3, 0, 0);
1495 if (mouse_setting.warp_pointer)
1496 term->set_cursor(-2, mv_mouse_x, mv_mouse_y);
1498 /* turn on the zoom box */
1499 term->set_cursor(-1, setting_zoom_x, setting_zoom_y);
1501 if (display_ipc_commands()) {
1502 fprintf(stderr, "starting zoom region.\n");
1507 /* complete zoom (any button
1508 * finishes zooming.) */
1510 /* the following variables are used to check,
1511 * if the box is big enough to be considered
1513 int dist_x = setting_zoom_x - mouse_x;
1514 int dist_y = setting_zoom_y - mouse_y;
1515 int dist = sqrt((double)(dist_x * dist_x + dist_y * dist_y));
1517 if (1 == b || 2 == b) {
1518 /* zoom region is finished by the `wrong' button.
1519 * `trap' the next button-release event so that
1520 * it won't trigger the actions which are bound
1523 trap_release = TRUE;
1526 if (term->set_cursor) {
1527 term->set_cursor(0, 0, 0);
1528 if (mouse_setting.annotate_zoom_box && term->put_tmptext) {
1529 term->put_tmptext(1, "");
1530 term->put_tmptext(2, "");
1534 if (dist > 10 /* more ore less arbitrary */ ) {
1536 double xmin, ymin, x2min, y2min;
1537 double xmax, ymax, x2max, y2max;
1539 MousePosToGraphPosReal(setting_zoom_x, setting_zoom_y, &xmin, &ymin, &x2min, &y2min);
1544 /* keep the axes (no)reversed as they are now */
1545 #define sgn(x) (x==0 ? 0 : (x>0 ? 1 : -1))
1546 #define rev(a1,a2,A) if (sgn(a2-a1) != sgn(axis_array[A].max-axis_array[A].min)) \
1547 { double tmp = a1; a1 = a2; a2 = tmp; }
1548 rev(xmin, xmax, FIRST_X_AXIS);
1549 rev(ymin, ymax, FIRST_Y_AXIS);
1550 rev(x2min, x2max, SECOND_X_AXIS);
1551 rev(y2min, y2max, SECOND_Y_AXIS);
1554 do_zoom(xmin, ymin, x2min, y2min, xmax, ymax, x2max, y2max);
1555 if (display_ipc_commands()) {
1556 fprintf(stderr, "zoom region finished.\n");
1559 /* silently ignore a tiny zoom box. This might
1560 * happen, if the user starts and finishes the
1561 * zoom box at the same position. */
1563 setting_zoom_region = FALSE;
1566 if (term->set_cursor) {
1567 if (button & (1 << 1))
1568 term->set_cursor(1, 0, 0);
1569 else if (button & (1 << 2))
1570 term->set_cursor(2, 0, 0);
1575 zero_rot_z = surface_rot_z + 360.0 * mouse_x / term->xmax;
1576 zero_rot_x = surface_rot_x - 180.0 * mouse_y / term->ymax;
1581 event_buttonrelease(struct gp_event_t *ge)
1588 doubleclick = ge->par2;
1590 button &= ~(1 << b); /* remove button */
1592 if (setting_zoom_region) {
1595 if (TRUE == trap_release) {
1596 trap_release = FALSE;
1600 MousePosToGraphPosReal(mouse_x, mouse_y, &real_x, &real_y, &real_x2, &real_y2);
1602 FPRINTF((stderr, "MOUSE.C: doublclick=%i, set=%i, motion=%i, ALMOST2D=%i\n", (int) doubleclick, (int) mouse_setting.doubleclick,
1603 (int) motion, (int) ALMOST2D));
1607 if (b == 1 && term->set_clipboard && ((doubleclick <= mouse_setting.doubleclick)
1608 || !mouse_setting.doubleclick)) {
1610 /* put coordinates to clipboard. For 3d plots this takes
1611 * only place, if the user didn't drag (rotate) the plot */
1613 if (!is_3d_plot || !motion) {
1614 GetAnnotateString(s0, real_x, real_y, clipboard_mode, clipboard_alt_string);
1615 term->set_clipboard(s0);
1616 if (display_ipc_commands()) {
1617 fprintf(stderr, "put `%s' to clipboard.\n", s0);
1623 /* draw temporary annotation or label. For 3d plots this takes
1624 * only place, if the user didn't drag (scale) the plot */
1626 if (!is_3d_plot || !motion) {
1628 GetAnnotateString(s0, real_x, real_y, mouse_mode, mouse_alt_string);
1629 if (mouse_setting.label) {
1630 if (modifier_mask & Mod_Ctrl) {
1631 remove_label(mouse_x, mouse_y);
1633 put_label(s0, real_x, real_y);
1641 (term->linewidth) (border_lp.l_width);
1642 (term->linetype) (border_lp.l_type);
1643 (term->move) (x - dx, y);
1644 (term->vector) (x + dx, y);
1645 (term->move) (x, y - dy);
1646 (term->vector) (x, y + dy);
1647 (term->justify_text) (LEFT);
1648 (term->put_text) (x + dx / 2, y + dy / 2 + term->v_char / 3, s0);
1654 if (is_3d_plot && (b == 1 || b == 2)) {
1655 if (!!(modifier_mask & Mod_Ctrl) && !needreplot) {
1656 /* redraw the 3d plot if its last redraw was 'quick'
1657 * (only axes) because modifier key was pressed */
1658 do_save_3dplot(first_3dplot, plot3d_num, 0);
1660 if (term->set_cursor)
1661 term->set_cursor(0, 0, 0);
1664 /* Export current mouse coords to user-accessible variables also */
1665 load_mouse_variables(mouse_x, mouse_y, TRUE, b);
1669 if (paused_for_mouse & PAUSE_CLICK) {
1670 /* remove pause message box after 'pause mouse' */
1671 paused_for_mouse = 0;
1672 kill_pending_Pause_dialog();
1678 event_motion(struct gp_event_t *ge)
1686 && (splot_map == FALSE) /* Rotate the surface if it is 3D graph but not "set view map". */
1689 TBOOLEAN redraw = FALSE;
1691 if (button & (1 << 1)) {
1692 /* dragging with button 1 -> rotate */
1693 #if 0 /* HBB 20001109: what's rint()? */
1694 surface_rot_x = rint(zero_rot_x + 180.0 * mouse_y / term->ymax);
1696 surface_rot_x = floor(0.5 + zero_rot_x + 180.0 * mouse_y / term->ymax);
1698 if (surface_rot_x < 0)
1700 if (surface_rot_x > 180)
1701 surface_rot_x = 180;
1702 #if 0 /* HBB 20001109: what's rint()? */
1703 surface_rot_z = rint(fmod(zero_rot_z - 360.0 * mouse_x / term->xmax, 360));
1705 surface_rot_z = floor(0.5 + fmod(zero_rot_z - 360.0 * mouse_x / term->xmax, 360));
1707 if (surface_rot_z < 0)
1708 surface_rot_z += 360;
1710 } else if (button & (1 << 2)) {
1711 /* dragging with button 2 -> scale or changing ticslevel.
1712 * we compare the movement in x and y direction, and
1713 * change either scale or zscale */
1715 relx = fabs(mouse_x - start_x) / term->h_tic;
1716 rely = fabs(mouse_y - start_y) / term->v_tic;
1719 /* threshold: motion should be at least 3 pixels.
1720 * We've to experiment with this. */
1721 if (relx < 3 && rely < 3)
1724 if (modifier_mask & Mod_Shift) {
1725 xyplane.ticslevel += (1 + fabs(xyplane.ticslevel))
1726 * (mouse_y - start_y) * 2.0 / term->ymax;
1730 surface_scale += (mouse_x - start_x) * 2.0 / term->xmax;
1731 if (surface_scale < 0)
1734 if (disable_mouse_z && (mouse_y-start_y > 0))
1737 surface_zscale += (mouse_y - start_y) * 2.0 / term->ymax;
1738 disable_mouse_z = FALSE;
1740 if (surface_zscale < 0)
1744 /* reset the start values */
1748 } /* if (mousebutton 2 is down) */
1756 /* is processing of motions allowed right now?
1758 * disabling further replots until it completes */
1759 allowmotion = FALSE;
1760 do_save_3dplot(first_3dplot, plot3d_num, !!(modifier_mask & Mod_Ctrl));
1762 /* postpone the replotting */
1766 } /* if (3D plot) */
1770 /* 2D plot, or suitably aligned 3D plot: update
1771 * statusline and possibly the zoombox annotation */
1772 if (!term->put_tmptext)
1774 MousePosToGraphPosReal(mouse_x, mouse_y, &real_x, &real_y, &real_x2, &real_y2);
1777 if (setting_zoom_region && mouse_setting.annotate_zoom_box) {
1778 double real_x, real_y, real_x2, real_y2;
1780 MousePosToGraphPosReal(mouse_x, mouse_y, &real_x, &real_y, &real_x2, &real_y2);
1781 sprintf(s, zoombox_format(), real_x, real_y);
1782 term->put_tmptext(2, s);
1789 event_modifier(struct gp_event_t *ge)
1791 modifier_mask = ge->par1;
1793 if (modifier_mask == 0 && is_3d_plot && (button & ((1 << 1) | (1 << 2))) && !needreplot) {
1794 /* redraw the 3d plot if modifier key released */
1795 do_save_3dplot(first_3dplot, plot3d_num, 0);
1805 do_save_3dplot(first_3dplot, plot3d_num, !!(modifier_mask & Mod_Ctrl));
1813 event_reset(struct gp_event_t *ge)
1817 builtin_cancel_zoom(ge);
1818 if (term && term->set_cursor) {
1819 term->set_cursor(0, 0, 0);
1820 if (mouse_setting.annotate_zoom_box && term->put_tmptext) {
1821 term->put_tmptext(1, "");
1822 term->put_tmptext(2, "");
1826 if (paused_for_mouse) {
1827 paused_for_mouse = 0;
1829 /* remove pause message box after 'pause mouse' */
1830 kill_pending_Pause_dialog();
1832 /* This hack is necessary on some systems in order to prevent one */
1833 /* character of input from being swallowed when the plot window is */
1834 /* closed. But which systems, exactly? */
1835 if (term && (!strncmp("x11",term->name,3) || !strncmp("wxt",term->name,3)))
1841 do_event(struct gp_event_t *ge)
1846 if (multiplot && ge->type != GE_fontprops)
1847 /* only informational event processing for multiplot */
1850 /* disable `replot` when some data were sent through stdin */
1851 replot_disabled = plotted_data_from_stdin;
1854 FPRINTF((stderr, "(do_event) type = %d\n", ge->type));
1855 FPRINTF((stderr, " mx, my = %d, %d\n", ge->mx, ge->my));
1856 FPRINTF((stderr, " par1, par2 = %d, %d\n", ge->par1, ge->par2));
1864 event_keypress(ge, TRUE);
1866 case GE_keypress_old:
1867 event_keypress(ge, FALSE);
1873 if (!mouse_setting.on)
1877 case GE_buttonpress:
1878 if (!mouse_setting.on)
1880 event_buttonpress(ge);
1882 case GE_buttonrelease:
1883 if (!mouse_setting.on)
1885 event_buttonrelease(ge);
1888 /* used only by ggi.trm */
1889 do_string("replot");
1895 term->h_char = ge->par1;
1896 term->v_char = ge->par2;
1897 /* Update aspect ratio based on current window size */
1898 term->v_tic = term->h_tic * (double)ge->mx / (double)ge->my;
1899 /* EAM FIXME - We could also update term->xmax and term->ymax here, */
1900 /* but the existing code doesn't expect it to change. */
1901 FPRINTF((stderr, "mouse do_event: window size %d X %d, font hchar %d vchar %d\n",
1902 ge->mx, ge->my, ge->par1,ge->par2));
1905 fprintf(stderr, "%s:%d protocol error\n", __FILE__, __LINE__);
1909 replot_disabled = FALSE; /* enable replot again */
1913 do_save_3dplot(struct surface_points *plots, int pcount, int quick)
1915 #define M_TEST_AXIS(A) \
1916 (A.log && ((!(A.set_autoscale & AUTOSCALE_MIN) && A.set_min <= 0) || \
1917 (!(A.set_autoscale & AUTOSCALE_MAX) && A.set_max <= 0)))
1920 /* this might happen after the `reset' command for example
1921 * which was reported by Franz Bakan. replotrequest()
1922 * should set up again everything. */
1925 if (M_TEST_AXIS(X_AXIS) || M_TEST_AXIS(Y_AXIS) || M_TEST_AXIS(Z_AXIS)
1926 || M_TEST_AXIS(CB_AXIS)
1928 graph_error("axis ranges must be above 0 for log scale!");
1931 do_3dplot(plots, pcount, quick);
1939 * bind related functions
1943 bind_install_default_bindings()
1946 bind_append("a", (char *) 0, builtin_autoscale);
1947 bind_append("b", (char *) 0, builtin_toggle_border);
1948 bind_append("e", (char *) 0, builtin_replot);
1949 bind_append("g", (char *) 0, builtin_toggle_grid);
1950 bind_append("h", (char *) 0, builtin_help);
1951 bind_append("l", (char *) 0, builtin_toggle_log);
1952 bind_append("L", (char *) 0, builtin_nearest_log);
1953 bind_append("m", (char *) 0, builtin_toggle_mouse);
1954 bind_append("r", (char *) 0, builtin_toggle_ruler);
1955 bind_append("1", (char *) 0, builtin_decrement_mousemode);
1956 bind_append("2", (char *) 0, builtin_increment_mousemode);
1957 bind_append("3", (char *) 0, builtin_decrement_clipboardmode);
1958 bind_append("4", (char *) 0, builtin_increment_clipboardmode);
1959 bind_append("5", (char *) 0, builtin_toggle_polardistance);
1960 bind_append("6", (char *) 0, builtin_toggle_verbose);
1961 bind_append("7", (char *) 0, builtin_toggle_ratio);
1962 bind_append("n", (char *) 0, builtin_zoom_next);
1963 bind_append("p", (char *) 0, builtin_zoom_previous);
1964 bind_append("u", (char *) 0, builtin_unzoom);
1965 bind_append("Right", (char *) 0, builtin_rotate_right);
1966 bind_append("Up", (char *) 0, builtin_rotate_up);
1967 bind_append("Left", (char *) 0, builtin_rotate_left);
1968 bind_append("Down", (char *) 0, builtin_rotate_down);
1969 bind_append("Escape", (char *) 0, builtin_cancel_zoom);
1973 bind_clear(bind_t * b)
1977 b->command = (char *) 0;
1979 b->prev = (struct bind_t *) 0;
1980 b->next = (struct bind_t *) 0;
1983 /* returns the enum which corresponds to the
1984 * string (ptr) or NO_KEY if ptr matches not
1985 * any of special_keys. */
1987 lookup_key(char *ptr, int *len)
1990 /* first, search in the table of "usual well-known" keys */
1991 int what = lookup_table_nth(usual_special_keys, ptr);
1993 *len = strlen(usual_special_keys[what].key);
1994 return usual_special_keys[what].value;
1996 /* second, search in the table of other keys */
1997 for (keyptr = special_keys; *keyptr; ++keyptr) {
1998 if (!strcmp(ptr, *keyptr)) {
2000 return keyptr - special_keys + GP_FIRST_KEY;
2006 /* returns 1 on success, else 0. */
2008 bind_scan_lhs(bind_t * out, const char *in)
2010 static const char DELIM = '-';
2018 for (ptr = (char *) in; ptr && *ptr; /* EMPTY */ ) {
2019 if (!strncasecmp(ptr, "alt-", 4)) {
2020 out->modifier |= Mod_Alt;
2022 } else if (!strncasecmp(ptr, "ctrl-", 5)) {
2023 out->modifier |= Mod_Ctrl;
2025 } else if (NO_KEY != (itmp = lookup_key(ptr, &len))) {
2028 } else if ((out->key = *ptr++) && *ptr && *ptr != DELIM) {
2029 fprintf(stderr, "bind: cannot parse %s\n", in);
2033 if (NO_KEY == out->key)
2034 return 0; /* failed */
2036 return 1; /* success */
2039 /* note, that this returns a pointer
2040 * to the static char* `out' which is
2041 * modified on subsequent calls.
2044 bind_fmt_lhs(const bind_t * in)
2046 static char out[0x40];
2047 out[0] = '\0'; /* empty string */
2050 if (in->modifier & Mod_Ctrl) {
2051 sprintf(out, "Ctrl-");
2053 if (in->modifier & Mod_Alt) {
2054 sprintf(out, "%sAlt-", out);
2056 if (in->key > GP_FIRST_KEY && in->key < GP_LAST_KEY) {
2057 sprintf(out, "%s%s", out, special_keys[in->key - GP_FIRST_KEY]);
2060 for ( ; usual_special_keys[k].value > 0; k++) {
2061 if (usual_special_keys[k].value == in->key) {
2062 sprintf(out, "%s%s", out, usual_special_keys[k].key);
2068 sprintf(out, "%s%c", out, in->key);
2074 bind_matches(const bind_t * a, const bind_t * b)
2076 /* discard Shift modifier */
2077 int a_mod = a->modifier & (Mod_Ctrl | Mod_Alt);
2078 int b_mod = b->modifier & (Mod_Ctrl | Mod_Alt);
2080 if (a->key == b->key && a_mod == b_mod)
2087 bind_display_one(bind_t * ptr)
2089 fprintf(stderr, " %-12s ", bind_fmt_lhs(ptr));
2090 fprintf(stderr, "%c ", ptr->allwindows ? '*' : ' ');
2092 fprintf(stderr, "`%s'\n", ptr->command);
2093 } else if (ptr->builtin) {
2094 fprintf(stderr, "%s\n", ptr->builtin(0));
2096 fprintf(stderr, "`%s:%d oops.'\n", __FILE__, __LINE__);
2101 bind_display(char *lhs)
2107 bind_install_default_bindings();
2111 /* display all bindings */
2112 char fmt[] = " %-17s %s\n";
2113 fprintf(stderr, "\n");
2114 fprintf(stderr, fmt, "2x<B1>",
2115 "print coordinates to clipboard using `clipboardformat`\n (see keys '3', '4')");
2116 fprintf(stderr, fmt, "<B2>", "annotate the graph using `mouseformat` (see keys '1', '2')");
2117 fprintf(stderr, fmt, "", "or draw labels if `set mouse labels is on`");
2118 fprintf(stderr, fmt, "<Ctrl-B2>", "remove label close to pointer if `set mouse labels` is on");
2119 fprintf(stderr, fmt, "<B3>", "mark zoom region (only for 2d-plots and maps).");
2120 fprintf(stderr, fmt, "<B1-Motion>", "change view (rotation). Use <ctrl> to rotate the axes only.");
2121 fprintf(stderr, fmt, "<B2-Motion>", "change view (scaling). Use <ctrl> to scale the axes only.");
2122 fprintf(stderr, fmt, "<Shift-B2-Motion>", "vertical motion -- change xyplane");
2123 fprintf(stderr, "\n");
2124 fprintf(stderr, " %-12s %s\n", "Space", "raise gnuplot console window");
2125 fprintf(stderr, " %-12s * %s\n", "q", "close this X11 plot window");
2126 fprintf(stderr, "\n");
2127 for (ptr = bindings; ptr; ptr = ptr->next) {
2128 bind_display_one(ptr);
2130 fprintf(stderr, "\n");
2131 fprintf(stderr, " * indicates this key is active from all plot windows\n");
2132 fprintf(stderr, "\n");
2136 if (!bind_scan_lhs(&lhs_scanned, lhs)) {
2139 for (ptr = bindings; ptr; ptr = ptr->next) {
2140 if (bind_matches(&lhs_scanned, ptr)) {
2141 bind_display_one(ptr);
2142 break; /* only one match */
2148 bind_remove(bind_t * b)
2152 } else if (b->builtin) {
2153 /* don't remove builtins, just remove the overriding command */
2156 b->command = (char *) 0;
2161 b->prev->next = b->next;
2163 b->next->prev = b->prev;
2165 bindings->prev = b->prev;
2168 b->command = (char *) 0;
2170 if (b == bindings) {
2172 if (bindings && bindings->prev) {
2173 bindings->prev->next = (bind_t *) 0;
2180 bind_append(char *lhs, char *rhs, char *(*builtin) (struct gp_event_t * ge))
2182 bind_t *new = (bind_t *) gp_alloc(sizeof(bind_t), "bind_append->new");
2184 if (!bind_scan_lhs(new, lhs)) {
2195 for (ptr = bindings; ptr; ptr = ptr->next) {
2196 if (bind_matches(new, ptr)) {
2197 /* overwriting existing binding */
2199 ptr->builtin = builtin;
2203 ptr->command = (char *) 0;
2206 } else { /* rhs is an empty string, so remove the binding */
2209 free(new); /* don't need it any more */
2213 /* if we're here, the binding does not exist yet */
2214 /* append binding ... */
2215 bindings->prev->next = new;
2216 new->prev = bindings->prev;
2219 bindings->prev = new;
2220 new->next = (struct bind_t *) 0;
2221 new->allwindows = FALSE; /* Can be explicitly set later */
2223 new->builtin = builtin;
2225 new->command = rhs; /* was allocated in command.c */
2232 bind_process(char *lhs, char *rhs, TBOOLEAN allwindows)
2235 bind_install_default_bindings();
2240 bind_append(lhs, rhs, 0);
2254 if (!bind_scan_lhs(&keypress, lhs))
2257 for (ptr = bindings; ptr; ptr = ptr->next) {
2258 if (bind_matches(&keypress, ptr))
2259 ptr->allwindows = TRUE;
2268 for (ptr = bindings; ptr; safe = ptr, ptr = ptr->next, free(safe)) {
2271 ptr->command = (char *) 0;
2274 bindings = (bind_t *) 0;
2277 /* Ruler is on, thus recalc its (px,py) from (x,y) for the current zoom and
2285 /* To be exact, it is 'set view map' splot. */
2286 unsigned int ppx, ppy;
2287 dummy = 1.0; /* dummy value, but not 0.0 for the fear of log z-axis */
2288 map3d_xy(ruler.x, ruler.y, dummy, &ppx, &ppy);
2293 /* It is 2D plot. */
2294 if (axis_array[FIRST_X_AXIS].log && ruler.x < 0)
2297 P = AXIS_LOG_VALUE(FIRST_X_AXIS, ruler.x);
2298 ruler.px = AXIS_MAP(FIRST_X_AXIS, P);
2300 if (axis_array[FIRST_Y_AXIS].log && ruler.y < 0)
2303 P = AXIS_LOG_VALUE(FIRST_Y_AXIS, ruler.y);
2304 ruler.py = AXIS_MAP(FIRST_Y_AXIS, P);
2306 MousePosToGraphPosReal(ruler.px, ruler.py, &dummy, &dummy, &ruler.x2, &ruler.y2);
2310 /* Recalculate and replot the ruler after a '(re)plot'. Called from term.c.
2315 if (!term->set_ruler || !ruler.on)
2317 (*term->set_ruler) (-1, -1);
2319 (*term->set_ruler) (ruler.px, ruler.py);
2322 /* Set ruler on/off, and set its position.
2323 Called from set.c for 'set mouse ruler ...' command.
2326 set_ruler(TBOOLEAN on, int mx, int my)
2328 struct gp_event_t ge;
2329 if (ruler.on == FALSE && on == FALSE)
2331 if (ruler.on == TRUE && on == TRUE && (mx < 0 || my < 0))
2333 if (ruler.on == TRUE) /* ruler is on => switch it off */
2334 builtin_toggle_ruler(&ge);
2335 /* now the ruler is off */
2336 if (on == FALSE) /* want ruler off */
2338 if (mx>=0 && my>=0) { /* change ruler position */
2341 } else { /* don't change ruler position */
2345 builtin_toggle_ruler(&ge);
2348 /* for checking if we change from plot to splot (or vice versa) */
2352 static int mode = MODE_PLOT;
2353 if (MODE_PLOT == set || MODE_SPLOT == set) {
2366 struct udvt_entry *u;
2368 if (term && term->set_ruler) {
2369 (*term->set_ruler) (-1, -1);
2371 if ((u = add_udv_by_name("MOUSE_RULER_X")))
2372 u->udv_undef = TRUE;
2373 if ((u = add_udv_by_name("MOUSE_RULER_Y")))
2374 u->udv_undef = TRUE;
2375 if (display_ipc_commands()) {
2376 fprintf(stderr, "turning ruler off.\n");
2382 nearest_label_tag(int xref, int yref, struct termentry *t)
2386 double diff_squared;
2388 struct text_label *this_label;
2392 for (this_label = first_label; this_label != NULL; this_label = this_label->next) {
2394 map3d_position(&this_label->place, &xd, &yd, "label");
2398 map_position(&this_label->place, &x, &y, "label");
2402 diff_squared = xd * xd + yd * yd;
2403 if (-1 == min || min > diff_squared) {
2404 /* now we check if we're within a certain
2405 * threshold around the label */
2406 double tic_diff_squared;
2408 get_offsets(this_label, t, &htic, &vtic);
2409 tic_diff_squared = htic * htic + vtic * vtic;
2410 if (diff_squared < tic_diff_squared) {
2412 min_tag = this_label->tag;
2421 remove_label(int x, int y)
2423 int tag = nearest_label_tag(x, y, term);
2426 sprintf(cmd, "unset label %d", tag);
2427 do_string_replot(cmd);
2432 put_label(char *label, double x, double y)
2435 sprintf(cmd, "set label \"%s\" at %g,%g %s", label, x, y, mouse_setting.labelopts);
2436 do_string_replot(cmd);
2440 /* routine required by pm.trm: fill in information needed for (un)checking
2441 menu items in the Presentation Manager terminal
2444 PM_set_gpPMmenu __PROTO((struct t_gpPMmenu * gpPMmenu))
2446 gpPMmenu->use_mouse = mouse_setting.on;
2447 if (zoom_now == NULL)
2448 gpPMmenu->where_zoom_queue = 0;
2450 gpPMmenu->where_zoom_queue = (zoom_now == zoom_head) ? 0 : 1;
2451 if (zoom_now->prev != NULL)
2452 gpPMmenu->where_zoom_queue |= 2;
2453 if (zoom_now->next != NULL)
2454 gpPMmenu->where_zoom_queue |= 4;
2456 gpPMmenu->polar_distance = mouse_setting.polardistance;
2460 /* Save current mouse position to user-accessible variables.
2461 * Save the keypress or mouse button that triggered this in MOUSE_KEY,
2462 * and define MOUSE_BUTTON if it was a button click.
2465 load_mouse_variables(double x, double y, TBOOLEAN button, int c)
2467 struct udvt_entry *current;
2469 MousePosToGraphPosReal(x, y, &real_x, &real_y, &real_x2, &real_y2);
2471 if ((current = add_udv_by_name("MOUSE_BUTTON"))) {
2472 current->udv_undef = !button;
2473 Ginteger(¤t->udv_value, button?c:-1);
2475 if ((current = add_udv_by_name("MOUSE_KEY"))) {
2476 current->udv_undef = FALSE;
2477 Ginteger(¤t->udv_value,c);
2479 #ifdef GP_STRING_VARS
2480 if ((current = add_udv_by_name("MOUSE_CHAR"))) {
2481 char *keychar = gp_alloc(2,"key_char");
2484 if (!current->udv_undef)
2485 gpfree_string(¤t->udv_value);
2486 current->udv_undef = FALSE;
2487 Gstring(¤t->udv_value,keychar);
2491 if ((current = add_udv_by_name("MOUSE_X"))) {
2492 current->udv_undef = FALSE;
2493 Gcomplex(¤t->udv_value,real_x,0);
2495 if ((current = add_udv_by_name("MOUSE_Y"))) {
2496 current->udv_undef = FALSE;
2497 Gcomplex(¤t->udv_value,real_y,0);
2499 if ((current = add_udv_by_name("MOUSE_X2"))) {
2500 current->udv_undef = FALSE;
2501 Gcomplex(¤t->udv_value,real_x2,0);
2503 if ((current = add_udv_by_name("MOUSE_Y2"))) {
2504 current->udv_undef = FALSE;
2505 Gcomplex(¤t->udv_value,real_y2,0);
2507 if ((current = add_udv_by_name("MOUSE_SHIFT"))) {
2508 current->udv_undef = FALSE;
2509 Ginteger(¤t->udv_value, modifier_mask & Mod_Shift);
2511 if ((current = add_udv_by_name("MOUSE_ALT"))) {
2512 current->udv_undef = FALSE;
2513 Ginteger(¤t->udv_value, modifier_mask & Mod_Alt);
2515 if ((current = add_udv_by_name("MOUSE_CTRL"))) {
2516 current->udv_undef = FALSE;
2517 Ginteger(¤t->udv_value, modifier_mask & Mod_Ctrl);
2522 #endif /* USE_MOUSE */