|
|
1.1 root 1: #ifndef lint
2: static char rcsid[] = "$Header: Scroll.c,v 1.7 87/09/14 00:43:28 swick Exp $";
3: #endif lint
4:
5: /*
6: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
7: *
8: * All Rights Reserved
9: *
10: * Permission to use, copy, modify, and distribute this software and its
11: * documentation for any purpose and without fee is hereby granted,
12: * provided that the above copyright notice appear in all copies and that
13: * both that copyright notice and this permission notice appear in
14: * supporting documentation, and that the name of Digital Equipment
15: * Corporation not be used in advertising or publicity pertaining to
16: * distribution of the software without specific, written prior permission.
17: *
18: *
19: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25: * SOFTWARE.
26: */
27: /* ScrollBar.c */
28: /* created by weissman, Mon Jul 7 13:20:03 1986 */
29: /* converted by swick, Thu Aug 27 1987 */
30:
31: #include "Xlib.h"
32: #include "Xresource.h"
33: /*#include "Conversion.h"*/
34: #include "Intrinsic.h"
35: #include "Scroll.h"
36: #include "ScrollP.h"
37: #include "Atoms.h"
38: #include "cursorfont.h"
39:
40: /* Private definitions. */
41:
42: static char *defaultTranslationTable[] = {
43: "<Btn1Down>: StartPageBack\n", /* should be generic... */
44: "<Btn2Down>: StartScroll\n",
45: "<Btn3Down>: StartPageForward\n", /* ...but needs TM args */
46: "<Btn1Up>: DoPageBack\n",
47: "<Btn2Up>: DoScroll\n",
48: "<Btn3Up>: DoPageForward\n",
49: "<Motion>2: MoveThumb\n", /* bug? in TM forces button spec here */
50: NULL
51: };
52:
53: /* grodyness needed because Xrm wants pointer to thing, not thing... */
54: static caddr_t defaultTranslations = (caddr_t)defaultTranslationTable;
55:
56: static XtResource resources[] = {
57: {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
58: XtOffset(ScrollbarWidget, scrollbar.orientation), XtRString, "vertical"},
59: {XtNscrollProc, XtCScrollProc, XtRFunction, sizeof(XtCallbackProc),
60: XtOffset(ScrollbarWidget, scrollbar.scrollProc), XtRFunction, NULL},
61: {XtNthumbProc, XtCScrollProc, XtRFunction, sizeof(XtCallbackProc),
62: XtOffset(ScrollbarWidget, scrollbar.thumbProc), XtRFunction, NULL},
63: {XtNparameter, XtCParameter, XtRPointer, sizeof(caddr_t),
64: XtOffset(ScrollbarWidget, scrollbar.closure), XtRPointer, NULL},
65: {XtNthumb, XtCThumb, XtRPixmap, sizeof(Pixmap),
66: XtOffset(ScrollbarWidget, scrollbar.thumb), XtRPixmap, NULL},
67: {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
68: XtOffset(ScrollbarWidget, scrollbar.foreground), XtRString, "black"},
69: {XtNscrollVCursor, XtCScrollVCursor, XtRCursor, sizeof(Cursor),
70: XtOffset(ScrollbarWidget, scrollbar.verCursor), XtRString, "sb_v_double_arrow"},
71: {XtNscrollHCursor, XtCScrollHCursor, XtRCursor, sizeof(Cursor),
72: XtOffset(ScrollbarWidget, scrollbar.horCursor), XtRString, "sb_h_double_arrow"},
73: {XtNscrollUCursor, XtCScrollUCursor, XtRCursor, sizeof(Cursor),
74: XtOffset(ScrollbarWidget, scrollbar.upCursor), XtRString, "sb_up_arrow"},
75: {XtNscrollDCursor, XtCScrollDCursor, XtRCursor, sizeof(Cursor),
76: XtOffset(ScrollbarWidget, scrollbar.downCursor), XtRString, "sb_down_arrow"},
77: {XtNscrollLCursor, XtCScrollLCursor, XtRCursor, sizeof(Cursor),
78: XtOffset(ScrollbarWidget, scrollbar.leftCursor), XtRString, "sb_left_arrow"},
79: {XtNscrollRCursor, XtCScrollRCursor, XtRCursor, sizeof(Cursor),
80: XtOffset(ScrollbarWidget, scrollbar.rightCursor), XtRString, "sb_right_arrow"},
81: {XtNeventBindings, XtCEventBindings, XtRStringTable, sizeof(_XtTranslations),
82: XtOffset(ScrollbarWidget, core.translations), XtRStringTable, (caddr_t)&defaultTranslations},
83: };
84:
85: static void ClassInitialize();
86: static void Initialize();
87: static void Realize();
88: static void Resize();
89: static void Redisplay();
90: static Boolean SetValues();
91:
92: static void StartPageBack();
93: static void StartSmoothScroll();
94: static void StartPageForward();
95: static void DoPageBack();
96: static void DoSmoothScroll();
97: static void DoPageForward();
98: static void MoveThumb();
99:
100: static XtActionsRec actions[] = {
101: {"StartPageBack", (caddr_t)StartPageBack},
102: {"StartScroll", (caddr_t)StartSmoothScroll},
103: {"StartPageForward", (caddr_t)StartPageForward},
104: {"DoPageBack", (caddr_t)DoPageBack},
105: {"DoScroll", (caddr_t)DoSmoothScroll},
106: {"DoPageForward", (caddr_t)DoPageForward},
107: {"MoveThumb", (caddr_t)MoveThumb},
108: {NULL,NULL}
109: };
110:
111:
112: static ScrollbarClassRec scrollbarClassRec = {
113: /* core fields */
114: /* superclass */ (WidgetClass) &widgetClassRec,
115: /* class_name */ "Scroll",
116: /* size */ sizeof(ScrollbarRec),
117: /* class_initialize */ ClassInitialize,
118: /* class_inited */ FALSE,
119: /* initialize */ Initialize,
120: /* realize */ Realize,
121: /* actions */ actions,
122: /* num_actions */ XtNumber(actions),
123: /* resources */ resources,
124: /* num_resources */ XtNumber(resources),
125: /* xrm_class */ NULLQUARK,
126: /* compress_motion */ FALSE,
127: /* compress_exposure*/ TRUE,
128: /* visible_interest */ FALSE,
129: /* destroy */ NULL,
130: /* resize */ Resize,
131: /* expose */ Redisplay,
132: /* set_values */ SetValues,
133: /* accept_focus */ NULL,
134: };
135:
136: WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec;
137:
138: #define MINBARHEIGHT 7 /* How many pixels of scrollbar to always show */
139: #define NoButton -1
140: #define PICKLENGTH(widget, x, y) \
141: ((widget->scrollbar.orientation == XtorientHorizontal) ? x : y)
142: #define PICKTHICKNESS(widget, x, y) \
143: ((widget->scrollbar.orientation == XtorientHorizontal) ? y : x)
144: #define MIN(x,y) ((x) < (y) ? (x) : (y))
145: #define MAX(x,y) ((x) > (y) ? (x) : (y))
146:
147:
148: /* Orientation enumeration constants */
149:
150: static XrmQuark XtQEhorizontal;
151: static XrmQuark XtQEvertical;
152:
153: /*ARGSUSED*/
154: #define done(address, type) \
155: { (*toVal).size = sizeof(type); (*toVal).addr = (caddr_t) address; }
156:
157: extern void _XLowerCase();
158:
159: static void CvtStringToOrientation(dpy, fromVal, toVal)
160: Display *dpy;
161: XrmValue fromVal;
162: XrmValue *toVal;
163: {
164: static XtOrientation orient;
165: XrmQuark q;
166: char lowerName[1000];
167:
168: /* ||| where to put LowerCase */
169: _XLowerCase((char *) fromVal.addr, lowerName);
170: q = XrmAtomToQuark(lowerName);
171: if (q == XtQEhorizontal) {
172: orient = XtorientHorizontal;
173: done(&orient, XtOrientation);
174: return;
175: }
176: if (q == XtQEvertical) {
177: orient = XtorientVertical;
178: done(&orient, XtOrientation);
179: return;
180: }
181: };
182:
183:
184: static void ClassInitialize()
185: {
186: XtQEhorizontal = XrmAtomToQuark(XtEhorizontal);
187: XtQEvertical = XrmAtomToQuark(XtEvertical);
188: XrmRegisterTypeConverter(XrmRString, XtROrientation, CvtStringToOrientation);
189: }
190:
191:
192:
193: /*
194: * Make sure the first number is within the range specified by the other
195: * two numbers.
196: */
197:
198: static int InRange(num, small, big)
199: int num, small, big;
200: {
201: return (num < small) ? small : ((num > big) ? big : num);
202: }
203:
204: /*
205: * Same as above, but for floating numbers.
206: */
207:
208: static float FloatInRange(num, small, big)
209: float num, small, big;
210: {
211: return (num < small) ? small : ((num > big) ? big : num);
212: }
213:
214:
215: /* Fill the area specified by top and bottom with the given pattern. */
216: static float FractionLoc(w, x, y)
217: ScrollbarWidget w;
218: int x, y;
219: {
220: float result;
221:
222: result = PICKLENGTH(w, (float) x/w->core.width,
223: (float) y/w->core.height);
224: return FloatInRange(result, 0.0, 1.0);
225: }
226:
227:
228: static FillArea(w, top, bottom, thumb)
229: ScrollbarWidget w;
230: Position top, bottom;
231: int thumb;
232: {
233: Dimension length = bottom-top;
234:
235: switch(thumb) {
236: /* Fill the new Thumb location */
237: case 1:
238: if (w->scrollbar.orientation == XtorientHorizontal)
239: XFillRectangle(XtDisplay(w), XtWindow(w),
240: w->scrollbar.gc, top, 1, length,
241: w->core.height-2);
242:
243: else XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
244: 1, top, w->core.width-2, length);
245:
246: break;
247: /* Clear the old Thumb location */
248: case 0:
249: if (w->scrollbar.orientation == XtorientHorizontal)
250: XClearArea(XtDisplay(w), XtWindow(w), top, 1,
251: length, w->core.height-2, FALSE);
252:
253: else XClearArea(XtDisplay(w), XtWindow(w), 1,
254: top, w->core.width-2, length, FALSE);
255:
256: }
257: }
258:
259:
260: /* Paint the thumb in the area specified by w->top and
261: w->shown. The old area is erased. The painting and
262: erasing is done cleverly so that no flickering will occur. */
263:
264: static void PaintThumb( w )
265: ScrollbarWidget w;
266: {
267: int length, oldtop, oldbot, newtop, newbot;
268: length = PICKLENGTH(w, w->core.width, w->core.height);
269: oldtop = w->scrollbar.topLoc;
270: oldbot = oldtop + w->scrollbar.shownLength;
271: newtop = length * w->scrollbar.top;
272: newbot = newtop + length * (w->scrollbar.shown);
273: if (newbot < newtop + MINBARHEIGHT) newbot = newtop + MINBARHEIGHT;
274: if (newtop < oldtop)
275: FillArea(w, newtop, MIN(newbot, oldtop), 1);
276: if (newtop > oldtop)
277: FillArea(w, oldtop, MIN(newtop, oldbot), 0);
278: if (newbot < oldbot)
279: FillArea(w, MAX(newbot, oldtop), oldbot, 0);
280: if (newbot > oldbot)
281: FillArea(w, MAX(newtop, oldbot), newbot, 1);
282: w->scrollbar.topLoc = newtop;
283: w->scrollbar.shownLength = newbot - newtop;
284: }
285:
286:
287: static void Initialize( request, new )
288: Widget request; /* what the client asked for */
289: Widget new; /* what we're going to give him */
290: {
291: ScrollbarWidget w = (ScrollbarWidget) new;
292: XGCValues gcValues;
293:
294: if (w->scrollbar.thumb == NULL) {
295: w->scrollbar.thumb = XtGrayPixmap( XtScreen(w) );
296: }
297:
298: gcValues.fill_style = FillTiled;
299: gcValues.tile = w->scrollbar.thumb;
300: w->scrollbar.gc = XtGetGC( w, GCFillStyle | GCTile, &gcValues);
301:
302: if (w->core.width == 0) w->core.width = 1;
303: if (w->core.height == 0) w->core.height = 1;
304:
305: }
306:
307: static void Realize( gw, valueMask, attributes )
308: Widget gw;
309: Mask valueMask;
310: XSetWindowAttributes *attributes;
311: {
312: ScrollbarWidget w = (ScrollbarWidget) gw;
313: XSetWindowAttributes winAttr;
314: Mask attrMask;
315:
316: w->scrollbar.inactiveCursor =
317: (w->scrollbar.orientation == XtorientVertical)
318: ? w->scrollbar.verCursor
319: : w->scrollbar.horCursor;
320:
321: winAttr = *attributes;
322: winAttr.cursor = w->scrollbar.inactiveCursor;
323: attrMask = valueMask | CWCursor;
324:
325: w->core.window =
326: XCreateWindow(
327: XtDisplay( w ), XtWindow(w->core.parent),
328: w->core.x, w->core.y,
329: w->core.width, w->core.height,
330: w->core.border_width, w->core.depth,
331: InputOutput, (Visual *)CopyFromParent,
332: attrMask, &winAttr );
333: }
334:
335:
336: static Boolean SetValues( current, request, desired )
337: Widget current, /* what I am */
338: request, /* what he wants me to be */
339: desired; /* what I will become */
340: {
341: ScrollbarWidget w = (ScrollbarWidget) current;
342: ScrollbarWidget rw = (ScrollbarWidget) request;
343: ScrollbarWidget dw = (ScrollbarWidget) desired;
344: short thumbmoved, redraw;
345:
346: thumbmoved = redraw = FALSE;
347:
348: /* Core make take care of the following... we'll have to see */
349: if (w->core.border_pixel != dw->core.border_pixel) {
350: if (w->core.border_width != 0)
351: XSetWindowBorder( XtDisplay(w), XtWindow(w), w->core.border_pixel );
352: }
353:
354: if (w->scrollbar.foreground != rw->scrollbar.foreground ||
355: w->core.background_pixel != rw->core.background_pixel)
356: redraw = TRUE;
357:
358: if (w->scrollbar.top != dw->scrollbar.top ||
359: w->scrollbar.shown != dw->scrollbar.shown)
360: thumbmoved = TRUE;
361:
362: if (redraw)
363: w->scrollbar.topLoc = -1000;
364:
365: return( redraw || thumbmoved );
366: }
367:
368: /* ARGSUSED */
369: static void Resize( gw, geometry )
370: Widget gw;
371: XtWidgetGeometry geometry;
372: {
373: ScrollbarWidget w = (ScrollbarWidget) gw;
374:
375: FillArea( w, w->scrollbar.topLoc,
376: w->scrollbar.topLoc + w->scrollbar.shownLength, 0 );
377:
378: w->scrollbar.topLoc = -1000; /* Forces entire thumb to be painted. */
379: PaintThumb( w );
380:
381: }
382:
383:
384: /* ARGSUSED */
385: static void Redisplay( gw, event )
386: Widget gw;
387: XEvent *event;
388: {
389: ScrollbarWidget w = (ScrollbarWidget) gw;
390:
391: w->scrollbar.topLoc = -1000; /* Forces entire thumb to be painted. */
392: PaintThumb( w );
393: }
394:
395:
396: static void StartScroll(gw, event, direction)
397: Widget gw;
398: XEvent *event;
399: char direction; /* Back|Forward|Smooth */
400: {
401: ScrollbarWidget w = (ScrollbarWidget) gw;
402: Cursor cursor;
403:
404: if (w->scrollbar.direction != 0) return;
405: w->scrollbar.direction = direction;
406:
407: switch( direction ) {
408: case 'B':
409: case 'b': cursor = (w->scrollbar.orientation == XtorientVertical)
410: ? w->scrollbar.upCursor
411: : w->scrollbar.leftCursor; break;
412:
413: case 'F':
414: case 'f': cursor = (w->scrollbar.orientation == XtorientVertical)
415: ? w->scrollbar.downCursor
416: : w->scrollbar.rightCursor; break;
417:
418: case 'S':
419: case 's': cursor = (w->scrollbar.orientation == XtorientVertical)
420: ? w->scrollbar.rightCursor
421: : w->scrollbar.upCursor; break;
422:
423: default: return; /* invalid invocation */
424: }
425:
426: XDefineCursor(XtDisplay(w), XtWindow(w), cursor);
427:
428: XFlush(XtDisplay(w));
429:
430: if (direction == 'S' || direction == 's') MoveThumb(gw, event);
431:
432: }
433:
434:
435: /* The following are only needed until the TM implements args */
436:
437: static void StartPageBack( gw, event )
438: Widget gw;
439: XEvent *event;
440: {
441: StartScroll( gw, event, 'B' );
442: };
443:
444: static void StartPageForward( gw, event )
445: Widget gw;
446: XEvent *event;
447: {
448: StartScroll( gw, event, 'F' );
449: };
450:
451: static void StartSmoothScroll( gw, event )
452: Widget gw;
453: XEvent *event;
454: {
455: StartScroll( gw, event, 'S' );
456: };
457:
458:
459: static void DoScroll( gw, event, direction )
460: Widget gw;
461: XEvent *event;
462: char direction;
463: {
464: ScrollbarWidget w = (ScrollbarWidget) gw;
465:
466: if (w->scrollbar.direction == 0) return;
467:
468: XDefineCursor(XtDisplay(w), XtWindow(w), w->scrollbar.inactiveCursor);
469: XFlush(XtDisplay(w));
470:
471: switch( direction ) {
472: case 'B':
473: case 'b':
474: case 'F':
475: case 'f': if (w->scrollbar.scrollProc)
476: (*(w->scrollbar.scrollProc))
477: ( w, w->scrollbar.closure,
478: InRange( PICKLENGTH( w,
479: event->xmotion.x,
480: event->xmotion.y),
481: 0,
482: (int)PICKLENGTH( w,
483: w->core.width,
484: w->core.height)));
485: break;
486:
487: case 'S':
488: case 's': /* MoveThumb has already called the thumbProc(s) */
489: break;
490: }
491:
492: w->scrollbar.direction = 0;
493:
494: }
495:
496: /* The following are only needed until the TM implements args */
497:
498: static void DoPageBack( gw, event )
499: Widget gw;
500: XEvent *event;
501: {
502: DoScroll( gw, event, 'B' );
503: }
504:
505: static void DoPageForward( gw, event )
506: Widget gw;
507: XEvent *event;
508: {
509: DoScroll( gw, event, 'F' );
510: };
511:
512: static void DoSmoothScroll( gw, event )
513: Widget gw;
514: XEvent *event;
515: {
516: DoScroll( gw, event, 'S' );
517: };
518:
519:
520:
521: static void MoveThumb( gw, event )
522: Widget gw;
523: XEvent *event;
524: {
525: ScrollbarWidget w = (ScrollbarWidget) gw;
526:
527: if (w->scrollbar.direction == 0) return;
528:
529: w->scrollbar.top = FractionLoc(w, event->xmotion.x, event->xmotion.y);
530: PaintThumb(w);
531:
532: /* XFlush(XtDisplay(w)); */
533:
534: if (w->scrollbar.thumbProc)
535: (*(w->scrollbar.thumbProc)) (w, w->scrollbar.closure, w->scrollbar.top);
536:
537: w->scrollbar.direction = 'S';
538: }
539:
540:
541:
542: /* Public routines. */
543:
544: /* Set the scroll bar to the given location. */
545: extern void XtScrollBarSetThumb( w, top, shown )
546: ScrollbarWidget w;
547: float top, shown;
548: {
549: w->scrollbar.top = top;
550: w->scrollbar.shown = shown;
551: PaintThumb( w );
552: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.