                         Screen & Window Management

     "The possession of gold has ruined fewer men than the lack of it."
                                         Thomas Bailey Aldrich, 1903

Introduction

          To put it bluntly, Turbo Pascal's writeln just isn't powerful
     enough for today's sophisticated applications. That's why Gold
     includes GOLDFAST and GOLDWIN. These units provide a powerful set
     of screen and window management routines, including the following:

          A family of flexible screen writing procedures making it easy
     to write at a specific location, write right-justified, write text
     automatically centered between two coordinates, etc. Routines to
     draw boxes and lines in a variety of shapes and sizes. The line
     drawing functions can automatically join-up with other lines
     already on display. 25, 43 and 50 line displays are supported.
     Virtual screens which can be created, written to and then moved to
     the visible screen for viewing. Multiple overlapping windows which
     can be partially dragged off screen, tiled, zoomed and stretched.
     Gold can write to partially or fully obscure Windows as well as the
     underlying background. All or part of the screen can be saved and
     restored with a variety of special effects. Routines to read the
     text or attribute directly from a screen or window. Functions to
     change the cursor shape and position. A set of boilerplate windows
     to prompt the user to select actions such as OK or Cancel, Yes or
     No, Live or Die, etc.

          TTT 5 Users  -- the windows management functions have been
     totally re-written for Gold. The old-style MkWin and RmWin
     procedures are still supported, but they don't offer any new
     functionality and are primarily offered for backward compatibility.
     To really leverage the power of Gold, you should change over to the
     new Winxxx procedures.

Understanding the Active Target

          If you don't have any windows or virtual screens, life is
     easy; every time you call one of the screen writing procedures
     (such as WriteAT) the text is written to the screen for all to see.
     No problem. However, if you have windows displayed or virtual
     screens created, Gold has to know where the text should be written.
     Remember, you can write to any window, virtual screen, or the
     visible screen. For example, on a desktop application, you might
     want to write some help text in window 1, display a list in window
     2, and perhaps write the current time to the background. Rather
     than force you to specify the target item with every procedure
     call, Gold uses the notion of active target. That is, at any one
     time either the visible screen, a virtual screen, or a window will
     have the active target, and Gold will direct all screen writing
     activity to that target. If you write some text which doesn't
     appear, check the active target -- you might be writing to a
     virtual screen or an obscured window.

     The following procedures support target management:

     ActivateWindow(Win:word);

          When you create a window, a window number or handle is
     returned. This procedure sets the target to the specified window.
     If the specified window does not exist, this procedure will be
     ignored.

     ActivateTopWindow;

          Makes the top-most window the target. If there are no windows,
     this procedure will be ignored.

     ActivateVirtualScreen(Page:word);

          Sets the target to the specified virtual screen. If the
     virtual screen does not exist, this procedure will be ignored.

     ActivateVisibleScreen;

          Sets the target to be the main screen. Gold will ignore all
     active windows and will write directly to the display. If there are
     windows displayed, you should use the next function.

     ActivateBackground;

     Use this function when windows are displayed and you want to write
     text behind the windows, i.e. to the background. If no windows are
     on display, this procedure is ignored.

General Purpose String Writing

The Write Procedures

          The following GOLDFAST functions will help you to quickly and
     easily write wherever you want:

     WritePlain(X,Y:byte; Str:string);
     WriteAT(X,Y,FB:byte; Str:string);
     WriteCol(Col,Row:byte; Str:string);
     WriteClick(X,Y,FB:byte;Str:string);
     WriteCenter(Y,FB:byte;Str:string);
     WriteMiddle(X,FB:byte;Str:string);
     WriteBetween(X1,X2,Y,FB:byte;Str:string);
     WriteRight(X,Y,FB:byte;Str:string);
     WriteVert(X,Y,FB:byte;Str:string);

          The procedure names are self-explanatory, but you can refer to
     the Reference Manual or the on-line help for a full description of
     each procedure. Note that Gold does not move the cursor during
     screen writes.

          If you specify a color attribute (FB) of UseTint (defined in
     GOLDATTR) with any of the screen writing procedures Gold will use
     the existing display attribute, i.e. written text will assume the
     color of the underlying screen or window.

          TTT 5 Users  -- all functions which accept a color use a
     combined color attribute, rather than separate foreground and
     background attributes. Refer to the section Specifying Display
     Colors in Chapter 3 for more information.

Writing ~Hi~

          In many applications you will want to write part of a string
     in one color, and the remainder of the string in another color. For
     example, when displaying the text "Are you sure you want to format
     the network server?", you might want the words format and network
     server to be in a color which makes them stand out clearly. One way
     to achieve this would be to write the text using several WriteAt
     statements, with a different attribute for each statement. A
     slicker way is to use Gold's WriteHi functions.

     WriteHi(X,Y,HiFB,FB:byte;Str:string);
     WriteHiCenter(Y,HiFB,FB:byte;Str:string);

          By embedding tilde characters ( ~ ) in the string, you can
     identify which portions of the string are to be written in each
     attribute. All characters up to the first tilde are written in the
     FB attribute, the text following the first tilde is written in the
     HiFB attribute. Thereafter, the attribute switches every time the
     tilde is encountered. The tilde characters are not displayed. To
     write the server format warning (described earlier) you might use
     the following statement:

     WriteHi(10,13,LightgrayOnBlue,WhiteOnBlue,
              'Are you sure you want to ~format~ the ~network server?');

          The concept of embedding tilde characters in strings is
     supported throughout Gold. For example, if you add an item to a
     pull down menu you can highlight a character by enclosing it within
     tildes, e.g. '~W~indow'. If you want to write a string with the
     first capital letter in a different color, use WriteCap as follows:

     WriteCap(X,Y,FBCap,FB:byte;Str:string);

          Run the demo DEMFS1 to see a variety of the screen writing
     functions in action.

Erasing Text and Changing Display Colors

     The following four procedures can be used to clear all or part of
     the text:

     Clear(FB:byte; C:Char);

          Clears the entire screen or window and fills the area with the
     specified character using the specified color.

     PartClear(X1,Y1,X2,Y2:byte; FB:byte; C:char);

          Similar to Clear, but only clears a specified region of the
     screen or window.

     ClearLine(Y,FB:integer);

          Clears an entire line, i.e. fills the entire line with spaces,
     using the specified attribute.

     ClearText(X1,Y1,X2,Y2,FB:byte);

          Similar to Clearline, but a rectangular section of the screen
     or window is cleared.

Writing Non-String Information

          One of the great strengths of Turbo Pascal's writeln is its
     ability to accept any number of variables of many different types.
     Unfortunately, the compiler does not allow third-party developers
     to create custom procedures with similar flexibility! There is no
     (practical) way around the fact that Gold's screen writing
     procedures only support strings. However, if you need to write
     other types, you can use the string conversion functions in GOLDSTR
     to cast different types to a string. For example, if you want to
     write an integer variable to a string you could use the IntToStr
     function as follows:

     WritePlain(1,1,IntToStr(ClientsAge));

          Although you may only pass one string argument to Gold's
     screen writing procedures, you can use Turbo Pascal's string
     concatenation operators to build a single string argument from
     multiple string components. For example, you could display
     someone's age with the following concatenated string:

     WritePlain(1,1,'Your age is '+IntToStr(ClientsAge));

          By using string casting functions and concatenation you can
     gain eighty percent of writeln's flexibility and take advantage of
     Gold's more powerful string writing procedures. One final thought.
     If you frequently write non-string types, you might consider
     writing your own procedure which is passed the non-string type and
     which, in turn, calls Gold's procedure. For example, the following
     procedure could be used to write any integer type:

          procedure WriteNumAt(X,Y,Attr: byte; Val:longint);
          {}
          begin
            WriteAT(X,Y,Attr,IntToStr(Val));
          end; { WriteNumAt }

          You might be wondering why we didn't include a whole family of
     procedures in Gold to accommodate all the varied types that you
     might need. We decided that 750 procedures was enough already.
     Write your own!

Box and Line Drawing

          To draw a box on the screen or window, simply call one of the
     following procedures:

     Box(X1,Y1,X2,Y2,FB,style:byte);

          Draws a rectangular box (using the ASCII box drawing
     characters) at the specified coordinates in the specified
     attribute. The style byte is described below. Note that the
     interior of the box is not written -- whatever was on the screen
     will remain visible.

     FBox(X1,Y1,X2,Y2,FB,style:byte);

          Like Box, but the interior of the box is filled.

     GrowFBox(X1,Y1,X2,Y2,FB,style:byte);

          Like FBox, but the box grows on the screen with a cutesy
     exploding effect.

     Box3D(X1,Y1,X2,Y2:byte;TLFB,BRFB,Style:byte);

          Like FBox, but the upper left and lower right sides are
     displayed with different attributes, giving a chiseled or 3-D
     effect. (Hey, its not bad for DOS.) The style attribute may have a
     value in the range 0 to 9. The box styles correspond with the
     window styles used throughout Gold. The appearance of the box is
     dependent upon the active character set, i.e. the box styles differ
     when custom characters are in use. The following table describes
     the supported box styles.

          Style  Standard Chars               Custom Chars

          0      No box (spaces)              No box (spaces)
          1      Single-line                  Single-line
          2      Double-line                  Single-line
          3      No box (spaces)              No box (spaces)
          4      Single-line                  Single edge line
          5      Two-line menu layout         Two-line menu layout
          6      Single line on three sides   Single line on three sides
          7      Single-line chiseled out     Single-line chiseled out
          8      Single-line chiseled in      Single-line chiseled in
          9      Special notepad              Special notepad


     Execute the program DEMFS2.PAS to see the supported box styles.

          To draw a single line using the following two functions, use a
     Style value of 1 for single lines and 2 for double lines:

     HorizLine(X1,X2,Y,FB,Style:byte);
     VertLine(X,Y1,Y2,FB,Style:byte);

          Use the smart-line drawing functions if you want to join
     intersecting lines. They will automatically draw box corners, and T
     junctions to join lines together. Cool.

     SmartVertLine(X,Y1,Y2,FB,Style:byte);
     SmartHorizLine(X1,X2,Y,FB,Style:byte);

          Execute the demo file DEMFS3.PAS to see the smart-line
     functions in action.

Reading the Display

          This section has nothing to do with optometry. If you want to
     literally pull characters or attributes from a specific location on
     the screen or window, you can use the following functions:

     ReadChar(X,Y:byte):char;

          Returns the character located at position (X,Y) of the target
     screen or window.

     ReadAttr(X,Y:byte):byte;

          Returns the attribute (or color) at position (X,Y) of the
     target screen or window.

     ReadWord(X,Y:byte;var Attr:byte; var Ch: char);

          Combines the above two functions into a single procedure call.

Customizing Scroll Bar Appearance

          Gold uses scroll bars in windows, lists, forms, etc. If you
     don't like the default characters used to create the scroll bars
     (shame on you), you can call the following procedure to instruct
     Gold to use your preferred characters:

     SetScrollChars(U,D,L,R,E,B:char);

          Defines which characters will be used to draw horizontal and
     vertical scroll bars. See the Reference Guide for further details.

          If you want to set the characters back to the (superior) Gold
     defaults, simply call the procedure SetScrollDefaults.

          Call procedures WriteHScrollBar and WriteVScrollBar to
     experiment with the scroll bar appearance. See the demo DEMFS4.PAS.

Automatic Line Wrapping

          GOLDFAST defines a global variable LineWrap which is used by
     the screen and window writing code to control whether Gold
     automatically wraps long strings to the next line. By default, line
     wrapping is turned off. If you want enable line wrapping, simply
     set LineWrap to true as follows:

          LineWrap := true;

Understanding Window Coordinates

          Normally, Gold uses global screen coordinates (which match the
     screen dimensions). For example, the (X,Y) coordinates (5,3)
     identify a location five character positions from the left side of
     the display and three rows down from the top of the display. Gold
     also supports local or window coordinates. When a local window is
     set, all screen writing coordinates become relative to the local
     window. The following routines provide coordinate support:

     SetWindow(X1,Y1,X2,Y2: byte);
     ResetWindow;
     SetWinIgnore(On:Boolean);
     GetSetWinIgnore(On:Boolean):boolean;

          Use the procedure SetWindow to limit screen writing within the
     specified coordinates. To remove the local window coordinates call
     ResetWindow -- this sets the screen writing back to the global
     coordinate system.

          Even though local window coordinates are set, you can instruct
     Gold to ignore them (or not) using the SetWinIgnore function.
     Alternatively, call GetSetWinIgnore if you want to record the
     ignore state, before temporarily setting it. Having written the
     appropriate data, set the coordinate state to its previous setting.
     You might use this function, for example, in a hooked procedure
     which displays a clock at the top right of the display, as follows:

          procedure DisplayTime;
          var IgnoreState: boolean;
          begin
             IgnoreState := GetSetWinIgnore(true);
             WriteAT(70,1,0,Time);
             SetWinIgnore(IgnoreState);
          end; { DisplayTime }

          The principles of active window coordinates apply to screens,
     virtual screens and windows.

          The demo program DEMFS5.PAS illustrates how to manipulate the
     window coordinate settings.

Managing Screens

Move Data Around the Screen

          The following three procedures manipulate data already visible
     on a screen:

     CopyScreenBlock(X1,Y1,X2,Y2,X,Y:byte);

          Copies text and attributes from one part of the screen to
     another. The source and target areas can overlap. The procedure is
     passed the upper left and lower right coordinates of the area to
     copy and the upper left coordinates of the target area.

     MoveScreenBlock(X1,Y1,X2,Y2,X,Y:byte);

          This procedure is similar to CopyScreenBlock except the
     original source area is erased.

     Scroll(Way:gDirection;X1,Y1,X2,Y2:byte);

          Scrolls text in a rectangular region of the screen. The data
     can be scrolled in any of the following four directions: Up, Down,
     Left, Right. One row or column of text is removed, blank characters
     are inserted in their place.

Using Virtual Screens

          When is a screen not a screen?  When it's a virtual screen. A
     virtual screen emulates the characteristics of the standard video
     memory, but is located on the heap. Virtual screens are used to
     save copies of the visible screen, as well as to prepare screens
     which can be pushed onto the visible screen in a flash (or with a
     sliding special effect).

          By default Gold supports five virtual screens. If (for some
     bizarre reason) you need more virtual screens, change the
     MaxVirtualScreens setting in GOLDFAST to a higher value.

Creating Virtual Screens

          To create a virtual screen simply call CreateScreen as
     follows:

     CreateScreen(Page,W,D,FB:byte);

          The page number is a value in the range 1 to MaxVirtualScreens
     (see note above). If that page is being used by another virtual
     screen, the screen will be overwritten. W and D represent the
     screen width and depth, respectively. A virtual screen can be as
     large as 255 characters wide by 255 rows deep. The last parameter,
     FB, is the default attribute of the newly created screen.

          Before writing to a virtual screen you should set the target
     focus using the ActivateVirtualScreen procedure (discussed
     earlier).

Saving the Visible Screen

          By calling SaveScreen you can create a virtual screen (with
     the same dimensions as the display) and automatically copy the
     visible screen contents to the virtual screen along with the cursor
     position and size. Use this function when you want to save the
     screen in its entirety to restore it later.

     SaveScreen(Page:byte);

     Saves the current screen (on the heap) for a subsequent restore.
     The only parameter passed is the page or screen number. If a screen
     has already been created with the same screen number, the old
     screen will be overwritten.

          When a virtual screen is created using CreateScreen or
     SaveScreen, memory must be allocated on the heap. Always check the
     LastFastError function to make sure the screen creation was
     successful. If the procedure fails due to a lack of memory, there
     are two probable causes.

          1 -- There really isn't enough memory.
          2 -- The maximum heap available has been restricted by the $M
               compiler directive (or the IDE equivalent).

Restoring Screens

          The user can only see the contents of a virtual screen when it
     is restored to the visible screen. To quickly restore a screen call
     the RestoreScreen procedure and identify the page or screen number
     of the page to be restored. The virtual screen is not affected by a
     restore; you can restore the same screen many times.

          If you only want to restore part of a virtual screen, use the
     following function:

     PartRestoreScreen(Page,X1,Y1,X2,Y2,X,Y:byte);

          Restores part of a virtual screen. The procedure is passed the
     screen number, the upper-left and lower-right coordinates of the
     area of the screen to be restored and the target coordinates for
     the top left corner of the area, i.e. part of a saved screen can be
     restored to a different location on the visible screen.

          For a little more pizzazz you can use a slide.i..n...g effect
     when you restore the screen. A little bit of flash goes a long way.
     The two slide functions (listed below) accept an additional
     argument of type gDirection, which is declared in GOLDFAST as
     follows:

          gDirection = (Up,Down,Left,Right,Vert,Horiz);

          As you might have deduced (Iowans excepted) this argument
     controls the direction used to slide the screen onto the display.

     SlideRestoreScreen(Page:byte;Way:gDirection);
     PartSlideRestoreScreen(Page:byte;Way:gDirection;X1,Y1,X2,Y2:byte);

Disposing of Screens

          Virtual screens consume memory (about 4000 bytes per 80 by 25
     screen). When you no longer need a virtual screen, you should
     dispose of it using the DisposeScreen function, as follows:

     DisposeScreen(Page:byte);

          Dispose of the memory used to store a virtual screen. If the
     specified screen doesn't exist, the procedure is ignored.

Using Condensed Screens

          Systems equipped with EGA or VGA displays can support the
     display of 43 or 50 lines of text. GOLDFAST includes the following
     two procedures to switch between condensed and standard modes.

     SetCondensed;

          Changes the display to 43 or 50 line mode.

     Set25;

          Sets the display mode to a standard 25 lines.

          The Gold variable HardVars.Depth is set to reflect the number
     of display lines.

          The mouse cursor will not be aware that the size of the screen
     has been altered. Having switched display modes you should call the
     mouse function MouseConfine (discussed in the next chapter) to
     allow the mouse to navigate the entire visible screen (and no
     more).

          Run the demo DEMFS6.PAS to see how to set display modes, and
     how to adjust the mouse.

Using Prefabricated Windows

          Most applications use a set of "standard windows" to interact
     with the user, e.g. message windows with some text and an OK
     button.

          Gold provides a set of prompt procedures and functions which
     make it easy to display text in a window. In each case, the
     procedure is passed a title and a message, and Gold computes the
     appropriate window size and position based on the length and
     content of the message text.

          For example, the following statement would instruct Gold to
     display a window with the title "Yowsa" and the message "What's
     happening babe?":

          PromptOK('Yowsa','What''s happening babe?');

          The user would be presented with the message window containing
     the text and a single OK button. Gold automatically calculates the
     window dimensions based on the input.

          The window style (i.e. box border) can be modified by setting
     the value of the variable WinVars.PromptStyle to a value in the
     range 1 to 9. The default is style 7.

          Gold provides the following prompt procedures and functions:

     PromptOK(Tit,Msg:string);

          Displays a message in a window with an OK button.

     PromptOKCancel(Tit,Msg:string): byte;

          Displays the title and message with OK and Cancel buttons. A 1
     is returned if OK is selected, and a 2 if Cancel is selected.

     PromptYesNo(Tit,Msg:string): byte;

          Like PromptOKCancel but the buttons say Yes and No.

     PromptCustom(Tit,Msg:string; But1,But2,But3:StrButton;
                  HK1,HK2,HK3, Default:word; WaitTime:longint): byte;

          Displays a custom prompt window with up to three custom
     buttons. As well as the title and the message, the function is
     passed the text of three buttons (null if the button is not needed)
     along with the hotkey for each button and the default. The final
     parameter is the wait time in milliseconds -- specify zero if you
     want to force the user to make a choice, otherwise the function
     will return a zero if the user has not pressed a button before the
     wait period has expired.

          In addition to the above prompt functions which accept the
     message as a single string, there are a corresponding set of
     functions which accept string linked lists (discussed in Chapter
     13) and are called PromptOKStrSLL, PromptOKCancelStrSLL,
     PromptYesNoStrLL, and PromptCustomStrLL. These functions allow you
     to display messages longer than 255 characters.

          Both the message text and the buttons supported embed "~"
     characters to allow two display colors to be used. Also, you can
     embed a split vertical bar character "|"  in the message string to
     force a line break, i.e. all text following the character will be
     written to the next line. One final tip: any line commencing with
     the "^" character will be automatically centered in the window. All
     these special characters are automatically stripped from the
     message before it is displayed.

          The button strings used in the standard (non-custom) prompt
     windows are defined as variables in GOLDWIN as follows:

          OKButStr: strButton = '  ~O~K  ';
          OKHotKey = 280;          { Alt+O }
          CancelButStr: strButton = '~C~ancel';
          CancelHotKey = 302;      { Alt+C }
          YesButStr: strButton = '   ~Y~es   ';
          YesHotKey = 277;         {Alt-Y}
          NoButStr: strButton = '   ~N~o   ';
          NoHotKey = 305;          {Alt-N}

          Both the text and the hotkeys can be changed for international
     applications.

          If you need to display a message longer than 255 characters,
     the message can be passed in the form of a string linked list
     (discussed in Chapter 13) using the following functions:

     PromptOKStrLL(Tit:string;StrLL:StringLL);
     PromptOKCancelStrLL(Tit:string;StrLL:StringLL): byte;
     PromptYesNoStrLL(Tit:string;StrLL:StringLL): byte;
     PromptCustomStrLL(Tit:string; StrLL:StringLL;  But1,But2,
                       But3:StrButton;  HK1,HK2,HK3,Default:word;
                       WaitTime:longint): byte;

          Other Gold units provide specialized windows such as forms,
     lists, calendars, calculators, file browsers and text editors.

Customizing Display Colors

          The colors used by the prompt windows are defined in GOLDTINT.
     The following table lists the member name along with the area
     affected:

          Tint Element        Description

          PromptBorder1       The color of the border line.
          PromptBorder2       The secondary color of the border line
                              when the style variable
                              WinVars.PromptStyle is set to 7 or 8.
          PromptTitle         The color of the title.
          PromptBody          The color of the window body.
          PromptBodyHi        The window of the highlighted text in the
                              window body, i.e. the text after the '~'.
          PromptButtonNorm    Standard color of the button when the
                              button doesn't have focus.
          PromptButtonNormHot Hi color of the button when the button
                              doesn't have focus.
          PromptButtonHi      Standard color of the button when the
                              button has focus.
          PromptButtonHiHot   Hi color of the button when the button has
                              focus.

          If you want to use custom display colors, simply change the
     appropriate element of the TINT color structure using the
     GoldSetcolor procedure. The following code is an extract of
     DEMPMT2.PAS:

          if ColorScreen then
          begin
             GoldSetColor(PromptBorder1,LightRedOnRed);
             GoldSetColor(PromptBorder2,LightRedOnRed);
             GoldSetColor(PromptTitle,WhiteOnRed);
             GoldSetColor(PromptBody,LightGrayOnRed);
             GoldSetColor(PromptButtonHiHot,WhiteOnMagenta);
             GoldSetColor(PromptButtonHi,YellowOnMagenta);
             GoldSetColor(PromptButtonNormHot,YellowOnMagenta);
             GoldSetColor(PromptButtonNorm,LightgrayOnMagenta);
          end;

          Run the demos DEMPMT1.PAS to DEMPMT5.PAS to see the prompt
     windows in action.

Creating and Managing Custom Windows

          If the standard prompt windows (described above) don't meet
     your needs, you can create your own custom windows.

Window Principles

          Gold supports an infinite number of windows (limited only by
     memory). A window has very similar properties to a screen: each
     window has a width, each window has a height, a window has an
     active cursor position and shape, and within the window there is an
     active area which can be written to. In addition to the screen-like
     properties, a window has a position, a style (or border design),
     and a title.

          When you want to display some information in a window, you
     should take the following steps:

          Decide on the window's dimensions, initial position, and style
          (discussed in the next section), then create a window
          structure by calling the WinCreate function, e.g.

               WinNum := WinCreate(5,5,75,20,4);

          The value returned by WinCreate is the logical window number
          (or handle) -- the first window will be window 1, etc. This
          window handle must be specified in the procedures called in
          steps 2 and 3. If WinCreate returns a zero, the window was not
          created (probably due to a lack of memory).

     Note:  Gold has not actually displayed the window at this stage;
     behind the scenes a window structure has been created in Gold's
     internal window list.

          Customize the window characteristics (such as the colors,
          title, etc.) using the WinSet... functions, e.g.

               WinSetTitle(1,' The Title ');

          Display the window by calling WinDisplay, e.g.

               WinDisplay(1);

          Get input from the user and check to see whether it is a
          window-specific keystroke/mouse action by calling the boolean
          function IsWinKey. If the function returns true, pass the
          keystroke data to the procedure WinProcessKey for processing,
          e.g.

               GetInput;
               if IsWinKey(LastKey,LastX,LastY) then
                  WinProcessKey(LastKey,LastX,LastY);

          Refresh the window contents (having written new data to it) by
          calling WinDrawTop or WinDrawAll.

          The following code is an extract from DEMWIN1.PAS which
          illustrates how to create, display and write to a window:

               WinHandle := WinCreate(5,5,75,20,1);
               WinSetType(WinHandle,WMove);
               WinSetTitle(WinHandle,' My First Window ');
               WinDisplay(WinHandle);
               WritePlain(1,1,'This .....');
               WinDrawAll;
               MouseShow(true);
               {now process keystrokes}
               with KeyVars do
                  repeat
                     GetInput;
                     if IsWinKey(LastKey,LastX,LastY) then
                        WinProcessKey(LastKey,LastX,LastY);
                  until (LastKey = 27) or (LastKey = 600);
               MouseShow(false);
               ResetStartupMode;

     Run the program DEMWIN1.PAS to see the code in action.

          To summarize, the window management process is: create,
     customize, display, handle input, redraw.

Window Styles

          A window style controls the format of the window border, i.e.
     whether it is single line, double line, etc. Gold supports nine
     different window styles -- ten, if you count style 0 which is no
     border.

          When a window is created (with the WinCreate function) the
     last byte parameter identifies the window style, and it should be a
     value in the range 0 through 9. These style numbers correspond with
     the box styles discussed on page 5-6. As with box styles, window
     styles are affected by the use of custom characters (refer to
     Chapter 3 for more information).

          Run the demo DEMWIN2.PAS to interactively modify the window
     styles and see the impact on the window border.

     The WinSet... Procedures

          After a window has been created, the properties of the windows
     can be changed from the defaults by using the following procedures:

     WinSetType(Win:integer;W:WinType);

          The window type controls which of the window border icons are
     active and visible. Windows can be a combination of closeable,
     moveable and stretchable. The first parameter identifies which
     window will have the type changed, and the second parameter
     indicates the new type. WinType is defined (in GOLDWIN) with the
     following members:

          WinType           Description

          WPlain            No icons.
          WClose            Close icon.
          WMove             Close icon and window can be dragged.
          WMoveNoClose      Window can be dragged but no close icon.
          WStretch          Window can be stretched, dragged and closed.

     WinSetMinSize(Win:integer;Width,Depth: byte);

          Defines the minimum size that a user can make a stretchable
     window.

     WinSetScrollType(Win:integer;S:ScrollType);

          Defines whether the window has horizontal and/or vertical
     scroll bars. The enumerated type ScrollType is defined in GOLDFAST
     with the following members: NoScroll, HorizScroll, VertScroll,
     BothScroll.

     WinSetColor(Win:integer; A:TintElement;C:byte);

          Sets the display color of a specific component (or element) of
     the window, e.g. the icons, the frame, the body, etc. See the
     section Window Colors (below) for further information.

     WinSetShowNum(Win:integer;On:boolean);

          Controls whether or not the window number is displayed on the
     top right of the window border.

     WinSetTitle(Win:integer;Tit:string);

          Sets the window title. Set to null to erase a title.

     WinSetPosition(Win:integer;NewX,NewY:shortint);

          Use this procedure to change the position of the top left
     corner of the window.

     WinSetStretchProc(Win:integer;S:StretchProc);

          During a user actioned window stretch (i.e. when the user is
     dragging the lower right window corner) Gold can call a stretch
     procedure to provide a way for the application to dynamically
     update the window during a stretch operation. Call this procedure
     to identify the name of the procedure which will be called as the
     window is stretched. Note that the procedure must be declared far
     with the following format:

          procedure MyProc(X1,Y1,X2,Y2:byte);

Window Shadows

          GOLDFAST includes the global variables ShadowType and
     ShadowAttr which control the position and color of window shadows.
     The shadow attribute may be any value in the range 0 to 255, and
     has a default value of 7 (lightgray on black). The following table
     identifies the impact of different ShadowType values:

          Value       Shadow Position

          0           Shadows drawn up and to the left.
          1           Shadows drawn up and to the right.
          2           Shadows drawn down and to the left.
          3           Shadows drawn down and to the right.
          4 or more   No shadow.

Window Colors

          For coloring purposes, a window is composed of several
     components, each of which may be assigned a different color. The
     table below lists the component together with a description.

          Component Description

          WinBorder        The standard window border.
          WinBorder3DIn    The "in" bump portion of the border for
                           styles 7 and 8.
          WinBorder3DOut   The "out" bump portion of the border for
                           styles 7 and 8.
          WinTitle         The window title.
          WinBody          The central part of the window (where text is
                           written).
          WinIcons         The close, zoom and stretch icons.
          WinCaption       The color of the title bar (or caption) when
                           used in styles 3 and 6 (the Windows emulation
                           styles).
          WinCustom        The color used to draw the Microsoft
                           Windows-style close and zoom icons for window
                           styles 3 and 6.
          WinBorderOff     The colors used to draw windows on the
                           desktop which don't have focus.

          There are two additional window colors which were not included
     in the table: WinMoveHi and WinMoveBody. These members are used to
     define the colors of the message displayed when a user presses
     Ctrl-F5 to move a window using the cursor keys.

          The default window colors are defined in GOLDTINT; there is
     one set for monochrome systems and another for color systems.

          To change the display colors for an individual window, you can
     call the WinSetColor procedure (discussed earlier) identifying the
     window component and the desired color, e.g.

     WinSetColor(WinNum,WinBorder,WhiteOnRed);
     WinSetColor(WinNum,WinTitle,YellowOnRed);
     WinSetColor(WinNum,WinBody,LightgrayOnRed);
     WinSetColor(WinNum,WinIcons,LightcyanOnRed);

          However, if you want to use a different (non-default) color
     scheme for all windows, change the GOLDTINT defaults prior to
     creating the windows. Refer to the section Customizing Display
     Colors in Chapter 3 for more information.

The Impact of Custom Characters

          Gold creates custom characters for line drawing, window icons,
     etc. The standard ASCII double line characters are not available
     when custom characters are active. If you have custom characters
     enabled, and you request a window style which uses double-line
     characters (such as style 2) Gold will automatically draw single
     lines instead. You can see the effect of the custom characters on
     window shapes by running DEMWIN1.PAS and toggling the Custom
     Characters check box. Refer to Chapter 3 for more information on
     the impact of custom characters on box and border drawing.

Processing Window Input

          There are many different user inputs which must be managed in
     a custom window: clicking on the various icons, dragging the window
     around the screen, stretching the window, double-clicking on the
     title, etc. Fortunately, Gold can manage all these inputs and leave
     you free to deal with the non-window related keystrokes and mouse
     clicks.

          The intricacies of managing mouse and keyboard input are
     discussed in the next Chapter, but the principles are simple. Any
     single user input can be defined with three variables: the
     keystroke which is of type word, and two bytes which identify the X
     and Y coordinates of the mouse cursor.

          Having garnered user input you can test whether the input is a
     window action by calling the function IsWinKey which is defined as
     follows:

     IsWinKey(K:word;KX,KY:byte):boolean;

          The function is passed three parameters identifying the
     keystroke details and returns true if the keystroke is a window
     management keystroke which can be handled automatically by Gold.
     If the function returns false, the keystroke is not associated with
     a generic window manipulation task (such as zoom or move), and
     should be handled by the application's own keyboard handler.

          If IsWinKey returns true, call the function WinProcessKey
     (defined below) to have Gold process the keystroke and manipulate
     the window as necessary.

     WinProcessKey(var K:word; var KX,KY:byte);

          This procedure is passed the window-related keystroke.

          Having processed the keystroke, Gold updates the passed
     parameters to indicate what window activity transpired. An
     application should evaluate the updated parameters and redraw the
     window contents as appropriate. For example, if the window was
     stretched, K will be updated with a value of  602, and the values
     of X and Y are irrelevant.

          The following table identifies the values which can be
     assigned to K along with those instances where X and Y also have a
     meaning.

          Key    Explanation

          600    The user clicked on the close icon and the window has
                 been closed.
          601    The window was moved or dragged.
          602    The window was zoomed or stretched, i.e. resized.
          610    The user clicked on the up arrow on the vertical
                 scrollbar.
          611    The user clicked on the down arrow on the vertical
                 scrollbar.
          612    The user clicked on the left arrow on the horizontal
                 scrollbar.
          613    The user clicked on the right arrow on the horizontal
                 scrollbar.
          614    The user clicked along the length of the vertical
                 scrollbar. X is updated to reflect the number of
                 characters down the scrollbar where the user clicked,
                 and Y identifies the length of the scrollbar in
                 characters.
          615    The user clicked along the length of the horizontal
                 scrollbar. X is updated to reflect the number of
                 characters along the scrollbar where the user clicked,
                 and Y identifies the length of the scrollbar in
                 characters.

The Timing of Window Updates

          The code which manages the window kernel is complex and
     primarily written in assembly language. So there! However, an
     understanding of the general architecture will help you to figure
     out when the visible screen is updated. It may also explain some of
     the odd behavior that occurs when you are tracing a program using
     the debugger.

          To allow for updates to fully or partially obscured windows,
     Gold maintains a window image off-screen. More often than not, an
     application will write several different strings to a window at one
     time. When you write to a window, the off-screen image of the
     window is immediately updated, but, to avoid unnecessary screen
     updates, the window image is not immediately transferred to the
     visible screen.

          The windows are updated on the visible screen when one of the
     following two functions is called:

     WinDrawAll;

          Forces an update of the screen background and all the windows.
     Thanks to the brilliance of the windows code, the user will not
     experience any flicker as the windows are updated.

     WinDrawTop;

          The top-most window is redrawn.

          If you want every window update to be automatically displayed
     on the visible screen, set the global GOLDFAST variable ShowNow to
     true.

Cursor Management

          Routines are available for hiding and displaying the cursor as
     well as changing the cursor shape from thin to half to full, or to
     any other available shape. The cursor routines function on
     monochrome and color video systems. As with screen and window
     updates, the cursor management functions are specific to the active
     window or screen.

Setting the Cursor Shape

          The following procedures can be used to set the cursor to one
     of four standard shapes:

     CursorOff;

          Makes the cursor invisible.

     CursorOn;

          Makes the cursor visible and sets it to the default DOS shape,
     i.e. a blinking line at the bottom of the character.

     CursorHalf;

          Makes the cursor a block filling the lower half of the
     character field.

     CursorFull;

          Makes the cursor a full block filling the entire character
     field.

          In text mode, an individual character is comprised of a number
     of scan lines. Usually the cursor is located on one or two scan
     lines near the bottom of the character. Different display systems
     use varying numbers of scan lines. For example, a monochrome
     display usually has fourteen scan lines, as does an EGA system, but
     a CGA only has 8. Use the function CharHeight to return the actual
     number of scan lines per character, before using CursorSize to set
     the cursor to a custom size.

     CharHeight: integer;

          Returns the number of scan lines per character used by the
     video display system in the current mode.

     CursorSize(T,B:byte);

          Sets the cursor to the specified top and bottom scan lines.
     The top scan line (e.g. the top bar of the letter "T") is scan line
     zero. As an example, to set the cursor to a half block filling the
     upper half of the screen (on a VGA system), call:

     SizeCursor(0,7);

     DEMFS8.PAS illustrates the cursor setting procedures.

Setting the Cursor Position

          You guessed it, to change the position of the cursor, call
     GotoXY and pass the new (X,Y) coordinates of the cursor. Gold's
     GotoXY is more sophisticated than Borland's GotoXY. For example, if
     you position the cursor in a window in a location that is
     physically off screen (because the window has been partially
     dragged screen), Gold will automatically make the cursor invisible.

     GotoXY(X,Y:byte);

          Positions the cursor (using local coordinates) relative to the
     active window or screen.

Getting the Cursor Details

          The following three routines will return information about the
     active window or screen's cursor location and size:

     CursorFind(var X,Y,Top,Bot:byte);

          Updates the passed parameters with the (X,Y) coordinates of
     the cursor, and the cursor's top and bottom scan lines.

     WhereX: byte;

          Returns the X coordinate position of the cursor.

     WhereY: byte;

          Returns the Y coordinate position of the cursor.

          If you want to manage the cursor using standard global screen
     coordinates (ignoring any local coordinates, windows and screens,
     etc.), you can use one of the following absolute cursor routines:

     AbsGotoXY(X,Y:byte);
     AbsWhereXY(var X,Y:byte);
     AbsCursorSize(T,B:byte);

Error Management

          Some of the GOLDFAST and GOLDWIN functions have the potential
     to fail. For example, CreateScreen may have insufficient memory.
     The Reference Manual identifies every procedure and function which
     may fail and set a non-zero error code. GOLDFAST and GOLDWIN
     provide the following two functions to test the success of the last
     command:

     LastFastError: integer;
     LastWinError: integer;

     Refer to Chapter 3 for more information on error management.

Other Neat Stuff

          Listed below are some additional procedures and functions
     which you may find useful:

     DrawShadow(X1,Y1,X2,Y2:integer);

          Draws a lightgray shadow down and to the right of the
     specified coordinates.

     Attrib(X1,Y1,X2,Y2,FB:byte);

          Changes the display attribute (i.e. color) of a region of the
     active screen or window. Note the text in the affected area is not
     deleted -- only the color of the text is changed. The procedure is
     passed the upper left and lower right (X,Y) coordinates together
     with the desired display attribute.

     ResetStartUpMode;

          Sets the display device to the same mode that was in effect
     when the program was executed and automatically removes any custom
     characters and replaces them with the standard ASCII character set.

