Replacing the Screen Writer "I don't want to achieve immortality through my work, I want to achieve immortality by not dying." Woody Allen The Toolkit uses some assembly language routines for writing to the screen, as well as for moving blocks of data to and from the screen. The routines are optimized for maximum speed, and by-pass BIOS, i.e. they write directly to the video area of memory. If you are using a non-standard display device, such as a palmtop computer, or you don't like the (1..80,1..25) coordinate scheme, or for whatever other reason, you can develop your own screen writing code to meet your custom needs. In this chapter you will learn how to create an object to replace the Toolkit's screen writing routines. Understanding ScreenOBJ and WriteOBJ Before discussing how to replace the Toolkit's methods, you need to understand how those methods work. Bear in mind that your replacement algorithms may need to write to virtual screens as well as to the physical screen. The ScreenOBJ object is the primary Toolkit object for managing screen and video related activity. The global instance Screen is automatically initialized when you use the totFAST unit, and you should use the Screen instance for all writing to the visible display. Additional ScreenOBJ instances can be used to manage virtual (or non-visible) screens. The method SAVE is used to save a copy of the visible screen, and the method CREATE is used to create an empty virtual screen with maximum dimensions of 255 rows by 255 columns. All or part of a virtual screen can subsequently be displayed on the visible screen. Each ScreenOBJ instance includes a pointer to a WriteOBJ object. Wri- teOBJ actually performs the core screen writing functions. For example, when you call ScreenOBJ's method WriteAT, behind the scenes the Toolkit calls the WriteOBJ method WriteAT. By instructing ScreenOBJ to point to a different WriteOBJ object you can change how screen tasks are per- formed. In other words, by creating a new WriteOBJ object, you change how the Toolkit accesses the video functions. The two step process is to create a descendant of WriteOBJ, and then instruct all ScreenOBJ instances to use this new object. 17-2 Extending the Toolkit -------------------------------------------------------------------------------- Replacing WriteOBJ The primary functions of WriteOBJ are to write to the screen, to move blocks of data to and from the screen, to position the cursor, to manage window settings, and to change the display attribute of a rect- angular area of the screen. The declaration of WriteOBJ is as follows: WritePtr = ^WriteOBJ; WriteOBJ = object vWidth: byte; {how wide is screen} vScreenPtr: pointer; {memory location of screen data} vWindow: tByteCoords; {active screen area} vWindowOn: boolean; {is window area active} vWindowIgnore: boolean; {ignore window settings} {methods...} Constructor Init; procedure SetScreen(var P:Pointer; W:byte); function WindowOff: boolean; procedure SetWinIgnore(On:Boolean); procedure WindowOn; procedure WindowCoords(var Coords: tByteCoords); function WindowActive: boolean; function WinX: byte; function WinY: byte; procedure GetWinCoords(var X1,Y1,X2,Y2:byte); procedure WriteAT(X,Y,attr:byte;Str:string); VIRTUAL; procedure WritePlain(X,Y:byte;Str:string); VIRTUAL; procedure Write(Str:string); VIRTUAL; procedure WriteLn(Str:string); VIRTUAL; procedure GotoXY(X,Y: word); VIRTUAL; function WhereX: word; VIRTUAL; function WhereY: word; VIRTUAL; procedure SetWindow(X1,Y1,X2,Y2: byte); VIRTUAL; procedure ResetWindow; VIRTUAL; procedure ChangeAttr(Col,Row,Att:byte;Len:word); VIRTUAL; procedure MoveFromScreen(var Source,Dest;Length:Word); VIRTUAL; procedure MoveToScreen(var Source,Dest; Length:Word); VIRTUAL; procedure Clear(Att:byte;Ch:char); VIRTUAL; destructor Done; VIRTUAL; end; {WriteOBJ} WriteOBJ's data describes the size and memory location of the screen, and the status of the window settings. Replacing the Screen Writer 17-3 -------------------------------------------------------------------------------- vWidth is a byte variable which identifies the width of the screen. vScreenPtr is a pointer to the start of the screen display memory area. The memory is organized into byte pairs, like actual video display memory - the first byte is the attribute of a character and the second byte is the ASCII code of the character. The associated ScreenOBJ instance allocates the necessary memory and calls the WriteOBJ method SetScreen to update the vWidth and vScreenPtr variables. The other variables provide information about the screen's active win- dow. vWindow is a record describing the (X1,Y1) and (X2,Y2) active window coordinates. vWindowOn and vWindowIgnore are two boolean variables which indicate whether the window settings are active. If vWindowOn is false or vWindowIgnore is true, the WriteOBJ screen writ- ing methods should ignore the current window settings. The virtual methods shown in the WriteOBJ declaration represent the heart of the screen writing routines. The table below describes their specific purpose. Method Description WriteAT(X,Y,attr:byte;Str:string); Writes to the screen at (X,Y) using the specified attribute. WritePlain(X,Y:byte;Str:string); Writes to the screen at (X,Y) using that region's attribute. Write(Str:string); Writes at the current cursor position like Turbo's Write. WriteLn(Str:string); Write at the current cursor posi- tion like Turbo's WriteLn. GotoXY(X,Y: word); Positions the cursor at (X,Y). WhereX: word; Returns the cursor's X coordi- nate. WhereY: word; Returns the cursor's Y coordi- SetWindow(X1,Y1,X2,Y2: byte); nate. ResetWindow; Sets the window coordinates to specified coordinates. ChangeAttr(Col,Row,Att:byte; Sets the window coordinates to Len:word); entire screen. MoveFromScreen(var Source,Dest; Changes the display attribute to Len:Word); Att starting at (X,Y) for Len bytes. Moves a block of memory from MoveToScreen(var Source,Dest; Source to Dest, assuming Source Len:Word); is the visible screen. Len repre- Clear(Att:byte;Ch:char); sents the number of words (not 17-4 Extending the Toolkit -------------------------------------------------------------------------------- bytes) to move. As above, but assumes Dest is the Done; visible screen. Clears a rectangular area of the display to the specified attrib- ute and replaces all characters with Ch. Disposes of the object. To develop your own WriteOBJ object, you should create a descendant of WriteOBJ, and thanks to inheritance, you can replace as little as one procedure or as many as all of them. The file EXTSCR1.PAS is a demonstration unit which creates a new object. The new object is called MonoWriteOBJ, and the objective is to force the Toolkit to use the attribute white-on-black, regardless of the attribute specified. The declaration of MonoWriteOBJ is as follows: Unit ExtFast; {$I TOTFLAGS.INC} INTERFACE uses DOS, CRT, totFAST; TYPE MonoWriteOBJ = object (WriteOBJ) constructor Init; procedure WriteAT(X,Y,attr:byte;Str:string); VIRTUAL; procedure ChangeAttr(X,Y,Att:byte;Len:word); VIRTUAL; procedure Clear(Att:byte;Ch:char); VIRTUAL; destructor Done; VIRTUAL; end; {MonoWriteOBJ} IMPLEMENTATION constructor MonoWriteOBJ.Init; {} begin WriteOBJ.Init; TextColor(white); Textbackground(black); end; {MonoWriteOBJ.Init} procedure MonoWriteOBJ.WriteAT(X,Y,attr:byte;Str:string); {} begin WriteOBJ.WriteAT(X,Y,white,Str); end; {MonoWriteOBJ.WriteAT} Replacing the Screen Writer 17-5 -------------------------------------------------------------------------------- procedure MonoWriteOBJ.ChangeAttr(X,Y,Att:byte;Len:word); {} begin WriteOBJ.ChangeAttr(X,Y,white,Len); end; {MonoWriteOBJ.ChangeAttr} procedure MonoWriteOBJ.Clear(Att:byte;Ch:char); {} begin WriteOBJ.Clear(white,Ch); end; {MonoWriteOBJ.Clear} destructor MonoWriteOBJ.Done; {} begin WriteOBJ.Done; end; {MonoWriteOBJ.Done} end. MonoWriteOBJ redefines the three primary methods which control display attributes. It intercepts the requested attribute and always substi- tutes the attribute white. If you want to modify the way the Toolkit writes to the physical screen, but are satisfied with the virtual screen routines, then your unit should use the totSYS unit, and the revised methods should use the following statement to determine whether the instance is pointing to the visible screen: if vScreenPtr = Monitor^.BaseOfScreen then {new visible screen routines} else {virtual screen} {call equivalent WriteOBJ method}; Using the Method AssignWriteOBJ Having created your new object, you must instruct the Toolkit to use it. This is achieved by initializing your object, and then calling the ScreenOBJ method AssignWriteOBJ method. For example: Screen.AssignWriteOBJ(WhiteWrite); Any virtual screens you create must be assigned the new WriteOBJ object individually in the same manner. For example: Save3.AssignWriteOBJ(WhiteWrite); 17-6 Extending the Toolkit -------------------------------------------------------------------------------- The demo program, EXTDEM3.PAS, listed below, shows the new ExtFast unit in use. This program is actually an adaptation of DEMBR1, which uses MonoWriteOBJ in preference to WriteOBJ. If you run it, you will see that the entire display uses white on black, even though other attrib- utes are specified. Program ExtendedDemoThree; {EXTDEM3 - this program shows how to use the MonoWriteOBJ object developed in the ExtFast unit. The demo is actually a simple adaptation of the browse demo file DEMBR1} Uses DOS,CRT, totINPUT, totFAST,totLIST, totSTR, ExtFast; var WhiteWrite: MonoWriteOBJ; BWin: BrowseArrayOBJ; StringList: array[1..26] of string[100]; I : integer; begin WhiteWrite.Init; Screen.AssignWriteOBJ(WhiteWrite); for I := 1 to 26 do {first assign something to the string array} StringList[I] := 'Line '+IntToStr(I)+': '+replica- te(80,char(I+64)); ShadowTot^.SetShadowStyle(downright,red,chr(219)); Screen.Clear(green,' '); {paint the screen} Key.SetFast; Key.SetClick(true); with BWin do begin Init; AssignList(StringList,26,100); Go; Done; end; end.