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