749N/A/*
749N/A * $XConsortium: Panner.c,v 1.49 94/04/17 20:12:31 kaleb Exp $
749N/A *
749N/ACopyright (c) 1989, 1994 X Consortium
749N/A
749N/APermission is hereby granted, free of charge, to any person obtaining a copy
749N/Aof this software and associated documentation files (the "Software"), to deal
749N/Ain the Software without restriction, including without limitation the rights
749N/Ato use, copy, modify, merge, publish, distribute, sublicense, and/or sell
749N/Acopies of the Software, and to permit persons to whom the Software is
749N/Afurnished to do so, subject to the following conditions:
749N/A
749N/AThe above copyright notice and this permission notice shall be included in
749N/Aall copies or substantial portions of the Software.
749N/A
749N/ATHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
749N/AIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
749N/AFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
749N/AX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
749N/AAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
749N/ACONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
749N/A
749N/AExcept as contained in this notice, the name of the X Consortium shall not be
749N/Aused in advertising or otherwise to promote the sale, use or other dealings
749N/Ain this Software without prior written authorization from the X Consortium.
749N/A *
749N/A * Author: Jim Fulton, MIT X Consortium
749N/A */
749N/A
749N/A#include <X11/IntrinsicP.h>
749N/A#include <X11/StringDefs.h> /* for XtN and XtC defines */
749N/A#include <X11/Xmu/CharSet.h> /* for XmuCompareISOLatin1() */
749N/A#include <X11/Xaw/XawInit.h> /* for XawInitializeWidgetSet */
749N/A#include <X11/Xaw/PannerP.h> /* us */
749N/A#include <X11/Xos.h>
749N/A#include <X11/Xmu/Misc.h> /* for Min */
749N/A#include <X11/Xmu/Drawing.h>
749N/A#include <ctype.h> /* for isascii() etc. */
749N/A#include <math.h> /* for atof() */
749N/A
749N/Aextern Bool XmuDistinguishablePixels(); /* not defined in any Xmu headers */
749N/A
749N/A#if defined(ISC) && defined(SYSV) && defined(SYSV386) && __STDC__
749N/Aextern double atof(char *);
749N/A#endif
749N/A
749N/Astatic char defaultTranslations[] =
749N/A "<Btn1Down>: start() \n\
749N/A <Btn1Motion>: move() \n\
749N/A <Btn1Up>: notify() stop() \n\
749N/A <Btn2Down>: abort() \n\
749N/A :<Key>KP_Enter: set(rubberband,toggle) \n\
749N/A <Key>space: page(+1p,+1p) \n\
749N/A <Key>Delete: page(-1p,-1p) \n\
749N/A :<Key>KP_Delete: page(-1p,-1p) \n\
749N/A <Key>BackSpace: page(-1p,-1p) \n\
749N/A <Key>Left: page(-.5p,+0) \n\
749N/A :<Key>KP_Left: page(-.5p,+0) \n\
749N/A <Key>Right: page(+.5p,+0) \n\
749N/A :<Key>KP_Right: page(+.5p,+0) \n\
749N/A <Key>Up: page(+0,-.5p) \n\
749N/A :<Key>KP_Up: page(+0,-.5p) \n\
749N/A <Key>Down: page(+0,+.5p) \n\
749N/A :<Key>KP_Down: page(+0,+.5p) \n\
749N/A <Key>Home: page(0,0) \n\
749N/A :<Key>KP_Home: page(0,0)";
749N/A
749N/A
749N/Astatic void ActionStart(), ActionStop(), ActionAbort(), ActionMove();
749N/Astatic void ActionPage(), ActionNotify(), ActionSet();
749N/A
749N/Astatic XtActionsRec actions[] = {
749N/A { "start", ActionStart }, /* start tmp graphics */
749N/A { "stop", ActionStop }, /* stop tmp graphics */
749N/A { "abort", ActionAbort }, /* punt */
749N/A { "move", ActionMove }, /* move tmp graphics on Motion event */
749N/A { "page", ActionPage }, /* page around usually from keyboard */
749N/A { "notify", ActionNotify }, /* callback new position */
749N/A { "set", ActionSet }, /* set various parameters */
749N/A};
749N/A
749N/A
749N/A/*
749N/A * resources for the panner
749N/A */
749N/Astatic XtResource resources[] = {
749N/A#define poff(field) XtOffsetOf(PannerRec, panner.field)
749N/A { XtNallowOff, XtCAllowOff, XtRBoolean, sizeof(Boolean),
749N/A poff(allow_off), XtRImmediate, (XtPointer) FALSE },
749N/A { XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
749N/A poff(resize_to_pref), XtRImmediate, (XtPointer) TRUE },
749N/A { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
749N/A poff(report_callbacks), XtRCallback, (XtPointer) NULL },
749N/A { XtNdefaultScale, XtCDefaultScale, XtRDimension, sizeof(Dimension),
749N/A poff(default_scale), XtRImmediate, (XtPointer) PANNER_DEFAULT_SCALE },
749N/A { XtNrubberBand, XtCRubberBand, XtRBoolean, sizeof(Boolean),
749N/A poff(rubber_band), XtRImmediate, (XtPointer) FALSE },
749N/A { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
749N/A poff(foreground), XtRString, (XtPointer) XtDefaultBackground },
749N/A { XtNinternalSpace, XtCInternalSpace, XtRDimension, sizeof(Dimension),
749N/A poff(internal_border), XtRImmediate, (XtPointer) 4 },
749N/A { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof(Dimension),
749N/A poff(line_width), XtRImmediate, (XtPointer) 0 },
749N/A { XtNcanvasWidth, XtCCanvasWidth, XtRDimension, sizeof(Dimension),
749N/A poff(canvas_width), XtRImmediate, (XtPointer) 0 },
749N/A { XtNcanvasHeight, XtCCanvasHeight, XtRDimension, sizeof(Dimension),
749N/A poff(canvas_height), XtRImmediate, (XtPointer) 0 },
749N/A { XtNsliderX, XtCSliderX, XtRPosition, sizeof(Position),
749N/A poff(slider_x), XtRImmediate, (XtPointer) 0 },
749N/A { XtNsliderY, XtCSliderY, XtRPosition, sizeof(Position),
749N/A poff(slider_y), XtRImmediate, (XtPointer) 0 },
749N/A { XtNsliderWidth, XtCSliderWidth, XtRDimension, sizeof(Dimension),
749N/A poff(slider_width), XtRImmediate, (XtPointer) 0 },
749N/A { XtNsliderHeight, XtCSliderHeight, XtRDimension, sizeof(Dimension),
749N/A poff(slider_height), XtRImmediate, (XtPointer) 0 },
749N/A { XtNshadowColor, XtCShadowColor, XtRPixel, sizeof(Pixel),
749N/A poff(shadow_color), XtRString, (XtPointer) XtDefaultForeground },
749N/A { XtNshadowThickness, XtCShadowThickness, XtRDimension, sizeof(Dimension),
749N/A poff(shadow_thickness), XtRImmediate, (XtPointer) 2 },
749N/A { XtNbackgroundStipple, XtCBackgroundStipple, XtRString, sizeof(String),
749N/A poff(stipple_name), XtRImmediate, (XtPointer) NULL },
749N/A#undef poff
749N/A};
749N/A
749N/A
749N/A/*
749N/A * widget class methods used below
749N/A */
749N/Astatic void Initialize(); /* create gc's */
749N/Astatic void Realize(); /* create window */
749N/Astatic void Destroy(); /* clean up widget */
749N/Astatic void Resize(); /* need to rescale ourselves */
749N/Astatic void Redisplay(); /* draw ourselves */
749N/Astatic Boolean SetValues(); /* set all of the resources */
749N/Astatic void SetValuesAlmost(); /* deal with failed setval geom req */
749N/Astatic XtGeometryResult QueryGeometry(); /* say how big we would like to be */
749N/A
749N/APannerClassRec pannerClassRec = {
749N/A { /* core fields */
749N/A /* superclass */ (WidgetClass) &simpleClassRec,
749N/A /* class_name */ "Panner",
749N/A /* widget_size */ sizeof(PannerRec),
749N/A /* class_initialize */ XawInitializeWidgetSet,
749N/A /* class_part_initialize */ NULL,
749N/A /* class_inited */ FALSE,
749N/A /* initialize */ Initialize,
749N/A /* initialize_hook */ NULL,
749N/A /* realize */ Realize,
749N/A /* actions */ actions,
749N/A /* num_actions */ XtNumber(actions),
749N/A /* resources */ resources,
749N/A /* num_resources */ XtNumber(resources),
749N/A /* xrm_class */ NULLQUARK,
749N/A /* compress_motion */ TRUE,
749N/A /* compress_exposure */ TRUE,
749N/A /* compress_enterleave */ TRUE,
749N/A /* visible_interest */ FALSE,
749N/A /* destroy */ Destroy,
749N/A /* resize */ Resize,
749N/A /* expose */ Redisplay,
749N/A /* set_values */ SetValues,
749N/A /* set_values_hook */ NULL,
749N/A /* set_values_almost */ SetValuesAlmost,
749N/A /* get_values_hook */ NULL,
749N/A /* accept_focus */ NULL,
749N/A /* version */ XtVersion,
749N/A /* callback_private */ NULL,
749N/A /* tm_table */ defaultTranslations,
749N/A /* query_geometry */ QueryGeometry,
749N/A /* display_accelerator */ XtInheritDisplayAccelerator,
749N/A /* extension */ NULL
749N/A },
749N/A { /* simple fields */
749N/A /* change_sensitive */ XtInheritChangeSensitive
749N/A },
749N/A { /* panner fields */
749N/A /* ignore */ 0
749N/A }
749N/A};
749N/A
749N/AWidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
749N/A
749N/A
749N/A/*****************************************************************************
749N/A * *
749N/A * panner utility routines *
749N/A * *
749N/A *****************************************************************************/
749N/A
749N/Astatic void reset_shadow_gc (pw) /* used when resources change */
749N/A PannerWidget pw;
749N/A{
749N/A XtGCMask valuemask = GCForeground;
749N/A XGCValues values;
749N/A unsigned long pixels[3];
749N/A
749N/A if (pw->panner.shadow_gc) XtReleaseGC ((Widget) pw, pw->panner.shadow_gc);
749N/A
749N/A pixels[0] = pw->panner.foreground;
749N/A pixels[1] = pw->core.background_pixel;
749N/A pixels[2] = pw->panner.shadow_color;
749N/A if (!pw->panner.stipple_name &&
749N/A !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
749N/A pixels, 3) &&
749N/A XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
749N/A pixels, 2))
749N/A {
749N/A valuemask = GCTile | GCFillStyle;
749N/A values.fill_style = FillTiled;
749N/A values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
749N/A pw->panner.foreground,
749N/A pw->core.background_pixel,
749N/A pw->core.depth);
749N/A }
749N/A else
749N/A {
749N/A if (!pw->panner.line_width &&
749N/A !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
749N/A pixels, 2))
749N/A pw->panner.line_width = 1;
749N/A valuemask = GCForeground;
749N/A values.foreground = pw->panner.shadow_color;
749N/A }
749N/A if (pw->panner.line_width > 0) {
749N/A values.line_width = pw->panner.line_width;
749N/A valuemask |= GCLineWidth;
749N/A }
749N/A
749N/A pw->panner.shadow_gc = XtGetGC ((Widget) pw, valuemask, &values);
749N/A}
749N/A
749N/Astatic void reset_slider_gc (pw) /* used when resources change */
749N/A PannerWidget pw;
749N/A{
749N/A XtGCMask valuemask = GCForeground;
749N/A XGCValues values;
749N/A
749N/A if (pw->panner.slider_gc) XtReleaseGC ((Widget) pw, pw->panner.slider_gc);
749N/A
749N/A values.foreground = pw->panner.foreground;
749N/A
749N/A pw->panner.slider_gc = XtGetGC ((Widget) pw, valuemask, &values);
749N/A}
749N/A
749N/Astatic void reset_xor_gc (pw) /* used when resources change */
749N/A PannerWidget pw;
749N/A{
749N/A if (pw->panner.xor_gc) XtReleaseGC ((Widget) pw, pw->panner.xor_gc);
749N/A
749N/A if (pw->panner.rubber_band) {
749N/A XtGCMask valuemask = (GCForeground | GCFunction);
749N/A XGCValues values;
749N/A Pixel tmp;
749N/A
749N/A tmp = ((pw->panner.foreground == pw->core.background_pixel) ?
749N/A pw->panner.shadow_color : pw->panner.foreground);
749N/A values.foreground = tmp ^ pw->core.background_pixel;
749N/A values.function = GXxor;
749N/A if (pw->panner.line_width > 0) {
749N/A valuemask |= GCLineWidth;
749N/A values.line_width = pw->panner.line_width;
749N/A }
749N/A pw->panner.xor_gc = XtGetGC ((Widget) pw, valuemask, &values);
749N/A } else {
749N/A pw->panner.xor_gc = NULL;
749N/A }
749N/A}
749N/A
749N/A
749N/Astatic void check_knob (pw, knob)
749N/A PannerWidget pw;
749N/A Boolean knob;
749N/A{
749N/A Position pad = pw->panner.internal_border * 2;
749N/A Position maxx = (((Position) pw->core.width) - pad -
749N/A ((Position) pw->panner.knob_width));
749N/A Position maxy = (((Position) pw->core.height) - pad -
749N/A ((Position) pw->panner.knob_height));
749N/A Position *x = (knob ? &pw->panner.knob_x : &pw->panner.tmp.x);
749N/A Position *y = (knob ? &pw->panner.knob_y : &pw->panner.tmp.y);
749N/A
749N/A /*
749N/A * note that positions are already normalized (i.e. internal_border
749N/A * has been subtracted out)
749N/A */
749N/A if (*x < 0) *x = 0;
749N/A if (*x > maxx) *x = maxx;
749N/A
749N/A if (*y < 0) *y = 0;
749N/A if (*y > maxy) *y = maxy;
749N/A
749N/A if (knob) {
749N/A pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
749N/A pw->panner.haspect + 0.5);
749N/A pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
749N/A pw->panner.vaspect + 0.5);
749N/A pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
749N/A }
749N/A}
749N/A
749N/A
749N/Astatic void move_shadow (pw)
749N/A PannerWidget pw;
749N/A{
749N/A if (pw->panner.shadow_thickness > 0) {
749N/A int lw = pw->panner.shadow_thickness + pw->panner.line_width * 2;
749N/A int pad = pw->panner.internal_border;
749N/A
749N/A if ((int)pw->panner.knob_height > lw && (int)pw->panner.knob_width > lw) {
749N/A XRectangle *r = pw->panner.shadow_rects;
749N/A r->x = (short) (pw->panner.knob_x + pad + pw->panner.knob_width);
749N/A r->y = (short) (pw->panner.knob_y + pad + lw);
749N/A r->width = pw->panner.shadow_thickness;
749N/A r->height = (unsigned short) (pw->panner.knob_height - lw);
749N/A r++;
749N/A r->x = (short) (pw->panner.knob_x + pad + lw);
749N/A r->y = (short) (pw->panner.knob_y + pad + pw->panner.knob_height);
749N/A r->width = (unsigned short) (pw->panner.knob_width - lw +
749N/A pw->panner.shadow_thickness);
749N/A r->height = pw->panner.shadow_thickness;
749N/A pw->panner.shadow_valid = TRUE;
749N/A return;
749N/A }
749N/A }
749N/A pw->panner.shadow_valid = FALSE;
749N/A}
749N/A
749N/Astatic void scale_knob (pw, location, size) /* set knob size and/or loc */
749N/A PannerWidget pw;
749N/A Boolean location, size;
749N/A{
749N/A if (location) {
749N/A pw->panner.knob_x = (Position) PANNER_HSCALE (pw, pw->panner.slider_x);
749N/A pw->panner.knob_y = (Position) PANNER_VSCALE (pw, pw->panner.slider_y);
749N/A }
749N/A if (size) {
749N/A Dimension width, height;
749N/A
749N/A if (pw->panner.slider_width < 1) {
749N/A pw->panner.slider_width = pw->panner.canvas_width;
749N/A }
749N/A if (pw->panner.slider_height < 1) {
749N/A pw->panner.slider_height = pw->panner.canvas_height;
749N/A }
749N/A width = Min (pw->panner.slider_width, pw->panner.canvas_width);
749N/A height = Min (pw->panner.slider_height, pw->panner.canvas_height);
749N/A
749N/A pw->panner.knob_width = (Dimension) PANNER_HSCALE (pw, width);
749N/A pw->panner.knob_height = (Dimension) PANNER_VSCALE (pw, height);
749N/A }
749N/A if (!pw->panner.allow_off) check_knob (pw, TRUE);
749N/A move_shadow (pw);
749N/A}
749N/A
749N/Astatic void rescale (pw)
749N/A PannerWidget pw;
749N/A{
749N/A int hpad = pw->panner.internal_border * 2;
749N/A int vpad = hpad;
749N/A
749N/A if (pw->panner.canvas_width < 1)
749N/A pw->panner.canvas_width = pw->core.width;
749N/A if (pw->panner.canvas_height < 1)
749N/A pw->panner.canvas_height = pw->core.height;
749N/A
749N/A if ((int)pw->core.width <= hpad) hpad = 0;
749N/A if ((int)pw->core.height <= vpad) vpad = 0;
749N/A
749N/A pw->panner.haspect = ((double) pw->core.width - hpad) /
749N/A (double) pw->panner.canvas_width;
749N/A pw->panner.vaspect = ((double) pw->core.height - vpad) /
749N/A (double) pw->panner.canvas_height;
749N/A scale_knob (pw, TRUE, TRUE);
749N/A}
749N/A
749N/A
749N/Astatic void get_default_size (pw, wp, hp)
749N/A PannerWidget pw;
749N/A Dimension *wp, *hp;
749N/A{
749N/A Dimension pad = pw->panner.internal_border * 2;
749N/A *wp = PANNER_DSCALE (pw, pw->panner.canvas_width) + pad;
749N/A *hp = PANNER_DSCALE (pw, pw->panner.canvas_height) + pad;
749N/A}
749N/A
749N/Astatic Boolean get_event_xy (pw, event, x, y)
749N/A PannerWidget pw;
749N/A XEvent *event;
749N/A int *x, *y;
749N/A{
749N/A int pad = pw->panner.internal_border;
749N/A
749N/A switch (event->type) {
749N/A case ButtonPress:
749N/A case ButtonRelease:
749N/A *x = event->xbutton.x - pad;
749N/A *y = event->xbutton.y - pad;
749N/A return TRUE;
749N/A
749N/A case KeyPress:
749N/A case KeyRelease:
749N/A *x = event->xkey.x - pad;
749N/A *y = event->xkey.y - pad;
749N/A return TRUE;
749N/A
749N/A case EnterNotify:
749N/A case LeaveNotify:
749N/A *x = event->xcrossing.x - pad;
749N/A *y = event->xcrossing.y - pad;
749N/A return TRUE;
749N/A
749N/A case MotionNotify:
749N/A *x = event->xmotion.x - pad;
749N/A *y = event->xmotion.y - pad;
749N/A return TRUE;
749N/A }
749N/A
749N/A return FALSE;
749N/A}
749N/A
749N/Astatic int parse_page_string (s, pagesize, canvassize, relative)
749N/A char *s;
749N/A int pagesize, canvassize;
749N/A Boolean *relative;
749N/A{
749N/A char *cp;
749N/A double val = 1.0;
749N/A Boolean rel = FALSE;
749N/A
749N/A /*
749N/A * syntax: spaces [+-] number spaces [pc\0] spaces
749N/A */
749N/A
749N/A for (; isascii(*s) && isspace(*s); s++) ; /* skip white space */
749N/A
749N/A if (*s == '+' || *s == '-') { /* deal with signs */
749N/A rel = TRUE;
749N/A if (*s == '-') val = -1.0;
749N/A s++;
749N/A }
749N/A if (!*s) { /* if null then return nothing */
749N/A *relative = TRUE;
749N/A return 0;
749N/A }
749N/A
749N/A /* skip over numbers */
749N/A for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
749N/A val *= atof (cp);
749N/A
749N/A /* skip blanks */
749N/A for (; isascii(*s) && isspace(*s); s++) ;
749N/A
749N/A if (*s) { /* if units */
749N/A switch (s[0]) {
749N/A case 'p': case 'P':
749N/A val *= (double) pagesize;
749N/A break;
749N/A
749N/A case 'c': case 'C':
749N/A val *= (double) canvassize;
749N/A break;
749N/A }
749N/A }
749N/A *relative = rel;
749N/A return ((int) val);
749N/A}
749N/A
749N/A
749N/A#define DRAW_TMP(pw) \
749N/A{ \
749N/A XDrawRectangle (XtDisplay(pw), XtWindow(pw), \
749N/A pw->panner.xor_gc, \
749N/A (int) (pw->panner.tmp.x + pw->panner.internal_border), \
749N/A (int) (pw->panner.tmp.y + pw->panner.internal_border), \
749N/A (unsigned int) (pw->panner.knob_width - 1), \
749N/A (unsigned int) (pw->panner.knob_height - 1)); \
749N/A pw->panner.tmp.showing = !pw->panner.tmp.showing; \
749N/A}
749N/A
749N/A#define UNDRAW_TMP(pw) \
749N/A{ \
749N/A if (pw->panner.tmp.showing) DRAW_TMP(pw); \
749N/A}
749N/A
749N/A#define BACKGROUND_STIPPLE(pw) \
749N/A XmuLocatePixmapFile (pw->core.screen, pw->panner.stipple_name, \
749N/A pw->panner.shadow_color, pw->core.background_pixel, \
749N/A pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
749N/A
749N/A#define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
749N/A
749N/A
749N/A/*****************************************************************************
749N/A * *
749N/A * panner class methods *
749N/A * *
749N/A *****************************************************************************/
749N/A
749N/A
749N/A/*ARGSUSED*/
749N/Astatic void Initialize (greq, gnew, args, num_args)
749N/A Widget greq, gnew;
749N/A ArgList args;
749N/A Cardinal *num_args;
749N/A{
749N/A PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
749N/A Dimension defwidth, defheight;
749N/A
749N/A if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
749N/A if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
749N/A if (req->panner.default_scale < 1)
749N/A new->panner.default_scale = PANNER_DEFAULT_SCALE;
749N/A
749N/A get_default_size (req, &defwidth, &defheight);
749N/A if (req->core.width < 1) new->core.width = defwidth;
749N/A if (req->core.height < 1) new->core.height = defheight;
749N/A
749N/A new->panner.shadow_gc = NULL;
749N/A reset_shadow_gc (new); /* shadowColor */
749N/A new->panner.slider_gc = NULL;
749N/A reset_slider_gc (new); /* foreground */
749N/A new->panner.xor_gc = NULL;
749N/A reset_xor_gc (new); /* foreground ^ background */
749N/A
749N/A rescale (new); /* does a position check */
749N/A new->panner.shadow_valid = FALSE;
749N/A new->panner.tmp.doing = FALSE;
749N/A new->panner.tmp.showing = FALSE;
749N/A}
749N/A
749N/A
749N/Astatic void Realize (gw, valuemaskp, attr)
749N/A Widget gw;
749N/A XtValueMask *valuemaskp;
749N/A XSetWindowAttributes *attr;
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A Pixmap pm = XtUnspecifiedPixmap;
749N/A Boolean gotpm = FALSE;
749N/A
749N/A if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
749N/A if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
749N/A
749N/A if (PIXMAP_OKAY(pm)) {
749N/A attr->background_pixmap = pm;
749N/A *valuemaskp |= CWBackPixmap;
749N/A *valuemaskp &= ~CWBackPixel;
749N/A gotpm = TRUE;
749N/A }
749N/A }
749N/A (*pannerWidgetClass->core_class.superclass->core_class.realize)
749N/A (gw, valuemaskp, attr);
749N/A
749N/A if (gotpm) XFreePixmap (XtDisplay(gw), pm);
749N/A}
749N/A
749N/A
749N/Astatic void Destroy (gw)
749N/A Widget gw;
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A
749N/A XtReleaseGC (gw, pw->panner.shadow_gc);
749N/A XtReleaseGC (gw, pw->panner.slider_gc);
749N/A XtReleaseGC (gw, pw->panner.xor_gc);
749N/A}
749N/A
749N/A
749N/Astatic void Resize (gw)
749N/A Widget gw;
749N/A{
749N/A rescale ((PannerWidget) gw);
749N/A}
749N/A
749N/A
749N/A/* ARGSUSED */
749N/Astatic void Redisplay (gw, event, region)
749N/A Widget gw;
749N/A XEvent *event;
749N/A Region region;
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A Display *dpy = XtDisplay(gw);
749N/A Window w = XtWindow(gw);
749N/A int pad = pw->panner.internal_border;
749N/A Dimension lw = pw->panner.line_width;
749N/A Dimension extra = pw->panner.shadow_thickness + lw * 2;
749N/A int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
749N/A
749N/A pw->panner.tmp.showing = FALSE;
749N/A XClearArea (XtDisplay(pw), XtWindow(pw),
749N/A (int) pw->panner.last_x - ((int) lw) + pad,
749N/A (int) pw->panner.last_y - ((int) lw) + pad,
749N/A (unsigned int) (pw->panner.knob_width + extra),
749N/A (unsigned int) (pw->panner.knob_height + extra),
749N/A False);
749N/A pw->panner.last_x = pw->panner.knob_x;
749N/A pw->panner.last_y = pw->panner.knob_y;
749N/A
749N/A XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
749N/A pw->panner.knob_width - 1, pw->panner.knob_height - 1);
749N/A
749N/A if (lw)
749N/A {
749N/A XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
749N/A (unsigned int) (pw->panner.knob_width - 1),
749N/A (unsigned int) (pw->panner.knob_height - 1));
749N/A }
749N/A
749N/A if (pw->panner.shadow_valid) {
749N/A XFillRectangles (dpy, w, pw->panner.shadow_gc,
749N/A pw->panner.shadow_rects, 2);
749N/A }
749N/A if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
749N/A}
749N/A
749N/A
749N/A/* ARGSUSED */
749N/Astatic Boolean SetValues (gcur, greq, gnew, args, num_args)
749N/A Widget gcur, greq, gnew;
749N/A ArgList args;
749N/A Cardinal *num_args;
749N/A{
749N/A PannerWidget cur = (PannerWidget) gcur;
749N/A PannerWidget new = (PannerWidget) gnew;
749N/A Boolean redisplay = FALSE;
749N/A
749N/A if (cur->panner.foreground != new->panner.foreground) {
749N/A reset_slider_gc (new);
749N/A if (cur->panner.foreground != cur->core.background_pixel)
749N/A reset_xor_gc (new);
749N/A redisplay = TRUE;
749N/A } else if (cur->panner.line_width != new->panner.line_width ||
749N/A cur->core.background_pixel != new->core.background_pixel) {
749N/A reset_xor_gc (new);
749N/A redisplay = TRUE;
749N/A }
749N/A if (cur->panner.shadow_color != new->panner.shadow_color) {
749N/A reset_shadow_gc (new);
749N/A if (cur->panner.foreground == cur->core.background_pixel)
749N/A reset_xor_gc (new);
749N/A redisplay = TRUE;
749N/A }
749N/A if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
749N/A move_shadow (new);
749N/A redisplay = TRUE;
749N/A }
749N/A if (cur->panner.rubber_band != new->panner.rubber_band) {
749N/A reset_xor_gc (new);
749N/A if (new->panner.tmp.doing) redisplay = TRUE;
749N/A }
749N/A
749N/A if ((cur->panner.stipple_name != new->panner.stipple_name ||
749N/A cur->panner.shadow_color != new->panner.shadow_color ||
749N/A cur->core.background_pixel != new->core.background_pixel) &&
749N/A XtIsRealized(gnew)) {
749N/A Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
749N/A : XtUnspecifiedPixmap);
749N/A
749N/A if (PIXMAP_OKAY(pm)) {
749N/A XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
749N/A XFreePixmap (XtDisplay (new), pm);
749N/A } else {
749N/A XSetWindowBackground (XtDisplay (new), XtWindow(new),
749N/A new->core.background_pixel);
749N/A }
749N/A redisplay = TRUE;
749N/A }
749N/A
749N/A if (new->panner.resize_to_pref &&
749N/A (cur->panner.canvas_width != new->panner.canvas_width ||
749N/A cur->panner.canvas_height != new->panner.canvas_height ||
749N/A cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
749N/A get_default_size (new, &new->core.width, &new->core.height);
749N/A redisplay = TRUE;
749N/A } else if (cur->panner.canvas_width != new->panner.canvas_width ||
749N/A cur->panner.canvas_height != new->panner.canvas_height ||
749N/A cur->panner.internal_border != new->panner.internal_border) {
749N/A rescale (new); /* does a scale_knob as well */
749N/A redisplay = TRUE;
749N/A } else {
749N/A Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
749N/A cur->panner.slider_y != new->panner.slider_y);
749N/A Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
749N/A cur->panner.slider_height != new->panner.slider_height);
749N/A if (loc || siz ||
749N/A (cur->panner.allow_off != new->panner.allow_off &&
749N/A new->panner.allow_off)) {
749N/A scale_knob (new, loc, siz);
749N/A redisplay = TRUE;
749N/A }
749N/A }
749N/A
749N/A return redisplay;
749N/A}
749N/A
749N/Astatic void SetValuesAlmost (gold, gnew, req, reply)
749N/A Widget gold, gnew;
749N/A XtWidgetGeometry *req, *reply;
749N/A{
749N/A if (reply->request_mode == 0) { /* got turned down, so cope */
749N/A Resize (gnew);
749N/A }
749N/A (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
749N/A (gold, gnew, req, reply);
749N/A}
749N/A
749N/Astatic XtGeometryResult QueryGeometry (gw, intended, pref)
749N/A Widget gw;
749N/A XtWidgetGeometry *intended, *pref;
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A
749N/A pref->request_mode = (CWWidth | CWHeight);
749N/A get_default_size (pw, &pref->width, &pref->height);
749N/A
749N/A if (((intended->request_mode & (CWWidth | CWHeight)) ==
749N/A (CWWidth | CWHeight)) &&
749N/A intended->width == pref->width &&
749N/A intended->height == pref->height)
749N/A return XtGeometryYes;
749N/A else if (pref->width == pw->core.width && pref->height == pw->core.height)
749N/A return XtGeometryNo;
749N/A else
749N/A return XtGeometryAlmost;
749N/A}
749N/A
749N/A
749N/A/*****************************************************************************
749N/A * *
749N/A * panner action procs *
749N/A * *
749N/A *****************************************************************************/
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionStart (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event;
749N/A String *params; /* unused */
749N/A Cardinal *num_params; /* unused */
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A int x, y;
749N/A
749N/A if (!get_event_xy (pw, event, &x, &y)) {
749N/A XBell (XtDisplay(gw), 0); /* should do error message */
749N/A return;
749N/A }
749N/A
749N/A pw->panner.tmp.doing = TRUE;
749N/A pw->panner.tmp.startx = pw->panner.knob_x;
749N/A pw->panner.tmp.starty = pw->panner.knob_y;
749N/A pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
749N/A pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
749N/A pw->panner.tmp.x = pw->panner.knob_x;
749N/A pw->panner.tmp.y = pw->panner.knob_y;
749N/A if (pw->panner.rubber_band) DRAW_TMP (pw);
749N/A}
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionStop (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event;
749N/A String *params; /* unused */
749N/A Cardinal *num_params; /* unused */
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A int x, y;
749N/A
749N/A if (get_event_xy (pw, event, &x, &y)) {
749N/A pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
749N/A pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
749N/A if (!pw->panner.allow_off) check_knob (pw, FALSE);
749N/A }
749N/A if (pw->panner.rubber_band) UNDRAW_TMP (pw);
749N/A pw->panner.tmp.doing = FALSE;
749N/A}
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionAbort (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event;
749N/A String *params; /* unused */
749N/A Cardinal *num_params; /* unused */
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A
749N/A if (!pw->panner.tmp.doing) return;
749N/A
749N/A if (pw->panner.rubber_band) UNDRAW_TMP (pw);
749N/A
749N/A if (!pw->panner.rubber_band) { /* restore old position */
749N/A pw->panner.tmp.x = pw->panner.tmp.startx;
749N/A pw->panner.tmp.y = pw->panner.tmp.starty;
749N/A ActionNotify (gw, event, params, num_params);
749N/A }
749N/A pw->panner.tmp.doing = FALSE;
749N/A}
749N/A
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionMove (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event; /* must be a motion event */
749N/A String *params; /* unused */
749N/A Cardinal *num_params; /* unused */
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A int x, y;
749N/A
749N/A if (!pw->panner.tmp.doing) return;
749N/A
749N/A if (!get_event_xy (pw, event, &x, &y)) {
749N/A XBell (XtDisplay(gw), 0); /* should do error message */
749N/A return;
749N/A }
749N/A
749N/A if (pw->panner.rubber_band) UNDRAW_TMP (pw);
749N/A pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
749N/A pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
749N/A
749N/A if (!pw->panner.rubber_band) {
749N/A ActionNotify (gw, event, params, num_params); /* does a check */
749N/A } else {
749N/A if (!pw->panner.allow_off) check_knob (pw, FALSE);
749N/A DRAW_TMP (pw);
749N/A }
749N/A}
749N/A
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionPage (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event; /* unused */
749N/A String *params;
749N/A Cardinal *num_params; /* unused */
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A Cardinal zero = 0;
749N/A Boolean isin = pw->panner.tmp.doing;
749N/A int x, y;
749N/A Boolean relx, rely;
749N/A int pad = pw->panner.internal_border * 2;
749N/A
749N/A if (*num_params != 2) {
749N/A XBell (XtDisplay(gw), 0);
749N/A return;
749N/A }
749N/A
749N/A x = parse_page_string (params[0], (int) pw->panner.knob_width,
749N/A ((int) pw->core.width) - pad, &relx);
749N/A y = parse_page_string (params[1], (int) pw->panner.knob_height,
749N/A ((int) pw->core.height) - pad, &rely);
749N/A
749N/A if (relx) x += pw->panner.knob_x;
749N/A if (rely) y += pw->panner.knob_y;
749N/A
749N/A if (isin) { /* if in, then use move */
749N/A XEvent ev;
749N/A ev.xbutton.type = ButtonPress;
749N/A ev.xbutton.x = x;
749N/A ev.xbutton.y = y;
749N/A ActionMove (gw, &ev, (String *) NULL, &zero);
749N/A } else { /* else just do it */
749N/A pw->panner.tmp.doing = TRUE;
749N/A pw->panner.tmp.x = x;
749N/A pw->panner.tmp.y = y;
749N/A ActionNotify (gw, event, (String *) NULL, &zero);
749N/A pw->panner.tmp.doing = FALSE;
749N/A }
749N/A}
749N/A
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionNotify (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event; /* unused */
749N/A String *params; /* unused */
749N/A Cardinal *num_params; /* unused */
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A
749N/A if (!pw->panner.tmp.doing) return;
749N/A
749N/A if (!pw->panner.allow_off) check_knob (pw, FALSE);
749N/A pw->panner.knob_x = pw->panner.tmp.x;
749N/A pw->panner.knob_y = pw->panner.tmp.y;
749N/A move_shadow (pw);
749N/A
749N/A pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
749N/A pw->panner.haspect + 0.5);
749N/A pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
749N/A pw->panner.vaspect + 0.5);
749N/A if (!pw->panner.allow_off) {
749N/A Position tmp;
749N/A
749N/A if (pw->panner.slider_x >
749N/A (tmp = (((Position) pw->panner.canvas_width) -
749N/A ((Position) pw->panner.slider_width))))
749N/A pw->panner.slider_x = tmp;
749N/A if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
749N/A if (pw->panner.slider_y >
749N/A (tmp = (((Position) pw->panner.canvas_height) -
749N/A ((Position) pw->panner.slider_height))))
749N/A pw->panner.slider_y = tmp;
749N/A if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
749N/A }
749N/A
749N/A if (pw->panner.last_x != pw->panner.knob_x ||
749N/A pw->panner.last_y != pw->panner.knob_y) {
749N/A XawPannerReport rep;
749N/A
749N/A Redisplay (gw, (XEvent*) NULL, (Region) NULL);
749N/A rep.changed = (XawPRSliderX | XawPRSliderY);
749N/A rep.slider_x = pw->panner.slider_x;
749N/A rep.slider_y = pw->panner.slider_y;
749N/A rep.slider_width = pw->panner.slider_width;
749N/A rep.slider_height = pw->panner.slider_height;
749N/A rep.canvas_width = pw->panner.canvas_width;
749N/A rep.canvas_height = pw->panner.canvas_height;
749N/A XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
749N/A }
749N/A}
749N/A
749N/A/* ARGSUSED */
749N/Astatic void ActionSet (gw, event, params, num_params)
749N/A Widget gw;
749N/A XEvent *event; /* unused */
749N/A String *params;
749N/A Cardinal *num_params;
749N/A{
749N/A PannerWidget pw = (PannerWidget) gw;
749N/A Boolean rb;
749N/A
749N/A if (*num_params < 2 ||
749N/A XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
749N/A XBell (XtDisplay(gw), 0);
749N/A return;
749N/A }
749N/A
749N/A if (XmuCompareISOLatin1 (params[1], "on") == 0) {
749N/A rb = TRUE;
749N/A } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
749N/A rb = FALSE;
749N/A } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
749N/A rb = !pw->panner.rubber_band;
749N/A } else {
749N/A XBell (XtDisplay(gw), 0);
749N/A return;
749N/A }
749N/A
749N/A if (rb != pw->panner.rubber_band) {
749N/A Arg args[1];
749N/A XtSetArg (args[0], XtNrubberBand, rb);
749N/A XtSetValues (gw, args, (Cardinal) 1);
749N/A }
749N/A}