1 /*
2 **
3 ** Scrollbar.c
4 **
5 ** Copyright (C) 1994, 1995, 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with GNU gv; see the file COPYING. If not, write to
20 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ** Boston, MA 02111-1307, USA.
22 **
23 ** Author: Johannes Plass (plass@thep.physik.uni-mainz.de)
24 ** Department of Physics
25 ** Johannes Gutenberg-University
26 ** Mainz, Germany
27 **
28 ** Jose E. Marchesi (jemarch@gnu.org)
29 ** GNU Project
30 **
31 */
32
33 #include "ac_config.h"
34 /*
35 #define MESSAGES
36 */
37 #include "message.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <math.h>
42
43 #include <inttypes.h>
44
45 #include "paths.h"
46 #include INC_X11(IntrinsicP.h)
47 #include INC_X11(StringDefs.h)
48 #include INC_XAW(XawInit.h)
49 #include INC_XMU(Drawing.h)
50 #include "ScrollbarP.h"
51 #include "actions.h"
52
53
54 /* Private definitions. */
55
56 static char defaultTranslations[] =
57 "<Btn1Down>: NotifyScroll()\n\
58 <Btn2Down>: MoveThumb() NotifyThumb() \n\
59 <Btn3Down>: NotifyScroll()\n\
60 <Btn1Motion>: HandleThumb() HandleAutoscroll() \n\
61 <Btn2Motion>: MoveThumb() NotifyThumb() \n\
62 <Btn3Motion>: HandleThumb() \n\
63 <BtnUp>: EndScroll()";
64
65 static float floatZero = 0.0;
66
67 #define Offset(field) XtOffsetOf(ScrollbarRec, scrollbar.field)
68 static XtResource resources[] = {
69 {XtNlength, XtCLength, XtRDimension, sizeof(Dimension),
70 Offset(length), XtRImmediate, (XtPointer) 1},
71 {XtNthickness, XtCThickness, XtRDimension, sizeof(Dimension),
72 Offset(thickness), XtRImmediate, (XtPointer) 14},
73 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
74 Offset(orientation), XtRImmediate, (XtPointer) XtorientVertical},
75 {XtNscrollProc, XtCCallback, XtRCallback, sizeof(XtPointer),
76 Offset(scrollProc), XtRCallback, NULL},
77 {XtNthumbProc, XtCCallback, XtRCallback, sizeof(XtPointer),
78 Offset(thumbProc), XtRCallback, NULL},
79 {XtNjumpProc, XtCCallback, XtRCallback, sizeof(XtPointer),
80 Offset(jumpProc), XtRCallback, NULL},
81 {XtNtopOfThumb, XtCTopOfThumb, XtRFloat, sizeof(float),
82 Offset(top), XtRFloat, (XtPointer)&floatZero},
83 {XtNthumb, XtCThumb, XtRBitmap, sizeof(Pixmap),
84 Offset(thumb), XtRImmediate, (XtPointer) None},
85 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
86 Offset(foreground), XtRString, XtDefaultForeground},
87 {XtNshown, XtCShown, XtRFloat, sizeof(float),
88 Offset(shown), XtRFloat, (XtPointer)&floatZero},
89 {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
90 Offset(min_thumb), XtRImmediate, (XtPointer) 7},
91 {XtNshowArrows, XtCShowArrows, XtRBoolean, sizeof(Boolean),
92 Offset(show_arrows), XtRImmediate, (XtPointer) TRUE},
93 {XtNthumbTopIndent, XtCThumbTopIndent, XtRDimension, sizeof(Dimension),
94 Offset(thumb_top_indent), XtRImmediate, (XtPointer) 1},
95 {XtNthumbSideIndent, XtCThumbSideIndent, XtRDimension, sizeof(Dimension),
96 Offset(thumb_side_indent), XtRImmediate, (XtPointer) 0},
97 {XtNarrowTopIndent, XtCArrowTopIndent, XtRDimension, sizeof(Dimension),
98 Offset(arrow_top_indent), XtRImmediate, (XtPointer) 0},
99 {XtNarrowSideIndent, XtCArrowSideIndent, XtRDimension, sizeof(Dimension),
100 Offset(arrow_side_indent), XtRImmediate, (XtPointer) 0},
101 {XtNuseDynamic, XtCUseDynamic, XtRBoolean, sizeof(Boolean),
102 Offset(use_dynamic), XtRImmediate, (XtPointer) TRUE},
103 {XtNinterval, XtCInterval, XtRInt, sizeof(int),
104 Offset(interval), XtRImmediate, (XtPointer) 100},
105 {XtNdelay, XtCDelay, XtRInt, sizeof(int),
106 Offset(delay), XtRImmediate, (XtPointer) 300},
107 };
108 #undef Offset
109
110 static void ClassInitialize(void);
111 static void Initialize(Widget,Widget,ArgList,Cardinal*);
112 static void Destroy(Widget);
113 static void Realize(Widget,XtValueMask*,XSetWindowAttributes*);
114 static void Resize(Widget);
115 static void Redisplay(Widget,XEvent*,Region);
116 static Boolean SetValues(Widget,Widget,Widget,ArgList,Cardinal*);
117
118 static void HandleThumb(Widget,XEvent*,String*,Cardinal*);
119 static void HandleAutoscroll(Widget,XEvent*,String*,Cardinal*);
120 static void MoveThumb(Widget,XEvent*,String*,Cardinal*);
121 static void NotifyThumb(Widget,XEvent*,String*,Cardinal*);
122 static void NotifyScroll(Widget,XEvent*,String*,Cardinal*);
123 static void EndScroll(Widget,XEvent*,String*,Cardinal*);
124
125 static XtActionsRec actions[] = {
126 {"HandleThumb", HandleThumb},
127 {"HandleAutoscroll",HandleAutoscroll},
128 {"MoveThumb", MoveThumb},
129 {"NotifyThumb", NotifyThumb},
130 {"NotifyScroll", NotifyScroll},
131 {"EndScroll", EndScroll}
132 };
133
134 ScrollbarClassRec scrollbarClassRec = {
135 { /* core fields */
136 /* superclass */ (WidgetClass) &threeDClassRec,
137 /* class_name */ "Scrollbar",
138 /* size */ sizeof(ScrollbarRec),
139 /* class_initialize */ ClassInitialize,
140 /* class_part_init */ NULL,
141 /* class_inited */ FALSE,
142 /* initialize */ Initialize,
143 /* initialize_hook */ NULL,
144 /* realize */ Realize,
145 /* actions */ actions,
146 /* num_actions */ XtNumber(actions),
147 /* resources */ resources,
148 /* num_resources */ XtNumber(resources),
149 /* xrm_class */ NULLQUARK,
150 /* compress_motion */ TRUE,
151 /* compress_exposure*/ TRUE,
152 /* compress_enterleave*/ TRUE,
153 /* visible_interest */ FALSE,
154 /* destroy */ Destroy,
155 /* resize */ Resize,
156 /* expose */ Redisplay,
157 /* set_values */ SetValues,
158 /* set_values_hook */ NULL,
159 /* set_values_almost*/ XtInheritSetValuesAlmost,
160 /* get_values_hook */ NULL,
161 /* accept_focus */ NULL,
162 /* version */ XtVersion,
163 /* callback_private */ NULL,
164 /* tm_table */ defaultTranslations,
165 /* query_geometry */ XtInheritQueryGeometry,
166 /* display_accelerator*/ XtInheritDisplayAccelerator,
167 /* extension */ NULL
168 },
169 { /* simple fields */
170 /* change_sensitive */ XtInheritChangeSensitive
171 },
172 { /* threeD fields */
173 /* shadowdraw */ XtInheritXaw3dShadowDraw
174 },
175 { /* scrollbar fields */
176 /* ignore */ 0 /*###jp### changed 21.10.94*/
177 }
178
179 };
180
181 WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec;
182
183 /*###############################################################################
184 PREPROCESSOR INSTRUCTIONS
185 ###############################################################################*/
186
187 #if defined(MIN)
188 # undef MIN
189 #endif
190 #if defined(MAX)
191 # undef MAX
192 #endif
193 #define MIN(_x_,_y_) ((_x_)<(_y_)?(_x_):(_y_))
194 #define MAX(_x_,_y_) ((_x_)>(_y_)?(_x_):(_y_))
195 #define PUT_IN_RANGE(min,num,max) MAX((min),MIN((num),(max)))
196
197 #define SCROLLBARWIDGET ScrollbarWidget sbw = (ScrollbarWidget)
198
199 #define IS_REALIZED (XtIsRealized((Widget)sbw)) /*###jp### changed 21.10.94*/
200 #define IS_HORIZONTAL (sbw->scrollbar.orientation == XtorientHorizontal)
201 #define IS_VERTICAL (sbw->scrollbar.orientation == XtorientVertical)
202 #define DISPLAY XtDisplay(sbw)
203 #define WINDOW XtWindow(sbw)
204
205 #define SBW sbw
206 /* public */
207 #define WIDTH sbw->core.width
208 #define HEIGHT sbw->core.height
209 #define BACKGROUND_PIXEL sbw->core.background_pixel
210 #define CURSOR_NAME sbw->simple.cursor_name
211 #define SHADOW sbw->threeD.shadow_width
212 #define BOT_SHADOW_GC sbw->threeD.bot_shadow_GC
213 #define TOP_SHADOW_GC sbw->threeD.top_shadow_GC
214
215 #define FOREGROUND sbw->scrollbar.foreground
216 #define MIN_THUMB sbw->scrollbar.min_thumb
217 #define SCROLLBAR_GC sbw->scrollbar.gc
218 #define THUMB sbw->scrollbar.thumb
219 #define LENGTH sbw->scrollbar.length
220 #define SHOWN sbw->scrollbar.shown
221 #define SHOWNLENGTH sbw->scrollbar.shownLength
222 #define TOP sbw->scrollbar.top
223 #define TOPLOC sbw->scrollbar.topLoc
224 #define THICKNESS sbw->scrollbar.thickness
225 #define THUMB_SIDE_INDENT sbw->scrollbar.thumb_side_indent
226 #define THUMB_TOP_INDENT sbw->scrollbar.thumb_top_indent
227 #define SHOW_ARROWS sbw->scrollbar.show_arrows
228 #define ARROW_TOP_INDENT sbw->scrollbar.arrow_top_indent
229 #define ARROW_SIDE_INDENT sbw->scrollbar.arrow_side_indent
230 #define INTERVAL sbw->scrollbar.interval
231 #define DELAY sbw->scrollbar.delay
232
233 /* private */
234 #define TIMER sbw->scrollbar.timer_id
235 #define DYNAMIC sbw->scrollbar.dynamic
236 #define SCROLLMODE sbw->scrollbar.scroll_mode
237 #define SHADOW_BASE sbw->scrollbar.shadow_base
238 #define ARROW_WIDTH sbw->scrollbar.arrow_width
239 #define ARROW_HEIGHT sbw->scrollbar.arrow_height
240 #define ARROW_TOP_TO_BORDER sbw->scrollbar.arrow_top_to_border
241 #define ARROW_TO_BORDER sbw->scrollbar.arrow_to_border
242 #define ARROW_SHADOW sbw->scrollbar.arrow_shadow
243 #define THUMB_SHADOW sbw->scrollbar.thumb_shadow
244 #define THUMB_TO_ARROW sbw->scrollbar.thumb_to_arrow
245 #define THUMB_TO_BORDER sbw->scrollbar.thumb_to_border
246 #define USE_DYNAMIC sbw->scrollbar.use_dynamic
247
248 #define USE_FILL Display *dpy = DISPLAY; Window wndw = WINDOW
249 #define FILL(point,count,gc) XFillPolygon(dpy,wndw,gc,point,count,Complex,CoordModeOrigin)
250 #define FILLrect(xc,yc,wid,hei,gc) XFillRectangle(dpy,wndw,gc,(int)(xc),(int)(yc),(unsigned int)(wid),(unsigned int)(hei))
251 #define DRAWline(xs,ys,xe,ye,gc) XDrawLine(dpy,wndw,gc,(int)(xs),(int)(ys),(int)(xe),(int)(ye))
252 #define DRAWlines(point,count,gc) XDrawLines(dpy,wndw,gc,point,count,CoordModeOrigin)
253 #define CLEAR(xc,yc,wid,hei) XClearArea(dpy,wndw,(int)(xc),(int)(yc),(unsigned int)(wid),(unsigned int)(hei),FALSE)
254
255 #define SET_TIMER(widget,interval) \
256 TIMER = XtAppAddTimeOut ( \
257 XtWidgetToApplicationContext(((Widget)(widget))), \
258 ((unsigned long)(interval)), \
259 RepeatNotify, \
260 ((XtPointer)((Widget)(widget))) \
261 )
262 #define DISABLED ((XtIntervalId) 0)
263 #define DESTROY_TIMER if (TIMER) { XtRemoveTimeOut(TIMER); TIMER = DISABLED; }
264
265 #define CALLscrollProc(widget,data) \
266 XtCallCallbacks ( ((Widget)(widget)),XtNscrollProc,((XtPointer)(intptr_t)(data)))
267
268 #define POINT(name,xcoord,ycoord) name.x=(short)(xcoord);name.y=(short)(ycoord)
269
270 /*### Definitions related to the Scrollbar Geometry ###########################*/
271
272 #define NICE_DIMENSION 5
273
274 #define _SCROLL_THICKNESS_ ((int)THICKNESS-2*THUMB_TO_BORDER)
275 #define _SCROLL_LENGTH_ ((int)LENGTH-2*(ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW)-1)
276
277 #define _RIGHT_END_OF_SCROLL_REGION_ ((int)THICKNESS-1-THUMB_TO_BORDER)
278 #define _LEFT_START_OF_SCROLL_REGION_ (THUMB_TO_BORDER)
279 #define _START_OF_SCROLL_REGION_ (ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW)
280 #define _END_OF_SCROLL_REGION_ ((int)LENGTH-1-ARROW_TOP_TO_BORDER-ARROW_HEIGHT-THUMB_TO_ARROW)
281
282 /*### Identificational Definitions ############################################*/
283
284 /* Scroll Mode */
285 #define NOSCROLL 0
286 #define CONTINUOUS 2
287 #define ARROW_UP 1
288 #define ARROW_DOWN 3
289 #define PAGE_UP 4
290 #define PAGE_DOWN 5
291
292 /* identifies upper/left, lower/right */
293 #define UPPER_PART 1
294 #define LOWER_PART 0
295
296 /* arrow identifier */
297 #define UPPER_ARROW 0
298 #define LOWER_ARROW 1
299 #define BOTH_ARROWS 2
300 #define NORMAL_ARROW 1
301 #define INVERTED_ARROW 0
302
303 #define _SC_INIT_VALUE_ 9999
304
305 /*### Options at Compiling Time ###############################################*/
306
307 #define MIN_INTERVAL 8
308 #define MAX_INTERVAL 800
309 #define DYNAMIC_REGION 40.0
310 #define MIN_DELAY 10 /* the minimum delay between clicking on an arrow and */
311 /* the start of the autoscroll action */
312
313 #define ARROW_SCROLL_AMOUNT (MAX(100,LENGTH)/20)
314 #define PAGE_SCROLL_AMOUNT LENGTH
315
316 /*###############################################################################
317 EraseThumbRegion
318 ###############################################################################*/
319
EraseThumbRegion(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr)320 static void EraseThumbRegion(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr)
321 {
322 USE_FILL;
323
324 BEGINMESSAGE(EraseThumbRegion)
325 if (IS_VERTICAL) { CLEAR(xl,yt,xr-xl+1,yb-yt+1); }
326 else { CLEAR(yt,xl,yb-yt+1,xr-xl+1); }
327 ENDMESSAGE(EraseThumbRegion)
328 }
329
330 /*###############################################################################
331 PaintThumbCover
332 ###############################################################################*/
333
PaintThumbCover(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr)334 static void PaintThumbCover(ScrollbarWidget SBW, Dimension yt, Dimension yb,Dimension xl,Dimension xr)
335 {
336 USE_FILL;
337
338 BEGINMESSAGE(PaintThumbCover)
339 if (IS_VERTICAL) FILLrect(xl,yt,xr+1-xl,yb-yt+1,SCROLLBAR_GC);
340 else FILLrect(yt,xl,yb-yt+1,xr+1-xl,SCROLLBAR_GC);
341 ENDMESSAGE(PaintThumbCover)
342 }
343
344 /*###############################################################################
345 PaintShadowAtSidesOfThumb
346 ###############################################################################*/
347
PaintShadowAtSidesOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s)348 static void PaintShadowAtSidesOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s)
349 {
350 USE_FILL;
351
352 BEGINMESSAGE(PaintShadowAtSidesOfThumb)
353 if (IS_VERTICAL) {
354 FILLrect(xl,yt,s+1,yb-yt+1,TOP_SHADOW_GC); FILLrect(xr+1-s,yt,s,yb-yt+1,BOT_SHADOW_GC);
355 } else {
356 FILLrect(yt,xl,yb-yt+1,s+1,TOP_SHADOW_GC); FILLrect(yt,xr+1-s,yb-yt+1,s,BOT_SHADOW_GC);
357 }
358 ENDMESSAGE(PaintShadowAtSidesOfThumb)
359 }
360
361 /*###############################################################################
362 PaintShadowAtEndOfThumb
363 ###############################################################################*/
364
PaintShadowAtEndOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s,int part)365 static void PaintShadowAtEndOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s, int part)
366 {
367 XPoint shadowPT[4];
368 USE_FILL;
369
370 BEGINMESSAGE(PaintShadowAtEndOfThumb)
371
372 if (IS_VERTICAL) {
373 if (part==UPPER_PART) {
374 POINT(shadowPT[3],xl,yt); POINT(shadowPT[2],xr+1,yt);
375 POINT(shadowPT[0],xl+s,yb); POINT(shadowPT[1],xr-s+1,yb);
376 } else {
377 POINT(shadowPT[3],xl+s,yt+1); POINT(shadowPT[2],xr-s+1,yt+1);
378 POINT(shadowPT[0],xl,yb+1); POINT(shadowPT[1],xr+1,yb+1);
379 }
380 } else {
381 if (part==UPPER_PART) {
382 POINT(shadowPT[0],yt,xl);
383 POINT(shadowPT[1],yb,xl+s);
384 POINT(shadowPT[2],yb,xr-s+1);
385 POINT(shadowPT[3],yt,xr+1);
386 } else {
387 POINT(shadowPT[0],yb+1,xl);
388 POINT(shadowPT[1],yt+1,xl+s);
389 POINT(shadowPT[2],yt+1,xr-s+1);
390 POINT(shadowPT[3],yb+1,xr+1);
391 }
392 }
393 if (part==UPPER_PART) { FILL(shadowPT,4,TOP_SHADOW_GC); }
394 else { FILL(shadowPT,4,BOT_SHADOW_GC); }
395
396 ENDMESSAGE(PaintShadowAtEndOfThumb)
397 }
398
399 /*###############################################################################
400 PaintWholeThumb
401 ###############################################################################*/
402
PaintWholeThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s)403 static void PaintWholeThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s)
404 {
405 BEGINMESSAGE(PaintWholeThumb)
406 if (s) {
407 PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
408 PaintShadowAtEndOfThumb(SBW,yt,yt+s,xl,xr,s,UPPER_PART);
409 PaintShadowAtEndOfThumb(SBW,yb-s,yb,xl,xr,s,LOWER_PART);
410 }
411 PaintThumbCover(SBW,yt+s,yb-s,xl+s,xr-s);
412 ENDMESSAGE(PaintWholeThumb)
413 }
414
415 /*###############################################################################
416 PaintMiddleOfThumb
417 ###############################################################################*/
418
PaintMiddleOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s)419 static void PaintMiddleOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s)
420 {
421 BEGINMESSAGE(PaintMiddleOfThumb)
422 if ((int)s) PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
423 PaintThumbCover(SBW,yt,yb,xl+s,xr-s);
424 ENDMESSAGE(PaintMiddleOfThumb)
425 }
426
427 /*###############################################################################
428 PaintEndOfThumb
429 ###############################################################################*/
430
PaintEndOfThumb(ScrollbarWidget SBW,Dimension yt,Dimension yb,Dimension xl,Dimension xr,Dimension s,int part)431 static void PaintEndOfThumb(ScrollbarWidget SBW, Dimension yt, Dimension yb, Dimension xl, Dimension xr, Dimension s, int part)
432 {
433 BEGINMESSAGE(PaintEndOfThumb)
434 if (part==UPPER_PART) {
435 if (s) {
436 PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
437 PaintShadowAtEndOfThumb(SBW,yt,yt+s,xl,xr,s,UPPER_PART);
438 }
439 PaintThumbCover(SBW,yt+s,yb,xl+s,xr-s);
440 } else {
441 if (s) {
442 PaintShadowAtSidesOfThumb(SBW,yt,yb,xl,xr,s);
443 PaintShadowAtEndOfThumb(SBW,yb-s,yb,xl,xr,s,LOWER_PART);
444 }
445 PaintThumbCover(SBW,yt,yb-s,xl+s,xr-s);
446 }
447 ENDMESSAGE(PaintEndOfThumb)
448 }
449
450 /*###############################################################################
451 GetRelativeThumbLocation
452 ###############################################################################*/
453
GetRelativeThumbLocation(ScrollbarWidget SBW,Dimension * newtop,Dimension * newbot)454 static void GetRelativeThumbLocation(ScrollbarWidget SBW, Dimension *newtop, Dimension *newbot)
455 {
456 Dimension scroll_length = (Dimension) _SCROLL_LENGTH_-MIN_THUMB;
457 Dimension end_of_scroll_region = (Dimension) _END_OF_SCROLL_REGION_;
458
459 BEGINMESSAGE(GetRelativeThumbLocation)
460 *newtop = (Dimension) (_START_OF_SCROLL_REGION_+scroll_length*TOP);
461 *newtop = MIN(*newtop,end_of_scroll_region);
462 *newbot = (Dimension)(*newtop+scroll_length*SHOWN);
463 *newbot = MAX(*newbot,(Dimension)(*newtop+MIN_THUMB));
464 *newbot = MIN(*newbot,end_of_scroll_region);
465 IIMESSAGE(*newtop,*newbot)
466 ENDMESSAGE(GetRelativeThumbLocation)
467 }
468
469 /*###############################################################################
470 AdjustThumbShadow
471 ###############################################################################*/
472
AdjustThumbShadow(ScrollbarWidget SBW,Dimension newtop,Dimension newbot)473 static Boolean AdjustThumbShadow(ScrollbarWidget SBW, Dimension newtop, Dimension newbot)
474 {
475 Dimension xl = (Dimension) _LEFT_START_OF_SCROLL_REGION_;
476 Dimension xr = (Dimension) _RIGHT_END_OF_SCROLL_REGION_;
477 int s;
478 Boolean changed = False;
479
480 BEGINMESSAGE(AdjustThumbShadow)
481 IIMESSAGE(newtop,newbot) IIMESSAGE(xl,xr) IMESSAGE(THUMB_SHADOW)
482 s = MIN((int)(newbot-newtop+1),(int)(xr-xl+1))/2;
483 s = MAX(0,s); s = MIN(s,(int)SHADOW);
484 if (s != THUMB_SHADOW) {
485 THUMB_SHADOW = s;
486 INFIMESSAGE(had to adjust thumb shadow:,THUMB_SHADOW)
487 changed = True;
488 } else {
489 INFMESSAGE(thumb shadow is just nice)
490 }
491 ENDMESSAGE(AdjustThumbShadow)
492 return changed;
493 }
494
495 /*###############################################################################
496 PaintThumb
497 ###############################################################################*/
498
PaintThumb(ScrollbarWidget SBW)499 static void PaintThumb(ScrollbarWidget SBW)
500 {
501 Dimension xl = (Dimension) _LEFT_START_OF_SCROLL_REGION_;
502 Dimension xr = (Dimension) _RIGHT_END_OF_SCROLL_REGION_;
503 Dimension oldtop, oldbot, newtop, newbot;
504
505 BEGINMESSAGE(PaintThumb)
506
507 if (!IS_REALIZED) { INFMESSAGE(not realized) ENDMESSAGE(PaintThumb) return; }
508 if ((LENGTH<1) || (THICKNESS<1)) { INFMESSAGE(not enough space) ENDMESSAGE(PaintThumb) return; }
509
510 GetRelativeThumbLocation(SBW,&newtop,&newbot);
511 oldtop = TOPLOC; oldbot = oldtop + SHOWNLENGTH-1;
512 IIMESSAGE(newtop,oldtop) IIMESSAGE(newbot,oldbot)
513 IIMESSAGE(xr,xl) IMESSAGE(THUMB_SHADOW)
514
515 if (AdjustThumbShadow(SBW,newtop,newbot)) {
516 INFMESSAGE(doing full repaint with adjusted thumb shadow)
517 if (oldbot>oldtop) EraseThumbRegion(SBW,oldtop,oldbot,xl,xr);
518 if (newbot>newtop) PaintWholeThumb(SBW,newtop,newbot,xl,xr,(Dimension)THUMB_SHADOW);
519 } else {
520 Dimension s = (Dimension) THUMB_SHADOW;
521 if ((newtop >= oldbot) || (newbot <= oldtop)) {
522 INFMESSAGE(doing full repaint)
523 if (oldbot>oldtop) EraseThumbRegion(SBW,oldtop,oldbot,xl,xr);
524 if (newbot>newtop) PaintWholeThumb(SBW,newtop,newbot,xl,xr,s);
525 } else {
526 INFMESSAGE(doing partial repaint)
527 if (newtop > oldtop) EraseThumbRegion(SBW,oldtop,newtop-1,xl,xr);
528 if (newbot < oldbot) EraseThumbRegion(SBW,newbot+1,oldbot,xl,xr);
529 if (newtop < oldtop) PaintMiddleOfThumb(SBW,newtop,MIN(newbot,oldtop+s),xl,xr,s);
530 if (newbot > oldbot) PaintMiddleOfThumb(SBW,MAX(newtop,oldbot-s),newbot,xl,xr,s);
531 if ((newtop!=oldtop)&&(s)) PaintShadowAtEndOfThumb(SBW,newtop,newtop+s,xl,xr,s,UPPER_PART);
532 if ((newbot!=oldbot)&&(s)) PaintShadowAtEndOfThumb(SBW,newbot-s,newbot,xl,xr,s,LOWER_PART);
533 }
534 }
535 TOPLOC = newtop;
536 SHOWNLENGTH = newbot-newtop+1;
537
538 ENDMESSAGE(PaintThumb)
539 }
540
541 /*###############################################################################
542 PaintArrows
543 ###############################################################################*/
544
545 #define vPOLY_4(name,x0,y0,x1,y1,x2,y2,x3,y3) \
546 name[0].x=(short)(x0);name[0].y=(short)(y0);\
547 name[1].x=(short)(x1);name[1].y=(short)(y1);\
548 name[2].x=(short)(x2);name[2].y=(short)(y2);\
549 name[3].x=(short)(x3);name[3].y=(short)(y3);\
550 name[4].x=(short)(x0);name[4].y=(short)(y0)
551
552 #define hPOLY_4(name,x0,y0,x1,y1,x2,y2,x3,y3) \
553 name[0].x=(short)(y0);name[0].y=(short)(x0);\
554 name[1].x=(short)(y1);name[1].y=(short)(x1);\
555 name[2].x=(short)(y2);name[2].y=(short)(x2);\
556 name[3].x=(short)(y3);name[3].y=(short)(x3);\
557 name[4].x=(short)(y0);name[4].y=(short)(x0)
558
559 #define COORD(name,value) short name = (short) (value)
560
PaintArrows(ScrollbarWidget SBW,int which,int mode)561 static void PaintArrows(ScrollbarWidget SBW, int which, int mode)
562 {
563 BEGINMESSAGE(PaintArrows)
564
565 if ((!IS_REALIZED) || ((ARROW_HEIGHT<1) || (ARROW_WIDTH<1)) || (!SHOW_ARROWS)) {
566 ENDMESSAGE(PaintArrows)
567 return;
568 }
569
570 { GC ts_gc = ((mode==NORMAL_ARROW) ? TOP_SHADOW_GC : BOT_SHADOW_GC);
571 GC bs_gc = ((mode==NORMAL_ARROW) ? BOT_SHADOW_GC : TOP_SHADOW_GC);
572 XPoint ls[5];
573 XPoint rs[5];
574 XPoint bs[5];
575 XPoint cover[5];
576 USE_FILL;
577 int ATB = ARROW_TO_BORDER;
578 int ATTB = ARROW_TOP_TO_BORDER;
579 int AH = ARROW_HEIGHT-1;
580 int AW = ARROW_WIDTH-1;
581 int AS = ARROW_SHADOW;
582 int D_AS = (int) (1.5*ARROW_SHADOW);
583
584 if (which==UPPER_ARROW || which==BOTH_ARROWS) {
585 if (IS_VERTICAL) {
586 COORD(y,ATTB);
587 COORD(yy,ATTB+2*AS);
588 COORD(yyy,ATTB+AH-AS);
589 COORD(yyyy,ATTB+AH);
590 COORD(lll,ATB); COORD(ll,ATB+D_AS); COORD(l,ATB+AW/2);
591 COORD(r,ATB+(AW+1)/2); COORD(rr,ATB+AW-D_AS); COORD(rrr,ATB+AW);
592 vPOLY_4(cover,r,yy,rr,yyy,ll,yyy,l,yy);
593 if (AS) {
594 vPOLY_4(ls,l,y,lll,yyyy,ll,yyy,l,yy);
595 vPOLY_4(rs,r,y,rrr,yyyy,rr,yyy,r,yy);
596 vPOLY_4(bs,lll,yyyy+1,rrr,yyyy+1,rrr-AS,yyyy+1-AS,lll+AS,yyyy+1-AS);
597 FILL(bs,5,bs_gc);
598 if (AS==1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
599 FILL(ls,5,ts_gc); DRAWlines(ls,5,ts_gc);
600 FILL(rs,5,bs_gc); DRAWlines(rs,5,bs_gc);
601 if (AS!=1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
602 } else {
603 FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);
604 }
605 } else {
606 COORD(x,ATTB);
607 COORD(xx,ATTB+2*AS);
608 COORD(xxx,ATTB+AH-AS);
609 COORD(xxxx,ATTB+AH);
610 COORD(l,ATB+(AW+1)/2); COORD(ll,ATB+AW-D_AS); COORD(lll,ATB+AW);
611 COORD(r,ATB+AW/2); COORD(rr,ATB+D_AS); COORD(rrr,ATB);
612 hPOLY_4(cover,ll,xxx,rr,xxx,r,xx,l,xx);
613 if (AS) {
614 hPOLY_4(ls,lll,xxxx,ll,xxx,l,xx,l,x);
615 hPOLY_4(rs,rrr,xxxx,rr,xxx,r,xx,r,x);
616 hPOLY_4(bs,lll,xxxx,rrr,xxxx,rr,xxx,ll,xxx);
617 FILL(bs,5,bs_gc); DRAWlines(bs,5,bs_gc);
618 FILL(ls,5,bs_gc); DRAWlines(ls,5,bs_gc);
619 FILL(rs,5,ts_gc); DRAWlines(rs,5,ts_gc);
620 FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);
621 } else {
622 FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);
623 }
624 }
625 }
626 if (which==LOWER_ARROW || which==BOTH_ARROWS) {
627 if (IS_VERTICAL) {
628 COORD(L,LENGTH-1);
629 COORD(y,L-ATTB);
630 COORD(yy,L-ATTB-2*AS);
631 COORD(yyy,L-ATTB-AH+AS);
632 COORD(yyyy,L-ATTB-AH);
633 COORD(lll,ATB); COORD(ll,ATB+D_AS); COORD(l,ATB+AW/2);
634 COORD(r,ATB+(AW+1)/2); COORD(rr,ATB+AW-D_AS); COORD(rrr,ATB+AW);
635 vPOLY_4(cover,ll,yyy,l,yy,r,yy,rr,yyy);
636 if (AS) {
637 vPOLY_4(ls,lll,yyyy,l,y,l,yy,ll,yyy);
638 vPOLY_4(rs,rrr,yyyy,r,y,r,yy,rr,yyy);
639 vPOLY_4(bs,rrr,yyyy,rr,yyy,ll,yyy,lll,yyyy);
640 FILL(bs,5,ts_gc); DRAWlines(bs,5,ts_gc);
641 FILL(ls,5,ts_gc); DRAWlines(ls,5,ts_gc);
642 if (AS==1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
643 FILL(rs,5,bs_gc); DRAWlines(rs,5,bs_gc);
644 if (AS!=1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
645 } else {
646 FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);
647 }
648 } else {
649 COORD(L,LENGTH-1);
650 COORD(x,L-ATTB);
651 COORD(xx,L-ATTB-2*AS);
652 COORD(xxx,L-ATTB-AH+AS);
653 COORD(xxxx,L-ATTB-AH);
654 COORD(lll,ATB); COORD(ll,ATB+D_AS); COORD(l,ATB+AW/2);
655 COORD(r,ATB+(AW+1)/2); COORD(rr,ATB+AW-D_AS); COORD(rrr,ATB+AW);
656 hPOLY_4(cover,ll,xxx,rr,xxx,r,xx,l,xx);
657 if (AS) {
658 hPOLY_4(ls,lll,xxxx,ll,xxx,l,xx,l,x);
659 hPOLY_4(rs,rrr,xxxx,rr,xxx,r,xx,r,x);
660 hPOLY_4(bs,lll,xxxx,rrr,xxxx,rr,xxx,ll,xxx);
661 FILL(bs,5,ts_gc); DRAWlines(bs,5,ts_gc);
662 if (AS==1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
663 FILL(ls,5,ts_gc); DRAWlines(ls,5,ts_gc);
664 FILL(rs,5,bs_gc); DRAWlines(rs,5,bs_gc);
665 if (AS!=1) { FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);}
666 } else {
667 FILL(cover,5,SCROLLBAR_GC); DRAWlines(cover,5,SCROLLBAR_GC);
668 }
669 }
670 }
671 }
672 ENDMESSAGE(PaintArrows)
673 }
674
675 /*###############################################################################
676 CreateGC
677 ###############################################################################*/
678
CreateGC(Widget w)679 static void CreateGC(Widget w)
680 {
681 SCROLLBARWIDGET w;
682 XGCValues gcValues;
683 XtGCMask mask;
684 unsigned int depth = 1;
685
686 BEGINMESSAGE(CreateGC)
687 if (THUMB == XtUnspecifiedPixmap) {
688 THUMB = XmuCreateStippledPixmap (XtScreen(w),
689 (Pixel) 1, (Pixel) 0, depth);
690 } else if (THUMB != None) {
691 Window root;
692 int x, y;
693 unsigned int width, height, bw;
694 if (XGetGeometry (XtDisplay(w), THUMB, &root, &x, &y,
695 &width, &height, &bw, &depth) == 0) {
696 XtAppError (XtWidgetToApplicationContext (w),
697 "Scrollbar Widget: Could not get geometry of thumb pixmap.");
698 }
699 }
700
701 gcValues.foreground = FOREGROUND;
702 gcValues.background = BACKGROUND_PIXEL;
703 mask = GCForeground | GCBackground;
704
705 if (THUMB != None) {
706 if (depth == 1) {
707 gcValues.fill_style = FillOpaqueStippled;
708 gcValues.stipple = SBW->scrollbar.thumb;
709 mask |= GCFillStyle | GCStipple;
710 }
711 else {
712 gcValues.fill_style = FillTiled;
713 gcValues.tile = SBW->scrollbar.thumb;
714 mask |= GCFillStyle | GCTile;
715 }
716 }
717 /* the creation should be non-caching, because */
718 /* we now set and clear clip masks on the gc returned */
719 SCROLLBAR_GC = XtGetGC(w, mask, &gcValues);
720
721 ENDMESSAGE(CreateGC)
722 }
723
724 /*###############################################################################
725 SetDimensions
726 ###############################################################################*/
727
SetDimensions(ScrollbarWidget SBW)728 static void SetDimensions(ScrollbarWidget SBW)
729 {
730 Dimension tmp;
731
732 BEGINMESSAGE(SetDimensions)
733
734 if (IS_VERTICAL) { LENGTH = HEIGHT; THICKNESS = WIDTH; }
735 else { LENGTH = WIDTH; THICKNESS = HEIGHT; }
736
737 IIMESSAGE(THICKNESS,LENGTH)
738
739 INFMESSAGE(### shadow width #############)
740 if (SHADOW_BASE == _SC_INIT_VALUE_) SHADOW_BASE = SHADOW;
741 SHADOW = SHADOW_BASE;
742 tmp = MIN(THICKNESS,LENGTH);
743 if (tmp<4*SHADOW) {
744 if (tmp>=4) SHADOW = tmp/4; else SHADOW = tmp/2;
745 INFMESSAGE(adjusted shadow)
746 }
747 IMESSAGE(SHADOW)
748
749 INFMESSAGE(### arrow geometry ###########)
750 if (SHOW_ARROWS) {
751 ARROW_TO_BORDER = (int) (SHADOW+ARROW_SIDE_INDENT);
752 ARROW_TOP_TO_BORDER = (int) (SHADOW+ARROW_TOP_INDENT);
753 ARROW_WIDTH = (int)THICKNESS-2*ARROW_TO_BORDER;
754 ARROW_HEIGHT = ((int)LENGTH-(int)MIN_THUMB)/2-(int)THUMB_TOP_INDENT-ARROW_TOP_TO_BORDER;
755
756 if ((ARROW_WIDTH < NICE_DIMENSION) && (ARROW_SIDE_INDENT)) {
757 while (ARROW_TO_BORDER>(int)SHADOW) {
758 --ARROW_TO_BORDER;
759 ARROW_WIDTH = ((int)THICKNESS-2*ARROW_TO_BORDER);
760 if (ARROW_WIDTH>=NICE_DIMENSION) break;
761 }
762 INFMESSAGE(adjusted arrow side indent)
763 }
764 if ((ARROW_HEIGHT<ARROW_WIDTH) && (ARROW_TOP_INDENT)) {
765 while (ARROW_TOP_TO_BORDER>(int)SHADOW) {
766 --ARROW_TOP_TO_BORDER;
767 ARROW_HEIGHT = ((int)LENGTH-(int)MIN_THUMB)/2-(int)THUMB_TOP_INDENT-ARROW_TOP_TO_BORDER;
768 if (ARROW_HEIGHT>=NICE_DIMENSION) break;
769 }
770 ARROW_HEIGHT = MAX(0,ARROW_HEIGHT);
771 INFMESSAGE(adjusted arrow top indent)
772 }
773 ARROW_WIDTH = MIN(ARROW_WIDTH,ARROW_HEIGHT);
774 if ((ARROW_WIDTH+(int)THICKNESS)&1) --ARROW_WIDTH;
775 ARROW_HEIGHT = ARROW_WIDTH; if (ARROW_HEIGHT) ARROW_HEIGHT -= (1-(ARROW_WIDTH&1));
776 ARROW_TO_BORDER = ((int)THICKNESS - ARROW_WIDTH)/2;
777 ARROW_SHADOW = (ARROW_WIDTH-1)/3; ARROW_SHADOW = PUT_IN_RANGE(0,ARROW_SHADOW,(int)SHADOW);
778 } else {
779 ARROW_TO_BORDER = ARROW_TOP_TO_BORDER = (int) SHADOW;
780 ARROW_WIDTH = ARROW_HEIGHT = 0;
781 }
782 IIMESSAGE(ARROW_WIDTH,ARROW_HEIGHT)
783 IIMESSAGE(ARROW_TO_BORDER,ARROW_TOP_TO_BORDER) IMESSAGE(ARROW_SHADOW)
784
785 INFMESSAGE(### thumb geometry ###########)
786 THUMB_SHADOW = (int) SHADOW;
787 THUMB_TO_BORDER = (int) (THUMB_SIDE_INDENT+SHADOW);
788 THUMB_TO_ARROW = (int) (THUMB_TOP_INDENT);
789
790 if ((int)THICKNESS-2*THUMB_TO_BORDER<NICE_DIMENSION) {
791 THUMB_TO_BORDER = ((int)THICKNESS-NICE_DIMENSION)/2;
792 THUMB_TO_BORDER = MAX(THUMB_TO_BORDER,(int)SHADOW);
793 INFMESSAGE(adjusted thumb side indent)
794 }
795 if (((int)LENGTH-2*(ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW)<(int)MIN_THUMB) && (THUMB_TO_ARROW)) {
796 THUMB_TO_ARROW = ((int)LENGTH-(int)MIN_THUMB)/2-ARROW_TOP_TO_BORDER-ARROW_HEIGHT;
797 THUMB_TO_ARROW = MAX(0,THUMB_TO_ARROW);
798 INFMESSAGE(adjusted minimal distance thumb to arrow)
799 }
800 IMESSAGE(MIN_THUMB) IIMESSAGE(THUMB_TO_BORDER,THUMB_TO_ARROW)
801
802 ENDMESSAGE(SetDimensions)
803 }
804
805 /*###############################################################################
806 ClassInitialize
807 ###############################################################################*/
808
ClassInitialize(void)809 static void ClassInitialize(void)
810 {
811 static Boolean initialized = FALSE;
812
813 BEGINMESSAGE(ClassInitialize)
814 if (initialized) {INFMESSAGE(class already initialized) return; }
815 XawInitializeWidgetSet();
816 XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
817 (XtConvertArgList)NULL, (Cardinal) 0);
818 initialized = TRUE;
819 ENDMESSAGE(ClassInitialize)
820 }
821
822 /*###############################################################################
823 Initialize
824 ###############################################################################*/
825
Initialize(Widget request _GL_UNUSED,Widget new,ArgList args _GL_UNUSED,Cardinal * num_args _GL_UNUSED)826 static void Initialize(Widget request _GL_UNUSED, Widget new, ArgList args _GL_UNUSED, Cardinal *num_args _GL_UNUSED)
827 /* request: what the client asked for */
828 /* new: what we're going to give him */
829 {
830 SCROLLBARWIDGET new;
831
832 BEGINMESSAGE(Initialize)
833 CreateGC(new);
834 if (WIDTH == 0) WIDTH = (IS_VERTICAL) ? THICKNESS : LENGTH;
835 if (HEIGHT == 0) HEIGHT = (IS_HORIZONTAL) ? THICKNESS : LENGTH;
836 SHADOW_BASE = _SC_INIT_VALUE_;
837 TOPLOC = 0;
838 SHOWNLENGTH = 1;
839 INTERVAL = MAX(INTERVAL,MIN_INTERVAL);
840 DELAY = MAX(DELAY,MIN_DELAY);
841 SCROLLMODE = NOSCROLL;
842 TIMER = DISABLED;
843 DYNAMIC = 0;
844 /*
845 how could we ever come away without the following line ...???
846 1/95 ###jp###
847 */
848 SetDimensions(SBW); /*#test#*/
849 ENDMESSAGE(Initialize)
850 }
851
852 /*###############################################################################
853 Realize
854 ###############################################################################*/
855
Realize(Widget w,Mask * valueMask,XSetWindowAttributes * attributes)856 static void Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
857 {
858 SCROLLBARWIDGET w;
859 BEGINMESSAGE(Realize)
860 if(CURSOR_NAME == NULL) XtVaSetValues(w, XtNcursorName, "top_left_arrow", NULL);
861 /* dont set the cursor of the window to anything */
862 *valueMask &= ~CWCursor;
863 /*
864 * The Simple widget actually stuffs the value in the valuemask.
865 */
866 (*scrollbarWidgetClass->core_class.superclass->core_class.realize) (w, valueMask, attributes);
867 ENDMESSAGE(Realize)
868 }
869
870 /*###############################################################################
871 SetValues
872 ###############################################################################*/
873
SetValues(Widget old,Widget request _GL_UNUSED,Widget new,ArgList args _GL_UNUSED,Cardinal * num_args _GL_UNUSED)874 static Boolean SetValues(Widget old, Widget request _GL_UNUSED, Widget new, ArgList args _GL_UNUSED, Cardinal *num_args _GL_UNUSED)
875 {
876 SCROLLBARWIDGET new;
877 ScrollbarWidget old_sbw = (ScrollbarWidget) old;
878 Boolean redraw = FALSE;
879
880 BEGINMESSAGE(SetValues)
881
882 if (SHOWN < 0.0 || SHOWN > 1.0 || TOP < 0.0 || TOP > 1.0) {
883 INFMESSAGE(### bad values for thumb position/length ###)
884 FMESSAGE(SHOWN) FMESSAGE(TOP)
885 SHOWN = old_sbw->scrollbar.shown; TOP = old_sbw->scrollbar.top;
886 SHOWN = PUT_IN_RANGE(0.0,SHOWN,1.0);
887 TOP = PUT_IN_RANGE(0.0,TOP, 1.0);
888 INFMESSAGE(corrected to)
889 FMESSAGE(SHOWN) FMESSAGE(TOP)
890 }
891 FMESSAGE(SHOWN) FMESSAGE(TOP)
892 if ((TOP != old_sbw->scrollbar.top) || (SHOWN != old_sbw->scrollbar.shown)) {
893 INFMESSAGE(thumb position/length has changed)
894 redraw = TRUE;
895 }
896
897 if (FOREGROUND != old_sbw->scrollbar.foreground ||
898 BACKGROUND_PIXEL != old_sbw->core.background_pixel ||
899 THUMB != old_sbw->scrollbar.thumb) {
900 INFMESSAGE(GC has changed)
901 XtReleaseGC((Widget)SBW, SCROLLBAR_GC); /*###jp### changed 21.10.94*/
902 CreateGC(new);
903 redraw = TRUE;
904 }
905
906 if ( (SHADOW != old_sbw->threeD.shadow_width) ||
907 (SHOW_ARROWS != old_sbw->scrollbar.show_arrows) ||
908 (ARROW_TOP_INDENT != old_sbw->scrollbar.arrow_top_indent) ||
909 (ARROW_SIDE_INDENT != old_sbw->scrollbar.arrow_side_indent) ||
910 (THUMB_SIDE_INDENT != old_sbw->scrollbar.thumb_side_indent) ||
911 (THUMB_TOP_INDENT != old_sbw->scrollbar.thumb_top_indent) ||
912 (MIN_THUMB != old_sbw->scrollbar.min_thumb) ) {
913 INFMESSAGE(internal scrollbar geometry has changed)
914 SHADOW_BASE=_SC_INIT_VALUE_;
915 SetDimensions(SBW);
916 redraw =TRUE;
917 }
918 INTERVAL = MAX(INTERVAL,MIN_INTERVAL);
919 DELAY = MAX(DELAY,MIN_DELAY);
920
921 if (!IS_REALIZED) { INFMESSAGE(not realized) redraw=FALSE; }
922
923 # ifdef MESSAGES
924 if (redraw) { INFMESSAGE(need redisplay) }
925 else { INFMESSAGE(redisplay unnecessary) }
926 # endif
927
928 ENDMESSAGE(SetValues)
929 return redraw;
930 }
931
932 /*###############################################################################
933 Resize
934 ###############################################################################*/
935
Resize(Widget w)936 static void Resize(Widget w)
937 {
938 SCROLLBARWIDGET w;
939 XEvent event;
940
941 BEGINMESSAGE(Resize)
942 SetDimensions(SBW);
943 event.xexpose.x = 0; event.xexpose.y = 0;
944 event.xexpose.width = WIDTH; event.xexpose.height = HEIGHT;
945 Redisplay(w, (XEvent *) &event, (Region)NULL);
946 ENDMESSAGE(Resize)
947 }
948
949 /*###############################################################################
950 Redisplay
951 compress_exposure is TRUE, so 'event' contains the bounding box for the
952 'region' to be exposed. Graphics actions will be restricted to this
953 bounding box to minimize visual disturbances.
954 ###############################################################################*/
955
Redisplay(Widget w,XEvent * event,Region region)956 static void Redisplay(Widget w, XEvent *event, Region region)
957 {
958 SCROLLBARWIDGET w;
959 ScrollbarWidgetClass swclass = (ScrollbarWidgetClass) XtClass (w);
960 Dimension s;
961 Dimension newtop, newbot;
962 Dimension xl = (Dimension) _LEFT_START_OF_SCROLL_REGION_;
963 Dimension xr = (Dimension) _RIGHT_END_OF_SCROLL_REGION_;
964 Dimension yt,yb;
965
966 BEGINMESSAGE(Redisplay)
967
968 if (!IS_REALIZED) { INFMESSAGE(not realized) ENDMESSAGE(Redisplay) return; }
969 if ((LENGTH<1) || (THICKNESS<1)) {
970 INFMESSAGE(not enough space) ENDMESSAGE(Redisplay) return;
971 }
972
973 if ((region) && (XRectInRegion(region,0,0,WIDTH,HEIGHT) == RectangleOut)) {
974 INFMESSAGE(request out of region) ENDMESSAGE(Redisplay)
975 return;
976 }
977
978 GetRelativeThumbLocation(SBW,&newtop,&newbot);
979 AdjustThumbShadow(SBW,newtop,newbot);
980 s = (Dimension)(THUMB_SHADOW);
981 if (event) {
982 if (IS_HORIZONTAL) { yt=(Dimension)(event->xexpose.x); yb=(Dimension)(yt+event->xexpose.width); }
983 else { yt=(Dimension)(event->xexpose.y); yb=(Dimension)(yt+event->xexpose.height); }
984 if (SHOW_ARROWS) {
985 Dimension soar = (Dimension) (ARROW_TOP_TO_BORDER);
986 Dimension sosr = (Dimension) _START_OF_SCROLL_REGION_;
987 Dimension eosr = (Dimension) (_END_OF_SCROLL_REGION_+THUMB_TO_ARROW);
988 Dimension eoar = (Dimension) (LENGTH-1-soar);
989 if ((yb>=soar) && (yt<sosr))
990 PaintArrows(SBW,UPPER_ARROW,(SCROLLMODE==ARROW_UP) ? INVERTED_ARROW : NORMAL_ARROW);
991 if ((yb>eosr) && (yt<=eoar))
992 PaintArrows(SBW,LOWER_ARROW,(SCROLLMODE==ARROW_DOWN) ? INVERTED_ARROW : NORMAL_ARROW);
993 }
994 if ((yb>=newtop) && (yt<=newbot)) {
995 if ((yt<=newtop+s) && (yb+s>=newbot)) PaintWholeThumb(SBW,newtop,newbot,xl,xr,s);
996 else if ((yt<=newtop+s) && (yb+s<newbot)) PaintEndOfThumb(SBW,newtop,yb,xl,xr,s,UPPER_PART);
997 else if ((yt>newtop+s) && (yb+s>=newbot)) PaintEndOfThumb(SBW,yt,newbot,xl,xr,s,LOWER_PART);
998 else if ((yt>newtop+s) && (yb+s<newbot)) PaintMiddleOfThumb(SBW,yt,yb,xl,xr,s);
999 }
1000 } else {
1001 /* should never come here */
1002 printf(" Scrollbarwidget: no event forced exit\n");
1003 clean_safe_tempdir();
1004 exit(0);
1005 }
1006 TOPLOC = newtop;
1007 SHOWNLENGTH = newbot-newtop+1;
1008
1009 (*swclass->threeD_class.shadowdraw) (w, event, region, sbw->threeD.relief, FALSE);
1010
1011 ENDMESSAGE(Redisplay)
1012 }
1013
1014 /*###############################################################################
1015 Destroy
1016 ###############################################################################*/
1017
Destroy(w)1018 static void Destroy (w)
1019 Widget w;
1020 {
1021 SCROLLBARWIDGET w;
1022 BEGINMESSAGE(Destroy)
1023 DESTROY_TIMER;
1024 XtReleaseGC (w, SCROLLBAR_GC);
1025 ENDMESSAGE(Destroy)
1026 }
1027
1028 /*###############################################################################
1029 CompareEvents
1030 ###############################################################################*/
1031
1032 #define CHECK(field) if (newEvent->field != oldEvent->field) return False;
1033
CompareEvents(XEvent * oldEvent,XEvent * newEvent)1034 static Boolean CompareEvents (XEvent *oldEvent, XEvent *newEvent)
1035 {
1036 INFMESSAGE(executing Procedure: CompareEvents)
1037 CHECK(xany.display);
1038 CHECK(xany.type);
1039 CHECK(xany.window);
1040
1041 switch (newEvent->type) {
1042 case MotionNotify:
1043 CHECK(xmotion.state);
1044 break;
1045 case ButtonPress:
1046 case ButtonRelease:
1047 CHECK(xbutton.state);
1048 CHECK(xbutton.button);
1049 break;
1050 case KeyPress:
1051 case KeyRelease:
1052 CHECK(xkey.state);
1053 CHECK(xkey.keycode);
1054 break;
1055 case EnterNotify:
1056 case LeaveNotify:
1057 CHECK(xcrossing.mode);
1058 CHECK(xcrossing.detail);
1059 CHECK(xcrossing.state);
1060 break;
1061 }
1062
1063 return True;
1064 }
1065
1066 /*###############################################################################
1067 PeekNotifyEvent
1068 ###############################################################################*/
1069
1070 struct EventData {
1071 XEvent *oldEvent;
1072 int count;
1073 };
1074
PeekNotifyEvent(Display * dpy,XEvent * event,char * args)1075 static Bool PeekNotifyEvent (Display *dpy, XEvent *event, char *args)
1076 {
1077 struct EventData *eventData = (struct EventData*)args;
1078 INFMESSAGE(executing Procedure: PeekNotifyEvent)
1079 return ((++eventData->count == QLength(dpy)) /* since PeekIf blocks */
1080 || CompareEvents(event, eventData->oldEvent));
1081 }
1082
1083 /*###############################################################################
1084 LookAhead
1085 ###############################################################################*/
1086
LookAhead(Widget w,XEvent * event)1087 static Boolean LookAhead (Widget w, XEvent *event)
1088 {
1089 XEvent newEvent;
1090 struct EventData eventData;
1091
1092 BEGINMESSAGE(LookAhead)
1093 if (QLength (XtDisplay (w)) == 0) {
1094 INFMESSAGE(aborting) ENDMESSAGE(LookAhead)
1095 return False;
1096 }
1097
1098 eventData.count = 0;
1099 eventData.oldEvent = event;
1100
1101 XPeekIfEvent (XtDisplay (w), &newEvent, PeekNotifyEvent, (char*)&eventData);
1102
1103 ENDMESSAGE(LookAhead)
1104 return CompareEvents (event, &newEvent);
1105 }
1106
1107 /*###############################################################################
1108 ExtractPosition
1109 ###############################################################################*/
1110
1111 #define GET_EVENT_POS(kind) *position = (is_vertical) ? event->kind.y : event->kind.x
1112
ExtractPosition(XEvent * event,Position * position,Boolean is_vertical)1113 static void ExtractPosition(XEvent *event, Position *position, Boolean is_vertical)
1114 {
1115 BEGINMESSAGE(ExtractPosition)
1116 switch( event->type ) {
1117 case MotionNotify:
1118 GET_EVENT_POS(xmotion); break;
1119 case ButtonPress:
1120 case ButtonRelease:
1121 GET_EVENT_POS(xbutton); break;
1122 case KeyPress:
1123 case KeyRelease:
1124 GET_EVENT_POS(xkey); break;
1125 case EnterNotify:
1126 case LeaveNotify:
1127 GET_EVENT_POS(xcrossing); break;
1128 default:
1129 *position = 0;
1130 }
1131 ENDMESSAGE(ExtractPosition)
1132 }
1133
1134 /*###############################################################################
1135 HandleThumb
1136 ###############################################################################*/
1137
HandleThumb(Widget w,XEvent * event,String * params,Cardinal * num_params)1138 static void HandleThumb (Widget w, XEvent *event, String *params, Cardinal *num_params)
1139 {
1140 SCROLLBARWIDGET w;
1141 Position position;
1142 Position teoar = (Position) ARROW_TOP_TO_BORDER+ARROW_HEIGHT-1;
1143 Position beoar = (Position) LENGTH-teoar+1;
1144
1145 BEGINMESSAGE(HandleThumb)
1146 if ((SCROLLMODE != NOSCROLL) && (SCROLLMODE != CONTINUOUS)) {
1147 INFMESSAGE(aborting due to wrong scrollmode) ENDMESSAGE(HandleThumb)
1148 return;
1149 }
1150
1151 ExtractPosition(event,&position,(IS_VERTICAL));
1152 if ( (SCROLLMODE==CONTINUOUS) ||
1153 ((position >= TOPLOC) && (position < TOPLOC + SHOWNLENGTH)
1154 && (position>teoar) && (position<beoar)) ) {
1155 XtCallActionProc(w, "MoveThumb", event, params, *num_params);
1156 XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
1157 }
1158 ENDMESSAGE(HandleThumb)
1159 }
1160
1161 /*###############################################################################
1162 HandleAutoscroll
1163 ###############################################################################*/
1164
HandleAutoscroll(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params)1165 static void HandleAutoscroll(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params)
1166 {
1167 SCROLLBARWIDGET w;
1168 static Position old_position;
1169 Position position;
1170 int diff;
1171 float rel_diff;
1172
1173 BEGINMESSAGE(HandleAutoscroll)
1174
1175 if ((SCROLLMODE != ARROW_UP) && (SCROLLMODE != ARROW_DOWN)) {
1176 INFMESSAGE(returning due to wrong scroll mode) ENDMESSAGE(HandleAutoscroll)
1177 return;
1178 }
1179 if (!USE_DYNAMIC) {
1180 DYNAMIC = INTERVAL;
1181 ENDMESSAGE(HandleAutoscroll)
1182 return;
1183 }
1184
1185 ExtractPosition(event,&position,(IS_VERTICAL));
1186 if (*num_params == _SC_INIT_VALUE_) {
1187 INFMESSAGE(... initializing)
1188 old_position = position;
1189 ENDMESSAGE(HandleAutoscroll)
1190 return;
1191 }
1192
1193 DYNAMIC = PUT_IN_RANGE(MIN_INTERVAL,DYNAMIC,MAX_INTERVAL); IMESSAGE(DYNAMIC)
1194 diff = (SCROLLMODE==ARROW_UP) ? ((int)position)-((int)old_position):((int)old_position)-((int)position);
1195 rel_diff = PUT_IN_RANGE(-1.0,((float)diff)/DYNAMIC_REGION,1.0);
1196 if (rel_diff>0) DYNAMIC = INTERVAL + (Dimension)((MAX_INTERVAL-(int)INTERVAL)*rel_diff);
1197 else DYNAMIC = INTERVAL + (Dimension)((MIN_INTERVAL-(int)INTERVAL)*(-rel_diff));
1198 IMESSAGE(DYNAMIC)
1199
1200 ENDMESSAGE(HandleAutoscroll)
1201 }
1202
1203 /*###############################################################################
1204 RepeatNotify
1205 ###############################################################################*/
1206
RepeatNotify(XtPointer client_data,XtIntervalId * idp _GL_UNUSED)1207 static void RepeatNotify (XtPointer client_data, XtIntervalId *idp _GL_UNUSED)
1208 {
1209 SCROLLBARWIDGET client_data;
1210 int call_data=0;
1211
1212 BEGINMESSAGE(RepeatNotify)
1213 if (SCROLLMODE == NOSCROLL || SCROLLMODE == CONTINUOUS) {
1214 DESTROY_TIMER;
1215 INFMESSAGE(aborting due to wrong scroll_mode) ENDMESSAGE(RepeatNotify)
1216 return;
1217 }
1218
1219 switch (SCROLLMODE) {
1220 case ARROW_UP:
1221 call_data = -ARROW_SCROLL_AMOUNT;
1222 break;
1223 case ARROW_DOWN:
1224 call_data = ARROW_SCROLL_AMOUNT;
1225 break;
1226 case PAGE_UP:
1227 call_data = -PAGE_SCROLL_AMOUNT;
1228 break;
1229 case PAGE_DOWN:
1230 call_data = PAGE_SCROLL_AMOUNT;
1231 break;
1232 }
1233
1234 CALLscrollProc(client_data,call_data);
1235 SET_TIMER( client_data, DYNAMIC);
1236
1237 ENDMESSAGE(RepeatNotify)
1238 }
1239
1240 /*###############################################################################
1241 NotifyScroll
1242 ###############################################################################*/
1243
1244
NotifyScroll(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1245 static void NotifyScroll(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1246 {
1247 SCROLLBARWIDGET w;
1248 Position tsoar = (Position) ARROW_TOP_TO_BORDER;
1249 Position teoar = (Position) ARROW_TOP_TO_BORDER+ARROW_HEIGHT-1;
1250 Position beoar = (Position) LENGTH-teoar+1;
1251 Position bsoar = (Position) LENGTH-tsoar-1;
1252 Position position;
1253 Cardinal init_num_params = _SC_INIT_VALUE_;
1254
1255 BEGINMESSAGE(NotifyScroll)
1256
1257 if (SCROLLMODE==CONTINUOUS) {
1258 INFMESSAGE(aborting since CONTINUOUS scroll in progress) ENDMESSAGE(NotifyScroll)
1259 return;
1260 }
1261
1262 ExtractPosition(event,&position,(IS_VERTICAL));
1263 if ((position>=tsoar) && (position <= teoar)) {
1264 if (SHOW_ARROWS) { INFMESSAGE(handle upper/left arrow)
1265 PaintArrows(SBW,UPPER_ARROW,INVERTED_ARROW);
1266 SCROLLMODE = ARROW_UP;
1267 CALLscrollProc(w,((int)-ARROW_SCROLL_AMOUNT));
1268 DYNAMIC = INTERVAL;
1269 HandleAutoscroll(w, event, NULL, &init_num_params);
1270 SET_TIMER(w,DELAY);
1271 }
1272 } else if ((position >= beoar) && (position<=bsoar)) {
1273 if (SHOW_ARROWS) { INFMESSAGE(handle lower/right arrow)
1274 PaintArrows(SBW,LOWER_ARROW,INVERTED_ARROW);
1275 SCROLLMODE = ARROW_DOWN;
1276 CALLscrollProc(w,((int)ARROW_SCROLL_AMOUNT));
1277 DYNAMIC = INTERVAL;
1278 HandleAutoscroll(w, event, NULL, &init_num_params);
1279 SET_TIMER(w,DELAY);
1280 }
1281 } else if ((position>teoar) &&(position < TOPLOC)) { INFMESSAGE(handle Zone above Thumb)
1282 SCROLLMODE = PAGE_UP;
1283 CALLscrollProc(w,((int)-PAGE_SCROLL_AMOUNT));
1284 DYNAMIC = INTERVAL;
1285 SET_TIMER(w,DELAY);
1286 } else if ((position<beoar)&&(position > TOPLOC + SHOWNLENGTH)) { INFMESSAGE(handle Zone below Thumb)
1287 SCROLLMODE = PAGE_DOWN;
1288 CALLscrollProc(w,((int)PAGE_SCROLL_AMOUNT));
1289 DYNAMIC = INTERVAL;
1290 SET_TIMER(w,DELAY);
1291 }
1292 ENDMESSAGE(NotifyScroll);
1293 }
1294
1295 /*###############################################################################
1296 EndScroll
1297 ###############################################################################*/
1298
1299 /* ARGSUSED */
EndScroll(Widget w,XEvent * event _GL_UNUSED,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1300 static void EndScroll(Widget w, XEvent *event _GL_UNUSED, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1301 {
1302 SCROLLBARWIDGET w;
1303
1304 BEGINMESSAGE(EndScroll)
1305 if (SHOW_ARROWS) {
1306 if (SCROLLMODE==ARROW_UP) PaintArrows(SBW,UPPER_ARROW,NORMAL_ARROW);
1307 if (SCROLLMODE==ARROW_DOWN) PaintArrows(SBW,LOWER_ARROW,NORMAL_ARROW);
1308 }
1309 SCROLLMODE=NOSCROLL;
1310 DESTROY_TIMER;
1311 ENDMESSAGE(EndScroll)
1312 }
1313
1314 /*###############################################################################
1315 MoveThumb
1316 ###############################################################################*/
1317
MoveThumb(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1318 static void MoveThumb(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1319 {
1320 SCROLLBARWIDGET w;
1321 Position position;
1322 static Position old_position;
1323 float losr = (float)(_SCROLL_LENGTH_-MIN_THUMB);
1324 Position tosr = (Position) ARROW_TOP_TO_BORDER+ARROW_HEIGHT+THUMB_TO_ARROW;
1325 Position bosr = (Position) LENGTH-1-tosr;
1326 BEGINMESSAGE(MoveThumb)
1327 if (LookAhead (w, event)) {
1328 INFMESSAGE(aborting due to LookAhead) ENDMESSAGE(MoveThumb)
1329 return;
1330 }
1331
1332 if (!event->xmotion.same_screen) {
1333 INFMESSAGE(aborting due to wrong screen) ENDMESSAGE(MoveThumb)
1334 return;
1335 }
1336
1337 ExtractPosition(event,&position,(IS_VERTICAL));
1338 position = PUT_IN_RANGE(tosr,position,bosr);
1339
1340 if (SCROLLMODE != CONTINUOUS) {
1341 if ((position < TOPLOC) || (position >= TOPLOC + SHOWNLENGTH)) {
1342 TOP = PUT_IN_RANGE(0.0,((float)(position-tosr))/losr, 1.0-SHOWN);
1343 }
1344 SCROLLMODE=CONTINUOUS;
1345 } else {
1346 TOP = PUT_IN_RANGE(0.0,TOP+((float)(position-old_position))/losr, 1.0-SHOWN);
1347 }
1348 old_position = position;
1349 PaintThumb(SBW);
1350 XFlush(XtDisplay (w));
1351 ENDMESSAGE(MoveThumb)
1352 }
1353
1354 /*###############################################################################
1355 NotifyThumb
1356 ###############################################################################*/
1357
NotifyThumb(Widget w,XEvent * event,String * params _GL_UNUSED,Cardinal * num_params _GL_UNUSED)1358 static void NotifyThumb(Widget w, XEvent *event, String *params _GL_UNUSED, Cardinal *num_params _GL_UNUSED)
1359 {
1360 register SCROLLBARWIDGET w;
1361
1362 BEGINMESSAGE(NotifyThumb)
1363 if (LookAhead (w, event)) {
1364 INFMESSAGE(returning due to LookAhead) ENDMESSAGE(NotifyThumb)
1365 return;
1366 }
1367 /*
1368 thumbProc is not pretty, but is necessary for backwards
1369 compatibility on those architectures for which it work{s,ed};
1370 the intent is to pass a (truncated) float by value.
1371 */
1372 XtCallCallbacks (w, XtNthumbProc, *(XtPointer*)&TOP);
1373 XtCallCallbacks (w, XtNjumpProc, (XtPointer)&TOP);
1374 ENDMESSAGE(NotifyThumb)
1375 }
1376
1377 /********************************************************************************
1378 *
1379 * Public routines.
1380 *
1381 *******************************************************************************/
1382
1383 /*###############################################################################
1384 XawScrollbarSetThumb
1385 Set the scroll bar to the given location.
1386 ###############################################################################*/
1387
XawScrollbarSetThumb(Widget w,double top,double shown)1388 void XawScrollbarSetThumb (Widget w,
1389 #if NeedWidePrototypes
1390 double top, double shown
1391 #else
1392 float top, float shown
1393 #endif
1394 )
1395 {
1396 SCROLLBARWIDGET w;
1397
1398 BEGINMESSAGE(XawScrollbarSetThumb)
1399
1400 if (SCROLLMODE == CONTINUOUS) {
1401 INFMESSAGE(aborting since CONTINUOUS scroll in progress) ENDMESSAGE(XawScrollbarSetThumb)
1402 return;
1403 }
1404
1405 SHOWN = PUT_IN_RANGE(0.0,shown,1.0); FMESSAGE(SHOWN)
1406 TOP = PUT_IN_RANGE(0.0,top, 1.0); FMESSAGE(TOP)
1407 PaintThumb(SBW);
1408
1409 ENDMESSAGE(XawScrollbarSetThumb)
1410 }
1411
1412