home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 January / macpower199701.bin / AMUG / Programming_10 / WASTE 1.3a1.sit / WASTE 1.3a1 Distribution / Demo / WEDemoWindows.c < prev   
Encoding:
C/C++ Source or Header  |  1996-08-23  |  21.9 KB  |  957 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     Window Handling
  4.  
  5.     Copyright ゥ 1993-1996 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __ALIASES__
  13. #include <Aliases.h>
  14. #endif
  15.  
  16. #ifndef __TOOLUTILS__
  17. #include <ToolUtils.h>
  18. #endif
  19.  
  20. #ifndef __FILETYPESANDCREATORS__
  21. #include <FileTypesAndCreators.h>
  22. #endif
  23.  
  24. #ifndef _LongCoords_
  25. #include "LongCoords.h"
  26. #endif
  27.  
  28. #ifndef __WEDEMOAPP__
  29. #include "WEDemoIntf.h"
  30. #endif
  31.  
  32. // some consts used by DoGrow()
  33.  
  34. enum {
  35.     kMinWindowWidth        = 200,
  36.     kMinWindowHeight    = 80
  37. };
  38.  
  39. // static variables
  40.  
  41. static SInt32 sScrollStep; // how many pixels to scroll (used by ScrollProc)
  42.  
  43.  
  44. static void    CalcGrowIconRect( WindowRef window, Rect *iconRect )
  45. {
  46.     Rect portRect = GetWindowPort( window )->portRect;
  47.  
  48.     iconRect->top = portRect.bottom - (kBarWidth - 2);
  49.     iconRect->left = portRect.right - (kBarWidth - 2);
  50.     iconRect->bottom = portRect.bottom;
  51.     iconRect->right = portRect.right;
  52. }
  53.  
  54. static void    CalcTextRect( WindowRef window, Rect *textRect )
  55. {
  56.     Rect portRect = GetWindowPort( window )->portRect;
  57.  
  58.     textRect->top = 0;
  59.     textRect->left = 0;
  60.     textRect->bottom = portRect.bottom - (kBarWidth - 1);
  61.     textRect->right = portRect.right - (kBarWidth - 1);
  62.     InsetRect( textRect, kTextMargin, kTextMargin );
  63. }
  64.  
  65. static void    CalcScrollBarRect( WindowRef window, VHSelect axis, Rect *barRect )
  66. {
  67.     Rect portRect = GetWindowPort( window )->portRect;
  68.  
  69.     switch ( axis )
  70.     {
  71.         case v:
  72.             barRect->top = -1;
  73.             barRect->left = portRect.right - (kBarWidth - 1);
  74.             barRect->bottom = portRect.bottom - (kBarWidth - 2);
  75.             barRect->right = portRect.right + 1;
  76.             break;
  77.  
  78.         case h:
  79.             barRect->top = portRect.bottom - (kBarWidth - 1);
  80.             barRect->left = -1;
  81.             barRect->bottom = portRect.bottom + 1;
  82.             barRect->right = portRect.right - (kBarWidth - 2 );
  83.             break;
  84.     }
  85. }
  86.  
  87. /*
  88.     the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon
  89.     to the left and top margins of the window's content area
  90.     these additional lines may create ugly dirt, so we use this routine to temporarily
  91.     set the clip region to the grow icon rect.
  92.  
  93.     in addition, if validate is true, we call _ValidRect on the icon rect
  94. */
  95.  
  96. static void    MyDrawGrowIcon( WindowRef window, Boolean validate )
  97. {
  98.     GrafPtr        savePort;
  99.     RgnHandle    saveClip;
  100.     Rect        r;
  101.  
  102.     // save port and set thePort to wind
  103.  
  104.     GetPort( &savePort );
  105.     SetPortWindowPort( window );
  106.  
  107.     // save the clip region
  108.  
  109.     saveClip = NewRgn();
  110.     GetClip( saveClip );
  111.  
  112.     // calculate the grow icon rect
  113.  
  114.     CalcGrowIconRect( window, &r );
  115.  
  116.     // set clip region to grow icon rect
  117.  
  118.     ClipRect( &r );
  119.  
  120.     // call _DrawGrowIcon
  121.  
  122.     DrawGrowIcon( window );
  123.  
  124.     // if validate is true, remove the grow icon rect from the update region
  125.  
  126.     if ( validate )
  127.         ValidRect( &r );
  128.  
  129.     // restore old clip region
  130.  
  131.     SetClip( saveClip );
  132.     DisposeRgn( saveClip );
  133.  
  134.     // restore old port
  135.  
  136.     SetPort( savePort );
  137. }
  138.  
  139. static void    ScrollBarChanged( WindowRef window )
  140. {
  141.     // scroll text to reflect new scroll bar setting
  142.  
  143.     DocumentHandle hDocument = GetWindowDocument( window );
  144.     WEReference    we;
  145.     LongRect viewRect, destRect;
  146.  
  147.     we = (*hDocument)->we;
  148.     WEGetViewRect( &viewRect, we );
  149.     WEGetDestRect( &destRect, we );
  150.     WEScroll
  151.     (
  152.         viewRect.left - destRect.left - LCGetValue( (*hDocument)->scrollBars[ h ] ),
  153.         viewRect.top - destRect.top - LCGetValue( (*hDocument)->scrollBars[ v ] ),
  154.         we
  155.     );
  156. }
  157.  
  158. static void    AdjustBars( WindowRef window )
  159. {
  160.     DocumentHandle    hDocument;
  161.     WEReference        we;
  162.     GrafPtr            savePort;
  163.     LongRect        viewRect, destRect;
  164.     SInt32            value;
  165.     SInt32            max;
  166.     ControlRef        bar;
  167.  
  168.     GetPort( &savePort );
  169.     SetPortWindowPort( window );
  170.  
  171.     hDocument = GetWindowDocument(window);
  172.     we = (*hDocument)->we;
  173.  
  174.     // get the view and destination rectangle
  175.  
  176.     WEGetViewRect( &viewRect, we );
  177.     WEGetDestRect( &destRect, we );
  178.  
  179.     //    do the vertical axis
  180.  
  181.     //    get scroll bar handle
  182.  
  183.     bar = (*hDocument)->scrollBars[ v ];
  184.  
  185.     //    calculate new scroll bar settings
  186.  
  187.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  188.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  189.  
  190.     value = viewRect.top - destRect.top;
  191.     max = value + (destRect.bottom - viewRect.bottom);
  192.  
  193.     //    make sure max is always non-negative
  194.  
  195.     if ( max <= 0 )
  196.         max = 0;
  197.  
  198.     //    reset the scroll bar
  199.  
  200.     LCSetMax( bar, max );
  201.     LCSetValue( bar, value );
  202.  
  203.     //    if value exceeds max then the bottom of the destRect is above
  204.     //    the bottom of the view rectangle:  we need to scroll the text downward
  205.  
  206.     if ( value > max )
  207.         ScrollBarChanged( window );
  208.  
  209.     //    now do the horizontal axis
  210.  
  211.     //    get scroll bar handle
  212.  
  213.     bar = (*hDocument)->scrollBars[ h ];
  214.  
  215.     //    calculate new scroll bar settings
  216.  
  217.     value = viewRect.left - destRect.left;
  218.     max = value + (destRect.right - viewRect.right);
  219.  
  220.     //    make sure max is always non-negative
  221.  
  222.     if ( max <= 0 )
  223.         max = 0;
  224.  
  225.     //    reset the scroll bar
  226.  
  227.     LCSetMax( bar, max );
  228.     LCSetValue( bar, value );
  229.  
  230.     SetPort( savePort );
  231. }
  232.  
  233. static void    ViewChanged( WindowRef window )
  234. {
  235.     DocumentHandle    hDocument;
  236.     GrafPtr            savePort;
  237.     ControlRef        bar;
  238.     Rect            r;
  239.     LongRect        viewRect;
  240.     VHSelect        axis;
  241.  
  242.     GetPort( &savePort );
  243.     SetPortWindowPort( window );
  244.  
  245.     hDocument = GetWindowDocument( window );
  246.  
  247.     //    resize the text area
  248.  
  249.     CalcTextRect( window, &r );
  250.     WERectToLongRect( &r, &viewRect );
  251.     WESetViewRect( &viewRect, (*hDocument)->we );
  252.  
  253.     //     move and resize the control bars
  254.  
  255.     for ( axis = v; axis <= h; axis++ )
  256.     {
  257.         bar = (*hDocument)->scrollBars[ axis ];
  258.         CalcScrollBarRect( window, axis, &r );
  259.         MoveControl( bar, r.left, r.top );
  260.         SizeControl( bar, r.right - r.left, r.bottom - r.top );
  261.         ValidRect( &r );
  262.     }
  263.  
  264.     //    reset the thumb positions and the max values of the control bars
  265.     AdjustBars( window );
  266.  
  267.     //    redraw the control bars
  268.  
  269.     ShowControl( (*hDocument)->scrollBars[ v ] );
  270.     ShowControl( (*hDocument)->scrollBars[ h ] );
  271.  
  272.     SetPort( savePort );
  273. }
  274.  
  275. /*
  276.     This is a deviation from the original Pascal WASTE Demo App code.
  277.  
  278.     This "morally correct" code for window dragging is per an article in MacTech
  279.     Magazine (July 1994, Vol 10, No. 7). by Eric Shapiro (of Rock Ridge Enterprises)
  280.     called "Multiple Monitors vs. Your Application"
  281.  
  282.     Eric addressed numerous things to allow your app to deal nicely with multiple
  283.     monitor setups, one of them is dragging.
  284.  
  285.     According to Eric, many apps don't let you drag windows to second monitors, and
  286.     though holding down the cmd/opt keys often overrides this problem, it should
  287.     still be updated.  And the only reason qd.screenBits.bounds works to allow
  288.     you to drag to second monitors is because of a kludge Apple put in the Window Manager
  289.  
  290.     So, this is some code from Eric to make our app be "morally correct" :)
  291. */
  292.  
  293. void DoDrag ( Point thePoint, WindowRef window )
  294. {
  295.     Rect desktopBounds ;
  296.  
  297.     if ( gHasColorQD )
  298.     {
  299.         desktopBounds = ( * GetGrayRgn ( ) ) -> rgnBBox ;
  300.     }
  301.     else
  302.     {
  303.         desktopBounds = qd . screenBits . bounds ;
  304.     }
  305.  
  306.     DragWindow ( window, thePoint, & desktopBounds ) ;
  307. }
  308.  
  309. void Resize ( Point newSize, WindowRef window )
  310. {
  311.     DocumentHandle    hDocument ;
  312.     GrafPtr            savePort ;
  313.     Rect            r ;
  314.     RgnHandle        tempRgn, dirtyRgn ;
  315.  
  316.     //    set up the port
  317.     GetPort( & savePort ) ;
  318.     SetPortWindowPort ( window ) ;
  319.  
  320.     hDocument = GetWindowDocument ( window ) ;
  321.  
  322.     //    create temporary regions for calculations
  323.     tempRgn = NewRgn ( ) ;
  324.     dirtyRgn = NewRgn ( ) ;
  325.  
  326.     //    save old text region
  327.     CalcTextRect ( window, & r ) ;
  328.     RectRgn ( tempRgn, & r ) ;
  329.  
  330.     //    erase the old grow icon rect
  331.     CalcGrowIconRect ( window, & r ) ;
  332.     EraseRect ( & r ) ;
  333.  
  334.     //    hide the scroll bars
  335.     HideControl ( ( * hDocument ) -> scrollBars [ v ] ) ;
  336.     HideControl ( ( * hDocument ) -> scrollBars [ h ] ) ;
  337.  
  338.     //    perform the actual resizing of the window, redraw scroll bars and grow icon
  339.     SizeWindow ( window, newSize . h, newSize . v, false ) ;
  340.     ViewChanged ( window ) ;
  341.     MyDrawGrowIcon ( window, true ) ;
  342.  
  343.     //    calculate the dirty region (to be updated)
  344.     CalcTextRect ( window, & r );
  345.     RectRgn ( dirtyRgn, & r ) ;
  346.     XorRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;
  347.     InsetRect ( & r, - kTextMargin, - kTextMargin ) ;
  348.     RectRgn ( tempRgn, & r ) ;
  349.     SectRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;
  350.  
  351.     //    mark the dirty region as invalid
  352.     InvalRgn ( dirtyRgn ) ;
  353.  
  354.     //    throw away temporary regions
  355.     DisposeRgn ( tempRgn ) ;
  356.     DisposeRgn ( dirtyRgn ) ;
  357.  
  358.     //    restore the port
  359.     SetPort ( savePort ) ;
  360. }
  361.  
  362. void DoGrow ( Point hitPt, WindowRef window )
  363. {
  364.     Rect sizeRect ;
  365.     SInt32 newSize ;
  366.  
  367.     SetRect( & sizeRect, kMinWindowWidth, kMinWindowHeight, SHRT_MAX, SHRT_MAX ) ;
  368.     if ( ( newSize = GrowWindow ( window, hitPt, & sizeRect ) ) != 0L )
  369.     {
  370.         //    for some reason, GrowWindow( ) returns a long value,
  371.         //    but it's really a Point
  372.  
  373.         Resize ( * ( Point * ) & newSize, window ) ;
  374.     }
  375. }
  376.  
  377. void DoZoom ( SInt16 partCode, WindowRef window )
  378. {
  379.     DocumentHandle    hDocument;
  380.     GrafPtr            savePort;
  381.     Rect            r;
  382.  
  383.     GetPort( &savePort );
  384.     SetPortWindowPort( window );
  385.  
  386.     hDocument = GetWindowDocument(window);
  387.  
  388.     r = GetWindowPort( window )->portRect;
  389.     EraseRect( &r );
  390.     HideControl( (*hDocument)->scrollBars[ v ] );
  391.     HideControl( (*hDocument)->scrollBars[ h ] );
  392.  
  393.     ZoomWindow( window, partCode, false );
  394.  
  395.     ViewChanged( window );
  396.     CalcTextRect( window, &r );
  397.     InvalRect( &r );
  398.  
  399.     SetPort( savePort );
  400. }
  401.  
  402. // this is a callback tourine called by the Toolbox Control Manager
  403. // move the scroll bar thumb and scroll the text accordingly
  404.  
  405. static pascal void ScrollProc ( ControlRef bar, ControlPartCode partCode )
  406. {
  407.     SInt32 value, step ;
  408.  
  409.     if ( partCode == kControlNoPart )
  410.     {
  411.         return ;
  412.     }
  413.  
  414.     value = LCGetValue ( bar ) ;
  415.     step = sScrollStep ;
  416.  
  417.     if ( ( ( value < LCGetMax ( bar ) ) && ( step > 0 ) ) ||
  418.          ( ( value > 0 ) && ( step < 0 ) ) )
  419.     {
  420.         LCSetValue ( bar, value + step ) ;
  421.         ScrollBarChanged ( FrontWindow ( ) ) ;
  422.     }
  423. }
  424.  
  425. static void    DoScrollBar( Point hitPt, EventModifiers modifiers, WindowRef window )
  426. {
  427.     DocumentHandle        hDocument;
  428.     ControlRef            bar = nil;
  429.     LongRect            viewRect;
  430.     ControlPartCode        partCode;
  431.     SInt32                pageSize;
  432.     SInt32                step = 0;
  433.  
  434. #ifdef __cplusplus
  435.     static ControlActionUPP sScrollerUPP = NewControlActionProc( ScrollProc );
  436. #else
  437.     static ControlActionUPP sScrollerUPP = nil;
  438.     if (sScrollerUPP == nil)
  439.     {
  440.         sScrollerUPP = NewControlActionProc( ScrollProc );
  441.     }
  442. #endif
  443.  
  444.     hDocument = GetWindowDocument( window );
  445.     WEGetViewRect( &viewRect, (*hDocument)->we );
  446.  
  447.     //    find out which control was hit (if any) and in which part
  448.     partCode = FindControl( hitPt, window, &bar );
  449.  
  450.     //    if any control was hit, it must be one of our two scroll bars:
  451.     //    find out which and calculate the page size for it
  452.     if ( bar == (*hDocument)->scrollBars[ v ] )
  453.     {
  454.         pageSize = viewRect.bottom - viewRect.top;
  455.     }
  456.     else if ( bar == (*hDocument)->scrollBars[ h ] )
  457.     {
  458.         pageSize = viewRect.right - viewRect.left;
  459.     }
  460.     else
  461.     {
  462.         return;        // return immediately if none of our scrollbars was hit
  463.     }
  464.  
  465.     //    dispatch on partCode
  466.     switch ( partCode )
  467.     {
  468.         case kControlIndicatorPart:
  469.             // click in thumb: call TrackControl with no actionProc and adjust text
  470.             TrackControl( bar, hitPt, nil );
  471.             LCSynch( bar );
  472.             ScrollBarChanged( window );
  473.             return;
  474.  
  475.         case kControlUpButtonPart:
  476.             step = - ( ( modifiers & optionKey ) ? 1 : kScrollDelta );
  477.             break;
  478.  
  479.         case kControlDownButtonPart:
  480.             step = + ( ( modifiers & optionKey ) ? 1 : kScrollDelta );
  481.             break;
  482.  
  483.         case kControlPageUpPart:
  484.             step = - ( pageSize - kScrollDelta );
  485.             break;
  486.  
  487.         case kControlPageDownPart:
  488.             step = + ( pageSize - kScrollDelta );
  489.             break;
  490.  
  491.     }    // switch
  492.  
  493.     //    save step in a static variable for our ScrollProc callback
  494.     sScrollStep = step;
  495.  
  496.     //    track the mouse
  497.     TrackControl( bar, hitPt, sScrollerUPP );
  498. }
  499.  
  500. /*
  501.     This is a callback routine called whenever the text is scrolled automaticall.
  502.     Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE
  503.     in many different circumstances, and we want to be notified when this happens
  504.     so we can adjust the scroll bars
  505. */
  506.  
  507. static pascal void TextScrolled ( WEReference we )
  508. {
  509.     WindowRef window = nil ;
  510.  
  511.     //    retrieve the window pointer stored in the WE instance as a "reference constant"
  512.     if ( WEGetInfo( weRefCon, & window, we ) != noErr )
  513.     {
  514.         return ;
  515.     }
  516.  
  517.     //    make sure the scroll bars are in synch with the destination rectangle
  518.     AdjustBars ( window ) ;
  519. }
  520.  
  521. Boolean    DoContent ( Point hitPt, const EventRecord * event, WindowRef window )
  522. {
  523.     WEReference        we = GetWindowWE ( window ) ;
  524.     Rect            textRect ;
  525.     GrafPtr            savePort ;
  526.     Boolean            isMyClick = false ;
  527.  
  528.     //    set up the port
  529.     GetPort ( & savePort ) ;
  530.     SetPortWindowPort ( window ) ;
  531.  
  532.     //    convert the point to local coordinates
  533.     GlobalToLocal ( & hitPt ) ;
  534.  
  535.     //    a click in an inactive window should normally activate it,
  536.     //    but the availability of the Drag Manager introduces an exception to this rule:
  537.     //    a click in the background selection may start a drag gesture,
  538.     //    without activating the window
  539.  
  540.     if ( IsWindowHilited ( window ) )
  541.     {
  542.         isMyClick = true ;            //    active window -> always handle click
  543.     }
  544.     else if ( gHasDragAndDrop )
  545.     {
  546.         SInt32 selStart, selEnd ;
  547.         RgnHandle selRgn ;
  548.  
  549.         WEGetSelection ( & selStart, & selEnd, we ) ;
  550.         selRgn = WEGetHiliteRgn ( selStart, selEnd, we ) ;
  551.         isMyClick = PtInRgn ( hitPt, selRgn ) && WaitMouseMoved ( event -> where ) ;
  552.         DisposeRgn ( selRgn ) ;
  553.     }
  554.  
  555.     if ( isMyClick )
  556.     {
  557.         CalcTextRect ( window, & textRect ) ;
  558.  
  559.         if ( PtInRect ( hitPt, & textRect ) )
  560.         {
  561.             WEClick ( hitPt, event -> modifiers, event -> when, we ) ;
  562.         }
  563.         else
  564.         {
  565.             DoScrollBar ( hitPt, event -> modifiers, window ) ;
  566.         }
  567.     }
  568.  
  569.     //    restore the port
  570.     SetPort ( savePort ) ;
  571.  
  572.     //    return true if the click should activate this window
  573.     return ! isMyClick ;
  574. }
  575.  
  576. static void    DoScrollKey ( SInt16 keyCode, WindowRef window )
  577. {
  578.     DocumentHandle        hDocument ;
  579.     ControlRef            bar ;
  580.     SInt32                value ;
  581.     LongRect            viewRect ;
  582.  
  583.     hDocument = GetWindowDocument ( window ) ;
  584.     bar = ( * hDocument ) -> scrollBars [ v ] ;
  585.  
  586.     //    get current scroll bar value
  587.     value = LCGetValue ( bar ) ;
  588.  
  589.     //    get text view rect
  590.     WEGetViewRect ( & viewRect, ( * hDocument ) -> we ) ;
  591.  
  592.     switch ( keyCode )
  593.     {
  594.  
  595.         case keyPgUp:
  596.             value -= ( viewRect . bottom - viewRect . top ) - kScrollDelta ;
  597.             break ;
  598.  
  599.         case keyPgDn:
  600.             value += ( viewRect . bottom - viewRect . top ) - kScrollDelta ;
  601.             break ;
  602.  
  603.         case keyHome:
  604.             value = 0 ;
  605.             break ;
  606.  
  607.         case keyEnd:
  608.             value = LONG_MAX ;
  609.             break ;
  610.     }    // switch
  611.  
  612.     //    set the new scroll bar value and scroll the text pane accordingly
  613.  
  614.     LCSetValue ( bar, value ) ;
  615.     ScrollBarChanged ( window ) ;
  616. }
  617.  
  618. void DoKey ( SInt16 key, const EventRecord * event )
  619. {
  620.     WindowRef window ;
  621.     SInt16 keyCode ;
  622.  
  623.     //    do nothing if no window is active
  624.     if ( ( window = FrontWindow ( ) ) == nil )
  625.         return;
  626.  
  627.     //    extract virtual key code from event record
  628.     keyCode = ( event->message & keyCodeMask ) >> 8 ;
  629.  
  630.     // page movement keys are handled by DoScrollKey()
  631.     switch ( keyCode )
  632.     {
  633.         case keyPgUp:
  634.         case keyPgDn:
  635.         case keyHome:
  636.         case keyEnd:
  637.             DoScrollKey ( keyCode, window ) ;
  638.             break ;
  639.  
  640.         default:
  641.             WEKey ( key, event -> modifiers, GetWindowWE (window) ) ;
  642.             break ;
  643.     }
  644. }
  645.  
  646. void DoUpdate ( WindowRef window )
  647. {
  648.     GrafPtr        savePort ;
  649.     RgnHandle    updateRgn ;
  650.  
  651.     // if we have no windows, there's nothing to update!
  652.     if ( window == nil )
  653.     {
  654.         return ;
  655.     }
  656.  
  657.     // save the old drawing port
  658.     GetPort ( & savePort ) ;
  659.     SetPortWindowPort ( window ) ;
  660.  
  661.     // notify everything that we're doing an update.
  662.     BeginUpdate ( window ) ;
  663.  
  664.     // BeginUpdate sets the window port visRgn to the region to update
  665.     updateRgn = GetWindowPort ( window ) -> visRgn ;
  666.  
  667.     if ( ! EmptyRgn ( updateRgn ) )    // if it's not an empty region, let's update it!
  668.     {
  669.         // erase the update region
  670.         EraseRgn ( updateRgn ) ;
  671.  
  672.         //    draw scroll bars
  673.         UpdateControls ( window, updateRgn ) ;
  674.  
  675.         //    draw grow icon
  676.         MyDrawGrowIcon ( window, false ) ;
  677.  
  678.         //    draw text
  679.         WEUpdate ( updateRgn, GetWindowWE ( window ) ) ;
  680.     }
  681.  
  682.     // tell everything we're done updating
  683.     EndUpdate ( window ) ;
  684.  
  685.     // restore the old graphics port
  686.     SetPort ( savePort ) ;
  687. }
  688.  
  689. void DoActivate ( Boolean isActivating, WindowRef window )
  690. {
  691.     DocumentHandle        hDocument ;
  692.     WEReference            we ;
  693.     GrafPtr                savePort ;
  694.     Rect                barRect ;
  695.     ControlPartCode        barHilite ;
  696.     SInt16                menuID ;
  697.     VHSelect            axis ;
  698.  
  699.     // if this is not one of our document windows, nothing to do here...
  700.     if ( ( hDocument = GetWindowDocument ( window ) ) == nil )
  701.     {
  702.         return ;
  703.     }
  704.     we = ( * hDocument ) -> we ;
  705.  
  706.     //    sanity check: do nothing if required activation state
  707.     //    is the same as the current activation state
  708.     if ( isActivating == WEIsActive ( we ) )
  709.     {
  710.         return ;
  711.     }
  712.  
  713.     //     set up the port
  714.     GetPort ( & savePort ) ;
  715.     SetPortWindowPort ( window ) ;
  716.  
  717.     // activate or deactivate the text (and any other relevant stuff) depending on just
  718.     // what we're doing here...
  719.     if ( isActivating )
  720.     {
  721.         WEActivate ( we ) ;
  722.         barHilite = kControlNoPart ;
  723.     }
  724.     else
  725.     {
  726.         WEDeactivate ( we ) ;
  727.         barHilite = kControlDisabledPart ;
  728.     }
  729.  
  730.     //    redraw the grow icon (and validate its rect)
  731.     MyDrawGrowIcon ( window, true ) ;
  732.  
  733.     //    redraw the scroll bars with the new highlighting (and validate their rects)
  734.     for ( axis = v ; axis <= h ; axis ++ )
  735.     {
  736.         HiliteControl ( ( * hDocument ) -> scrollBars [ axis ], barHilite ) ;
  737.         CalcScrollBarRect ( window, axis, & barRect ) ;
  738.         ValidRect ( & barRect ) ;
  739.     }
  740.  
  741.     //    if activating, undim text-related menus
  742.     if ( isActivating )
  743.     {
  744.         for ( menuID = kMenuEdit ; menuID <= kMenuFeatures ; menuID ++ )
  745.         {
  746.             EnableItem ( GetMenuHandle ( menuID ), 0 ) ;
  747.         }
  748.     }
  749.  
  750.     // invalidate the menu bar
  751.     InvalMenuBar ( ) ;
  752.  
  753.     // restore the old graphics port..
  754.     SetPort ( savePort ) ;
  755. }
  756.  
  757. OSErr CreateWindow ( const FSSpec * pFileSpec )
  758. {
  759.     DocumentHandle    hDocument = nil ;
  760.     WindowRef        window = nil ;
  761.     AliasHandle        alias = nil ;
  762.     WEReference        we = nil ;
  763.     ControlRef        bar = nil ;
  764.     FInfo            fileInfo ;
  765.     Rect            textRect ;
  766.     LongRect        lr ;
  767.     VHSelect        axis ;
  768.     OSErr            err ;
  769.  
  770. #ifdef __cplusplus
  771.     static WEScrollUPP sScrollerUPP = NewWEScrollProc ( TextScrolled ) ;
  772. #else
  773.     static WEScrollUPP sScrollerUPP = nil ;
  774.     if ( sScrollerUPP == nil )
  775.     {
  776.         sScrollerUPP = NewWEScrollProc ( TextScrolled ) ;
  777.     }
  778. #endif
  779.  
  780.     //    allocate a relocateable block to hold a document record
  781.     hDocument = ( DocumentHandle ) NewHandleClear ( sizeof ( DocumentRecord ) ) ;
  782.     if ( ( err = MemError( ) ) != noErr )
  783.     {
  784.         goto cleanup ;
  785.     }
  786.  
  787.     //    create the window from a 'WIND' template: the window is initially invisible
  788.     //    if ColorQuickDraw is available, create a color window
  789.     if ( gHasColorQD )
  790.     {
  791.         window = GetNewCWindow ( kWindowTemplateID, nil, ( WindowRef ) -1L ) ;
  792.     }
  793.     else
  794.     {
  795.         window = GetNewWindow ( kWindowTemplateID, nil, ( WindowRef ) -1L ) ;
  796.     }
  797.  
  798.     //    make sure we got a window
  799.     if ( window == nil )
  800.     {
  801.         err = memFullErr ;
  802.         goto cleanup ;
  803.     }
  804.  
  805.     // link the document record to the window and the other way around
  806.     SetWRefCon ( window, ( SInt32 ) hDocument ) ;
  807.     ( * hDocument ) -> owner = window ;
  808.  
  809.     // we got a window, so tell QuickDraw where to draw...
  810.     SetPortWindowPort ( window ) ;
  811.  
  812.     //    calculate the text rectangle
  813.     CalcTextRect ( window, & textRect ) ;
  814.     WERectToLongRect ( & textRect, & lr ) ;
  815.  
  816.     //    create a new WASTE instance
  817.     if ( ( err = WENew ( & lr, & lr, weDoAutoScroll +
  818.                                      weDoOutlineHilite +
  819.                                      weDoUndo +
  820.                                      weDoIntCutAndPaste +
  821.                                      weDoDragAndDrop +
  822.                                      weDoUseTempMem +
  823.                                      weDoDrawOffscreen, & we) ) != noErr )
  824.     {
  825.         goto cleanup ;
  826.     }
  827.  
  828.     //    save a reference to the window in the WE instance
  829.     if ( ( err = WESetInfo ( weRefCon, & window, we ) ) != noErr )
  830.     {
  831.         goto cleanup ;
  832.     }
  833.  
  834.     //    now the other way around:  save the WE reference in the document record
  835.     ( * hDocument ) -> we = we ;
  836.  
  837.     //    set up our scroll callback
  838.     if ( ( err = WESetInfo ( weScrollProc, & sScrollerUPP, we ) ) != noErr )
  839.     {
  840.         goto cleanup ;
  841.     }
  842.  
  843.     //    create the scroll bars from a control template
  844.     for ( axis = v ; axis <= h; axis ++ )
  845.     {
  846.         if ( ( bar = GetNewControl ( kScrollBarTemplateID, window ) ) == nil )
  847.         {
  848.             err = memFullErr ;
  849.             goto cleanup ;
  850.         }
  851.         HiliteControl ( bar, kControlDisabledPart ) ;
  852.  
  853.         //    attach a LongControl record to the scroll bar:  this allows us to use long
  854.         //    settings and thus scroll text taller than 32,767 pixels
  855.         if ( ( err = LCAttach ( bar ) ) != noErr )
  856.         {
  857.             goto cleanup;
  858.         }
  859.  
  860.         //    save control handle in the document record
  861.         ( * hDocument ) -> scrollBars [ axis ] = bar ;
  862.  
  863.     }    // for
  864.  
  865.     //    ViewChanged adjusts the scroll bars rectangles to the window frame
  866.     ViewChanged ( window ) ;
  867.  
  868.     //    if pFileSpec is not nil, it points to a file to read, so let's read it!
  869.     if ( pFileSpec != nil )
  870.     {
  871.         // turn the cursor into a wristwatch because this can be a lengthy operation
  872.         SetCursor ( * GetCursor ( watchCursor ) ) ;
  873.  
  874.         //    retrieve file infomation
  875.         if ( ( err = FSpGetFInfo ( pFileSpec, & fileInfo ) ) != noErr )
  876.         {
  877.             goto cleanup ;
  878.         }
  879.  
  880.         //    make sure we recognize the file type
  881.         if ( ( fileInfo . fdType != kTypeText ) && ( fileInfo . fdType != ftSimpleTextDocument ) )
  882.         {
  883.             err = badFileFormat ;
  884.             goto cleanup ;
  885.         }
  886.  
  887.         //    read in the file
  888.         if ( ( err = ReadTextFile ( pFileSpec, we ) ) != noErr )
  889.         {
  890.             goto cleanup ;
  891.         }
  892.  
  893.         //    set the window title to the file name
  894.         SetWTitle ( window, pFileSpec -> name ) ;
  895.  
  896.         //    create an alias to keep track of the file
  897.         if ( ( err = NewAlias ( nil, pFileSpec, & alias ) ) != noErr )
  898.         {
  899.             goto cleanup ;
  900.         }
  901.         ( * hDocument ) -> fileAlias = ( Handle ) alias ;
  902.  
  903.         //    if the file is a read-only file, go ahead and enable those flags
  904.         if ( fileInfo . fdType == ftSimpleTextDocument )
  905.         {
  906.             WEFeatureFlag ( weFReadOnly, weBitSet, we ) ;
  907.         }
  908.  
  909.         //    let's make sure the cursor is happy...
  910.         SetCursor ( & qd . arrow ) ;
  911.     }
  912.  
  913.     //    adjust scroll bar settings based on the total text height
  914.     AdjustBars ( window ) ;
  915.  
  916.     //    finally!  show the document window
  917.     ShowWindow ( window ) ;
  918.  
  919. cleanup:
  920.     if ( err != noErr )
  921.     {
  922.         ErrorAlert ( err ) ;
  923.     }
  924.     return err ;
  925. }
  926.  
  927. void DestroyWindow ( WindowRef window )
  928. {
  929.     DocumentHandle    hDocument ;
  930.     SInt16            menuID ;
  931.  
  932.     hDocument = GetWindowDocument ( window ) ;
  933.  
  934.     //    destroy the WASTE instance
  935.     WEDispose ( ( * hDocument ) -> we ) ;
  936.  
  937.     //    destory the LongControl records attached to the scroll bars
  938.     LCDetach ( ( * hDocument ) -> scrollBars [ v ] ) ;
  939.     LCDetach ( ( * hDocument ) -> scrollBars [ h ] ) ;
  940.  
  941.     //    dispose of the file alias, if any
  942.     ForgetHandle ( & ( ( * hDocument ) -> fileAlias ) ) ;
  943.  
  944.     //    destroy the window record and all associated data structures
  945.     DisposeWindow ( window ) ;
  946.  
  947.     //    finally, dispose of the document record
  948.     DisposeHandle ( ( Handle ) hDocument ) ;
  949.  
  950.     // adjust the menus to suit
  951.     for ( menuID = kMenuFont ; menuID <= kMenuFeatures ; menuID ++ )
  952.     {
  953.         DisableItem ( GetMenuHandle ( menuID ), 0 ) ;
  954.     }
  955.     InvalMenuBar ( ) ;
  956. }
  957.