Using Windows "A gentleman is a man who can play the accordian, but doesn't." Anonymous The Object Hierarchy All the objects discussed thus far are independent, i.e. no object has any relationship with the others. However, the totWIN unit takes advan- tage of an OOP facility known as inheritance. Sometimes, a program just needs a quick pop-up window to display a message. Other times you may want to display a window which can be moved or dragged around the screen. Furthermore, in sophisticated pro- grams, you may want windows which can be moved and stretched by drag- ging the lower-right window corner. Using traditional Pascal you might create multiple window types, one to handle each window style. Or, you might create a single powerful window which is capable of providing the most sophisticated window needs, but with features that can be disabled when simple windows are required. Both of these solutions are clumsy and usually result in wasted code. Using OOP, we can create a basic window object, and then create a sibling window object which inherits all the properties of the basic window, but which has some additional features. This new window object can also have a sibling object which inherits the properties of the window objects from which it is derived. By linking these window objects together, an object hierarchy is formed. Figure 7.1 illustrates the totWIN object hierarchy. The four window objects have the following properties: WinOBJ This basic window object paints a pop-up window on the display, with an optional shadow. Once the window has been displayed, all screen writing is restricted to within the window boundaries. Once the window is removed, the original (underlying) screen contents are restored, and the cursor is restored to its previous location and shape. MoveWinOBJ This object has all the properties of the basic window, but the window can also be moved around the screen. This is useful for pop-up messages and the like, because the user can move the message to another location to see the obscured part of the display. ScrollWinOBJ This object has all the properties of the moveable window, but the window can also have optional scroll bars displayed on the right and lower window edges. 7-2 User's Guide -------------------------------------------------------------------------------- StretchWinOBJ This is the most sophisticated window object. It has all the properties of the other windows, but it can also be stretched and zoomed. Figure 7.1 [PICTURE] Window Object Hierarchy When you want to display a window, just create an instance of the appropriate window type and call the relevant window methods. For exam- ple, the following code fragment creates a basic pop-up window and displays the message "Hello Mum". (The individual methods will be discussed in detail in later sections.) When the program is executed, a simple window is displayed, and the user can exit by pressing [KEYCAP] or by clicking the mouse on the close [*] icon. program DemoWindowOne; {DEMWI1} Uses DOS,CRT, totFAST, totINPUT, totWIN; var MyWindow: WinOBJ; K: word; X,Y: byte; begin Screen.Clear(white,'°'); {paint the screen} with MyWindow do begin Init; Draw; Screen.WriteLn('Hello Mum'); Repeat WinGetKey(K,X,Y); until (K = 600) or (K= 27); Done; end; end. The following demo program, DEMWI2.PAS, is the same as the previous demo, except that the window instance is of type MoveWinOBJ. This pro- gram creates a moveable window. The user can move the window by holding down the mouse button on the top row of the window and dragging the window. The same effect can be achieved by pressing [KEYCAP]and using the arrow keys. Pressing [KEYCAP] ends the keyboard move operation. program DemoWindowTwo; {DEMWI2 - a moveable window} Using Windows 7-3 -------------------------------------------------------------------------------- Uses DOS,CRT, totFAST, totINPUT, totWIN; var MyWindow: MoveWinOBJ; K: word; X,Y: byte; begin Screen.Clear(white,'°'); {paint the screen} with MyWindow do begin Init; Draw; Screen.WriteLn('Hello Mum'); Repeat WinGetKey(K,X,Y); until (K = 600) or (K= 27); Done; end; end. Window Attributes The color scheme used by all windows defaults to the colors defined in the LookTOT^ instance. LookTOT^ also defines the special keys which are used to move, stretch and zoom windows using the keyboard. By modifying the LookTOT^ settings, you can quickly and easily change the default window colors and special keys. The two LookTOT^ methods which control the windows defaults are: LookTOT^.SetWindow(Border,Body,Icons,Title: byte); This method is used to specify the four window display attributes. All windows have four basic color zones: the window border (where the box is usually drawn), the main window body, the special mouse icons on the top border, and the attributes for the title. LookTOT^.SetWinKeys(Move,Stretch,Zoom: word); This method is used to define the keys which can be used to move, stretch and zoom a window. By default these keys are [KEYCAP], [KEYCAP] and [KEYCAP]. A user without a mouse must use these keys to manipulate a window. Refer to the LookTOT section on page 3-12 of chapter 3: Toolkit Basics for further information. 7-4 User's Guide -------------------------------------------------------------------------------- You can, of course, change the default window display attributes for any window instance. In other words, every window can have its own unique color combinations. LookTOT^ is simply used to define the default colors which will be used if no other colors are specified. Note: the special keys for window manipulation are not configurable for each individual window. It would be confusing for the user if different keys were used on different windows! All windows optionally support shadows. The shadow characteristics are controlled by the global instance ShadowTOT^. Refer to page 3-13 for further information. Getting User Input In the last chapter you learned that the KEY instance is used to deter- mine user input. If you were observant, you may also have noticed that some of the key codes in table 6.1 represented special window actions. For example, code 600 indicates that the user selected the close window icon. If there is a window on display, and you are waiting for user input, call the window method WinGetKey, rather than the Key.GetInput method. Behind the scenes, WinGetKey calls Key.GetInput. The user action is then checked to see if the user is trying to perform a window specific task, like clicking on the close icon, or moving the window. The window object will automatically process the key if it is a window-related task, and adjust the key to indicate the task performed. The following key codes indicate some window activity took place: 600 Window closed 601 Window moved 602 Window re-sized 610 Scroll Up 611 Scroll Down 612 Scroll Left 613 Scroll Right 614 Vertical Elevator 615 Horizontal Elevator Note: if the key code indicates that the window has been re-sized or scrolled, your application will need to refresh the window contents as appropriate. Many of the other Toolkit units provide automatic Using Windows 7-5 -------------------------------------------------------------------------------- support for displaying items like lists, files and directories in a window. All this screen refreshing and display management is handled for you. The syntax of the WinGetKey method is as follows: WinGetKey(var K:word; var X,Y: byte); This method is passed 3 variable parameters. The first parameter will be updated with the key the user pressed, and the second two parameters will be updated with the (X,Y) coordinates of the mouse when the action took place. If the key code is 614 or 615 (indicating the user clicked the mouse in the scroll bar) the (X,Y) coordinates represent the frac- tion (X/Y) showing how far down to scroll. Refer back to the example on page 7.3, and you will notice that WinGet- Key is called until the user selects the close icon (code 600) or presses [KEYCAP] (code 27). Basic Windows The basic window object type is WinOBJ. Any WinOBJ instance is a static pop-up window. Don't forget that every instance must be initialized with the INIT method and disposed of with the DONE method. The DRAW method is used to save the screen contents and display the window frame. Any subsequent screen writes will be within the window. The window can be removed with the method REMOVE, and the original screen contents are then restored. Ordinarily, the window is automatically removed when the DONE method is called. There are a variety of WinOBJ methods for setting the window character- istics, as follows: SetSize(X1,Y1,X2,Y2,Style:byte); When the window instance is initialized, the window is set with dimen- sions (10,5) to (70,20) in a style of 1. The style parameter is the same as the box style parameter discussed in chapter 5: Writing to the Screen page 5-7. Call the method SetSize to customize the size and style of the window. SetTitle(Title:string); Sets the window title. The window objects support the use of the title prefix characters, as discussed on page 5-8. If the Title is too long, it will be truncated to fit within the window boundaries. 7-6 User's Guide -------------------------------------------------------------------------------- SetColors(Border,Body,Title,Icons: byte); Use this method to customize the display attributes of the window. The four parameters represent the combined foreground/background attributes for the window border, window body, window title, and the close/zoom icons respectively. If your program will be run on monochrome and color systems, call the method Monitor^.ColorOn to decide whether to use color or monochrome color combinations. SetRemove(On:boolean); By default, the window is removed when the method Done is called. Use this method to control whether the window is removed or not. Pass TRUE to activate the window removal, or FALSE to leave the window image on the screen when Done is called. SetClose(On:boolean); This method controls whether the close icon [*] is drawn at the top left of the window. Pass TRUE to enable it, or FALSE to disable it. By default, the close icon is enabled. The following example, DEMWI3.PAS, shows how to use these basic window methods, and figure 7.2 shows the generated screen image: program DemoWindowThree; {DEMWI3 - WinOBJ settings} Uses DOS,CRT, totFAST, totINPUT, totWIN; var MyWindow: WinOBJ; K: word; X,Y: byte; begin Screen.Clear(white,'°'); {paint the screen} with MyWindow do begin Init; SetSize(5,5,25,10,3); SetTitle(' Greetings '); SetClose(false); SetRemove(false); SetColors(94,95,89,80); Draw; Screen.WritePlain(1,1,'Hello Mum'); Repeat WinGetKey(K,X,Y); until (K=27); Using Windows 7-7 -------------------------------------------------------------------------------- Done; end; end. Figure 7.2 [SCREEN] A WinOBJ Example The following WinOBJ function methods return information about the cur- rent window settings: GetSize(var X1,Y1,X2,Y2,Style: byte); This method is passed five variable parameters which are updated with the current window coordinates and style. GetX: byte; Returns the X coordinate of the upperleft window corner. GetY: byte; Returns the Y coordinate of the upperleft window corner. GetStyle: byte; Returns the window style. GetBorderAttr: byte; Returns the display attribute of the window border. GetBodyAttr: byte; Returns the display attribute of the main window area. GetIconsAttr: byte; Returns the display attribute of the window close and zoom icons. GetTitleAttr: byte; Returns the display attribute of the window title. GetRemoveStatus: boolean; 7-8 User's Guide -------------------------------------------------------------------------------- Returns true if the window will be removed when the Done method is called. Once you have initialized the window and assigned the appropriate set- tings, the window is ready to be displayed. To display the window, use one of the following two methods: Draw; The window is displayed, and the cursor is moved to the top left corner of the window. GrowDraw; This is the same as draw, except that the window g.r..o..w...s onto the screen for a special effect. Once the window has been drawn, use the standard Screen methods to write to the window. Note that the upperleft coordinate of the inner part of the window is (1,1). Refer to page 5-16 for a discussion of window coordinates. The following method, Remove, can be used to remove the window: Remove; Restores the original screen contents as well as the cursor location and shape. If window coordinates were active when the window was drawn, the previous window coordinates are restored. The Remove method is automatically called if the DONE method is called, if the remove setting is true and if the window is still on display. The Done method also disposes of any memory used by the window. Moveable Windows A moveable window is like the static windows just described, except that the user can move the window to any location on the screen. Remem- ber that a user can move the window by holding down the left mouse button on the top window border (making sure not to hit a window icon), and dragging the window around the display. The same result can be achieved by pressing the move hotkey (defined in LOOKtot^), which defaults to [KEYCAP]. The window can then be moved by pressing the cursor keys, and the move is completed by pressing [KEYCAP]. Using Windows 7-9 -------------------------------------------------------------------------------- A moveable window is created by declaring an instance of type MoveWi- nOBJ. Moveable windows share all the properties of static windows, and all the previously described methods are available. Moveable windows have the following two methods which restrict window movement: SetBoundary(X1,Y1,X2,Y2:byte); This method controls the area of the screen in which the window can be moved. By default, this boundary is the entire screen. Use this method to stop the user from placing the window on top of some information you want to be displayed. For example, the following statement will keep the window away from the top and bottom display lines: SetBoundary(1,2,80,24);. SetAllowMove(On:boolean); Not too surprisingly, by default, the Toolkit allows the user to move moveable windows. This method allows you to restrict, and later, enable window movement. Pass a False parameter to stop window movement, and a True to enable movement. Circumstances under which you might use this routine; you are using other Toolkit units, which themselves use move- able windows, but you want to disable movement. For example, message, list and browse objects. Refer back to DEMWI2.PAS on page 7.3 for an example of a moveable window. Windows with Scroll Bars If you have run some of the larger Toolkit demo programs, you may have noticed the scroll bars on some of the window boundaries. The scroll bars provide a way for the user to scroll a window's contents using the mouse. Various units in the Toolkit (discussed in later chapters) pro- vide comprehensive support for displaying files, directories and lists in windows with scroll bars. However, if these objects don't meet your needs, you can build your own scrollable window using the ScrollWinOBJ object. ScrollWinOBJ is a descendant of MoveWINOBJ, and so shares all the prop- erties and methods of the moveable windows just discussed. In essence, a scrollable window is simply a moveable window with scroll bars (see figure 7.3). Figure 7.3 [SCREEN] A Scrollable Window 7-10 User's Guide -------------------------------------------------------------------------------- Scrollable windows support both horizontal and/or vertical scroll bars, which can be activated by calling the following method: SetScrollable(Vert,Horiz:boolean); This method controls which scroll bars are drawn; the first parameter controls the vertical scroll bar, and the second the horizontal one. Pass a TRUE to instruct the window to display the scroll bars. By default, both scroll bars are disabled, i.e. set to false. The sliding elevator in the body of the scroll bar gives the user a visual indication of which part of the data is currently being dis- played in the window. For example, if the window is displaying a file and the elevator is at the top of the scroll bar, the user must be looking at the first part of the file. As the user scrolls down, the elevator will jump down in increments. When the end of the file is being viewed, the elevator will be at the bottom of the scroll bar. Similary, the horizontal elevator will show the relative lateral posi- tion of the window, e.g. how far along the line is being viewed. Whenever you change the contents of a scrollable window, you should re-draw the scroll bar(s) to show the relative location of the dis- played data. The methods DrawHorizBar and DrawVertBar are used for this purpose. When a scroll bar is re-drawn, the Toolkit must be instructed where to position the elevator. This is achieved by passing two parame- ters to the drawing methods. The first parameter represents the current value (or location), and the second is the maximum value. For example, if you are browsing a 1000 line file, and the first line visible in the window is 265, the passed parameters would be (265,1000). The syntax of the scroll bar drawing methods is as follows: DrawHorizBar(Current,Max:longint); Draws a horizontal scroll bar at the bottom of the window and positions the elevator based on the fraction (Current/Max). DrawVertBar(Current,Max: longint); Draws a vertical scroll bar at the right of the window and positions the elevator based on the fraction (Current/Max). Once you have initially displayed the window, call the method WinGet- Key(K,X,Y); (discussed on page 7-4) to determine the user action. The following key codes indicate some scrolling activity: Using Windows 7-11 -------------------------------------------------------------------------------- 610 Scroll Up 611 Scroll Down 612 Scroll Left 613 Scroll Right 614 Vertical Elevator 615 Horizontal Elevator You should re-draw the window contents based on the action requested by the user. The codes 614 and 615 indicate the user clicked the left mouse button on the body of the scroll bar. This means the user wants to jump to a different part of the data. The X and Y parameters returned from WinGetKey indicate which data to display. The X coordi- nate represents the number of characters along from the top (or left) of the scroll bar where the user clicked the mouse. The Y coordinate indicates the total length of the scroll bar. For example, if the X and Y parameters are returned as 5 and 15, respectively, you need to display the data which is 5/15ths of the way from the top of the data. In our example of a 1000 line text file, you would need to display the lines commencing with line 333, i.e. (5/15)*1000. Having re-drawn the window contents, don't forget to re-draw the scroll bars. Note: only window styles 1 through 5 support scrollable windows. If the style is set to any other value, the window will use style 1. Stretchable Windows The most flexible form of window supported by the Toolkit is called a stretchable window. A stretchable window is a moveable window, the dimensions of which can also be changed. A user can change the size of a stretchable window by pressing down the left mouse button on the lower right corner of the window and dragging the corner to the desired location. The same result can be achieved by pressing the stretch hotkey (defined in LOOKtot^), which defaults to [KEYCAP]. The window can then be moved by pressing the cursor keys, and the move is com- pleted by pressing [KEYCAP]. A user can also zoom the window to its full size by clicking on the zoom icon, located at the top right of the window. When the window is 7-12 User's Guide -------------------------------------------------------------------------------- fully zoomed, it can be restored to its pre-zoom dimensions by clicking on the zoom icon a second time. The default zoom and un-zoom key is [KEYCAP]. To create a stretchable window, create an object instance of type StretchWinOBJ. This object is descendant from ScrollWinOBJ and so shares all its characteristics and methods. The coordinates of a full zoomed window are defined with the SetBounda- ries method described in the previous section. The following method is used to control the minimum window size: SetMinSize(Width,Depth: byte); The two parameters set the minimum width and depth of the window in characters. By default, the minimum is 10 characters wide by 5 charac- ters deep. The following method can be used to control whether the user is allowed to stretch and zoom the window: SetAllowStretch(On:boolean); Pass a False parameter to disable window stretching, or a True parame- ter to enable window stretching. When stretching is disabled, the size of the window cannot be changed with either the mouse or the keyboard. Whenever a user stretches or zooms a window, the window is re-drawn with the new dimensions, and the body of the window is cleared. You must then rewrite the window contents, and re-draw the scroll bars. WinGetKey will return a code of 602 if the user has re-sized the win- dow. Listed below is the demo program DEMWI4.PAS which provides a framework for building your own scrollable window routines. program DemoWindowFour; {DEMWI4 - a StretchWinOBJ template} Uses DOS,CRT, totFAST, totINPUT, totWIN; var MyWindow: StretchWinOBJ; K: word; X,Y: byte; Using Windows 7-13 -------------------------------------------------------------------------------- procedure ScreenRefreshProc; {This procedure would refresh the screen contents} begin Screen.WritePlain(1,1,'Fresh Screen'); {...} MyWindow.DrawHorizBar(1,100); {the parameters should reflect} MyWindow.DrawVertBar(1,100); {the data position of the window} end; procedure ScrollUpProc; begin end; procedure ScrollDownProc; begin end; procedure ScrollLeftProc; begin end; procedure ScrollRightProc; begin end; procedure ScrollJumpVertProc(X,Y:byte); begin end; procedure ScrollJumpHorizProc(X,Y:byte); begin end; begin Screen.Clear(white,'°'); {paint the screen} with MyWindow do begin Init; SetTitle(' Template '); SetBoundary(1,1,80,24); SetScrollable(true,true); Draw; ScreenRefreshProc; Repeat WinGetKey(K,X,Y); case K of 602: ScreenRefreshProc; 610: ScrollUpProc; 611: ScrollDownProc; 612: ScrollLeftProc; 613: ScrollRightProc; 614: ScrollJumpVertProc(X,Y); 7-14 User's Guide -------------------------------------------------------------------------------- 615: ScrollJumpHorizProc(X,Y); end; until (K=27) or (K=600); Done; end; end. In Part 2: Extending the Toolkit, techniques for creating objects descendant from ScrollWinOBJ are discussed. Specifically, the text describes how to create an object for scrolling a virtual screen within a window.