home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / comm / revrdist.sit / RevRdist / RevRdist src / TransDisplay.c < prev    next >
Encoding:
Text File  |  1990-07-30  |  26.1 KB  |  1,188 lines  |  [TEXT/KAHL]

  1. /*
  2.     TransDisplay version 2.0 - TransSkel plug-in module supporting
  3.     an arbitrary number of generic display windows with memory.
  4.  
  5.     TransSkel and TransDisplay are public domain, and are written by:
  6.  
  7.             Paul DuBois
  8.             Wisconsin Regional Primate Research Center
  9.             1220 Capitol Court
  10.             Madison, WI  53715-1299  USA
  11.  
  12.     UUCP:    {harvard,rutgers,ucbvax}!uwvax!rhesus!dubois
  13.     ARPA:    dubois@primate.wisc.edu
  14.  
  15.     This version of TransDisplay written for LightspeedC.  LightspeedC
  16.     is a trademark of:
  17.             THINK Technologies, Inc
  18.             420 Bedford Street  Suite 350
  19.             Lexington, MA  02173  USA
  20.  
  21.   History
  22.   08/25/86    Genesis.  Beta version.
  23.   09/15/86    Changed to allow arbitrary number of windows.  Changed
  24.             version number to 1.0.
  25.   01/17/87    Changed version number to 1.01.  The window type when a new
  26.             window is created with NewDWindow is documentProc+8 now, so
  27.             that the window will have a zoom box on a machine with 128K
  28.             ROMS.
  29.   01/29/89    Version 2.0.  Converted to work with TransSkel 2.0.  Display
  30.             window creation routines now check whether window and window
  31.             handler creation succeeded and return nil if not.  2-byte and
  32.             4-byte integer types are typedef'ed to Integer and Longint to
  33.             ease porting.
  34. */
  35.  
  36.  
  37. /*
  38.     The following symbol controls the compile mode.  If it is #define'd,
  39.     TransDisplay allows only a single display window, and generates
  40.     less code.  If it is #undef'ed, TransDisplay allows an arbitrary
  41.     number of display windows, but generates more code.
  42. */
  43.  
  44. # undef    singleDisplay
  45.  
  46. # include    <ControlMgr.h>    /* includes WindowMgr.h, QuickDraw.h, MacTypes.h */
  47. # include    <TextEdit.h>
  48. # include    "TransDisplay.h"
  49.  
  50. #include <TransSkelProto.h>
  51. #include <TransDisplayProto.h>
  52.  
  53.  
  54. /*
  55.     Display window types, constants, variables.
  56. */
  57.  
  58.  
  59. # define    monaco        4
  60.  
  61.  
  62. /*
  63.     Default values for display window characteristics
  64. */
  65.  
  66. static Integer    d_font = monaco;        /* default font              */
  67. static Integer    d_size = 9;                /* default pointsize         */
  68. static Integer    d_wrap = 0;                /* default word wrap (on)    */
  69. static Integer    d_just = teJustLeft;    /* default justification     */
  70. static Longint    d_maxText = 30000L;        /* default max text allowed  */
  71. static Longint    d_flushAmt = 25000L;    /* default autoflush amount  */
  72. static vProcPtr    d_activate = nil;        /* default notification proc */
  73.  
  74.  
  75. /*
  76.     Lowest allowable values for autoflush characteristics
  77. */
  78.  
  79. # define    d_loMaxText        (100L)
  80. # define    d_loFlushAmt    (100L)
  81.  
  82.  
  83. # ifndef    singleDisplay
  84.  
  85. /*
  86.     New(TypeName) returns handle to new object, for any TypeName.
  87.     If there is insufficient memory, the result is nil.
  88. */
  89.  
  90. # define    New(x)    (x **) NewHandle ((Size) sizeof (x))
  91.  
  92.  
  93. /*
  94.     dwList points to a list of structures describing the known display
  95.     windows.
  96.  
  97.     curDispWind is the current output window.
  98.     If curDispWind = nil, output is currently turned off.
  99. */
  100.  
  101.  
  102. typedef struct DisplayInfo
  103. {
  104.     WindowPtr            dWind;            /* display window         */
  105.     TEHandle            dTE;            /* window text            */
  106.     ControlHandle        dScroll;        /* window scroll bar      */
  107.     vProcPtr                dActivate;        /* notification procedure */
  108.     Longint                dMaxText;        /* max text length        */
  109.     Longint                dFlushAmt;        /* amount to autoflush    */
  110.     struct DisplayInfo    **dNext;        /* next window structure  */
  111. } DisplayInfo, *DIPtr, **DIHandle;
  112.  
  113.  
  114. static DIHandle        dwList = nil;
  115.  
  116. # endif
  117.  
  118. /*
  119.     Variables pertaining to the display window being operated on
  120.     (updated, resized, etc.).  This window is not necessarily the
  121.     same as curDispWind!  These variables are synced to the window
  122.     with SyncGlobals.
  123. */
  124.  
  125. # ifndef    singleDisplay
  126. static DIHandle            dispInfo;        /* info structure         */
  127. # endif
  128.  
  129. static WindowPtr        dispWind = nil;    /* the window             */
  130. static TEHandle            dispTE;            /* window text            */
  131. static ControlHandle    dispScroll;        /* the scroll bar         */
  132. static vProcPtr            dActivate;        /* notification procedure */
  133. static Longint            dMaxText;        /* max text allowed       */
  134. static Longint            dFlushAmt;        /* amount to flush        */
  135.  
  136.  
  137. /*
  138.     curDispWind is the current output window.
  139.     If curDispWind = nil, output is turned off.
  140. */
  141.  
  142. static WindowPtr    curDispWind = nil;
  143.  
  144.  
  145. /* -------------------------------------------------------------------- */
  146. /*                Miscellaneous Internal (private) Routines                */
  147. /* -------------------------------------------------------------------- */
  148.  
  149. /* Prototypes */
  150. static void DrawGrowBox (void);
  151. static DIHandle GetDInfo (WindowPtr theWind);
  152. static void SyncGlobals (WindowPtr theWind);
  153. static void CalcEditRect (Rect *r);
  154. static void CalcScrollRect (Rect *r);
  155. static LinesOffTop (void);
  156. static void HiliteScroll (void);
  157. static void ScrollText (Integer lDelta);
  158. static pascal void TrackScroll (ControlHandle theScroll, Integer partCode);
  159. static void OverhaulDisplay (void);
  160. static void Activate (Boolean isActive);
  161. static void Update (Boolean resized);
  162. static void Mouse (Point thePt, Longint t, Integer mods);
  163. static void Clobber (void);
  164. static SetupDWindow (void);
  165. static void HexByte (Integer value);
  166.  
  167. /*
  168.     Draw grow box of dispWind in lower right hand corner
  169. */
  170.  
  171.  
  172. static void
  173. DrawGrowBox ()
  174. {
  175. register RgnHandle    oldClip;
  176. Rect                r;
  177.  
  178.     r = dispWind->portRect;
  179.     r.left = r.right - 15;        /* draw only in corner */
  180.     r.top = r.bottom - 15;
  181.     oldClip = NewRgn ();
  182.     GetClip (oldClip);
  183.     ClipRect (&r);
  184.     DrawGrowIcon (dispWind);
  185.     SetClip (oldClip);
  186.     DisposeRgn (oldClip);
  187. }
  188.  
  189.  
  190.  
  191. /* -------------------------------------------------------------------- */
  192. /*            Lowest-level Internal (Private) Display Window Routines        */
  193. /* -------------------------------------------------------------------- */
  194.  
  195.  
  196. # ifndef    singleDisplay
  197.  
  198. /*
  199.     Get display window info associated with window.
  200.     Return nil if window isn't a known display window.
  201. */
  202.  
  203. static DIHandle GetDInfo (theWind)
  204. WindowPtr    theWind;
  205. {
  206. register DIHandle    h;
  207.  
  208.     for (h = dwList; h != nil; h = (**h).dNext)
  209.     {
  210.         if ((**h).dWind == theWind)
  211.             return (h);
  212.     }
  213.     return (nil);
  214. }
  215.  
  216. # endif
  217.  
  218. # ifdef    singleDisplay
  219. # define    SyncGlobals(x)    ;    /* make it a nop */
  220. # else
  221.  
  222. /*
  223.     Synchronize globals to a display window.  theWind must be a legal
  224.     display window, with one exception:  if theWind is nil, the
  225.     variables are synced to the current port.  That is safe (and
  226.     correct) because:
  227.     (i)     nil is only passed by display window handler procedures,
  228.          which are only called by TransSkel for display window
  229.          events.
  230.     (ii) For those handler procs that pass nil, TransSkel either sets
  231.          the port to the window before calling the proc (update, clobber,
  232.          idle procs), or the window is frontmost, and so will be the
  233.          current port anyway (mouse proc).
  234.     Hence, use of the current port under these circumstances
  235.     always produces a legal display window.
  236.     
  237.     SyncGlobals is not used in single display mode, because the
  238.     globals are all set by SetupDWindow and do not change thereafter.
  239. */
  240.  
  241. static void
  242. SyncGlobals (theWind)
  243. WindowPtr    theWind;
  244. {
  245. register DIPtr    dp;
  246.  
  247.     if (theWind == nil)                    /* use current window */
  248.         GetPort (&theWind);
  249.  
  250.     dispWind = theWind;
  251.     dispInfo = GetDInfo (dispWind);
  252.     dp = *dispInfo;
  253.     dispScroll = (*dp).dScroll;
  254.     dispTE = (*dp).dTE;
  255.     dActivate = (*dp).dActivate;
  256.     dMaxText = (*dp).dMaxText;
  257.     dFlushAmt = (*dp).dFlushAmt;
  258. }
  259.  
  260. # endif
  261.  
  262.  
  263. /*
  264.     Calculate the dimensions of the editing rectangle for
  265.     dispWind (which must be set properly and is assumed to be
  266.     the current port).  (The viewRect and destRect are the
  267.     same size.)  Assumes the port, text font and text size are all
  268.     set properly.  The viewRect is sized so that an integral
  269.     number of lines can be displayed in it, i.e., so that a
  270.     partial line never shows at the bottom.
  271. */
  272.  
  273. static void
  274. CalcEditRect (r)
  275. Rect        *r;
  276. {
  277. FontInfo            f;
  278. register Integer    lineHeight;
  279.  
  280.     GetFontInfo (&f);
  281.     lineHeight = f.ascent + f.descent + f.leading;
  282.     *r = dispWind->portRect;
  283.     r->left += 4;
  284.     r->right -= 17;            /* leave room for scroll bar + 2 */
  285.     r->top += 2;
  286.     r->bottom = r->top + ((r->bottom - r->top - 2) / lineHeight) * lineHeight;
  287. }
  288.  
  289.  
  290. /*
  291.     Calculate the dimensions of the scroll bar rectangle for the
  292.     window.  Make sure that the edges overlap the window frame and
  293.     the grow box.
  294. */
  295.  
  296. static void
  297. CalcScrollRect (r)
  298. Rect        *r;
  299. {
  300.     *r = dispWind->portRect;
  301.     ++r->right;
  302.     --r->top;
  303.     r->left = r->right - 16;
  304.     r->bottom -= 14;
  305. }
  306.  
  307.  
  308. /*
  309.     Calculate the number of lines currently scrolled off
  310.     the top.
  311. */
  312.  
  313. static LinesOffTop ()
  314. {
  315. register TEPtr    ePtr;
  316.  
  317.     ePtr = *dispTE;
  318.     return (((*ePtr).viewRect.top - (*ePtr).destRect.top)
  319.                 / (*ePtr).lineHeight);
  320. }
  321.  
  322.  
  323. /*
  324.     Highlight the scroll bar properly.  This means that it's not
  325.     made active if the window itself isn't active, even if
  326.     there's enough text to fill the window.
  327. */
  328.  
  329. static void
  330. HiliteScroll ()
  331. {
  332.     HiliteControl (dispScroll, dispWind == FrontWindow () &&
  333.                                 GetCtlMax (dispScroll) > 0 ? 0 : 255);
  334. }
  335.  
  336.  
  337. /*
  338.     Scroll to the correct position.  lDelta is the
  339.     amount to CHANGE the current scroll setting by.
  340.     Positive scrolls the text up, negative down.
  341. */
  342.  
  343. static void
  344. ScrollText (lDelta)
  345. Integer    lDelta;
  346. {
  347. register Integer    lHeight;
  348. register Integer    newLine;
  349. register Integer    topLine;
  350.  
  351.     lHeight = (**dispTE).lineHeight;
  352.     topLine = LinesOffTop ();
  353.     newLine = topLine + lDelta;
  354.     if (newLine < 0)
  355.         newLine = 0;
  356.     if (newLine > GetCtlMax (dispScroll))
  357.         newLine = GetCtlMax (dispScroll);
  358.     SetCtlValue (dispScroll, newLine);
  359.     TEScroll (0, (topLine - newLine ) * lHeight, dispTE);
  360. }
  361.  
  362.  
  363. /*
  364.     Filter proc for tracking mousedown in scroll bar.  The code for
  365.     the part originally hit is stored in the control's reference
  366.     value by Mouse () before calling this.
  367.  
  368.     Scroll by one line if the mouse is in an arrow.  Scroll by a half
  369.     window's worth of lines if the mouse is in a page region.
  370. */
  371.  
  372. static pascal void TrackScroll (theScroll, partCode)
  373. ControlHandle    theScroll;
  374. Integer            partCode;
  375. {
  376. register Integer    lDelta;
  377. register Integer    halfPage;
  378.  
  379.     if (partCode == GetCRefCon (theScroll))    /* still in same part? */
  380.     {
  381.         halfPage = (((**dispTE).viewRect.bottom - (**dispTE).viewRect.top)
  382.                         / (**dispTE).lineHeight) / 2;
  383.         if (halfPage == 0)
  384.             ++halfPage;
  385.         switch (partCode)
  386.         {
  387.             case inUpButton: lDelta = -1; break;
  388.             case inDownButton: lDelta = 1; break;
  389.             case inPageUp: lDelta = -halfPage; break;
  390.             case inPageDown: lDelta = halfPage; break;
  391.         }
  392.         ScrollText (lDelta);
  393.     }
  394. }
  395.  
  396.  
  397. /*
  398.     Adjust the text in the text record and the scroll bar.  This is
  399.     called for major catastrophes, such as resizing the window, or
  400.     changing the word wrap style.  It makes sure the view and
  401.     destination rectangles are sized properly, and that the bottom
  402.     line of text never scrolls up past the bottom line of the
  403.     window, if there's enough to fill the window, and that the
  404.     scroll bar max and current values are set properly.
  405.  
  406.     Resizing the dest rect just means resetting the right edge
  407.     (the top is NOT reset), since text might be scrolled off the
  408.     top (i.e., destRect.top != 0).
  409. */
  410.  
  411. static void
  412. OverhaulDisplay ()
  413. {
  414. Rect                r;
  415. register Integer    nLines;            /* # of lines in TERec */
  416. register Integer    visLines;        /* # of lines displayable in window */
  417. register Integer    topLines;        /* # of lines currently scrolled off top */
  418. register Integer    scrollLines;    /* # of lines to scroll down */
  419. register Integer    lHeight;
  420.  
  421.     CalcEditRect (&r);
  422.     (**dispTE).destRect.right = r.right;
  423.     (**dispTE).viewRect = r;
  424.     TECalText (dispTE);        /* recalc line starts */
  425.     /*r = (**dispTE).viewRect;*/    /* ?? */
  426.     lHeight = (**dispTE).lineHeight;
  427.     nLines = (**dispTE).nLines;
  428.     visLines = (r.bottom - r.top) / lHeight;
  429.     topLines = LinesOffTop ();
  430.  
  431. /*
  432.     If the text doesn't fill the window (visLines > nLines - topLines),
  433.     pull the text down if possible (if topLines > 0).  Make sure not
  434.     to try to scroll down by more lines than are hidden off the top.
  435. */
  436.     scrollLines = visLines - (nLines - topLines);
  437.     if (scrollLines > 0 && topLines > 0)
  438.     {
  439.         if (scrollLines > topLines)
  440.             scrollLines = topLines;
  441.         TEScroll (0, scrollLines * lHeight, dispTE);
  442.         topLines -= scrollLines;
  443.     }
  444.     TEUpdate (&r, dispTE);
  445.  
  446.     SetCtlMax (dispScroll, nLines - visLines < 0 ? 0 : nLines - visLines);
  447.     SetCtlValue (dispScroll, topLines);
  448.     HiliteScroll ();
  449. }
  450.  
  451.  
  452. /* ---------------------------------------------------------------- */
  453. /*                        Window Handler Routines                        */
  454. /* ---------------------------------------------------------------- */
  455.  
  456.  
  457. /*
  458.     When the window comes active, highlight the scroll bar appropriately.
  459.     When the window is deactivated, un-highlight the scroll bar.
  460.     Redraw the grow box.
  461.  
  462.     Notify the host as appropriate.
  463.  
  464.     Note that clicking close box hides the window, which generates a
  465.     deactivate event, so there is no need for a close notifier.
  466. */
  467.  
  468. static void
  469. Activate (isActive)
  470. Boolean    isActive;
  471. {
  472.     SyncGlobals (nil);                /* sync to current port */
  473.     DrawGrowBox ();
  474.     HiliteScroll ();
  475.  
  476.     if (dActivate != nil)
  477.         (*dActivate) (isActive);
  478. }
  479.  
  480.  
  481. /*
  482.     Update window.  The update event might be in response to a
  483.     window resizing.  If so, move and resize the scroll bar,
  484.     and recalculate the text display.
  485.  
  486.     The ValidRect call is done because the HideControl adds the
  487.     control bounds box to the update region - which would generate
  488.     another update event!  Since everything is redrawn below anyway,
  489.     the ValidRect is used to cancel the update.
  490. */
  491.  
  492. static void
  493. Update (resized)
  494. Boolean    resized;
  495. {
  496. Rect    r;
  497.  
  498.     SyncGlobals (nil);                    /* sync to current port */
  499.     r = dispWind->portRect;
  500.     EraseRect (&r);
  501.     if (resized)
  502.     {
  503.         HideControl (dispScroll);
  504.         r = (**dispScroll).contrlRect;
  505.         ValidRect (&r);
  506.         CalcScrollRect (&r);
  507.         SizeControl (dispScroll, 16, r.bottom - r.top);
  508.         MoveControl (dispScroll, r.left, r.top);
  509.         OverhaulDisplay ();
  510.         ShowControl (dispScroll);
  511.     }
  512.     else
  513.     {
  514.         r = (**dispTE).viewRect;
  515.         TEUpdate (&r, dispTE);        /* redraw text display */
  516.     }
  517.  
  518.     DrawGrowBox ();
  519.     DrawControls (dispWind);    /* redraw scroll bar */
  520. }
  521.  
  522.  
  523. /*
  524.     Handle mouse clicks in window
  525. */
  526.  
  527. static void
  528. Mouse (thePt, t, mods)
  529. Point    thePt;
  530. Longint    t;
  531. Integer    mods;
  532. {
  533. register Integer    thePart;
  534. register Integer    oldCtlValue;
  535.  
  536.     SyncGlobals (nil);                /* sync to current port */
  537.  
  538.     if ((thePart = TestControl (dispScroll, thePt)) == inThumb)
  539.     {
  540.         oldCtlValue = GetCtlValue (dispScroll);
  541.         if (TrackControl (dispScroll, thePt, nil) == inThumb)
  542.             ScrollText (GetCtlValue (dispScroll) - oldCtlValue);
  543.     }
  544.     else if (thePart != 0)
  545.     {
  546.         SetCRefCon (dispScroll, (Longint) thePart);
  547.         (void) TrackControl (dispScroll, thePt, &TrackScroll);
  548.     }
  549. }
  550.  
  551.  
  552.  
  553. /*
  554.     Remove the display window from the list, and dispose of it.
  555.     Since the clobber procedure is never called except for real display
  556.     windows, and since the list must therefore be non-empty, it is
  557.     not necessary to check the legality of the window or that the
  558.     window's in the list.
  559.  
  560.     Must do SetDWindow (nil) to turn output off, if the window being
  561.     clobbered is the current output window.
  562. */
  563.  
  564. static void
  565. Clobber ()
  566. {
  567. # ifndef    singleDisplay
  568. register DIHandle    h, h2;
  569. # endif
  570.  
  571.     SyncGlobals (nil);                    /* sync to current port */
  572.  
  573.     if (dispWind == curDispWind)
  574.         SetDWindow (nil);
  575.  
  576. # ifndef    singleDisplay
  577.  
  578.     if ((**dwList).dWind == dispWind)    /* is it the first window in list? */
  579.     {
  580.         h2 = dwList;
  581.         dwList = (**dwList).dNext;
  582.     }
  583.     else
  584.     {
  585.         for (h = dwList; h != nil; h = h2)
  586.         {
  587.             h2 = (**h).dNext;
  588.             if ((**h2).dWind == dispWind)    /* found it */
  589.             {
  590.                 (**h).dNext = (**h2).dNext;
  591.                 break;
  592.             }
  593.         }
  594.     }
  595.     DisposHandle ((Handle)h2);        /* get rid of information structure */
  596.  
  597. # endif
  598.  
  599.     TEDispose (dispTE);            /* toss text record */
  600.     DisposeWindow (dispWind);    /* toss window and scroll bar */
  601.     dispWind = nil;
  602. }
  603.  
  604.  
  605. /* ---------------------------------------------------------------- */
  606. /*                            Control Routines                        */
  607. /* ---------------------------------------------------------------- */
  608.  
  609.  
  610. /*
  611.     Test whether a window is a legal display window or not
  612. */
  613.  
  614. Boolean IsDWindow (theWind)
  615. WindowPtr    theWind;
  616. {
  617.  
  618. # ifdef    singleDisplay
  619.     return (theWind == dispWind && dispWind != nil);
  620. # else
  621.     return (GetDInfo (theWind) != nil);
  622. # endif
  623. }
  624.  
  625.  
  626. /*
  627.     Return handle to display window's text record
  628. */
  629.  
  630. TEHandle GetDWindowTE (theWind)
  631. WindowPtr    theWind;
  632. {
  633.  
  634. # ifndef    singleDisplay
  635. register DIHandle    dInfo;
  636.     return (GetDInfo (theWind) == nil ? nil : (**dInfo).dTE);
  637. # else
  638.     return (IsDWindow (theWind) ? dispTE : nil);
  639. # endif
  640. }
  641.  
  642.  
  643. /*
  644.     Change the text display characteristics of a display window
  645.     and redisplay it.  As a side effect, this always scrolls to the
  646.     home position.
  647. */
  648.  
  649. void
  650. SetDWindowStyle (theWind, font, size, wrap, just)
  651. WindowPtr    theWind;
  652. Integer        font;
  653. Integer        size;
  654. Integer        wrap;
  655. Integer        just;
  656. {
  657. GrafPtr                savePort;
  658. FontInfo            f;
  659. register TEHandle    te;
  660. Rect                r;
  661.  
  662.     if (theWind == nil)            /* reset window creation defaults */
  663.     {
  664.         d_font = font;
  665.         d_size = size;
  666.         d_wrap = wrap;
  667.         d_just = just;
  668.         return;
  669.     }
  670.  
  671.     if (IsDWindow (theWind))
  672.     {
  673.         GetPort (&savePort);
  674.         SyncGlobals (theWind);
  675.         SetPort (dispWind);
  676.         te = dispTE;
  677.         r = (**te).viewRect;
  678.         EraseRect (&r);
  679.         r = (**te).destRect;    /* scroll home without redrawing */
  680.         OffsetRect (&r, 0, 2 - r.top);
  681.         (**te).destRect = r;
  682.  
  683.         (**te).crOnly = wrap;    /* set word wrap */
  684.         TESetJust (just, te);    /* set justification */
  685.  
  686.         TextFont (font);         /* set the font and point size */
  687.         TextSize (size);        /* of text record (this is the */
  688.         GetFontInfo (&f);        /* hard part) */
  689.         (**te).lineHeight = f.ascent + f.descent + f.leading;
  690.         (**te).fontAscent = f.ascent;
  691.         (**te).txFont = font;
  692.         (**te).txSize = size;
  693.  
  694.         OverhaulDisplay ();
  695.         SetPort (savePort);
  696.     }
  697. }
  698.  
  699.  
  700. /*
  701.     Scroll the text in the window so that line lineNum is at the top.
  702.     First line is line zero.
  703. */
  704.  
  705. void
  706. SetDWindowPos (theWind, lineNum)
  707. WindowPtr    theWind;
  708. Integer        lineNum;
  709. {
  710. GrafPtr        savePort;
  711.  
  712.     if (IsDWindow (theWind))
  713.     {
  714.         GetPort (&savePort);
  715.         SyncGlobals (theWind);
  716.         SetPort (dispWind);
  717.         ScrollText (lineNum - GetCtlValue (dispScroll));
  718.         SetPort (savePort);
  719.     }
  720. }
  721.  
  722.  
  723. /*
  724.     Set display window activate notification procedure.
  725.     Pass nil to disable it.
  726. */
  727.  
  728. void
  729. SetDWindowNotify (theWind, p)
  730. WindowPtr    theWind;
  731. vProcPtr    p;
  732. {
  733. # ifndef    singleDisplay
  734. register DIHandle    dInfo;
  735. # endif
  736.  
  737.     if (theWind == nil)            /* reset window creation default */
  738.     {
  739.         d_activate = p;
  740.         return;
  741.     }
  742.  
  743. # ifdef    singleDisplay
  744.  
  745.     if (IsDWindow (theWind))
  746.         dActivate = p;
  747.  
  748. # else
  749.  
  750.     if ((dInfo = GetDInfo (theWind)) != nil)
  751.     {
  752.         (**dInfo).dActivate = p;
  753.     }
  754.  
  755. # endif
  756. }
  757.  
  758.  
  759. /*
  760.     Set display window autoflush characteristics
  761. */
  762.  
  763. void
  764. SetDWindowFlush (theWind, maxText, flushAmt)
  765. WindowPtr    theWind;
  766. Longint        maxText;
  767. Longint        flushAmt;
  768. {
  769. # ifndef    singleDisplay
  770. register DIHandle    dInfo;
  771. # endif
  772.  
  773.     if (maxText > 32767L)
  774.         maxText = 32767L;
  775.     if (maxText < d_loMaxText)
  776.         maxText = d_loMaxText;
  777.     if (flushAmt < d_loFlushAmt)
  778.         flushAmt = d_loFlushAmt;
  779.  
  780.     if (theWind == nil)            /* reset window creation defaults */
  781.     {
  782.         d_maxText = maxText;
  783.         d_flushAmt = flushAmt;
  784.         return;
  785.     }
  786.  
  787. # ifdef    singleDisplay
  788.  
  789.     if (IsDWindow (theWind))
  790.     {
  791.  
  792.         dMaxText = maxText;
  793.         dFlushAmt = flushAmt;
  794.     }
  795.  
  796. # else
  797.  
  798.     if ((dInfo = GetDInfo (theWind)) != nil)
  799.     {
  800.         (**dInfo).dMaxText = maxText;
  801.         (**dInfo).dFlushAmt = flushAmt;
  802.     }
  803.  
  804. # endif
  805. }
  806.  
  807.  
  808. /*
  809.     Set which display window is to be used for output.  If theWind
  810.     is nil, output is turned off.  If theWind is not a legal display
  811.     window, nothing is done.
  812. */
  813.  
  814. void
  815. SetDWindow (theWind)
  816. WindowPtr    theWind;
  817. {
  818.     if (theWind == nil || IsDWindow (theWind))
  819.     {
  820.         curDispWind = theWind;
  821.     }
  822. }
  823.  
  824.  
  825. /*
  826.     Get the WindowPtr of the current output display window.  If
  827.     output is turned off, this will be nil.
  828. */
  829.  
  830. GetDWindow (theWind)
  831. WindowPtr    *theWind;
  832. {
  833.     *theWind = curDispWind;
  834. }
  835.  
  836.  
  837. /*
  838.     Flush text from the window and readjust the display.
  839. */
  840.  
  841. void
  842. FlushDWindow (theWind, byteCount)
  843. WindowPtr    theWind;
  844. Longint        byteCount;
  845. {
  846.     if (IsDWindow (theWind))
  847.     {
  848.         SyncGlobals (theWind);
  849.         TESetSelect (0L, byteCount, dispTE);    /* select text */
  850.         TEDelete (dispTE);                        /* clobber it */
  851.         OverhaulDisplay ();
  852.     }
  853. }
  854.  
  855.  
  856. /*
  857.     Create and initialize a display window and the associated data
  858.     structures, and return the window pointer.  Install window in
  859.     list of display windows.
  860. */
  861.  
  862. static SetupDWindow ()
  863. {
  864. Rect    r;
  865. GrafPtr    savePort;
  866.  
  867. # ifndef    singleDisplay
  868. register DIHandle    dInfo;
  869. # endif
  870.  
  871.  
  872.     GetPort (&savePort);
  873.     if (SkelWindow (dispWind,    /* the window */
  874.                 Mouse,        /* mouse click handler */
  875.                 nil,        /* key clicks are ignored */
  876.                 Update,        /* window updating procedure */
  877.                 Activate,    /* window activate/deactivate procedure */
  878.                 nil,        /* TransSkel hides window if no close proc */
  879.                             /* (generates deactivate event) */
  880.                 Clobber,    /* window disposal procedure */
  881.                 nil,        /* no idle proc */
  882.                 false) == 0)    /* irrelevant since no idle proc */
  883.     {
  884.         SetPort (savePort);
  885.         return (0);
  886.     }
  887.  
  888. /*
  889.     Build the scroll bar.  Make sure the borders overlap the
  890.     window frame and the frame of the grow box.
  891. */
  892.  
  893.     CalcScrollRect (&r);
  894.     dispScroll = NewControl (dispWind, &r, "\p", true, 0, 0, 0,
  895.                                 scrollBarProc, 0L);
  896.  
  897. /*
  898.     Create the TE record used for text display.  Use defaults for
  899.     display characteristics.  Setting window style overhauls
  900.     display, so can cancel and update event pending for the window.
  901. */
  902.  
  903.     CalcEditRect (&r);
  904.     dispTE = TENew (&r, &r);
  905.  
  906. # ifndef    singleDisplay
  907.  
  908. /*
  909.     Get new information structure, attach to list of known display
  910.     windows.
  911. */
  912.     dInfo = New (DisplayInfo);
  913.     (**dInfo).dNext = dwList;
  914.     dwList = dInfo;
  915.     (**dInfo).dWind = dispWind;
  916.     (**dInfo).dScroll = dispScroll;
  917.     (**dInfo).dTE = dispTE;
  918.     
  919. # endif
  920.  
  921.     SetDWindowNotify (dispWind, d_activate);
  922.     SetDWindowFlush (dispWind, d_maxText, d_flushAmt);
  923.     SetDWindowStyle (dispWind, d_font, d_size, d_wrap, d_just);
  924.  
  925. /*
  926.     Make window current display output window
  927. */
  928.  
  929.     SetDWindow (dispWind);
  930.     SetPort (savePort);
  931.     return (1);
  932. }
  933.  
  934.  
  935. /*
  936.     Create and initialize a display window and the associated data
  937.     structures, and return the window pointer.  Install window in
  938.     list of display windows.  In single-window mode, disallow
  939.     creation of a new window if one already exists.
  940.  
  941.     The parameters are similar to those for NewWindow.  See Inside
  942.     Macintosh.
  943. */
  944.  
  945. WindowPtr NewDWindow (bounds, title, visible, behind, goAway, refCon)
  946. Rect        *bounds;
  947. StringPtr    title;
  948. Boolean        visible;
  949. WindowPtr    behind;
  950. Boolean        goAway;
  951. Longint        refCon;
  952. {
  953.  
  954. # ifdef    singleDisplay
  955.  
  956.     if (dispWind != nil)
  957.         return (nil);
  958.  
  959. # endif
  960.  
  961.     if ((dispWind = NewWindow (nil,
  962.                                bounds,
  963.                                title,
  964.                                visible,
  965.                                documentProc + 8,
  966.                                behind,
  967.                                goAway,
  968.                                refCon)) != nil)
  969.     {
  970.         if (SetupDWindow ())
  971.             return (dispWind);
  972.         DisposeWindow (dispWind);
  973.     }
  974.     return (nil);
  975. }
  976.  
  977.  
  978. /*
  979.     Create and initialize a display window (using a resource) and
  980.     the associated data structures, and return the window pointer.
  981.     Install window in list of display windows.  In single-window
  982.     mode, disallow creation of a new window if one already exists.
  983.  
  984.     The parameters are similar to those for GetNewWindow.  See Inside
  985.     Macintosh.
  986. */
  987.  
  988. WindowPtr GetNewDWindow (resourceNum, behind)
  989. Integer        resourceNum;
  990. WindowPtr    behind;
  991. {
  992.  
  993. # ifdef    singleDisplay
  994.  
  995.     if (dispWind != nil)
  996.         return (nil);
  997.  
  998. # endif
  999.  
  1000.     if ((dispWind = GetNewWindow (resourceNum, nil, behind)) != nil)
  1001.     {
  1002.         if (SetupDWindow ())
  1003.             return (dispWind);
  1004.         DisposeWindow (dispWind);
  1005.     }
  1006.     return (nil);
  1007. }
  1008.  
  1009.  
  1010.  
  1011.  
  1012. /* ------------------------------------------------------------ */
  1013. /*                        Output Routines                            */
  1014. /* ------------------------------------------------------------ */
  1015.  
  1016.  
  1017. /*
  1018.     Write text to display area if output is on (curDispWind != nil).
  1019.     DisplayText is the fundamental output routine.  All other
  1020.     output calls map (eventually) to it.
  1021.  
  1022.     First check whether the insertion will cause overflow and flush
  1023.     out some stuff if so.  Insert new text at the end, then test
  1024.     whether lines must be scrolled to get the new stuff to show up.
  1025.     If yes, then do the scroll.  Set values of scroll bar properly
  1026.     and highlight as appropriate.
  1027.  
  1028.     The current port is preserved.  Since all output calls end up
  1029.     here, it's the only output routine that has to save the port
  1030.     and check whether output is on.
  1031. */
  1032.  
  1033. void
  1034. DisplayText (theText, len)
  1035. Ptr        theText;
  1036. Longint    len;
  1037. {
  1038. register Integer    nLines;            /* # of lines in TERec */
  1039. register Integer    dispLines;        /* # of lines displayable in window */
  1040. register Integer    topLines;        /* # of lines currently scrolled off top */
  1041. register Integer    scrollLines;    /* # of lines to scroll up */
  1042. register Integer    lHeight;
  1043. Rect                r;
  1044. GrafPtr                savePort;
  1045. register TEHandle    dTE;
  1046.  
  1047.     if (curDispWind == nil)
  1048.         return;
  1049.  
  1050.     GetPort (&savePort);
  1051.     SetPort (curDispWind);
  1052.     SyncGlobals (curDispWind);
  1053.     dTE = dispTE;
  1054.  
  1055.     if ((**dTE).teLength + len > dMaxText)    /* check overflow */
  1056.     {
  1057.         FlushDWindow (dispWind, dFlushAmt);
  1058.         DisplayString ((StringPtr) "\p\r(autoflush occurred)\r");
  1059.     }
  1060.  
  1061.     lHeight = (**dTE).lineHeight;
  1062.     TESetSelect (32767L, 32767L, dTE);    /* set to insert at end */
  1063.     TEInsert (theText, len, dTE);
  1064.     r = (**dTE).viewRect;
  1065.     nLines = (**dTE).nLines;
  1066.     dispLines = (r.bottom - r.top) / lHeight;
  1067.     topLines = LinesOffTop ();
  1068.     scrollLines = nLines - (topLines + dispLines);
  1069.     if (scrollLines > 0) /* must scroll up */
  1070.         TEScroll (0, -lHeight * scrollLines, dTE); /* scroll up */
  1071.     topLines = nLines - dispLines;
  1072.     if (topLines >= 0 && GetCtlMax (dispScroll) != topLines)
  1073.     {
  1074. /*        SetCtlMax (dispScroll, topLines);
  1075.  *        Using SetCltMax followed immediately by SetCtlValue resulted
  1076.  *        in a jumpy thumb, because both calls caused the control to be
  1077.  *        updated, with different positions.  So, we set the max directly
  1078.  *        and let SetCtlValue be the only update.
  1079.  */
  1080.         (*dispScroll)->contrlMax = topLines;
  1081.         SetCtlValue (dispScroll, topLines);
  1082.     }
  1083.     HiliteScroll ();
  1084.     SetPort (savePort);
  1085. }
  1086.  
  1087.  
  1088. /*
  1089.     Derived output routines:
  1090.  
  1091.     DisplayString    Write (Pascal) string
  1092.  
  1093.     DisplayLong        Write value of long integer
  1094.     DisplayInt        Write value of integer
  1095.     DisplayChar        Write character
  1096.  
  1097.     DisplayHexLong    Write value of long integer in hex (8 digits)
  1098.     DisplayHexInt    Write value of integer in hex (4 digits)
  1099.     DisplayHexChar    Write value of character in hex (2 digit)
  1100.  
  1101.     DisplayBoolean    Write boolean value
  1102.     DisplayLn        Write carriage return
  1103. */
  1104.  
  1105. void
  1106. DisplayString (theStr)
  1107. StringPtr    theStr;
  1108. {
  1109.     DisplayText ((Ptr) theStr+1, (Longint) theStr[0]);
  1110. }
  1111.  
  1112.  
  1113. void
  1114. DisplayLong (l)
  1115. Longint        l;
  1116. {
  1117. Str255        s;
  1118.  
  1119.     NumToString (l, s);
  1120.     DisplayString (s);
  1121. }
  1122.  
  1123.  
  1124. void
  1125. DisplayInt (i)
  1126. Integer    i;
  1127. {
  1128.     DisplayLong ((Longint) i);
  1129. }
  1130.  
  1131.  
  1132. void
  1133. DisplayChar (c)
  1134. char    c;
  1135. {
  1136.     DisplayText ((Ptr) &c, 1L);
  1137. }
  1138.  
  1139.  
  1140. void
  1141. DisplayLn ()
  1142. {
  1143.     DisplayChar ('\r');
  1144. }
  1145.  
  1146.  
  1147. void
  1148. DisplayBoolean (b)
  1149. Boolean    b;
  1150. {
  1151.     DisplayString ((StringPtr)(b ? "\ptrue" : "\pfalse"));
  1152. }
  1153.  
  1154.  
  1155. static void
  1156. HexByte (value)    /* should be 0..15 */
  1157. Integer    value;
  1158. {
  1159.     DisplayChar ((char) (value + (value < 10 ? '0' : 'a' - 10)));
  1160. }
  1161.  
  1162.  
  1163. void
  1164. DisplayHexChar (c)
  1165. char    c;
  1166. {
  1167.     HexByte ((Integer) (c >> 4) & 0x0f);
  1168.     HexByte ((Integer) c & 0x0f);
  1169. }
  1170.  
  1171.  
  1172. void
  1173. DisplayHexInt (i)
  1174. Integer    i;
  1175. {
  1176.     DisplayHexChar ((char) ((i >> 8) & 0xff));
  1177.     DisplayHexChar ((char) (i & 0xff));
  1178. }
  1179.  
  1180.  
  1181. void
  1182. DisplayHexLong (l)
  1183. Longint    l;
  1184. {
  1185.     DisplayHexInt ((Integer) (l >> 16) & 0xffff);
  1186.     DisplayHexInt ((Integer) l & 0xffff);
  1187. }
  1188.