|
|
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.