Mercurial > hg > xemacs-beta
comparison lwlib/xlwscrollbar.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* Implements a lightweight scrollbar widget. | |
2 Copyright (C) 1992, 1993, 1994 Lucid, Inc. | |
3 | |
4 This file is part of the Lucid Widget Library. | |
5 | |
6 The Lucid Widget Library is free software; you can redistribute it and/or | |
7 modify it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2, or (at your option) | |
9 any later version. | |
10 | |
11 The Lucid Widget Library is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | |
20 /* Created by Douglas Keller <dkeller@vnet.ibm.com> */ | |
21 /* Last changed 03/24/95 */ | |
22 | |
23 /* | |
24 * Athena-style scrollbar button bindings added on Sun Dec 24 22:03:57 1995 | |
25 * by Jonathan Stigelman <Stig@hackvan.com>... Ho ho ho! | |
26 * | |
27 * To use them, put this resource in your .Xdefaults | |
28 * | |
29 * Emacs*XlwScrollBar.translations: #override \n\ | |
30 * <Btn1Down>: PageDownOrRight() \n\ | |
31 * <Btn3Down>: PageUpOrLeft() | |
32 * | |
33 */ | |
34 | |
35 /* | |
36 * Resources Supported: | |
37 * XmNforeground | |
38 * XmNbackground | |
39 * XmNtopShadowColor | |
40 * XmNtopShadowPixmap | |
41 * XmNbottomShadowColor | |
42 * XmNbottomShadowPixmap | |
43 * XmNtroughColor | |
44 * XmNshadowThickness | |
45 * XmNshowArrows | |
46 * XmNorientation | |
47 * XmNborderWidth | |
48 * | |
49 * XmNminimum | |
50 * XmNmaximum | |
51 * XmNvalue | |
52 * XmNincrement | |
53 * XmNpageIncrement | |
54 * | |
55 * XmNvalueChangedCallback | |
56 * XmNincrementCallback | |
57 * XmNdecrementCallback | |
58 * XmNpageIncrementCallback | |
59 * XmNpageDecrementCallback | |
60 * XmNtoTopCallback | |
61 * XmNtoBottomCallback | |
62 * XmNdragCallback | |
63 * | |
64 * XmNknobStyle - values can be: "plain" or "dimple" | |
65 * XmNarrowPosition - values can be: "opposite" or "same" | |
66 * | |
67 */ | |
68 | |
69 #include <stdio.h> | |
70 #include <stdlib.h> | |
71 #include <limits.h> | |
72 | |
73 #include <X11/IntrinsicP.h> | |
74 #include <X11/StringDefs.h> | |
75 #include <X11/bitmaps/gray> | |
76 | |
77 #include "xlwscrollbarP.h" | |
78 #include "xlwscrollbar.h" | |
79 | |
80 #define DBUG(x) | |
81 | |
82 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ | |
83 ? ((unsigned long) (x)) : ((unsigned long) (y))) | |
84 | |
85 #define VERT(w) (w->sb.orientation == XmVERTICAL) | |
86 | |
87 #define SS_MIN 8 | |
88 | |
89 #define ARROW_UP 0 | |
90 #define ARROW_DOWN 1 | |
91 #define ARROW_LEFT 2 | |
92 #define ARROW_RIGHT 3 | |
93 | |
94 #define ARM_NONE 0 | |
95 #define ARM_KNOB 1 | |
96 #define ARM_UP 2 | |
97 #define ARM_DOWN 3 | |
98 #define ARM_PAGEUP 4 | |
99 #define ARM_PAGEDOWN 5 | |
100 | |
101 #define BUTTON_NONE 0 | |
102 #define BUTTON_KNOB 1 | |
103 #define BUTTON_UP_ARROW 2 | |
104 #define BUTTON_DOWN_ARROW 3 | |
105 #define BUTTON_TROUGH_ABOVE 4 | |
106 #define BUTTON_TROUGH_BELOW 5 | |
107 | |
108 #define KNOB_PLAIN 0 | |
109 #define KNOB_DIMPLE 1 | |
110 | |
111 /************************************************************************ | |
112 ** | |
113 ** Resources | |
114 ** | |
115 */ | |
116 #define offset(field) XtOffset(XlwScrollBarWidget, field) | |
117 | |
118 static XtResource resources[] = { | |
119 { XmNforeground, XmCForeground, XtRPixel, sizeof(Pixel), | |
120 offset(sb.foreground), XtRImmediate, XtDefaultForeground }, | |
121 | |
122 { XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof(Pixel), | |
123 offset(sb.topShadowColor), XtRImmediate, (XtPointer) ~0 }, | |
124 { XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof(Pixel), | |
125 offset(sb.bottomShadowColor), XtRImmediate, (XtPointer)~0 }, | |
126 | |
127 { XmNtopShadowPixmap, XmCTopShadowPixmap, XtRPixmap, sizeof (Pixmap), | |
128 offset(sb.topShadowPixmap), XtRImmediate, (XtPointer)None}, | |
129 { XmNbottomShadowPixmap, XmCBottomShadowPixmap, XtRPixmap, sizeof (Pixmap), | |
130 offset(sb.bottomShadowPixmap), XtRImmediate, (XtPointer)None}, | |
131 | |
132 { XmNtroughColor, XmCTroughColor, XtRPixel, sizeof(Pixel), | |
133 offset(sb.troughColor), XtRImmediate, (XtPointer)~0 }, | |
134 | |
135 { XmNshadowThickness, XmCShadowThickness, XtRInt, sizeof(int), | |
136 offset(sb.shadowThickness), XtRImmediate, (XtPointer)2 }, | |
137 | |
138 { XmNborderWidth, XmCBorderWidth, XtRDimension, sizeof(Dimension), | |
139 offset(core.border_width), XtRImmediate, (XtPointer)0 }, | |
140 | |
141 { XmNshowArrows, XmCShowArrows, XtRBoolean, sizeof(Boolean), | |
142 offset(sb.showArrows), XtRImmediate, (XtPointer)True }, | |
143 | |
144 { XmNinitialDelay, XmCInitialDelay, XtRInt, sizeof(int), | |
145 offset(sb.initialDelay), XtRImmediate, (XtPointer) 250 }, | |
146 { XmNrepeatDelay, XmCRepeatDelay, XtRInt, sizeof(int), | |
147 offset(sb.repeatDelay), XtRImmediate, (XtPointer) 50 }, | |
148 | |
149 { XmNorientation, XmCOrientation, XtROrientation, sizeof(unsigned char), | |
150 offset(sb.orientation), XtRImmediate, (XtPointer) XmVERTICAL }, | |
151 | |
152 | |
153 { XmNminimum, XmCMinimum, XtRInt, sizeof(int), | |
154 offset(sb.minimum), XtRImmediate, (XtPointer) 0}, | |
155 { XmNmaximum, XmCMaximum, XtRInt, sizeof(int), | |
156 offset(sb.maximum), XtRImmediate, (XtPointer) 100}, | |
157 { XmNvalue, XmCValue, XtRInt, sizeof(int), | |
158 offset(sb.value), XtRImmediate, (XtPointer) 0}, | |
159 { XmNsliderSize, XmCSliderSize, XtRInt, sizeof(int), | |
160 offset(sb.sliderSize), XtRImmediate, (XtPointer) 10}, | |
161 { XmNincrement, XmCIncrement, XtRInt, sizeof(int), | |
162 offset(sb.increment), XtRImmediate, (XtPointer) 1}, | |
163 { XmNpageIncrement, XmCPageIncrement, XtRInt, sizeof(int), | |
164 offset(sb.pageIncrement), XtRImmediate, (XtPointer) 10}, | |
165 | |
166 { XmNvalueChangedCallback, XmCValueChangedCallback, XtRCallback, sizeof(XtPointer), | |
167 offset(sb.valueChangedCBL), XtRCallback, NULL}, | |
168 { XmNincrementCallback, XmCIncrementCallback, XtRCallback, sizeof(XtPointer), | |
169 offset(sb.incrementCBL), XtRCallback, NULL}, | |
170 { XmNdecrementCallback, XmCDecrementCallback, XtRCallback, sizeof(XtPointer), | |
171 offset(sb.decrementCBL), XtRCallback, NULL}, | |
172 { XmNpageIncrementCallback, XmCPageIncrementCallback, XtRCallback, sizeof(XtPointer), | |
173 offset(sb.pageIncrementCBL), XtRCallback, NULL}, | |
174 { XmNpageDecrementCallback, XmCPageDecrementCallback, XtRCallback, sizeof(XtPointer), | |
175 offset(sb.pageDecrementCBL), XtRCallback, NULL}, | |
176 { XmNtoTopCallback, XmCToTopCallback, XtRCallback, sizeof(XtPointer), | |
177 offset(sb.toTopCBL), XtRCallback, NULL}, | |
178 { XmNtoBottomCallback, XmCToBottomCallback, XtRCallback, sizeof(XtPointer), | |
179 offset(sb.toBottomCBL), XtRCallback, NULL}, | |
180 { XmNdragCallback, XmCDragCallback, XtRCallback, sizeof(XtPointer), | |
181 offset(sb.dragCBL), XtRCallback, NULL}, | |
182 | |
183 { XmNknobStyle, XmCKnobStyle, XtRString, sizeof(char *), | |
184 offset(sb.knobStyle), XtRImmediate, NULL}, | |
185 | |
186 { XmNarrowPosition, XmCArrowPosition, XtRString, sizeof(char *), | |
187 offset(sb.arrowPosition), XtRImmediate, NULL}, | |
188 }; | |
189 | |
190 /************************************************************************ | |
191 ** | |
192 ** Prototypes | |
193 ** | |
194 */ | |
195 | |
196 /* | |
197 ** Actions | |
198 */ | |
199 static void Select(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
200 static void PageUpOrLeft(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
201 static void PageDownOrRight(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
202 static void Drag(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
203 static void Release(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
204 static void Jump(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
205 static void Abort(Widget w, XEvent *event, String *parms, Cardinal *num_parms); | |
206 | |
207 /* | |
208 ** Methods | |
209 */ | |
210 static void Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num_args); | |
211 static Boolean SetValues(Widget current, Widget request, Widget nw, ArgList args, Cardinal *num_args); | |
212 static void Destroy(Widget widget); | |
213 static void Redisplay(Widget widget, XEvent *event, Region region); | |
214 static void Resize(Widget widget); | |
215 static void Realize(Widget widget, XtValueMask *valuemask, XSetWindowAttributes *attr); | |
216 | |
217 /* | |
218 ** Private | |
219 */ | |
220 | |
221 | |
222 /************************************************************************ | |
223 ** | |
224 ** Actions Table | |
225 ** | |
226 */ | |
227 static XtActionsRec actions[] = { | |
228 {"Select", Select}, | |
229 {"PageDownOrRight", PageDownOrRight}, | |
230 {"PageUpOrLeft", PageUpOrLeft}, | |
231 {"Drag", Drag}, | |
232 {"Release", Release}, | |
233 {"Jump", Jump}, | |
234 {"Abort", Abort}, | |
235 }; | |
236 | |
237 /************************************************************************ | |
238 ** | |
239 ** Default Translation Table | |
240 ** | |
241 */ | |
242 static char default_translations[] = | |
243 "<Btn1Down>: Select()\n" | |
244 "<Btn1Motion>: Drag()\n" | |
245 "<Btn1Up>: Release()\n" | |
246 "<Btn2Down>: Jump()\n" | |
247 "<Btn2Motion>: Drag()\n" | |
248 "<Btn2Up>: Release()\n" | |
249 "<Key>Delete: Abort()" | |
250 ; | |
251 | |
252 /************************************************************************ | |
253 ** | |
254 ** Class record initalization | |
255 ** | |
256 */ | |
257 XlwScrollBarClassRec xlwScrollBarClassRec = { | |
258 /* core_class fields */ | |
259 { | |
260 /* superclass */ (WidgetClass) &coreClassRec, | |
261 /* class_name */ "XlwScrollBar", | |
262 /* widget_size */ sizeof(XlwScrollBarRec), | |
263 /* class_initialize */ NULL, | |
264 /* class_part_init */ NULL, | |
265 /* class_inited */ False, | |
266 /* initialize */ Initialize, | |
267 /* initialize_hook */ NULL, | |
268 /* realize */ Realize, | |
269 /* actions */ actions, | |
270 /* num_actions */ XtNumber(actions), | |
271 /* resources */ resources, | |
272 /* num_resources */ XtNumber(resources), | |
273 /* xrm_class */ NULLQUARK, | |
274 /* compress_motion */ True, | |
275 /* compress_exposure */ XtExposeCompressMultiple, | |
276 /* compress_enterleave */ True, | |
277 /* visible_interest */ False, | |
278 /* destroy */ Destroy, | |
279 /* resize */ Resize, | |
280 /* expose */ Redisplay, | |
281 /* set_values */ SetValues, | |
282 /* set_values_hook */ NULL, | |
283 /* set_values_almost */ XtInheritSetValuesAlmost, | |
284 /* get_values_hook */ NULL, | |
285 /* accept_focus */ NULL, | |
286 /* version */ XtVersionDontCheck, | |
287 /* callback_private */ NULL, | |
288 /* tm_table */ default_translations, | |
289 /* query_geometry */ NULL, | |
290 }, | |
291 /* scrollbar_class fields */ | |
292 { | |
293 /* dummy_field */ 0, | |
294 }, | |
295 }; | |
296 | |
297 WidgetClass xlwScrollBarWidgetClass = (WidgetClass) &xlwScrollBarClassRec; | |
298 | |
299 /************************************************************************ | |
300 ** | |
301 ** Debug funcitons | |
302 ** | |
303 */ | |
304 | |
305 #ifdef SHOW_CLEAR | |
306 static void myXClearArea(Display *dpy, Drawable d, int x, int y, int w, int h, Boolean exp, XlwScrollBarWidget widget) | |
307 { | |
308 XFillRectangle(dpy, d, widget->sb.topShadowGC, x, y, w, h); | |
309 XSync(dpy, False); | |
310 sleep(2); | |
311 XClearArea(dpy, d, x, y, w, h, exp); | |
312 } | |
313 | |
314 #define XClearArea(dpy,win,x,y,width,height,exp) myXClearArea(dpy,win,x,y,width,height,exp,w) | |
315 #endif | |
316 | |
317 #ifdef CHECK_VALUES | |
318 static void check(XlwScrollBarWidget w) | |
319 { | |
320 int height; | |
321 | |
322 height= widget_h(w); | |
323 if( w->sb.showArrows ) height -= (2*arrow_h(w)); | |
324 | |
325 if( (w->sb.above + w->sb.ss + w->sb.below > height) || | |
326 (w->sb.value < w->sb.minimum) || | |
327 (w->sb.value > w->sb.maximum - w->sb.sliderSize ) | |
328 ) | |
329 { | |
330 printf("above=%d ss=%d below=%d height=%d\n", | |
331 w->sb.above, w->sb.ss, w->sb.below, height); | |
332 printf("value=%d min=%d max=%d ss=%d max-ss=%d\n", | |
333 w->sb.value, w->sb.minimum, w->sb.maximum, w->sb.sliderSize, w->sb.maximum - w->sb.sliderSize); | |
334 abort(); | |
335 } | |
336 } | |
337 | |
338 # define CHECK(w) check(w) | |
339 #else | |
340 # define CHECK(w) | |
341 #endif | |
342 | |
343 /************************************************************************ | |
344 ** | |
345 ** Static funcitons | |
346 ** | |
347 */ | |
348 | |
349 static void call_callbacks(XlwScrollBarWidget w, int reason, int value, int pixel, | |
350 XEvent *event) | |
351 { | |
352 XlwScrollBarCallbackStruct cbs; | |
353 Boolean called_anything; | |
354 | |
355 cbs.reason = reason; | |
356 cbs.event = event; | |
357 cbs.value = value; | |
358 cbs.pixel = pixel; | |
359 | |
360 called_anything = False; | |
361 | |
362 switch( reason ) | |
363 { | |
364 case XmCR_VALUE_CHANGED: | |
365 XtCallCallbackList( (Widget)w, w->sb.valueChangedCBL, &cbs ); | |
366 called_anything = True; | |
367 break; | |
368 case XmCR_INCREMENT: | |
369 if( w->sb.incrementCBL ) | |
370 { | |
371 XtCallCallbackList( (Widget)w, w->sb.incrementCBL, &cbs ); | |
372 called_anything = True; | |
373 } | |
374 break; | |
375 case XmCR_DECREMENT: | |
376 if( w->sb.decrementCBL ) | |
377 { | |
378 XtCallCallbackList( (Widget)w, w->sb.decrementCBL, &cbs ); | |
379 called_anything = True; | |
380 } | |
381 break; | |
382 case XmCR_PAGE_INCREMENT: | |
383 if( w->sb.incrementCBL ) | |
384 { | |
385 XtCallCallbackList( (Widget)w, w->sb.pageIncrementCBL, &cbs ); | |
386 called_anything = True; | |
387 } | |
388 break; | |
389 case XmCR_PAGE_DECREMENT: | |
390 if( w->sb.decrementCBL ) | |
391 { | |
392 XtCallCallbackList( (Widget)w, w->sb.pageDecrementCBL, &cbs ); | |
393 called_anything = True; | |
394 } | |
395 break; | |
396 case XmCR_TO_TOP: | |
397 if( w->sb.toTopCBL ) | |
398 { | |
399 XtCallCallbackList( (Widget)w, w->sb.toTopCBL, &cbs ); | |
400 called_anything = True; | |
401 } | |
402 break; | |
403 case XmCR_TO_BOTTOM: | |
404 if( w->sb.toBottomCBL ) | |
405 { | |
406 XtCallCallbackList( (Widget)w, w->sb.toBottomCBL, &cbs ); | |
407 called_anything = True; | |
408 } | |
409 break; | |
410 case XmCR_DRAG: | |
411 if( w->sb.dragCBL ) | |
412 { | |
413 XtCallCallbackList( (Widget)w, w->sb.dragCBL, &cbs ); | |
414 } | |
415 called_anything = True; /* Special Case */ | |
416 break; | |
417 } | |
418 | |
419 if( !called_anything ) | |
420 { | |
421 cbs.reason = XmCR_VALUE_CHANGED; | |
422 XtCallCallbackList( (Widget)w, w->sb.valueChangedCBL, &cbs ); | |
423 } | |
424 } | |
425 | |
426 /* | |
427 ** Widget sizes minus the shadow and highlight area | |
428 ** | |
429 */ | |
430 static int widget_x(XlwScrollBarWidget w) | |
431 { | |
432 return( w->sb.shadowThickness ); | |
433 } | |
434 | |
435 static int widget_y(XlwScrollBarWidget w) | |
436 { | |
437 return( w->sb.shadowThickness ); | |
438 } | |
439 | |
440 static int widget_w(XlwScrollBarWidget w) | |
441 { | |
442 int width, x = w->sb.shadowThickness; | |
443 | |
444 width = VERT(w) ? w->core.width : w->core.height; | |
445 | |
446 if( width <= (2 * x) ) | |
447 return( 1 ); | |
448 else | |
449 return( width - (2 * x) ); | |
450 } | |
451 | |
452 static int widget_h(XlwScrollBarWidget w) | |
453 { | |
454 int height, y = w->sb.shadowThickness; | |
455 | |
456 height = VERT(w) ? w->core.height : w->core.width; | |
457 | |
458 if( height <= (2 * y) ) | |
459 return( 1 ); | |
460 else | |
461 return( height - (2 * y) ); | |
462 } | |
463 | |
464 static int arrow_h(XlwScrollBarWidget w) | |
465 { | |
466 int width, height; | |
467 | |
468 width = widget_w(w); | |
469 height= widget_h(w); | |
470 | |
471 if( width > ((height / 2) - (SS_MIN / 2) - 1) ) | |
472 { | |
473 return( ((height / 2) - (SS_MIN / 2) - 1) ); | |
474 } | |
475 else | |
476 { | |
477 return( width ); | |
478 } | |
479 } | |
480 | |
481 static int event_x(XlwScrollBarWidget w, XEvent *event) | |
482 { | |
483 return( VERT(w) ? event->xbutton.x : event->xbutton.y ); | |
484 } | |
485 | |
486 static int event_y(XlwScrollBarWidget w, XEvent *event) | |
487 { | |
488 return( VERT(w) ? event->xbutton.y : event->xbutton.x ); | |
489 } | |
490 | |
491 /* | |
492 ** Safe addition and subtraction | |
493 */ | |
494 static int safe_add(int a, int b) | |
495 { | |
496 if( a > 0 && INT_MAX - a < b ) return( INT_MAX ); | |
497 else return( a + b ); | |
498 } | |
499 | |
500 static int safe_subtract(int a, int b) | |
501 { | |
502 if( a < 0 && -(INT_MIN - a) < b ) return( INT_MIN ); | |
503 else return( a - b ); | |
504 } | |
505 | |
506 static int knob_style(XlwScrollBarWidget w) | |
507 { | |
508 if( w->sb.knobStyle ) | |
509 { | |
510 if( w->sb.knobStyle[0] == 'd' ) | |
511 { | |
512 return( KNOB_DIMPLE ); | |
513 } | |
514 } | |
515 return( KNOB_PLAIN ); | |
516 } | |
517 | |
518 static Boolean arrow_same_end(XlwScrollBarWidget w) | |
519 { | |
520 if( w->sb.arrowPosition && w->sb.arrowPosition[0] == 's' ) | |
521 { | |
522 return( True ); | |
523 } | |
524 return( False ); | |
525 } | |
526 | |
527 /* | |
528 ** GC and Pixel allocation | |
529 */ | |
530 static GC get_gc(XlwScrollBarWidget w, Pixel fg, Pixel bg, Pixmap pm) | |
531 { | |
532 XGCValues values; | |
533 XtGCMask mask; | |
534 | |
535 if (pm == w->sb.grayPixmap) { | |
536 /* If we're using the gray pixmap, guarantee white on black ... | |
537 * otherwise, we could end up with something odd like grey on white | |
538 * when we're on a color display that ran out of color cells | |
539 */ | |
540 | |
541 fg = WhitePixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w))); | |
542 bg = BlackPixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w))); | |
543 } | |
544 | |
545 values.foreground = fg; | |
546 values.background = bg; | |
547 values.fill_style = FillOpaqueStippled; | |
548 values.stipple = pm; | |
549 mask = GCForeground | GCBackground | | |
550 ( pm == None ? 0 : GCStipple | GCFillStyle ); | |
551 return( XtGetGC((Widget)w, mask, &values) ); | |
552 } | |
553 | |
554 /* Replacement for XAllocColor() that tries to return the nearest | |
555 available color if the colormap is full. From FSF Emacs. */ | |
556 | |
557 static int | |
558 allocate_nearest_color (Display *display, Colormap screen_colormap, | |
559 XColor *color_def) | |
560 { | |
561 int status; | |
562 | |
563 status = XAllocColor (display, screen_colormap, color_def); | |
564 if (!status) | |
565 { | |
566 /* If we got to this point, the colormap is full, so we're | |
567 going to try and get the next closest color. | |
568 The algorithm used is a least-squares matching, which is | |
569 what X uses for closest color matching with StaticColor visuals. */ | |
570 | |
571 XColor *cells; | |
572 int no_cells; | |
573 int nearest; | |
574 long nearest_delta, trial_delta; | |
575 int x; | |
576 | |
577 no_cells = XDisplayCells (display, XDefaultScreen (display)); | |
578 /* Don't use alloca here because lwlib doesn't have the | |
579 necessary configuration information that src does. */ | |
580 cells = (XColor *) malloc (sizeof (XColor) * no_cells); | |
581 | |
582 for (x = 0; x < no_cells; x++) | |
583 cells[x].pixel = x; | |
584 | |
585 XQueryColors (display, screen_colormap, cells, no_cells); | |
586 nearest = 0; | |
587 /* I'm assuming CSE so I'm not going to condense this. */ | |
588 nearest_delta = ((((color_def->red >> 8) - (cells[0].red >> 8)) | |
589 * ((color_def->red >> 8) - (cells[0].red >> 8))) | |
590 + | |
591 (((color_def->green >> 8) - (cells[0].green >> 8)) | |
592 * ((color_def->green >> 8) - (cells[0].green >> 8))) | |
593 + | |
594 (((color_def->blue >> 8) - (cells[0].blue >> 8)) | |
595 * ((color_def->blue >> 8) - (cells[0].blue >> 8)))); | |
596 for (x = 1; x < no_cells; x++) | |
597 { | |
598 trial_delta = ((((color_def->red >> 8) - (cells[x].red >> 8)) | |
599 * ((color_def->red >> 8) - (cells[x].red >> 8))) | |
600 + | |
601 (((color_def->green >> 8) - (cells[x].green >> 8)) | |
602 * ((color_def->green >> 8) - (cells[x].green >> 8))) | |
603 + | |
604 (((color_def->blue >> 8) - (cells[x].blue >> 8)) | |
605 * ((color_def->blue >> 8) - (cells[x].blue >> 8)))); | |
606 if (trial_delta < nearest_delta) | |
607 { | |
608 nearest = x; | |
609 nearest_delta = trial_delta; | |
610 } | |
611 } | |
612 color_def->red = cells[nearest].red; | |
613 color_def->green = cells[nearest].green; | |
614 color_def->blue = cells[nearest].blue; | |
615 status = XAllocColor (display, screen_colormap, color_def); | |
616 | |
617 free (cells); | |
618 } | |
619 | |
620 return status; | |
621 } | |
622 | |
623 static void make_shadow_pixels(XlwScrollBarWidget w) | |
624 { | |
625 Display *dpy = XtDisplay((Widget) w); | |
626 Colormap cmap = w->core.colormap; | |
627 XColor topc, botc; | |
628 int top_frobbed, bottom_frobbed; | |
629 Pixel bg, fg; | |
630 | |
631 top_frobbed = bottom_frobbed = 0; | |
632 | |
633 bg = w->core.background_pixel; | |
634 fg = w->sb.foreground; | |
635 | |
636 if( w->sb.topShadowColor == (Pixel)~0) w->sb.topShadowColor = bg; | |
637 if( w->sb.bottomShadowColor == (Pixel)~0) w->sb.bottomShadowColor = fg; | |
638 | |
639 if( w->sb.topShadowColor == bg || w->sb.topShadowColor == fg ) | |
640 { | |
641 topc.pixel = bg; | |
642 XQueryColor( dpy, cmap, &topc ); | |
643 /* don't overflow/wrap! */ | |
644 topc.red = MINL(65535, topc.red * 1.2); | |
645 topc.green = MINL(65535, topc.green * 1.2); | |
646 topc.blue = MINL(65535, topc.blue * 1.2); | |
647 if( allocate_nearest_color(dpy, cmap, &topc) ) | |
648 { | |
649 if( topc.pixel == bg ) | |
650 { | |
651 XFreeColors( dpy, cmap, &topc.pixel, 1, 0); | |
652 topc.red = MINL(65535, topc.red + 0x8000); | |
653 topc.green = MINL(65535, topc.green + 0x8000); | |
654 topc.blue = MINL(65535, topc.blue + 0x8000); | |
655 if( allocate_nearest_color(dpy, cmap, &topc) ) | |
656 { | |
657 w->sb.topShadowColor = topc.pixel; | |
658 } | |
659 } | |
660 else | |
661 { | |
662 w->sb.topShadowColor = topc.pixel; | |
663 } | |
664 | |
665 top_frobbed = 1; | |
666 } | |
667 } | |
668 | |
669 if( w->sb.bottomShadowColor == fg || w->sb.bottomShadowColor == bg ) | |
670 { | |
671 botc.pixel = bg; | |
672 XQueryColor( dpy, cmap, &botc ); | |
673 botc.red *= 0.6; | |
674 botc.green *= 0.6; | |
675 botc.blue *= 0.6; | |
676 if( allocate_nearest_color(dpy, cmap, &botc) ) | |
677 { | |
678 if( botc.pixel == bg ) | |
679 { | |
680 XFreeColors( dpy, cmap, &botc.pixel, 1, 0); | |
681 botc.red = MINL(65535, botc.red + 0x4000); | |
682 botc.green = MINL(65535, botc.green + 0x4000); | |
683 botc.blue = MINL(65535, botc.blue + 0x4000); | |
684 if( allocate_nearest_color(dpy, cmap, &botc) ) | |
685 { | |
686 w->sb.bottomShadowColor = botc.pixel; | |
687 } | |
688 } | |
689 else | |
690 { | |
691 w->sb.bottomShadowColor = botc.pixel; | |
692 } | |
693 bottom_frobbed = 1; | |
694 } | |
695 } | |
696 | |
697 if( top_frobbed && bottom_frobbed ) | |
698 { | |
699 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3)); | |
700 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3)); | |
701 if( bot_avg > top_avg ) | |
702 { | |
703 Pixel tmp = w->sb.topShadowColor; | |
704 w->sb.topShadowColor = w->sb.bottomShadowColor; | |
705 w->sb.bottomShadowColor = tmp; | |
706 } | |
707 else if( topc.pixel == botc.pixel ) | |
708 { | |
709 if( botc.pixel == bg ) | |
710 w->sb.topShadowColor = bg; | |
711 else | |
712 w->sb.bottomShadowColor = fg; | |
713 } | |
714 } | |
715 | |
716 if (w->sb.topShadowColor == w->core.background_pixel || | |
717 w->sb.bottomShadowColor == w->core.background_pixel) { | |
718 | |
719 /* Assume we're in mono. This code should be okay even if we're | |
720 * really in color but just short on color cells -- We want the | |
721 * following behavior, which has been empirically determined to | |
722 * work well for all fg/bg combinations in mono: If the trough | |
723 * and thumb are BOTH black, then use a white top shadow and a | |
724 * grey bottom shadow, otherwise use a grey top shadow and a | |
725 * black bottom shadow. | |
726 */ | |
727 | |
728 Pixel white = WhitePixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w))); | |
729 Pixel black = BlackPixelOfScreen(DefaultScreenOfDisplay(XtDisplay(w))); | |
730 | |
731 /* Note: core.background_pixel is the color of the thumb ... */ | |
732 | |
733 if (w->core.background_pixel == black && | |
734 w->sb.troughColor == black) { | |
735 | |
736 w->sb.topShadowColor = white; | |
737 w->sb.bottomShadowPixmap = w->sb.grayPixmap; | |
738 | |
739 } else { | |
740 | |
741 w->sb.topShadowPixmap = w->sb.grayPixmap; | |
742 w->sb.bottomShadowColor = black; | |
743 } | |
744 | |
745 } | |
746 | |
747 | |
748 } | |
749 | |
750 static void make_trough_pixel(XlwScrollBarWidget w) | |
751 { | |
752 Display *dpy = XtDisplay((Widget) w); | |
753 Colormap cmap = DefaultColormapOfScreen( XtScreen((Widget)w) ); | |
754 XColor troughC; | |
755 | |
756 if( w->sb.troughColor == (Pixel)~0) w->sb.troughColor = w->core.background_pixel; | |
757 | |
758 if( w->sb.troughColor == w->core.background_pixel ) | |
759 { | |
760 troughC.pixel = w->core.background_pixel; | |
761 XQueryColor( dpy, cmap, &troughC ); | |
762 troughC.red *= 0.8; | |
763 troughC.green *= 0.8; | |
764 troughC.blue *= 0.8; | |
765 if( allocate_nearest_color(dpy, cmap, &troughC) ) | |
766 { | |
767 w->sb.troughColor = troughC.pixel; | |
768 } | |
769 } | |
770 } | |
771 | |
772 /* | |
773 ** Draw 3d border | |
774 */ | |
775 static void draw_shadows(Display *dpy, Drawable d, | |
776 GC shine_gc, GC shadow_gc, | |
777 int x, int y, int width, int height, | |
778 int shadowT) | |
779 { | |
780 XSegment shine[10], shadow[10]; | |
781 int i; | |
782 | |
783 if(shadowT > (width / 2)) shadowT = (width / 2); | |
784 if(shadowT > (height / 2)) shadowT = (height / 2); | |
785 if(shadowT <= 0) return; | |
786 | |
787 for(i = 0; i < shadowT; i++) | |
788 { | |
789 /* Top segments */ | |
790 shine[i].x1 = x; | |
791 shine[i].y2 = shine[i].y1 = y + i; | |
792 shine[i].x2 = x + width - i - 1; | |
793 /* Left segments */ | |
794 shine[i + shadowT].x2 = shine[i + shadowT].x1 = x + i; | |
795 shine[i + shadowT].y1 = y + shadowT; | |
796 shine[i + shadowT].y2 = y + height - i - 1; | |
797 | |
798 /* Bottom segments */ | |
799 shadow[i].x1 = x + i; | |
800 shadow[i].y2 = shadow[i].y1 = y + height - i - 1; | |
801 shadow[i].x2 = x + width - 1 ; | |
802 /* Right segments */ | |
803 shadow[i + shadowT].x2 = shadow[i + shadowT].x1 = x + width - i - 1; | |
804 shadow[i + shadowT].y1 = y + i + 1; | |
805 shadow[i + shadowT].y2 = y + height - 1 ; | |
806 } | |
807 | |
808 XDrawSegments( dpy, d, shine_gc, shine, shadowT * 2 ); | |
809 XDrawSegments( dpy, d, shadow_gc, shadow, shadowT * 2 ); | |
810 } | |
811 | |
812 /* | |
813 ** Draw 3d arrows, left, up, down, and right | |
814 */ | |
815 static int make_vert_seg(XSegment *seg, int x1, int y1, int x2, int y2, int shadowT) | |
816 { | |
817 int i; | |
818 | |
819 for(i=0; i<shadowT; i++) | |
820 { | |
821 seg[i].x1 = x1; | |
822 seg[i].y1 = y1 + i; | |
823 seg[i].x2 = x2; | |
824 seg[i].y2 = y2 + i; | |
825 } | |
826 return( shadowT ); | |
827 } | |
828 | |
829 static int make_hor_seg(XSegment *seg, int x1, int y1, int x2, int y2, int shadowT) | |
830 { | |
831 int i; | |
832 | |
833 for(i=0; i<shadowT; i++) | |
834 { | |
835 seg[i].x1 = x1 + i; | |
836 seg[i].y1 = y1; | |
837 seg[i].x2 = x2 + i; | |
838 seg[i].y2 = y2; | |
839 } | |
840 return( shadowT ); | |
841 } | |
842 | |
843 static void draw_arrow_up(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC, | |
844 int x, int y, int width, int height, int shadowT) | |
845 { | |
846 XSegment shine[10], shadow[10]; | |
847 XPoint triangle[3]; | |
848 int mid; | |
849 | |
850 mid = width / 2; | |
851 | |
852 if(shadowT > (width / 2)) shadowT = (width / 2); | |
853 if(shadowT > (height / 2)) shadowT = (height / 2); | |
854 if(shadowT <= 0) shadowT = 0; | |
855 | |
856 /* / */ | |
857 make_vert_seg( shine, | |
858 x, y + height - shadowT - 1, | |
859 x + mid, y, shadowT ); | |
860 /* _\ */ | |
861 make_vert_seg( shadow, | |
862 x, y + height - shadowT - 1, | |
863 x + width - 1, y + height - shadowT - 1, shadowT ); | |
864 make_vert_seg( shadow + shadowT, | |
865 x + mid, y, | |
866 x + width - 1, y + height - shadowT - 1, shadowT ); | |
867 | |
868 triangle[0].x = x; | |
869 triangle[0].y = y + height - 1; | |
870 triangle[1].x = x + mid; | |
871 triangle[1].y = y; | |
872 triangle[2].x = x + width - 1; | |
873 triangle[2].y = y + height - 1; | |
874 | |
875 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord ); | |
876 | |
877 XDrawSegments( dpy, win, shadowGC, shadow, shadowT * 2 ); | |
878 XDrawSegments( dpy, win, shineGC, shine, shadowT ); | |
879 } | |
880 | |
881 static void draw_arrow_left(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC, | |
882 int x, int y, int width, int height, int shadowT) | |
883 { | |
884 XSegment shine[10], shadow[10]; | |
885 XPoint triangle[3]; | |
886 int mid; | |
887 | |
888 mid = width / 2; | |
889 | |
890 if(shadowT > (width / 2)) shadowT = (width / 2); | |
891 if(shadowT > (height / 2)) shadowT = (height / 2); | |
892 if(shadowT <= 0) shadowT = 0; | |
893 | |
894 /* / */ | |
895 make_hor_seg( shine, | |
896 x, y + mid, | |
897 x + width - shadowT - 1, y, shadowT ); | |
898 /* \| */ | |
899 make_hor_seg( shadow, | |
900 x, y + mid, | |
901 x + width - shadowT - 1, y + height - 1, shadowT ); | |
902 make_hor_seg( shadow + shadowT, | |
903 x + width - shadowT - 1, y, | |
904 x + width - shadowT - 1, y + height - 1, shadowT ); | |
905 | |
906 triangle[0].x = x + width - 1; | |
907 triangle[0].y = y + height - 1; | |
908 triangle[1].x = x; | |
909 triangle[1].y = y + mid; | |
910 triangle[2].x = x + width - 1; | |
911 triangle[2].y = y; | |
912 | |
913 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord ); | |
914 | |
915 XDrawSegments( dpy, win, shadowGC, shadow, shadowT * 2 ); | |
916 XDrawSegments( dpy, win, shineGC, shine, shadowT ); | |
917 } | |
918 | |
919 static void draw_arrow_down(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC, | |
920 int x, int y, int width, int height, int shadowT) | |
921 { | |
922 XSegment shine[10], shadow[10]; | |
923 XPoint triangle[3]; | |
924 int mid; | |
925 | |
926 mid = width / 2; | |
927 | |
928 if(shadowT > (width / 2)) shadowT = (width / 2); | |
929 if(shadowT > (height / 2)) shadowT = (height / 2); | |
930 if(shadowT <= 0) shadowT = 0; | |
931 | |
932 /* \- */ | |
933 make_vert_seg( shine, | |
934 x, y, | |
935 x + mid, y + height - shadowT - 1, shadowT ); | |
936 make_vert_seg( shine + shadowT, | |
937 x, y, | |
938 x + width - 1, y, shadowT ); | |
939 /* / */ | |
940 make_vert_seg( shadow, | |
941 x + width - 1, y, | |
942 x + mid, y + height - shadowT - 1, shadowT ); | |
943 | |
944 triangle[0].x = x; | |
945 triangle[0].y = y; | |
946 triangle[1].x = x + mid; | |
947 triangle[1].y = y + height - 1; | |
948 triangle[2].x = x + width - 1; | |
949 triangle[2].y = y; | |
950 | |
951 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord ); | |
952 | |
953 XDrawSegments( dpy, win, shadowGC, shadow, shadowT ); | |
954 XDrawSegments( dpy, win, shineGC, shine, shadowT * 2 ); | |
955 } | |
956 | |
957 static void draw_arrow_right(Display *dpy, Drawable win, GC bgGC, GC shineGC, GC shadowGC, | |
958 int x, int y, int width, int height, int shadowT) | |
959 { | |
960 XSegment shine[10], shadow[10]; | |
961 XPoint triangle[3]; | |
962 int mid; | |
963 | |
964 mid = width / 2; | |
965 | |
966 if(shadowT > (width / 2)) shadowT = (width / 2); | |
967 if(shadowT > (height / 2)) shadowT = (height / 2); | |
968 if(shadowT <= 0) shadowT = 0; | |
969 | |
970 /* |\ */ | |
971 make_hor_seg( shine, | |
972 x, y, | |
973 x + width - shadowT - 1, y + mid, shadowT ); | |
974 make_hor_seg( shine + shadowT, | |
975 x, y, | |
976 x, y + height -1, shadowT ); | |
977 /* / */ | |
978 make_hor_seg( shadow, | |
979 x, y + height -1, | |
980 x + width - shadowT - 1, y + mid, shadowT ); | |
981 | |
982 triangle[0].x = x + 1; | |
983 triangle[0].y = y + height - 1; | |
984 triangle[1].x = x + width - 1; | |
985 triangle[1].y = y + mid; | |
986 triangle[2].x = x + 1; | |
987 triangle[2].y = y; | |
988 | |
989 XFillPolygon( dpy, win, bgGC, triangle, 3, Convex, ArcChord ); | |
990 | |
991 XDrawSegments( dpy, win, shadowGC, shadow, shadowT ); | |
992 XDrawSegments( dpy, win, shineGC, shine, shadowT * 2 ); | |
993 } | |
994 | |
995 static void draw_dimple(Display *dpy, Drawable win, GC shine, GC shadow, | |
996 int x, int y, int width, int height) | |
997 { | |
998 XDrawArc(dpy, win, shine, x, y, width, height, 46*64, 180*64); | |
999 XDrawArc(dpy, win, shadow, x, y, width, height, 45*64, -179*64); | |
1000 } | |
1001 | |
1002 /* | |
1003 ** Scrollbar values -> pixels, pixels -> scrollbar values | |
1004 */ | |
1005 | |
1006 static void seg_pixel_sizes(XlwScrollBarWidget w, int *above_return, int *ss_return, | |
1007 int *below_return) | |
1008 { | |
1009 float total, height, fuz; | |
1010 int value; | |
1011 int above, ss, below; | |
1012 | |
1013 height= widget_h(w); | |
1014 if( w->sb.showArrows ) height -= (2*arrow_h(w)); | |
1015 | |
1016 value = w->sb.value - w->sb.minimum; | |
1017 | |
1018 total = w->sb.maximum - w->sb.minimum; | |
1019 fuz = total / 2; | |
1020 | |
1021 ss = ((height * w->sb.sliderSize + fuz) / total); | |
1022 above = ((height * value + fuz) / total); | |
1023 below = ((height) - (ss + above)); | |
1024 | |
1025 /* Dont' let knob get smaller than SS_MIN */ | |
1026 if( ss < SS_MIN ) | |
1027 { | |
1028 /* add a percent amount for interger rounding */ | |
1029 float tmp = ((((float)(SS_MIN - ss) * (float)value)) / total) + 0.5; | |
1030 | |
1031 above -= (int)tmp; | |
1032 ss = SS_MIN; | |
1033 below = ((height) - (ss + above)); | |
1034 | |
1035 if( above < 0 ) | |
1036 { | |
1037 above = 0; | |
1038 below = height - ss; | |
1039 } | |
1040 if( below < 0 ) | |
1041 { | |
1042 above = height - ss; | |
1043 below = 0; | |
1044 } | |
1045 if( ss > height ) | |
1046 { | |
1047 above = 0; | |
1048 ss = height; | |
1049 below = 0; | |
1050 } | |
1051 } | |
1052 | |
1053 *above_return = above; | |
1054 *ss_return = ss; | |
1055 *below_return = below; | |
1056 | |
1057 CHECK(w); | |
1058 } | |
1059 | |
1060 static void verify_values(XlwScrollBarWidget w) | |
1061 { | |
1062 int total = w->sb.maximum - w->sb.minimum; | |
1063 | |
1064 if( w->sb.sliderSize > total ) | |
1065 { | |
1066 w->sb.sliderSize = total; | |
1067 } | |
1068 if( w->sb.pageIncrement > total ) | |
1069 { | |
1070 w->sb.pageIncrement = total; | |
1071 } | |
1072 if( w->sb.increment > total ) | |
1073 { | |
1074 w->sb.increment = total; | |
1075 } | |
1076 if( w->sb.value < w->sb.minimum ) | |
1077 { | |
1078 w->sb.value = w->sb.minimum; | |
1079 } | |
1080 if( w->sb.value > w->sb.maximum - w->sb.sliderSize) | |
1081 { | |
1082 w->sb.value = w->sb.maximum - w->sb.sliderSize; | |
1083 } | |
1084 } | |
1085 | |
1086 static int value_from_pixel(XlwScrollBarWidget w, int above) | |
1087 { | |
1088 float total, height, fuz; | |
1089 int value, ss; | |
1090 | |
1091 height= widget_h(w); | |
1092 if( w->sb.showArrows ) height -= (2*arrow_h(w)); | |
1093 | |
1094 total = w->sb.maximum - w->sb.minimum; | |
1095 fuz = height / 2; | |
1096 | |
1097 ss = ((height * w->sb.sliderSize + (total / 2)) / total); | |
1098 | |
1099 if( ss < SS_MIN ) | |
1100 { | |
1101 /* add a percent amount for interger rounding */ | |
1102 above += ((((SS_MIN - ss) * above) + fuz) / height); | |
1103 } | |
1104 | |
1105 { | |
1106 /* Prevent SIGFPE's that would occur if we don't truncate the | |
1107 value. */ | |
1108 float floatval = w->sb.minimum + ((float)(above * total + fuz ) / height); | |
1109 if (floatval >= (float) INT_MAX) | |
1110 value = INT_MAX; | |
1111 else if (floatval <= (float) INT_MIN) | |
1112 value = INT_MIN; | |
1113 else | |
1114 value = floatval; | |
1115 } | |
1116 | |
1117 return( value ); | |
1118 } | |
1119 | |
1120 | |
1121 static void redraw_dimple(XlwScrollBarWidget w, Display *dpy, Window win, | |
1122 int x, int y, int width, int height) | |
1123 { | |
1124 GC shine, shadow; | |
1125 int shadowT, size; | |
1126 | |
1127 if( KNOB_DIMPLE == knob_style(w) ) | |
1128 { | |
1129 if( w->sb.armed == ARM_KNOB ) | |
1130 { | |
1131 shine = w->sb.bottomShadowGC; | |
1132 shadow = w->sb.topShadowGC; | |
1133 } | |
1134 else | |
1135 { | |
1136 shine = w->sb.topShadowGC; | |
1137 shadow = w->sb.bottomShadowGC; | |
1138 } | |
1139 | |
1140 shadowT = w->sb.shadowThickness; | |
1141 | |
1142 x += shadowT; | |
1143 y += shadowT; | |
1144 width -= 2*shadowT; | |
1145 height -= 2*shadowT; | |
1146 | |
1147 size = (width < height ? width : height) * 3 / 4; | |
1148 | |
1149 if( size%2 != (width < height ? width : height)%2 ) size--; | |
1150 | |
1151 DBUG (fprintf(stderr, "%d %d\n", | |
1152 x + (width / 2) - (size / 2) - 2*shadowT, | |
1153 width - size - shadowT)); | |
1154 | |
1155 draw_dimple( dpy, win, shine, shadow, | |
1156 x + (width / 2) - (size / 2), | |
1157 y + (height / 2) - (size / 2), | |
1158 size, size ); | |
1159 } | |
1160 } | |
1161 | |
1162 static void draw_knob(XlwScrollBarWidget w, int above, int ss, int below) | |
1163 { | |
1164 Display *dpy = XtDisplay((Widget)w); | |
1165 Window win = XtWindow((Widget)w); | |
1166 int x, y, width, height; | |
1167 int shadowT; | |
1168 | |
1169 x = widget_x(w); | |
1170 y = widget_y(w); | |
1171 width = widget_w(w); | |
1172 height = widget_h(w); | |
1173 | |
1174 shadowT = w->sb.shadowThickness; | |
1175 | |
1176 if(shadowT > (width / 2)) shadowT = (width / 2); | |
1177 if(shadowT > (height / 2)) shadowT = (height / 2); | |
1178 if(shadowT <= 0) return; | |
1179 | |
1180 if( w->sb.showArrows && !arrow_same_end(w) ) y += (arrow_h(w)); | |
1181 | |
1182 /* trough above knob */ | |
1183 if( above > 0 ) | |
1184 { | |
1185 if( VERT(w) ) | |
1186 XClearArea( dpy, win, x, y, width, above, False ); | |
1187 else | |
1188 XClearArea( dpy, win, y, x, above, width, False ); | |
1189 } | |
1190 | |
1191 /* knob */ | |
1192 if( VERT(w) ) | |
1193 { | |
1194 draw_shadows( dpy, win, w->sb.topShadowGC, w->sb.bottomShadowGC, | |
1195 x, y + above, width, ss, shadowT); | |
1196 XFillRectangle( dpy, win, | |
1197 w->sb.backgroundGC, | |
1198 x+shadowT, y + above + shadowT, width-2*shadowT, ss-2*shadowT ); | |
1199 redraw_dimple(w, dpy, win, x, y + above, width, ss); | |
1200 } | |
1201 else | |
1202 { | |
1203 draw_shadows( dpy, win, w->sb.topShadowGC, w->sb.bottomShadowGC, | |
1204 y + above, x, ss, width, shadowT); | |
1205 XFillRectangle( dpy, win, | |
1206 w->sb.backgroundGC, | |
1207 y + above + shadowT, x+shadowT, ss-2*shadowT, width-2*shadowT ); | |
1208 redraw_dimple(w, dpy, win, y + above, x, ss, width); | |
1209 } | |
1210 | |
1211 /* trough below knob */ | |
1212 if( below > 0 ) | |
1213 { | |
1214 if( VERT(w) ) | |
1215 XClearArea( dpy, win, x, y + above + ss, width, below, False ); | |
1216 else | |
1217 XClearArea( dpy, win, y + above + ss, x, below, width, False ); | |
1218 } | |
1219 | |
1220 CHECK(w); | |
1221 } | |
1222 | |
1223 static void redraw_up_arrow(XlwScrollBarWidget w, Boolean armed, Boolean clear_behind) | |
1224 { | |
1225 Display *dpy = XtDisplay((Widget)w); | |
1226 Window win = XtWindow((Widget)w); | |
1227 GC bg, shine, shadow; | |
1228 int x, y, width, height, arrow_height, shadowT; | |
1229 | |
1230 x = widget_x(w); | |
1231 y = widget_y(w); | |
1232 width = widget_w(w); | |
1233 height = widget_h(w); | |
1234 arrow_height = arrow_h(w); | |
1235 | |
1236 shadowT = w->sb.shadowThickness; | |
1237 bg = w->sb.backgroundGC; | |
1238 | |
1239 if( armed ) | |
1240 { | |
1241 shine = w->sb.bottomShadowGC; | |
1242 shadow = w->sb.topShadowGC; | |
1243 } | |
1244 else | |
1245 { | |
1246 shine = w->sb.topShadowGC; | |
1247 shadow = w->sb.bottomShadowGC; | |
1248 } | |
1249 | |
1250 if( VERT(w) ) | |
1251 { | |
1252 if( arrow_same_end(w) ) | |
1253 { | |
1254 y += height - 2*arrow_h(w) + 2; | |
1255 } | |
1256 if( clear_behind ) | |
1257 XClearArea( dpy, win, x, y, width, arrow_height + 1, False ); | |
1258 draw_arrow_up( dpy, win, bg, shine, shadow, | |
1259 x + (width - arrow_height)/2, y, | |
1260 arrow_height, arrow_height, shadowT ); | |
1261 } | |
1262 else | |
1263 { | |
1264 if( arrow_same_end(w) ) | |
1265 { | |
1266 y += height - 2*arrow_h(w); | |
1267 } | |
1268 if( clear_behind ) | |
1269 XClearArea( dpy, win, y, x, arrow_height + 1, height, False ); | |
1270 draw_arrow_left( dpy, win, bg, shine, shadow, | |
1271 y, x + (width - arrow_height)/2, | |
1272 arrow_height, arrow_height, shadowT ); | |
1273 } | |
1274 } | |
1275 | |
1276 static void redraw_down_arrow(XlwScrollBarWidget w, Boolean armed, Boolean clear_behind) | |
1277 { | |
1278 Display *dpy = XtDisplay((Widget)w); | |
1279 Window win = XtWindow((Widget)w); | |
1280 GC bg, shine, shadow; | |
1281 int x, y, width, height, arrow_height, shadowT; | |
1282 | |
1283 x = widget_x(w); | |
1284 y = widget_y(w); | |
1285 width = widget_w(w); | |
1286 height = widget_h(w); | |
1287 arrow_height = arrow_h(w); | |
1288 | |
1289 shadowT = w->sb.shadowThickness; | |
1290 bg = w->sb.backgroundGC; | |
1291 | |
1292 if( armed ) | |
1293 { | |
1294 shine = w->sb.bottomShadowGC; | |
1295 shadow = w->sb.topShadowGC; | |
1296 } | |
1297 else | |
1298 { | |
1299 shine = w->sb.topShadowGC; | |
1300 shadow = w->sb.bottomShadowGC; | |
1301 } | |
1302 | |
1303 if( VERT(w) ) | |
1304 { | |
1305 if( clear_behind ) | |
1306 XClearArea( dpy, win, x, y + height - arrow_height, width, arrow_height + 1, False ); | |
1307 draw_arrow_down( dpy, win, bg, shine, shadow, | |
1308 x + (width - arrow_height)/2, y + height - arrow_height + 1, | |
1309 arrow_height, arrow_height, shadowT ); | |
1310 } | |
1311 else | |
1312 { | |
1313 if( clear_behind ) | |
1314 XClearArea( dpy, win, y + height - arrow_height, x, arrow_height + 1, height, False ); | |
1315 draw_arrow_right( dpy, win, bg, shine, shadow, | |
1316 y + height - arrow_height + 1, x + (width - arrow_height)/2, | |
1317 arrow_height, arrow_height, shadowT ); | |
1318 } | |
1319 } | |
1320 | |
1321 static void redraw_everything(XlwScrollBarWidget w, Region region, Boolean behind_arrows) | |
1322 { | |
1323 Display *dpy = XtDisplay((Widget)w); | |
1324 Window win = XtWindow((Widget)w); | |
1325 int x, y, width, height, shadowT, tmp; | |
1326 | |
1327 x = widget_x(w); | |
1328 y = widget_y(w); | |
1329 width = widget_w(w); | |
1330 height = widget_h(w); | |
1331 shadowT = w->sb.shadowThickness; | |
1332 | |
1333 if( w->sb.showArrows ) | |
1334 { | |
1335 if( region == NULL || XRectInRegion( region, x, y, width, width ) ) | |
1336 { | |
1337 redraw_up_arrow( w, False, behind_arrows ); | |
1338 } | |
1339 if( VERT(w) ) | |
1340 { | |
1341 y = y + height - width + 1; | |
1342 } | |
1343 else | |
1344 { | |
1345 tmp = y; | |
1346 y = x; | |
1347 x = tmp + height - width + 1; | |
1348 } | |
1349 if( region == NULL || XRectInRegion( region, x, y, width, width ) ) | |
1350 { | |
1351 redraw_down_arrow( w, False, behind_arrows ); | |
1352 } | |
1353 } | |
1354 | |
1355 draw_shadows( dpy, win, w->sb.bottomShadowGC, w->sb.topShadowGC, | |
1356 0, 0, w->core.width, w->core.height, shadowT); | |
1357 | |
1358 draw_knob( w, w->sb.above, w->sb.ss, w->sb.below ); | |
1359 | |
1360 } | |
1361 | |
1362 /************************************************************************ | |
1363 ** | |
1364 ** Method funcitons | |
1365 ** | |
1366 */ | |
1367 | |
1368 /* | |
1369 ** Initialize | |
1370 */ | |
1371 static void Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num_args) | |
1372 { | |
1373 XlwScrollBarWidget request = (XlwScrollBarWidget) treq; | |
1374 XlwScrollBarWidget w = (XlwScrollBarWidget) tnew; | |
1375 Display *dpy = XtDisplay((Widget)w); | |
1376 Window win = RootWindowOfScreen( DefaultScreenOfDisplay(dpy) ); | |
1377 | |
1378 DBUG(fprintf(stderr, "Initialize\n")); | |
1379 | |
1380 if( request->core.width == 0 ) w->core.width += (VERT(w) ? 12 : 25); | |
1381 if( request->core.height == 0 ) w->core.height += (VERT(w) ? 25 : 12); | |
1382 | |
1383 verify_values(w); | |
1384 | |
1385 w->sb.lastY = 0; | |
1386 w->sb.above = 0; | |
1387 w->sb.ss = 0; | |
1388 w->sb.below = 0; | |
1389 w->sb.armed = ARM_NONE; | |
1390 | |
1391 if( w->sb.shadowThickness > 5 ) w->sb.shadowThickness = 5; | |
1392 | |
1393 w->sb.grayPixmap = | |
1394 XCreatePixmapFromBitmapData( dpy, win, (char *) gray_bits, gray_width, | |
1395 gray_height, 1, 0, 1); | |
1396 | |
1397 make_trough_pixel( w ); | |
1398 | |
1399 make_shadow_pixels( w ); | |
1400 | |
1401 w->sb.backgroundGC = get_gc(w, w->core.background_pixel, w->core.background_pixel, None); | |
1402 w->sb.topShadowGC = get_gc(w, w->sb.topShadowColor, w->core.background_pixel, w->sb.topShadowPixmap); | |
1403 w->sb.bottomShadowGC = get_gc(w, w->sb.bottomShadowColor, w->core.background_pixel, w->sb.bottomShadowPixmap); | |
1404 | |
1405 w->sb.fullRedrawNext = True; | |
1406 } | |
1407 | |
1408 /* | |
1409 ** Destroy | |
1410 */ | |
1411 static void Destroy(Widget widget) | |
1412 { | |
1413 XlwScrollBarWidget w = (XlwScrollBarWidget) widget; | |
1414 Display *dpy = XtDisplay((Widget)w); | |
1415 | |
1416 DBUG(fprintf(stderr, "Destroy\n")); | |
1417 | |
1418 XtReleaseGC(widget, w->sb.bottomShadowGC); | |
1419 XtReleaseGC(widget, w->sb.topShadowGC); | |
1420 XtReleaseGC(widget, w->sb.backgroundGC); | |
1421 | |
1422 XFreePixmap( dpy, w->sb.grayPixmap ); | |
1423 } | |
1424 | |
1425 /* | |
1426 ** Realize | |
1427 */ | |
1428 static void Realize(Widget widget, XtValueMask *valuemask, XSetWindowAttributes *attr) | |
1429 { | |
1430 XlwScrollBarWidget w = (XlwScrollBarWidget) widget; | |
1431 Display *dpy = XtDisplay((Widget)w); | |
1432 Window win; | |
1433 XSetWindowAttributes win_attr; | |
1434 | |
1435 DBUG(fprintf(stderr, "Realize\n")); | |
1436 | |
1437 (*coreClassRec.core_class.realize)(widget, valuemask, attr); | |
1438 | |
1439 win = XtWindow((Widget)w); | |
1440 | |
1441 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
1442 | |
1443 XSetWindowBackground( dpy, win, w->sb.troughColor); | |
1444 | |
1445 /* Change bit gravity so widget is not cleared on resize */ | |
1446 win_attr.bit_gravity = NorthWestGravity; | |
1447 XChangeWindowAttributes( dpy, win, CWBitGravity , &win_attr); | |
1448 | |
1449 } | |
1450 | |
1451 /* | |
1452 ** Resize | |
1453 */ | |
1454 static void Resize(Widget widget) | |
1455 { | |
1456 XlwScrollBarWidget w = (XlwScrollBarWidget) widget; | |
1457 Display *dpy = XtDisplay((Widget)w); | |
1458 Window win = XtWindow((Widget)w); | |
1459 | |
1460 if( XtIsRealized(widget) ) | |
1461 { | |
1462 DBUG(fprintf(stderr, "Resize = %08lx\n", w)); | |
1463 | |
1464 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
1465 | |
1466 /*redraw_everything(w, NULL, True);*/ | |
1467 | |
1468 w->sb.fullRedrawNext = True; | |
1469 /* Force expose event */ | |
1470 XClearArea(dpy, win, widget_x(w), widget_y(w), 1, 1, True); | |
1471 } | |
1472 } | |
1473 | |
1474 /* | |
1475 ** Redisplay | |
1476 */ | |
1477 static void Redisplay(Widget widget, XEvent *event, Region region) | |
1478 { | |
1479 XlwScrollBarWidget w = (XlwScrollBarWidget) widget; | |
1480 | |
1481 DBUG(fprintf(stderr, "Redisplay = %08lx\n", w)); | |
1482 | |
1483 if( XtIsRealized(widget) ) | |
1484 { | |
1485 if( w->sb.fullRedrawNext ) | |
1486 { | |
1487 redraw_everything(w, NULL, True); | |
1488 } | |
1489 else | |
1490 { | |
1491 redraw_everything(w, region, False); | |
1492 } | |
1493 w->sb.fullRedrawNext = False; | |
1494 } | |
1495 } | |
1496 | |
1497 /* | |
1498 ** SetValues | |
1499 */ | |
1500 static Boolean SetValues(Widget current, Widget request, Widget neww, ArgList args, Cardinal *num_args) | |
1501 { | |
1502 XlwScrollBarWidget cur = (XlwScrollBarWidget) current; | |
1503 XlwScrollBarWidget w = (XlwScrollBarWidget) neww; | |
1504 Boolean do_redisplay = False; | |
1505 | |
1506 if( cur->sb.troughColor != w->sb.troughColor ) | |
1507 { | |
1508 if( XtIsRealized((Widget)w) ) | |
1509 { | |
1510 XSetWindowBackground( XtDisplay((Widget)w), XtWindow((Widget)w), | |
1511 w->sb.troughColor); | |
1512 do_redisplay = True; | |
1513 } | |
1514 } | |
1515 | |
1516 if( cur->core.background_pixel != w->core.background_pixel ) | |
1517 { | |
1518 XtReleaseGC((Widget)cur, cur->sb.backgroundGC); | |
1519 w->sb.backgroundGC = get_gc(w, w->core.background_pixel, w->core.background_pixel, None); | |
1520 do_redisplay = True; | |
1521 } | |
1522 | |
1523 if( cur->sb.topShadowColor != w->sb.topShadowColor || | |
1524 cur->sb.topShadowPixmap != w->sb.topShadowPixmap ) | |
1525 { | |
1526 XtReleaseGC((Widget)cur, cur->sb.topShadowGC); | |
1527 w->sb.topShadowGC = get_gc(w, w->sb.topShadowColor, w->core.background_pixel, w->sb.topShadowPixmap); | |
1528 do_redisplay = True; | |
1529 } | |
1530 | |
1531 if( cur->sb.bottomShadowColor != w->sb.bottomShadowColor || | |
1532 cur->sb.bottomShadowPixmap != w->sb.bottomShadowPixmap ) | |
1533 { | |
1534 XtReleaseGC((Widget)cur, cur->sb.bottomShadowGC); | |
1535 w->sb.bottomShadowGC = get_gc(w, w->sb.bottomShadowColor, w->core.background_pixel, w->sb.bottomShadowPixmap); | |
1536 do_redisplay = True; | |
1537 } | |
1538 | |
1539 if( cur->sb.orientation != w->sb.orientation ) | |
1540 { | |
1541 do_redisplay = True; | |
1542 } | |
1543 | |
1544 | |
1545 if( cur->sb.minimum != w->sb.minimum || | |
1546 cur->sb.maximum != w->sb.maximum || | |
1547 cur->sb.sliderSize != w->sb.sliderSize || | |
1548 cur->sb.value != w->sb.value || | |
1549 cur->sb.pageIncrement != w->sb.pageIncrement || | |
1550 cur->sb.increment != w->sb.increment ) | |
1551 { | |
1552 verify_values(w); | |
1553 if( XtIsRealized((Widget)w) ) | |
1554 { | |
1555 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
1556 draw_knob( w, w->sb.above, w->sb.ss, w->sb.below ); | |
1557 } | |
1558 } | |
1559 | |
1560 if( w->sb.shadowThickness > 5 ) w->sb.shadowThickness = 5; | |
1561 | |
1562 return( do_redisplay ); | |
1563 } | |
1564 | |
1565 void XlwScrollBarGetValues(Widget widget, int *value, int *sliderSize, | |
1566 int *increment, int *pageIncrement) | |
1567 { | |
1568 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
1569 | |
1570 if( w && XtClass((Widget)w) == xlwScrollBarWidgetClass ) | |
1571 { | |
1572 if( value ) *value = w->sb.value; | |
1573 if( sliderSize ) *sliderSize = w->sb.sliderSize; | |
1574 if( increment ) *increment = w->sb.increment; | |
1575 if( pageIncrement ) *pageIncrement = w->sb.pageIncrement; | |
1576 } | |
1577 } | |
1578 | |
1579 void XlwScrollBarSetValues(Widget widget, int value, int sliderSize, | |
1580 int increment, int pageIncrement, Boolean notify) | |
1581 { | |
1582 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
1583 int last_value; | |
1584 | |
1585 if( w && XtClass((Widget)w) == xlwScrollBarWidgetClass && | |
1586 (w->sb.value != value || | |
1587 w->sb.sliderSize != sliderSize || | |
1588 w->sb.increment != increment || | |
1589 w->sb.pageIncrement != pageIncrement )) | |
1590 { | |
1591 w->sb.value = value; | |
1592 w->sb.sliderSize = sliderSize; | |
1593 w->sb.increment = increment; | |
1594 w->sb.pageIncrement = pageIncrement; | |
1595 | |
1596 verify_values(w); | |
1597 | |
1598 if( XtIsRealized(widget) ) | |
1599 { | |
1600 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
1601 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
1602 | |
1603 last_value = w->sb.value; | |
1604 w->sb.value = value_from_pixel(w, w->sb.above); | |
1605 verify_values(w); | |
1606 | |
1607 if( w->sb.value != last_value && notify ) | |
1608 { | |
1609 call_callbacks( w, XmCR_VALUE_CHANGED, w->sb.value, 0, NULL ); | |
1610 } | |
1611 } | |
1612 } | |
1613 } | |
1614 | |
1615 /************************************************************************ | |
1616 ** | |
1617 ** Action funcitons | |
1618 ** | |
1619 */ | |
1620 | |
1621 static void timer(XtPointer data, XtIntervalId *id) | |
1622 { | |
1623 XlwScrollBarWidget w = (XlwScrollBarWidget)data; | |
1624 int reason, last_value; | |
1625 | |
1626 if( w->sb.armed != ARM_NONE ) | |
1627 { | |
1628 last_value = w->sb.value; | |
1629 reason = XmCR_NONE; | |
1630 | |
1631 switch( w->sb.armed ) | |
1632 { | |
1633 case ARM_PAGEUP: | |
1634 w->sb.value = safe_subtract( w->sb.value, w->sb.pageIncrement ); | |
1635 reason = XmCR_PAGE_DECREMENT; | |
1636 break; | |
1637 case ARM_PAGEDOWN: | |
1638 w->sb.value = safe_add( w->sb.value, w->sb.pageIncrement ); | |
1639 reason = XmCR_PAGE_INCREMENT; | |
1640 break; | |
1641 case ARM_UP: | |
1642 w->sb.value = safe_subtract( w->sb.value, w->sb.increment ); | |
1643 reason = XmCR_DECREMENT; | |
1644 break; | |
1645 case ARM_DOWN: | |
1646 w->sb.value = safe_add( w->sb.value, w->sb.increment ); | |
1647 reason = XmCR_INCREMENT; | |
1648 break; | |
1649 } | |
1650 | |
1651 verify_values(w); | |
1652 | |
1653 if( last_value != w->sb.value ) | |
1654 { | |
1655 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
1656 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
1657 | |
1658 call_callbacks( w, reason, w->sb.value, 0, NULL ); | |
1659 | |
1660 XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w), | |
1661 (unsigned long) w->sb.repeatDelay, | |
1662 timer, (XtPointer) w ); | |
1663 } | |
1664 } | |
1665 } | |
1666 | |
1667 static int what_button(XlwScrollBarWidget w, int mouse_x, int mouse_y) | |
1668 { | |
1669 int x, y, width, height, arrow_height_top, arrow_height_bottom; | |
1670 int where; | |
1671 | |
1672 x = widget_x(w); | |
1673 y = widget_y(w); | |
1674 width = widget_w(w); | |
1675 height = widget_h(w); | |
1676 | |
1677 #if 0 | |
1678 arrow_height = w->sb.showArrows ? arrow_h(w) : 0; | |
1679 #endif | |
1680 if( w->sb.showArrows ) | |
1681 { | |
1682 if( arrow_same_end(w) ) | |
1683 { | |
1684 arrow_height_top = 0; | |
1685 arrow_height_bottom = 2*arrow_h(w); | |
1686 } | |
1687 else | |
1688 { | |
1689 arrow_height_top = arrow_height_bottom = arrow_h(w); | |
1690 } | |
1691 } | |
1692 else | |
1693 { | |
1694 arrow_height_top = arrow_height_bottom = 0; | |
1695 } | |
1696 | |
1697 where = BUTTON_NONE; | |
1698 | |
1699 if( mouse_x > x && mouse_x < (x + width) ) | |
1700 { | |
1701 if( mouse_y > (y + arrow_height_top) && mouse_y < (y + height - arrow_height_bottom) ) | |
1702 { | |
1703 if( mouse_y < (y + w->sb.above + arrow_height_top) ) | |
1704 { | |
1705 where = BUTTON_TROUGH_ABOVE; | |
1706 } | |
1707 else if( mouse_y > (y + w->sb.above + w->sb.ss + arrow_height_top) ) | |
1708 { | |
1709 where = BUTTON_TROUGH_BELOW; | |
1710 } | |
1711 else | |
1712 { | |
1713 where = BUTTON_KNOB; | |
1714 } | |
1715 } | |
1716 else if( arrow_same_end(w) ) | |
1717 { | |
1718 if( mouse_y > (y + height - arrow_height_bottom + 1) && mouse_y < (y + height) ) | |
1719 { | |
1720 if( mouse_y < (y + height - arrow_height_bottom/2) ) | |
1721 { | |
1722 where = BUTTON_UP_ARROW; | |
1723 } | |
1724 else | |
1725 { | |
1726 where = BUTTON_DOWN_ARROW; | |
1727 } | |
1728 } | |
1729 } | |
1730 else | |
1731 { | |
1732 if( mouse_y > y && mouse_y < (y + arrow_height_top) ) | |
1733 { | |
1734 where = BUTTON_UP_ARROW; | |
1735 } | |
1736 else if( mouse_y > (y + height - arrow_height_bottom + 1) && mouse_y < (y + height) ) | |
1737 { | |
1738 where = BUTTON_DOWN_ARROW; | |
1739 } | |
1740 } | |
1741 } | |
1742 #if 0 | |
1743 if( mouse_x > x && mouse_x < (x + width) ) | |
1744 { | |
1745 if( mouse_y > (y + arrow_height) && mouse_y < (y + height - arrow_height) ) | |
1746 { | |
1747 if( mouse_y < (y+w->sb.above+arrow_height) ) | |
1748 { | |
1749 where = BUTTON_TROUGH_ABOVE; | |
1750 } | |
1751 else if( mouse_y > (y + w->sb.above + w->sb.ss + arrow_height) ) | |
1752 { | |
1753 where = BUTTON_TROUGH_BELOW; | |
1754 } | |
1755 else | |
1756 { | |
1757 where = BUTTON_KNOB; | |
1758 } | |
1759 } | |
1760 else if( mouse_y > y && mouse_y < (y + arrow_height) ) | |
1761 { | |
1762 where = BUTTON_UP_ARROW; | |
1763 } | |
1764 else if( mouse_y > (y + height - arrow_height + 1) && mouse_y < (y + height) ) | |
1765 { | |
1766 where = BUTTON_DOWN_ARROW; | |
1767 } | |
1768 } | |
1769 #endif | |
1770 return( where ); | |
1771 } | |
1772 | |
1773 #define FORCED_SCROLL_NONE 0 | |
1774 #define FORCED_SCROLL_DOWNRIGHT 1 | |
1775 #define FORCED_SCROLL_UPLEFT 2 | |
1776 | |
1777 int forced_scroll_flag = FORCED_SCROLL_NONE; | |
1778 | |
1779 /* | |
1780 ** PageDownOrRight | |
1781 */ | |
1782 static void PageDownOrRight(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
1783 { | |
1784 forced_scroll_flag = FORCED_SCROLL_DOWNRIGHT; | |
1785 Select(widget, event, parms, num_parms); | |
1786 forced_scroll_flag = FORCED_SCROLL_NONE; | |
1787 } | |
1788 | |
1789 /* | |
1790 ** PageUpOrLeft | |
1791 */ | |
1792 static void PageUpOrLeft(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
1793 { | |
1794 forced_scroll_flag = FORCED_SCROLL_UPLEFT; | |
1795 Select(widget, event, parms, num_parms); | |
1796 forced_scroll_flag = FORCED_SCROLL_NONE; | |
1797 } | |
1798 | |
1799 /* | |
1800 ** Select | |
1801 */ | |
1802 static void Select(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
1803 { | |
1804 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
1805 int mouse_x, mouse_y; | |
1806 int reason, last_value; | |
1807 int sb_button; | |
1808 | |
1809 DBUG(fprintf(stderr, "Select:\n")); | |
1810 | |
1811 mouse_x = event_x( w, event ); | |
1812 mouse_y = event_y( w, event ); | |
1813 | |
1814 w->sb.savedValue = w->sb.value; | |
1815 | |
1816 last_value = w->sb.value; | |
1817 reason = XmCR_NONE; | |
1818 | |
1819 XtGrabKeyboard( (Widget)w, False, GrabModeAsync, GrabModeAsync, event->xbutton.time ); | |
1820 | |
1821 sb_button = what_button(w, mouse_x, mouse_y); | |
1822 | |
1823 if ( forced_scroll_flag != FORCED_SCROLL_NONE ) | |
1824 { | |
1825 switch ( sb_button ) | |
1826 { | |
1827 case BUTTON_TROUGH_ABOVE: | |
1828 case BUTTON_TROUGH_BELOW: | |
1829 case BUTTON_KNOB: | |
1830 sb_button= BUTTON_NONE; /* cause next switch to fall through */ | |
1831 if ( forced_scroll_flag == FORCED_SCROLL_UPLEFT ) | |
1832 { | |
1833 w->sb.value = safe_subtract( w->sb.value, w->sb.pageIncrement ); | |
1834 w->sb.armed = ARM_PAGEUP; | |
1835 reason = XmCR_PAGE_DECREMENT; | |
1836 break; | |
1837 } | |
1838 else if ( forced_scroll_flag == FORCED_SCROLL_DOWNRIGHT ) | |
1839 { | |
1840 w->sb.value = safe_add( w->sb.value, w->sb.pageIncrement ); | |
1841 w->sb.armed = ARM_PAGEDOWN; | |
1842 reason = XmCR_PAGE_INCREMENT; | |
1843 break; | |
1844 } | |
1845 abort(); | |
1846 } | |
1847 } | |
1848 | |
1849 switch( sb_button ) | |
1850 { | |
1851 case BUTTON_TROUGH_ABOVE: | |
1852 w->sb.value = safe_subtract( w->sb.value, w->sb.pageIncrement ); | |
1853 w->sb.armed = ARM_PAGEUP; | |
1854 reason = XmCR_PAGE_DECREMENT; | |
1855 break; | |
1856 case BUTTON_TROUGH_BELOW: | |
1857 w->sb.value = safe_add( w->sb.value, w->sb.pageIncrement ); | |
1858 w->sb.armed = ARM_PAGEDOWN; | |
1859 reason = XmCR_PAGE_INCREMENT; | |
1860 break; | |
1861 case BUTTON_KNOB: | |
1862 w->sb.lastY = mouse_y; | |
1863 w->sb.armed = ARM_KNOB; | |
1864 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
1865 break; | |
1866 case BUTTON_UP_ARROW: | |
1867 if( event->xbutton.state & ControlMask ) | |
1868 { | |
1869 w->sb.value = INT_MIN; | |
1870 w->sb.armed = ARM_UP; | |
1871 reason = XmCR_TO_TOP; | |
1872 } | |
1873 else | |
1874 { | |
1875 w->sb.value = safe_subtract( w->sb.value, w->sb.increment ); | |
1876 w->sb.armed = ARM_UP; | |
1877 reason = XmCR_DECREMENT; | |
1878 } | |
1879 redraw_up_arrow(w, True, False); | |
1880 break; | |
1881 case BUTTON_DOWN_ARROW: | |
1882 if( event->xbutton.state & ControlMask ) | |
1883 { | |
1884 w->sb.value = INT_MAX; | |
1885 w->sb.armed = ARM_DOWN; | |
1886 reason = XmCR_TO_BOTTOM; | |
1887 } | |
1888 else | |
1889 { | |
1890 w->sb.value = safe_add( w->sb.value, w->sb.increment ); | |
1891 w->sb.armed = ARM_DOWN; | |
1892 reason = XmCR_INCREMENT; | |
1893 } | |
1894 redraw_down_arrow(w, True, False); | |
1895 break; | |
1896 } | |
1897 | |
1898 verify_values(w); | |
1899 | |
1900 if( last_value != w->sb.value ) | |
1901 { | |
1902 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
1903 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
1904 | |
1905 call_callbacks( w, reason, w->sb.value, mouse_y, event ); | |
1906 | |
1907 XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)w), | |
1908 (unsigned long) w->sb.initialDelay, | |
1909 timer, (XtPointer) w ); | |
1910 } | |
1911 | |
1912 CHECK(w); | |
1913 } | |
1914 | |
1915 /* | |
1916 ** Drag | |
1917 */ | |
1918 static void Drag(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
1919 { | |
1920 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
1921 int diff; | |
1922 int height, mouse_y; | |
1923 int last_value, last_above; | |
1924 | |
1925 DBUG(fprintf(stderr, "Drag:\n")); | |
1926 | |
1927 if( w->sb.armed == ARM_KNOB ) | |
1928 { | |
1929 height = widget_h(w); | |
1930 if( w->sb.showArrows ) height -= (2*arrow_h(w)); | |
1931 | |
1932 mouse_y = event_y( w, event ); | |
1933 | |
1934 diff = mouse_y - w->sb.lastY; | |
1935 | |
1936 last_above = w->sb.above; | |
1937 last_value = w->sb.value; | |
1938 | |
1939 if( diff < 0 ) | |
1940 { | |
1941 /* up */ | |
1942 w->sb.above -= (-diff); | |
1943 if( w->sb.above < 0 ) | |
1944 { | |
1945 mouse_y = (mouse_y - w->sb.above); | |
1946 w->sb.above = 0; | |
1947 diff = 0; | |
1948 w->sb.below = height - w->sb.ss; | |
1949 } | |
1950 w->sb.below -= diff; | |
1951 CHECK(w); | |
1952 } | |
1953 else if( diff > 0 ) | |
1954 { | |
1955 /* down */ | |
1956 w->sb.above += diff; | |
1957 if( w->sb.above + w->sb.ss > height ) | |
1958 { | |
1959 mouse_y = height + (mouse_y - (w->sb.above + w->sb.ss)); | |
1960 w->sb.above = height - w->sb.ss; | |
1961 diff = 0; | |
1962 w->sb.below = 0; | |
1963 } | |
1964 w->sb.below -= diff; | |
1965 CHECK(w); | |
1966 } | |
1967 | |
1968 if( last_above != w->sb.above ) | |
1969 { | |
1970 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
1971 | |
1972 w->sb.lastY = mouse_y; | |
1973 | |
1974 w->sb.value = value_from_pixel(w, w->sb.above); | |
1975 verify_values(w); | |
1976 CHECK(w); | |
1977 | |
1978 if( w->sb.value != last_value ) | |
1979 { | |
1980 call_callbacks( w, XmCR_DRAG, w->sb.value, event_y(w, event), event ); | |
1981 } | |
1982 } | |
1983 } | |
1984 CHECK(w); | |
1985 } | |
1986 | |
1987 /* | |
1988 ** Release | |
1989 */ | |
1990 static void Release(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
1991 { | |
1992 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
1993 | |
1994 DBUG(fprintf(stderr, "EndDrag:\n")); | |
1995 | |
1996 switch( w->sb.armed ) | |
1997 { | |
1998 case ARM_KNOB: | |
1999 call_callbacks( w, XmCR_VALUE_CHANGED, w->sb.value, event_y(w, event), event ); | |
2000 w->sb.armed = ARM_NONE; | |
2001 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
2002 break; | |
2003 case ARM_UP: | |
2004 redraw_up_arrow(w, False, False); | |
2005 break; | |
2006 case ARM_DOWN: | |
2007 redraw_down_arrow(w, False, False); | |
2008 break; | |
2009 } | |
2010 | |
2011 XtUngrabKeyboard( (Widget)w, event->xbutton.time ); | |
2012 | |
2013 w->sb.armed = ARM_NONE; | |
2014 } | |
2015 | |
2016 /* | |
2017 ** Jump | |
2018 */ | |
2019 static void Jump(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
2020 { | |
2021 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
2022 int x, y, width, height, mouse_x, mouse_y; | |
2023 int arrow_height; | |
2024 int last_above, last_value; | |
2025 | |
2026 DBUG(fprintf(stderr, "Jump:\n")); | |
2027 | |
2028 x = widget_x(w); | |
2029 y = widget_y(w); | |
2030 width = widget_w(w); | |
2031 height = widget_h(w); | |
2032 mouse_x = event_x( w, event ); | |
2033 mouse_y = event_y( w, event ); | |
2034 | |
2035 arrow_height = w->sb.showArrows ? arrow_h(w) : 0; | |
2036 | |
2037 XtGrabKeyboard( (Widget)w, False, GrabModeAsync, GrabModeAsync, event->xbutton.time ); | |
2038 | |
2039 switch( what_button(w, mouse_x, mouse_y) ) | |
2040 { | |
2041 case BUTTON_TROUGH_ABOVE: | |
2042 case BUTTON_TROUGH_BELOW: | |
2043 case BUTTON_KNOB: | |
2044 w->sb.savedValue = w->sb.value; | |
2045 | |
2046 height -= (2*arrow_height); | |
2047 y += arrow_height; | |
2048 | |
2049 last_above = w->sb.above; | |
2050 last_value = w->sb.value; | |
2051 | |
2052 w->sb.armed = ARM_KNOB; | |
2053 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
2054 | |
2055 w->sb.above = mouse_y - (w->sb.ss / 2) - arrow_height; | |
2056 if( w->sb.above < 0 ) | |
2057 { | |
2058 w->sb.above = 0; | |
2059 } | |
2060 else if( w->sb.above + w->sb.ss > height ) | |
2061 { | |
2062 w->sb.above = height - w->sb.ss; | |
2063 } | |
2064 w->sb.below = (height - (w->sb.ss + w->sb.above)); | |
2065 | |
2066 if( last_above != w->sb.above ) | |
2067 { | |
2068 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
2069 | |
2070 w->sb.value = value_from_pixel(w, w->sb.above); | |
2071 verify_values(w); | |
2072 CHECK(w); | |
2073 | |
2074 w->sb.lastY = mouse_y; | |
2075 w->sb.lastY = w->sb.above + arrow_height + (w->sb.ss / 2); | |
2076 | |
2077 if( w->sb.value != last_value ) | |
2078 { | |
2079 call_callbacks( w, XmCR_DRAG, w->sb.value, event_y(w, event), event ); | |
2080 } | |
2081 } | |
2082 break; | |
2083 } | |
2084 CHECK(w); | |
2085 } | |
2086 | |
2087 /* | |
2088 ** Abort | |
2089 */ | |
2090 static void Abort(Widget widget, XEvent *event, String *parms, Cardinal *num_parms) | |
2091 { | |
2092 XlwScrollBarWidget w = (XlwScrollBarWidget)widget; | |
2093 | |
2094 DBUG(fprintf(stderr, "Abort:\n")); | |
2095 | |
2096 if( w->sb.armed != ARM_NONE ) | |
2097 { | |
2098 if( w->sb.value != w->sb.savedValue ) | |
2099 { | |
2100 w->sb.value = w->sb.savedValue; | |
2101 | |
2102 seg_pixel_sizes(w, &w->sb.above, &w->sb.ss, &w->sb.below); | |
2103 draw_knob(w, w->sb.above, w->sb.ss, w->sb.below); | |
2104 | |
2105 call_callbacks( w, XmCR_VALUE_CHANGED, w->sb.value, event_y(w, event), event ); | |
2106 } | |
2107 | |
2108 switch( w->sb.armed ) | |
2109 { | |
2110 case ARM_UP: | |
2111 redraw_up_arrow(w, False, False); | |
2112 break; | |
2113 case ARM_DOWN: | |
2114 redraw_down_arrow(w, False, False); | |
2115 break; | |
2116 } | |
2117 | |
2118 w->sb.armed = ARM_NONE; | |
2119 | |
2120 XtUngrabKeyboard( (Widget)w, event->xbutton.time ); | |
2121 } | |
2122 } |