diff options
Diffstat (limited to 'libXaw/src/Panner.c')
-rw-r--r-- | libXaw/src/Panner.c | 2158 |
1 files changed, 1079 insertions, 1079 deletions
diff --git a/libXaw/src/Panner.c b/libXaw/src/Panner.c index 2ab88f5ed..04c3b4ce1 100644 --- a/libXaw/src/Panner.c +++ b/libXaw/src/Panner.c @@ -1,1079 +1,1079 @@ -/* - * -Copyright 1989, 1994, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - * - * Author: Jim Fulton, MIT X Consortium - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <ctype.h> -#include <math.h> -#include <X11/IntrinsicP.h> -#include <X11/StringDefs.h> -#include <X11/Xos.h> -#include <X11/Xmu/CharSet.h> -#include <X11/Xmu/Drawing.h> -#include <X11/Xmu/Misc.h> -#include <X11/Xaw/PannerP.h> -#include <X11/Xaw/XawInit.h> -#include "Private.h" - -#if defined(ISC) && __STDC__ && !defined(ISC30) -extern double atof(char *); -#else -#include <stdlib.h> /* for atof() */ -#endif - -/* - * Class Methods - */ -static void XawPannerDestroy(Widget); -static void XawPannerInitialize(Widget, Widget, ArgList, Cardinal*); -static XtGeometryResult XawPannerQueryGeometry(Widget, XtWidgetGeometry*, - XtWidgetGeometry*); -static void XawPannerRealize(Widget, XtValueMask*, XSetWindowAttributes*); -static void XawPannerRedisplay(Widget, XEvent*, Region); -static void XawPannerResize(Widget); -static Boolean XawPannerSetValues(Widget, Widget, Widget, ArgList, Cardinal*); -static void XawPannerSetValuesAlmost(Widget, Widget, XtWidgetGeometry*, - XtWidgetGeometry*); - -/* - * Prototypes - */ -static void check_knob(PannerWidget, Bool); -static void get_default_size(PannerWidget, Dimension*, Dimension*); -static Bool get_event_xy(PannerWidget, XEvent*, int*, int*); -static void move_shadow(PannerWidget); -static int parse_page_string(char*, int, int, Bool*); -static void rescale(PannerWidget); -static void reset_shadow_gc(PannerWidget); -static void reset_slider_gc(PannerWidget); -static void reset_xor_gc(PannerWidget); -static void scale_knob(PannerWidget, Bool, Bool); - -/* - * Actions - */ -static void ActionAbort(Widget, XEvent*, String*, Cardinal*); -static void ActionMove(Widget, XEvent*, String*, Cardinal*); -static void ActionNotify(Widget, XEvent*, String*, Cardinal*); -static void ActionPage(Widget, XEvent*, String*, Cardinal*); -static void ActionSet(Widget, XEvent*, String*, Cardinal*); -static void ActionStart(Widget, XEvent*, String*, Cardinal*); -static void ActionStop(Widget, XEvent*, String*, Cardinal*); - -/* - * From Xmu/Distinct.c - */ -Bool XmuDistinguishablePixels(Display*, Colormap, unsigned long*, int); - -/* - * Initialization - */ -static char defaultTranslations[] = -"<Btn1Down>:" "start()\n" -"<Btn1Motion>:" "move()\n" -"<Btn1Up>:" "notify() stop()\n" -"<Btn2Down>:" "abort()\n" -":<Key>KP_Enter:" "set(rubberband,toggle)\n" -"<Key>space:" "page(+1p,+1p)\n" -"<Key>Delete:" "page(-1p,-1p)\n" -":<Key>KP_Delete:" "page(-1p,-1p)\n" -"<Key>BackSpace:" "page(-1p,-1p)\n" -"<Key>Left:" "page(-.5p,+0)\n" -":<Key>KP_Left:" "page(-.5p,+0)\n" -"<Key>Right:" "page(+.5p,+0)\n" -":<Key>KP_Right:" "page(+.5p,+0)\n" -"<Key>Up:" "page(+0,-.5p)\n" -":<Key>KP_Up:" "page(+0,-.5p)\n" -"<Key>Down:" "page(+0,+.5p)\n" -":<Key>KP_Down:" "page(+0,+.5p)\n" -"<Key>Home:" "page(0,0)\n" -":<Key>KP_Home:" "page(0,0)\n" -; - -static XtActionsRec actions[] = { - {"start", ActionStart}, /* start tmp graphics */ - {"stop", ActionStop}, /* stop tmp graphics */ - {"abort", ActionAbort}, /* punt */ - {"move", ActionMove}, /* move tmp graphics on Motion event */ - {"page", ActionPage}, /* page around usually from keyboard */ - {"notify", ActionNotify}, /* callback new position */ - {"set", ActionSet}, /* set various parameters */ -}; - -#define offset(field) XtOffsetOf(PannerRec, panner.field) -static XtResource resources[] = { - { - XtNallowOff, - XtCAllowOff, - XtRBoolean, - sizeof(Boolean), - offset(allow_off), - XtRImmediate, - (XtPointer)False - }, - { - XtNresize, - XtCResize, - XtRBoolean, - sizeof(Boolean), - offset(resize_to_pref), - XtRImmediate, - (XtPointer)True - }, - { - XtNreportCallback, - XtCReportCallback, - XtRCallback, - sizeof(XtPointer), - offset(report_callbacks), - XtRCallback, - NULL - }, - { - XtNdefaultScale, - XtCDefaultScale, - XtRDimension, - sizeof(Dimension), - offset(default_scale), - XtRImmediate, - (XtPointer)PANNER_DEFAULT_SCALE - }, - { - XtNrubberBand, - XtCRubberBand, - XtRBoolean, - sizeof(Boolean), - offset(rubber_band), - XtRImmediate, - (XtPointer)False - }, - { - XtNforeground, - XtCForeground, - XtRPixel, - sizeof(Pixel), - offset(foreground), - XtRString, - (XtPointer)XtDefaultBackground - }, - { - XtNinternalSpace, - XtCInternalSpace, - XtRDimension, - sizeof(Dimension), - offset(internal_border), - XtRImmediate, - (XtPointer)4 - }, - { - XtNlineWidth, - XtCLineWidth, - XtRDimension, - sizeof(Dimension), - offset(line_width), - XtRImmediate, - (XtPointer)0 - }, - { - XtNcanvasWidth, - XtCCanvasWidth, - XtRDimension, - sizeof(Dimension), - offset(canvas_width), - XtRImmediate, - (XtPointer)0 - }, - { - XtNcanvasHeight, - XtCCanvasHeight, - XtRDimension, - sizeof(Dimension), - offset(canvas_height), - XtRImmediate, - (XtPointer)0 - }, - { - XtNsliderX, - XtCSliderX, - XtRPosition, - sizeof(Position), - offset(slider_x), - XtRImmediate, - (XtPointer)0 - }, - { - XtNsliderY, - XtCSliderY, - XtRPosition, - sizeof(Position), - offset(slider_y), - XtRImmediate, - (XtPointer)0 - }, - { - XtNsliderWidth, - XtCSliderWidth, - XtRDimension, - sizeof(Dimension), - offset(slider_width), - XtRImmediate, - (XtPointer)0 - }, - { - XtNsliderHeight, - XtCSliderHeight, - XtRDimension, - sizeof(Dimension), - offset(slider_height), - XtRImmediate, - (XtPointer)0 - }, - { - XtNshadowColor, - XtCShadowColor, - XtRPixel, - sizeof(Pixel), - offset(shadow_color), - XtRString, - (XtPointer)XtDefaultForeground - }, - { - XtNshadowThickness, - XtCShadowThickness, - XtRDimension, - sizeof(Dimension), - offset(shadow_thickness), - XtRImmediate, - (XtPointer)2 - }, - { - XtNbackgroundStipple, - XtCBackgroundStipple, - XtRString, - sizeof(String), - offset(stipple_name), - XtRImmediate, - NULL - }, -}; -#undef offset - -#define Superclass (&simpleClassRec) -PannerClassRec pannerClassRec = { - /* core */ - { - (WidgetClass)Superclass, /* superclass */ - "Panner", /* class_name */ - sizeof(PannerRec), /* widget_size */ - XawInitializeWidgetSet, /* class_initialize */ - NULL, /* class_part_initialize */ - False, /* class_inited */ - XawPannerInitialize, /* initialize */ - NULL, /* initialize_hook */ - XawPannerRealize, /* realize */ - actions, /* actions */ - XtNumber(actions), /* num_actions */ - resources, /* resources */ - XtNumber(resources), /* num_resources */ - NULLQUARK, /* xrm_class */ - True, /* compress_motion */ - True, /* compress_exposure */ - True, /* compress_enterleave */ - False, /* visible_interest */ - XawPannerDestroy, /* destroy */ - XawPannerResize, /* resize */ - XawPannerRedisplay, /* expose */ - XawPannerSetValues, /* set_values */ - NULL, /* set_values_hook */ - XawPannerSetValuesAlmost, /* set_values_almost */ - NULL, /* get_values_hook */ - NULL, /* accept_focus */ - XtVersion, /* version */ - NULL, /* callback_private */ - defaultTranslations, /* tm_table */ - XawPannerQueryGeometry, /* query_geometry */ - XtInheritDisplayAccelerator, /* display_accelerator */ - NULL, /* extension */ - }, - /* simple */ - { - XtInheritChangeSensitive, /* change_sensitive */ - }, - /* panner */ - { - NULL, /* extension */ - } -}; - -WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec; - - -/* - * Implementation - */ -static void -reset_shadow_gc(PannerWidget pw) -{ - XtGCMask valuemask = GCForeground; - XGCValues values; - unsigned long pixels[3]; - - if (pw->panner.shadow_gc) - XtReleaseGC((Widget)pw, pw->panner.shadow_gc); - - pixels[0] = pw->panner.foreground; - pixels[1] = pw->core.background_pixel; - pixels[2] = pw->panner.shadow_color; - - if (!pw->panner.stipple_name && - !XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap, - pixels, 3) && - XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap, - pixels, 2)) { - valuemask = GCTile | GCFillStyle; - values.fill_style = FillTiled; - values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw), - pw->panner.foreground, - pw->core.background_pixel, - pw->core.depth); - } - else { - if (!pw->panner.line_width && - !XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap, - pixels, 2)) - pw->panner.line_width = 1; - valuemask = GCForeground; - values.foreground = pw->panner.shadow_color; - } - if (pw->panner.line_width > 0) { - values.line_width = pw->panner.line_width; - valuemask |= GCLineWidth; - } - - pw->panner.shadow_gc = XtGetGC((Widget)pw, valuemask, &values); -} - -static void -reset_slider_gc(PannerWidget pw) -{ - XtGCMask valuemask = GCForeground; - XGCValues values; - - if (pw->panner.slider_gc) - XtReleaseGC((Widget)pw, pw->panner.slider_gc); - - values.foreground = pw->panner.foreground; - - pw->panner.slider_gc = XtGetGC((Widget)pw, valuemask, &values); -} - -static void -reset_xor_gc(PannerWidget pw) -{ - if (pw->panner.xor_gc) - XtReleaseGC((Widget)pw, pw->panner.xor_gc); - - if (pw->panner.rubber_band) { - XtGCMask valuemask = (GCForeground | GCFunction); - XGCValues values; - Pixel tmp; - - tmp = (pw->panner.foreground == pw->core.background_pixel ? - pw->panner.shadow_color : pw->panner.foreground); - values.foreground = tmp ^ pw->core.background_pixel; - values.function = GXxor; - if (pw->panner.line_width > 0) { - valuemask |= GCLineWidth; - values.line_width = pw->panner.line_width; - } - pw->panner.xor_gc = XtGetGC((Widget)pw, valuemask, &values); - } - else - pw->panner.xor_gc = NULL; -} - -static void -check_knob(PannerWidget pw, Bool knob) -{ - Position pad = pw->panner.internal_border << 1; - Position maxx = (Position)XtWidth(pw) - pad - - (Position)pw->panner.knob_width; - Position maxy = (Position)XtHeight(pw) - pad - - (Position)pw->panner.knob_height; - Position *x = knob ? &pw->panner.knob_x : &pw->panner.tmp.x; - Position *y = knob ? &pw->panner.knob_y : &pw->panner.tmp.y; - - /* - * note that positions are already normalized (i.e. internal_border - * has been subtracted out) - */ - if (*x < 0) - *x = 0; - if (*x > maxx) - *x = maxx; - - if (*y < 0) - *y = 0; - if (*y > maxy) - *y = maxy; - - if (knob) { - pw->panner.slider_x = (Position)((double)pw->panner.knob_x - / pw->panner.haspect + 0.5); - pw->panner.slider_y = (Position)((double)pw->panner.knob_y - / pw->panner.vaspect + 0.5); - pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE; - } -} - -static void -move_shadow(PannerWidget pw) -{ - if (pw->panner.shadow_thickness > 0) { - int lw = pw->panner.shadow_thickness + (pw->panner.line_width << 1); - int pad = pw->panner.internal_border; - - if (pw->panner.knob_height > lw && pw->panner.knob_width > lw) { - XRectangle *r = pw->panner.shadow_rects; - - r->x = pw->panner.knob_x + pad + pw->panner.knob_width; - r->y = pw->panner.knob_y + pad + lw; - r->width = pw->panner.shadow_thickness; - r->height = pw->panner.knob_height - lw; - r++; - r->x = pw->panner.knob_x + pad + lw; - r->y = pw->panner.knob_y + pad + pw->panner.knob_height; - r->width = pw->panner.knob_width - lw + pw->panner.shadow_thickness; - r->height = pw->panner.shadow_thickness; - pw->panner.shadow_valid = True; - return; - } - } - pw->panner.shadow_valid = False; -} - -static void -scale_knob(PannerWidget pw, Bool location, Bool size) -{ - if (location) { - pw->panner.knob_x = (Position)PANNER_HSCALE(pw, pw->panner.slider_x); - pw->panner.knob_y = (Position)PANNER_VSCALE(pw, pw->panner.slider_y); - } - if (size) { - Dimension width, height; - - if (pw->panner.slider_width < 1) - pw->panner.slider_width = pw->panner.canvas_width; - if (pw->panner.slider_height < 1) - pw->panner.slider_height = pw->panner.canvas_height; - width = Min(pw->panner.slider_width, pw->panner.canvas_width); - height = Min(pw->panner.slider_height, pw->panner.canvas_height); - - pw->panner.knob_width = (Dimension)PANNER_HSCALE(pw, width); - pw->panner.knob_height = (Dimension)PANNER_VSCALE(pw, height); - } - if (!pw->panner.allow_off) - check_knob(pw, True); - move_shadow(pw); -} - -static void -rescale(PannerWidget pw) -{ - int hpad = pw->panner.internal_border << 1; - int vpad = hpad; - - if (pw->panner.canvas_width < 1) - pw->panner.canvas_width = XtWidth(pw); - if (pw->panner.canvas_height < 1) - pw->panner.canvas_height = XtHeight(pw); - - if (XtWidth(pw) <= hpad) - hpad = 0; - if (XtHeight(pw) <= vpad) - vpad = 0; - - pw->panner.haspect = ((double)XtWidth(pw) - hpad + .5) - / (double)pw->panner.canvas_width; - pw->panner.vaspect = ((double)XtHeight(pw) - vpad + .5) - / (double)pw->panner.canvas_height; - scale_knob(pw, True, True); -} - -static void -get_default_size(PannerWidget pw, Dimension *wp, Dimension *hp) -{ - Dimension pad = pw->panner.internal_border << 1; - - *wp = PANNER_DSCALE(pw, pw->panner.canvas_width) + pad; - *hp = PANNER_DSCALE(pw, pw->panner.canvas_height) + pad; -} - -static Bool -get_event_xy(PannerWidget pw, XEvent *event, int *x, int *y) -{ - int pad = pw->panner.internal_border; - - switch (event->type) { - case ButtonPress: - case ButtonRelease: - *x = event->xbutton.x - pad; - *y = event->xbutton.y - pad; - return (True); - case KeyPress: - case KeyRelease: - *x = event->xkey.x - pad; - *y = event->xkey.y - pad; - return (True); - case EnterNotify: - case LeaveNotify: - *x = event->xcrossing.x - pad; - *y = event->xcrossing.y - pad; - return (True); - case MotionNotify: - *x = event->xmotion.x - pad; - *y = event->xmotion.y - pad; - return (True); - } - - return (False); -} - -static int -parse_page_string(char *s, int pagesize, int canvassize, Bool *relative) -{ - char *cp; - double val = 1.0; - Bool rel = False; - - /* - * syntax: spaces [+-] number spaces [pc\0] spaces - */ - for (; isascii(*s) && isspace(*s); s++) /* skip white space */ - ; - - if (*s == '+' || *s == '-') { /* deal with signs */ - rel = True; - if (*s == '-') - val = -1.0; - s++; - } - if (!*s) { /* if null then return nothing */ - *relative = True; - return (0); - } - - /* skip over numbers */ - for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) - ; - val *= atof(cp); - - /* skip blanks */ - for (; isascii(*s) && isspace(*s); s++) - ; - - if (*s) { /* if units */ - switch (s[0]) { - case 'p': - case 'P': - val *= (double)pagesize; - break; - case 'c': - case 'C': - val *= (double)canvassize; - break; - } - } - *relative = rel; - - return ((int)val); -} - -#define DRAW_TMP(pw) \ -{ \ - XDrawRectangle(XtDisplay(pw), XtWindow(pw), \ - pw->panner.xor_gc, \ - pw->panner.tmp.x + pw->panner.internal_border, \ - pw->panner.tmp.y + pw->panner.internal_border, \ - pw->panner.knob_width - 1, \ - pw->panner.knob_height - 1); \ - pw->panner.tmp.showing = !pw->panner.tmp.showing; \ -} - -#define UNDRAW_TMP(pw) \ -{ \ - if (pw->panner.tmp.showing) \ - DRAW_TMP(pw); \ -} - -#define BACKGROUND_STIPPLE(pw) \ -XmuLocatePixmapFile(pw->core.screen, pw->panner.stipple_name, \ - pw->panner.shadow_color, pw->core.background_pixel, \ - pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL) - -#define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap) - -/*ARGSUSED*/ -static void -XawPannerInitialize(Widget greq, Widget gnew, ArgList args, Cardinal *num_args) -{ - PannerWidget req = (PannerWidget)greq, cnew = (PannerWidget)gnew; - Dimension defwidth, defheight; - - if (req->panner.canvas_width < 1) - cnew->panner.canvas_width = 1; - if (req->panner.canvas_height < 1) - cnew->panner.canvas_height = 1; - if (req->panner.default_scale < 1) - cnew->panner.default_scale = PANNER_DEFAULT_SCALE; - - get_default_size(req, &defwidth, &defheight); - if (XtWidth(req) < 1) - XtWidth(cnew) = defwidth; - if (XtHeight(req) < 1) - XtHeight(cnew) = defheight; - - cnew->panner.shadow_gc = NULL; - reset_shadow_gc(cnew); /* shadowColor */ - cnew->panner.slider_gc = NULL; - reset_slider_gc(cnew); /* foreground */ - cnew->panner.xor_gc = NULL; - reset_xor_gc(cnew); /* foreground ^ background */ - - rescale(cnew); /* does a position check */ - cnew->panner.shadow_valid = False; - cnew->panner.tmp.doing = False; - cnew->panner.tmp.showing = False; - } - -static void -XawPannerRealize(Widget gw, XtValueMask *valuemaskp, - XSetWindowAttributes *attr) -{ - PannerWidget pw = (PannerWidget)gw; - Pixmap pm = XtUnspecifiedPixmap; - Bool gotpm = False; - - if (pw->core.background_pixmap == XtUnspecifiedPixmap) { - if (pw->panner.stipple_name) - pm = BACKGROUND_STIPPLE(pw); - - if (PIXMAP_OKAY(pm)) { - attr->background_pixmap = pm; - *valuemaskp |= CWBackPixmap; - *valuemaskp &= ~CWBackPixel; - gotpm = True; - } - } - (*pannerWidgetClass->core_class.superclass->core_class.realize) - (gw, valuemaskp, attr); - - if (gotpm) - XFreePixmap(XtDisplay(gw), pm); -} - -static void -XawPannerDestroy(Widget gw) -{ - PannerWidget pw = (PannerWidget)gw; - - XtReleaseGC(gw, pw->panner.shadow_gc); - XtReleaseGC(gw, pw->panner.slider_gc); - XtReleaseGC(gw, pw->panner.xor_gc); -} - -static void -XawPannerResize(Widget gw) -{ - rescale((PannerWidget)gw); -} - -static void -XawPannerRedisplay(Widget gw, XEvent *event, Region region) -{ - PannerWidget pw = (PannerWidget)gw; - Display *dpy = XtDisplay(gw); - Window w = XtWindow(gw); - int pad = pw->panner.internal_border; - Dimension lw = pw->panner.line_width; - Dimension extra = pw->panner.shadow_thickness + (lw << 1); - int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad; - - if (Superclass->core_class.expose) - (Superclass->core_class.expose)(gw, event, region); - - pw->panner.tmp.showing = False; - XClearArea(XtDisplay(pw), XtWindow(pw), - (int)pw->panner.last_x - ((int)lw) + pad, - (int)pw->panner.last_y - ((int)lw) + pad, - pw->panner.knob_width + extra, - pw->panner.knob_height + extra, - False); - pw->panner.last_x = pw->panner.knob_x; - pw->panner.last_y = pw->panner.knob_y; - - XFillRectangle(dpy, w, pw->panner.slider_gc, kx, ky, - pw->panner.knob_width - 1, pw->panner.knob_height - 1); - - if (lw) - XDrawRectangle(dpy, w, pw->panner.shadow_gc, kx, ky, - pw->panner.knob_width - 1, pw->panner.knob_height - 1); - - if (pw->panner.shadow_valid) - XFillRectangles(dpy, w, pw->panner.shadow_gc, pw->panner.shadow_rects, 2); - - if (pw->panner.tmp.doing && pw->panner.rubber_band) - DRAW_TMP(pw); -} - -/*ARGSUSED*/ -static Boolean -XawPannerSetValues(Widget gcur, Widget greq, Widget gnew, - ArgList args, Cardinal *num_args) -{ - PannerWidget cur = (PannerWidget)gcur; - PannerWidget cnew = (PannerWidget)gnew; - Bool redisplay = False; - - if (cur->panner.foreground != cnew->panner.foreground) { - reset_slider_gc(cnew); - if (cur->panner.foreground != cur->core.background_pixel) - reset_xor_gc(cnew); - redisplay = True; - } - else if (cur->panner.line_width != cnew->panner.line_width || - cur->core.background_pixel != cnew->core.background_pixel) { - reset_xor_gc(cnew); - redisplay = True; - } - if (cur->panner.shadow_color != cnew->panner.shadow_color) { - reset_shadow_gc(cnew); - if (cur->panner.foreground == cur->core.background_pixel) - reset_xor_gc(cnew); - redisplay = True; - } - if (cur->panner.shadow_thickness != cnew->panner.shadow_thickness) { - move_shadow(cnew); - redisplay = True; - } - if (cur->panner.rubber_band != cnew->panner.rubber_band) { - reset_xor_gc(cnew); - if (cnew->panner.tmp.doing) - redisplay = True; - } - - if ((cur->panner.stipple_name != cnew->panner.stipple_name - || cur->panner.shadow_color != cnew->panner.shadow_color - || cur->core.background_pixel != cnew->core.background_pixel) - && XtIsRealized(gnew)) { - Pixmap pm = cnew->panner.stipple_name ? - BACKGROUND_STIPPLE(cnew) : XtUnspecifiedPixmap; - - if (PIXMAP_OKAY(pm)) { - XSetWindowBackgroundPixmap(XtDisplay(cnew), XtWindow(cnew), pm); - XFreePixmap(XtDisplay(cnew), pm); - } - else - XSetWindowBackground(XtDisplay(cnew), XtWindow(cnew), - cnew->core.background_pixel); - - redisplay = True; - } - - if (cnew->panner.resize_to_pref && - (cur->panner.canvas_width != cnew->panner.canvas_width - || cur->panner.canvas_height != cnew->panner.canvas_height - || cur->panner.resize_to_pref != cnew->panner.resize_to_pref)) { - get_default_size(cnew, &cnew->core.width, &cnew->core.height); - redisplay = True; - } - else if (cur->panner.canvas_width != cnew->panner.canvas_width - || cur->panner.canvas_height != cnew->panner.canvas_height - || cur->panner.internal_border != cnew->panner.internal_border) { - rescale(cnew); /* does a scale_knob as well */ - redisplay = True; - } - else { - Bool loc = cur->panner.slider_x != cnew->panner.slider_x || - cur->panner.slider_y != cnew->panner.slider_y; - Bool siz = cur->panner.slider_width != cnew->panner.slider_width || - cur->panner.slider_height != cnew->panner.slider_height; - if (loc || siz || (cur->panner.allow_off != cnew->panner.allow_off - && cnew->panner.allow_off)) { - scale_knob(cnew, loc, siz); - redisplay = True; - } - } - - return (redisplay); -} - -static void -XawPannerSetValuesAlmost(Widget gold, Widget gnew, XtWidgetGeometry *req, - XtWidgetGeometry *reply) -{ - if (reply->request_mode == 0) /* got turned down, so cope */ - XawPannerResize(gnew); - - (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost) - (gold, gnew, req, reply); -} - -static XtGeometryResult -XawPannerQueryGeometry(Widget gw, XtWidgetGeometry *intended, - XtWidgetGeometry *pref) -{ - PannerWidget pw = (PannerWidget)gw; - - pref->request_mode = (CWWidth | CWHeight); - get_default_size(pw, &pref->width, &pref->height); - - if (((intended->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight)) - && intended->width == pref->width && intended->height == pref->height) - return (XtGeometryYes); - else if (pref->width == XtWidth(pw) && pref->height == XtHeight(pw)) - return (XtGeometryNo); - - return (XtGeometryAlmost); -} - - -/*ARGSUSED*/ -static void -ActionStart(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - int x, y; - - if (!get_event_xy(pw, event, &x, &y)) { - XBell(XtDisplay(gw), 0); - return; - } - - pw->panner.tmp.doing = True; - pw->panner.tmp.startx = pw->panner.knob_x; - pw->panner.tmp.starty = pw->panner.knob_y; - pw->panner.tmp.dx = x - pw->panner.knob_x; - pw->panner.tmp.dy = y - pw->panner.knob_y; - pw->panner.tmp.x = pw->panner.knob_x; - pw->panner.tmp.y = pw->panner.knob_y; - if (pw->panner.rubber_band) - DRAW_TMP(pw); -} - -/*ARGSUSED*/ -static void -ActionStop(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - int x, y; - - if (get_event_xy(pw, event, &x, &y)) { - pw->panner.tmp.x = x - pw->panner.tmp.dx; - pw->panner.tmp.y = y - pw->panner.tmp.dy; - if (!pw->panner.allow_off) - check_knob(pw, False); - } - if (pw->panner.rubber_band) - DRAW_TMP(pw); - pw->panner.tmp.doing = False; -} - -static void -ActionAbort(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - - if (!pw->panner.tmp.doing) - return; - - if (pw->panner.rubber_band) - UNDRAW_TMP(pw); - - if (!pw->panner.rubber_band) { /* restore old position */ - pw->panner.tmp.x = pw->panner.tmp.startx; - pw->panner.tmp.y = pw->panner.tmp.starty; - ActionNotify(gw, event, params, num_params); - } - pw->panner.tmp.doing = False; -} - -static void -ActionMove(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - int x, y; - - if (!pw->panner.tmp.doing) - return; - - if (!get_event_xy(pw, event, &x, &y)) { - XBell(XtDisplay(gw), 0); /* should do error message */ - return; - } - - if (pw->panner.rubber_band) - UNDRAW_TMP(pw); - pw->panner.tmp.x = x - pw->panner.tmp.dx; - pw->panner.tmp.y = y - pw->panner.tmp.dy; - - if (!pw->panner.rubber_band) - ActionNotify(gw, event, params, num_params); - else { - if (!pw->panner.allow_off) - check_knob(pw, False); - DRAW_TMP(pw); - } -} - - -static void -ActionPage(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - Cardinal zero = 0; - Bool isin = pw->panner.tmp.doing; - int x, y; - Bool relx, rely; - int pad = pw->panner.internal_border << 1; - - if (*num_params != 2) { - XBell(XtDisplay(gw), 0); - return; - } - - x = parse_page_string(params[0], pw->panner.knob_width, - (int)XtWidth(pw) - pad, &relx); - y = parse_page_string(params[1], pw->panner.knob_height, - (int)XtHeight(pw) - pad, &rely); - - if (relx) - x += pw->panner.knob_x; - if (rely) - y += pw->panner.knob_y; - - if (isin) { /* if in, then use move */ - XEvent ev; - - ev.xbutton.type = ButtonPress; - ev.xbutton.x = x; - ev.xbutton.y = y; - ActionMove(gw, &ev, NULL, &zero); - } - else { - pw->panner.tmp.doing = True; - pw->panner.tmp.x = x; - pw->panner.tmp.y = y; - ActionNotify(gw, event, NULL, &zero); - pw->panner.tmp.doing = False; - } -} - -/*ARGSUSED*/ -static void -ActionNotify(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - - if (!pw->panner.tmp.doing) - return; - - if (!pw->panner.allow_off) - check_knob(pw, False); - pw->panner.knob_x = pw->panner.tmp.x; - pw->panner.knob_y = pw->panner.tmp.y; - move_shadow(pw); - - pw->panner.slider_x = (Position)((double)pw->panner.knob_x - / pw->panner.haspect + 0.5); - pw->panner.slider_y = (Position)((double) pw->panner.knob_y - / pw->panner.vaspect + 0.5); - if (!pw->panner.allow_off) { - Position tmp; - - if (pw->panner.slider_x - > (tmp = (Position)pw->panner.canvas_width - - (Position)pw->panner.slider_width)) - pw->panner.slider_x = tmp; - if (pw->panner.slider_x < 0) - pw->panner.slider_x = 0; - if (pw->panner.slider_y - > (tmp = (Position)pw->panner.canvas_height - - (Position)pw->panner.slider_height)) - pw->panner.slider_y = tmp; - if (pw->panner.slider_y < 0) - pw->panner.slider_y = 0; - } - - if (pw->panner.last_x != pw->panner.knob_x || - pw->panner.last_y != pw->panner.knob_y) { - XawPannerReport rep; - - XawPannerRedisplay(gw, NULL, NULL); - rep.changed = XawPRSliderX | XawPRSliderY; - rep.slider_x = pw->panner.slider_x; - rep.slider_y = pw->panner.slider_y; - rep.slider_width = pw->panner.slider_width; - rep.slider_height = pw->panner.slider_height; - rep.canvas_width = pw->panner.canvas_width; - rep.canvas_height = pw->panner.canvas_height; - XtCallCallbackList(gw, pw->panner.report_callbacks, (XtPointer)&rep); - } -} - -/*ARGSUSED*/ -static void -ActionSet(Widget gw, XEvent *event, String *params, Cardinal *num_params) -{ - PannerWidget pw = (PannerWidget)gw; - Bool rb; - - if (*num_params < 2 || - XmuCompareISOLatin1(params[0], "rubberband") != 0) { - XBell(XtDisplay(gw), 0); - return; - } - - if (XmuCompareISOLatin1(params[1], "on") == 0) - rb = True; - else if (XmuCompareISOLatin1(params[1], "off") == 0) - rb = False; - else if (XmuCompareISOLatin1(params[1], "toggle") == 0) - rb = !pw->panner.rubber_band; - else { - XBell(XtDisplay(gw), 0); - return; - } - - if (rb != pw->panner.rubber_band) { - Arg args[1]; - - XtSetArg(args[0], XtNrubberBand, rb); - XtSetValues(gw, args, 1); - } -} +/*
+ *
+Copyright 1989, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <ctype.h>
+#include <math.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xmu/CharSet.h>
+#include <X11/Xmu/Drawing.h>
+#include <X11/Xmu/Misc.h>
+#include <X11/Xaw/PannerP.h>
+#include <X11/Xaw/XawInit.h>
+#include "Private.h"
+
+#if defined(ISC) && __STDC__ && !defined(ISC30)
+extern double atof(char *);
+#else
+#include <stdlib.h> /* for atof() */
+#endif
+
+/*
+ * Class Methods
+ */
+static void XawPannerDestroy(Widget);
+static void XawPannerInitialize(Widget, Widget, ArgList, Cardinal*);
+static XtGeometryResult XawPannerQueryGeometry(Widget, XtWidgetGeometry*,
+ XtWidgetGeometry*);
+static void XawPannerRealize(Widget, XtValueMask*, XSetWindowAttributes*);
+static void XawPannerRedisplay(Widget, XEvent*, Region);
+static void XawPannerResize(Widget);
+static Boolean XawPannerSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
+static void XawPannerSetValuesAlmost(Widget, Widget, XtWidgetGeometry*,
+ XtWidgetGeometry*);
+
+/*
+ * Prototypes
+ */
+static void check_knob(PannerWidget, Bool);
+static void get_default_size(PannerWidget, Dimension*, Dimension*);
+static Bool get_event_xy(PannerWidget, XEvent*, int*, int*);
+static void move_shadow(PannerWidget);
+static int parse_page_string(char*, int, int, Bool*);
+static void rescale(PannerWidget);
+static void reset_shadow_gc(PannerWidget);
+static void reset_slider_gc(PannerWidget);
+static void reset_xor_gc(PannerWidget);
+static void scale_knob(PannerWidget, Bool, Bool);
+
+/*
+ * Actions
+ */
+static void ActionAbort(Widget, XEvent*, String*, Cardinal*);
+static void ActionMove(Widget, XEvent*, String*, Cardinal*);
+static void ActionNotify(Widget, XEvent*, String*, Cardinal*);
+static void ActionPage(Widget, XEvent*, String*, Cardinal*);
+static void ActionSet(Widget, XEvent*, String*, Cardinal*);
+static void ActionStart(Widget, XEvent*, String*, Cardinal*);
+static void ActionStop(Widget, XEvent*, String*, Cardinal*);
+
+/*
+ * From Xmu/Distinct.c
+ */
+Bool XmuDistinguishablePixels(Display*, Colormap, unsigned long*, int);
+
+/*
+ * Initialization
+ */
+static char defaultTranslations[] =
+"<Btn1Down>:" "start()\n"
+"<Btn1Motion>:" "move()\n"
+"<Btn1Up>:" "notify() stop()\n"
+"<Btn2Down>:" "abort()\n"
+":<Key>KP_Enter:" "set(rubberband,toggle)\n"
+"<Key>space:" "page(+1p,+1p)\n"
+"<Key>Delete:" "page(-1p,-1p)\n"
+":<Key>KP_Delete:" "page(-1p,-1p)\n"
+"<Key>BackSpace:" "page(-1p,-1p)\n"
+"<Key>Left:" "page(-.5p,+0)\n"
+":<Key>KP_Left:" "page(-.5p,+0)\n"
+"<Key>Right:" "page(+.5p,+0)\n"
+":<Key>KP_Right:" "page(+.5p,+0)\n"
+"<Key>Up:" "page(+0,-.5p)\n"
+":<Key>KP_Up:" "page(+0,-.5p)\n"
+"<Key>Down:" "page(+0,+.5p)\n"
+":<Key>KP_Down:" "page(+0,+.5p)\n"
+"<Key>Home:" "page(0,0)\n"
+":<Key>KP_Home:" "page(0,0)\n"
+;
+
+static XtActionsRec actions[] = {
+ {"start", ActionStart}, /* start tmp graphics */
+ {"stop", ActionStop}, /* stop tmp graphics */
+ {"abort", ActionAbort}, /* punt */
+ {"move", ActionMove}, /* move tmp graphics on Motion event */
+ {"page", ActionPage}, /* page around usually from keyboard */
+ {"notify", ActionNotify}, /* callback new position */
+ {"set", ActionSet}, /* set various parameters */
+};
+
+#define offset(field) XtOffsetOf(PannerRec, panner.field)
+static XtResource resources[] = {
+ {
+ XtNallowOff,
+ XtCAllowOff,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(allow_off),
+ XtRImmediate,
+ (XtPointer)False
+ },
+ {
+ XtNresize,
+ XtCResize,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(resize_to_pref),
+ XtRImmediate,
+ (XtPointer)True
+ },
+ {
+ XtNreportCallback,
+ XtCReportCallback,
+ XtRCallback,
+ sizeof(XtPointer),
+ offset(report_callbacks),
+ XtRCallback,
+ NULL
+ },
+ {
+ XtNdefaultScale,
+ XtCDefaultScale,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(default_scale),
+ XtRImmediate,
+ (XtPointer)PANNER_DEFAULT_SCALE
+ },
+ {
+ XtNrubberBand,
+ XtCRubberBand,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(rubber_band),
+ XtRImmediate,
+ (XtPointer)False
+ },
+ {
+ XtNforeground,
+ XtCForeground,
+ XtRPixel,
+ sizeof(Pixel),
+ offset(foreground),
+ XtRString,
+ (XtPointer)XtDefaultBackground
+ },
+ {
+ XtNinternalSpace,
+ XtCInternalSpace,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(internal_border),
+ XtRImmediate,
+ (XtPointer)4
+ },
+ {
+ XtNlineWidth,
+ XtCLineWidth,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(line_width),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNcanvasWidth,
+ XtCCanvasWidth,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(canvas_width),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNcanvasHeight,
+ XtCCanvasHeight,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(canvas_height),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNsliderX,
+ XtCSliderX,
+ XtRPosition,
+ sizeof(Position),
+ offset(slider_x),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNsliderY,
+ XtCSliderY,
+ XtRPosition,
+ sizeof(Position),
+ offset(slider_y),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNsliderWidth,
+ XtCSliderWidth,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(slider_width),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNsliderHeight,
+ XtCSliderHeight,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(slider_height),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNshadowColor,
+ XtCShadowColor,
+ XtRPixel,
+ sizeof(Pixel),
+ offset(shadow_color),
+ XtRString,
+ (XtPointer)XtDefaultForeground
+ },
+ {
+ XtNshadowThickness,
+ XtCShadowThickness,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(shadow_thickness),
+ XtRImmediate,
+ (XtPointer)2
+ },
+ {
+ XtNbackgroundStipple,
+ XtCBackgroundStipple,
+ XtRString,
+ sizeof(String),
+ offset(stipple_name),
+ XtRImmediate,
+ NULL
+ },
+};
+#undef offset
+
+#define Superclass (&simpleClassRec)
+PannerClassRec pannerClassRec = {
+ /* core */
+ {
+ (WidgetClass)Superclass, /* superclass */
+ "Panner", /* class_name */
+ sizeof(PannerRec), /* widget_size */
+ XawInitializeWidgetSet, /* class_initialize */
+ NULL, /* class_part_initialize */
+ False, /* class_inited */
+ XawPannerInitialize, /* initialize */
+ NULL, /* initialize_hook */
+ XawPannerRealize, /* realize */
+ actions, /* actions */
+ XtNumber(actions), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ True, /* compress_motion */
+ True, /* compress_exposure */
+ True, /* compress_enterleave */
+ False, /* visible_interest */
+ XawPannerDestroy, /* destroy */
+ XawPannerResize, /* resize */
+ XawPannerRedisplay, /* expose */
+ XawPannerSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XawPannerSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ defaultTranslations, /* tm_table */
+ XawPannerQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL, /* extension */
+ },
+ /* simple */
+ {
+ XtInheritChangeSensitive, /* change_sensitive */
+ },
+ /* panner */
+ {
+ NULL, /* extension */
+ }
+};
+
+WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
+
+
+/*
+ * Implementation
+ */
+static void
+reset_shadow_gc(PannerWidget pw)
+{
+ XtGCMask valuemask = GCForeground;
+ XGCValues values;
+ unsigned long pixels[3];
+
+ if (pw->panner.shadow_gc)
+ XtReleaseGC((Widget)pw, pw->panner.shadow_gc);
+
+ pixels[0] = pw->panner.foreground;
+ pixels[1] = pw->core.background_pixel;
+ pixels[2] = pw->panner.shadow_color;
+
+ if (!pw->panner.stipple_name &&
+ !XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
+ pixels, 3) &&
+ XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
+ pixels, 2)) {
+ valuemask = GCTile | GCFillStyle;
+ values.fill_style = FillTiled;
+ values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
+ pw->panner.foreground,
+ pw->core.background_pixel,
+ pw->core.depth);
+ }
+ else {
+ if (!pw->panner.line_width &&
+ !XmuDistinguishablePixels(XtDisplay(pw), pw->core.colormap,
+ pixels, 2))
+ pw->panner.line_width = 1;
+ valuemask = GCForeground;
+ values.foreground = pw->panner.shadow_color;
+ }
+ if (pw->panner.line_width > 0) {
+ values.line_width = pw->panner.line_width;
+ valuemask |= GCLineWidth;
+ }
+
+ pw->panner.shadow_gc = XtGetGC((Widget)pw, valuemask, &values);
+}
+
+static void
+reset_slider_gc(PannerWidget pw)
+{
+ XtGCMask valuemask = GCForeground;
+ XGCValues values;
+
+ if (pw->panner.slider_gc)
+ XtReleaseGC((Widget)pw, pw->panner.slider_gc);
+
+ values.foreground = pw->panner.foreground;
+
+ pw->panner.slider_gc = XtGetGC((Widget)pw, valuemask, &values);
+}
+
+static void
+reset_xor_gc(PannerWidget pw)
+{
+ if (pw->panner.xor_gc)
+ XtReleaseGC((Widget)pw, pw->panner.xor_gc);
+
+ if (pw->panner.rubber_band) {
+ XtGCMask valuemask = (GCForeground | GCFunction);
+ XGCValues values;
+ Pixel tmp;
+
+ tmp = (pw->panner.foreground == pw->core.background_pixel ?
+ pw->panner.shadow_color : pw->panner.foreground);
+ values.foreground = tmp ^ pw->core.background_pixel;
+ values.function = GXxor;
+ if (pw->panner.line_width > 0) {
+ valuemask |= GCLineWidth;
+ values.line_width = pw->panner.line_width;
+ }
+ pw->panner.xor_gc = XtGetGC((Widget)pw, valuemask, &values);
+ }
+ else
+ pw->panner.xor_gc = NULL;
+}
+
+static void
+check_knob(PannerWidget pw, Bool knob)
+{
+ Position pad = pw->panner.internal_border << 1;
+ Position maxx = (Position)XtWidth(pw) - pad -
+ (Position)pw->panner.knob_width;
+ Position maxy = (Position)XtHeight(pw) - pad -
+ (Position)pw->panner.knob_height;
+ Position *x = knob ? &pw->panner.knob_x : &pw->panner.tmp.x;
+ Position *y = knob ? &pw->panner.knob_y : &pw->panner.tmp.y;
+
+ /*
+ * note that positions are already normalized (i.e. internal_border
+ * has been subtracted out)
+ */
+ if (*x < 0)
+ *x = 0;
+ if (*x > maxx)
+ *x = maxx;
+
+ if (*y < 0)
+ *y = 0;
+ if (*y > maxy)
+ *y = maxy;
+
+ if (knob) {
+ pw->panner.slider_x = (Position)((double)pw->panner.knob_x
+ / pw->panner.haspect + 0.5);
+ pw->panner.slider_y = (Position)((double)pw->panner.knob_y
+ / pw->panner.vaspect + 0.5);
+ pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
+ }
+}
+
+static void
+move_shadow(PannerWidget pw)
+{
+ if (pw->panner.shadow_thickness > 0) {
+ int lw = pw->panner.shadow_thickness + (pw->panner.line_width << 1);
+ int pad = pw->panner.internal_border;
+
+ if (pw->panner.knob_height > lw && pw->panner.knob_width > lw) {
+ XRectangle *r = pw->panner.shadow_rects;
+
+ r->x = pw->panner.knob_x + pad + pw->panner.knob_width;
+ r->y = pw->panner.knob_y + pad + lw;
+ r->width = pw->panner.shadow_thickness;
+ r->height = pw->panner.knob_height - lw;
+ r++;
+ r->x = pw->panner.knob_x + pad + lw;
+ r->y = pw->panner.knob_y + pad + pw->panner.knob_height;
+ r->width = pw->panner.knob_width - lw + pw->panner.shadow_thickness;
+ r->height = pw->panner.shadow_thickness;
+ pw->panner.shadow_valid = True;
+ return;
+ }
+ }
+ pw->panner.shadow_valid = False;
+}
+
+static void
+scale_knob(PannerWidget pw, Bool location, Bool size)
+{
+ if (location) {
+ pw->panner.knob_x = (Position)PANNER_HSCALE(pw, pw->panner.slider_x);
+ pw->panner.knob_y = (Position)PANNER_VSCALE(pw, pw->panner.slider_y);
+ }
+ if (size) {
+ Dimension width, height;
+
+ if (pw->panner.slider_width < 1)
+ pw->panner.slider_width = pw->panner.canvas_width;
+ if (pw->panner.slider_height < 1)
+ pw->panner.slider_height = pw->panner.canvas_height;
+ width = Min(pw->panner.slider_width, pw->panner.canvas_width);
+ height = Min(pw->panner.slider_height, pw->panner.canvas_height);
+
+ pw->panner.knob_width = (Dimension)PANNER_HSCALE(pw, width);
+ pw->panner.knob_height = (Dimension)PANNER_VSCALE(pw, height);
+ }
+ if (!pw->panner.allow_off)
+ check_knob(pw, True);
+ move_shadow(pw);
+}
+
+static void
+rescale(PannerWidget pw)
+{
+ int hpad = pw->panner.internal_border << 1;
+ int vpad = hpad;
+
+ if (pw->panner.canvas_width < 1)
+ pw->panner.canvas_width = XtWidth(pw);
+ if (pw->panner.canvas_height < 1)
+ pw->panner.canvas_height = XtHeight(pw);
+
+ if (XtWidth(pw) <= hpad)
+ hpad = 0;
+ if (XtHeight(pw) <= vpad)
+ vpad = 0;
+
+ pw->panner.haspect = ((double)XtWidth(pw) - hpad + .5)
+ / (double)pw->panner.canvas_width;
+ pw->panner.vaspect = ((double)XtHeight(pw) - vpad + .5)
+ / (double)pw->panner.canvas_height;
+ scale_knob(pw, True, True);
+}
+
+static void
+get_default_size(PannerWidget pw, Dimension *wp, Dimension *hp)
+{
+ Dimension pad = pw->panner.internal_border << 1;
+
+ *wp = PANNER_DSCALE(pw, pw->panner.canvas_width) + pad;
+ *hp = PANNER_DSCALE(pw, pw->panner.canvas_height) + pad;
+}
+
+static Bool
+get_event_xy(PannerWidget pw, XEvent *event, int *x, int *y)
+{
+ int pad = pw->panner.internal_border;
+
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x - pad;
+ *y = event->xbutton.y - pad;
+ return (True);
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x - pad;
+ *y = event->xkey.y - pad;
+ return (True);
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x - pad;
+ *y = event->xcrossing.y - pad;
+ return (True);
+ case MotionNotify:
+ *x = event->xmotion.x - pad;
+ *y = event->xmotion.y - pad;
+ return (True);
+ }
+
+ return (False);
+}
+
+static int
+parse_page_string(char *s, int pagesize, int canvassize, Bool *relative)
+{
+ char *cp;
+ double val = 1.0;
+ Bool rel = False;
+
+ /*
+ * syntax: spaces [+-] number spaces [pc\0] spaces
+ */
+ for (; isascii(*s) && isspace(*s); s++) /* skip white space */
+ ;
+
+ if (*s == '+' || *s == '-') { /* deal with signs */
+ rel = True;
+ if (*s == '-')
+ val = -1.0;
+ s++;
+ }
+ if (!*s) { /* if null then return nothing */
+ *relative = True;
+ return (0);
+ }
+
+ /* skip over numbers */
+ for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++)
+ ;
+ val *= atof(cp);
+
+ /* skip blanks */
+ for (; isascii(*s) && isspace(*s); s++)
+ ;
+
+ if (*s) { /* if units */
+ switch (s[0]) {
+ case 'p':
+ case 'P':
+ val *= (double)pagesize;
+ break;
+ case 'c':
+ case 'C':
+ val *= (double)canvassize;
+ break;
+ }
+ }
+ *relative = rel;
+
+ return ((int)val);
+}
+
+#define DRAW_TMP(pw) \
+{ \
+ XDrawRectangle(XtDisplay(pw), XtWindow(pw), \
+ pw->panner.xor_gc, \
+ pw->panner.tmp.x + pw->panner.internal_border, \
+ pw->panner.tmp.y + pw->panner.internal_border, \
+ pw->panner.knob_width - 1, \
+ pw->panner.knob_height - 1); \
+ pw->panner.tmp.showing = !pw->panner.tmp.showing; \
+}
+
+#define UNDRAW_TMP(pw) \
+{ \
+ if (pw->panner.tmp.showing) \
+ DRAW_TMP(pw); \
+}
+
+#define BACKGROUND_STIPPLE(pw) \
+XmuLocatePixmapFile(pw->core.screen, pw->panner.stipple_name, \
+ pw->panner.shadow_color, pw->core.background_pixel, \
+ pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
+
+#define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
+
+/*ARGSUSED*/
+static void
+XawPannerInitialize(Widget greq, Widget gnew, ArgList args, Cardinal *num_args)
+{
+ PannerWidget req = (PannerWidget)greq, cnew = (PannerWidget)gnew;
+ Dimension defwidth, defheight;
+
+ if (req->panner.canvas_width < 1)
+ cnew->panner.canvas_width = 1;
+ if (req->panner.canvas_height < 1)
+ cnew->panner.canvas_height = 1;
+ if (req->panner.default_scale < 1)
+ cnew->panner.default_scale = PANNER_DEFAULT_SCALE;
+
+ get_default_size(req, &defwidth, &defheight);
+ if (XtWidth(req) < 1)
+ XtWidth(cnew) = defwidth;
+ if (XtHeight(req) < 1)
+ XtHeight(cnew) = defheight;
+
+ cnew->panner.shadow_gc = NULL;
+ reset_shadow_gc(cnew); /* shadowColor */
+ cnew->panner.slider_gc = NULL;
+ reset_slider_gc(cnew); /* foreground */
+ cnew->panner.xor_gc = NULL;
+ reset_xor_gc(cnew); /* foreground ^ background */
+
+ rescale(cnew); /* does a position check */
+ cnew->panner.shadow_valid = False;
+ cnew->panner.tmp.doing = False;
+ cnew->panner.tmp.showing = False;
+ }
+
+static void
+XawPannerRealize(Widget gw, XtValueMask *valuemaskp,
+ XSetWindowAttributes *attr)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ Pixmap pm = XtUnspecifiedPixmap;
+ Bool gotpm = False;
+
+ if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
+ if (pw->panner.stipple_name)
+ pm = BACKGROUND_STIPPLE(pw);
+
+ if (PIXMAP_OKAY(pm)) {
+ attr->background_pixmap = pm;
+ *valuemaskp |= CWBackPixmap;
+ *valuemaskp &= ~CWBackPixel;
+ gotpm = True;
+ }
+ }
+ (*pannerWidgetClass->core_class.superclass->core_class.realize)
+ (gw, valuemaskp, attr);
+
+ if (gotpm)
+ XFreePixmap(XtDisplay(gw), pm);
+}
+
+static void
+XawPannerDestroy(Widget gw)
+{
+ PannerWidget pw = (PannerWidget)gw;
+
+ XtReleaseGC(gw, pw->panner.shadow_gc);
+ XtReleaseGC(gw, pw->panner.slider_gc);
+ XtReleaseGC(gw, pw->panner.xor_gc);
+}
+
+static void
+XawPannerResize(Widget gw)
+{
+ rescale((PannerWidget)gw);
+}
+
+static void
+XawPannerRedisplay(Widget gw, XEvent *event, Region region)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ Display *dpy = XtDisplay(gw);
+ Window w = XtWindow(gw);
+ int pad = pw->panner.internal_border;
+ Dimension lw = pw->panner.line_width;
+ Dimension extra = pw->panner.shadow_thickness + (lw << 1);
+ int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
+
+ if (Superclass->core_class.expose)
+ (Superclass->core_class.expose)(gw, event, region);
+
+ pw->panner.tmp.showing = False;
+ XClearArea(XtDisplay(pw), XtWindow(pw),
+ (int)pw->panner.last_x - ((int)lw) + pad,
+ (int)pw->panner.last_y - ((int)lw) + pad,
+ pw->panner.knob_width + extra,
+ pw->panner.knob_height + extra,
+ False);
+ pw->panner.last_x = pw->panner.knob_x;
+ pw->panner.last_y = pw->panner.knob_y;
+
+ XFillRectangle(dpy, w, pw->panner.slider_gc, kx, ky,
+ pw->panner.knob_width - 1, pw->panner.knob_height - 1);
+
+ if (lw)
+ XDrawRectangle(dpy, w, pw->panner.shadow_gc, kx, ky,
+ pw->panner.knob_width - 1, pw->panner.knob_height - 1);
+
+ if (pw->panner.shadow_valid)
+ XFillRectangles(dpy, w, pw->panner.shadow_gc, pw->panner.shadow_rects, 2);
+
+ if (pw->panner.tmp.doing && pw->panner.rubber_band)
+ DRAW_TMP(pw);
+}
+
+/*ARGSUSED*/
+static Boolean
+XawPannerSetValues(Widget gcur, Widget greq, Widget gnew,
+ ArgList args, Cardinal *num_args)
+{
+ PannerWidget cur = (PannerWidget)gcur;
+ PannerWidget cnew = (PannerWidget)gnew;
+ Bool redisplay = False;
+
+ if (cur->panner.foreground != cnew->panner.foreground) {
+ reset_slider_gc(cnew);
+ if (cur->panner.foreground != cur->core.background_pixel)
+ reset_xor_gc(cnew);
+ redisplay = True;
+ }
+ else if (cur->panner.line_width != cnew->panner.line_width ||
+ cur->core.background_pixel != cnew->core.background_pixel) {
+ reset_xor_gc(cnew);
+ redisplay = True;
+ }
+ if (cur->panner.shadow_color != cnew->panner.shadow_color) {
+ reset_shadow_gc(cnew);
+ if (cur->panner.foreground == cur->core.background_pixel)
+ reset_xor_gc(cnew);
+ redisplay = True;
+ }
+ if (cur->panner.shadow_thickness != cnew->panner.shadow_thickness) {
+ move_shadow(cnew);
+ redisplay = True;
+ }
+ if (cur->panner.rubber_band != cnew->panner.rubber_band) {
+ reset_xor_gc(cnew);
+ if (cnew->panner.tmp.doing)
+ redisplay = True;
+ }
+
+ if ((cur->panner.stipple_name != cnew->panner.stipple_name
+ || cur->panner.shadow_color != cnew->panner.shadow_color
+ || cur->core.background_pixel != cnew->core.background_pixel)
+ && XtIsRealized(gnew)) {
+ Pixmap pm = cnew->panner.stipple_name ?
+ BACKGROUND_STIPPLE(cnew) : XtUnspecifiedPixmap;
+
+ if (PIXMAP_OKAY(pm)) {
+ XSetWindowBackgroundPixmap(XtDisplay(cnew), XtWindow(cnew), pm);
+ XFreePixmap(XtDisplay(cnew), pm);
+ }
+ else
+ XSetWindowBackground(XtDisplay(cnew), XtWindow(cnew),
+ cnew->core.background_pixel);
+
+ redisplay = True;
+ }
+
+ if (cnew->panner.resize_to_pref &&
+ (cur->panner.canvas_width != cnew->panner.canvas_width
+ || cur->panner.canvas_height != cnew->panner.canvas_height
+ || cur->panner.resize_to_pref != cnew->panner.resize_to_pref)) {
+ get_default_size(cnew, &cnew->core.width, &cnew->core.height);
+ redisplay = True;
+ }
+ else if (cur->panner.canvas_width != cnew->panner.canvas_width
+ || cur->panner.canvas_height != cnew->panner.canvas_height
+ || cur->panner.internal_border != cnew->panner.internal_border) {
+ rescale(cnew); /* does a scale_knob as well */
+ redisplay = True;
+ }
+ else {
+ Bool loc = cur->panner.slider_x != cnew->panner.slider_x ||
+ cur->panner.slider_y != cnew->panner.slider_y;
+ Bool siz = cur->panner.slider_width != cnew->panner.slider_width ||
+ cur->panner.slider_height != cnew->panner.slider_height;
+ if (loc || siz || (cur->panner.allow_off != cnew->panner.allow_off
+ && cnew->panner.allow_off)) {
+ scale_knob(cnew, loc, siz);
+ redisplay = True;
+ }
+ }
+
+ return (redisplay);
+}
+
+static void
+XawPannerSetValuesAlmost(Widget gold, Widget gnew, XtWidgetGeometry *req,
+ XtWidgetGeometry *reply)
+{
+ if (reply->request_mode == 0) /* got turned down, so cope */
+ XawPannerResize(gnew);
+
+ (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
+ (gold, gnew, req, reply);
+}
+
+static XtGeometryResult
+XawPannerQueryGeometry(Widget gw, XtWidgetGeometry *intended,
+ XtWidgetGeometry *pref)
+{
+ PannerWidget pw = (PannerWidget)gw;
+
+ pref->request_mode = (CWWidth | CWHeight);
+ get_default_size(pw, &pref->width, &pref->height);
+
+ if (((intended->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight))
+ && intended->width == pref->width && intended->height == pref->height)
+ return (XtGeometryYes);
+ else if (pref->width == XtWidth(pw) && pref->height == XtHeight(pw))
+ return (XtGeometryNo);
+
+ return (XtGeometryAlmost);
+}
+
+
+/*ARGSUSED*/
+static void
+ActionStart(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ int x, y;
+
+ if (!get_event_xy(pw, event, &x, &y)) {
+ XBell(XtDisplay(gw), 0);
+ return;
+ }
+
+ pw->panner.tmp.doing = True;
+ pw->panner.tmp.startx = pw->panner.knob_x;
+ pw->panner.tmp.starty = pw->panner.knob_y;
+ pw->panner.tmp.dx = x - pw->panner.knob_x;
+ pw->panner.tmp.dy = y - pw->panner.knob_y;
+ pw->panner.tmp.x = pw->panner.knob_x;
+ pw->panner.tmp.y = pw->panner.knob_y;
+ if (pw->panner.rubber_band)
+ DRAW_TMP(pw);
+}
+
+/*ARGSUSED*/
+static void
+ActionStop(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ int x, y;
+
+ if (get_event_xy(pw, event, &x, &y)) {
+ pw->panner.tmp.x = x - pw->panner.tmp.dx;
+ pw->panner.tmp.y = y - pw->panner.tmp.dy;
+ if (!pw->panner.allow_off)
+ check_knob(pw, False);
+ }
+ if (pw->panner.rubber_band)
+ DRAW_TMP(pw);
+ pw->panner.tmp.doing = False;
+}
+
+static void
+ActionAbort(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+
+ if (!pw->panner.tmp.doing)
+ return;
+
+ if (pw->panner.rubber_band)
+ UNDRAW_TMP(pw);
+
+ if (!pw->panner.rubber_band) { /* restore old position */
+ pw->panner.tmp.x = pw->panner.tmp.startx;
+ pw->panner.tmp.y = pw->panner.tmp.starty;
+ ActionNotify(gw, event, params, num_params);
+ }
+ pw->panner.tmp.doing = False;
+}
+
+static void
+ActionMove(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ int x, y;
+
+ if (!pw->panner.tmp.doing)
+ return;
+
+ if (!get_event_xy(pw, event, &x, &y)) {
+ XBell(XtDisplay(gw), 0); /* should do error message */
+ return;
+ }
+
+ if (pw->panner.rubber_band)
+ UNDRAW_TMP(pw);
+ pw->panner.tmp.x = x - pw->panner.tmp.dx;
+ pw->panner.tmp.y = y - pw->panner.tmp.dy;
+
+ if (!pw->panner.rubber_band)
+ ActionNotify(gw, event, params, num_params);
+ else {
+ if (!pw->panner.allow_off)
+ check_knob(pw, False);
+ DRAW_TMP(pw);
+ }
+}
+
+
+static void
+ActionPage(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ Cardinal zero = 0;
+ Bool isin = pw->panner.tmp.doing;
+ int x, y;
+ Bool relx, rely;
+ int pad = pw->panner.internal_border << 1;
+
+ if (*num_params != 2) {
+ XBell(XtDisplay(gw), 0);
+ return;
+ }
+
+ x = parse_page_string(params[0], pw->panner.knob_width,
+ (int)XtWidth(pw) - pad, &relx);
+ y = parse_page_string(params[1], pw->panner.knob_height,
+ (int)XtHeight(pw) - pad, &rely);
+
+ if (relx)
+ x += pw->panner.knob_x;
+ if (rely)
+ y += pw->panner.knob_y;
+
+ if (isin) { /* if in, then use move */
+ XEvent ev;
+
+ ev.xbutton.type = ButtonPress;
+ ev.xbutton.x = x;
+ ev.xbutton.y = y;
+ ActionMove(gw, &ev, NULL, &zero);
+ }
+ else {
+ pw->panner.tmp.doing = True;
+ pw->panner.tmp.x = x;
+ pw->panner.tmp.y = y;
+ ActionNotify(gw, event, NULL, &zero);
+ pw->panner.tmp.doing = False;
+ }
+}
+
+/*ARGSUSED*/
+static void
+ActionNotify(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+
+ if (!pw->panner.tmp.doing)
+ return;
+
+ if (!pw->panner.allow_off)
+ check_knob(pw, False);
+ pw->panner.knob_x = pw->panner.tmp.x;
+ pw->panner.knob_y = pw->panner.tmp.y;
+ move_shadow(pw);
+
+ pw->panner.slider_x = (Position)((double)pw->panner.knob_x
+ / pw->panner.haspect + 0.5);
+ pw->panner.slider_y = (Position)((double) pw->panner.knob_y
+ / pw->panner.vaspect + 0.5);
+ if (!pw->panner.allow_off) {
+ Position tmp;
+
+ if (pw->panner.slider_x
+ > (tmp = (Position)pw->panner.canvas_width -
+ (Position)pw->panner.slider_width))
+ pw->panner.slider_x = tmp;
+ if (pw->panner.slider_x < 0)
+ pw->panner.slider_x = 0;
+ if (pw->panner.slider_y
+ > (tmp = (Position)pw->panner.canvas_height -
+ (Position)pw->panner.slider_height))
+ pw->panner.slider_y = tmp;
+ if (pw->panner.slider_y < 0)
+ pw->panner.slider_y = 0;
+ }
+
+ if (pw->panner.last_x != pw->panner.knob_x ||
+ pw->panner.last_y != pw->panner.knob_y) {
+ XawPannerReport rep;
+
+ XawPannerRedisplay(gw, NULL, NULL);
+ rep.changed = XawPRSliderX | XawPRSliderY;
+ rep.slider_x = pw->panner.slider_x;
+ rep.slider_y = pw->panner.slider_y;
+ rep.slider_width = pw->panner.slider_width;
+ rep.slider_height = pw->panner.slider_height;
+ rep.canvas_width = pw->panner.canvas_width;
+ rep.canvas_height = pw->panner.canvas_height;
+ XtCallCallbackList(gw, pw->panner.report_callbacks, (XtPointer)&rep);
+ }
+}
+
+/*ARGSUSED*/
+static void
+ActionSet(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget)gw;
+ Bool rb;
+
+ if (*num_params < 2 ||
+ XmuCompareISOLatin1(params[0], "rubberband") != 0) {
+ XBell(XtDisplay(gw), 0);
+ return;
+ }
+
+ if (XmuCompareISOLatin1(params[1], "on") == 0)
+ rb = True;
+ else if (XmuCompareISOLatin1(params[1], "off") == 0)
+ rb = False;
+ else if (XmuCompareISOLatin1(params[1], "toggle") == 0)
+ rb = !pw->panner.rubber_band;
+ else {
+ XBell(XtDisplay(gw), 0);
+ return;
+ }
+
+ if (rb != pw->panner.rubber_band) {
+ Arg args[1];
+
+ XtSetArg(args[0], XtNrubberBand, rb);
+ XtSetValues(gw, args, 1);
+ }
+}
|