00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <X11/IntrinsicP.h>
00031 #include <X11/StringDefs.h>
00032 #include <X11/Xmu/CharSet.h>
00033 #include <X11/Xaw3d/XawInit.h>
00034 #include <X11/Xaw3d/PannerP.h>
00035 #include <X11/Xos.h>
00036 #include <X11/Xmu/Misc.h>
00037 #include <X11/Xmu/Drawing.h>
00038 #include <ctype.h>
00039 #include <math.h>
00040
00041 extern Bool XmuDistinguishablePixels();
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 },
00074 { "stop", ActionStop },
00075 { "abort", ActionAbort },
00076 { "move", ActionMove },
00077 { "page", ActionPage },
00078 { "notify", ActionNotify },
00079 { "set", ActionSet },
00080 };
00081
00082
00083
00084
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
00128
00129 static void Initialize();
00130 static void Realize();
00131 static void Destroy();
00132 static void Resize();
00133 static void Redisplay();
00134 static Boolean SetValues();
00135 static void SetValuesAlmost();
00136 static XtGeometryResult QueryGeometry();
00137
00138 PannerClassRec pannerClassRec = {
00139 {
00140 (WidgetClass) &simpleClassRec,
00141 "Panner",
00142 sizeof(PannerRec),
00143 XawInitializeWidgetSet,
00144 NULL,
00145 FALSE,
00146 Initialize,
00147 NULL,
00148 Realize,
00149 actions,
00150 XtNumber(actions),
00151 resources,
00152 XtNumber(resources),
00153 NULLQUARK,
00154 TRUE,
00155 TRUE,
00156 TRUE,
00157 FALSE,
00158 Destroy,
00159 Resize,
00160 Redisplay,
00161 SetValues,
00162 NULL,
00163 SetValuesAlmost,
00164 NULL,
00165 NULL,
00166 XtVersion,
00167 NULL,
00168 defaultTranslations,
00169 QueryGeometry,
00170 XtInheritDisplayAccelerator,
00171 NULL
00172 },
00173 {
00174 XtInheritChangeSensitive
00175 },
00176 {
00177 0
00178 }
00179 };
00180
00181 WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
00182
00183
00184
00185
00186
00187
00188
00189
00190 static void reset_shadow_gc (pw)
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)
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)
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
00284
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)
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
00432
00433
00434 for (; isascii(*s) && isspace(*s); s++) ;
00435
00436 if (*s == '+' || *s == '-') {
00437 rel = TRUE;
00438 if (*s == '-') val = -1.0;
00439 s++;
00440 }
00441 if (!*s) {
00442 *relative = TRUE;
00443 return 0;
00444 }
00445
00446
00447 for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
00448 val *= atof (cp);
00449
00450
00451 for (; isascii(*s) && isspace(*s); s++) ;
00452
00453 if (*s) {
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
00496
00497
00498
00499
00500
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);
00520 new->panner.slider_gc = NULL;
00521 reset_slider_gc (new);
00522 new->panner.xor_gc = NULL;
00523 reset_xor_gc (new);
00524
00525 rescale (new);
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
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
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);
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) {
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
00732
00733
00734
00735
00736 static void ActionStart (gw, event, params, num_params)
00737 Widget gw;
00738 XEvent *event;
00739 String *params;
00740 Cardinal *num_params;
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);
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
00761 static void ActionStop (gw, event, params, num_params)
00762 Widget gw;
00763 XEvent *event;
00764 String *params;
00765 Cardinal *num_params;
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
00780 static void ActionAbort (gw, event, params, num_params)
00781 Widget gw;
00782 XEvent *event;
00783 String *params;
00784 Cardinal *num_params;
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) {
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
00802 static void ActionMove (gw, event, params, num_params)
00803 Widget gw;
00804 XEvent *event;
00805 String *params;
00806 Cardinal *num_params;
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);
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);
00824 } else {
00825 if (!pw->panner.allow_off) check_knob (pw, FALSE);
00826 DRAW_TMP (pw);
00827 }
00828 }
00829
00830
00831
00832 static void ActionPage (gw, event, params, num_params)
00833 Widget gw;
00834 XEvent *event;
00835 String *params;
00836 Cardinal *num_params;
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) {
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 {
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
00875 static void ActionNotify (gw, event, params, num_params)
00876 Widget gw;
00877 XEvent *event;
00878 String *params;
00879 Cardinal *num_params;
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
00926 static void ActionSet (gw, event, params, num_params)
00927 Widget gw;
00928 XEvent *event;
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 }