3 Copyright 1989, 1994, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 * Author: Jim Fulton, MIT X Consortium
33 #include <X11/IntrinsicP.h>
34 #include <X11/StringDefs.h>
36 #include <X11/Xmu/CharSet.h>
37 #include <X11/Xmu/Drawing.h>
38 #include <X11/Xmu/Misc.h>
39 #include <X11/Xaw/PannerP.h>
40 #include <X11/Xaw/XawInit.h>
43 #if defined(ISC) && __STDC__ && !defined(ISC30)
44 extern double atof(char *);
46 #include <stdlib.h> /* for atof() */
52 static void XawPannerDestroy(Widget);
53 static void XawPannerInitialize(Widget, Widget, ArgList, Cardinal*);
54 static XtGeometryResult XawPannerQueryGeometry(Widget, XtWidgetGeometry*,
56 static void XawPannerRealize(Widget, XtValueMask*, XSetWindowAttributes*);
57 static void XawPannerRedisplay(Widget, XEvent*, Region);
58 static void XawPannerResize(Widget);
59 static Boolean XawPannerSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
60 static void XawPannerSetValuesAlmost(Widget, Widget, XtWidgetGeometry*,
66 static void check_knob(PannerWidget, Bool);
67 static void get_default_size(PannerWidget, Dimension*, Dimension*);
68 static Bool get_event_xy(PannerWidget, XEvent*, int*, int*);
69 static void move_shadow(PannerWidget);
70 static int parse_page_string(char*, int, int, Bool*);
71 static void rescale(PannerWidget);
72 static void reset_shadow_gc(PannerWidget);
73 static void reset_slider_gc(PannerWidget);
74 static void reset_xor_gc(PannerWidget);
75 static void scale_knob(PannerWidget, Bool, Bool);
80 static void ActionAbort(Widget, XEvent*, String*, Cardinal*);
81 static void ActionMove(Widget, XEvent*, String*, Cardinal*);
82 static void ActionNotify(Widget, XEvent*, String*, Cardinal*);
83 static void ActionPage(Widget, XEvent*, String*, Cardinal*);
84 static void ActionSet(Widget, XEvent*, String*, Cardinal*);
85 static void ActionStart(Widget, XEvent*, String*, Cardinal*);
86 static void ActionStop(Widget, XEvent*, String*, Cardinal*);
91 Bool XmuDistinguishablePixels(Display*, Colormap, unsigned long*, int);
96 static char defaultTranslations[] =
97 "<Btn1Down>:" "start()\n"
98 "<Btn1Motion>:" "move()\n"
99 "<Btn1Up>:" "notify() stop()\n"
100 "<Btn2Down>:" "abort()\n"
101 ":<Key>KP_Enter:" "set(rubberband,toggle)\n"
102 "<Key>space:" "page(+1p,+1p)\n"
103 "<Key>Delete:" "page(-1p,-1p)\n"
104 ":<Key>KP_Delete:" "page(-1p,-1p)\n"
105 "<Key>BackSpace:" "page(-1p,-1p)\n"
106 "<Key>Left:" "page(-.5p,+0)\n"
107 ":<Key>KP_Left:" "page(-.5p,+0)\n"
108 "<Key>Right:" "page(+.5p,+0)\n"
109 ":<Key>KP_Right:" "page(+.5p,+0)\n"
110 "<Key>Up:" "page(+0,-.5p)\n"
111 ":<Key>KP_Up:" "page(+0,-.5p)\n"
112 "<Key>Down:" "page(+0,+.5p)\n"
113 ":<Key>KP_Down:" "page(+0,+.5p)\n"
114 "<Key>Home:" "page(0,0)\n"
115 ":<Key>KP_Home:" "page(0,0)\n"
118 static XtActionsRec actions[] = {
119 {"start", ActionStart}, /* start tmp graphics */
120 {"stop", ActionStop}, /* stop tmp graphics */
121 {"abort", ActionAbort}, /* punt */
122 {"move", ActionMove}, /* move tmp graphics on Motion event */
123 {"page", ActionPage}, /* page around usually from keyboard */
124 {"notify", ActionNotify}, /* callback new position */
125 {"set", ActionSet}, /* set various parameters */
128 #define offset(field) XtOffsetOf(PannerRec, panner.field)
129 static XtResource resources[] = {
144 offset(resize_to_pref),
153 offset(report_callbacks),
162 offset(default_scale),
164 (XtPointer)PANNER_DEFAULT_SCALE
182 (XtPointer)XtDefaultBackground
189 offset(internal_border),
207 offset(canvas_width),
216 offset(canvas_height),
243 offset(slider_width),
252 offset(slider_height),
261 offset(shadow_color),
263 (XtPointer)XtDefaultForeground
270 offset(shadow_thickness),
275 XtNbackgroundStipple,
276 XtCBackgroundStipple,
279 offset(stipple_name),
286 #define Superclass (&simpleClassRec)
287 PannerClassRec pannerClassRec = {
290 (WidgetClass)Superclass, /* superclass */
291 "Panner", /* class_name */
292 sizeof(PannerRec), /* widget_size */
293 XawInitializeWidgetSet, /* class_initialize */
294 NULL, /* class_part_initialize */
295 False, /* class_inited */
296 XawPannerInitialize, /* initialize */
297 NULL, /* initialize_hook */
298 XawPannerRealize, /* realize */
299 actions, /* actions */
300 XtNumber(actions), /* num_actions */
301 resources, /* resources */
302 XtNumber(resources), /* num_resources */
303 NULLQUARK, /* xrm_class */
304 True, /* compress_motion */
305 True, /* compress_exposure */
306 True, /* compress_enterleave */
307 False, /* visible_interest */
308 XawPannerDestroy, /* destroy */
309 XawPannerResize, /* resize */
310 XawPannerRedisplay, /* expose */
311 XawPannerSetValues, /* set_values */
312 NULL, /* set_values_hook */
313 XawPannerSetValuesAlmost, /* set_values_almost */
314 NULL, /* get_values_hook */
315 NULL, /* accept_focus */
316 XtVersion, /* version */
317 NULL, /* callback_private */
318 defaultTranslations, /* tm_table */
319 XawPannerQueryGeometry, /* query_geometry */
320 XtInheritDisplayAccelerator, /* display_accelerator */
321 NULL, /* extension */
325 XtInheritChangeSensitive, /* change_sensitive */
329 NULL, /* extension */
333 WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
340 reset_shadow_gc(PannerWidget pw)
342 XtGCMask valuemask = GCForeground;
344 unsigned long pixels[3];
346 if (pw->panner.shadow_gc)
347 XtReleaseGC((Widget)pw, pw->panner.shadow_gc);
349 pixels[0] = pw->panner.foreground;
350 pixels[1] = pw->core.background_pixel;
351 pixels[2] = pw->panner.shadow_color;
353 if (!pw->panner.stipple_name &&
354 !XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
356 XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
358 valuemask = GCTile | GCFillStyle;
359 values.fill_style = FillTiled;
360 values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
361 pw->panner.foreground,
362 pw->core.background_pixel,
366 if (!pw->panner.line_width &&
367 !XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
369 pw->panner.line_width = 1;
370 valuemask = GCForeground;
371 values.foreground = pw->panner.shadow_color;
373 if (pw->panner.line_width > 0) {
374 values.line_width = pw->panner.line_width;
375 valuemask |= GCLineWidth;
378 pw->panner.shadow_gc = XtGetGC((Widget)pw, valuemask, &values);
382 reset_slider_gc(PannerWidget pw)
384 XtGCMask valuemask = GCForeground;
387 if (pw->panner.slider_gc)
388 XtReleaseGC((Widget)pw, pw->panner.slider_gc);
390 values.foreground = pw->panner.foreground;
392 pw->panner.slider_gc = XtGetGC((Widget)pw, valuemask, &values);
396 reset_xor_gc(PannerWidget pw)
398 if (pw->panner.xor_gc)
399 XtReleaseGC((Widget)pw, pw->panner.xor_gc);
401 if (pw->panner.rubber_band) {
402 XtGCMask valuemask = (GCForeground | GCFunction);
406 tmp = (pw->panner.foreground == pw->core.background_pixel ?
407 pw->panner.shadow_color : pw->panner.foreground);
408 values.foreground = tmp ^ pw->core.background_pixel;
409 values.function = GXxor;
410 if (pw->panner.line_width > 0) {
411 valuemask |= GCLineWidth;
412 values.line_width = pw->panner.line_width;
414 pw->panner.xor_gc = XtGetGC((Widget)pw, valuemask, &values);
417 pw->panner.xor_gc = NULL;
421 check_knob(PannerWidget pw, Bool knob)
423 Position pad = pw->panner.internal_border << 1;
424 Position maxx = (Position)XtWidth(pw) - pad -
425 (Position)pw->panner.knob_width;
426 Position maxy = (Position)XtHeight(pw) - pad -
427 (Position)pw->panner.knob_height;
428 Position *x = knob ? &pw->panner.knob_x : &pw->panner.tmp.x;
429 Position *y = knob ? &pw->panner.knob_y : &pw->panner.tmp.y;
432 * note that positions are already normalized (i.e. internal_border
433 * has been subtracted out)
446 pw->panner.slider_x = (Position)((double)pw->panner.knob_x
447 / pw->panner.haspect + 0.5);
448 pw->panner.slider_y = (Position)((double)pw->panner.knob_y
449 / pw->panner.vaspect + 0.5);
450 pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
455 move_shadow(PannerWidget pw)
457 if (pw->panner.shadow_thickness > 0) {
458 int lw = pw->panner.shadow_thickness + (pw->panner.line_width << 1);
459 int pad = pw->panner.internal_border;
461 if (pw->panner.knob_height > lw && pw->panner.knob_width > lw) {
462 XRectangle *r = pw->panner.shadow_rects;
464 r->x = pw->panner.knob_x + pad + pw->panner.knob_width;
465 r->y = pw->panner.knob_y + pad + lw;
466 r->width = pw->panner.shadow_thickness;
467 r->height = pw->panner.knob_height - lw;
469 r->x = pw->panner.knob_x + pad + lw;
470 r->y = pw->panner.knob_y + pad + pw->panner.knob_height;
471 r->width = pw->panner.knob_width - lw + pw->panner.shadow_thickness;
472 r->height = pw->panner.shadow_thickness;
473 pw->panner.shadow_valid = True;
477 pw->panner.shadow_valid = False;
481 scale_knob(PannerWidget pw, Bool location, Bool size)
484 pw->panner.knob_x = (Position)PANNER_HSCALE(pw, pw->panner.slider_x);
485 pw->panner.knob_y = (Position)PANNER_VSCALE(pw, pw->panner.slider_y);
488 Dimension width, height;
490 if (pw->panner.slider_width < 1)
491 pw->panner.slider_width = pw->panner.canvas_width;
492 if (pw->panner.slider_height < 1)
493 pw->panner.slider_height = pw->panner.canvas_height;
494 width = Min(pw->panner.slider_width, pw->panner.canvas_width);
495 height = Min(pw->panner.slider_height, pw->panner.canvas_height);
497 pw->panner.knob_width = (Dimension)PANNER_HSCALE(pw, width);
498 pw->panner.knob_height = (Dimension)PANNER_VSCALE(pw, height);
500 if (!pw->panner.allow_off)
501 check_knob(pw, True);
506 rescale(PannerWidget pw)
508 int hpad = pw->panner.internal_border << 1;
511 if (pw->panner.canvas_width < 1)
512 pw->panner.canvas_width = XtWidth(pw);
513 if (pw->panner.canvas_height < 1)
514 pw->panner.canvas_height = XtHeight(pw);
516 if (XtWidth(pw) <= hpad)
518 if (XtHeight(pw) <= vpad)
521 pw->panner.haspect = ((double)XtWidth(pw) - hpad + .5)
522 / (double)pw->panner.canvas_width;
523 pw->panner.vaspect = ((double)XtHeight(pw) - vpad + .5)
524 / (double)pw->panner.canvas_height;
525 scale_knob(pw, True, True);
529 get_default_size(PannerWidget pw, Dimension *wp, Dimension *hp)
531 Dimension pad = pw->panner.internal_border << 1;
533 *wp = PANNER_DSCALE(pw, pw->panner.canvas_width) + pad;
534 *hp = PANNER_DSCALE(pw, pw->panner.canvas_height) + pad;
538 get_event_xy(PannerWidget pw, XEvent *event, int *x, int *y)
540 int pad = pw->panner.internal_border;
542 switch (event->type) {
545 *x = event->xbutton.x - pad;
546 *y = event->xbutton.y - pad;
550 *x = event->xkey.x - pad;
551 *y = event->xkey.y - pad;
555 *x = event->xcrossing.x - pad;
556 *y = event->xcrossing.y - pad;
559 *x = event->xmotion.x - pad;
560 *y = event->xmotion.y - pad;
568 parse_page_string(char *s, int pagesize, int canvassize, Bool *relative)
575 * syntax: spaces [+-] number spaces [pc\0] spaces
577 for (; isascii(*s) && isspace(*s); s++) /* skip white space */
580 if (*s == '+' || *s == '-') { /* deal with signs */
586 if (!*s) { /* if null then return nothing */
591 /* skip over numbers */
592 for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++)
597 for (; isascii(*s) && isspace(*s); s++)
600 if (*s) { /* if units */
604 val *= (double)pagesize;
608 val *= (double)canvassize;
617 #define DRAW_TMP(pw) \
619 XDrawRectangle(XtDisplay(pw), XtWindow(pw), \
621 pw->panner.tmp.x + pw->panner.internal_border, \
622 pw->panner.tmp.y + pw->panner.internal_border, \
623 pw->panner.knob_width - 1, \
624 pw->panner.knob_height - 1); \
625 pw->panner.tmp.showing = !pw->panner.tmp.showing; \
628 #define UNDRAW_TMP(pw) \
630 if (pw->panner.tmp.showing) \
634 #define BACKGROUND_STIPPLE(pw) \
635 XmuLocatePixmapFile(pw->core.screen, pw->panner.stipple_name, \
636 pw->panner.shadow_color, pw->core.background_pixel, \
637 pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
639 #define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
643 XawPannerInitialize(Widget greq, Widget gnew, ArgList args, Cardinal *num_args)
645 PannerWidget req = (PannerWidget)greq, cnew = (PannerWidget)gnew;
646 Dimension defwidth, defheight;
648 if (req->panner.canvas_width < 1)
649 cnew->panner.canvas_width = 1;
650 if (req->panner.canvas_height < 1)
651 cnew->panner.canvas_height = 1;
652 if (req->panner.default_scale < 1)
653 cnew->panner.default_scale = PANNER_DEFAULT_SCALE;
655 get_default_size(req, &defwidth, &defheight);
656 if (XtWidth(req) < 1)
657 XtWidth(cnew) = defwidth;
658 if (XtHeight(req) < 1)
659 XtHeight(cnew) = defheight;
661 cnew->panner.shadow_gc = NULL;
662 reset_shadow_gc(cnew); /* shadowColor */
663 cnew->panner.slider_gc = NULL;
664 reset_slider_gc(cnew); /* foreground */
665 cnew->panner.xor_gc = NULL;
666 reset_xor_gc(cnew); /* foreground ^ background */
668 rescale(cnew); /* does a position check */
669 cnew->panner.shadow_valid = False;
670 cnew->panner.tmp.doing = False;
671 cnew->panner.tmp.showing = False;
675 XawPannerRealize(Widget gw, XtValueMask *valuemaskp,
676 XSetWindowAttributes *attr)
678 PannerWidget pw = (PannerWidget)gw;
679 Pixmap pm = XtUnspecifiedPixmap;
682 if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
683 if (pw->panner.stipple_name)
684 pm = BACKGROUND_STIPPLE(pw);
686 if (PIXMAP_OKAY(pm)) {
687 attr->background_pixmap = pm;
688 *valuemaskp |= CWBackPixmap;
689 *valuemaskp &= ~CWBackPixel;
693 (*pannerWidgetClass->core_class.superclass->core_class.realize)
694 (gw, valuemaskp, attr);
697 XFreePixmap(XtDisplay(gw), pm);
701 XawPannerDestroy(Widget gw)
703 PannerWidget pw = (PannerWidget)gw;
705 XtReleaseGC(gw, pw->panner.shadow_gc);
706 XtReleaseGC(gw, pw->panner.slider_gc);
707 XtReleaseGC(gw, pw->panner.xor_gc);
711 XawPannerResize(Widget gw)
713 rescale((PannerWidget)gw);
717 XawPannerRedisplay(Widget gw, XEvent *event, Region region)
719 PannerWidget pw = (PannerWidget)gw;
720 Display *dpy = XtDisplay(gw);
721 Window w = XtWindow(gw);
722 int pad = pw->panner.internal_border;
723 Dimension lw = pw->panner.line_width;
724 Dimension extra = pw->panner.shadow_thickness + (lw << 1);
725 int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
727 if (Superclass->core_class.expose)
728 (Superclass->core_class.expose)(gw, event, region);
730 pw->panner.tmp.showing = False;
731 XClearArea(XtDisplay(pw), XtWindow(pw),
732 (int)pw->panner.last_x - ((int)lw) + pad,
733 (int)pw->panner.last_y - ((int)lw) + pad,
734 pw->panner.knob_width + extra,
735 pw->panner.knob_height + extra,
737 pw->panner.last_x = pw->panner.knob_x;
738 pw->panner.last_y = pw->panner.knob_y;
740 XFillRectangle(dpy, w, pw->panner.slider_gc, kx, ky,
741 pw->panner.knob_width - 1, pw->panner.knob_height - 1);
744 XDrawRectangle(dpy, w, pw->panner.shadow_gc, kx, ky,
745 pw->panner.knob_width - 1, pw->panner.knob_height - 1);
747 if (pw->panner.shadow_valid)
748 XFillRectangles(dpy, w, pw->panner.shadow_gc, pw->panner.shadow_rects, 2);
750 if (pw->panner.tmp.doing && pw->panner.rubber_band)
756 XawPannerSetValues(Widget gcur, Widget greq, Widget gnew,
757 ArgList args, Cardinal *num_args)
759 PannerWidget cur = (PannerWidget)gcur;
760 PannerWidget cnew = (PannerWidget)gnew;
761 Bool redisplay = False;
763 if (cur->panner.foreground != cnew->panner.foreground) {
764 reset_slider_gc(cnew);
765 if (cur->panner.foreground != cur->core.background_pixel)
769 else if (cur->panner.line_width != cnew->panner.line_width ||
770 cur->core.background_pixel != cnew->core.background_pixel) {
774 if (cur->panner.shadow_color != cnew->panner.shadow_color) {
775 reset_shadow_gc(cnew);
776 if (cur->panner.foreground == cur->core.background_pixel)
780 if (cur->panner.shadow_thickness != cnew->panner.shadow_thickness) {
784 if (cur->panner.rubber_band != cnew->panner.rubber_band) {
786 if (cnew->panner.tmp.doing)
790 if ((cur->panner.stipple_name != cnew->panner.stipple_name
791 || cur->panner.shadow_color != cnew->panner.shadow_color
792 || cur->core.background_pixel != cnew->core.background_pixel)
793 && XtIsRealized(gnew)) {
794 Pixmap pm = cnew->panner.stipple_name ?
795 BACKGROUND_STIPPLE(cnew) : XtUnspecifiedPixmap;
797 if (PIXMAP_OKAY(pm)) {
798 XSetWindowBackgroundPixmap(XtDisplay(cnew), XtWindow(cnew), pm);
799 XFreePixmap(XtDisplay(cnew), pm);
802 XSetWindowBackground(XtDisplay(cnew), XtWindow(cnew),
803 cnew->core.background_pixel);
808 if (cnew->panner.resize_to_pref &&
809 (cur->panner.canvas_width != cnew->panner.canvas_width
810 || cur->panner.canvas_height != cnew->panner.canvas_height
811 || cur->panner.resize_to_pref != cnew->panner.resize_to_pref)) {
812 get_default_size(cnew, &cnew->core.width, &cnew->core.height);
815 else if (cur->panner.canvas_width != cnew->panner.canvas_width
816 || cur->panner.canvas_height != cnew->panner.canvas_height
817 || cur->panner.internal_border != cnew->panner.internal_border) {
818 rescale(cnew); /* does a scale_knob as well */
822 Bool loc = cur->panner.slider_x != cnew->panner.slider_x ||
823 cur->panner.slider_y != cnew->panner.slider_y;
824 Bool siz = cur->panner.slider_width != cnew->panner.slider_width ||
825 cur->panner.slider_height != cnew->panner.slider_height;
826 if (loc || siz || (cur->panner.allow_off != cnew->panner.allow_off
827 && cnew->panner.allow_off)) {
828 scale_knob(cnew, loc, siz);
837 XawPannerSetValuesAlmost(Widget gold, Widget gnew, XtWidgetGeometry *req,
838 XtWidgetGeometry *reply)
840 if (reply->request_mode == 0) /* got turned down, so cope */
841 XawPannerResize(gnew);
843 (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
844 (gold, gnew, req, reply);
847 static XtGeometryResult
848 XawPannerQueryGeometry(Widget gw, XtWidgetGeometry *intended,
849 XtWidgetGeometry *pref)
851 PannerWidget pw = (PannerWidget)gw;
853 pref->request_mode = (CWWidth | CWHeight);
854 get_default_size(pw, &pref->width, &pref->height);
856 if (((intended->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
857 && intended->width == pref->width && intended->height == pref->height)
858 return (XtGeometryYes);
859 else if (pref->width == XtWidth(pw) && pref->height == XtHeight(pw))
860 return (XtGeometryNo);
862 return (XtGeometryAlmost);
868 ActionStart(Widget gw, XEvent *event, String *params, Cardinal *num_params)
870 PannerWidget pw = (PannerWidget)gw;
873 if (!get_event_xy(pw, event, &x, &y)) {
874 XBell(XtDisplay(gw), 0);
878 pw->panner.tmp.doing = True;
879 pw->panner.tmp.startx = pw->panner.knob_x;
880 pw->panner.tmp.starty = pw->panner.knob_y;
881 pw->panner.tmp.dx = x - pw->panner.knob_x;
882 pw->panner.tmp.dy = y - pw->panner.knob_y;
883 pw->panner.tmp.x = pw->panner.knob_x;
884 pw->panner.tmp.y = pw->panner.knob_y;
885 if (pw->panner.rubber_band)
891 ActionStop(Widget gw, XEvent *event, String *params, Cardinal *num_params)
893 PannerWidget pw = (PannerWidget)gw;
896 if (get_event_xy(pw, event, &x, &y)) {
897 pw->panner.tmp.x = x - pw->panner.tmp.dx;
898 pw->panner.tmp.y = y - pw->panner.tmp.dy;
899 if (!pw->panner.allow_off)
900 check_knob(pw, False);
902 if (pw->panner.rubber_band)
904 pw->panner.tmp.doing = False;
908 ActionAbort(Widget gw, XEvent *event, String *params, Cardinal *num_params)
910 PannerWidget pw = (PannerWidget)gw;
912 if (!pw->panner.tmp.doing)
915 if (pw->panner.rubber_band)
918 if (!pw->panner.rubber_band) { /* restore old position */
919 pw->panner.tmp.x = pw->panner.tmp.startx;
920 pw->panner.tmp.y = pw->panner.tmp.starty;
921 ActionNotify(gw, event, params, num_params);
923 pw->panner.tmp.doing = False;
927 ActionMove(Widget gw, XEvent *event, String *params, Cardinal *num_params)
929 PannerWidget pw = (PannerWidget)gw;
932 if (!pw->panner.tmp.doing)
935 if (!get_event_xy(pw, event, &x, &y)) {
936 XBell(XtDisplay(gw), 0); /* should do error message */
940 if (pw->panner.rubber_band)
942 pw->panner.tmp.x = x - pw->panner.tmp.dx;
943 pw->panner.tmp.y = y - pw->panner.tmp.dy;
945 if (!pw->panner.rubber_band)
946 ActionNotify(gw, event, params, num_params);
948 if (!pw->panner.allow_off)
949 check_knob(pw, False);
956 ActionPage(Widget gw, XEvent *event, String *params, Cardinal *num_params)
958 PannerWidget pw = (PannerWidget)gw;
960 Bool isin = pw->panner.tmp.doing;
963 int pad = pw->panner.internal_border << 1;
965 if (*num_params != 2) {
966 XBell(XtDisplay(gw), 0);
970 x = parse_page_string(params[0], pw->panner.knob_width,
971 (int)XtWidth(pw) - pad, &relx);
972 y = parse_page_string(params[1], pw->panner.knob_height,
973 (int)XtHeight(pw) - pad, &rely);
976 x += pw->panner.knob_x;
978 y += pw->panner.knob_y;
980 if (isin) { /* if in, then use move */
983 ev.xbutton.type = ButtonPress;
986 ActionMove(gw, &ev, NULL, &zero);
989 pw->panner.tmp.doing = True;
990 pw->panner.tmp.x = x;
991 pw->panner.tmp.y = y;
992 ActionNotify(gw, event, NULL, &zero);
993 pw->panner.tmp.doing = False;
999 ActionNotify(Widget gw, XEvent *event, String *params, Cardinal *num_params)
1001 PannerWidget pw = (PannerWidget)gw;
1003 if (!pw->panner.tmp.doing)
1006 if (!pw->panner.allow_off)
1007 check_knob(pw, False);
1008 pw->panner.knob_x = pw->panner.tmp.x;
1009 pw->panner.knob_y = pw->panner.tmp.y;
1012 pw->panner.slider_x = (Position)((double)pw->panner.knob_x
1013 / pw->panner.haspect + 0.5);
1014 pw->panner.slider_y = (Position)((double) pw->panner.knob_y
1015 / pw->panner.vaspect + 0.5);
1016 if (!pw->panner.allow_off) {
1019 if (pw->panner.slider_x
1020 > (tmp = (Position)pw->panner.canvas_width -
1021 (Position)pw->panner.slider_width))
1022 pw->panner.slider_x = tmp;
1023 if (pw->panner.slider_x < 0)
1024 pw->panner.slider_x = 0;
1025 if (pw->panner.slider_y
1026 > (tmp = (Position)pw->panner.canvas_height -
1027 (Position)pw->panner.slider_height))
1028 pw->panner.slider_y = tmp;
1029 if (pw->panner.slider_y < 0)
1030 pw->panner.slider_y = 0;
1033 if (pw->panner.last_x != pw->panner.knob_x ||
1034 pw->panner.last_y != pw->panner.knob_y) {
1035 XawPannerReport rep;
1037 XawPannerRedisplay(gw, NULL, NULL);
1038 rep.changed = XawPRSliderX | XawPRSliderY;
1039 rep.slider_x = pw->panner.slider_x;
1040 rep.slider_y = pw->panner.slider_y;
1041 rep.slider_width = pw->panner.slider_width;
1042 rep.slider_height = pw->panner.slider_height;
1043 rep.canvas_width = pw->panner.canvas_width;
1044 rep.canvas_height = pw->panner.canvas_height;
1045 XtCallCallbackList(gw, pw->panner.report_callbacks, (XtPointer)&rep);
1051 ActionSet(Widget gw, XEvent *event, String *params, Cardinal *num_params)
1053 PannerWidget pw = (PannerWidget)gw;
1056 if (*num_params < 2 ||
1057 XmuCompareISOLatin1(params[0], "rubberband") != 0) {
1058 XBell(XtDisplay(gw), 0);
1062 if (XmuCompareISOLatin1(params[1], "on") == 0)
1064 else if (XmuCompareISOLatin1(params[1], "off") == 0)
1066 else if (XmuCompareISOLatin1(params[1], "toggle") == 0)
1067 rb = !pw->panner.rubber_band;
1069 XBell(XtDisplay(gw), 0);
1073 if (rb != pw->panner.rubber_band) {
1076 XtSetArg(args[0], XtNrubberBand, rb);
1077 XtSetValues(gw, args, 1);