1 /*
2 * $XConsortium: Panner.c,v 1.52 95/01/10 14:31:26 kaleb Exp $
3 *
4 Copyright (c) 1989, 1994 X Consortium
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of the X Consortium shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the X Consortium.
26 *
27 * Author: Jim Fulton, MIT X Consortium
28 */
29
30 #include "xdvi-config.h"
31 #include "xdvi.h"
32 #include "string-utils.h"
33
34 #if defined(MOTIF) && defined(USE_PANNER) && USE_XAW_PANNER /* entire file */
35
36 #if defined(__GNUC__) && DEVEL_MODE
37 #warning COMPILING Panner_c
38 #endif
39
40 #include <X11/IntrinsicP.h>
41 #include <X11/StringDefs.h> /* for XtN and XtC defines */
42 #include <X11/Xmu/CharSet.h> /* for XmuCompareISOLatin1() */
43 #include "PannerP.h" /* us */
44 #include <X11/Xos.h>
45 #include <X11/Xmu/Misc.h> /* for Min */
46 #include <X11/Xmu/Drawing.h>
47 #include <ctype.h> /* for isascii() etc. */
48
49 extern Bool XmuDistinguishablePixels(); /* not defined in any Xmu headers */
50
51 #if HAVE_XKB_BELL_EXT
52 # include <X11/XKBlib.h>
53 # define panBell(display, window, percent) \
54 XkbBell(display, window, percent, (Atom) None)
55 #else
56 # define panBell(display, window, percent) XBell(display, percent)
57 #endif
58
59 /*
60 ======================================================================
61 begin copy from Simple.c
62 ======================================================================
63 */
64
65 #define offset(field) XtOffsetOf(SimpleRec, simple.field)
66
67 static XtResource resources[] = {
68 {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
69 offset(cursor), XtRImmediate, (XtPointer) None},
70 {XtNinsensitiveBorder, XtCInsensitive, XtRPixmap, sizeof(Pixmap),
71 offset(insensitive_border), XtRImmediate, (XtPointer) NULL},
72 {XtNpointerColor, XtCForeground, XtRPixel, sizeof(Pixel),
73 offset(pointer_fg), XtRString, XtDefaultForeground},
74 {XtNpointerColorBackground, XtCBackground, XtRPixel, sizeof(Pixel),
75 offset(pointer_bg), XtRString, XtDefaultBackground},
76 {XtNcursorName, XtCCursor, XtRString, sizeof(String),
77 offset(cursor_name), XtRString, NULL},
78 {XtNinternational, XtCInternational, XtRBoolean, sizeof(Boolean),
79 offset(international), XtRImmediate, (XtPointer) FALSE},
80 #undef offset
81 };
82
83 static void ClassPartInitialize(), ClassInitialize(),Realize(),ConvertCursor();
84 static Bool SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args);
85 static Bool ChangeSensitive(Widget w);
86
87 SimpleClassRec simpleClassRec = {
88 { /* core fields */
89 /* superclass */ (WidgetClass) &widgetClassRec,
90 /* class_name */ "Simple",
91 /* widget_size */ sizeof(SimpleRec),
92 /* class_initialize */ ClassInitialize,
93 /* class_part_initialize */ ClassPartInitialize,
94 /* class_inited */ FALSE,
95 /* initialize */ NULL,
96 /* initialize_hook */ NULL,
97 /* realize */ Realize,
98 /* actions */ NULL,
99 /* num_actions */ 0,
100 /* resources */ resources,
101 /* num_resources */ XtNumber(resources),
102 /* xrm_class */ NULLQUARK,
103 /* compress_motion */ TRUE,
104 /* compress_exposure */ TRUE,
105 /* compress_enterleave */ TRUE,
106 /* visible_interest */ FALSE,
107 /* destroy */ NULL,
108 /* resize */ NULL,
109 /* expose */ NULL,
110 #warning FIXME: incompatible pointer type
111 /* set_values */ SetValues,
112 /* set_values_hook */ NULL,
113 /* set_values_almost */ XtInheritSetValuesAlmost,
114 /* get_values_hook */ NULL,
115 /* accept_focus */ NULL,
116 /* version */ XtVersion,
117 /* callback_private */ NULL,
118 /* tm_table */ NULL,
119 /* query_geometry */ XtInheritQueryGeometry,
120 /* display_accelerator */ XtInheritDisplayAccelerator,
121 /* extension */ NULL
122 },
123 { /* simple fields */
124 /* change_sensitive */ ChangeSensitive
125 #ifndef HAVE_OLD_XAW
126 , NULL
127 #endif
128 }
129 };
130
131 WidgetClass simpleWidgetClass = (WidgetClass)&simpleClassRec;
132
ClassInitialize()133 static void ClassInitialize()
134 {
135 static XtConvertArgRec convertArg[] = {
136 {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.screen),
137 sizeof(Screen *)},
138 {XtResourceString, (XtPointer) XtNpointerColor, sizeof(Pixel)},
139 {XtResourceString, (XtPointer) XtNpointerColorBackground,
140 sizeof(Pixel)},
141 {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.colormap),
142 sizeof(Colormap)}
143 };
144
145 XawInitializeWidgetSet();
146 XtSetTypeConverter( XtRString, XtRColorCursor, XmuCvtStringToColorCursor,
147 convertArg, XtNumber(convertArg),
148 XtCacheByDisplay, (XtDestructor)NULL);
149 }
150
ClassPartInitialize(class)151 static void ClassPartInitialize(class)
152 WidgetClass class;
153 {
154 SimpleWidgetClass c = (SimpleWidgetClass) class;
155 SimpleWidgetClass super = (SimpleWidgetClass)
156 c->core_class.superclass;
157
158 if (c->simple_class.change_sensitive == NULL) {
159 char buf[BUFSIZ];
160
161 (void) sprintf(buf,
162 "%s Widget: The Simple Widget class method 'change_sensitive' is undefined.\nA function must be defined or inherited.",
163 c->core_class.class_name);
164 XtWarning(buf);
165 c->simple_class.change_sensitive = ChangeSensitive;
166 }
167
168 if (c->simple_class.change_sensitive == XtInheritChangeSensitive)
169 c->simple_class.change_sensitive = super->simple_class.change_sensitive;
170 }
171
Realize(w,valueMask,attributes)172 static void Realize(w, valueMask, attributes)
173 Widget w;
174 Mask *valueMask;
175 XSetWindowAttributes *attributes;
176 {
177 Pixmap border_pixmap = 0;
178 if (!XtIsSensitive(w)) {
179 /* change border to gray; have to remember the old one,
180 * so XtDestroyWidget deletes the proper one */
181 if (((SimpleWidget)w)->simple.insensitive_border == None)
182 ((SimpleWidget)w)->simple.insensitive_border =
183 XmuCreateStippledPixmap(XtScreen(w),
184 w->core.border_pixel,
185 w->core.background_pixel,
186 w->core.depth);
187 border_pixmap = w->core.border_pixmap;
188 attributes->border_pixmap =
189 w->core.border_pixmap = ((SimpleWidget)w)->simple.insensitive_border;
190
191 *valueMask |= CWBorderPixmap;
192 *valueMask &= ~CWBorderPixel;
193 }
194
195 ConvertCursor(w);
196
197 if ((attributes->cursor = ((SimpleWidget)w)->simple.cursor) != None)
198 *valueMask |= CWCursor;
199
200 XtCreateWindow( w, (unsigned int)InputOutput, (Visual *)CopyFromParent,
201 *valueMask, attributes );
202
203 if (!XtIsSensitive(w))
204 w->core.border_pixmap = border_pixmap;
205 }
206
207 /* Function Name: ConvertCursor
208 * Description: Converts a name to a new cursor.
209 * Arguments: w - the simple widget.
210 * Returns: none.
211 */
212
213 static void
ConvertCursor(w)214 ConvertCursor(w)
215 Widget w;
216 {
217 SimpleWidget simple = (SimpleWidget) w;
218 XrmValue from, to;
219 Cursor cursor;
220
221 if (simple->simple.cursor_name == NULL)
222 return;
223
224 from.addr = (XPointer) simple->simple.cursor_name;
225 from.size = strlen((char *) from.addr) + 1;
226
227 to.size = sizeof(Cursor);
228 to.addr = (XPointer) &cursor;
229
230 if (XtConvertAndStore(w, XtRString, &from, XtRColorCursor, &to)) {
231 if ( cursor != None)
232 simple->simple.cursor = cursor;
233 }
234 else {
235 XtAppErrorMsg(XtWidgetToApplicationContext(w),
236 "convertFailed","ConvertCursor","XawError",
237 "Simple: ConvertCursor failed.",
238 (String *)NULL, (Cardinal *)NULL);
239 }
240 }
241
242
243 /* ARGSUSED */
244 static Bool
SetValues(Widget current,Widget request,Widget new,ArgList args,Cardinal * num_args)245 SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
246 {
247 SimpleWidget s_old = (SimpleWidget) current;
248 SimpleWidget s_new = (SimpleWidget) new;
249 Boolean new_cursor = FALSE;
250
251 UNUSED(request);
252 UNUSED(args);
253 UNUSED(num_args);
254 /* this disables user changes after creation*/
255 s_new->simple.international = s_old->simple.international;
256
257 if ( XtIsSensitive(current) != XtIsSensitive(new) )
258 (*((SimpleWidgetClass)XtClass(new))->
259 simple_class.change_sensitive) ( new );
260
261 if (s_old->simple.cursor != s_new->simple.cursor) {
262 new_cursor = TRUE;
263 }
264
265 /*
266 * We are not handling the string cursor_name correctly here.
267 */
268
269 if ( (s_old->simple.pointer_fg != s_new->simple.pointer_fg) ||
270 (s_old->simple.pointer_bg != s_new->simple.pointer_bg) ||
271 (s_old->simple.cursor_name != s_new->simple.cursor_name) ) {
272 ConvertCursor(new);
273 new_cursor = TRUE;
274 }
275
276 if (new_cursor && XtIsRealized(new))
277 XDefineCursor(XtDisplay(new), XtWindow(new), s_new->simple.cursor);
278
279 return False;
280 }
281
282
ChangeSensitive(Widget w)283 static Bool ChangeSensitive(Widget w)
284 {
285 if (XtIsRealized(w)) {
286 if (XtIsSensitive(w))
287 if (w->core.border_pixmap != XtUnspecifiedPixmap)
288 XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
289 w->core.border_pixmap );
290 else
291 XSetWindowBorder( XtDisplay(w), XtWindow(w),
292 w->core.border_pixel );
293 else {
294 if (((SimpleWidget)w)->simple.insensitive_border == None)
295 ((SimpleWidget)w)->simple.insensitive_border =
296 XmuCreateStippledPixmap(XtScreen(w),
297 w->core.border_pixel,
298 w->core.background_pixel,
299 w->core.depth);
300 XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
301 ((SimpleWidget)w)->
302 simple.insensitive_border );
303 }
304 }
305 return False;
306 }
307
308 /*
309 ======================================================================
310 end copy from Simple.c
311 ======================================================================
312 */
313
314
315 /* following function copied from XawInit.c */
XawInitializeWidgetSet()316 void XawInitializeWidgetSet ()
317 {
318 static int firsttime = 1;
319
320 if (firsttime) {
321 firsttime = 0;
322 XtInitializeWidgetClass (vendorShellWidgetClass);
323 }
324 }
325
326 static char defaultTranslations[] =
327 "<Btn1Down>: start() \n\
328 <Btn1Motion>: move() \n\
329 <Btn1Up>: notify() stop() \n\
330 <Btn2Down>: abort() \n\
331 :<Key>KP_Enter: set(rubberband,toggle) \n\
332 <Key>space: page(+1p,+1p) \n\
333 <Key>Delete: page(-1p,-1p) \n\
334 :<Key>KP_Delete: page(-1p,-1p) \n\
335 <Key>BackSpace: page(-1p,-1p) \n\
336 <Key>Left: page(-.5p,+0) \n\
337 :<Key>KP_Left: page(-.5p,+0) \n\
338 <Key>Right: page(+.5p,+0) \n\
339 :<Key>KP_Right: page(+.5p,+0) \n\
340 <Key>Up: page(+0,-.5p) \n\
341 :<Key>KP_Up: page(+0,-.5p) \n\
342 <Key>Down: page(+0,+.5p) \n\
343 :<Key>KP_Down: page(+0,+.5p) \n\
344 <Key>Home: page(0,0) \n\
345 :<Key>KP_Home: page(0,0)";
346
347
348 static void ActionStart(), ActionStop(), ActionAbort(), ActionMove();
349 static void ActionPage(), ActionNotify(), ActionSet();
350
351 static XtActionsRec actions[] = {
352 { "start", ActionStart }, /* start tmp graphics */
353 { "stop", ActionStop }, /* stop tmp graphics */
354 { "abort", ActionAbort }, /* punt */
355 { "move", ActionMove }, /* move tmp graphics on Motion event */
356 { "page", ActionPage }, /* page around usually from keyboard */
357 { "notify", ActionNotify }, /* callback new position */
358 { "set", ActionSet }, /* set various parameters */
359 };
360
361
362 /*
363 * resources for the panner
364 */
365 static XtResource panner_resources[] = {
366 #define poff(field) XtOffsetOf(PannerRec, panner.field)
367 { XtNallowOff, XtCAllowOff, XtRBoolean, sizeof(Boolean),
368 poff(allow_off), XtRImmediate, (XtPointer) FALSE },
369 { XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
370 poff(resize_to_pref), XtRImmediate, (XtPointer) TRUE },
371 { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
372 poff(report_callbacks), XtRCallback, (XtPointer) NULL },
373 { XtNdefaultScale, XtCDefaultScale, XtRDimension, sizeof(Dimension),
374 poff(default_scale), XtRImmediate, (XtPointer) PANNER_DEFAULT_SCALE },
375 { XtNrubberBand, XtCRubberBand, XtRBoolean, sizeof(Boolean),
376 poff(rubber_band), XtRImmediate, (XtPointer) FALSE },
377 { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
378 poff(foreground), XtRString, (XtPointer) XtDefaultBackground },
379 { XtNinternalSpace, XtCInternalSpace, XtRDimension, sizeof(Dimension),
380 poff(internal_border), XtRImmediate, (XtPointer) 4 },
381 { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof(Dimension),
382 poff(line_width), XtRImmediate, (XtPointer) 0 },
383 { XtNcanvasWidth, XtCCanvasWidth, XtRDimension, sizeof(Dimension),
384 poff(canvas_width), XtRImmediate, (XtPointer) 0 },
385 { XtNcanvasHeight, XtCCanvasHeight, XtRDimension, sizeof(Dimension),
386 poff(canvas_height), XtRImmediate, (XtPointer) 0 },
387 { XtNsliderX, XtCSliderX, XtRPosition, sizeof(Position),
388 poff(slider_x), XtRImmediate, (XtPointer) 0 },
389 { XtNsliderY, XtCSliderY, XtRPosition, sizeof(Position),
390 poff(slider_y), XtRImmediate, (XtPointer) 0 },
391 { XtNsliderWidth, XtCSliderWidth, XtRDimension, sizeof(Dimension),
392 poff(slider_width), XtRImmediate, (XtPointer) 0 },
393 { XtNsliderHeight, XtCSliderHeight, XtRDimension, sizeof(Dimension),
394 poff(slider_height), XtRImmediate, (XtPointer) 0 },
395 { XtNshadowColor, XtCShadowColor, XtRPixel, sizeof(Pixel),
396 poff(shadow_color), XtRString, (XtPointer) XtDefaultForeground },
397 { XtNshadowThickness, XtCShadowThickness, XtRDimension, sizeof(Dimension),
398 poff(shadow_thickness), XtRImmediate, (XtPointer) 2 },
399 { XtNbackgroundStipple, XtCBackgroundStipple, XtRString, sizeof(String),
400 poff(stipple_name), XtRImmediate, (XtPointer) NULL },
401 #undef poff
402 };
403
404
405 /*
406 * widget class methods used below
407 */
408 static void Initialize(); /* create gc's */
409 static void PannerRealize(); /* create window */
410 static void Destroy(); /* clean up widget */
411 static void Resize(); /* need to rescale ourselves */
412 static void Redisplay(); /* draw ourselves */
413 static Boolean PannerSetValues(); /* set all of the resources */
414 static void SetValuesAlmost(); /* deal with failed setval geom req */
415 static XtGeometryResult QueryGeometry(); /* say how big we would like to be */
416
417 PannerClassRec pannerClassRec = {
418 { /* core fields */
419 /* superclass */ (WidgetClass) &simpleClassRec,
420 /* class_name */ "Panner",
421 /* widget_size */ sizeof(PannerRec),
422 /* class_initialize */ XawInitializeWidgetSet,
423 /* class_part_initialize */ NULL,
424 /* class_inited */ FALSE,
425 /* initialize */ Initialize,
426 /* initialize_hook */ NULL,
427 /* realize */ PannerRealize,
428 /* actions */ actions,
429 /* num_actions */ XtNumber(actions),
430 /* resources */ panner_resources,
431 /* num_resources */ XtNumber(panner_resources),
432 /* xrm_class */ NULLQUARK,
433 /* compress_motion */ TRUE,
434 /* compress_exposure */ TRUE,
435 /* compress_enterleave */ TRUE,
436 /* visible_interest */ FALSE,
437 /* destroy */ Destroy,
438 /* resize */ Resize,
439 /* expose */ Redisplay,
440 /* set_values */ PannerSetValues,
441 /* set_values_hook */ NULL,
442 /* set_values_almost */ SetValuesAlmost,
443 /* get_values_hook */ NULL,
444 /* accept_focus */ NULL,
445 /* version */ XtVersion,
446 /* callback_private */ NULL,
447 /* tm_table */ defaultTranslations,
448 /* query_geometry */ QueryGeometry,
449 /* display_accelerator */ XtInheritDisplayAccelerator,
450 /* extension */ NULL
451 },
452 { /* simple fields */
453 /* change_sensitive */ XtInheritChangeSensitive
454 #ifndef HAVE_OLD_XAW
455 , NULL
456 #endif
457 },
458 { /* panner fields */
459 /* ignore */ 0
460 }
461 };
462
463 WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
464
465
466 /*****************************************************************************
467 * *
468 * panner utility routines *
469 * *
470 *****************************************************************************/
471
reset_shadow_gc(pw)472 static void reset_shadow_gc (pw) /* used when resources change */
473 PannerWidget pw;
474 {
475 XtGCMask valuemask = GCForeground;
476 XGCValues values;
477 unsigned long pixels[3];
478
479 if (pw->panner.shadow_gc) XtReleaseGC ((Widget) pw, pw->panner.shadow_gc);
480
481 pixels[0] = pw->panner.foreground;
482 pixels[1] = pw->core.background_pixel;
483 pixels[2] = pw->panner.shadow_color;
484 if (!pw->panner.stipple_name &&
485 !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
486 pixels, 3) &&
487 XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
488 pixels, 2))
489 {
490 valuemask = GCTile | GCFillStyle;
491 values.fill_style = FillTiled;
492 values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
493 pw->panner.foreground,
494 pw->core.background_pixel,
495 pw->core.depth);
496 }
497 else
498 {
499 if (!pw->panner.line_width &&
500 !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
501 pixels, 2))
502 pw->panner.line_width = 1;
503 valuemask = GCForeground;
504 values.foreground = pw->panner.shadow_color;
505 }
506 if (pw->panner.line_width > 0) {
507 values.line_width = pw->panner.line_width;
508 valuemask |= GCLineWidth;
509 }
510
511 pw->panner.shadow_gc = XtGetGC ((Widget) pw, valuemask, &values);
512 }
513
reset_slider_gc(pw)514 static void reset_slider_gc (pw) /* used when resources change */
515 PannerWidget pw;
516 {
517 XtGCMask valuemask = GCForeground;
518 XGCValues values;
519
520 if (pw->panner.slider_gc) XtReleaseGC ((Widget) pw, pw->panner.slider_gc);
521
522 values.foreground = pw->panner.foreground;
523
524 pw->panner.slider_gc = XtGetGC ((Widget) pw, valuemask, &values);
525 }
526
reset_xor_gc(pw)527 static void reset_xor_gc (pw) /* used when resources change */
528 PannerWidget pw;
529 {
530 if (pw->panner.xor_gc) XtReleaseGC ((Widget) pw, pw->panner.xor_gc);
531
532 if (pw->panner.rubber_band) {
533 XtGCMask valuemask = (GCForeground | GCFunction);
534 XGCValues values;
535 Pixel tmp;
536
537 tmp = ((pw->panner.foreground == pw->core.background_pixel) ?
538 pw->panner.shadow_color : pw->panner.foreground);
539 values.foreground = tmp ^ pw->core.background_pixel;
540 values.function = GXxor;
541 if (pw->panner.line_width > 0) {
542 valuemask |= GCLineWidth;
543 values.line_width = pw->panner.line_width;
544 }
545 pw->panner.xor_gc = XtGetGC ((Widget) pw, valuemask, &values);
546 } else {
547 pw->panner.xor_gc = NULL;
548 }
549 }
550
551
check_knob(pw,knob)552 static void check_knob (pw, knob)
553 PannerWidget pw;
554 Boolean knob;
555 {
556 Position pad = pw->panner.internal_border * 2;
557 Position maxx = (((Position) pw->core.width) - pad -
558 ((Position) pw->panner.knob_width));
559 Position maxy = (((Position) pw->core.height) - pad -
560 ((Position) pw->panner.knob_height));
561 Position *x = (knob ? &pw->panner.knob_x : &pw->panner.tmp.x);
562 Position *y = (knob ? &pw->panner.knob_y : &pw->panner.tmp.y);
563
564 /*
565 * note that positions are already normalized (i.e. internal_border
566 * has been subtracted out)
567 */
568 if (*x < 0) *x = 0;
569 if (*x > maxx) *x = maxx;
570
571 if (*y < 0) *y = 0;
572 if (*y > maxy) *y = maxy;
573
574 if (knob) {
575 pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
576 pw->panner.haspect + 0.5);
577 pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
578 pw->panner.vaspect + 0.5);
579 pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
580 }
581 }
582
583
move_shadow(pw)584 static void move_shadow (pw)
585 PannerWidget pw;
586 {
587 if (pw->panner.shadow_thickness > 0) {
588 int lw = pw->panner.shadow_thickness + pw->panner.line_width * 2;
589 int pad = pw->panner.internal_border;
590
591 if ((int)pw->panner.knob_height > lw && (int)pw->panner.knob_width > lw) {
592 XRectangle *r = pw->panner.shadow_rects;
593 r->x = (short) (pw->panner.knob_x + pad + pw->panner.knob_width);
594 r->y = (short) (pw->panner.knob_y + pad + lw);
595 r->width = pw->panner.shadow_thickness;
596 r->height = (unsigned short) (pw->panner.knob_height - lw);
597 r++;
598 r->x = (short) (pw->panner.knob_x + pad + lw);
599 r->y = (short) (pw->panner.knob_y + pad + pw->panner.knob_height);
600 r->width = (unsigned short) (pw->panner.knob_width - lw +
601 pw->panner.shadow_thickness);
602 r->height = pw->panner.shadow_thickness;
603 pw->panner.shadow_valid = TRUE;
604 return;
605 }
606 }
607 pw->panner.shadow_valid = FALSE;
608 }
609
scale_knob(pw,location,size)610 static void scale_knob (pw, location, size) /* set knob size and/or loc */
611 PannerWidget pw;
612 Boolean location, size;
613 {
614 if (location) {
615 pw->panner.knob_x = (Position) PANNER_HSCALE (pw, pw->panner.slider_x);
616 pw->panner.knob_y = (Position) PANNER_VSCALE (pw, pw->panner.slider_y);
617 }
618 if (size) {
619 Dimension width, height;
620
621 if (pw->panner.slider_width < 1) {
622 pw->panner.slider_width = pw->panner.canvas_width;
623 }
624 if (pw->panner.slider_height < 1) {
625 pw->panner.slider_height = pw->panner.canvas_height;
626 }
627 width = Min (pw->panner.slider_width, pw->panner.canvas_width);
628 height = Min (pw->panner.slider_height, pw->panner.canvas_height);
629
630 pw->panner.knob_width = (Dimension) PANNER_HSCALE (pw, width);
631 pw->panner.knob_height = (Dimension) PANNER_VSCALE (pw, height);
632 }
633 if (!pw->panner.allow_off) check_knob (pw, TRUE);
634 move_shadow (pw);
635 }
636
rescale(pw)637 static void rescale (pw)
638 PannerWidget pw;
639 {
640 int hpad = pw->panner.internal_border * 2;
641 int vpad = hpad;
642
643 if (pw->panner.canvas_width < 1)
644 pw->panner.canvas_width = pw->core.width;
645 if (pw->panner.canvas_height < 1)
646 pw->panner.canvas_height = pw->core.height;
647
648 if ((int)pw->core.width <= hpad) hpad = 0;
649 if ((int)pw->core.height <= vpad) vpad = 0;
650
651 pw->panner.haspect = ((double) pw->core.width - hpad) /
652 (double) pw->panner.canvas_width;
653 pw->panner.vaspect = ((double) pw->core.height - vpad) /
654 (double) pw->panner.canvas_height;
655 scale_knob (pw, TRUE, TRUE);
656 }
657
658
get_default_size(pw,wp,hp)659 static void get_default_size (pw, wp, hp)
660 PannerWidget pw;
661 Dimension *wp, *hp;
662 {
663 Dimension pad = pw->panner.internal_border * 2;
664 *wp = PANNER_DSCALE (pw, pw->panner.canvas_width) + pad;
665 *hp = PANNER_DSCALE (pw, pw->panner.canvas_height) + pad;
666 }
667
get_event_xy(pw,event,x,y)668 static Boolean get_event_xy (pw, event, x, y)
669 PannerWidget pw;
670 XEvent *event;
671 int *x, *y;
672 {
673 int pad = pw->panner.internal_border;
674
675 switch (event->type) {
676 case ButtonPress:
677 case ButtonRelease:
678 *x = event->xbutton.x - pad;
679 *y = event->xbutton.y - pad;
680 return TRUE;
681
682 case KeyPress:
683 case KeyRelease:
684 *x = event->xkey.x - pad;
685 *y = event->xkey.y - pad;
686 return TRUE;
687
688 case EnterNotify:
689 case LeaveNotify:
690 *x = event->xcrossing.x - pad;
691 *y = event->xcrossing.y - pad;
692 return TRUE;
693
694 case MotionNotify:
695 *x = event->xmotion.x - pad;
696 *y = event->xmotion.y - pad;
697 return TRUE;
698 }
699
700 return FALSE;
701 }
702
parse_page_string(s,pagesize,canvassize,relative)703 static int parse_page_string (s, pagesize, canvassize, relative)
704 char *s;
705 int pagesize, canvassize;
706 Boolean *relative;
707 {
708 char *cp;
709 double val = 1.0;
710 Boolean rel = FALSE;
711
712 /*
713 * syntax: spaces [+-] number spaces [pc\0] spaces
714 */
715
716 for (; isascii(*s) && isspace(*s); s++) ; /* skip white space */
717
718 if (*s == '+' || *s == '-') { /* deal with signs */
719 rel = TRUE;
720 if (*s == '-') val = -1.0;
721 s++;
722 }
723 if (!*s) { /* if null then return nothing */
724 *relative = TRUE;
725 return 0;
726 }
727
728 /* skip over numbers */
729 for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
730 val *= atof(cp);
731
732 /* skip blanks */
733 for (; isascii(*s) && isspace(*s); s++) ;
734
735 if (*s) { /* if units */
736 switch (s[0]) {
737 case 'p': case 'P':
738 val *= (double) pagesize;
739 break;
740
741 case 'c': case 'C':
742 val *= (double) canvassize;
743 break;
744 }
745 }
746 *relative = rel;
747 return ((int) val);
748 }
749
750
751 #define DRAW_TMP(pw) \
752 { \
753 XDrawRectangle (XtDisplay(pw), XtWindow(pw), \
754 pw->panner.xor_gc, \
755 (int) (pw->panner.tmp.x + pw->panner.internal_border), \
756 (int) (pw->panner.tmp.y + pw->panner.internal_border), \
757 (unsigned int) (pw->panner.knob_width - 1), \
758 (unsigned int) (pw->panner.knob_height - 1)); \
759 pw->panner.tmp.showing = !pw->panner.tmp.showing; \
760 }
761
762 #define UNDRAW_TMP(pw) \
763 { \
764 if (pw->panner.tmp.showing) DRAW_TMP(pw); \
765 }
766
767 #define BACKGROUND_STIPPLE(pw) \
768 XmuLocatePixmapFile (pw->core.screen, pw->panner.stipple_name, \
769 pw->panner.shadow_color, pw->core.background_pixel, \
770 pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
771
772 #define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
773
774
775 /*****************************************************************************
776 * *
777 * panner class methods *
778 * *
779 *****************************************************************************/
780
781
782 /*ARGSUSED*/
Initialize(greq,gnew,args,num_args)783 static void Initialize (greq, gnew, args, num_args)
784 Widget greq, gnew;
785 ArgList args;
786 Cardinal *num_args;
787 {
788 PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
789 Dimension defwidth, defheight;
790
791 UNUSED(args);
792 UNUSED(num_args);
793
794 if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
795 if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
796 if (req->panner.default_scale < 1)
797 new->panner.default_scale = PANNER_DEFAULT_SCALE;
798
799 get_default_size (req, &defwidth, &defheight);
800 if (req->core.width < 1) new->core.width = defwidth;
801 if (req->core.height < 1) new->core.height = defheight;
802
803 new->panner.shadow_gc = NULL;
804 reset_shadow_gc (new); /* shadowColor */
805 new->panner.slider_gc = NULL;
806 reset_slider_gc (new); /* foreground */
807 new->panner.xor_gc = NULL;
808 reset_xor_gc (new); /* foreground ^ background */
809
810 rescale (new); /* does a position check */
811 new->panner.shadow_valid = FALSE;
812 new->panner.tmp.doing = FALSE;
813 new->panner.tmp.showing = FALSE;
814 }
815
816
PannerRealize(gw,valuemaskp,attr)817 static void PannerRealize (gw, valuemaskp, attr)
818 Widget gw;
819 XtValueMask *valuemaskp;
820 XSetWindowAttributes *attr;
821 {
822 PannerWidget pw = (PannerWidget) gw;
823 Pixmap pm = XtUnspecifiedPixmap;
824 Boolean gotpm = FALSE;
825
826 if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
827 if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
828
829 if (PIXMAP_OKAY(pm)) {
830 attr->background_pixmap = pm;
831 *valuemaskp |= CWBackPixmap;
832 *valuemaskp &= ~CWBackPixel;
833 gotpm = TRUE;
834 }
835 }
836 (*pannerWidgetClass->core_class.superclass->core_class.realize)
837 (gw, valuemaskp, attr);
838
839 if (gotpm) XFreePixmap (XtDisplay(gw), pm);
840 }
841
842
Destroy(gw)843 static void Destroy (gw)
844 Widget gw;
845 {
846 PannerWidget pw = (PannerWidget) gw;
847
848 XtReleaseGC (gw, pw->panner.shadow_gc);
849 XtReleaseGC (gw, pw->panner.slider_gc);
850 XtReleaseGC (gw, pw->panner.xor_gc);
851 }
852
853
Resize(gw)854 static void Resize (gw)
855 Widget gw;
856 {
857 rescale ((PannerWidget) gw);
858 }
859
860
861 /* ARGSUSED */
Redisplay(Widget gw,XEvent * event,Region region)862 static void Redisplay (Widget gw, XEvent *event, Region region)
863 {
864 PannerWidget pw = (PannerWidget) gw;
865 Display *dpy = XtDisplay(gw);
866 Window w = XtWindow(gw);
867 int pad = pw->panner.internal_border;
868 Dimension lw = pw->panner.line_width;
869 Dimension extra = pw->panner.shadow_thickness + lw * 2;
870 int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
871
872 UNUSED(event);
873 UNUSED(region);
874
875 pw->panner.tmp.showing = FALSE;
876 XClearArea (XtDisplay(pw), XtWindow(pw),
877 (int) pw->panner.last_x - ((int) lw) + pad,
878 (int) pw->panner.last_y - ((int) lw) + pad,
879 (unsigned int) (pw->panner.knob_width + extra),
880 (unsigned int) (pw->panner.knob_height + extra),
881 False);
882 pw->panner.last_x = pw->panner.knob_x;
883 pw->panner.last_y = pw->panner.knob_y;
884
885 XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
886 pw->panner.knob_width - 1, pw->panner.knob_height - 1);
887
888 if (lw)
889 {
890 XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
891 (unsigned int) (pw->panner.knob_width - 1),
892 (unsigned int) (pw->panner.knob_height - 1));
893 }
894
895 if (pw->panner.shadow_valid) {
896 XFillRectangles (dpy, w, pw->panner.shadow_gc,
897 pw->panner.shadow_rects, 2);
898 }
899 if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
900 }
901
902
903 /* ARGSUSED */
PannerSetValues(Widget gcur,Widget greq,Widget gnew,ArgList args,Cardinal * num_args)904 static Boolean PannerSetValues (Widget gcur, Widget greq, Widget gnew, ArgList args, Cardinal *num_args)
905 {
906 PannerWidget cur = (PannerWidget) gcur;
907 PannerWidget new = (PannerWidget) gnew;
908 Boolean redisplay = FALSE;
909
910 UNUSED(greq);
911 UNUSED(args);
912 UNUSED(num_args);
913
914 if (cur->panner.foreground != new->panner.foreground) {
915 reset_slider_gc (new);
916 if (cur->panner.foreground != cur->core.background_pixel)
917 reset_xor_gc (new);
918 redisplay = TRUE;
919 } else if (cur->panner.line_width != new->panner.line_width ||
920 cur->core.background_pixel != new->core.background_pixel) {
921 reset_xor_gc (new);
922 redisplay = TRUE;
923 }
924 if (cur->panner.shadow_color != new->panner.shadow_color) {
925 reset_shadow_gc (new);
926 if (cur->panner.foreground == cur->core.background_pixel)
927 reset_xor_gc (new);
928 redisplay = TRUE;
929 }
930 if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
931 move_shadow (new);
932 redisplay = TRUE;
933 }
934 if (cur->panner.rubber_band != new->panner.rubber_band) {
935 reset_xor_gc (new);
936 if (new->panner.tmp.doing) redisplay = TRUE;
937 }
938
939 if ((cur->panner.stipple_name != new->panner.stipple_name ||
940 cur->panner.shadow_color != new->panner.shadow_color ||
941 cur->core.background_pixel != new->core.background_pixel) &&
942 XtIsRealized(gnew)) {
943 Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
944 : XtUnspecifiedPixmap);
945
946 if (PIXMAP_OKAY(pm)) {
947 XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
948 XFreePixmap (XtDisplay (new), pm);
949 } else {
950 XSetWindowBackground (XtDisplay (new), XtWindow(new),
951 new->core.background_pixel);
952 }
953 redisplay = TRUE;
954 }
955
956 if (new->panner.resize_to_pref &&
957 (cur->panner.canvas_width != new->panner.canvas_width ||
958 cur->panner.canvas_height != new->panner.canvas_height ||
959 cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
960 get_default_size (new, &new->core.width, &new->core.height);
961 redisplay = TRUE;
962 } else if (cur->panner.canvas_width != new->panner.canvas_width ||
963 cur->panner.canvas_height != new->panner.canvas_height ||
964 cur->panner.internal_border != new->panner.internal_border) {
965 rescale (new); /* does a scale_knob as well */
966 redisplay = TRUE;
967 } else {
968 Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
969 cur->panner.slider_y != new->panner.slider_y);
970 Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
971 cur->panner.slider_height != new->panner.slider_height);
972 if (loc || siz ||
973 (cur->panner.allow_off != new->panner.allow_off &&
974 new->panner.allow_off)) {
975 scale_knob (new, loc, siz);
976 redisplay = TRUE;
977 }
978 }
979
980 return redisplay;
981 }
982
SetValuesAlmost(gold,gnew,req,reply)983 static void SetValuesAlmost (gold, gnew, req, reply)
984 Widget gold, gnew;
985 XtWidgetGeometry *req, *reply;
986 {
987 if (reply->request_mode == 0) { /* got turned down, so cope */
988 Resize (gnew);
989 }
990 (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
991 (gold, gnew, req, reply);
992 }
993
QueryGeometry(gw,intended,pref)994 static XtGeometryResult QueryGeometry (gw, intended, pref)
995 Widget gw;
996 XtWidgetGeometry *intended, *pref;
997 {
998 PannerWidget pw = (PannerWidget) gw;
999
1000 pref->request_mode = (CWWidth | CWHeight);
1001 get_default_size (pw, &pref->width, &pref->height);
1002
1003 if (((intended->request_mode & (CWWidth | CWHeight)) ==
1004 (CWWidth | CWHeight)) &&
1005 intended->width == pref->width &&
1006 intended->height == pref->height)
1007 return XtGeometryYes;
1008 else if (pref->width == pw->core.width && pref->height == pw->core.height)
1009 return XtGeometryNo;
1010 else
1011 return XtGeometryAlmost;
1012 }
1013
1014
1015 /*****************************************************************************
1016 * *
1017 * panner action procs *
1018 * *
1019 *****************************************************************************/
1020
1021 /* ARGSUSED */
ActionStart(Widget gw,XEvent * event,String * params,Cardinal * num_params)1022 static void ActionStart (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1023 {
1024 PannerWidget pw = (PannerWidget) gw;
1025 int x, y;
1026
1027 UNUSED(params);
1028 UNUSED(num_params);
1029
1030 if (!get_event_xy (pw, event, &x, &y)) {
1031 panBell(XtDisplay(gw), XtWindow(gw), 0); /* should do error message */
1032 return;
1033 }
1034
1035 pw->panner.tmp.doing = TRUE;
1036 pw->panner.tmp.startx = pw->panner.knob_x;
1037 pw->panner.tmp.starty = pw->panner.knob_y;
1038 pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
1039 pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
1040 pw->panner.tmp.x = pw->panner.knob_x;
1041 pw->panner.tmp.y = pw->panner.knob_y;
1042 if (pw->panner.rubber_band) DRAW_TMP (pw);
1043 }
1044
1045 /* ARGSUSED */
ActionStop(Widget gw,XEvent * event,String * params,Cardinal * num_params)1046 static void ActionStop (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1047 {
1048 PannerWidget pw = (PannerWidget) gw;
1049 int x, y;
1050
1051 UNUSED(params);
1052 UNUSED(num_params);
1053
1054 if (get_event_xy (pw, event, &x, &y)) {
1055 pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
1056 pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
1057 if (!pw->panner.allow_off) check_knob (pw, FALSE);
1058 }
1059 if (pw->panner.rubber_band) UNDRAW_TMP (pw);
1060 pw->panner.tmp.doing = FALSE;
1061 }
1062
1063 /* ARGSUSED */
ActionAbort(Widget gw,XEvent * event,String * params,Cardinal * num_params)1064 static void ActionAbort (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1065 {
1066 PannerWidget pw = (PannerWidget) gw;
1067
1068 UNUSED(params);
1069 UNUSED(num_params);
1070
1071 if (!pw->panner.tmp.doing) return;
1072
1073 if (pw->panner.rubber_band) UNDRAW_TMP (pw);
1074
1075 if (!pw->panner.rubber_band) { /* restore old position */
1076 pw->panner.tmp.x = pw->panner.tmp.startx;
1077 pw->panner.tmp.y = pw->panner.tmp.starty;
1078 ActionNotify (gw, event, params, num_params);
1079 }
1080 pw->panner.tmp.doing = FALSE;
1081 }
1082
1083
1084 /* ARGSUSED */
ActionMove(Widget gw,XEvent * event,String * params,Cardinal * num_params)1085 static void ActionMove (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1086 {
1087 PannerWidget pw = (PannerWidget) gw;
1088 int x, y;
1089
1090 UNUSED(params);
1091 UNUSED(num_params);
1092
1093 if (!pw->panner.tmp.doing) return;
1094
1095 if (!get_event_xy (pw, event, &x, &y)) {
1096 panBell(XtDisplay(gw), XtWindow(gw), 0); /* should do error message */
1097 return;
1098 }
1099
1100 if (pw->panner.rubber_band) UNDRAW_TMP (pw);
1101 pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
1102 pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
1103
1104 if (!pw->panner.rubber_band) {
1105 ActionNotify (gw, event, params, num_params); /* does a check */
1106 } else {
1107 if (!pw->panner.allow_off) check_knob (pw, FALSE);
1108 DRAW_TMP (pw);
1109 }
1110 }
1111
1112
1113 /* ARGSUSED */
ActionPage(Widget gw,XEvent * event,String * params,Cardinal * num_params)1114 static void ActionPage (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1115 {
1116 PannerWidget pw = (PannerWidget) gw;
1117 Cardinal zero = 0;
1118 Boolean isin = pw->panner.tmp.doing;
1119 int x, y;
1120 Boolean relx, rely;
1121 int pad = pw->panner.internal_border * 2;
1122
1123 UNUSED(event);
1124 UNUSED(num_params);
1125
1126 if (*num_params != 2) {
1127 panBell (XtDisplay(gw), XtWindow(gw), 0);
1128 return;
1129 }
1130
1131 x = parse_page_string (params[0], (int) pw->panner.knob_width,
1132 ((int) pw->core.width) - pad, &relx);
1133 y = parse_page_string (params[1], (int) pw->panner.knob_height,
1134 ((int) pw->core.height) - pad, &rely);
1135
1136 if (relx) x += pw->panner.knob_x;
1137 if (rely) y += pw->panner.knob_y;
1138
1139 if (isin) { /* if in, then use move */
1140 XEvent ev;
1141 ev.xbutton.type = ButtonPress;
1142 ev.xbutton.x = x;
1143 ev.xbutton.y = y;
1144 ActionMove (gw, &ev, (String *) NULL, &zero);
1145 } else { /* else just do it */
1146 pw->panner.tmp.doing = TRUE;
1147 pw->panner.tmp.x = x;
1148 pw->panner.tmp.y = y;
1149 ActionNotify (gw, event, (String *) NULL, &zero);
1150 pw->panner.tmp.doing = FALSE;
1151 }
1152 }
1153
1154
1155 /* ARGSUSED */
ActionNotify(Widget gw,XEvent * event,String * params,Cardinal * num_params)1156 static void ActionNotify (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1157 {
1158 PannerWidget pw = (PannerWidget) gw;
1159
1160 UNUSED(event);
1161 UNUSED(params);
1162 UNUSED(num_params);
1163
1164 if (!pw->panner.tmp.doing) return;
1165
1166 if (!pw->panner.allow_off) check_knob (pw, FALSE);
1167 pw->panner.knob_x = pw->panner.tmp.x;
1168 pw->panner.knob_y = pw->panner.tmp.y;
1169 move_shadow (pw);
1170
1171 pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
1172 pw->panner.haspect + 0.5);
1173 pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
1174 pw->panner.vaspect + 0.5);
1175 if (!pw->panner.allow_off) {
1176 Position tmp;
1177
1178 if (pw->panner.slider_x >
1179 (tmp = (((Position) pw->panner.canvas_width) -
1180 ((Position) pw->panner.slider_width))))
1181 pw->panner.slider_x = tmp;
1182 if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
1183 if (pw->panner.slider_y >
1184 (tmp = (((Position) pw->panner.canvas_height) -
1185 ((Position) pw->panner.slider_height))))
1186 pw->panner.slider_y = tmp;
1187 if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
1188 }
1189
1190 if (pw->panner.last_x != pw->panner.knob_x ||
1191 pw->panner.last_y != pw->panner.knob_y) {
1192 XawPannerReport rep;
1193
1194 Redisplay (gw, (XEvent*) NULL, (Region) NULL);
1195 rep.changed = (XawPRSliderX | XawPRSliderY);
1196 rep.slider_x = pw->panner.slider_x;
1197 rep.slider_y = pw->panner.slider_y;
1198 rep.slider_width = pw->panner.slider_width;
1199 rep.slider_height = pw->panner.slider_height;
1200 rep.canvas_width = pw->panner.canvas_width;
1201 rep.canvas_height = pw->panner.canvas_height;
1202 XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
1203 }
1204 }
1205
1206 /* ARGSUSED */
ActionSet(Widget gw,XEvent * event,String * params,Cardinal * num_params)1207 static void ActionSet (Widget gw, XEvent *event, String *params, Cardinal *num_params)
1208 {
1209 PannerWidget pw = (PannerWidget) gw;
1210 Boolean rb;
1211
1212 UNUSED(event);
1213
1214 if (*num_params < 2 ||
1215 XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
1216 panBell (XtDisplay(gw), XtWindow(gw), 0);
1217 return;
1218 }
1219
1220 if (XmuCompareISOLatin1 (params[1], "on") == 0) {
1221 rb = TRUE;
1222 } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
1223 rb = FALSE;
1224 } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
1225 rb = !pw->panner.rubber_band;
1226 } else {
1227 panBell (XtDisplay(gw), XtWindow(gw), 0);
1228 return;
1229 }
1230
1231 if (rb != pw->panner.rubber_band) {
1232 Arg args[1];
1233 XtSetArg (args[0], XtNrubberBand, rb);
1234 XtSetValues (gw, args, (Cardinal) 1);
1235 }
1236 }
1237
1238 #endif /* MOTIF && USE_PANNER */
1239