home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / WASTE 1.1a4 / Demo Source / WEDemoWindows.p < prev   
Encoding:
Text File  |  1994-11-12  |  20.9 KB  |  834 lines  |  [TEXT/PJMM]

  1. unit DemoWindows;
  2.  
  3. { WASTE DEMO PROJECT: }
  4. { Window Handling }
  5.  
  6. { Copyright © 1993-1994 Merzwaren }
  7. { All Rights Reserved }
  8.  
  9. interface
  10.     uses
  11.         DemoIntf;
  12.  
  13.     procedure DoDrag (hitPt: Point;
  14.                                     window: WindowPtr);
  15.     procedure DoGrow (hitPt: Point;
  16.                                     window: WindowPtr);
  17.     procedure DoZoom (partCode: Integer;
  18.                                     window: WindowPtr);
  19.     procedure DoContent (hitPt: Point;
  20.                                     var event: EventRecord;
  21.                                     window: WindowPtr);
  22.     procedure DoKey (key: Char;
  23.                                     var event: EventRecord);
  24.     procedure DoUpdate (window: WindowPtr);
  25.     procedure DoActivate (activFlag: Boolean;
  26.                                     window: WindowPtr);
  27.     function CreateWindow (pFileSpec: FSSpecPtr): OSErr;
  28.     procedure DestroyWindow (window: WindowPtr);
  29.  
  30. implementation
  31.     uses
  32.         Aliases, LongControls, DemoFiles;
  33.  
  34.     var
  35.  
  36. { static variables }
  37.  
  38.         sScrollStep: Integer;                    { how many pixels to scroll (used by ScrollProc) }
  39.  
  40.     procedure MyDrawGrowIcon (wind: GrafPtr;
  41.                                     validate: Boolean);
  42. { the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon }
  43. { to the left and top margins of the window's content area }
  44. { these additional lines may create ugly dirt, so we use this routine to temporarily }
  45. { set the clip region to the grow icon rect }
  46. { in addition, if validate is TRUE, we call _ValidRect on the icon rect }
  47.         var
  48.             savePort: GrafPtr;
  49.             saveClip: RgnHandle;
  50.             r: Rect;
  51.     begin
  52.  
  53. { save port and set thePort to wind }
  54.         GetPort(savePort);
  55.         SetPort(wind);
  56.  
  57. { save the clip region }
  58.         saveClip := NewRgn;
  59.         GetClip(saveClip);
  60.  
  61. { calculate grow icon rect }
  62.         r.botRight := wind^.portRect.botRight;
  63.         r.top := r.bottom - (kBarWidth - 2);
  64.         r.left := r.right - (kBarWidth - 2);
  65.  
  66. { set clip region to grow icon rect }
  67.         ClipRect(r);
  68.  
  69. { call _DrawGrowIcon }
  70.         DrawGrowIcon(wind);
  71.  
  72. { if validate is TRUE, remove the grow icon rect from the update region }
  73.         if (validate) then
  74.             ValidRect(r);
  75.  
  76. { restore old clip region }
  77.         SetClip(saveClip);
  78.         DisposeRgn(saveClip);
  79.  
  80. { restore old port }
  81.         SetPort(savePort);
  82.  
  83.     end;  { MyDrawGrowIcon }
  84.  
  85.     procedure ScrollBarChanged (window: WindowPtr);
  86. { scroll text to reflect new scroll bar setting }
  87.         var
  88.             hWE: WEHandle;
  89.             viewRect, destRect: LongRect;
  90.     begin
  91.         hWE := DocumentPeek(window)^.hWE;
  92.         WEGetViewRect(viewRect, hWE);
  93.         WEGetDestRect(destRect, hWE);
  94.         WEScroll(viewRect.left - destRect.left - LCGetValue(DocumentPeek(window)^.scrollBars.h), viewRect.top - destRect.top - LCGetValue(DocumentPeek(window)^.scrollBars.v), hWE);
  95.     end;  { ScrollBarChanged }
  96.  
  97.     procedure AdjustBars (window: WindowPtr);
  98. { recalculate scroll bar settings based on the text total height and destination rectangle }
  99.         var
  100.             hWE: WEHandle;
  101.             savePort: GrafPtr;
  102.             viewRect, destRect: LongRect;
  103.             value: LongInt;
  104.             max: LongInt;
  105.             bar: ControlHandle;
  106.             axis: VHSelect;
  107.     begin
  108.         GetPort(savePort);
  109.         SetPort(window);
  110.  
  111. { get view and destination rectangle }
  112.         hWE := DocumentPeek(window)^.hWE;
  113.         WEGetViewRect(viewRect, hWE);
  114.         WEGetDestRect(destRect, hWE);
  115.  
  116. { do for each axis }
  117.         for axis := v to h do
  118.             begin
  119.  
  120. { get scroll bar handle }
  121.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  122.  
  123. { calculate new scroll bar settings }
  124.  
  125. { NOTE: (destRect.bottom - destRect.top) always equals the total text height because }
  126. { WASTE automatically updates destRect.bottom whenever line breaks are recalculated }
  127.  
  128.                 value := viewRect.topLeft.vh[axis] - destRect.topLeft.vh[axis];
  129.                 max := value + (destRect.botRight.vh[axis] - viewRect.botRight.vh[axis]);
  130.  
  131. { make sure max is always non-negative }
  132.                 if (max <= 0) then
  133.                     max := 0;
  134.  
  135. { reset the scroll bar }
  136.                 LCSetMax(bar, max);
  137.                 LCSetValue(bar, value);
  138.  
  139. { if value exceeds max then the bottom of the destination rectangle is above }
  140. { the bottom of the view rectangle: we need to scroll the text downward }
  141.                 if (value > max) then
  142.                     ScrollBarChanged(window);
  143.  
  144.             end;  { for axis }
  145.  
  146.         SetPort(savePort);
  147.  
  148.     end;  { AdjustBars }
  149.  
  150.     procedure ViewChanged (window: WindowPtr);
  151. { Fix its scroll bars and WE view rect when the window is created, }
  152. { or after it is resized or zoomed, or when the page is adjusted }
  153.         var
  154.             savePort: GrafPtr;
  155.             bar: ControlHandle;
  156.             barRects: array[VHSelect] of Rect;
  157.             r: Rect;
  158.             viewRect: LongRect;
  159.             axis: VHSelect;
  160.     begin
  161.  
  162.         GetPort(savePort);
  163.         SetPort(window);
  164.  
  165. { recalculate the correct rectangles for the text area and the scroll bars, }
  166. { based on the window's port rect }
  167.         with window^.portRect do
  168.             begin
  169.                 SetRect(barRects[v], right - (kBarWidth - 1), -1, right + 1, bottom - (kBarWidth - 2));
  170.                 SetRect(barRects[h], -1, bottom - (kBarWidth - 1), right - (kBarWidth - 2), bottom + 1);
  171.                 SetRect(r, 0, 0, right - (kBarWidth - 1), bottom - (kBarWidth - 1));
  172.                 InsetRect(r, kTextMargin, kTextMargin);
  173.                 WERectToLongRect(r, viewRect);
  174.             end;
  175.  
  176. { resize the text area }
  177.         WESetViewRect(viewRect, DocumentPeek(window)^.hWE);
  178.  
  179. { move and resize the control bars }
  180.         for axis := v to h do
  181.             begin
  182.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  183.                 r := barRects[axis];
  184.                 MoveControl(bar, r.left, r.top);
  185.                 SizeControl(bar, r.right - r.left, r.bottom - r.top);
  186.                 ValidRect(r);
  187.             end;  { for axis }
  188.  
  189. { reset thumb positions and the max values of the control bars }
  190.         AdjustBars(window);
  191.  
  192. { redraw the control bars }
  193.         ShowControl(DocumentPeek(window)^.scrollBars.v);
  194.         ShowControl(DocumentPeek(window)^.scrollBars.h);
  195.  
  196.         SetPort(savePort);
  197.  
  198.     end;  { ViewChanged }
  199.  
  200.     procedure DoDrag (hitPt: Point;
  201.                                     window: WindowPtr);
  202.         var
  203.             dragRect: Rect;
  204.     begin
  205.         dragRect := GetGrayRgn^^.rgnBBox;
  206.         DragWindow(window, hitPt, dragRect);
  207.     end;  { DoDrag }
  208.  
  209.     procedure Resize (newSize: Point;
  210.                                     window: WindowPtr);
  211.         var
  212.             savePort: GrafPtr;
  213.             viewRect: LongRect;
  214.             r: Rect;
  215.             tempRgn, dirtyRgn: RgnHandle;
  216.     begin
  217.  
  218.         GetPort(savePort);
  219.         SetPort(window);
  220.  
  221. { create temporary regions for calculations }
  222.         tempRgn := NewRgn;
  223.         dirtyRgn := NewRgn;
  224.  
  225. { save old text region }
  226.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  227.         WELongRectToRect(viewRect, r);
  228.         RectRgn(tempRgn, r);
  229.  
  230. { erase the old grow icon rect }
  231.         r.botRight := window^.portRect.botRight;
  232.         r.top := r.bottom - (kBarWidth - 2);
  233.         r.left := r.right - (kBarWidth - 2);
  234.         EraseRect(r);
  235.  
  236. { hide the scroll bars }
  237.         HideControl(DocumentPeek(window)^.scrollBars.v);
  238.         HideControl(DocumentPeek(window)^.scrollBars.h);
  239.  
  240. { perform the actual resizing of window, redraw scroll bars and grow icon}
  241.         SizeWindow(window, newSize.h, newSize.v, false);
  242.         ViewChanged(window);
  243.         MyDrawGrowIcon(window, true);
  244.  
  245. { calculate the dirty region (to be updated) }
  246.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  247.         WELongRectToRect(viewRect, r);
  248.         RectRgn(dirtyRgn, r);
  249.         XOrRgn(dirtyRgn, tempRgn, dirtyRgn);
  250.         with window^.portRect do
  251.             SetRectRgn(tempRgn, left, top, right - (kBarWidth - 1), bottom - (kBarWidth - 1));
  252.         SectRgn(dirtyRgn, tempRgn, dirtyRgn);
  253.  
  254. { mark the dirty region as invalid }
  255.         InvalRgn(dirtyRgn);
  256.  
  257. { throw away temporary regions }
  258.         DisposeRgn(tempRgn);
  259.         DisposeRgn(dirtyRgn);
  260.  
  261.         SetPort(savePort);
  262.  
  263.     end;  { Resize }
  264.  
  265.     procedure DoGrow (hitPt: Point;
  266.                                     window: WindowPtr);
  267.         const
  268.             kMinWindowWidth = 200;
  269.             kMinWindowHeight = 80;
  270.         var
  271.             sizeRect: Rect;
  272.             newSize: LongInt;
  273.     begin
  274.         SetRect(sizeRect, kMinWindowWidth, kMinWindowHeight, maxint, maxint);
  275.         newSize := GrowWindow(window, hitPt, sizeRect);
  276.         if (newSize <> 0) then
  277.             Resize(Point(newSize), window);
  278.     end;  { DoGrow }
  279.  
  280.     procedure DoZoom (partCode: Integer;
  281.                                     window: WindowPtr);
  282.         var
  283.             savePort: GrafPtr;
  284.             viewRect: LongRect;
  285.             textRect: Rect;
  286.     begin
  287.  
  288.         GetPort(savePort);
  289.         SetPort(window);
  290.  
  291.         EraseRect(window^.portRect);
  292.         HideControl(DocumentPeek(window)^.scrollBars.v);
  293.         HideControl(DocumentPeek(window)^.scrollBars.h);
  294.         ZoomWindow(window, partCode, false);
  295.         ViewChanged(window);
  296.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  297.         WELongRectToRect(viewRect, textRect);
  298.         InvalRect(textRect);
  299.  
  300.         SetPort(savePort);
  301.  
  302.     end;  { DoZoom }
  303.  
  304.     procedure ScrollProc (bar: ControlHandle;
  305.                                     partCode: Integer);
  306.  
  307. { this is a callback routine called by the Toolbox Control Manager }
  308. { move the scroll bar thumb and scroll the text accordingly }
  309.  
  310.         var
  311.             value, step: LongInt;
  312.     begin
  313.  
  314.         if (partCode = 0) then
  315.             Exit(ScrollProc);
  316.  
  317.         value := LCGetValue(bar);
  318.         step := sScrollStep;
  319.  
  320.         if ((value < LCGetMax(bar)) and (step > 0)) or ((value > 0) and (step < 0)) then
  321.             begin
  322.                 LCSetValue(bar, value + step);
  323.                 ScrollBarChanged(FrontWindow);
  324.             end;
  325.     end;  { ScrollProc }
  326.  
  327.     procedure DoScrollBar (hitPt: Point;
  328.                                     modifiers: Integer;
  329.                                     window: WindowPtr);
  330.         var
  331.             bar: ControlHandle;
  332.             viewRect: LongRect;
  333.             axis: VHSelect;
  334.             partCode, step: Integer;
  335.     begin
  336.  
  337. { find out which scroll bar was hit (if any) and in which part }
  338.         partCode := FindControl(hitPt, window, bar);
  339.  
  340.         if (bar <> nil) then
  341.  
  342. { dispatch on partCode }
  343.             if (partCode = inThumb) then
  344.                 begin
  345.  
  346. { click in thumb: call TrackControl with no actionProc and adjust text }
  347.                     partCode := TrackControl(bar, hitPt, nil);
  348.                     LCSynch(bar);
  349.                     ScrollBarChanged(window);
  350.  
  351.                 end
  352.             else
  353.                 begin
  354.  
  355. { click in a bar, but not in thumb }
  356. { which scroll bar was hit? }
  357.                     if (bar = DocumentPeek(window)^.scrollBars.v) then
  358.                         axis := v
  359.                     else
  360.                         axis := h;
  361.  
  362. { get text view rectangle }
  363.                     WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  364.  
  365. { dispatch on partCode }
  366.                     case partCode of
  367.  
  368.                         inUpButton: 
  369.                             if (BitAnd(modifiers, optionKey) = 0) then
  370.                                 step := -kScrollDelta
  371.                             else
  372.                                 step := -1;
  373.  
  374.                         inDownButton: 
  375.                             if (BitAnd(modifiers, optionKey) = 0) then
  376.                                 step := +kScrollDelta
  377.                             else
  378.                                 step := +1;
  379.  
  380.                         inPageUp: 
  381.                             step := -(viewRect.botRight.vh[axis] - viewRect.topLeft.vh[axis]) + kScrollDelta;
  382.  
  383.                         inPageDown: 
  384.                             step := (viewRect.botRight.vh[axis] - viewRect.topLeft.vh[axis]) - kScrollDelta;
  385.  
  386.                         otherwise
  387.                             step := 0;
  388.                     end;  { case }
  389.  
  390. { save step in a static variable for our ScrollProc callback }
  391.                     sScrollStep := step;
  392.  
  393. { track the mouse }
  394.                     partCode := TrackControl(bar, hitPt, @ScrollProc);
  395.  
  396.                 end;
  397.     end;  { DoScrollBar }
  398.  
  399.     function ClickLoop (hWE: WEHandle): Boolean;
  400.  
  401. { this is a callback routine repeatedly called by WEClick while tracking the mouse }
  402. { if the mouse goes out of the text rect, scroll the text and adjust the scroll bars }
  403.  
  404.         var
  405.             window: WindowPtr;
  406.             textRect: LongRect;
  407.             mouseLoc: Point;
  408.             bar: ControlHandle;
  409.             oldValue: LongInt;
  410.             delta: Integer;
  411.             axis: VHSelect;
  412.     begin
  413.  
  414. { return TRUE so WEClick keeps tracking the mouse }
  415.         ClickLoop := true;
  416.  
  417. { retrieve the window pointer stored in the WE instance as a "reference constant" }
  418.         if (WEGetInfo(weRefCon, @window, hWE) <> noErr) then
  419.             Exit(ClickLoop);
  420.  
  421. { get text rect and mouse location (in local coords) }
  422.         WEGetViewRect(textRect, hWE);
  423.         GetMouse(mouseLoc);
  424.  
  425.         for axis := v to h do
  426.             begin
  427.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  428.                 oldValue := LCGetValue(bar);
  429.                 delta := mouseLoc.vh[axis] - textRect.botRight.vh[axis];
  430.                 if (delta > 0) then
  431.                     begin
  432.                         if (oldValue < LCGetMax(bar)) then
  433.                             LCSetValue(bar, oldValue + kScrollDelta);
  434.                     end
  435.                 else
  436.                     begin
  437.                         delta := textRect.topLeft.vh[axis] - mouseLoc.vh[axis];
  438.                         if (delta > 0) then
  439.                             begin
  440.                                 if (oldValue > 0) then
  441.                                     LCSetValue(bar, oldValue - kScrollDelta);
  442.                             end;
  443.                     end;
  444.             end;  { for axis }
  445.  
  446. { scroll the text to match current scroll bar settings }
  447.         ScrollBarChanged(window);
  448.  
  449.     end;  { ClickLoop }
  450.  
  451.     procedure TextScrolled (hWE: WEHandle);
  452.  
  453. { This is a callback routine called whenever the text is scrolled automatically. }
  454. { Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE }
  455. { in many different circumstances, and we want to be notified when this happens }
  456. { so we can adjust the scroll bars }
  457.  
  458.         var
  459.             window: WindowPtr;
  460.     begin
  461.  
  462. { retrieve the window pointer stored in the WE instance as a "reference constant" }
  463.         if (WEGetInfo(weRefCon, @window, hWE) <> noErr) then
  464.             Exit(TextScrolled);
  465.  
  466. { make sure scroll bars are in synch with the destination rectangle }
  467.         AdjustBars(window);
  468.  
  469.     end;  { TextScrolled }
  470.  
  471.     procedure DoContent (hitPt: Point;
  472.                                     var event: EventRecord;
  473.                                     window: WindowPtr);
  474.         var
  475.             selStart, selEnd: LongInt;
  476.             selRgn: RgnHandle;
  477.             handleClick: Boolean;
  478.             viewRect: LongRect;
  479.             textRect: Rect;
  480.             savePort: GrafPtr;
  481.     begin
  482.  
  483. { set the port to our window's port }
  484.         GetPort(savePort);
  485.         SetPort(window);
  486.  
  487. { convert the point to local coordinates }
  488.         GlobalToLocal(hitPt);
  489.  
  490. { a click in an inactive window should normally activate it, }
  491. { but the availability of the Drag Manager introduces an exception to this rule: }
  492. { a click in the background selection may start a drag gesture, }
  493. { without activating the window }
  494.  
  495.         if (FrontWindow <> window) then
  496.             if (gHasDragAndDrop) then
  497.                 begin
  498.                     WEGetSelection(selStart, selEnd, DocumentPeek(window)^.hWE);
  499.                     selRgn := WEGetHiliteRgn(selStart, selEnd, DocumentPeek(window)^.hWE);
  500.                     handleClick := PtInRgn(hitPt, selRgn) & WaitMouseMoved(event.where);
  501.                     DisposeRgn(selRgn);
  502.                 end
  503.             else
  504.                 handleClick := false            { no Drag Manager: never click-through }
  505.         else
  506.             handleClick := true;                { window is frontmost; always handle click }
  507.  
  508.         if (handleClick) then
  509.             begin
  510.  
  511. { get view rectangle in short coordinates }
  512.                 WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  513.                 WELongRectToRect(viewRect, textRect);
  514.  
  515.                 if PtInRect(hitPt, textRect) then
  516.                     WEClick(hitPt, event.modifiers, event.when, DocumentPeek(window)^.hWE)
  517.                 else
  518.                     DoScrollBar(hitPt, event.modifiers, window);
  519.  
  520.             end
  521.         else
  522.             SelectWindow(window);
  523.  
  524. { restore the port }
  525.         SetPort(savePort);
  526.  
  527.     end;  { DoContent }
  528.  
  529.     procedure DoScrollKey (keyCode: SignedByte;
  530.                                     window: WindowPtr);
  531.         var
  532.             bar: ControlHandle;
  533.             v: LongInt;
  534.             viewRect: LongRect;
  535.     begin
  536.         bar := DocumentPeek(window)^.scrollBars.v;
  537.  
  538. { do nothing if the scroll bar isn't active }
  539.         if (bar^^.contrlHilite <> kCtlActive) then
  540.             Exit(DoScrollKey);
  541.  
  542. { get current scroll bar value }
  543.         v := LCGetValue(bar);
  544.  
  545. { get text view rect }
  546.         WEGetViewRect(viewRect, DocumentPeek(window)^.hWE);
  547.  
  548.         case keyCode of
  549.  
  550.             keyPgUp: 
  551.                 v := v - (viewRect.bottom - viewRect.top) + kScrollDelta;
  552.  
  553.             keyPgDn: 
  554.                 v := v + (viewRect.bottom - viewRect.top) - kScrollDelta;
  555.  
  556.             keyHome: 
  557.                 v := 0;
  558.  
  559.             keyEnd: 
  560.                 v := maxLongInt;
  561.  
  562.             otherwise
  563.                 ;
  564.         end;  { case }
  565.  
  566. { set the new scroll bar value and scroll the text pane accordingly }
  567.         LCSetValue(bar, v);
  568.         ScrollBarChanged(window);
  569.  
  570.     end;  { DoScrollKey }
  571.  
  572.     procedure DoKey (key: Char;
  573.                                     var event: EventRecord);
  574.         var
  575.             window: WindowPtr;
  576.             keyCode: SignedByte;
  577.     begin
  578.         window := FrontWindow;
  579.  
  580. { do nothing if no window is active }
  581.         if (window = nil) then
  582.             Exit(DoKey);
  583.  
  584. { extract virtual key code from event record }
  585.         keyCode := BSR(BAND(event.message, keyCodeMask), 8);
  586.  
  587. { page movement keys are handled by DoScrollKey }
  588.         if (keyCode in [keyPgUp, keyPgDn, keyHome, keyEnd]) then
  589.             DoScrollKey(keyCode, window)
  590.         else
  591.             WEKey(key, event.modifiers, DocumentPeek(window)^.hWE);
  592.  
  593.     end;  { DoKey }
  594.  
  595.     procedure DoUpdate (window: WindowPtr);
  596.         var
  597.             savePort: GrafPtr;
  598.             updateRgn: RgnHandle;
  599.     begin
  600.         GetPort(savePort);
  601.         SetPort(window);
  602.         BeginUpdate(window);
  603.  
  604. { BeginUpdate sets the window visRgn to the region to update }
  605.         updateRgn := window^.visRgn;
  606.  
  607. { erase update region }
  608.         EraseRgn(updateRgn);
  609.  
  610. { draw scroll bars }
  611.         UpdateControls(window, updateRgn);
  612.  
  613. { draw grow icon }
  614.         MyDrawGrowIcon(window, false);
  615.  
  616. { draw text }
  617.         WEUpdate(updateRgn, DocumentPeek(window)^.hWE);
  618.  
  619.         EndUpdate(window);
  620.         SetPort(savePort);
  621.  
  622.     end;  { DoUpdate }
  623.  
  624.     procedure DoActivate (activFlag: Boolean;
  625.                                     window: WindowPtr);
  626.         var
  627.             savePort: GrafPtr;
  628.             bar: ControlHandle;
  629.             barHilite: Integer;
  630.             barRect: Rect;
  631.             axis: VHSelect;
  632.             menuID: Integer;
  633.     begin
  634.  
  635. { set up the port }
  636.         GetPort(savePort);
  637.         SetPort(window);
  638.  
  639.         if (activFlag) then
  640.             begin
  641.                 WEActivate(DocumentPeek(window)^.hWE);
  642.                 barHilite := kCtlActive;
  643.             end
  644.         else
  645.             begin
  646.                 WEDeactivate(DocumentPeek(window)^.hWE);
  647.                 barHilite := kCtlBackground;
  648.             end;
  649.  
  650. { redraw the grow icon (and validate its rect) }
  651.         MyDrawGrowIcon(window, true);
  652.  
  653. { redraw the scroll bars with the new highlighting (and validate their rects) }
  654.         for axis := v to h do
  655.             begin
  656.                 bar := DocumentPeek(window)^.scrollBars.vh[axis];
  657.                 HiliteControl(bar, barHilite);
  658.                 barRect := bar^^.contrlRect;
  659.                 ValidRect(barRect);
  660.             end;
  661.  
  662. { dim or undim text-related menus }
  663.         for menuID := kMenuEdit to kMenuAlignment do
  664.             if (activFlag) then
  665.                 EnableItem(GetMHandle(menuID), 0)
  666.             else
  667.                 DisableItem(GetMHandle(menuID), 0);
  668.  
  669. { invalidate the menu bar }
  670.         InvalMenuBar;
  671.  
  672. { restore the port }
  673.         SetPort(savePort);
  674.  
  675.     end;  { DoActivate }
  676.  
  677.     function CreateWindow (pFileSpec: FSSpecPtr): OSErr;
  678.         var
  679.             pWRecord: Ptr;
  680.             window: WindowPtr;
  681.             hWE: WEHandle;
  682.             bar: ControlHandle;
  683.             axis: VHSelect;
  684.             fileInfo: FInfo;
  685.             fileRefNum: Integer;
  686.             textRect: Rect;
  687.             longTextRect: LongRect;
  688.             callback: ProcPtr;
  689.  
  690.         procedure CheckErr (err: OSErr);
  691.         begin
  692.             if (err <> noErr) then
  693.                 begin
  694.                     CreateWindow := err;
  695.                     ErrorAlert(err);
  696.  
  697. { here we should destroy partially allocated data structures to avoid memory leaks }
  698. { but, hey, this is just a demo, not a real-world application }
  699.                     Exit(CreateWindow);
  700.                 end;
  701.         end;  { CheckErr }
  702.  
  703.     begin
  704.         CreateWindow := noErr;
  705.  
  706. { allocate a non-relocatable block to hold a document record }
  707.         pWRecord := NewPtrClear(SizeOf(DocumentRecord));
  708.         CheckErr(MemError);
  709.  
  710. { create the window from a 'WIND' template; the window is initially invisible }
  711. { if Color QuickDraw is available, create a color window }
  712.         if (gHasColorQD) then
  713.             window := GetNewCWindow(kWindowTemplateID, pWRecord, WindowPtr(-1))
  714.         else
  715.             window := GetNewWindow(kWindowTemplateID, pWRecord, WindowPtr(-1));
  716.  
  717. { make sure we got a window }
  718.         if (window = nil) then
  719.             begin
  720.                 DisposePtr(pWRecord);
  721.                 CheckErr(memFullErr);
  722.             end;
  723.  
  724. { calculate the text rectangle }
  725.         textRect := window^.portRect;
  726.         textRect.right := textRect.right - (kBarWidth - 1);
  727.         textRect.bottom := textRect.bottom - (kBarWidth - 1);
  728.         InsetRect(textRect, kTextMargin, kTextMargin);
  729.         WERectToLongRect(textRect, longTextRect);
  730.  
  731. { before calling WENew, set the port to gWindow, }
  732. { so the WE instance knows where to draw }
  733.         SetPort(window);
  734.  
  735. { create the WE instance, enabling certain features }
  736.         CheckErr(WENew(longTextRect, longTextRect, weDoAutoScroll + weDoOutlineHilite + weDoIntCutAndPaste + weDoUndo + weDoUseTempMem + weDoDrawOffscreen, hWE));
  737.  
  738. { save a reference to the window in the WE instance }
  739.         CheckErr(WESetInfo(weRefCon, @window, hWE));
  740.  
  741. { now the other way around: save the WE handle in the document record }
  742.         DocumentPeek(window)^.hWE := hWE;
  743.  
  744. { set up our callbacks }
  745.         callback := @ClickLoop;
  746.         CheckErr(WESetInfo(weClickLoop, @callback, hWE));
  747.         callback := @TextScrolled;
  748.         CheckErr(WESetInfo(weScrollProc, @callback, hWE));
  749.         callback := @TranslateDrag;
  750.         CheckErr(WESetInfo(weTranslateDragHook, @callback, hWE));
  751.  
  752.         for axis := v to h do
  753.             begin
  754.  
  755. { create a scroll bar from a 'CNTL' template }
  756.                 bar := GetNewControl(kScrollBarTemplateID, window);
  757.                 if (bar = nil) then
  758.                     CheckErr(-1);
  759.                 HiliteControl(bar, kCtlBackground);
  760.  
  761. { attach a LongControl record to the scroll bar; this allows us to use long }
  762. { settings and thus to scroll text taller than 32,767 pixels }
  763.                 CheckErr(LCAttach(bar));
  764.  
  765. { save control handle in the document record }
  766.                 DocumentPeek(window)^.scrollBars.vh[axis] := bar;
  767.  
  768.             end;  { for axis }
  769.  
  770. { ViewChanged adjusts the scroll bars rectangles to the window frame }
  771.         ViewChanged(window);
  772.  
  773. { if pFileSpec is not NIL, it points to a file to read }
  774.         if (pFileSpec <> nil) then
  775.             begin
  776.  
  777. { turn the cursor into a wristwatch because this can be a lengthy operation }
  778.                 SetCursor(GetCursor(watchCursor)^^);
  779.  
  780. { retrieve file information }
  781.                 CheckErr(FSpGetFInfo(pFileSpec^, fileInfo));
  782.  
  783. { make sure we recognize the file type }
  784.                 if (fileInfo.fdType <> kTypeText) then
  785.                     CheckErr(-1);
  786.  
  787. { read in the file }
  788.                 CheckErr(ReadTextFile(pFileSpec, hWE));
  789.  
  790. { calculate line breaks }
  791.                 CheckErr(WECalText(hWE));
  792.  
  793. { set the window title to the file name }
  794.                 SetWTitle(window, pFileSpec^.name);
  795.  
  796. { create an alias to keep track of the file }
  797.                 CheckErr(NewAlias(nil, pFileSpec^, AliasHandle(DocumentPeek(window)^.fileAlias)));
  798.  
  799.             end;  { if pFileSpec <> NIL }
  800.  
  801. { adjust scroll bar settings based on the total text height }
  802.         AdjustBars(window);
  803.  
  804. { show the document window }
  805.         ShowWindow(window);
  806.  
  807.     end;  { CreateWindow }
  808.  
  809.     procedure DestroyWindow (window: WindowPtr);
  810.         var
  811.             menuID: Integer;
  812.     begin
  813.  
  814. { destroy the WE record }
  815.         WEDispose(DocumentPeek(window)^.hWE);
  816.  
  817. { destroy the LongControl records attached to the scroll bars }
  818.         LCDetach(DocumentPeek(window)^.scrollBars.v);
  819.         LCDetach(DocumentPeek(window)^.scrollBars.h);
  820.  
  821. { dispose of the file alias, if any }
  822.         ForgetHandle(DocumentPeek(window)^.fileAlias);
  823.  
  824. { destroy the window record and all associated data structures }
  825.         DisposeWindow(window);
  826.  
  827. { disable the text-editing menus }
  828.         for menuID := kMenuFont to kMenuAlignment do
  829.             DisableItem(GetMHandle(menuID), 0);
  830.         InvalMenuBar;
  831.  
  832.     end;  { DestroyWindow }
  833.  
  834. end.