home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Panner.c.orig < prev    next >
Encoding:
Text File  |  1991-08-26  |  28.9 KB  |  939 lines

  1. /*
  2.  * $XConsortium: Panner.c,v 1.43 91/08/26 10:53:17 gildea Exp $
  3.  *
  4.  * Copyright 1989 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Jim Fulton, MIT X Consortium
  24.  */
  25.  
  26. #include <X11/IntrinsicP.h>        /* for toolkit routines */
  27. #include <X11/StringDefs.h>        /* for XtN and XtC defines */
  28. #include <X11/Xmu/CharSet.h>        /* for XmuCompareISOLatin1() */
  29. #include <X11/Xaw/XawInit.h>        /* for XawInitializeWidgetSet */
  30. #include <X11/Xaw/PannerP.h>        /* us */
  31. #include <X11/Xmu/Misc.h>        /* for Min */
  32. #include <ctype.h>            /* for isascii() etc. */
  33. #include <math.h>            /* for atof() */
  34.  
  35. #if defined(ISC) && defined(SYSV) && defined(SYSV386) && __STDC__
  36. extern double atof(char *);
  37. #endif
  38.  
  39. static char defaultTranslations[] = 
  40.   "<Btn1Down>:    start() \n\
  41.    <Btn1Motion>:  move() \n\
  42.    <Btn1Up>:      notify() stop() \n\
  43.    <Btn2Down>:    abort() \n\
  44.    <Key>KP_Enter: set(rubberband,toggle) \n\
  45.    <Key>space:    page(+1p,+1p) \n\
  46.    <Key>Delete:   page(-1p,-1p) \n\
  47.    <Key>BackSpace:  page(-1p,-1p) \n\
  48.    <Key>Left:     page(-.5p,+0) \n\
  49.    <Key>Right:    page(+.5p,+0) \n\
  50.    <Key>Up:       page(+0,-.5p) \n\
  51.    <Key>Down:     page(+0,+.5p) \n\
  52.    <Key>Home:     page(0,0) ";
  53.  
  54.  
  55. static void ActionStart(), ActionStop(), ActionAbort(), ActionMove();
  56. static void ActionPage(), ActionNotify(), ActionSet();
  57.  
  58. static XtActionsRec actions[] = {
  59.     { "start", ActionStart },        /* start tmp graphics */
  60.     { "stop", ActionStop },        /* stop tmp graphics */
  61.     { "abort", ActionAbort },        /* punt */
  62.     { "move", ActionMove },        /* move tmp graphics on Motion event */
  63.     { "page", ActionPage },        /* page around usually from keyboard */
  64.     { "notify", ActionNotify },        /* callback new position */
  65.     { "set", ActionSet },        /* set various parameters */
  66. };
  67.  
  68.  
  69. /*
  70.  * resources for the panner
  71.  */
  72. static XtResource resources[] = {
  73. #define poff(field) XtOffsetOf(PannerRec, panner.field)
  74.     { XtNallowOff, XtCAllowOff, XtRBoolean, sizeof(Boolean),
  75.     poff(allow_off), XtRImmediate, (XtPointer) FALSE },
  76.     { XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
  77.     poff(resize_to_pref), XtRImmediate, (XtPointer) TRUE },
  78.     { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
  79.     poff(report_callbacks), XtRCallback, (XtPointer) NULL },
  80.     { XtNdefaultScale, XtCDefaultScale, XtRDimension, sizeof(Dimension),
  81.     poff(default_scale), XtRImmediate, (XtPointer) PANNER_DEFAULT_SCALE },
  82.     { XtNrubberBand, XtCRubberBand, XtRBoolean, sizeof(Boolean),
  83.     poff(rubber_band), XtRImmediate, (XtPointer) FALSE },
  84.     { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 
  85.     poff(foreground), XtRString, (XtPointer) XtDefaultBackground },
  86.     { XtNinternalSpace, XtCInternalSpace, XtRDimension, sizeof(Dimension),
  87.     poff(internal_border), XtRImmediate, (XtPointer) 4 },
  88.     { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof(Dimension),
  89.     poff(line_width), XtRImmediate, (XtPointer) 0 },
  90.     { XtNcanvasWidth, XtCCanvasWidth, XtRDimension, sizeof(Dimension),
  91.     poff(canvas_width), XtRImmediate, (XtPointer) 0 },
  92.     { XtNcanvasHeight, XtCCanvasHeight, XtRDimension, sizeof(Dimension),
  93.     poff(canvas_height), XtRImmediate, (XtPointer) 0 },
  94.     { XtNsliderX, XtCSliderX, XtRPosition, sizeof(Position),
  95.     poff(slider_x), XtRImmediate, (XtPointer) 0 },
  96.     { XtNsliderY, XtCSliderY, XtRPosition, sizeof(Position),
  97.     poff(slider_y), XtRImmediate, (XtPointer) 0 },
  98.     { XtNsliderWidth, XtCSliderWidth, XtRDimension, sizeof(Dimension),
  99.     poff(slider_width), XtRImmediate, (XtPointer) 0 },
  100.     { XtNsliderHeight, XtCSliderHeight, XtRDimension, sizeof(Dimension),
  101.     poff(slider_height), XtRImmediate, (XtPointer) 0 },
  102.     { XtNshadowColor, XtCShadowColor, XtRPixel, sizeof(Pixel),
  103.     poff(shadow_color), XtRString, (XtPointer) XtDefaultForeground },
  104.     { XtNshadowThickness, XtCShadowThickness, XtRDimension, sizeof(Dimension),
  105.     poff(shadow_thickness), XtRImmediate, (XtPointer) 2 },
  106.     { XtNbackgroundStipple, XtCBackgroundStipple, XtRString, sizeof(String),
  107.     poff(stipple_name), XtRImmediate, (XtPointer) NULL },
  108. #undef poff
  109. };
  110.  
  111.  
  112. /*
  113.  * widget class methods used below
  114.  */
  115. static void Initialize();        /* create gc's */
  116. static void Realize();            /* create window */
  117. static void Destroy();            /* clean up widget */
  118. static void Resize();            /* need to rescale ourselves */
  119. static void Redisplay();        /* draw ourselves */
  120. static Boolean SetValues();        /* set all of the resources */
  121. static void SetValuesAlmost();        /* deal with failed setval geom req */
  122. static XtGeometryResult QueryGeometry();  /* say how big we would like to be */
  123.  
  124. PannerClassRec pannerClassRec = {
  125.   { /* core fields */
  126.     /* superclass        */    (WidgetClass) &simpleClassRec,
  127.     /* class_name        */    "Panner",
  128.     /* widget_size        */    sizeof(PannerRec),
  129.     /* class_initialize        */    XawInitializeWidgetSet,
  130.     /* class_part_initialize    */    NULL,
  131.     /* class_inited        */    FALSE,
  132.     /* initialize        */    Initialize,
  133.     /* initialize_hook        */    NULL,
  134.     /* realize            */    Realize,
  135.     /* actions            */    actions,
  136.     /* num_actions        */    XtNumber(actions),
  137.     /* resources        */    resources,
  138.     /* num_resources        */    XtNumber(resources),
  139.     /* xrm_class        */    NULLQUARK,
  140.     /* compress_motion        */    TRUE,
  141.     /* compress_exposure    */    TRUE,
  142.     /* compress_enterleave    */    TRUE,
  143.     /* visible_interest        */    FALSE,
  144.     /* destroy            */    Destroy,
  145.     /* resize            */    Resize,
  146.     /* expose            */    Redisplay,
  147.     /* set_values        */    SetValues,
  148.     /* set_values_hook        */    NULL,
  149.     /* set_values_almost    */    SetValuesAlmost,
  150.     /* get_values_hook        */    NULL,
  151.     /* accept_focus        */    NULL,
  152.     /* version            */    XtVersion,
  153.     /* callback_private        */    NULL,
  154.     /* tm_table            */    defaultTranslations,
  155.     /* query_geometry        */    QueryGeometry,
  156.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  157.     /* extension        */    NULL
  158.   },
  159.   { /* simple fields */
  160.     /* change_sensitive        */    XtInheritChangeSensitive
  161.   },
  162.   { /* panner fields */
  163.     /* ignore                   */    0
  164.   }
  165. };
  166.  
  167. WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
  168.  
  169.  
  170. /*****************************************************************************
  171.  *                                                                           *
  172.  *                panner utility routines                          *
  173.  *                                                                           *
  174.  *****************************************************************************/
  175.  
  176. static void reset_shadow_gc (pw)    /* used when resources change */
  177.     PannerWidget pw;
  178. {
  179.     XtGCMask valuemask = GCForeground;
  180.     XGCValues values;
  181.     unsigned long   pixels[3];
  182.  
  183.     if (pw->panner.shadow_gc) XtReleaseGC ((Widget) pw, pw->panner.shadow_gc);
  184.  
  185.     pixels[0] = pw->panner.foreground;
  186.     pixels[1] = pw->core.background_pixel;
  187.     pixels[2] = pw->panner.shadow_color;
  188.     if (!pw->panner.stipple_name &&
  189.     !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
  190.                     pixels, 3) &&
  191.     XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
  192.                     pixels, 2))
  193.     {
  194.     valuemask = GCTile | GCFillStyle;
  195.     values.fill_style = FillTiled;
  196.     values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
  197.                           pw->panner.foreground,
  198.                           pw->core.background_pixel,
  199.                           pw->core.depth);
  200.     }
  201.     else
  202.     {
  203.     if (!pw->panner.line_width &&
  204.         !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
  205.                        pixels, 2))
  206.         pw->panner.line_width = 1;
  207.     valuemask = GCForeground;
  208.     values.foreground = pw->panner.shadow_color;
  209.     }
  210.     if (pw->panner.line_width > 0) {
  211.     values.line_width = pw->panner.line_width;
  212.     valuemask |= GCLineWidth;
  213.     }
  214.  
  215.     pw->panner.shadow_gc = XtGetGC ((Widget) pw, valuemask, &values);
  216. }
  217.  
  218. static void reset_slider_gc (pw)    /* used when resources change */
  219.     PannerWidget pw;
  220. {
  221.     XtGCMask valuemask = GCForeground;
  222.     XGCValues values;
  223.  
  224.     if (pw->panner.slider_gc) XtReleaseGC ((Widget) pw, pw->panner.slider_gc);
  225.  
  226.     values.foreground = pw->panner.foreground;
  227.  
  228.     pw->panner.slider_gc = XtGetGC ((Widget) pw, valuemask, &values);
  229. }
  230.  
  231. static void reset_xor_gc (pw)        /* used when resources change */
  232.     PannerWidget pw;
  233. {
  234.     if (pw->panner.xor_gc) XtReleaseGC ((Widget) pw, pw->panner.xor_gc);
  235.  
  236.     if (pw->panner.rubber_band) {
  237.     XtGCMask valuemask = (GCForeground | GCFunction);
  238.     XGCValues values;
  239.     Pixel tmp;
  240.  
  241.     tmp = ((pw->panner.foreground == pw->core.background_pixel) ?
  242.            pw->panner.shadow_color : pw->panner.foreground);
  243.     values.foreground = tmp ^ pw->core.background_pixel;
  244.     values.function = GXxor;
  245.     if (pw->panner.line_width > 0) {
  246.         valuemask |= GCLineWidth;
  247.         values.line_width = pw->panner.line_width;
  248.     }
  249.     pw->panner.xor_gc = XtGetGC ((Widget) pw, valuemask, &values);
  250.     } else {
  251.     pw->panner.xor_gc = NULL;
  252.     }
  253. }
  254.  
  255.  
  256. static void check_knob (pw, knob)
  257.     register PannerWidget pw;
  258.     Boolean knob;
  259. {
  260.     Position pad = pw->panner.internal_border * 2;
  261.     Position maxx = (((Position) pw->core.width) - pad -
  262.              ((Position) pw->panner.knob_width));
  263.     Position maxy = (((Position) pw->core.height) - pad -
  264.              ((Position) pw->panner.knob_height));
  265.     Position *x = (knob ? &pw->panner.knob_x : &pw->panner.tmp.x);
  266.     Position *y = (knob ? &pw->panner.knob_y : &pw->panner.tmp.y);
  267.  
  268.     /*
  269.      * note that positions are already normalized (i.e. internal_border
  270.      * has been subtracted out)
  271.      */
  272.     if (*x < 0) *x = 0;
  273.     if (*x > maxx) *x = maxx;
  274.  
  275.     if (*y < 0) *y = 0;
  276.     if (*y > maxy) *y = maxy;
  277.  
  278.     if (knob) {
  279.     pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
  280.                       pw->panner.haspect + 0.5);
  281.     pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
  282.                       pw->panner.vaspect + 0.5);
  283.     pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
  284.     }
  285. }
  286.  
  287.  
  288. static void move_shadow (pw)
  289.     register PannerWidget pw;
  290. {
  291.     if (pw->panner.shadow_thickness > 0) {
  292.     int lw = pw->panner.shadow_thickness + pw->panner.line_width * 2;
  293.     int pad = pw->panner.internal_border;
  294.  
  295.     if ((int)pw->panner.knob_height > lw && (int)pw->panner.knob_width > lw) {
  296.         register XRectangle *r = pw->panner.shadow_rects;
  297.         r->x = (short) (pw->panner.knob_x + pad + pw->panner.knob_width);
  298.         r->y = (short) (pw->panner.knob_y + pad + lw);
  299.         r->width = pw->panner.shadow_thickness;
  300.         r->height = (unsigned short) (pw->panner.knob_height - lw);
  301.         r++;
  302.         r->x = (short) (pw->panner.knob_x + pad + lw);
  303.         r->y = (short) (pw->panner.knob_y + pad + pw->panner.knob_height);
  304.         r->width = (unsigned short) (pw->panner.knob_width - lw +
  305.                      pw->panner.shadow_thickness);
  306.         r->height = pw->panner.shadow_thickness;
  307.         pw->panner.shadow_valid = TRUE;
  308.         return;
  309.     }
  310.     }
  311.     pw->panner.shadow_valid = FALSE;
  312. }
  313.  
  314. static void scale_knob (pw, location, size)  /* set knob size and/or loc */
  315.     PannerWidget pw;
  316.     Boolean location, size;
  317. {
  318.     if (location) {
  319.     pw->panner.knob_x = (Position) PANNER_HSCALE (pw, pw->panner.slider_x);
  320.     pw->panner.knob_y = (Position) PANNER_VSCALE (pw, pw->panner.slider_y);
  321.     }
  322.     if (size) {
  323.     Dimension width, height;
  324.  
  325.     if (pw->panner.slider_width < 1) {
  326.         pw->panner.slider_width = pw->panner.canvas_width;
  327.     }
  328.     if (pw->panner.slider_height < 1) {
  329.         pw->panner.slider_height = pw->panner.canvas_height;
  330.     }
  331.     width = Min (pw->panner.slider_width, pw->panner.canvas_width);
  332.     height = Min (pw->panner.slider_height, pw->panner.canvas_height);
  333.  
  334.     pw->panner.knob_width = (Dimension) PANNER_HSCALE (pw, width);
  335.     pw->panner.knob_height = (Dimension) PANNER_VSCALE (pw, height);
  336.     }
  337.     if (!pw->panner.allow_off) check_knob (pw, TRUE);
  338.     move_shadow (pw);
  339. }
  340.  
  341. static void rescale (pw)
  342.     PannerWidget pw;
  343. {
  344.     int hpad = pw->panner.internal_border * 2;
  345.     int vpad = hpad;
  346.  
  347.     if (pw->panner.canvas_width < 1)
  348.       pw->panner.canvas_width = pw->core.width;
  349.     if (pw->panner.canvas_height < 1)
  350.       pw->panner.canvas_height = pw->core.height;
  351.  
  352.     if ((int)pw->core.width <= hpad) hpad = 0;
  353.     if ((int)pw->core.height <= vpad) vpad = 0;
  354.  
  355.     pw->panner.haspect = ((double) pw->core.width - hpad) /
  356.               (double) pw->panner.canvas_width;
  357.     pw->panner.vaspect = ((double) pw->core.height - vpad) /
  358.               (double) pw->panner.canvas_height;
  359.     scale_knob (pw, TRUE, TRUE);
  360. }
  361.  
  362.  
  363. static void get_default_size (pw, wp, hp)
  364.     PannerWidget pw;
  365.     Dimension *wp, *hp;
  366. {
  367.     Dimension pad = pw->panner.internal_border * 2;
  368.     *wp = PANNER_DSCALE (pw, pw->panner.canvas_width) + pad;
  369.     *hp = PANNER_DSCALE (pw, pw->panner.canvas_height) + pad;
  370. }
  371.  
  372. static Boolean get_event_xy (pw, event, x, y)
  373.     PannerWidget pw;
  374.     XEvent *event;
  375.     int *x, *y;
  376. {
  377.     int pad = pw->panner.internal_border;
  378.  
  379.     switch (event->type) {
  380.       case ButtonPress:
  381.       case ButtonRelease:
  382.     *x = event->xbutton.x - pad;
  383.     *y = event->xbutton.y - pad;
  384.     return TRUE;
  385.  
  386.       case KeyPress:
  387.       case KeyRelease:
  388.     *x = event->xkey.x - pad;
  389.     *y = event->xkey.y - pad;
  390.     return TRUE;
  391.  
  392.       case EnterNotify:
  393.       case LeaveNotify:
  394.     *x = event->xcrossing.x - pad;
  395.     *y = event->xcrossing.y - pad;
  396.     return TRUE;
  397.  
  398.       case MotionNotify:
  399.     *x = event->xmotion.x - pad;
  400.     *y = event->xmotion.y - pad;
  401.     return TRUE;
  402.     }
  403.  
  404.     return FALSE;
  405. }
  406.  
  407. static int parse_page_string (s, pagesize, canvassize, relative)
  408.     register char *s;
  409.     int pagesize, canvassize;
  410.     Boolean *relative;
  411. {
  412.     char *cp;
  413.     double val = 1.0;
  414.     Boolean rel = FALSE;
  415.  
  416.     /*
  417.      * syntax:    spaces [+-] number spaces [pc\0] spaces
  418.      */
  419.  
  420.     for (; isascii(*s) && isspace(*s); s++) ;    /* skip white space */
  421.  
  422.     if (*s == '+' || *s == '-') {    /* deal with signs */
  423.     rel = TRUE;
  424.     if (*s == '-') val = -1.0;
  425.     s++;
  426.     }
  427.     if (!*s) {                /* if null then return nothing */
  428.     *relative = TRUE;
  429.     return 0;
  430.     }
  431.  
  432.                     /* skip over numbers */
  433.     for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
  434.     val *= atof (cp);
  435.  
  436.                     /* skip blanks */
  437.     for (; isascii(*s) && isspace(*s); s++) ;
  438.  
  439.     if (*s) {                /* if units */
  440.     switch (s[0]) {
  441.       case 'p': case 'P':
  442.         val *= (double) pagesize;
  443.         break;
  444.  
  445.       case 'c': case 'C':
  446.         val *= (double) canvassize;
  447.         break;
  448.     }
  449.     }
  450.     *relative = rel;
  451.     return ((int) val);
  452. }
  453.  
  454.  
  455. #define DRAW_TMP(pw) \
  456. { \
  457.     XDrawRectangle (XtDisplay(pw), XtWindow(pw), \
  458.             pw->panner.xor_gc, \
  459.             (int) (pw->panner.tmp.x + pw->panner.internal_border), \
  460.             (int) (pw->panner.tmp.y + pw->panner.internal_border), \
  461.             (unsigned int) (pw->panner.knob_width - 1), \
  462.             (unsigned int) (pw->panner.knob_height - 1)); \
  463.     pw->panner.tmp.showing = !pw->panner.tmp.showing; \
  464. }
  465.  
  466. #define UNDRAW_TMP(pw) \
  467. { \
  468.     if (pw->panner.tmp.showing) DRAW_TMP(pw); \
  469. }
  470.  
  471. #define BACKGROUND_STIPPLE(pw) \
  472.   XmuLocatePixmapFile (pw->core.screen, pw->panner.stipple_name, \
  473.                pw->panner.shadow_color, pw->core.background_pixel, \
  474.                pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
  475.     
  476. #define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
  477.  
  478.  
  479. /*****************************************************************************
  480.  *                                                                           *
  481.  *                  panner class methods                            *
  482.  *                                                                           *
  483.  *****************************************************************************/
  484.  
  485.  
  486. static void Initialize (greq, gnew)
  487.     Widget greq, gnew;
  488. {
  489.     PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
  490.     Dimension defwidth, defheight;
  491.  
  492.     if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
  493.     if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
  494.     if (req->panner.default_scale < 1)
  495.       new->panner.default_scale = PANNER_DEFAULT_SCALE;
  496.  
  497.     get_default_size (req, &defwidth, &defheight);
  498.     if (req->core.width < 1) new->core.width = defwidth;
  499.     if (req->core.height < 1) new->core.height = defheight;
  500.  
  501.     new->panner.shadow_gc = NULL;
  502.     reset_shadow_gc (new);        /* shadowColor */
  503.     new->panner.slider_gc = NULL;
  504.     reset_slider_gc (new);        /* foreground */
  505.     new->panner.xor_gc = NULL;
  506.     reset_xor_gc (new);            /* foreground ^ background */
  507.  
  508.     rescale (new);            /* does a position check */
  509.     new->panner.shadow_valid = FALSE;
  510.     new->panner.tmp.doing = FALSE;
  511.     new->panner.tmp.showing = FALSE;
  512. }
  513.  
  514.  
  515. static void Realize (gw, valuemaskp, attr)
  516.     Widget gw;
  517.     XtValueMask *valuemaskp;
  518.     XSetWindowAttributes *attr;
  519. {
  520.     PannerWidget pw = (PannerWidget) gw;
  521.     Pixmap pm = XtUnspecifiedPixmap;
  522.     Boolean gotpm = FALSE;
  523.  
  524.     if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
  525.     if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
  526.  
  527.     if (PIXMAP_OKAY(pm)) {
  528.         attr->background_pixmap = pm;
  529.         *valuemaskp |= CWBackPixmap;
  530.         *valuemaskp &= ~CWBackPixel;
  531.         gotpm = TRUE;
  532.     }
  533.     }
  534.     (*gw->core.widget_class->core_class.superclass->core_class.realize)
  535.       (gw, valuemaskp, attr);
  536.  
  537.     if (gotpm) XFreePixmap (XtDisplay(gw), pm);
  538. }
  539.  
  540.  
  541. static void Destroy (gw)
  542.     Widget gw;
  543. {
  544.     PannerWidget pw = (PannerWidget) gw;
  545.  
  546.     XtReleaseGC (gw, pw->panner.shadow_gc);
  547.     XtReleaseGC (gw, pw->panner.slider_gc);
  548.     XtReleaseGC (gw, pw->panner.xor_gc);
  549. }
  550.  
  551.  
  552. static void Resize (gw)
  553.     Widget gw;
  554. {
  555.     rescale ((PannerWidget) gw);
  556. }
  557.  
  558.  
  559. /* ARGSUSED */
  560. static void Redisplay (gw, event, region)
  561.     Widget gw;
  562.     XEvent *event;
  563.     Region region;
  564. {
  565.     PannerWidget pw = (PannerWidget) gw;
  566.     Display *dpy = XtDisplay(gw);
  567.     Window w = XtWindow(gw);
  568.     int pad = pw->panner.internal_border;
  569.     Dimension lw = pw->panner.line_width;
  570.     Dimension extra = pw->panner.shadow_thickness + lw * 2;
  571.     int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
  572.  
  573.     pw->panner.tmp.showing = FALSE;
  574.     XClearArea (XtDisplay(pw), XtWindow(pw), 
  575.         (int) pw->panner.last_x - ((int) lw) + pad, 
  576.         (int) pw->panner.last_y - ((int) lw) + pad, 
  577.         (unsigned int) (pw->panner.knob_width + extra),
  578.         (unsigned int) (pw->panner.knob_height + extra),
  579.         False);
  580.     pw->panner.last_x = pw->panner.knob_x;
  581.     pw->panner.last_y = pw->panner.knob_y;
  582.  
  583.     XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
  584.             pw->panner.knob_width - 1, pw->panner.knob_height - 1);
  585.  
  586.     if (lw)
  587.     {
  588.         XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
  589.                 (unsigned int) (pw->panner.knob_width - 1), 
  590.                 (unsigned int) (pw->panner.knob_height - 1));
  591.     }
  592.  
  593.     if (pw->panner.shadow_valid) {
  594.     XFillRectangles (dpy, w, pw->panner.shadow_gc,
  595.              pw->panner.shadow_rects, 2);
  596.     }
  597.     if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
  598. }
  599.  
  600.  
  601. /* ARGSUSED */
  602. static Boolean SetValues (gcur, greq, gnew)
  603.     Widget gcur, greq, gnew;
  604. {
  605.     PannerWidget cur = (PannerWidget) gcur;
  606.     PannerWidget new = (PannerWidget) gnew;
  607.     Boolean redisplay = FALSE;
  608.  
  609.     if (cur->panner.foreground != new->panner.foreground) {
  610.     reset_slider_gc (new);
  611.     if (cur->panner.foreground != cur->core.background_pixel)
  612.       reset_xor_gc (new);
  613.     redisplay = TRUE;
  614.     } else if (cur->panner.line_width != new->panner.line_width ||
  615.            cur->core.background_pixel != new->core.background_pixel) {
  616.     reset_xor_gc (new);
  617.     redisplay = TRUE;
  618.     }
  619.     if (cur->panner.shadow_color != new->panner.shadow_color) {
  620.     reset_shadow_gc (new);
  621.     if (cur->panner.foreground == cur->core.background_pixel)
  622.       reset_xor_gc (new);
  623.     redisplay = TRUE;
  624.     }
  625.     if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
  626.     move_shadow (new);
  627.     redisplay = TRUE;
  628.     }
  629.     if (cur->panner.rubber_band != new->panner.rubber_band) {
  630.     reset_xor_gc (new);
  631.     if (new->panner.tmp.doing) redisplay = TRUE;
  632.     }
  633.  
  634.     if ((cur->panner.stipple_name != new->panner.stipple_name ||
  635.      cur->panner.shadow_color != new->panner.shadow_color ||
  636.      cur->core.background_pixel != new->core.background_pixel) &&
  637.     XtIsRealized(gnew)) {
  638.     Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
  639.              : XtUnspecifiedPixmap);
  640.  
  641.     if (PIXMAP_OKAY(pm)) {
  642.         XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
  643.         XFreePixmap (XtDisplay (new), pm);
  644.     } else {
  645.         XSetWindowBackground (XtDisplay (new), XtWindow(new),
  646.                   new->core.background_pixel);
  647.     }
  648.     redisplay = TRUE;
  649.     }
  650.  
  651.     if (new->panner.resize_to_pref &&
  652.     (cur->panner.canvas_width != new->panner.canvas_width ||
  653.      cur->panner.canvas_height != new->panner.canvas_height ||
  654.      cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
  655.     get_default_size (new, &new->core.width, &new->core.height);
  656.     redisplay = TRUE;
  657.     } else if (cur->panner.canvas_width != new->panner.canvas_width ||
  658.     cur->panner.canvas_height != new->panner.canvas_height ||
  659.     cur->panner.internal_border != new->panner.internal_border) {
  660.     rescale (new);            /* does a scale_knob as well */
  661.     redisplay = TRUE;
  662.     } else {
  663.     Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
  664.                cur->panner.slider_y != new->panner.slider_y);
  665.     Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
  666.                cur->panner.slider_height != new->panner.slider_height);
  667.     if (loc || siz ||
  668.         (cur->panner.allow_off != new->panner.allow_off &&
  669.          new->panner.allow_off)) {
  670.         scale_knob (new, loc, siz);
  671.         redisplay = TRUE;
  672.     }
  673.     }
  674.  
  675.     return redisplay;
  676. }
  677.  
  678. static void SetValuesAlmost (gold, gnew, req, reply)
  679.     Widget gold, gnew;
  680.     XtWidgetGeometry *req, *reply;
  681. {
  682.     if (reply->request_mode == 0) {    /* got turned down, so cope */
  683.     Resize (gnew);
  684.     }
  685.     (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
  686.     (gold, gnew, req, reply);
  687. }
  688.  
  689. static XtGeometryResult QueryGeometry (gw, intended, pref)
  690.     Widget gw;
  691.     XtWidgetGeometry *intended, *pref;
  692. {
  693.     PannerWidget pw = (PannerWidget) gw;
  694.  
  695.     pref->request_mode = (CWWidth | CWHeight);
  696.     get_default_size (pw, &pref->width, &pref->height);
  697.  
  698.     if (((intended->request_mode & (CWWidth | CWHeight)) ==
  699.      (CWWidth | CWHeight)) &&
  700.     intended->width == pref->width &&
  701.     intended->height == pref->height)
  702.       return XtGeometryYes;
  703.     else if (pref->width == pw->core.width && pref->height == pw->core.height)
  704.       return XtGeometryNo;
  705.     else
  706.       return XtGeometryAlmost;
  707. }
  708.  
  709.  
  710. /*****************************************************************************
  711.  *                                                                           *
  712.  *                   panner action procs                            *
  713.  *                                                                           *
  714.  *****************************************************************************/
  715.  
  716. /* ARGSUSED */
  717. static void ActionStart (gw, event, params, num_params)
  718.     Widget gw;
  719.     XEvent *event;
  720.     String *params;            /* unused */
  721.     Cardinal *num_params;        /* unused */
  722. {
  723.     PannerWidget pw = (PannerWidget) gw;
  724.     int x, y;
  725.  
  726.     if (!get_event_xy (pw, event, &x, &y)) {
  727.     XBell (XtDisplay(gw), 0);    /* should do error message */
  728.     return;
  729.     }
  730.  
  731.     pw->panner.tmp.doing = TRUE;
  732.     pw->panner.tmp.startx = pw->panner.knob_x;
  733.     pw->panner.tmp.starty = pw->panner.knob_y;
  734.     pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
  735.     pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
  736.     pw->panner.tmp.x = pw->panner.knob_x;
  737.     pw->panner.tmp.y = pw->panner.knob_y;
  738.     if (pw->panner.rubber_band) DRAW_TMP (pw);
  739. }
  740.  
  741. /* ARGSUSED */
  742. static void ActionStop (gw, event, params, num_params)
  743.     Widget gw;
  744.     XEvent *event;
  745.     String *params;            /* unused */
  746.     Cardinal *num_params;        /* unused */
  747. {
  748.     PannerWidget pw = (PannerWidget) gw;
  749.     int x, y;
  750.  
  751.     if (get_event_xy (pw, event, &x, &y)) {
  752.     pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
  753.     pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
  754.     if (!pw->panner.allow_off) check_knob (pw, FALSE);
  755.     }
  756.     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
  757.     pw->panner.tmp.doing = FALSE;
  758. }
  759.  
  760. /* ARGSUSED */
  761. static void ActionAbort (gw, event, params, num_params)
  762.     Widget gw;
  763.     XEvent *event;
  764.     String *params;            /* unused */
  765.     Cardinal *num_params;        /* unused */
  766. {
  767.     PannerWidget pw = (PannerWidget) gw;
  768.  
  769.     if (!pw->panner.tmp.doing) return;
  770.  
  771.     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
  772.  
  773.     if (!pw->panner.rubber_band) {        /* restore old position */
  774.     pw->panner.tmp.x = pw->panner.tmp.startx;
  775.     pw->panner.tmp.y = pw->panner.tmp.starty;
  776.     ActionNotify (gw, event, params, num_params);
  777.     }
  778.     pw->panner.tmp.doing = FALSE;
  779. }
  780.  
  781.  
  782. /* ARGSUSED */
  783. static void ActionMove (gw, event, params, num_params)
  784.     Widget gw;
  785.     XEvent *event;            /* must be a motion event */
  786.     String *params;            /* unused */
  787.     Cardinal *num_params;        /* unused */
  788. {
  789.     PannerWidget pw = (PannerWidget) gw;
  790.     int x, y;
  791.  
  792.     if (!pw->panner.tmp.doing) return;
  793.  
  794.     if (!get_event_xy (pw, event, &x, &y)) {
  795.     XBell (XtDisplay(gw), 0);    /* should do error message */
  796.     return;
  797.     }
  798.  
  799.     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
  800.     pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
  801.     pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
  802.  
  803.     if (!pw->panner.rubber_band) {
  804.     ActionNotify (gw, event, params, num_params);  /* does a check */
  805.     } else {
  806.     if (!pw->panner.allow_off) check_knob (pw, FALSE);
  807.     DRAW_TMP (pw);
  808.     }
  809. }
  810.  
  811.  
  812. /* ARGSUSED */
  813. static void ActionPage (gw, event, params, num_params)
  814.     Widget gw;
  815.     XEvent *event;            /* unused */
  816.     String *params;
  817.     Cardinal *num_params;        /* unused */
  818. {
  819.     PannerWidget pw = (PannerWidget) gw;
  820.     Cardinal zero = 0;
  821.     Boolean isin = pw->panner.tmp.doing;
  822.     int x, y;
  823.     Boolean relx, rely;
  824.     int pad = pw->panner.internal_border * 2;
  825.  
  826.     if (*num_params != 2) {
  827.     XBell (XtDisplay(gw), 0);
  828.     return;
  829.     }
  830.  
  831.     x = parse_page_string (params[0], (int) pw->panner.knob_width,
  832.                ((int) pw->core.width) - pad, &relx);
  833.     y = parse_page_string (params[1], (int) pw->panner.knob_height,
  834.                ((int) pw->core.height) - pad, &rely);
  835.  
  836.     if (relx) x += pw->panner.knob_x;
  837.     if (rely) y += pw->panner.knob_y;
  838.  
  839.     if (isin) {                /* if in, then use move */
  840.     XEvent ev;
  841.     ev.xbutton.type = ButtonPress;
  842.     ev.xbutton.x = x;
  843.     ev.xbutton.y = y;
  844.     ActionMove (gw, &ev, (String *) NULL, &zero);
  845.     } else {                /* else just do it */
  846.     pw->panner.tmp.doing = TRUE;
  847.     pw->panner.tmp.x = x;
  848.     pw->panner.tmp.y = y;
  849.     ActionNotify (gw, event, (String *) NULL, &zero);
  850.     pw->panner.tmp.doing = FALSE;
  851.     }
  852. }
  853.  
  854.  
  855. /* ARGSUSED */
  856. static void ActionNotify (gw, event, params, num_params)
  857.     Widget gw;
  858.     XEvent *event;            /* unused */
  859.     String *params;            /* unused */
  860.     Cardinal *num_params;        /* unused */
  861. {
  862.     PannerWidget pw = (PannerWidget) gw;
  863.  
  864.     if (!pw->panner.tmp.doing) return;
  865.  
  866.     if (!pw->panner.allow_off) check_knob (pw, FALSE);
  867.     pw->panner.knob_x = pw->panner.tmp.x;
  868.     pw->panner.knob_y = pw->panner.tmp.y;
  869.     move_shadow (pw);
  870.  
  871.     pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
  872.                       pw->panner.haspect + 0.5);
  873.     pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
  874.                       pw->panner.vaspect + 0.5);
  875.     if (!pw->panner.allow_off) {
  876.     Position tmp;
  877.     
  878.     if (pw->panner.slider_x >
  879.         (tmp = (((Position) pw->panner.canvas_width) - 
  880.             ((Position) pw->panner.slider_width))))
  881.       pw->panner.slider_x = tmp;
  882.     if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
  883.     if (pw->panner.slider_y >
  884.         (tmp = (((Position) pw->panner.canvas_height) - 
  885.             ((Position) pw->panner.slider_height))))
  886.       pw->panner.slider_y = tmp;
  887.     if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
  888.     }
  889.  
  890.     if (pw->panner.last_x != pw->panner.knob_x ||
  891.     pw->panner.last_y != pw->panner.knob_y) {
  892.     XawPannerReport rep;
  893.  
  894.     Redisplay (gw, (XEvent*) NULL, (Region) NULL);
  895.     rep.changed = (XawPRSliderX | XawPRSliderY);
  896.     rep.slider_x = pw->panner.slider_x;
  897.     rep.slider_y = pw->panner.slider_y;
  898.     rep.slider_width = pw->panner.slider_width;
  899.     rep.slider_height = pw->panner.slider_height;
  900.     rep.canvas_width = pw->panner.canvas_width;
  901.     rep.canvas_height = pw->panner.canvas_height;
  902.     XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
  903.     }
  904. }
  905.  
  906. /* ARGSUSED */
  907. static void ActionSet (gw, event, params, num_params)
  908.     Widget gw;
  909.     XEvent *event;            /* unused */
  910.     String *params;
  911.     Cardinal *num_params;
  912. {
  913.     PannerWidget pw = (PannerWidget) gw;
  914.     Boolean rb;
  915.  
  916.     if (*num_params < 2 ||
  917.     XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
  918.     XBell (XtDisplay(gw), 0);
  919.     return;
  920.     }
  921.  
  922.     if (XmuCompareISOLatin1 (params[1], "on") == 0) {
  923.     rb = TRUE;
  924.     } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
  925.     rb = FALSE;
  926.     } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
  927.     rb = !pw->panner.rubber_band;
  928.     } else {
  929.     XBell (XtDisplay(gw), 0);
  930.     return;
  931.     }
  932.  
  933.     if (rb != pw->panner.rubber_band) {
  934.     Arg args[1];
  935.     XtSetArg (args[0], XtNrubberBand, rb);
  936.     XtSetValues (gw, args, (Cardinal) 1);
  937.     }
  938. }
  939.