home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Panner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  29.0 KB  |  943 lines

  1. /*
  2.  * $XConsortium: Panner.c,v 1.45 92/03/03 13:52:26 converse 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, args, num_args)
  487.     Widget greq, gnew;
  488.     ArgList args;
  489.     Cardinal *num_args;
  490. {
  491.     PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
  492.     Dimension defwidth, defheight;
  493.  
  494.     if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
  495.     if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
  496.     if (req->panner.default_scale < 1)
  497.       new->panner.default_scale = PANNER_DEFAULT_SCALE;
  498.  
  499.     get_default_size (req, &defwidth, &defheight);
  500.     if (req->core.width < 1) new->core.width = defwidth;
  501.     if (req->core.height < 1) new->core.height = defheight;
  502.  
  503.     new->panner.shadow_gc = NULL;
  504.     reset_shadow_gc (new);        /* shadowColor */
  505.     new->panner.slider_gc = NULL;
  506.     reset_slider_gc (new);        /* foreground */
  507.     new->panner.xor_gc = NULL;
  508.     reset_xor_gc (new);            /* foreground ^ background */
  509.  
  510.     rescale (new);            /* does a position check */
  511.     new->panner.shadow_valid = FALSE;
  512.     new->panner.tmp.doing = FALSE;
  513.     new->panner.tmp.showing = FALSE;
  514. }
  515.  
  516.  
  517. static void Realize (gw, valuemaskp, attr)
  518.     Widget gw;
  519.     XtValueMask *valuemaskp;
  520.     XSetWindowAttributes *attr;
  521. {
  522.     PannerWidget pw = (PannerWidget) gw;
  523.     Pixmap pm = XtUnspecifiedPixmap;
  524.     Boolean gotpm = FALSE;
  525.  
  526.     if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
  527.     if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
  528.  
  529.     if (PIXMAP_OKAY(pm)) {
  530.         attr->background_pixmap = pm;
  531.         *valuemaskp |= CWBackPixmap;
  532.         *valuemaskp &= ~CWBackPixel;
  533.         gotpm = TRUE;
  534.     }
  535.     }
  536.     (*pannerWidgetClass->core_class.superclass->core_class.realize)
  537.       (gw, valuemaskp, attr);
  538.  
  539.     if (gotpm) XFreePixmap (XtDisplay(gw), pm);
  540. }
  541.  
  542.  
  543. static void Destroy (gw)
  544.     Widget gw;
  545. {
  546.     PannerWidget pw = (PannerWidget) gw;
  547.  
  548.     XtReleaseGC (gw, pw->panner.shadow_gc);
  549.     XtReleaseGC (gw, pw->panner.slider_gc);
  550.     XtReleaseGC (gw, pw->panner.xor_gc);
  551. }
  552.  
  553.  
  554. static void Resize (gw)
  555.     Widget gw;
  556. {
  557.     rescale ((PannerWidget) gw);
  558. }
  559.  
  560.  
  561. /* ARGSUSED */
  562. static void Redisplay (gw, event, region)
  563.     Widget gw;
  564.     XEvent *event;
  565.     Region region;
  566. {
  567.     PannerWidget pw = (PannerWidget) gw;
  568.     Display *dpy = XtDisplay(gw);
  569.     Window w = XtWindow(gw);
  570.     int pad = pw->panner.internal_border;
  571.     Dimension lw = pw->panner.line_width;
  572.     Dimension extra = pw->panner.shadow_thickness + lw * 2;
  573.     int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
  574.  
  575.     pw->panner.tmp.showing = FALSE;
  576.     XClearArea (XtDisplay(pw), XtWindow(pw), 
  577.         (int) pw->panner.last_x - ((int) lw) + pad, 
  578.         (int) pw->panner.last_y - ((int) lw) + pad, 
  579.         (unsigned int) (pw->panner.knob_width + extra),
  580.         (unsigned int) (pw->panner.knob_height + extra),
  581.         False);
  582.     pw->panner.last_x = pw->panner.knob_x;
  583.     pw->panner.last_y = pw->panner.knob_y;
  584.  
  585.     XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
  586.             pw->panner.knob_width - 1, pw->panner.knob_height - 1);
  587.  
  588.     if (lw)
  589.     {
  590.         XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
  591.                 (unsigned int) (pw->panner.knob_width - 1), 
  592.                 (unsigned int) (pw->panner.knob_height - 1));
  593.     }
  594.  
  595.     if (pw->panner.shadow_valid) {
  596.     XFillRectangles (dpy, w, pw->panner.shadow_gc,
  597.              pw->panner.shadow_rects, 2);
  598.     }
  599.     if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
  600. }
  601.  
  602.  
  603. /* ARGSUSED */
  604. static Boolean SetValues (gcur, greq, gnew, args, num_args)
  605.     Widget gcur, greq, gnew;
  606.     ArgList args;
  607.     Cardinal *num_args;
  608. {
  609.     PannerWidget cur = (PannerWidget) gcur;
  610.     PannerWidget new = (PannerWidget) gnew;
  611.     Boolean redisplay = FALSE;
  612.  
  613.     if (cur->panner.foreground != new->panner.foreground) {
  614.     reset_slider_gc (new);
  615.     if (cur->panner.foreground != cur->core.background_pixel)
  616.       reset_xor_gc (new);
  617.     redisplay = TRUE;
  618.     } else if (cur->panner.line_width != new->panner.line_width ||
  619.            cur->core.background_pixel != new->core.background_pixel) {
  620.     reset_xor_gc (new);
  621.     redisplay = TRUE;
  622.     }
  623.     if (cur->panner.shadow_color != new->panner.shadow_color) {
  624.     reset_shadow_gc (new);
  625.     if (cur->panner.foreground == cur->core.background_pixel)
  626.       reset_xor_gc (new);
  627.     redisplay = TRUE;
  628.     }
  629.     if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
  630.     move_shadow (new);
  631.     redisplay = TRUE;
  632.     }
  633.     if (cur->panner.rubber_band != new->panner.rubber_band) {
  634.     reset_xor_gc (new);
  635.     if (new->panner.tmp.doing) redisplay = TRUE;
  636.     }
  637.  
  638.     if ((cur->panner.stipple_name != new->panner.stipple_name ||
  639.      cur->panner.shadow_color != new->panner.shadow_color ||
  640.      cur->core.background_pixel != new->core.background_pixel) &&
  641.     XtIsRealized(gnew)) {
  642.     Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
  643.              : XtUnspecifiedPixmap);
  644.  
  645.     if (PIXMAP_OKAY(pm)) {
  646.         XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
  647.         XFreePixmap (XtDisplay (new), pm);
  648.     } else {
  649.         XSetWindowBackground (XtDisplay (new), XtWindow(new),
  650.                   new->core.background_pixel);
  651.     }
  652.     redisplay = TRUE;
  653.     }
  654.  
  655.     if (new->panner.resize_to_pref &&
  656.     (cur->panner.canvas_width != new->panner.canvas_width ||
  657.      cur->panner.canvas_height != new->panner.canvas_height ||
  658.      cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
  659.     get_default_size (new, &new->core.width, &new->core.height);
  660.     redisplay = TRUE;
  661.     } else if (cur->panner.canvas_width != new->panner.canvas_width ||
  662.     cur->panner.canvas_height != new->panner.canvas_height ||
  663.     cur->panner.internal_border != new->panner.internal_border) {
  664.     rescale (new);            /* does a scale_knob as well */
  665.     redisplay = TRUE;
  666.     } else {
  667.     Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
  668.                cur->panner.slider_y != new->panner.slider_y);
  669.     Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
  670.                cur->panner.slider_height != new->panner.slider_height);
  671.     if (loc || siz ||
  672.         (cur->panner.allow_off != new->panner.allow_off &&
  673.          new->panner.allow_off)) {
  674.         scale_knob (new, loc, siz);
  675.         redisplay = TRUE;
  676.     }
  677.     }
  678.  
  679.     return redisplay;
  680. }
  681.  
  682. static void SetValuesAlmost (gold, gnew, req, reply)
  683.     Widget gold, gnew;
  684.     XtWidgetGeometry *req, *reply;
  685. {
  686.     if (reply->request_mode == 0) {    /* got turned down, so cope */
  687.     Resize (gnew);
  688.     }
  689.     (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
  690.     (gold, gnew, req, reply);
  691. }
  692.  
  693. static XtGeometryResult QueryGeometry (gw, intended, pref)
  694.     Widget gw;
  695.     XtWidgetGeometry *intended, *pref;
  696. {
  697.     PannerWidget pw = (PannerWidget) gw;
  698.  
  699.     pref->request_mode = (CWWidth | CWHeight);
  700.     get_default_size (pw, &pref->width, &pref->height);
  701.  
  702.     if (((intended->request_mode & (CWWidth | CWHeight)) ==
  703.      (CWWidth | CWHeight)) &&
  704.     intended->width == pref->width &&
  705.     intended->height == pref->height)
  706.       return XtGeometryYes;
  707.     else if (pref->width == pw->core.width && pref->height == pw->core.height)
  708.       return XtGeometryNo;
  709.     else
  710.       return XtGeometryAlmost;
  711. }
  712.  
  713.  
  714. /*****************************************************************************
  715.  *                                                                           *
  716.  *                   panner action procs                            *
  717.  *                                                                           *
  718.  *****************************************************************************/
  719.  
  720. /* ARGSUSED */
  721. static void ActionStart (gw, event, params, num_params)
  722.     Widget gw;
  723.     XEvent *event;
  724.     String *params;            /* unused */
  725.     Cardinal *num_params;        /* unused */
  726. {
  727.     PannerWidget pw = (PannerWidget) gw;
  728.     int x, y;
  729.  
  730.     if (!get_event_xy (pw, event, &x, &y)) {
  731.     XBell (XtDisplay(gw), 0);    /* should do error message */
  732.     return;
  733.     }
  734.  
  735.     pw->panner.tmp.doing = TRUE;
  736.     pw->panner.tmp.startx = pw->panner.knob_x;
  737.     pw->panner.tmp.starty = pw->panner.knob_y;
  738.     pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
  739.     pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
  740.     pw->panner.tmp.x = pw->panner.knob_x;
  741.     pw->panner.tmp.y = pw->panner.knob_y;
  742.     if (pw->panner.rubber_band) DRAW_TMP (pw);
  743. }
  744.  
  745. /* ARGSUSED */
  746. static void ActionStop (gw, event, params, num_params)
  747.     Widget gw;
  748.     XEvent *event;
  749.     String *params;            /* unused */
  750.     Cardinal *num_params;        /* unused */
  751. {
  752.     PannerWidget pw = (PannerWidget) gw;
  753.     int x, y;
  754.  
  755.     if (get_event_xy (pw, event, &x, &y)) {
  756.     pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
  757.     pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
  758.     if (!pw->panner.allow_off) check_knob (pw, FALSE);
  759.     }
  760.     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
  761.     pw->panner.tmp.doing = FALSE;
  762. }
  763.  
  764. /* ARGSUSED */
  765. static void ActionAbort (gw, event, params, num_params)
  766.     Widget gw;
  767.     XEvent *event;
  768.     String *params;            /* unused */
  769.     Cardinal *num_params;        /* unused */
  770. {
  771.     PannerWidget pw = (PannerWidget) gw;
  772.  
  773.     if (!pw->panner.tmp.doing) return;
  774.  
  775.     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
  776.  
  777.     if (!pw->panner.rubber_band) {        /* restore old position */
  778.     pw->panner.tmp.x = pw->panner.tmp.startx;
  779.     pw->panner.tmp.y = pw->panner.tmp.starty;
  780.     ActionNotify (gw, event, params, num_params);
  781.     }
  782.     pw->panner.tmp.doing = FALSE;
  783. }
  784.  
  785.  
  786. /* ARGSUSED */
  787. static void ActionMove (gw, event, params, num_params)
  788.     Widget gw;
  789.     XEvent *event;            /* must be a motion event */
  790.     String *params;            /* unused */
  791.     Cardinal *num_params;        /* unused */
  792. {
  793.     PannerWidget pw = (PannerWidget) gw;
  794.     int x, y;
  795.  
  796.     if (!pw->panner.tmp.doing) return;
  797.  
  798.     if (!get_event_xy (pw, event, &x, &y)) {
  799.     XBell (XtDisplay(gw), 0);    /* should do error message */
  800.     return;
  801.     }
  802.  
  803.     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
  804.     pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
  805.     pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
  806.  
  807.     if (!pw->panner.rubber_band) {
  808.     ActionNotify (gw, event, params, num_params);  /* does a check */
  809.     } else {
  810.     if (!pw->panner.allow_off) check_knob (pw, FALSE);
  811.     DRAW_TMP (pw);
  812.     }
  813. }
  814.  
  815.  
  816. /* ARGSUSED */
  817. static void ActionPage (gw, event, params, num_params)
  818.     Widget gw;
  819.     XEvent *event;            /* unused */
  820.     String *params;
  821.     Cardinal *num_params;        /* unused */
  822. {
  823.     PannerWidget pw = (PannerWidget) gw;
  824.     Cardinal zero = 0;
  825.     Boolean isin = pw->panner.tmp.doing;
  826.     int x, y;
  827.     Boolean relx, rely;
  828.     int pad = pw->panner.internal_border * 2;
  829.  
  830.     if (*num_params != 2) {
  831.     XBell (XtDisplay(gw), 0);
  832.     return;
  833.     }
  834.  
  835.     x = parse_page_string (params[0], (int) pw->panner.knob_width,
  836.                ((int) pw->core.width) - pad, &relx);
  837.     y = parse_page_string (params[1], (int) pw->panner.knob_height,
  838.                ((int) pw->core.height) - pad, &rely);
  839.  
  840.     if (relx) x += pw->panner.knob_x;
  841.     if (rely) y += pw->panner.knob_y;
  842.  
  843.     if (isin) {                /* if in, then use move */
  844.     XEvent ev;
  845.     ev.xbutton.type = ButtonPress;
  846.     ev.xbutton.x = x;
  847.     ev.xbutton.y = y;
  848.     ActionMove (gw, &ev, (String *) NULL, &zero);
  849.     } else {                /* else just do it */
  850.     pw->panner.tmp.doing = TRUE;
  851.     pw->panner.tmp.x = x;
  852.     pw->panner.tmp.y = y;
  853.     ActionNotify (gw, event, (String *) NULL, &zero);
  854.     pw->panner.tmp.doing = FALSE;
  855.     }
  856. }
  857.  
  858.  
  859. /* ARGSUSED */
  860. static void ActionNotify (gw, event, params, num_params)
  861.     Widget gw;
  862.     XEvent *event;            /* unused */
  863.     String *params;            /* unused */
  864.     Cardinal *num_params;        /* unused */
  865. {
  866.     PannerWidget pw = (PannerWidget) gw;
  867.  
  868.     if (!pw->panner.tmp.doing) return;
  869.  
  870.     if (!pw->panner.allow_off) check_knob (pw, FALSE);
  871.     pw->panner.knob_x = pw->panner.tmp.x;
  872.     pw->panner.knob_y = pw->panner.tmp.y;
  873.     move_shadow (pw);
  874.  
  875.     pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
  876.                       pw->panner.haspect + 0.5);
  877.     pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
  878.                       pw->panner.vaspect + 0.5);
  879.     if (!pw->panner.allow_off) {
  880.     Position tmp;
  881.     
  882.     if (pw->panner.slider_x >
  883.         (tmp = (((Position) pw->panner.canvas_width) - 
  884.             ((Position) pw->panner.slider_width))))
  885.       pw->panner.slider_x = tmp;
  886.     if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
  887.     if (pw->panner.slider_y >
  888.         (tmp = (((Position) pw->panner.canvas_height) - 
  889.             ((Position) pw->panner.slider_height))))
  890.       pw->panner.slider_y = tmp;
  891.     if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
  892.     }
  893.  
  894.     if (pw->panner.last_x != pw->panner.knob_x ||
  895.     pw->panner.last_y != pw->panner.knob_y) {
  896.     XawPannerReport rep;
  897.  
  898.     Redisplay (gw, (XEvent*) NULL, (Region) NULL);
  899.     rep.changed = (XawPRSliderX | XawPRSliderY);
  900.     rep.slider_x = pw->panner.slider_x;
  901.     rep.slider_y = pw->panner.slider_y;
  902.     rep.slider_width = pw->panner.slider_width;
  903.     rep.slider_height = pw->panner.slider_height;
  904.     rep.canvas_width = pw->panner.canvas_width;
  905.     rep.canvas_height = pw->panner.canvas_height;
  906.     XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
  907.     }
  908. }
  909.  
  910. /* ARGSUSED */
  911. static void ActionSet (gw, event, params, num_params)
  912.     Widget gw;
  913.     XEvent *event;            /* unused */
  914.     String *params;
  915.     Cardinal *num_params;
  916. {
  917.     PannerWidget pw = (PannerWidget) gw;
  918.     Boolean rb;
  919.  
  920.     if (*num_params < 2 ||
  921.     XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
  922.     XBell (XtDisplay(gw), 0);
  923.     return;
  924.     }
  925.  
  926.     if (XmuCompareISOLatin1 (params[1], "on") == 0) {
  927.     rb = TRUE;
  928.     } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
  929.     rb = FALSE;
  930.     } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
  931.     rb = !pw->panner.rubber_band;
  932.     } else {
  933.     XBell (XtDisplay(gw), 0);
  934.     return;
  935.     }
  936.  
  937.     if (rb != pw->panner.rubber_band) {
  938.     Arg args[1];
  939.     XtSetArg (args[0], XtNrubberBand, rb);
  940.     XtSetValues (gw, args, (Cardinal) 1);
  941.     }
  942. }
  943.