Statement CLASS Foundation

Class declaration

Syntax
[STATIC|FREEZE|FINAL] CLASS <ClassName> ;
                      [FROM <SuperClass,...>] ;
                   [SHARING <SuperClass,...>]
              [CLASS METHOD initClass]
                   [ METHOD init]
         <class declaration statements>
                   ENDCLASS
Parameters
STATIC
If the optional STATIC clause is used, the class function is treated as a STATIC FUNCTION and can only be called within the source code file in which the class is declared and implemented. The class object and class name are not registered with the Xbase++ runtime. A call of ClassObject(<ClassName>) will return NIL.
FREEZE
By using FREEZE a class is no more allowed to be replaced by another class with the same name. By default Xbase++ allows the replacement of classes at runtime. Using FREEZE, class implementars can ensure that their class is not replaced by a different implementation. Attempting to replace a frozen class using a dynamically created class ( ClassCreate() ) raises a runtime error. Subclassing is still allowed.
FINAL
A FINAL class can not be used as a superclass. Final classes cannot be subclassed, consequently it is not possible to change behaviour of final classes. Attempting to create a subclass from a final class leads to a runtime error.
<ClassName>
<ClassName> is the name of the class being defined. It also serves as the name of the class function which returns a reference to a class object for that class. The name for the class follows the same convention as function names. It must begin with an underscore or a letter and must contain alpha numeric characters. The first 255 characters are significant.
<SuperClass,...>
<SuperClass,...> is a comma separated list of names of the classes from which the new class derives. When the optional FROM clause is used, the new class inherits all the member variables and methods of the superclasses. As a result, a new level is created in the class hierarchy. The new class lies at the bottom of the inheritance tree and can execute all the methods which are not declared as HIDDEN: in the superclasses.
When the class variables of the superclasses are not declared as SHARED, they are applied in the new class as copies. Changes made to these variables by instances of the new class <ClassName> are not reflected in instances of the superclasses. However, when class variables are declared as SHARED in the superclasses, changes made to these variables are reflected in the superclasses as well as in the new class <ClassName>.
The optional clause SHARING is only significant for class hierarchies that employ multiple inheritance where two or more superclasses have member variables with the same names. If separate member variables with the same name exist in two superclasses, only one member variable applies in the new class <ClassName>. (More information may be found in the section "Inheritance and overwrite" in the chapter Basics of Programming with Objects.)
CLASS METHOD initClass
The class method :initClass() may optionally be declared. When declared, it is invoked once, immediately after the first call to the class function. The :initClass() method is a good place to initialize class variables with default values. The code for the :initClass() method must be implemented separately after the statement ENDCLASS. When writing an :initClass() method, a reference to the class object is available in the variable self.
METHOD init
The method :init() may optionally be declared. When declared, it is invoked immediately after a new instance of the class (an object) has been instantiated via the method:new(). :Init() is usually used to initialize the instance variables of the instantiated object with default values. Like all methods, the code for :init() must be implemented separately after the statement ENDCLASS. The same arguments passed to the :new() method are passed to the :init() method. A reference to the newly instantiated object is available to the :init() method in the variable self.
Description

The statement CLASS starts the declaration of a class. Following the class definition are the declarations of the member variables and methods which are available to instances of the class. The class declaration ends with the statement ENDCLASS. Following the declaration section, the methods declared in the class must be coded. (See: METHOD (Implementation)).

The class declaration CLASS...ENDCLASS consists entirely of four parts:

Define the class function
Declare the classes from which to inherit (superclasses)
Declare the class variables and class methods
Declare the instance variables and instance methods

The class function has the function name <ClassName> and returns a reference to the class object. The class object represents the class and using the class method :new(), generates instances (objects) of the class. The word "new" is reserved and cannot be used as the name of a method or an instance variable. Other reserved identifiers used for methods in all classes are listed in the table below:

Reserved methods
Method Description
:className() Returns the class name as a character string
:classObject() Returns the class object of an instance
:isDerivedFrom() Determines whether or not an object is derived from a particular class :isDerivedFrom(<cClassName> | <oClassObject>) --> .T.|.F.
:new() Creates instances of a class

When the class declaration uses the optional statement STATIC CLASS, the class function is a STATIC FUNCTION and cannot be called outside the source code file within which the class is declared.

A class may be produced from previously declared classes. The names of the declared classes must be indicated by the statement CLASS with the option FROM as a comma separated list <SuperClass,...>. These classes are superclasses, and the new class is a subclass of the superclasses. All classes that are not declared as STATIC, may be used as superclasses, including classes contained in the Xbase++ language. The new class <ClassName> inherits the entire structure of the superclasses. In this way, the new class has access to all member variables and methods of the superclasses which are not declared with the HIDDEN: visibility attribute within the superclasses.

The option FROM defines all classes whose member variables and methods are to be inherited by the new class. If class variables exist in the superclasses, all the class variables of the superclasses which are not declared SHARED are added to the class <ClassName>. When SHARED is not used, the new class receives its own class variables with the same names as those in the superclasses. In this case the new class cannot access the same class variables as the superclasses. The new class has, effectively, received copies of the class variables of the superclasses and accesses its own values.

The option SHARING is significant only when the new class <ClassName> inherits from two or more classes <SuperClass,...>which themselves have a common superclass. The following example should help explain this relationship: Assume a class A with an instance variable iVarA. Classes B and C are subclasses of class A (and thus each include a copy of iVarA). Finally a class D is declared which is derived from classes B and C. When the SHARING option is used in the class D declaration, both of the inherited copies of the instance variable iVarA in classB and C are brought together as a single instance variable in class D. Class D then has only one copy of instance variable iVarA.

The following statements (<class declaration statements>) are used in declaring member variables and methods:

Statements for the declaration of a class
Statement Meaning
HIDDEN: Only visible within methods of this class
PROTECTED: Only visible within methods of this class and its subclasses
EXPORTED: Visible to the entire application (globally visible)
CLASS VAR ..[IS]..[IN] Declaration of a class variable
VAR ..[IS]..[IN] Declaration of an instance variable
CLASS METHOD ..[IS]..[IN] Declaration of a class method
METHOD ..[IS]..[IN] Declaration of an instance method

By default, all of the instance variables and methods declared in the class are treated as having HIDDEN: visibility. When a member variable or method is HIDDEN:, it is not visible outside the methods of the class. When the visibility attribute PROTECTED: or EXPORTED: is used, all subsequent member variables and methods declared assume this visibility until a different visibility attribute is used. In addition to the keywords affecting visibility, member variables can assume separate attributes that control the ability to assign values (write access). More information on visibility may be found in the sections discussing the respective attributes.

Details for the declaration of member variables and methods are found in the sections covering the corresponding statements.

The optional clauses STATIC, FREEZE and FINAL can not mixed. Their usage is mutual exclusive.

Examples
Declaring a CLASS
// The program example shows the basic procedure for 
// declaring a class and programming its methods. 
// The label class supports the ability to display a value 
// on the screen at specific coordinates and in a specific 
// color, and includes instance variables for the coordinates and color. 
// The only method is called Show(), in which the command SAY is 
// executed. The label class is used in a later program example. 

********************************************************** 
*                   Label Class                          * 
********************************************************** 
// 
// Class declaration 
// 
CLASS Label 
  EXPORTED:                         // Globally visible 
     VAR     nRow, nCol, cLabel, cColor 
     METHOD  init, Show 
ENDCLASS 
// 
// Initialize object with default values, if no 
// arguments are passed to Label():new() 
// 

METHOD Label:init( nRow, nCol, cLabel, cColor ) 
   ::nRow   := IIF( nRow == NIL, Row(), nRow ) 
   ::nCol   := IIF( nCol == NIL, Col(), nCol ) 
   ::cLabel := IIF( cLabel==NIL, "" , cLabel ) 
   ::cColor := IIF( cColor==NIL, SetColor(), cColor ) 
RETURN self 
// 
// Display label 
// 
METHOD Label:Show 
   @ ::nRow, ::nCol SAY ::cLabel COLOR ::cColor 
RETURN self 
Class variables and methods usage
// This class implements the Cursor class and 
// shows the procedure for initializing the class object 
// using the method :initClass() and assigning default values 
// to class variables. An instance of the Cursor class 
// can control the position and form of the screen cursor. 
// The Cursor class is used in another program. 

********************************************************** 
*                   Cursor Class.                       * 
********************************************************** 
#include "setcurs.ch" 
// 
// Class declaration including declaring class variables and methods 
// 
CLASS Cursor 
   EXPORTED:                        // Globally visible 
      CLASS VAR nMaxRow, nMaxCol READONLY SHARED 
                                    // Assignment possible only in 
                                    // methods. 
                                    // All subclasses have equal 
                                    // access 

      CLASS METHOD initClass, Hide, SetMode 

      VAR    nRow, nCol, nShape 
      METHOD init, Show, UpdatePos 
ENDCLASS 
// 
// Initialize the class object 
// 
CLASS METHOD Cursor:initClass() 
   ::nMaxRow := MaxRow() 
   ::nMaxCol := MaxCol() 
RETURN self 
// 
// Initialize instance variables of the object with default values 
// when no arguments are passed to the Cursor():new() (which 
// passes any arguments on to Cursor:init() automatically). 
// 
METHOD Cursor:init( nRow, nCol, nShape ) 
   ::nRow   := IIF( nRow  ==NIL, Row(), nRow ) 
   ::nCol   := IIF( nCol  ==NIL, Col(), nCol ) 
   ::nShape := IIF( nShape==NIL, SetCursor(), nShape ) 
RETURN self 
// 
// Example of a class method 
// 
CLASS METHOD Cursor:SetMode( nMaxRow, nMaxCol ) 
   IF SETMODE( nMaxRow, nMaxCol ) 
      ::initClass()                 // self is the class object 
   ENDIF 
RETURN self 
// 
// Turn off the cursor. The method is declared as a CLASS METHOD, 
// since no access to instance variables is required. 
// 
CLASS METHOD Cursor:Hide 
   SetCursor( SC_NONE ) 
RETURN self                         // self is the class object 
// 
// Turn the cursor on and reposition 
// 
METHOD Cursor:Show( nRow, nCol ) 
   IF ValType( nRow ) == "N" 
      ::nRow := nRow 
   ENDIF 
   IF ValType( nCol ) == "N" 
      ::nCol := nCol 
   ENDIF 
   SetPos( ::nRow, ::nCol ) 
   SetCursor( ::nShape ) 
RETURN self 
// 
// Synchronize the cursor position to actual screen position 
// 
METHOD Cursor:UpdatePos 
   ::nRow  := Row() 
   ::nCol  := Col() 
RETURN self 
Multiple Inheritance

// In this example, the box class is coded to override all the 
// instance variables and methods of the classes from the 
// previous two examples. The box class inherits from the cursor 
// and label classes and is a simple example of multiple inheritance. 
// Its functionality is a combination of the functions DispBox(), 
// SaveScreen() and RestScreen(). Movement methods are provided 
// which allow a box to move interactively on the screen. The 
// functionality of the label class is used to display a heading 
// on the border of a box. The cursor class is used to display 
// the screen cursor only within the border of a box. 

********************************************************** 
*          Box class is created from two classes         * 
*                  Cursor  Label                         * 
*                     \     /                            * 
*                       Box                              * 
********************************************************** 
#include "setcurs.ch" 

#define  IS_NEW      0              // Constants for ::nStatus 
#define  IS_HIDDEN   1 
#define  IS_VISIBLE  2 
// 
// Class declaration using FROM 
// 
CLASS Box FROM Cursor, Label        // Inherits from two classes 
   EXPORTED:                        // Globally visible 
   VAR nTop, nLeft, nBottom, nRight, cBox 
   VAR cScreen, nStatus READONLY    // READONLY -> Assignment only 
                                    // allowed from within Box class 
                                    // and its subclasses. 
   VAR nCursorRow IS nRow IN Cursor // New name since nRow and nCol 
   VAR nCursorCol IS nCol IN Cursor // exist in both superclasses 
                                    // "Cursor"and "Label" 
   VAR nLabelRow  IS nRow IN Label 
   VAR nLabelCol  IS nCol IN Label 

   METHOD init, Show, Hide, Say     // Initialization and display 
   METHOD Up, Down, Left, Right     // movement methods 

   HIDDEN:                          // Only visible in Box class 
   METHOD Savescreen, Restscreen    // Save and restore the screen 

ENDCLASS 
// 
// Initialize box object. The arguments passed 
// to the :new() method are passed to the :init() method. 
// See the next program example. 
// 
METHOD Box:init( nTop, nLeft , nBottom, nRight, ; 
                 cBox, cColor, cTitle ) 

   ::nTop       := nTop 
   ::nLeft      := nLeft 
   ::nBottom    := nBottom 
   ::nRight     := nRight 
   ::cBox       := cBox 
   ::nStatus    := IS_NEW           // Initialize instance variable 
                                    // inherited from the Cursor 
                                    // class 

   ::Cursor:init( nTop+1, nLeft+1, SC_NORMAL ) 
                                    // Constant from Setcurs.ch 

*------------------ Alternative Initialization method---------------* 
*  ::nCursorRow := nTop +1          // Declared in Cursor class and * 
*  ::nCursorCol := nLeft+1          // redeclared in the Box class  * 
*  ::nShape     := SC_NORMAL        // Declared in Cursor class     * 
*-------------------------------------------------------------------* 

   IF ValType( cTitle ) <> "C"      // Validate the title (headline) 
      cTitle := ""                  // and center 
   ENDIF 
   nLeft := nLeft+ Round((nRight-nLeft-LEN(cTitle)+1)/2 ,0) 
                                    // Initialize instance variables 
                                    // inherited from the Label class 

   ::Label:init( nTop, nLeft, cTitle, cColor ) 

*------------------ Alternative Initialization method-------------* 
*  ::nLabelRow  := nTop             // Declared in Label class and* 
*  ::nLabelCol  := nLeft            // redeclared in the Box class* 
*  ::cLabel     := cTitle           // Declared in the Label class* 
*  ::cColor     := cColor           // Declared in the Label class* 
*-----------------------------------------------------------------* 

RETURN self 
// 
// Display the box 
// 
METHOD Box:Show 
   LOCAL cBackGround 

   IF ::nStatus == IS_NEW           // Box was never displayed 
      ::SaveScreen()                // Save what will be overwritten 
      DispBox( ::nTop   , ::nLeft , ; 
               ::nBottom, ::nRight, ; 
               ::cBox   , ; 
               ::cColor   )         // cColor is declared in the 
                                    // Label class 
   ELSEIF ::nStatus == IS_HIDDEN    // Box is hidden 
      cBackGround := ;              // Save what will be overwritten 
         SaveScreen( ::nTop, ::nLeft, ::nBottom, ::nRight ) 
      ::RestScreen()                // restore screen 
      ::cScreen := cBackGround      // save background 
   ENDIF 

   ::nStatus := IS_VISIBLE          // save status 
   ::Label :Show()                  // Display title and cursor, by 
                                    // calling show methods from 
   ::Cursor:Show()                  // Label and Cursor classes 

RETURN self 
// 
// Hide the box 
// 
METHOD Box:Hide 
   LOCAL cForeGround 
   IF ::nStatus == IS_VISIBLE 
      ::Cursor : Hide()             // Turn off cursor 
                                    // Hide() is in the Cursor class 
      cForeGround := ;              // Save foreground 
         SaveScreen( ::nTop, ::nLeft, ::nBottom, ::nRight ) 
      ::RestScreen()                // Restore screen we overwrote 
      ::cScreen := cForeGround      // save foreground 
      ::nStatus := IS_HIDDEN        // save status 
   ENDIF 
RETURN self 
// 
// Display a value with the box using relative coordinates. 
// (0,0 corresponds to nTop+1 and nLeft+1). 
// Scroll the contents of the box when the row passed 
// is greater than the lowest line in the box. 
// 
METHOD Box:Say( nRow, nCol, xValue ) 
   LOCAL cOldColor := SetColor( ::cColor ) 

   IF ::nStatus == IS_VISIBLE .AND. PCount() == 3 
      nRow += ::nTop  + 1           // Figure in absolute 
      nCol += ::nLeft + 1           // coordinates 

      IF nRow >= ::nBottom          // last line is reached 
         ::nCursorRow := nRow := ::nBottom-1 
         Scroll( ::nTop+1, ::nLeft+1, ::nBottom-1, ::nRight-1, 1 ) 
      ENDIF 

      IF nCol >= ::nRight           // last column is reached 
         ::nCursorCol := nCol := ::nRight-1 
      ENDIF 

      @ nRow, nCol SAY PADR( xValue, ::nRight-nCol ) 
      ::Cursor:UpdatePos()          // method of the Cursor class 
   ENDIF 

   SetColor( cOldColor ) 
RETURN self 
// 
// Shift box one line up 
// 
METHOD Box:Up 
   IF ::nStatus == IS_VISIBLE .AND. ::nTop > 0 
      DispBegin() 
      ::Hide()                      // Instance variables: 
      ::nTop--                      // - in Box Class 
      ::nBottom--                   // - in Box Class 
      ::nCursorRow--                // - nRow in Cursor Class 
      ::nLabelRow--                 // - nRow in Label Class 
      ::Show() 
      DispEnd() 
   ENDIF 
RETURN self 
// 
// Shift box one line down 
// 
METHOD Box:Down 
   IF ::nStatus == IS_VISIBLE .AND.;// SHARED class variable 
      ::nBottom <  ::nMaxRow        // nMaxRow is in the Cursor class 
      DispBegin() 
      ::Hide()                      // Instance variables: 
      ::nTop++                      // - in Box class 
      ::nBottom++                   // - in Box class 
      ::nCursorRow++                // - nRow in Cursor class 
      ::nLabelRow++                 // - nRow in Label class 
      ::Show() 
      DispEnd() 
   ENDIF 
RETURN self 
// 
// Shift box one column to the left 
// 
METHOD Box:Left 
   IF ::nStatus == IS_VISIBLE .AND. ::nLeft > 0 
      DispBegin() 
      ::Hide()                      // Instance variables: 
      ::nLeft--                     // - in Box class 
      ::nRight--                    // - in Box class 
      ::nCursorCol--                // - nCol in Cursor class 
      ::nLabelCol--                 // - nCol in Label class 
      ::Show() 
      DispEnd() 
   ENDIF 
RETURN self 
// 
// Shift box one column to the right 
// 
METHOD Box:Right 
   IF ::nStatus == IS_VISIBLE .AND.;// SHARED class variable 
      ::nRight  <  ::nMaxCol        // nMaxCol is in the Cursor class 
      DispBegin() 
      ::Hide()                      // Instance variables: 
      ::nLeft++                     // - in Box class 
      ::nRight++                    // - in Box class 
      ::nCursorCol++                // - nCol in Cursor class 
      ::nLabelCol++                 // - nCol in Label class 
      ::Show() 
      DispEnd() 
   ENDIF 
RETURN self 
// 
// Save screen image 
// 
METHOD Box:Savescreen 
   ::cScreen := SaveScreen( ::nTop, ::nLeft, ::nBottom, ::nRight ) 
RETURN self 
// 
// Display screen image again 
// 
METHOD Box:Restscreen 
   RestScreen( ::nTop, ::nLeft, ::nBottom, ::nRight, ::cScreen ) 
RETURN self 
Moving a box - programmed in object-oriented style.
// This example demonstrates using the Box class. A box object is 
// produced, and then the user is allowed to interactively move it 
// around the screen. In addition to showing the Box class, this 
// example demonstrates the difference in style between procedural 
// and object-oriented programming. This example demonstrates the 
// object-oriented style. The next example demonstrates the procedural 
// style. 

********************************************************** 
* BOXOOP.PRG                                            * 
* Test program for the Box class                        * 
********************************************************** 
// 
// Move box with the arrow keys on the screen and 
// indicate Inkey() code within the box. 
// 
#include "Box.ch" 
#include "Inkey.ch" 

PROCEDURE Test 
   LOCAL oBox, nKey := 0, nRow := 0, nCol := 0 

// Generate box object 
   oBox := Box():new( 10, 10, 20, 40, ; 
                     "B_THIN", "W+/BG", "Heading" ) 
   oBox:show() 
   oBox:say( 0, 0, "Press a key,..." ) 
   oBox:say( 1, 0, "Arrow keys move the box" ) 
   oBox:say( 2, 0, "Escape key exits program" ) 
   nRow := 3 

   DO WHILE nKey <> K_ESC 
      nKey := Inkey(0) 
      DO CASE 
      CASE nKey == K_UP       ;   oBox:up() 
      CASE nKey == K_LEFT     ;   oBox:left() 
      CASE nKey == K_DOWN     ;   oBox:down() 
      CASE nKey == K_RIGHT    ;   oBox:right() 
      ENDCASE 

      oBox:say( nRow, nCol, ; 
                 "The Inkey() Code was:" + LTrim(Str(nKey)) ) 
      nRow ++ 
      nCol ++ 
      IF oBox:nCursorCol >= oBox:nRight-1 
         nCol := 0 
      ENDIF 
   ENDDO 

   oBox:hide() 

RETURN 
Moving a box - programmed in procedural style
// This example demonstrates the differences in style between 
// procedural and object-oriented programming. 
// The example demonstrates the procedural style. 
// One who has not worked with OOP may compare 
// the function BoxUp() in this example with the method up() 
// or the call to oBox:up() from the previous two examples. It 
// becomes clear that the values which are contained in 
// instance variables of a box object, are kept in 
// LOCAL variables in this example. 

********************************************************** 
* BOXPROC.PRG                                            * 
********************************************************** 
// 
// Move box with the arrow keys on the screen and 
// indicate Inkey() code within the box. 
// 
#include "Box.ch" 
#include "Inkey.ch" 

PROCEDURE Test 
   LOCAL cScreen  , nKey := 0, nRow   := 0, nCol  := 0 
   LOCAL nTop :=10, nLeft:=10, nBottom:=20, nRight:=40 

// Show box and save screen 
   cScreen := BoxShow( nTop, nLeft, nBottom, nRight, ; 
                       B_THIN, "W+/BG", "Heading" ) 
   BoxSay( 0, 0, nTop, nLeft, nBottom, nRight, ; 
           "Press key", "W+/BG" ) 
   BoxSay( 1, 0, nTop, nLeft, nBottom, nRight, ; 
          "Arrow keys move the box", "W+/BG" ) 
   BoxSay( 2, 0, nTop, nLeft, nBottom, nRight, ; 
           "Escape key exits program", "W+/BG" ) 
   nRow := 3 

   DO WHILE nKey <> K_ESC 
      nKey := Inkey(0) 
      DO CASE 
      CASE nKey == K_UP 
           BoxUp( @nTop, @nLeft, @nBottom, @nRight, @cScreen ) 
      CASE nKey == K_LEFT 
           BoxLeft( @nTop, @nLeft, @nBottom, @nRight, @cScreen ) 
      CASE nKey == K_DOWN 
           BoxDown( @nTop, @nLeft, @nBottom, @nRight, @cScreen ) 
      CASE nKey == K_RIGHT 
           BoxRight( @nTop, @nLeft, @nBottom, @nRight, @cScreen ) 
      ENDCASE 
      BoxSay( nRow, nCol, nTop, nLeft, nBottom, nRight, ; 
             "The Inkey() Code was:" + LTrim(Str(nKey)), "W+/BG" ) 
      nRow ++ 
      nCol ++ 
      IF Col() >= nRight-1 
         nCol := 0 
      ENDIF 
   ENDDO 

   RestScreen( nTop, nLeft, nBottom, nRight, cScreen ) 

RETURN 

********************************************************** 
* Box class programmed in a procedural style                     * 
********************************************************** 
// 
// Display box with centered heading and 
// return saved screen 
// 
#include "Setcurs.ch" 

FUNCTION BoxShow( nTop, nLeft , nBottom, nRight, ; 
                  cBox, cColor, cTitle ) 
   LOCAL cScreen 

   cScreen := SaveScreen( nTop, nLeft, nBottom, nRight ) 
   DispBox( nTop, nLeft, nBottom, nRight, cBox, cColor ) 

   nRight := nLeft+ Round((nRight-nLeft-LEN(cTitle)+1)/2 ,0) 

   @ nTop, nRight SAY cTitle COLOR cColor 
   SetPos( nTop+1, nLeft+1 ) 
RETURN cScreen 
// 
// Show a value within the box by relative coordinates 
// (0,0 corresponds to  nTop+1 and nLeft+1). When the output line is 
// past the bottom of the box,  scroll the contents of the box 
// 
PROCEDURE BoxSay( nRow, nCol, nTop, nLeft, nBottom, nRight, ; 
                  xValue, cColor ) 
   LOCAL cOldColor := SetColor( cColor ) 

   nRow += nTop +1 
   nCol += nLeft+1 

   IF nRow >= nBottom 
      nRow := nBottom-1 
      Scroll( nTop+1, nLeft+1, nBottom-1, nRight-1, 1 ) 
   ENDIF 

   IF nCol >= nRight 
      nCol := nRight-1 
   ENDIF 

   @ nRow, nCol SAY Trim( PADR( xValue, nRight-nCol )) 

   SetColor( cOldColor ) 
RETURN 
// 
// Shift box one line up 
// 
PROCEDURE BoxUp( nTop, nLeft, nBottom, nRight, cBackGround ) 
   LOCAL cForeGround 
   IF nTop > 0 
      DispBegin() 
      cForeGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cBackGround ) 
      nTop -- 
      nBottom -- 
      cBackGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cForeGround ) 
      SetPos( Row()-1, Col() ) 
      DispEnd() 
   ENDIF 
RETURN 
// 
// Shift box one column to the left 
// 
PROCEDURE BoxLeft( nTop, nLeft, nBottom, nRight, cBackGround ) 
   LOCAL cForeGround 
   IF nLeft > 0 
      DispBegin() 
      cForeGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cBackGround ) 
      nLeft -- 
      nRight -- 
      cBackGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cForeGround ) 
      SetPos( Row(), Col()-1 ) 
      DispEnd() 
   ENDIF 
RETURN 
// 
// Shift box one line down 
// 
PROCEDURE BoxDown( nTop, nLeft, nBottom, nRight, cBackGround ) 
   LOCAL cForeGround 
   IF nBottom < MaxRow() 
      DispBegin() 
      cForeGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cBackGround ) 
      nTop ++ 
      nBottom ++ 
      cBackGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cForeGround ) 
      SetPos( Row()+1, Col() ) 
      DispEnd() 
   ENDIF 
RETURN 
// 
// Shift box one column to the right 
// 
PROCEDURE BoxRight( nTop, nLeft, nBottom, nRight, cBackGround ) 
   LOCAL cForeGround 
   IF nRight < MaxCol() 
      DispBegin() 
      cForeGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cBackGround ) 
      nLeft ++ 
      nRight ++ 
      cBackGround := SaveScreen( nTop, nLeft, nBottom, nRight ) 
      RestScreen( nTop, nLeft, nBottom, nRight, cForeGround ) 
      SetPos( Row(), Col()+1 ) 
      DispEnd() 
   ENDIF 
RETURN 
Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.