home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MacStarter Pascal 1.0 / xWindows definition files / xWindow.p < prev   
Encoding:
Text File  |  1993-04-21  |  47.1 KB  |  1,355 lines  |  [TEXT/PJMM]

  1. unit xWindow;
  2.  
  3. { This unit defines the object type xWindows, which encapsulates much of the }
  4. { standard behavior of Macintosh Windows.  It is meant to be used as an abstract }
  5. { class.  A programmer can define a descendent class that adds functionality, such }
  6. { as graphics, text, or additional controls, to the basic behavior.   (An xWindow }
  7. { could also be used directly for simple applications.) }
  8. {      Also defined in this unit is the abstract class xWindowDecoration.  This }
  9. { represents things that can be added to windows.  For example, an instance of the }
  10. { descendent class xButton would be a button that the user could press.    Once }
  11. { installed in an xWindow, an xWindowDecoration can automatically receive and }
  12. { respond to events.   (You can directly use an xWindowDecoration to make a }
  13. { specific cursor appear over a rectangle in the window.) }
  14. {      This unit is meant to be used with the main program StandardMain.p, which }
  15. { includes an event loop that routes events to appropriate windows.  If the only }
  16. { windows used in your application are xWindows, you will not need to make any }
  17. { changes to the main program, except to add support for any menus or menu items }
  18. { that you add. }
  19. {       To open an use an xWindow, you should declare a variable VAR X: xWindow, }
  20. { allocate storage with NEW(X), then open the window with X.open or X.openInRect. }
  21. { As an alternative to the last step, you can set up the appearance of the window before }
  22. { opening it by calling X.setDefaults, then calling routines such as X.setFeatures to }
  23. { change the defaults, then calling X.doBasicOpen.  Note that X.doBasicOpen requires the }
  24. { values of certain instance variables to be set before it is called. }
  25. {       To define a subclass of xWindow, you should generally override one or both of the }
  26. { methods seDefaults and openInRect.  SetDefaults is the place to do any setup that is }
  27. { required before the window is opened; it should always be called at the beginning of }
  28. { openInRect.  OpenInRect should then call doBasicOpen to open the window; after this, }
  29. { it can make any modifications or additions to the window.  DoBasicOpen itself should }
  30. { not be modified. }
  31. {       The Macintosh ordinarily identifies windows by WindowPtr's.  Each xWindow }
  32. { corresponds to some windowPtr.  Sometimes, the Mac gives you only the windowPtr }
  33. { and you have to find the corresponding xWindow.  A function Window2xWindow is }
  34. { exported for this purpose. }
  35. {       The exported procedure InitXWindows should be called to initialize this unit; it }
  36. { is called in StandardMain, and need not be used elsewhrere. }
  37.  
  38.  
  39. interface
  40.  
  41. type
  42.  
  43.     windowFeatures = (hasGoAway, hasGrow, hasVScroll, hasHScroll, hasZoom, DAStyle);
  44.     windowFeatureSet = set of windowFeatures;
  45.  
  46.     xWindow = object
  47.  
  48.       { INSTANCE VARIABLES -- you should not use these directly }
  49.  
  50.             nextXWindow: xWindow;  { link to next window in list of open xWindows }
  51.             theWindow: WindowPtr;  { the refCon of this window contains a ref to this object }
  52.             userRef: longint;  { not used by xWindows system; available for any use }
  53.             features: windowFeatureSet;  { features this window has }
  54.             minSize, maxSize: point;  { specify min and max allowable sizes during a "Grow window" }
  55.             vScrollTopOffset, vScrollBottomOffset, hScrollLeftOffset, hScrollRightOffset: integer;
  56.                      { amount of space left at ends of scroll bars }
  57.             hLinesPerPage, vLinesPerPage: integer;  { clicking in the "page" area of a }
  58.                      { scroll bar is equivalent to clicking on an arrow this many times }
  59.             hPixelsPerLine, vPixelsPerLine: integer;
  60.             hScroll, vScroll: ControlHandle;  { the horizontal and vertical scroll bars }
  61.             decorations: xWindowDecoration;  { the "decorations" that have been installed in }
  62.                                                             { this window }
  63.  
  64.      { METHODS YOU ARE LIKELY TO OVERRIDE }
  65.  
  66.             procedure openInRect (title: string;
  67.                                         left, top, right, bottom: integer);
  68.                 { Open a window, with (top,left) as upper left corner and (bottom,right) }
  69.                 { as lower right corner of inside of window (excluding title bar). }
  70.                 { If the rectangle specified by top, left, right and bottom are empty (for }
  71.                 { example, is they are all empty), then the window will fill the screen. }
  72.                 { This default method simply calls SetDefaults, then calls doBasicOpen. }
  73.                 { You can define a descendent class of xWindow by redefining SetDefaults }
  74.                 { and/or openInRect, as described in the comments at the start of the UNIT. }
  75.             procedure open (title: string);
  76.                 { Opens a window.  Its width will be 3/4 of the screen width; its height 3/4 }
  77.                 { of the screen height, but not more than 2/3 of the width.  Each successive }
  78.                 { window will be offset from the previous one.  This method just calculates }
  79.                 {  the window rect, then calls openInRect, so in a descendent class, you only }
  80.                 { need to redefine openInRect. }
  81.             procedure SetDefaults;
  82.                 { This procedure is meant to be called in OpenInRect before the window is }
  83.                 { actually opened, to set up parameters that will be used in opening the }
  84.                 { window.  The default method calls SetFeatures, SetScrollOffsets,  }
  85.                 { SetMinMaxSize, and SetLinesPerPage.  If you want to change any of the }
  86.                 { defaults, or if you want to initialize any other instance variables, in a }
  87.                 { subclass of xWindows, you should override this method; call INHERITED }
  88.                 { SetDefaults, then make any changes or additions.  This could be used, for }
  89.                 { example, if you don't want a horizontal scroll bar in your window, or if you }
  90.                 { want to set a maximum window size.  }
  91.                 {      SHOULD NOT BE CALLED ONCE THE WINDOW IS OPENED.  xWindows does }
  92.                 { not support changing features on an open window. }
  93.             procedure doRedraw (badRect: Rect);
  94.                 { This is called when the contents of the window need to be redrawn, for }
  95.                 { example, when part of the window has been covered by a window which is }
  96.                 { then moved out of the way.  The parameter badRect is a rectangle that }
  97.                 { includes the part of the window that needs to be redrawn.  In most cases }
  98.                 { you can ignore this and draw the whole window, but in some case you might }
  99.                 { want to avoid unnecessary drawing.  The default method draws any }
  100.                 { xWindowDecorations that have been installed in the window. }
  101.                 { DoRedraw is also called during scrolling, unless you override the methods }
  102.                 { doHScroll and doVScroll.  If you have scroll bars, you will need to call }
  103.                 { GetHMax, GetVMax, GetHVal and GetVVal to determine which part of the }
  104.                 {total data needs to be redrawn. }
  105.             procedure doKey (ch: char;
  106.                                         modifiers: longint);
  107.                 { Called when the user types a character and this window is the front }
  108.                 { window.  The default method sends the keystroke to an xWindowDecoration. }
  109.                 { if appropriate.  The parameter Modifiers is a copy of the modifiers field }
  110.                 { of the event record, which can be used to determine whether the user was }
  111.                 { holding down the option or shift key when the key was pressed. }
  112.             procedure doContentClick (localPt: point;
  113.                                         modifiers: longint);
  114.                 { Called when the user clicks in the content area of the window.  This is NOT }
  115.                 { called when the user clicks in a scroll bar, grow box, etc.--such events are }
  116.                 { handled elsewhere.  The parameter Modifiers is a copy of the modifiers field }
  117.                 { of the event record which can be used to determine whether the user was }
  118.                 { pressing the command, shift, or option key when the mouse down occure. }
  119.                 { The default method sends the click to an xWindowDecoration if appropriate. }
  120.             procedure doClose;
  121.                 { Called when the window is being closed because the user clicks in the }
  122.                 { close box of the window.  You might also want to call it in response to a }
  123.                 { menu selection.  The default method disposes of any xWindowDecorations }
  124.                 { and of the horizontal and vertical scroll bars, then closes the window.  It does }
  125.                 { not dispose of the storage for the xWindow.  You can use DISPOSE to do so, }
  126.                 { or you can open a new window without using NEW on the variable again. }
  127.                 { You might want to override this, for example, to dispose of the data that }
  128.                 { specifies the contents of the window.  (Note however that the Mac toolbox }
  129.                 { procedure CloseWindow takes care of disposing of controls, such as }
  130.                 { buttons or check boxes. }
  131.             procedure doHScroll (dh: integer);
  132.             procedure doVScroll (dv: integer);
  133.                 { These are called when the user clicks in a scroll bar; they are called }
  134.                 { repeatedly as long as the user holds down the mouse button.  The parameters }
  135.                 { dh and dv specify the change the user has made in the value of the scroll }
  136.                 { bar.  The window contents must be drawn in response.  By default, the old }
  137.                 { contents are erased and  doRedraw is called.  If you are satisified with this, }
  138.                 { you don't have to redefine these.  However, the jerky visual appearance caused }
  139.                 { by erasing the whole window is not attractive. }
  140.             procedure AdjustToNewSize;
  141.                 { This is called when the window is resized (because of a doGrow or doZoom }
  142.                 { operation.  The default method resizes and repositions the scroll bars and any }
  143.                 { xWindowDecoration.  If you have added other stuff, you might need to adjust it. }
  144.                 { You will probably also need to set values associated with the scroll bars, }
  145.                 { such as HMax, VMax, HVal, VVal, LinesPerPage.  Call INHERITED AdjustToNewSize }
  146.                 { to move the scroll bar and decorations. }
  147.             procedure doActivate (active: boolean);
  148.                 { This is called when the window is activated or deactivated.  the default }
  149.                 { method hides the scroll bars on deactivation and shows them on reactivation. }
  150.                 { It also activates and deactivates xWindowDecorations. }
  151.             procedure idle;
  152.                 { This will ordinarily be called periodically while this is the front window. }
  153.                 { It can be called when there is no other event to be processed.  In some }
  154.                 { applications, you might want to call it even when this is not the front }
  155.                 { window.  A typically application is to call the ToolBox routine TEIdle when }
  156.                 { to blink the cursor in an active text edit.  The default routine sends idle }
  157.                 { messages to any xWindowDecorations that have been installed. }
  158.  
  159.     { METHODS FOR SETTING AND READING VALUES }
  160.  
  161.             procedure SetHMax (theMax: integer);
  162.             procedure SetVMax (theMax: integer);
  163.             procedure SetHVal (theVal: integer);
  164.             procedure SetVVal (theVal: integer);
  165.             function GetHMax: integer;
  166.             function GetVMax: integer;
  167.             function GetHVal: integer;
  168.             function GetVVal: integer;
  169.             procedure SetLinesPerPage (hPage, vPage: integer);
  170.                 { The values of the horizontal and vertical scroll bars go from zero to a }
  171.                 { user-specified maximum.  Methods are provided to set and read both the }
  172.                 { values and the maximums.  When the user clicks in the arrow of a scroll }
  173.                 { bar, the value changes by ±1.   When the user clicks in the gray area of }
  174.                 { the bar, it should change by an amount representing, more or less, a page }
  175.                 { of data.  SetLinesPerPage determines how many units the value should change }
  176.                 { by when the user clicks in the gray area.  The method SetDefaults sets the }
  177.                 { page sizes to 1, so that clicking in the gray area will have the same effect }
  178.                 { as clicking on an arrow.  Note that page sizes will generally have to be }
  179.                 { changed when the window changes size. }
  180.  
  181.             procedure setTitle (str: string);
  182.             function getTitle: str255;
  183.                 { These methods set and read the title displayed in the window's title bar. }
  184.  
  185.             procedure SetUserRef (theRef: longint);
  186.             function GetUserRef: longint;
  187.                 { These methods set and read a reference number associated with the }
  188.                 { window.  xWindow makes no use of this number; it is provided for the }
  189.                 { user, for example to store a handle to data displayed in the window. }
  190.  
  191.     { UTILITY METHODS }
  192.  
  193.             procedure hide;
  194.             procedure show;
  195.             procedure move (left, top: integer);
  196.             procedure setWindowSize (width, height: integer);
  197.                 { These four methods allow you to directly hide the window, show it, move it }
  198.                 { and set its size.  Procedure move moves the widow without changing its }
  199.                 { size so that its upper left corner at the point (left,top).  Procedure }
  200.                 { setWindowSize adjusts the lower right corner to acheive the specified }
  201.                 { width and height, and then calls AdjustToNewSize. }
  202.  
  203.     { METHODS FOR REWRITTING open }
  204.  
  205.             procedure SetFeatures (theFeatures: windowFeatureSet);
  206.                 { Change the feature list.  DO NOT CALL ONCE THE WINDOW IS OPENED. }
  207.             procedure SetScrollOffsets (vTop, vBottom, hLeft, hRight: integer);
  208.                 { Change the space left at the ends of the scroll bars.  By default, no extra }
  209.                 { space is left.  For example, you could use this if you want the vertical }
  210.                 { scroll to start 50 points from the top of the window.  You should probably }
  211.                 { adjust the maximum and minimum sizes with SetMaxMinSize to make sure }
  212.                 { the window contains enouge space for the scroll bars.  You should not call }
  213.                 { this procedure while the window is open (but if you really want to, you }
  214.                 { call it and then use the Mac toolbox routine InvalRect to force a window }
  215.                 { redraw.) }
  216.             procedure SetMinDragWidth (minWidth: integer);
  217.             procedure SetMaxDragWidth (maxWidth: integer);
  218.             procedure SetMinDragHeight (minHeight: integer);
  219.             procedure SetMaxDragHeight (maxHeight: integer);
  220.                 { These determine the maximum and minimum sizes of the window when the user }
  221.                 { drags the window's GrowBox to resize the window.  By default, the minimums are }
  222.                 { very small and the maximums are essentially infinite.   You should make sure that }
  223.                 { minimum size is sufficient to contain any "decorations you add to the window.  }
  224.                 { Also, make sure the original window fits in the specified ranges. }
  225.             procedure doBasicOpen (title: string;
  226.                                         left, top, right, bottom: integer);
  227.                 { Opens the window, using (left,top) and (bottom,right) as the upper left }
  228.                 { and lower right corners of the content rectangle of the window (excluding }
  229.                 { the title bar and border).  DO NOT CALL UNTIL VALUES HAVE BEEN SET }
  230.                 { WITH PRECEDING PROCEDURES. }
  231.  
  232.     { METHODS YOU WILL PROBABLY NEVER CHANGE OR USE DIRECTLY }
  233.  
  234.             procedure doEvent (event: eventRecord);
  235.                  { Called to handle an event directed to this window; directs the event }
  236.                  { to one of the following methods or to doActivate or to doKey. }
  237.             procedure doUpdate;
  238.                  { Handles an update event for the window; calls doRedraw. }
  239.             procedure doClick (globalPt: point;
  240.                                         modifiers: longint);
  241.                  { Handles a click anywhere in the window by calling appropriate method }
  242.             procedure doGrow (startPt: point);
  243.                  { Handles a user click in the GrowBox }
  244.             procedure doDrag (startPt: point);
  245.                  { Handles a user click in the title bar (exclusive of goAwayBox or ZoomBox }
  246.             procedure doZoom (startPt: point;
  247.                                         partNum: integer);
  248.                 { Handles a user click in the ZoomBox }
  249.             procedure adjustCursor (localPt: point);
  250.                 { if the cursor is over an xWindowDecoration, this sets the cursor to }
  251.                 { cursor for that decoration; otherwise it sets the cursor to the standard }
  252.                 { arrow }
  253.  
  254.         end;  { definition of xWindows }
  255.  
  256.     xWindowDecoration = object
  257.             { abstract class defining the common protocol for objects, such as buttons, }
  258.             { pictures, and input boxes, that can be added to xWidows. }
  259.  
  260.    { INSTANCE VARIABLES }
  261.  
  262.             itsWindow: xWindow;  { the window into which the decoration has been installed }
  263.             nextDecoration: xWindowDecoration;  { link in list of decorations for that window }
  264.             drawRect: Rect;  { rectangle completely containing the item }
  265.             clickRect: Rect;  { a rectangle containing the part of the decoration that can respond }
  266.                                  { to clicks (if any);  should be contained in drawRect; by default is }
  267.                                  { equal to drawRect }
  268.             left, top, height, width: integer;  { values determining position and size of object }
  269.                                    { (See procedure Install for a description ) }
  270.             visible: boolean;  { set to false if item is hidden }
  271.             wantsKey, wantsClick, wantsCR: boolean;  { determines whether events are sent }
  272.                                    { by xWindow procedures to this decoration; generally, only the }
  273.                                    { first (most recent) item in the decoration list that wants the event }
  274.                                    { receives it. }
  275.             itsCursor: cursor;   { the cursor to be displayed over this item's clickRect, if it is }
  276.                                        { active and visible }
  277.             grayedOut: boolean;  { set to true by some descendent class when the item is deactivated }
  278.  
  279.   { METHODS FOR INITIALIZING THE DECORATION }
  280.  
  281.             procedure init;
  282.              { inialize most of the instance variables; should be called before you do }
  283.              { anything else with the object. }
  284.             procedure install (win: xWindow;
  285.                                         theLeft, theTop, theWidth, theHeight: integer);
  286.              { Add an init'ed object to the specified xWindow.  The values of theLeft and }
  287.              { theTop determine the top left cornor of the drawRect of the item.   If both }
  288.              { are >= 0, then they simply give the coordinated of the that point.  If theLeft }
  289.              { is < 0, then the left side of the drawRect will be given by subtracting }
  290.              { abs(theLeft) from the right side of the window.  For example, if topLeft is }
  291.              { -50, then the top left cornor of the item will be 50 pixels in from the right }
  292.              { edge of the window; this relationship will be reestablished when the window }
  293.              { is resized by moving the item if necessary. }
  294.              {      Similarly, if theTop is < 0, then it gives the position of the top of the }
  295.              { decoration as an offset from the bottom edge of the window, so that the top }
  296.              { of the decoration will remain at a fixed height above the bottom of the window, }
  297.              { given by abs(theTop). }
  298.              {       Once the top, left cornor of the decoration is deterimined, then theWidth }
  299.              { theHeight are used to determine the width and height of the item.  If they are }
  300.              { both > 0, then they simply specify the actual height and width.  If theHeight is }
  301.              { <= 0, then its value is used as follows:  the right edge of the decoration's drawRect }
  302.              { will be positioned abs(theHeight) pixels in from the right edge of the window. }
  303.              { Similarly, if theWidth is <= 0, then the bottom edge of the decoration will be }
  304.              { abs(theWidth) pixels above the bottom edge of the window. }
  305.              {     Note that theLeft, theTop, theWidth and theHeight are stored in the instance }
  306.              { variables left, top, width and height and are used to recompute the position and }
  307.              { size of the decoration when the size of the window changes. }
  308.              {      All this is not as confusing as it may sound.  Here are some examples: }
  309.              { Install(xWin,10,10,-10,30):  the decoration is 30 units high, with top left }
  310.              {                 cornor at (10,10).  It stretches all across the top of the window. }
  311.              { Install(xWin,-60,20,40,40):  the decoration occupies a 40 by 40 square }
  312.              {                 that hangs in the top right cornor of the window. }
  313.  
  314.   { METHODS FOR MANIPULATING THE DECORATION }
  315.  
  316.             procedure move (newLeft, newTop: integer);
  317.              { move the decoration; newLeft and newTop have the same meaning as theLeft }
  318.              { and theTop in procedure Install.  }
  319.             procedure setSize (newWidth, newHeight: integer);
  320.              { change the size of the decoration; newWidth and newHeight have the same }
  321.              { meaning as theWidth and theHeight in procedure Install }
  322.             procedure remove;
  323.              { removes the item from its window, without destroying the data structures; }
  324.              { it could then potentially be installed in another window }
  325.             procedure kill;
  326.              { remove the item from its window and dispose of all storage (including calling }
  327.              { Dispose on the object itself }
  328.             procedure hide;
  329.              { make the decoration invisible; it can be made visible again with Show }
  330.             procedure show;
  331.              { makes a hidden decoration visible again }
  332.             procedure useCursor (c: cursor);
  333.              { specify that this cursor should be shown when the cursor position is over this }
  334.              { decoration's clickRect (and it is visible and not grayed out); by default, a }
  335.              { standard arrow cursor is used }
  336.             procedure forceRedraw;
  337.              { forces an update event for the drawRect of this decoration }
  338.  
  339.   { METHODS CALLED IN RESPONSE TO VARIOUS EVENTS }
  340.  
  341.             procedure adjustSize;
  342.               {called by install, setSize, move and xWindow.AdjustToNewSize to do the }
  343.               { calculation of the position and size of the decoration, as described in }
  344.               { procedure install; if you override this method, you can make any other }
  345.               { adjustments necessary when your decoration is moved or resized }
  346.             procedure doKey (ch: char;
  347.                                         modifiers: longint);
  348.               { handle a keystroke, other than CR or ENTER;  this is sent by procedure }
  349.               { xWindow.doKey to the first decoration in the window for which the instance }
  350.               { variable wantsKey is true (if any);  "modifiers" is the modifiers field of }
  351.               { the event record for the keyDown event. }
  352.             procedure doCR (ch: char);
  353.               { respond to user pressing either CR or ENTER;  this is sent by procedure }
  354.               { xWindow.doKey to the first decoration in the window for which the instance }
  355.               { variable wantsKey is true (if any) }
  356.             procedure doClick (localPt: point;
  357.                                         modifiers: longint);
  358.                { respond to the user clicking the mouse;  this is sent by procedure }
  359.                { xWindow.doContentClick to the first decoration it finds whose clickRect }
  360.                { contains the given point }
  361.             procedure doDraw;
  362.                { redraws the decoration; called by xWindow.doRedraw }
  363.             procedure doActivate (active: boolean);
  364.                { respond to an activate event for the window }
  365.             procedure Idle;
  366.                { this is sent once each time through the event loop to any active, visible }
  367.                { decoration in the front window; sent by xWindow.idle. }
  368.  
  369.         end;  { definition of xWindowDecoration }
  370.  
  371.  
  372. var
  373.     windowRect: Rect;  { used in opening widnows in procedure xWindows.openInRect. }
  374.  
  375. procedure InitXWindows;
  376. { This procedure is called in StandardMain; all it does is initialize the list of open }
  377. { xWindows to NIL }
  378.  
  379.  
  380. function Window2xWindow (win: WindowPtr;
  381.                             var xWin: xWindow): boolean;
  382. { looks up a Macintosh window in the list of open xWindows; returns TRUE if it is }
  383. { found, FALSE if not.  If it is found, xWin is set to be the xWindow corresponding to }
  384. { the Macintosh window. }
  385.  
  386.  
  387. procedure TellUser (message: string);
  388. { a utility procedure that simply displays an alert box containing the message, with an}
  389. { OK button for the user to click;  requires the presense of the alert resource #129 in }
  390. { resources for the program }
  391.  
  392.  
  393. implementation
  394.  
  395. var
  396.     FirstWin: xWindow;
  397.  
  398. procedure TellUser (message: string);
  399.     var
  400.         bttn: integer;
  401.     begin
  402.         ParamText(message, '', '', '');
  403.         SetCursor(arrow);
  404.         bttn := NoteAlert(129, nil);
  405.         if bttn = -1 then
  406.             Sysbeep(5);
  407.     end;
  408.  
  409. procedure InitXWindows;
  410.     begin
  411.         FirstWin := nil;
  412.     end;
  413.  
  414. function Window2xWindow (win: WindowPtr;
  415.                                 var xWin: xWindow): boolean;
  416.     begin
  417.         xWin := FirstWin;
  418.         while (xWin <> nil) & (xWin.theWindow <> win) do
  419.             xWin := xWin.nextXWindow;
  420.         Window2xWindow := xWin <> nil;
  421.     end;
  422.  
  423. procedure GetWindowRect (var left, top, right, bottom: integer);
  424.    { provides a succession of rectangles for opening windows, each offset over and down }
  425.    { from the last. }
  426.     var
  427.         r: Rect;  { a full screen }
  428.         w, h: integer;  { width and height of window rect }
  429.     begin
  430.         r := screenbits.bounds;
  431.         r.top := r.top + 38;
  432.         w := (3 * (r.right - r.left) div 4);
  433.         h := (3 * (r.bottom - r.top) div 4);
  434.         if w > 1000 then
  435.             w := 1000;
  436.         if h > 2 * w div 3 then
  437.             h := 2 * w div 3;
  438.     { we have to be carefull to initialize windowRect if it is not of the right size or not on the }
  439.     { screen, as is almost certainly the case when the program starts. }
  440.         if not PtInRect(windowRect.topLeft, R) | (w <> windowRect.right - windowRect.left) | (h <> windowRect.bottom - windowRect.top) then begin
  441.                 left := r.left + 4;
  442.                 top := r.top + 4;
  443.                 bottom := top + h;
  444.                 right := left + w;
  445.                 SetRect(windowRect, left, top, right, bottom);
  446.             end
  447.         else begin
  448.                 OffsetRect(WindowRect, 15, 15);
  449.                 if windowRect.Right > R.right - 2 then begin
  450.                         windowRect.left := R.left + 4;
  451.                         windowRect.right := windowRect.left + w;
  452.                         if windowRect.bottom > R.bottom - 2 then begin
  453.                                 windowRect.top := R.top + 11;
  454.                                 windowRect.bottom := windowRect.top + h;
  455.                             end;
  456.                     end
  457.                 else if windowRect.bottom > R.bottom - 2 then begin
  458.                         windowRect.top := R.top + 4;
  459.                         windowRect.bottom := windowRect.top + h;
  460.                     end;
  461.                 left := windowRect.left;
  462.                 right := windowRect.right;
  463.                 top := windowRect.top;
  464.                 bottom := windowRect.bottom;
  465.             end;
  466.     end;
  467.  
  468. procedure xWindow.open (title: string);
  469.     var
  470.         left, top, right, bottom: integer;
  471.     begin
  472.         GetWindowRect(left, top, right, bottom);
  473.         openInRect(title, left, top, right, bottom);
  474.     end;
  475.  
  476. procedure xWindow.openInRect (title: string;
  477.                                 left, top, right, bottom: integer);
  478.     begin
  479.         SetDefaults;
  480.         doBasicOpen(title, left, top, right, bottom);
  481.     end;
  482.  
  483. procedure xWindow.doRedraw (badRect: Rect);
  484.     var
  485.         d: xWindowDecoration;
  486.         junk: rect;
  487.     begin
  488.         d := decorations;
  489.         while d <> nil do begin
  490.                 if SectRect(d.drawRect, badRect, junk) & d.visible then
  491.                     d.doDraw;
  492.                 d := d.nextDecoration;
  493.             end;
  494.     end;
  495.  
  496. procedure xWindow.doContentClick (localPt: point;
  497.                                 modifiers: longint);
  498.     var
  499.         d: xWindowDecoration;
  500.     begin
  501.         d := decorations;
  502.         while d <> nil do
  503.             if PtInRect(localPt, d.clickRect) & d.wantsClick & d.visible then begin
  504.                     d.doClick(localPt, modifiers);
  505.                     EXIT(doContentClick);
  506.                 end
  507.             else
  508.                 d := d.nextDecoration;
  509.     end;
  510.  
  511. procedure xWindow.doKey (ch: char;
  512.                                 modifiers: longint);
  513.     var
  514.         d: xWindowDecoration;
  515.     begin
  516.         d := decorations;
  517.         if (ch = chr(13)) | (ch = chr(3)) then begin
  518.                 while d <> nil do
  519.                     if d.wantsCR & d.visible then begin
  520.                             d.doCR(ch);
  521.                             EXIT(doKey);
  522.                         end
  523.                     else
  524.                         d := d.nextDecoration;
  525.             end
  526.         else
  527.             while d <> nil do
  528.                 if d.wantsKey & d.visible then begin
  529.                         d.doKey(ch, modifiers);
  530.                         EXIT(doKey);
  531.                     end
  532.                 else
  533.                     d := d.nextDecoration;
  534.     end;
  535.  
  536. procedure xWindow.Idle;
  537.     var
  538.         d: xWindowDecoration;
  539.     begin
  540.         d := decorations;
  541.         while d <> nil do begin
  542.                 if d.visible and not d.grayedOut then
  543.                     d.idle;
  544.                 d := d.nextDecoration;
  545.             end;
  546.     end;
  547.  
  548. procedure xWindow.SetDefaults;
  549.     var
  550.         min, max: point;
  551.     begin
  552.         SetFeatures([hasGoAway, hasHScroll, hasVScroll, hasZoom, hasGrow]);
  553.         SetScrollOffsets(0, 0, 0, 0);
  554.         SetLinesPerPage(1, 1);
  555.         SetMinDragWidth(50);
  556.         SetMinDragHeight(50);
  557.         SetMaxDragWidth(maxint);
  558.         SetMaxDragHeight(maxint);
  559.         hpixelsPerLine := 1;
  560.         vpixelsPerLine := 1;
  561.     end;
  562.  
  563. procedure xWindow.SetFeatures (theFeatures: windowFeatureSet);
  564.     begin
  565.         features := theFeatures;
  566.     end;
  567.  
  568. procedure xWindow.SetScrollOffsets (vTop, vBottom, hLeft, hRight: integer);
  569.     begin
  570.         vScrollTopOffset := vTop;
  571.         vScrollBottomOffset := vBottom;
  572.         hScrollLeftOffset := hLeft;
  573.         hScrollRightOffset := hRight;
  574.     end;
  575.  
  576. procedure xWindow.SetLinesPerPage (hPage, vPage: integer);
  577.     begin
  578.         hLinesPerPage := hPage;
  579.         vLinesPerPage := vPage;
  580.     end;
  581.  
  582. procedure xWindow.SetMinDragWidth (minWidth: integer);
  583.     begin
  584.         minSize.h := minWidth;
  585.     end;
  586.  
  587. procedure xWindow.SetMaxDragWidth (maxWidth: integer);
  588.     begin
  589.         maxSize.h := maxWidth;
  590.     end;
  591.  
  592. procedure xWindow.SetMinDragHeight (minHeight: integer);
  593.     begin
  594.         minSize.v := minHeight;
  595.     end;
  596.  
  597. procedure xWindow.SetMaxDragHeight (maxHeight: integer);
  598.     begin
  599.         maxSize.v := maxHeight;
  600.     end;
  601.  
  602. procedure xWindow.doBasicOpen (title: string;
  603.                                 left, top, right, bottom: integer);
  604.     var
  605.         R, openRect: Rect;
  606.         windowProc: integer;
  607.         goAway: boolean;
  608.         win: WindowPtr;
  609.     begin
  610.         if minSize.h <= 10 then
  611.             minSize.h := 30;
  612.         if maxSize.h <= minSize.h then
  613.             maxSize.h := minSize.h;
  614.         if minSize.v <= 10 then
  615.             minSize.v := 30;
  616.         if maxSize.v <= minSize.v then
  617.             maxSize.v := minSize.v;
  618.         if hScrollLeftOffset < 0 then
  619.             hScrollLeftOffset := 0;
  620.         if hScrollRightOffset < 0 then
  621.             hScrollRightOffset := 0;
  622.         if vScrollTopOffset < 0 then
  623.             vScrollTopOffset := 0;
  624.         if vScrollBottomOffset < 0 then
  625.             vScrollBottomOffset := 0;
  626.         SetRect(openRect, left, top, right, bottom);
  627.         if EmptyRect(openRect) then begin
  628.                 openRect := screenBits.bounds;
  629.                 InsetRect(openRect, 5, 5);
  630.                 openRect.top := openRect.top + 38;
  631.             end;
  632.         if openRect.bottom < openRect.top + 30 then
  633.             openRect.bottom := openRect.top + 30;
  634.         if openRect.right < openRect.left + 30 then
  635.             openRect.right := openRect.left + 30;
  636.         goAway := hasGoAway in features;
  637.         if hasGrow in features then
  638.             windowProc := documentProc
  639.         else
  640.             windowProc := noGrowDocProc;
  641.         if hasZoom in features then
  642.             windowProc := windowProc + 8;
  643.         if DAStyle in features then
  644.             win := NewWindow(nil, openRect, title, true, rDocProc, pointer(-1), goAway, longint(self))
  645.         else
  646.             win := NewWindow(nil, openRect, title, true, windowProc, pointer(-1), goAway, longint(self));
  647.         theWindow := win;
  648.         decorations := nil;
  649.         if hasVScroll in features then begin
  650.                 R := theWindow^.portRect;
  651.                 R.right := R.right + 1;
  652.                 if (hasGrow in features) then
  653.                     R.bottom := R.bottom - 14
  654.                 else
  655.                     R.bottom := R.bottom + 1;
  656.                 R.left := R.right - 16;
  657.                 R.top := R.top + vScrollTopOffset - 1;
  658.                 R.bottom := R.bottom - vScrollBottomOffset;
  659.                 vScroll := NewControl(win, R, '', false, 0, 0, 0, scrollBarProc, longint(self));
  660.             end;
  661.         if hasHScroll in features then begin
  662.                 R := theWindow^.portRect;
  663.                 if (hasGrow in features) | (hasVScroll in features) then
  664.                     R.right := R.right - 14
  665.                 else
  666.                     R.right := R.right + 1;
  667.                 R.bottom := R.bottom + 1;
  668.                 R.top := R.bottom - 16;
  669.                 R.left := R.left + hScrollLeftOffset - 1;
  670.                 R.right := R.right - hScrollRightOffset;
  671.                 hScroll := NewControl(win, R, '', false, 0, 0, 0, scrollBarProc, longint(self));
  672.             end;
  673.         nextXWindow := FirstWin;
  674.         FirstWin := self
  675.     end;
  676.  
  677. procedure xWindow.doClose;
  678.     var
  679.         d, nextD: xWindowDecoration;
  680.         runner: xWindow;
  681.     begin
  682.         d := decorations;
  683.         while d <> nil do begin
  684.                 nextD := d.nextDecoration;
  685.                 d.kill;
  686.                 d := nextD;
  687.             end;
  688.         if self = FirstWin then                            { remove self from list of xWindows }
  689.             FirstWin := FirstWin.nextXWindow
  690.         else begin
  691.                 runner := FirstWin;
  692.                 while (runner.nextXWindow <> nil) & (runner.nextXwindow <> self) do
  693.                     runner := runner.nextXWindow;
  694.                 if runner.nextXWindow <> nil then
  695.                     runner.nextXWindow := runner.nextXWindow.nextXWindow;
  696.             end;
  697.         CloseWindow(theWindow);
  698.     end;
  699.  
  700. procedure xWindow.hide;
  701.     begin
  702.         HideWindow(theWindow);
  703.     end;
  704.  
  705. procedure xWindow.show;
  706.     begin
  707.         ShowWindow(theWindow);
  708.     end;
  709.  
  710. procedure xWindow.move (left, top: integer);
  711.     begin
  712.         MoveWindow(theWindow, left, top, false);
  713.     end;
  714.  
  715. procedure xWindow.setWindowSize (width, height: integer);
  716.     begin
  717.         SizeWindow(theWindow, width, height, false);
  718.         AdjustToNewSize;
  719.     end;
  720.  
  721. procedure xWindow.SetUserRef (theRef: longint);
  722.     begin
  723.         userRef := theRef;
  724.     end;
  725.  
  726. function xWindow.GetUserRef: longint;
  727.     begin
  728.         GetUserRef := userRef;
  729.     end;
  730.  
  731. procedure xWindow.AdjustToNewSize;
  732.     var
  733.         newHeight, newWidth: integer;
  734.         savePort: GrafPtr;
  735.         d: xWindowDecoration;
  736.     begin
  737.         newWidth := theWindow^.portRect.right - theWindow^.portRect.left;
  738.         newHeight := theWindow^.portRect.bottom - theWindow^.portRect.top;
  739.         if hasHScroll in features then
  740.             HideControl(hScroll);
  741.         if hasVScroll in features then
  742.             HideControl(vScroll);
  743.         SizeWindow(theWindow, newWidth, newHeight, false);
  744.         GetPort(savePort);
  745.         SetPort(theWindow);
  746.         if hasHScroll in features then begin
  747.                 MoveControl(hScroll, theWindow^.portRect.left - 1 + hScrollLeftOffset, theWindow^.portRect.bottom - 15);
  748.                 if (hasVscroll in features) | (hasGrow in features) then
  749.                     newWidth := newWidth - 13
  750.                 else
  751.                     newWidth := newWidth + 2;
  752.                 SizeControl(hScroll, newWidth - hScrollLeftOffset - hScrollRightOffset, 16);
  753.                 ShowControl(hScroll);
  754.             end;
  755.         if hasVScroll in features then begin
  756.                 MoveControl(vScroll, theWindow^.portRect.right - 15, theWindow^.portRect.top - 1 + vScrollTopOffset);
  757.                 if hasGrow in features then
  758.                     newHeight := newHeight - 13
  759.                 else
  760.                     newHeight := newHeight + 2;
  761.                 SizeControl(vScroll, 16, newHeight - vScrollTopOffset - vScrollBottomOffset);
  762.                 ShowControl(vScroll);
  763.             end;
  764.         d := decorations;
  765.         while d <> nil do begin
  766.                 d.adjustSize;
  767.                 d := d.nextDecoration;
  768.             end;
  769.         InvalRect(theWindow^.portRect);
  770.         SetPort(savePort);
  771.     end;
  772.  
  773. procedure xWindow.doEvent (event: eventRecord);
  774.     begin
  775.         case event.what of
  776.             keyDown, autoKey: 
  777.                 doKey(chr(BitAnd(event.message, $FF)), event.modifiers);
  778.             mouseDown: 
  779.                 doClick(event.where, event.modifiers);
  780.             updateEvt: 
  781.                 doUpdate;
  782.             activateEvt: 
  783.                 doActivate(BitAnd(event.modifiers, activeFlag) <> 0);
  784.             otherwise
  785.         end;
  786.     end;
  787.  
  788. procedure xWindow.setTitle (str: string);
  789.     begin
  790.         SetWTitle(theWindow, str);
  791.     end;
  792.  
  793. function xWindow.getTitle: str255;
  794.     var
  795.         str: str255;
  796.     begin
  797.         GetWTitle(theWindow, str);
  798.         getTitle := str;
  799.     end;
  800.  
  801. procedure xWindow.SetHMax (theMax: integer);
  802.     begin
  803.         if hasHScroll in features then
  804.             SetCtlMax(hScroll, theMax);
  805.     end;
  806.  
  807. procedure xWindow.SetVMax (theMax: integer);
  808.     begin
  809.         if hasVScroll in features then
  810.             SetCtlMax(vScroll, theMax);
  811.     end;
  812.  
  813. procedure xWindow.SetHVal (theVal: integer);
  814.     begin
  815.         if hasHScroll in features then
  816.             SetCtlValue(hScroll, theVal);
  817.     end;
  818.  
  819. procedure xWindow.SetVVal (theVal: integer);
  820.     begin
  821.         if hasVScroll in features then
  822.             SetCtlValue(vScroll, theVal);
  823.     end;
  824.  
  825. function xWindow.GetHMax: integer;
  826.     begin
  827.         if hasHScroll in features then
  828.             GetHMax := GetCtlMax(hScroll)
  829.         else
  830.             GetHMax := 0;
  831.     end;
  832.  
  833. function xWindow.GetVMax: integer;
  834.     begin
  835.         if hasVScroll in features then
  836.             GetVMax := GetCtlMax(vScroll)
  837.         else
  838.             GetVMax := 0;
  839.     end;
  840.  
  841. function xWindow.GetHVal: integer;
  842.     var
  843.         val: integer;
  844.     begin
  845.         if hasHScroll in features then
  846.             val := GetCtlValue(hScroll)
  847.         else
  848.             val := 0;
  849.         GetHVal := val;
  850.     end;
  851.  
  852. function xWindow.GetVVal: integer;
  853.     var
  854.         val: integer;
  855.     begin
  856.         if hasVScroll in features then
  857.             val := GetCtlValue(vScroll)
  858.         else
  859.             val := 0;
  860.         GetVVal := val;
  861.     end;
  862.  
  863. procedure xWindow.doHScroll (dh: integer);
  864.     var
  865.         savePort: GrafPtr;
  866.         R: rect;
  867.     begin
  868.         GetPort(savePort);
  869.         SetPort(theWindow);
  870.         R := theWindow^.portRect;
  871.         if hasVScroll in features then
  872.             R.right := R.right - 15;
  873.         if hasHScroll in features then
  874.             r.bottom := R.bottom - 15;
  875.         EraseRect(R);
  876.         doReDraw(R);
  877.         SetPort(savePort);
  878.     end;
  879.  
  880. procedure xWindow.doVScroll (dv: integer);
  881.     var
  882.         savePort: GrafPtr;
  883.         R: rect;
  884.     begin
  885.         GetPort(savePort);
  886.         SetPort(theWindow);
  887.         R := theWindow^.portRect;
  888.         if hasVScroll in features then
  889.             R.right := R.right - 15;
  890.         if hasHScroll in features then
  891.             r.bottom := R.bottom - 15;
  892.         EraseRect(R);
  893.         doReDraw(R);
  894.         SetPort(savePort);
  895.     end;
  896.  
  897. procedure continuousScroll (ctl: ControlHandle;
  898.                                 partCode: integer);
  899.     var
  900.         win: xWindow;
  901.         lines: integer;
  902.         horizontal: boolean;
  903.         val: integer;
  904.         max: integer;
  905.     begin
  906.         val := getCtlValue(ctl);
  907.         max := getCtlMax(ctl);
  908.         win := xWindow(ctl^^.ContrlRfCon);
  909.         horizontal := (hasHScroll in win.features) & (ctl = win.hScroll);
  910.         case partCode of
  911.             inDownButton: 
  912.                 if horizontal then
  913.                     lines := win.hpixelsperline
  914.                 else
  915.                     lines := win.vpixelsPerLine;
  916.             inUpButton: 
  917.                 if horizontal then
  918.                     lines := -win.hpixelsperline
  919.                 else
  920.                     lines := -win.vpixelsPerLine;
  921.             inPageDown: 
  922.                 if horizontal then
  923.                     lines := win.hLinesPerPage
  924.                 else
  925.                     lines := win.vLinesPerPage;
  926.             inPageUp: 
  927.                 if horizontal then
  928.                     lines := -win.hLinesPerPage
  929.                 else
  930.                     lines := -win.vLinesPerPage;
  931.             otherwise
  932.                 EXIT(ContinuousScroll);
  933.         end;
  934.         if val + lines < 0 then
  935.             lines := -val
  936.         else if val + lines > max then
  937.             lines := max - val;
  938.         if lines <> 0 then begin
  939.                 SetCtlValue(ctl, val + lines);
  940.                 if horizontal then
  941.                     win.doHScroll(lines)
  942.                 else
  943.                     win.doVScroll(lines)
  944.             end;
  945.     end;
  946.  
  947. procedure xWindow.doClick (globalPt: point;
  948.                                 modifiers: longint);
  949.     var
  950.         partNum: integer;
  951.         savePort: grafPtr;
  952.         part: integer;
  953.         theControl: controlHandle;
  954.         oldVal: integer;
  955.     begin
  956.         if theWindow <> FrontWindow then
  957.             SelectWindow(theWindow)
  958.         else begin
  959.                 partNum := FindWindow(globalPt, theWindow);
  960.                 case partnum of
  961.                     inContent:  begin
  962.                             GetPort(savePort);
  963.                             SetPort(theWindow);
  964.                             GlobalToLocal(globalPt);
  965.                             if ((not (hasHScroll in features) | (not PtInRect(globalPt, hScroll^^.contrlRect))) & (not (hasVScroll in features) | (not PtInRect(globalPt, vScroll^^.contrlRect)))) & (globalPt.h < theWindow^.portRect.right) & (globalPt.v < theWindow^.portRect.bottom) then
  966.                                 doContentClick(globalPt, modifiers)
  967.                             else begin
  968.                                     part := FindControl(globalPt, theWindow, theControl);
  969.                                     if (theControl <> hScroll) & (theControl <> vScroll) then begin
  970.                                         end
  971.                                     else if part in [inUpButton, inDownButton, inPageUp, inPageDown] then
  972.                                         part := TrackControl(theControl, globalPt, @continuousScroll)
  973.                                     else if part = inThumb then begin
  974.                                             oldVal := GetCtlValue(theControl);
  975.                                             part := TrackControl(theControl, globalPt, nil);
  976.                                             if (part = inThumb) & (oldVal <> GetCtlValue(theControl)) then
  977.                                                 if theControl = HScroll then
  978.                                                     doHScroll(GetCtlValue(theControl) - oldVal)
  979.                                                 else
  980.                                                     doVScroll(GetCtlValue(theControl) - oldVal)
  981.                                         end;
  982.                                 end;
  983.                             SetPort(savePort);
  984.                         end;
  985.                     inDrag: 
  986.                         doDrag(globalPt);
  987.                     inGrow: 
  988.                         DoGrow(globalPt);
  989.                     inGoAway: 
  990.                         if TrackGoAway(theWindow, globalPt) then
  991.                             doClose;
  992.                     inZoomIn, inZoomOut: 
  993.                         doZoom(globalPt, partNum);
  994.                 end;
  995.             end;
  996.     end;
  997.  
  998. procedure xWindow.doGrow (startPt: point);
  999.     var
  1000.         R: rect;
  1001.         newSize: longint;
  1002.         height, width: integer;
  1003.         savePort: GrafPtr;
  1004.     begin
  1005.         SetRect(R, minSize.h, minSize.v, maxSize.h, maxSize.v);
  1006.         newSize := GrowWindow(theWindow, startPt, R);
  1007.         if newSize <> 0 then begin
  1008.                 width := LoWord(newSize);
  1009.                 height := HiWord(newSize);
  1010.                 GetPort(savePort);
  1011.                 SetPort(theWindow);
  1012.                 eraseRect(theWindow^.portRect);
  1013.                 SizeWindow(theWindow, Width, Height, false);
  1014.                 AdjustToNewSize;
  1015.                 SetPort(savePort);
  1016.             end;
  1017.     end;
  1018.  
  1019. procedure xWindow.doDrag (startPt: point);
  1020.     var
  1021.         R: Rect;
  1022.     begin
  1023.         R := screenBits.bounds;
  1024.         R.top := 20;
  1025.         InsetRect(R, 4, 4);
  1026.         DragWindow(theWindow, startPt, R);
  1027.     end;
  1028.  
  1029. procedure xWindow.doZoom (startPt: point;
  1030.                                 partNum: integer);
  1031.     var
  1032.         savePort: GrafPtr;
  1033.     begin
  1034.         if not TrackBox(theWindow, startPt, partNum) then
  1035.             EXIT(doZoom);
  1036.         getPort(savePort);
  1037.         setPort(theWindow);
  1038.         eraseRect(theWindow^.portRect);
  1039.         ZoomWindow(theWindow, partNum, false);
  1040.         AdjustToNewSize;
  1041.         SetPort(savePort);
  1042.     end;
  1043.  
  1044. procedure xWindow.doUpdate;
  1045.     var
  1046.         savePort: GrafPtr;
  1047.         R: rect;
  1048.         oldPen: penState;
  1049.     begin
  1050.         GetPort(savePort);
  1051.         SetPort(theWindow);
  1052.         BeginUpdate(theWindow);
  1053.         EraseRect(theWindow^.portRect);
  1054.         if hasGrow in features then begin
  1055.                 GetPenState(oldPen);
  1056.                 PenSize(1, 1);
  1057.                 PenPat(black);
  1058.                 DrawGrowIcon(theWindow);
  1059.                 R := theWindow^.portRect;
  1060.                 PenMode(notPatCopy);
  1061.                 if not (hasHScroll in features) then begin
  1062.                         MoveTo(R.left, R.bottom - 15);
  1063.                         LineTo(R.right - 16, R.bottom - 15);
  1064.                     end
  1065.                 else if hScrollLeftOffset > 0 then begin
  1066.                         MoveTo(R.left, R.bottom - 15);
  1067.                         LineTo(hScrollLeftOffset - 1, R.bottom - 15);
  1068.                         PenMode(PatCopy);
  1069.                         Line(0, 14);
  1070.                         PenMode(notPatCopy);
  1071.                     end;
  1072.                 if not (hasVScroll in features) then begin
  1073.                         MoveTo(R.Right - 15, R.top);
  1074.                         LineTo(R.right - 15, R.bottom - 16);
  1075.                     end
  1076.                 else if vScrollTopOffset > 0 then begin
  1077.                         MoveTo(R.right - 15, R.top);
  1078.                         LineTo(R.right - 15, vScrollTopOffset - 1);
  1079.                         PenMode(PatCopy);
  1080.                         Line(14, 0);
  1081.                     end;
  1082.                 PenMode(PatCopy);
  1083.                 SetPenState(oldPen);
  1084.             end;
  1085.         UpdtControl(theWindow, theWindow^.visRgn);
  1086.         doReDraw(theWindow^.visRgn^^.rgnBBox);
  1087.         EndUpdate(theWindow);
  1088.         SetPort(savePort);
  1089.     end;
  1090.  
  1091. procedure xWindow.doActivate (active: boolean);
  1092.     var
  1093.         savePort: grafPtr;
  1094.         R: rect;
  1095.         d: xWindowDecoration;
  1096.     begin
  1097.         if hasGrow in features then begin { force redraw of grow icon }
  1098.                 GetPort(savePort);
  1099.                 SetPort(theWindow);
  1100.                 R := theWindow^.portRect;
  1101.                 R.top := R.bottom - 13;
  1102.                 R.left := R.right - 13;
  1103.                 InvalRect(R);
  1104.                 SetPort(savePort);
  1105.             end;
  1106.         if active then begin
  1107.                 if hasVScroll in features then
  1108.                     ShowControl(vScroll);
  1109.                 if hasHscroll in features then
  1110.                     ShowControl(hScroll);
  1111.             end
  1112.         else begin
  1113.                 if hasVScroll in features then
  1114.                     HideControl(vScroll);
  1115.                 if hasHscroll in features then
  1116.                     HideControl(hScroll);
  1117.             end;
  1118.         d := decorations;
  1119.         while d <> nil do begin
  1120.                 d.doActivate(active);
  1121.                 d := d.nextDecoration;
  1122.             end;
  1123.     end;
  1124.  
  1125. procedure xWindow.adjustCursor (localPt: point);
  1126.     var
  1127.         d: xWindowDecoration;
  1128.     begin
  1129.         d := decorations;
  1130.         while d <> nil do
  1131.             if PtInRect(localPt, d.clickRect) & not d.grayedOut & d.visible then begin
  1132.                     SetCursor(d.itsCursor);
  1133.                     EXIT(adjustCursor);
  1134.                 end
  1135.             else
  1136.                 d := d.nextDecoration;
  1137.         setCursor(arrow);
  1138.     end;
  1139.  
  1140. procedure xWindowDecoration.init;
  1141.     begin
  1142.         itsWindow := nil;
  1143.         nextDecoration := nil;
  1144.         visible := true;
  1145.         wantsKey := false;
  1146.         wantsClick := false;
  1147.         wantsCR := false;
  1148.         itsCursor := arrow;
  1149.         grayedOut := false;
  1150.     end;
  1151.  
  1152.  
  1153. procedure xWindowDecoration.install (Win: xWindow;
  1154.                                 theLeft, theTop, theWidth, theHeight: integer);
  1155.     var
  1156.         savePort: GrafPtr;
  1157.         d: xWindowDecoration;
  1158.     begin
  1159.         left := theLeft;
  1160.         top := theTop;
  1161.         width := theWidth;
  1162.         height := theHeight;
  1163.         itsWindow := win;
  1164.         nextDecoration := nil;
  1165.         if win.decorations = nil then
  1166.             win.decorations := self
  1167.         else begin
  1168.                 d := win.decorations;
  1169.                 while d.nextDecoration <> nil do
  1170.                     d := d.nextDecoration;
  1171.                 d.nextDecoration := self;
  1172.             end;
  1173.         adjustSize;
  1174.         if (win.theWindow <> nil) & visible then begin
  1175.                 GetPort(savePort);
  1176.                 SetPort(win.theWindow);
  1177.                 InvalRect(drawRect);
  1178.                 SetPort(savePort);
  1179.             end;
  1180.     end;
  1181.  
  1182. procedure xWindowDecoration.remove;
  1183.     var
  1184.         savePort: GrafPtr;
  1185.         d: xWindowDecoration;
  1186.         found: boolean;
  1187.     begin
  1188.         if itsWindow <> nil then begin
  1189.                 d := itsWindow.decorations;
  1190.                 found := false;
  1191.                 if d = self then begin
  1192.                         itsWindow.decorations := itsWindow.decorations.nextDecoration;
  1193.                         found := true;
  1194.                     end
  1195.                 else begin
  1196.                         while (d <> nil) & (d.nextDecoration <> self) do
  1197.                             d := d.nextDecoration;
  1198.                         if d <> nil then begin
  1199.                                 d.nextDecoration := d.nextDecoration.nextDecoration;
  1200.                                 found := true;
  1201.                             end;
  1202.                     end;
  1203.                 if found & (itsWindow.theWindow <> nil) then begin
  1204.                         GetPort(savePort);
  1205.                         SetPort(itsWindow.theWindow);
  1206.                         InvalRect(drawRect);
  1207.                         SetPort(savePort);
  1208.                     end;
  1209.                 itsWindow := nil;
  1210.                 nextDecoration := nil;
  1211.             end;
  1212.     end;
  1213.  
  1214. procedure xWindowDecoration.move (newLeft, newTop: integer);
  1215.     var
  1216.         savePort: GrafPtr;
  1217.     begin
  1218.         if (newLeft <> left) | (newTop <> top) then begin
  1219.                 left := newLeft;
  1220.                 top := newTop;
  1221.                 GetPort(savePort);
  1222.                 if (itsWindow <> nil) & (itsWindow.theWindow <> nil) then begin
  1223.                         GetPort(savePort);
  1224.                         SetPort(itsWindow.theWindow);
  1225.                         InvalRect(drawRect);
  1226.                         SetPort(savePort);
  1227.                         adjustSize;
  1228.                     end;
  1229.             end;
  1230.     end;
  1231.  
  1232. procedure xWindowDecoration.setSize (newWidth, newHeight: integer);
  1233.     var
  1234.         savePort: GrafPtr;
  1235.     begin
  1236.         if (newHeight <> height) | (newWidth <> width) then begin
  1237.                 height := newHeight;
  1238.                 width := newWidth;
  1239.                 GetPort(savePort);
  1240.                 if (itsWindow <> nil) & (itsWindow.theWindow <> nil) then begin
  1241.                         GetPort(savePort);
  1242.                         SetPort(itsWindow.theWindow);
  1243.                         if visible then
  1244.                             InvalRect(drawRect);
  1245.                         adjustSize;
  1246.                         if visible then
  1247.                             InvalRect(drawRect);
  1248.                         SetPort(savePort);
  1249.                     end;
  1250.             end;
  1251.     end;
  1252.  
  1253. procedure xWindowDecoration.kill;
  1254.     begin
  1255.         remove;
  1256.         dispose(self);
  1257.     end;
  1258.  
  1259. procedure xWindowDecoration.hide;
  1260.     var
  1261.         savePort: GrafPtr;
  1262.     begin
  1263.         if visible then begin
  1264.                 visible := false;
  1265.                 if (itsWindow <> nil) & (itsWindow.theWindow <> nil) then begin
  1266.                         GetPort(savePort);
  1267.                         SetPort(itsWindow.theWindow);
  1268.                         InvalRect(drawRect);
  1269.                         SetPort(savePort);
  1270.                     end;
  1271.             end;
  1272.     end;
  1273.  
  1274. procedure xWindowDecoration.show;
  1275.     var
  1276.         savePort: GrafPtr;
  1277.     begin
  1278.         if not visible then begin
  1279.                 visible := true;
  1280.                 if (itsWindow <> nil) & (itsWindow.theWindow <> nil) then begin
  1281.                         GetPort(savePort);
  1282.                         SetPort(itsWindow.theWindow);
  1283.                         InvalRect(drawRect);
  1284.                         SetPort(savePort);
  1285.                     end;
  1286.             end;
  1287.     end;
  1288.  
  1289. procedure xWindowDecoration.useCursor (c: cursor);
  1290.     begin
  1291.         itsCursor := c;
  1292.     end;
  1293.  
  1294. procedure xWindowDecoration.forceRedraw;
  1295.     var
  1296.         savePort: GrafPtr;
  1297.     begin
  1298.         if (itsWindow = nil) | (itsWindow.theWindow = nil) then
  1299.             EXIT(forceRedraw);
  1300.         GetPort(savePort);
  1301.         SetPort(itsWindow.theWindow);
  1302.         InvalRect(drawRect);
  1303.         SetPort(savePort);
  1304.     end;
  1305.  
  1306. procedure xWindowDecoration.adjustSize;
  1307.     begin
  1308.         if (itsWindow <> nil) & (itsWindow.theWindow <> nil) then begin
  1309.                 if left < 0 then
  1310.                     drawRect.left := itsWindow.theWindow^.portRect.right + left
  1311.                 else
  1312.                     drawRect.left := left;
  1313.                 if top < 0 then
  1314.                     drawRect.top := itsWindow.theWindow^.portRect.bottom + top
  1315.                 else
  1316.                     drawRect.top := top;
  1317.                 if height <= 0 then
  1318.                     drawRect.bottom := itsWindow.theWindow^.portRect.bottom + height
  1319.                 else
  1320.                     drawRect.bottom := drawRect.top + height;
  1321.                 if width <= 0 then
  1322.                     drawRect.right := itsWindow.theWindow^.portRect.right + width
  1323.                 else
  1324.                     drawRect.right := drawRect.left + width;
  1325.                 clickRect := drawRect;
  1326.             end;
  1327.     end;
  1328.  
  1329. procedure xWindowDecoration.doCR (ch: char);
  1330.     begin
  1331.     end;
  1332.  
  1333. procedure xWindowDecoration.doKey (ch: char;
  1334.                                 modifiers: longint);
  1335.     begin
  1336.     end;
  1337.  
  1338. procedure xWindowDecoration.doClick (localPt: point;
  1339.                                 modifiers: longint);
  1340.     begin
  1341.     end;
  1342.  
  1343. procedure xWindowDecoration.doDraw;
  1344.     begin
  1345.     end;
  1346.  
  1347. procedure xWindowDecoration.doActivate (active: boolean);
  1348.     begin
  1349.     end;
  1350.  
  1351. procedure xWindowDecoration.Idle;
  1352.     begin
  1353.     end;
  1354.  
  1355. end.