Panner.c

Go to the documentation of this file.
00001 /*
00002  * $XConsortium: Panner.c,v 1.52 95/01/10 14:31:26 kaleb Exp $
00003  *
00004 Copyright (c) 1989, 1994  X Consortium
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a copy
00007 of this software and associated documentation files (the "Software"), to deal
00008 in the Software without restriction, including without limitation the rights
00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, subject to the following conditions:
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 Except as contained in this notice, the name of the X Consortium shall not be
00024 used in advertising or otherwise to promote the sale, use or other dealings
00025 in this Software without prior written authorization from the X Consortium.
00026  *
00027  * Author:  Jim Fulton, MIT X Consortium
00028  */
00029 
00030 #include <X11/IntrinsicP.h>
00031 #include <X11/StringDefs.h>             /* for XtN and XtC defines */
00032 #include <X11/Xmu/CharSet.h>            /* for XmuCompareISOLatin1() */
00033 #include <X11/Xaw3d/XawInit.h>          /* for XawInitializeWidgetSet */
00034 #include <X11/Xaw3d/PannerP.h>          /* us */
00035 #include <X11/Xos.h>
00036 #include <X11/Xmu/Misc.h>               /* for Min */
00037 #include <X11/Xmu/Drawing.h>
00038 #include <ctype.h>                      /* for isascii() etc. */
00039 #include <math.h>                       /* for atof() */
00040 
00041 extern Bool XmuDistinguishablePixels(); /* not defined in any Xmu headers */
00042 
00043 #if defined(ISC) && __STDC__ && !defined(ISC30)
00044 extern double atof(char *);
00045 #endif
00046 
00047 static char defaultTranslations[] = 
00048   "<Btn1Down>:    start() \n\
00049    <Btn1Motion>:  move() \n\
00050    <Btn1Up>:      notify() stop() \n\
00051    <Btn2Down>:    abort() \n\
00052    :<Key>KP_Enter: set(rubberband,toggle) \n\
00053    <Key>space:    page(+1p,+1p) \n\
00054    <Key>Delete:   page(-1p,-1p) \n\
00055    :<Key>KP_Delete: page(-1p,-1p) \n\
00056    <Key>BackSpace: page(-1p,-1p) \n\
00057    <Key>Left:     page(-.5p,+0) \n\
00058    :<Key>KP_Left:  page(-.5p,+0) \n\
00059    <Key>Right:    page(+.5p,+0) \n\
00060    :<Key>KP_Right: page(+.5p,+0) \n\
00061    <Key>Up:       page(+0,-.5p) \n\
00062    :<Key>KP_Up:    page(+0,-.5p) \n\
00063    <Key>Down:     page(+0,+.5p) \n\
00064    :<Key>KP_Down:  page(+0,+.5p) \n\
00065    <Key>Home:     page(0,0) \n\
00066    :<Key>KP_Home:  page(0,0)";
00067 
00068 
00069 static void ActionStart(), ActionStop(), ActionAbort(), ActionMove();
00070 static void ActionPage(), ActionNotify(), ActionSet();
00071 
00072 static XtActionsRec actions[] = {
00073     { "start", ActionStart },           /* start tmp graphics */
00074     { "stop", ActionStop },             /* stop tmp graphics */
00075     { "abort", ActionAbort },           /* punt */
00076     { "move", ActionMove },             /* move tmp graphics on Motion event */
00077     { "page", ActionPage },             /* page around usually from keyboard */
00078     { "notify", ActionNotify },         /* callback new position */
00079     { "set", ActionSet },               /* set various parameters */
00080 };
00081 
00082 
00083 /*
00084  * resources for the panner
00085  */
00086 static XtResource resources[] = {
00087 #define poff(field) XtOffsetOf(PannerRec, panner.field)
00088     { XtNallowOff, XtCAllowOff, XtRBoolean, sizeof(Boolean),
00089         poff(allow_off), XtRImmediate, (XtPointer) FALSE },
00090     { XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
00091         poff(resize_to_pref), XtRImmediate, (XtPointer) TRUE },
00092     { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
00093         poff(report_callbacks), XtRCallback, (XtPointer) NULL },
00094     { XtNdefaultScale, XtCDefaultScale, XtRDimension, sizeof(Dimension),
00095         poff(default_scale), XtRImmediate, (XtPointer) PANNER_DEFAULT_SCALE },
00096     { XtNrubberBand, XtCRubberBand, XtRBoolean, sizeof(Boolean),
00097         poff(rubber_band), XtRImmediate, (XtPointer) FALSE },
00098     { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 
00099         poff(foreground), XtRString, (XtPointer) XtDefaultBackground },
00100     { XtNinternalSpace, XtCInternalSpace, XtRDimension, sizeof(Dimension),
00101         poff(internal_border), XtRImmediate, (XtPointer) 4 },
00102     { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof(Dimension),
00103         poff(line_width), XtRImmediate, (XtPointer) 0 },
00104     { XtNcanvasWidth, XtCCanvasWidth, XtRDimension, sizeof(Dimension),
00105         poff(canvas_width), XtRImmediate, (XtPointer) 0 },
00106     { XtNcanvasHeight, XtCCanvasHeight, XtRDimension, sizeof(Dimension),
00107         poff(canvas_height), XtRImmediate, (XtPointer) 0 },
00108     { XtNsliderX, XtCSliderX, XtRPosition, sizeof(Position),
00109         poff(slider_x), XtRImmediate, (XtPointer) 0 },
00110     { XtNsliderY, XtCSliderY, XtRPosition, sizeof(Position),
00111         poff(slider_y), XtRImmediate, (XtPointer) 0 },
00112     { XtNsliderWidth, XtCSliderWidth, XtRDimension, sizeof(Dimension),
00113         poff(slider_width), XtRImmediate, (XtPointer) 0 },
00114     { XtNsliderHeight, XtCSliderHeight, XtRDimension, sizeof(Dimension),
00115         poff(slider_height), XtRImmediate, (XtPointer) 0 },
00116     { XtNshadowColor, XtCShadowColor, XtRPixel, sizeof(Pixel),
00117         poff(shadow_color), XtRString, (XtPointer) XtDefaultForeground },
00118     { XtNshadowThickness, XtCShadowThickness, XtRDimension, sizeof(Dimension),
00119         poff(shadow_thickness), XtRImmediate, (XtPointer) 2 },
00120     { XtNbackgroundStipple, XtCBackgroundStipple, XtRString, sizeof(String),
00121         poff(stipple_name), XtRImmediate, (XtPointer) NULL },
00122 #undef poff
00123 };
00124 
00125 
00126 /*
00127  * widget class methods used below
00128  */
00129 static void Initialize();               /* create gc's */
00130 static void Realize();                  /* create window */
00131 static void Destroy();                  /* clean up widget */
00132 static void Resize();                   /* need to rescale ourselves */
00133 static void Redisplay();                /* draw ourselves */
00134 static Boolean SetValues();             /* set all of the resources */
00135 static void SetValuesAlmost();          /* deal with failed setval geom req */
00136 static XtGeometryResult QueryGeometry();  /* say how big we would like to be */
00137 
00138 PannerClassRec pannerClassRec = {
00139   { /* core fields */
00140     /* superclass               */      (WidgetClass) &simpleClassRec,
00141     /* class_name               */      "Panner",
00142     /* widget_size              */      sizeof(PannerRec),
00143     /* class_initialize         */      XawInitializeWidgetSet,
00144     /* class_part_initialize    */      NULL,
00145     /* class_inited             */      FALSE,
00146     /* initialize               */      Initialize,
00147     /* initialize_hook          */      NULL,
00148     /* realize                  */      Realize,
00149     /* actions                  */      actions,
00150     /* num_actions              */      XtNumber(actions),
00151     /* resources                */      resources,
00152     /* num_resources            */      XtNumber(resources),
00153     /* xrm_class                */      NULLQUARK,
00154     /* compress_motion          */      TRUE,
00155     /* compress_exposure        */      TRUE,
00156     /* compress_enterleave      */      TRUE,
00157     /* visible_interest         */      FALSE,
00158     /* destroy                  */      Destroy,
00159     /* resize                   */      Resize,
00160     /* expose                   */      Redisplay,
00161     /* set_values               */      SetValues,
00162     /* set_values_hook          */      NULL,
00163     /* set_values_almost        */      SetValuesAlmost,
00164     /* get_values_hook          */      NULL,
00165     /* accept_focus             */      NULL,
00166     /* version                  */      XtVersion,
00167     /* callback_private         */      NULL,
00168     /* tm_table                 */      defaultTranslations,
00169     /* query_geometry           */      QueryGeometry,
00170     /* display_accelerator      */      XtInheritDisplayAccelerator,
00171     /* extension                */      NULL
00172   },
00173   { /* simple fields */
00174     /* change_sensitive         */      XtInheritChangeSensitive
00175   },
00176   { /* panner fields */
00177     /* ignore                   */      0
00178   }
00179 };
00180 
00181 WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
00182 
00183 
00184 /*****************************************************************************
00185  *                                                                           *
00186  *                          panner utility routines                          *
00187  *                                                                           *
00188  *****************************************************************************/
00189 
00190 static void reset_shadow_gc (pw)        /* used when resources change */
00191     PannerWidget pw;
00192 {
00193     XtGCMask valuemask = GCForeground;
00194     XGCValues values;
00195     unsigned long   pixels[3];
00196 
00197     if (pw->panner.shadow_gc) XtReleaseGC ((Widget) pw, pw->panner.shadow_gc);
00198 
00199     pixels[0] = pw->panner.foreground;
00200     pixels[1] = pw->core.background_pixel;
00201     pixels[2] = pw->panner.shadow_color;
00202     if (!pw->panner.stipple_name &&
00203         !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
00204                                     pixels, 3) &&
00205         XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
00206                                     pixels, 2))
00207     {
00208         valuemask = GCTile | GCFillStyle;
00209         values.fill_style = FillTiled;
00210         values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
00211                                               pw->panner.foreground,
00212                                               pw->core.background_pixel,
00213                                               pw->core.depth);
00214     }
00215     else
00216     {
00217         if (!pw->panner.line_width &&
00218             !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
00219                                        pixels, 2))
00220             pw->panner.line_width = 1;
00221         valuemask = GCForeground;
00222         values.foreground = pw->panner.shadow_color;
00223     }
00224     if (pw->panner.line_width > 0) {
00225         values.line_width = pw->panner.line_width;
00226         valuemask |= GCLineWidth;
00227     }
00228 
00229     pw->panner.shadow_gc = XtGetGC ((Widget) pw, valuemask, &values);
00230 }
00231 
00232 static void reset_slider_gc (pw)        /* used when resources change */
00233     PannerWidget pw;
00234 {
00235     XtGCMask valuemask = GCForeground;
00236     XGCValues values;
00237 
00238     if (pw->panner.slider_gc) XtReleaseGC ((Widget) pw, pw->panner.slider_gc);
00239 
00240     values.foreground = pw->panner.foreground;
00241 
00242     pw->panner.slider_gc = XtGetGC ((Widget) pw, valuemask, &values);
00243 }
00244 
00245 static void reset_xor_gc (pw)           /* used when resources change */
00246     PannerWidget pw;
00247 {
00248     if (pw->panner.xor_gc) XtReleaseGC ((Widget) pw, pw->panner.xor_gc);
00249 
00250     if (pw->panner.rubber_band) {
00251         XtGCMask valuemask = (GCForeground | GCFunction);
00252         XGCValues values;
00253         Pixel tmp;
00254 
00255         tmp = ((pw->panner.foreground == pw->core.background_pixel) ?
00256                pw->panner.shadow_color : pw->panner.foreground);
00257         values.foreground = tmp ^ pw->core.background_pixel;
00258         values.function = GXxor;
00259         if (pw->panner.line_width > 0) {
00260             valuemask |= GCLineWidth;
00261             values.line_width = pw->panner.line_width;
00262         }
00263         pw->panner.xor_gc = XtGetGC ((Widget) pw, valuemask, &values);
00264     } else {
00265         pw->panner.xor_gc = NULL;
00266     }
00267 }
00268 
00269 
00270 static void check_knob (pw, knob)
00271     PannerWidget pw;
00272     Boolean knob;
00273 {
00274     Position pad = pw->panner.internal_border * 2;
00275     Position maxx = (((Position) pw->core.width) - pad -
00276                      ((Position) pw->panner.knob_width));
00277     Position maxy = (((Position) pw->core.height) - pad -
00278                      ((Position) pw->panner.knob_height));
00279     Position *x = (knob ? &pw->panner.knob_x : &pw->panner.tmp.x);
00280     Position *y = (knob ? &pw->panner.knob_y : &pw->panner.tmp.y);
00281 
00282     /*
00283      * note that positions are already normalized (i.e. internal_border
00284      * has been subtracted out)
00285      */
00286     if (*x < 0) *x = 0;
00287     if (*x > maxx) *x = maxx;
00288 
00289     if (*y < 0) *y = 0;
00290     if (*y > maxy) *y = maxy;
00291 
00292     if (knob) {
00293         pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
00294                                           pw->panner.haspect + 0.5);
00295         pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
00296                                           pw->panner.vaspect + 0.5);
00297         pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
00298     }
00299 }
00300 
00301 
00302 static void move_shadow (pw)
00303     PannerWidget pw;
00304 {
00305     if (pw->panner.shadow_thickness > 0) {
00306         int lw = pw->panner.shadow_thickness + pw->panner.line_width * 2;
00307         int pad = pw->panner.internal_border;
00308 
00309         if ((int)pw->panner.knob_height > lw && (int)pw->panner.knob_width > lw) {
00310             XRectangle *r = pw->panner.shadow_rects;
00311             r->x = (short) (pw->panner.knob_x + pad + pw->panner.knob_width);
00312             r->y = (short) (pw->panner.knob_y + pad + lw);
00313             r->width = pw->panner.shadow_thickness;
00314             r->height = (unsigned short) (pw->panner.knob_height - lw);
00315             r++;
00316             r->x = (short) (pw->panner.knob_x + pad + lw);
00317             r->y = (short) (pw->panner.knob_y + pad + pw->panner.knob_height);
00318             r->width = (unsigned short) (pw->panner.knob_width - lw +
00319                                          pw->panner.shadow_thickness);
00320             r->height = pw->panner.shadow_thickness;
00321             pw->panner.shadow_valid = TRUE;
00322             return;
00323         }
00324     }
00325     pw->panner.shadow_valid = FALSE;
00326 }
00327 
00328 static void scale_knob (pw, location, size)  /* set knob size and/or loc */
00329     PannerWidget pw;
00330     Boolean location, size;
00331 {
00332     if (location) {
00333         pw->panner.knob_x = (Position) PANNER_HSCALE (pw, pw->panner.slider_x);
00334         pw->panner.knob_y = (Position) PANNER_VSCALE (pw, pw->panner.slider_y);
00335     }
00336     if (size) {
00337         Dimension width, height;
00338 
00339         if (pw->panner.slider_width < 1) {
00340             pw->panner.slider_width = pw->panner.canvas_width;
00341         }
00342         if (pw->panner.slider_height < 1) {
00343             pw->panner.slider_height = pw->panner.canvas_height;
00344         }
00345         width = Min (pw->panner.slider_width, pw->panner.canvas_width);
00346         height = Min (pw->panner.slider_height, pw->panner.canvas_height);
00347 
00348         pw->panner.knob_width = (Dimension) PANNER_HSCALE (pw, width);
00349         pw->panner.knob_height = (Dimension) PANNER_VSCALE (pw, height);
00350     }
00351     if (!pw->panner.allow_off) check_knob (pw, TRUE);
00352     move_shadow (pw);
00353 }
00354 
00355 static void rescale (pw)
00356     PannerWidget pw;
00357 {
00358     int hpad = pw->panner.internal_border * 2;
00359     int vpad = hpad;
00360 
00361     if (pw->panner.canvas_width < 1)
00362       pw->panner.canvas_width = pw->core.width;
00363     if (pw->panner.canvas_height < 1)
00364       pw->panner.canvas_height = pw->core.height;
00365 
00366     if ((int)pw->core.width <= hpad) hpad = 0;
00367     if ((int)pw->core.height <= vpad) vpad = 0;
00368 
00369     pw->panner.haspect = ((double) pw->core.width - hpad) /
00370                           (double) pw->panner.canvas_width;
00371     pw->panner.vaspect = ((double) pw->core.height - vpad) /
00372                           (double) pw->panner.canvas_height;
00373     scale_knob (pw, TRUE, TRUE);
00374 }
00375 
00376 
00377 static void get_default_size (pw, wp, hp)
00378     PannerWidget pw;
00379     Dimension *wp, *hp;
00380 {
00381     Dimension pad = pw->panner.internal_border * 2;
00382     *wp = PANNER_DSCALE (pw, pw->panner.canvas_width) + pad;
00383     *hp = PANNER_DSCALE (pw, pw->panner.canvas_height) + pad;
00384 }
00385 
00386 static Boolean get_event_xy (pw, event, x, y)
00387     PannerWidget pw;
00388     XEvent *event;
00389     int *x, *y;
00390 {
00391     int pad = pw->panner.internal_border;
00392 
00393     switch (event->type) {
00394       case ButtonPress:
00395       case ButtonRelease:
00396         *x = event->xbutton.x - pad;
00397         *y = event->xbutton.y - pad;
00398         return TRUE;
00399 
00400       case KeyPress:
00401       case KeyRelease:
00402         *x = event->xkey.x - pad;
00403         *y = event->xkey.y - pad;
00404         return TRUE;
00405 
00406       case EnterNotify:
00407       case LeaveNotify:
00408         *x = event->xcrossing.x - pad;
00409         *y = event->xcrossing.y - pad;
00410         return TRUE;
00411 
00412       case MotionNotify:
00413         *x = event->xmotion.x - pad;
00414         *y = event->xmotion.y - pad;
00415         return TRUE;
00416     }
00417 
00418     return FALSE;
00419 }
00420 
00421 static int parse_page_string (s, pagesize, canvassize, relative)
00422     char *s;
00423     int pagesize, canvassize;
00424     Boolean *relative;
00425 {
00426     char *cp;
00427     double val = 1.0;
00428     Boolean rel = FALSE;
00429 
00430     /*
00431      * syntax:    spaces [+-] number spaces [pc\0] spaces
00432      */
00433 
00434     for (; isascii(*s) && isspace(*s); s++) ;   /* skip white space */
00435 
00436     if (*s == '+' || *s == '-') {       /* deal with signs */
00437         rel = TRUE;
00438         if (*s == '-') val = -1.0;
00439         s++;
00440     }
00441     if (!*s) {                          /* if null then return nothing */
00442         *relative = TRUE;
00443         return 0;
00444     }
00445 
00446                                         /* skip over numbers */
00447     for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
00448     val *= atof (cp);
00449 
00450                                         /* skip blanks */
00451     for (; isascii(*s) && isspace(*s); s++) ;
00452 
00453     if (*s) {                           /* if units */
00454         switch (s[0]) {
00455           case 'p': case 'P':
00456             val *= (double) pagesize;
00457             break;
00458 
00459           case 'c': case 'C':
00460             val *= (double) canvassize;
00461             break;
00462         }
00463     }
00464     *relative = rel;
00465     return ((int) val);
00466 }
00467 
00468 
00469 #define DRAW_TMP(pw) \
00470 { \
00471     XDrawRectangle (XtDisplay(pw), XtWindow(pw), \
00472                     pw->panner.xor_gc, \
00473                     (int) (pw->panner.tmp.x + pw->panner.internal_border), \
00474                     (int) (pw->panner.tmp.y + pw->panner.internal_border), \
00475                     (unsigned int) (pw->panner.knob_width - 1), \
00476                     (unsigned int) (pw->panner.knob_height - 1)); \
00477     pw->panner.tmp.showing = !pw->panner.tmp.showing; \
00478 }
00479 
00480 #define UNDRAW_TMP(pw) \
00481 { \
00482     if (pw->panner.tmp.showing) DRAW_TMP(pw); \
00483 }
00484 
00485 #define BACKGROUND_STIPPLE(pw) \
00486   XmuLocatePixmapFile (pw->core.screen, pw->panner.stipple_name, \
00487                        pw->panner.shadow_color, pw->core.background_pixel, \
00488                        pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
00489     
00490 #define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
00491 
00492 
00493 /*****************************************************************************
00494  *                                                                           *
00495  *                           panner class methods                            *
00496  *                                                                           *
00497  *****************************************************************************/
00498 
00499 
00500 /*ARGSUSED*/
00501 static void Initialize (greq, gnew, args, num_args)
00502     Widget greq, gnew;
00503     ArgList args;
00504     Cardinal *num_args;
00505 {
00506     PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
00507     Dimension defwidth, defheight;
00508 
00509     if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
00510     if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
00511     if (req->panner.default_scale < 1)
00512       new->panner.default_scale = PANNER_DEFAULT_SCALE;
00513 
00514     get_default_size (req, &defwidth, &defheight);
00515     if (req->core.width < 1) new->core.width = defwidth;
00516     if (req->core.height < 1) new->core.height = defheight;
00517 
00518     new->panner.shadow_gc = NULL;
00519     reset_shadow_gc (new);              /* shadowColor */
00520     new->panner.slider_gc = NULL;
00521     reset_slider_gc (new);              /* foreground */
00522     new->panner.xor_gc = NULL;
00523     reset_xor_gc (new);                 /* foreground ^ background */
00524 
00525     rescale (new);                      /* does a position check */
00526     new->panner.shadow_valid = FALSE;
00527     new->panner.tmp.doing = FALSE;
00528     new->panner.tmp.showing = FALSE;
00529 }
00530 
00531 
00532 static void Realize (gw, valuemaskp, attr)
00533     Widget gw;
00534     XtValueMask *valuemaskp;
00535     XSetWindowAttributes *attr;
00536 {
00537     PannerWidget pw = (PannerWidget) gw;
00538     Pixmap pm = XtUnspecifiedPixmap;
00539     Boolean gotpm = FALSE;
00540 
00541     if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
00542         if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
00543 
00544         if (PIXMAP_OKAY(pm)) {
00545             attr->background_pixmap = pm;
00546             *valuemaskp |= CWBackPixmap;
00547             *valuemaskp &= ~CWBackPixel;
00548             gotpm = TRUE;
00549         }
00550     }
00551     (*pannerWidgetClass->core_class.superclass->core_class.realize)
00552       (gw, valuemaskp, attr);
00553 
00554     if (gotpm) XFreePixmap (XtDisplay(gw), pm);
00555 }
00556 
00557 
00558 static void Destroy (gw)
00559     Widget gw;
00560 {
00561     PannerWidget pw = (PannerWidget) gw;
00562 
00563     XtReleaseGC (gw, pw->panner.shadow_gc);
00564     XtReleaseGC (gw, pw->panner.slider_gc);
00565     XtReleaseGC (gw, pw->panner.xor_gc);
00566 }
00567 
00568 
00569 static void Resize (gw)
00570     Widget gw;
00571 {
00572     rescale ((PannerWidget) gw);
00573 }
00574 
00575 
00576 /* ARGSUSED */
00577 static void Redisplay (gw, event, region)
00578     Widget gw;
00579     XEvent *event;
00580     Region region;
00581 {
00582     PannerWidget pw = (PannerWidget) gw;
00583     Display *dpy = XtDisplay(gw);
00584     Window w = XtWindow(gw);
00585     int pad = pw->panner.internal_border;
00586     Dimension lw = pw->panner.line_width;
00587     Dimension extra = pw->panner.shadow_thickness + lw * 2;
00588     int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
00589 
00590     pw->panner.tmp.showing = FALSE;
00591     XClearArea (XtDisplay(pw), XtWindow(pw), 
00592                 (int) pw->panner.last_x - ((int) lw) + pad, 
00593                 (int) pw->panner.last_y - ((int) lw) + pad, 
00594                 (unsigned int) (pw->panner.knob_width + extra),
00595                 (unsigned int) (pw->panner.knob_height + extra),
00596                 False);
00597     pw->panner.last_x = pw->panner.knob_x;
00598     pw->panner.last_y = pw->panner.knob_y;
00599 
00600     XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
00601                     pw->panner.knob_width - 1, pw->panner.knob_height - 1);
00602 
00603     if (lw)
00604     {
00605         XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
00606                         (unsigned int) (pw->panner.knob_width - 1), 
00607                         (unsigned int) (pw->panner.knob_height - 1));
00608     }
00609 
00610     if (pw->panner.shadow_valid) {
00611         XFillRectangles (dpy, w, pw->panner.shadow_gc,
00612                          pw->panner.shadow_rects, 2);
00613     }
00614     if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
00615 }
00616 
00617 
00618 /* ARGSUSED */
00619 static Boolean SetValues (gcur, greq, gnew, args, num_args)
00620     Widget gcur, greq, gnew;
00621     ArgList args;
00622     Cardinal *num_args;
00623 {
00624     PannerWidget cur = (PannerWidget) gcur;
00625     PannerWidget new = (PannerWidget) gnew;
00626     Boolean redisplay = FALSE;
00627 
00628     if (cur->panner.foreground != new->panner.foreground) {
00629         reset_slider_gc (new);
00630         if (cur->panner.foreground != cur->core.background_pixel)
00631           reset_xor_gc (new);
00632         redisplay = TRUE;
00633     } else if (cur->panner.line_width != new->panner.line_width ||
00634                cur->core.background_pixel != new->core.background_pixel) {
00635         reset_xor_gc (new);
00636         redisplay = TRUE;
00637     }
00638     if (cur->panner.shadow_color != new->panner.shadow_color) {
00639         reset_shadow_gc (new);
00640         if (cur->panner.foreground == cur->core.background_pixel)
00641           reset_xor_gc (new);
00642         redisplay = TRUE;
00643     }
00644     if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
00645         move_shadow (new);
00646         redisplay = TRUE;
00647     }
00648     if (cur->panner.rubber_band != new->panner.rubber_band) {
00649         reset_xor_gc (new);
00650         if (new->panner.tmp.doing) redisplay = TRUE;
00651     }
00652 
00653     if ((cur->panner.stipple_name != new->panner.stipple_name ||
00654          cur->panner.shadow_color != new->panner.shadow_color ||
00655          cur->core.background_pixel != new->core.background_pixel) &&
00656         XtIsRealized(gnew)) {
00657         Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
00658                      : XtUnspecifiedPixmap);
00659 
00660         if (PIXMAP_OKAY(pm)) {
00661             XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
00662             XFreePixmap (XtDisplay (new), pm);
00663         } else {
00664             XSetWindowBackground (XtDisplay (new), XtWindow(new),
00665                                   new->core.background_pixel);
00666         }
00667         redisplay = TRUE;
00668     }
00669 
00670     if (new->panner.resize_to_pref &&
00671         (cur->panner.canvas_width != new->panner.canvas_width ||
00672          cur->panner.canvas_height != new->panner.canvas_height ||
00673          cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
00674         get_default_size (new, &new->core.width, &new->core.height);
00675         redisplay = TRUE;
00676     } else if (cur->panner.canvas_width != new->panner.canvas_width ||
00677         cur->panner.canvas_height != new->panner.canvas_height ||
00678         cur->panner.internal_border != new->panner.internal_border) {
00679         rescale (new);                  /* does a scale_knob as well */
00680         redisplay = TRUE;
00681     } else {
00682         Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
00683                        cur->panner.slider_y != new->panner.slider_y);
00684         Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
00685                        cur->panner.slider_height != new->panner.slider_height);
00686         if (loc || siz ||
00687             (cur->panner.allow_off != new->panner.allow_off &&
00688              new->panner.allow_off)) {
00689             scale_knob (new, loc, siz);
00690             redisplay = TRUE;
00691         }
00692     }
00693 
00694     return redisplay;
00695 }
00696 
00697 static void SetValuesAlmost (gold, gnew, req, reply)
00698     Widget gold, gnew;
00699     XtWidgetGeometry *req, *reply;
00700 {
00701     if (reply->request_mode == 0) {     /* got turned down, so cope */
00702         Resize (gnew);
00703     }
00704     (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
00705         (gold, gnew, req, reply);
00706 }
00707 
00708 static XtGeometryResult QueryGeometry (gw, intended, pref)
00709     Widget gw;
00710     XtWidgetGeometry *intended, *pref;
00711 {
00712     PannerWidget pw = (PannerWidget) gw;
00713 
00714     pref->request_mode = (CWWidth | CWHeight);
00715     get_default_size (pw, &pref->width, &pref->height);
00716 
00717     if (((intended->request_mode & (CWWidth | CWHeight)) ==
00718          (CWWidth | CWHeight)) &&
00719         intended->width == pref->width &&
00720         intended->height == pref->height)
00721       return XtGeometryYes;
00722     else if (pref->width == pw->core.width && pref->height == pw->core.height)
00723       return XtGeometryNo;
00724     else
00725       return XtGeometryAlmost;
00726 }
00727 
00728 
00729 /*****************************************************************************
00730  *                                                                           *
00731  *                            panner action procs                            *
00732  *                                                                           *
00733  *****************************************************************************/
00734 
00735 /* ARGSUSED */
00736 static void ActionStart (gw, event, params, num_params)
00737     Widget gw;
00738     XEvent *event;
00739     String *params;                     /* unused */
00740     Cardinal *num_params;               /* unused */
00741 {
00742     PannerWidget pw = (PannerWidget) gw;
00743     int x, y;
00744 
00745     if (!get_event_xy (pw, event, &x, &y)) {
00746         XBell (XtDisplay(gw), 0);       /* should do error message */
00747         return;
00748     }
00749 
00750     pw->panner.tmp.doing = TRUE;
00751     pw->panner.tmp.startx = pw->panner.knob_x;
00752     pw->panner.tmp.starty = pw->panner.knob_y;
00753     pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
00754     pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
00755     pw->panner.tmp.x = pw->panner.knob_x;
00756     pw->panner.tmp.y = pw->panner.knob_y;
00757     if (pw->panner.rubber_band) DRAW_TMP (pw);
00758 }
00759 
00760 /* ARGSUSED */
00761 static void ActionStop (gw, event, params, num_params)
00762     Widget gw;
00763     XEvent *event;
00764     String *params;                     /* unused */
00765     Cardinal *num_params;               /* unused */
00766 {
00767     PannerWidget pw = (PannerWidget) gw;
00768     int x, y;
00769 
00770     if (get_event_xy (pw, event, &x, &y)) {
00771         pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
00772         pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
00773         if (!pw->panner.allow_off) check_knob (pw, FALSE);
00774     }
00775     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
00776     pw->panner.tmp.doing = FALSE;
00777 }
00778 
00779 /* ARGSUSED */
00780 static void ActionAbort (gw, event, params, num_params)
00781     Widget gw;
00782     XEvent *event;
00783     String *params;                     /* unused */
00784     Cardinal *num_params;               /* unused */
00785 {
00786     PannerWidget pw = (PannerWidget) gw;
00787 
00788     if (!pw->panner.tmp.doing) return;
00789 
00790     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
00791 
00792     if (!pw->panner.rubber_band) {              /* restore old position */
00793         pw->panner.tmp.x = pw->panner.tmp.startx;
00794         pw->panner.tmp.y = pw->panner.tmp.starty;
00795         ActionNotify (gw, event, params, num_params);
00796     }
00797     pw->panner.tmp.doing = FALSE;
00798 }
00799 
00800 
00801 /* ARGSUSED */
00802 static void ActionMove (gw, event, params, num_params)
00803     Widget gw;
00804     XEvent *event;                      /* must be a motion event */
00805     String *params;                     /* unused */
00806     Cardinal *num_params;               /* unused */
00807 {
00808     PannerWidget pw = (PannerWidget) gw;
00809     int x, y;
00810 
00811     if (!pw->panner.tmp.doing) return;
00812 
00813     if (!get_event_xy (pw, event, &x, &y)) {
00814         XBell (XtDisplay(gw), 0);       /* should do error message */
00815         return;
00816     }
00817 
00818     if (pw->panner.rubber_band) UNDRAW_TMP (pw);
00819     pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
00820     pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
00821 
00822     if (!pw->panner.rubber_band) {
00823         ActionNotify (gw, event, params, num_params);  /* does a check */
00824     } else {
00825         if (!pw->panner.allow_off) check_knob (pw, FALSE);
00826         DRAW_TMP (pw);
00827     }
00828 }
00829 
00830 
00831 /* ARGSUSED */
00832 static void ActionPage (gw, event, params, num_params)
00833     Widget gw;
00834     XEvent *event;                      /* unused */
00835     String *params;
00836     Cardinal *num_params;               /* unused */
00837 {
00838     PannerWidget pw = (PannerWidget) gw;
00839     Cardinal zero = 0;
00840     Boolean isin = pw->panner.tmp.doing;
00841     int x, y;
00842     Boolean relx, rely;
00843     int pad = pw->panner.internal_border * 2;
00844 
00845     if (*num_params != 2) {
00846         XBell (XtDisplay(gw), 0);
00847         return;
00848     }
00849 
00850     x = parse_page_string (params[0], (int) pw->panner.knob_width,
00851                            ((int) pw->core.width) - pad, &relx);
00852     y = parse_page_string (params[1], (int) pw->panner.knob_height,
00853                            ((int) pw->core.height) - pad, &rely);
00854 
00855     if (relx) x += pw->panner.knob_x;
00856     if (rely) y += pw->panner.knob_y;
00857 
00858     if (isin) {                         /* if in, then use move */
00859         XEvent ev;
00860         ev.xbutton.type = ButtonPress;
00861         ev.xbutton.x = x;
00862         ev.xbutton.y = y;
00863         ActionMove (gw, &ev, (String *) NULL, &zero);
00864     } else {                            /* else just do it */
00865         pw->panner.tmp.doing = TRUE;
00866         pw->panner.tmp.x = x;
00867         pw->panner.tmp.y = y;
00868         ActionNotify (gw, event, (String *) NULL, &zero);
00869         pw->panner.tmp.doing = FALSE;
00870     }
00871 }
00872 
00873 
00874 /* ARGSUSED */
00875 static void ActionNotify (gw, event, params, num_params)
00876     Widget gw;
00877     XEvent *event;                      /* unused */
00878     String *params;                     /* unused */
00879     Cardinal *num_params;               /* unused */
00880 {
00881     PannerWidget pw = (PannerWidget) gw;
00882 
00883     if (!pw->panner.tmp.doing) return;
00884 
00885     if (!pw->panner.allow_off) check_knob (pw, FALSE);
00886     pw->panner.knob_x = pw->panner.tmp.x;
00887     pw->panner.knob_y = pw->panner.tmp.y;
00888     move_shadow (pw);
00889 
00890     pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
00891                                       pw->panner.haspect + 0.5);
00892     pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
00893                                       pw->panner.vaspect + 0.5);
00894     if (!pw->panner.allow_off) {
00895         Position tmp;
00896         
00897         if (pw->panner.slider_x >
00898             (tmp = (((Position) pw->panner.canvas_width) - 
00899                     ((Position) pw->panner.slider_width))))
00900           pw->panner.slider_x = tmp;
00901         if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
00902         if (pw->panner.slider_y >
00903             (tmp = (((Position) pw->panner.canvas_height) - 
00904                     ((Position) pw->panner.slider_height))))
00905           pw->panner.slider_y = tmp;
00906         if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
00907     }
00908 
00909     if (pw->panner.last_x != pw->panner.knob_x ||
00910         pw->panner.last_y != pw->panner.knob_y) {
00911         XawPannerReport rep;
00912 
00913         Redisplay (gw, (XEvent*) NULL, (Region) NULL);
00914         rep.changed = (XawPRSliderX | XawPRSliderY);
00915         rep.slider_x = pw->panner.slider_x;
00916         rep.slider_y = pw->panner.slider_y;
00917         rep.slider_width = pw->panner.slider_width;
00918         rep.slider_height = pw->panner.slider_height;
00919         rep.canvas_width = pw->panner.canvas_width;
00920         rep.canvas_height = pw->panner.canvas_height;
00921         XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
00922     }
00923 }
00924 
00925 /* ARGSUSED */
00926 static void ActionSet (gw, event, params, num_params)
00927     Widget gw;
00928     XEvent *event;                      /* unused */
00929     String *params;
00930     Cardinal *num_params;
00931 {
00932     PannerWidget pw = (PannerWidget) gw;
00933     Boolean rb;
00934 
00935     if (*num_params < 2 ||
00936         XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
00937         XBell (XtDisplay(gw), 0);
00938         return;
00939     }
00940 
00941     if (XmuCompareISOLatin1 (params[1], "on") == 0) {
00942         rb = TRUE;
00943     } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
00944         rb = FALSE;
00945     } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
00946         rb = !pw->panner.rubber_band;
00947     } else {
00948         XBell (XtDisplay(gw), 0);
00949         return;
00950     }
00951 
00952     if (rb != pw->panner.rubber_band) {
00953         Arg args[1];
00954         XtSetArg (args[0], XtNrubberBand, rb);
00955         XtSetValues (gw, args, (Cardinal) 1);
00956     }
00957 }

Generated on Sun Mar 4 15:03:55 2007 for Scilab [trunk] by  doxygen 1.5.1