//********************************************************************************
//* File       : AnsiCmdWin.hpp                                                  *
//* Author     : Mahlon R. Smith                                                 *
//*              Copyright (c) 2022-2026 Mahlon R. Smith, The Software Samurai   *
//*                 GNU GPL copyright notice below                               *
//* Date       : 31-Mar-2026                                                     *
//* Version    : (see AnsiCmdVersion string in AnsiCmd.cpp)                      *
//*                                                                              *
//* Description: AnsiCmd class definition, supplementary.                        *
//*              Window-oriented objects are defined here.                       *
//*                                                                              *
//*                                                                              *
//********************************************************************************

#if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0
extern ofstream ofsdbg ;
extern gString  gsdbg ;
#define DEBUG_WDUMP (0)    // enable write of config data to log
#define DEBUG_FDUMP (0)    // enable write of field data members to log
#define DEBUG_MDUMP (1)    // enable write of field MRParse data to log
#define DEBUG_FIFO  (0)    // enable write of BlockFifo data to log
#define DEBUG_PHOTO (0)    // enable capture of window screenshot
#define DEBUG_KPUSH (0)    // enable support methods of KeycodePush group
#endif   // DEBUG_ANSICMD && DEBUG_LOG


//*****************
//* Include Files *
//*****************
#include "AnsiCmdDlg.hpp"


//*****************************************************************
//* Copy of window configuration information. See WinInfo method. *
//*****************************************************************
class winInfo
{
   public:
   WinPos winBase ;              //* Terminal window offset (1-based)
   short height ;                //* Height of window object (rows)
   short width ;                 //* Width of window object (columns)
   short txtRows ;               //* Number of text (interior) rows
   short txtCols ;               //* Number of text (interior) columns
   acAttr bdrAttr ;              //* Color attributes for window border
   acAttr txtAttr ;              //* Color attributes for window interior
   LineType bdrStyle ;           //* Line type for border
   const skForm *skf ;           //* Definition of text fields within the window
   bool  wcbConnected ;          //* Set if connected with Wayland clipboard
   termConfig tcfg ;             //* Terminal configuration data (AnsiCmd class members)

} ;   // winInfo

//* Data cache for text written directly to interior of ACWin class. *
const int DB_BUFFSIZE = gsALLOCMIN * 4 ; // size of DataBlock buffer (approx. 1 full window)
class DataBlock
{
   public:
     ~DataBlock ( void ) { }     // destructor
      DataBlock ( void )         // default constructor
      { this->txt[0] = '\0' ; this->active = false ; }

      //** Data Members **
      char      txt[DB_BUFFSIZE];// text data
      WinPos    wp ;             // text position (zero-based offset from window base)
      acaExpand aca ;            // color attributes
      bool      active ;         // set if object contains live data

} ;   // DataBlock

const short DB_MAX = 8 ;         // number of DataBlock elements in FIFO array

//* Control structure for an array of TextBlock objects. *
class BlockFifo
{
   public:
  ~BlockFifo ( void ) { }        // destructor
   BlockFifo ( void )            // default constructor
   { this->reset ( acaATTR_DFLT ) ; }

   //* Initialization constructor *
   BlockFifo ( const WinPos& winBase, acAttr winAttr )
   {
      this->reset ( winAttr ) ;
      this->base = winBase ;
   }

   //* Write the data to the next free record in the FIFO queue. *
   void saveRecord ( const wchar_t* srcTxt, const WinPos& srcPos, const acaExpand& srcAttr )
   {
      bool overwrite = this->block[this->next].active ;
      gString gs( srcTxt ) ;
      gs.copy( this->block[this->next].txt, gsALLOCMIN ) ;
      this->block[this->next].wp = srcPos ;
      this->block[this->next].aca = srcAttr ;
      this->block[this->next].active = true ;
      this->nextStep ( overwrite ) ;
   }

   //* Return a pointer to the next active record in the FIFO queue.       *
   //* -- If 'topRecord' is set return the first record in queue (if any). *
   //* -- Otherwise, return the next record in the queue. (ref: pullIndx)  *
   //* -- If no more active records to be reported, return a NULL pointer. *
   DataBlock* pullRecord ( bool topRecord )
   {
      static short pullIndx = ZERO ;
      DataBlock* dbptr = NULL ;

      if ( topRecord )
         pullIndx = this->top ;
      if ( this->block[pullIndx].active && (topRecord || (pullIndx != this->top)) )
         dbptr = &this->block[pullIndx] ;
      if ( ++pullIndx >= DB_MAX )
         pullIndx = ZERO ;
      return ( dbptr ) ;
   }

   void reset ( acAttr color )   // reinitialize all members
   {
      this->base = { ZERO, ZERO } ;
      this->top = this->next = ZERO ;
      for ( short b = ZERO ; b < DB_MAX ; ++b )
      {
         this->block[b].txt[ZERO] = NULLCHAR ;
         this->block[b].wp = { ZERO, ZERO } ;
         this->block[b].aca.decode( color ) ;
         this->block[b].active = false ;
      }
   }

   protected:
   void nextStep ( bool overwrite ) // advance the indices
   {
      if ( overwrite && this->next == this->top ) // if top record was just overwritten
      { if ( ++this->top >= DB_MAX ) this->top = ZERO ; }
      if ( ++this->next >= DB_MAX )       // reference next available space
         this->next = ZERO ;
   }

   //** Data Members **
   public:
   WinPos base ;              // terminal relative origin for display area (window interior)
   DataBlock block[DB_MAX] ;  // array of objects describing each block of text
   short top ;                // index of oldest block in the fifo array
   short next ;               // index of next free block in the fifo array

} ;   // BlockFifo

//* Key input-stream pushback queue.           *
//* See winRead() and KeycodPush() for details.*
class keyPushback
{
   #define KEYPUSH_MAX (16)         //* Maximum consecutive pushes without a pull

   public:
   ~keyPushback ( void )            //* Destructor
   { /* nothing to do at this time */ }

   keyPushback ( void )             //* Default constructor
   { this->kCount = ZERO ; }

   bool keyPush ( wchar_t wKey )    //* Push a keycode into the FIFO queue
   {
      bool status = false ;
      if ( this->kCount < KEYPUSH_MAX )
      { this->kPush[this->kCount++] = wKey ; status = true ; }
      return status ;
   }

   bool keyPull ( wchar_t& wKey )   //* Extract a keycode from the FIFO queue
   {
      bool status = false ;
      if ( this->kCount > ZERO )
      {
         wKey = this->kPush[ZERO] ; // oldest data in the queue
         --this->kCount ;           // decrement push count

         //* Shift remaining data downward *
         short i = ZERO, j = 1 ;
         while ( j <= this->kCount )
            this->kPush[i++] = this->kPush[j++] ;
         status = true ;
      }
      else
         wKey = NULLCHAR ;
      return status ;
   }

   bool keyAvail ( void )           //* Report whether queue contains key data
   { return ( bool(this->kCount > ZERO) ) ; }

   void keyReset ( void )           //* Clear the buffer
   { this->kCount = ZERO ; }

   //** Public Data Members **
   wchar_t     kPush[KEYPUSH_MAX] ; 
   short       kCount ;             //* Number of keycodes in pushback queue
} ;

//* Type definition for callback function for external update of window *
//* controls. May be used by application-layer code to handle user input*
//* that is not automatically handled by the window object.             *
//* See prototype for EstablishCallback() method below for more details.*
typedef wchar_t (*CUPTR)( short ctrlIndex, wchar_t wkey, bool firstTime ) ;

//***********************************************************************
//* acWin class                                                         *
//* -----------                                                         *
//* This is a derived class whose parent is the AnsiCmd class.          *
//*                                                                     *
//* The public methods of AnsiCmd are inherited from the parent.        *
//* These include the methods which provide the ANSI escape sequences   *
//* and general housekeeping methods.                                   *
//*                                                                     *
//* The private data members of the parent class are not directly       *
//* available.                                                          *
//***********************************************************************

class ACWin : public AnsiCmd
{
   public:

   //* Destructor: Return all allocated resources to the system before  *
   //* exit.                                                            *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: nothing                                                 *
   virtual ~ACWin () ;

   //* Default Constructor:                                             *
   //* Create a default window:                                         *
   //*    posRow  : offset one row from top of terminal window          *
   //*    posCol  : centered in the terminal window                     *
   //*    winHgt  : height == eight(8) rows                             *
   //*    winWid  : width  == thirty-six(36) columns                    *
   //*    All other parameters use the initialization defaults.         *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: implicitly returns a pointer to object                  *
   ACWin ( void ) ;

   //* Initialization Constructor:                                      *
   //* Four parameters are required: upper-left row, upper-left column  *
   //* window height (rows) and window width (columns).                 *
   //* Optional parameters, if not specified, are set to default values.*
   //*                                                                  *
   //* Input  : posRow : Row - position of window within terminal window*
   //*          posCol    : Column - position of window within terminal *
   //*                      window                                      *
   //*          winHeight : Height of window in rows                    *
   //*          winWidth  : Width of window in columns                  *
   //*          bdrLine   : (optional, ltSINGLE by default, member      *
   //*                      enum LineType) border style                 *
   //*          bdrAttrib : (optional, acaATTR_DFLT by default,         *
   //*                      terminal defaults) border color attributes  *
   //*                      OR'd value of acAttr bitfields              *
   //*          txtAttrib : (optional, acaATTR_DFLT by default,         *
   //*                      terminal defaults)                          *
   //*                      interior color attributes and text          *
   //*                      modifiers OR'd value of acAttr bitfields    *
   //*          winTitle  : (optional, null pointer by default)         *
   //*                      if specified, text for window title         *
   //*                      displayed in top border                     *
   //*          formDef   : (optional, null pointer by default)         *
   //*                      an 'skForm' object which specifies the      *
   //*                      position and dimensions of the input fields *
   //*          termDef   : (optional, null pointer by default)         *
   //*                      pointer to an initialized TermConfig object *
   //*                      which specifies terminal setup options.     *
   //*                                                                  *
   //* Returns: implicitly returns a pointer to object                  *
   ACWin ( short posRow, short posCol, short winHeight, short winWidth,
           LineType bdrLine = ltSINGLE, acAttr bdrAttrib  = acaATTR_DFLT,
           acAttr txtAttrib  = acaATTR_DFLT, const char* winTitle = NULL,
           const skForm *formDef = NULL, const TermConfig *termDef = NULL ) ;

   //* Complete window setup and display it within the terminal window. *
   //*                                                                  *
   //* Input  : initText : (optional, null pointer by default)          *
   //*                     initial text to be written to window         *
   //*          initField: (optional, -1 by default) [CURRENTLY UNUSED] *
   //*                     index of target field for storing 'initText' *
   //*                     data. Ignored if 'initText' not specified.   *
   //* Returns: cursor position (offset) i.e. text insertion point      *
   WinPos OpenWindow ( const char* initText = NULL, short initField = -1 ) ;

   //* Close the window: Erase the window display data.                 *
   //*                                                                  *
   //* Note that the window object still exists in memory.              *
   //* To release the window's resources, invoke the destructor i.e.    *
   //* delete the ACWin object. Ex: ACWin *winPtr; ... delete winPtr;   *
   //*                                                                  *
   //* Input  : clear    : (optional, 'true' by default)                *
   //*                     if 'true',  clear (erase) the display area   *
   //*                     if 'false', do not clear the display area    *
   //*          fillColor: (optional, terminal dflt attr by default)    *
   //*                     color attribute used to erase data from      *
   //*                     window.                                      *
   //* Returns: nothing                                                 *
   void CloseWindow ( bool clear = true, acAttr fillAttr = acaUSEDFLT ) ;

   //* Redraw the window to display any changes that have been made,    *
   //* or to recover when other data have obscured the the window.      *
   //* For instance, call RefreshWin() after a call to HideWin().       *
   //*                                                                  *
   //* Input  : all  : (optional, 'true' by default)                    *
   //*                 if 'true',  refresh border and interior          *
   //*                 if 'false', refresh interior only                *
   //* Returns: nothing                                                 *
   void RefreshWin ( bool all = true ) ;

   //* Temporarily erase the window from the terminal display.          *
   //* Data in the skForm object (if any) will be retained, and text    *
   //* previously written directly into the window interior will also   *
   //* be retained.                                                     *
   //*                                                                  *
   //* Input  : fillAttr : (optional, default: terminal dflt attribute) *
   //*          color attribute used to erase data from window.         *
   //* Returns: nothing                                                 *
   void HideWin ( acAttr fillAttr = acaUSEDFLT ) ;

   //* Move the window to another position within the terminal window.  *
   //* This is simply erasing the window, updating the base position    *
   //* and redrawing the window at the new position.                    *
   //* Data in the skForm object (if any) will be redrawn as part of    *
   //* the move; however, any text previously written directly into the *
   //* window interior will be lost. (see 'newText')                    *
   //*                                                                  *
   //* Input  : newPos   : (by reference) new row/column position for   *
   //*                     window origin (upper-left corner of window)  *
   //*          newText  : (optional, null pointer by default)          *
   //*                     text to be written to interior of window,    *
   //*                     beginning at the upper left corner of the    *
   //*                     window interior.                             *
   //* Returns: 'true'  if success                                      *
   //*          'false' if specified position would place any part      *
   //*                  of the window outside the visible area of the   *
   //*                  terminal display.                               *
   bool MoveWin ( const WinPos& newPos, const char *newText = NULL ) ;

   //* Erase all text in the interior (text area) of the window.        *
   //* The text in the skForm object (if any) is not redrawn.           *
   //* See also RefreshWin().                                           *
   //*                                                                  *
   //* Input  : newAttr : (optional, acaUSEDFLT by default)             *
   //*                    new color attributes for text area of window  *
   //*                    (logical OR of forground and background color)*
   //*                    (attributes and attribute modifiers          )*
   //* Returns: Cursor position (text insertion point)                  *
   //*          This is the upper-left corner of the text area (0/0).   *
   WinPos ClearWin ( acAttr newAttr = acaUSEDFLT ) ;

   //* Returns a copy of the window's current size, position, attributes*
   //* and other basic information.                                     *
   //*                                                                  *
   //* Note that the current window dimensions and position are not     *
   //* guaranteed to be those specified during instantiation. This is   *
   //* because the ACWin constructor range checks and automatically     *
   //* adjusts these values as necessary to fit within the terminal     *
   //* window.                                                          *
   //*                                                                  *
   //* Input  : wInfo  : (by reference) a winInfo-class object to       *
   //*                   receive the data                               *
   //* Returns: nothing                                                 *
   void WinInfo ( winInfo& wInfo ) ;

   //* Erase text from the specified row of the text area.              *
   //*                                                                  *
   //* To clear a single text field within the window, use the          *
   //* ClearField() method instead.                                     *
   //*                                                                  *
   //* Input  : trgRow  : target row (0-based offset into text area)    *
   //*          txtAttr : (optional, acaUSEDFLT by default)             *
   //*                    new color attributes for text area of window  *
   //*                    (logical OR of forground and background color)*
   //*                    (attributes and attribute modifiers          )*
   //* Returns: Cursor position (text insertion point)                  *
   //*          This is the left edge of the specified row (trgRow/0).  *
   //*          Note: If 'trgRow' is out-of-range, window will not be   *
   //*                modified.                                         *
   WinPos ClearRow ( short trgRow, acAttr txtAttr = acaUSEDFLT ) ;

   //* Write text to the interior of the window.                        *
   //* This group of methods writes directly into the window's text     *
   //* area, bypassing any defined text fields.                         *
   //*                                                                  *
   //* Input  : txtPos : WinPos-class object indicates the zero-based   *
   //*                  OFFSET from upper-left corner of window interior*
   //*          txt    : text to write in one of the following formats: *
   //*                   -- gString object by reference                 *
   //*                   -- wchar_t pointer                             *
   //*                   -- char pointer                                *
   //*          txtAttr: (optional, existing text attributes by default)*
   //*                   text attributes and text modifiers             *
   //*          clear  : (optional, 'false' by default)                 *
   //*                   if 'false', existing displayed text unmodified *
   //*                   if 'true',  erase window interior before write *
   //*                                                                  *
   //* Returns: current cursor position (window offset)                 *
   WinPos Write ( WinPos txtPos, const gString& txtData, 
                  acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
   WinPos Write ( WinPos txtPos, const wchar_t* txtData, 
                  acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
   WinPos Write ( WinPos txtPos, const char* txtData, 
                  acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
   WinPos Write ( WinPos txtPos, wchar_t txtData, 
                  acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;

   //* Get the current cursor offset within the window's text area.     *
   //*                                                                  *
   //* Input  : none                                                    *
   //* Returns: current cursor position (window offset)                 *
   WinPos GetCursorPos ( void ) ;

   //* Set the cursor offset within the window's text area.             *
   //*                                                                  *
   //*          ** Cursor position may be specified in either of 2 ways:*
   //* Input  : wPos : (by reference) offset from upper-left corner of  *
   //*                 window's text area (0-based offset)              *
   //*               OR                                                 *
   //*          rOff : row offset                                       *
   //*          cOff : column offset                                    *
   //*                                                                  *
   //* Returns: current cursor position (window offset)                 *
   WinPos SetCursorPos ( const WinPos& wPos ) ;
   WinPos SetCursorPos ( short rOff, short cOff ) ;

   //* Set the color attributes and modifiers for the window text area. *
   //*                                                                  *
   //* Input  : txtAttr : (acAttr bitfield) a logical OR of forground   *
   //*                    and background color attributes and attribute *
   //*                    modifiers                                     *
   //* Returns: nothing                                                 *
   void SetTextAttr ( acAttr txtAttr ) ;

   //* Set the color attributes and modifiers for the window border.    *
   //*                                                                  *
   //* Input  : bdrAttr : (acAttr bitfield) a logical OR of forground   *
   //*                    and background color attributes and attribute *
   //*                    modifiers                                     *
   //*          bdrStyle: (optional, ltHORIZ i.e. an invalid value by   *
   //*                    default) specify the border line style        *
   //*                    either ltSINGLE or ltDUAL                     *
   //* Returns: nothing                                                 *
   void SetBorderAttr ( acAttr bdrAttr, LineType bdrStyle = ltHORIZ ) ;

                  //***********************************
                  //** skForm and skField Management **
                  //***********************************
   //* Set or modify the setup data for the specified field.            *
   //* The setup data parameters include:                               *
   //*   1) field text                                                  *
   //*   2) field color attributes                                      *
   //*   3) insertion point (cursor position)                           *
   //* The effect is the same as seperately calling three individual    *
   //* methods: SetFieldText, SetFieldAttr and SetFieldIP except that   *
   //* this method is more efficient if modifying multiple parameters.  *
   //*                                                                  *
   //* Input  : fIndx : index of target field                           *
   //*          srcTxt: text to be written to target field              *
   //*          txtAttr : (optional, default: acaUSEDFLT, indicating )  *
   //*                    (current attributes should not be modified )  *
   //*                    acAttr bitfield which is a logical OR of      *
   //*                    forground and background color attributes     *
   //*                    and text modifiers                            *
   //*          newIp   : (optional, zero(0) by default)                *
   //*                    character offset into the text of the field   *
   //*                    ZERO <= newIp <= text characters              *
   //*                    ZERO == field origin and any value at or      *
   //*                    beyond the number of characters in the array  *
   //*                    signals that IP should be set to end-of-text. *
   //*          refresh : (optional, default:true) refresh display      *
   //*                    if 'true'  make changes visible               *
   //*                    if 'false' do not update display              *
   //*                                                                  *
   //* Returns: 'true'  if successful                                   *
   //*          'false' if invalid field index specified                *
   bool  SetFieldData ( short fIndx, const gString& srcTxt, acAttr txtAttr = acaUSEDFLT, 
                        int newIp = ZERO, bool refresh = true ) ;
   bool  SetFieldData ( short fIndx, const wchar_t* srcTxt, acAttr txtAttr = acaUSEDFLT, 
                        int newIp = ZERO, bool refresh = true ) ;
   bool  SetFieldData ( short fIndx, const char* srcTxt, acAttr txtAttr = acaUSEDFLT, 
                        int newIp = ZERO, bool refresh = true ) ;

   //* Get a copy of the current settings for the specified field.      *
   //*                                                                  *
   //* Input  : fIndx   : index of target field within the skForm object*
   //*          skfld   : (by reference) receives a copy of data members*
   //*                                                                  *
   //* Returns: 'true'  if successful                                   *
   //*          'false' if invalid field index specified                *
   bool GetFieldData ( short fIndx, skField& skfld ) const ;

   //* Replace the current contents of the field with new data.         *
   //* The 'off' (offset), 'shft' (horiz. shift) and 'ip' (insertion    *
   //* point) members of the field are set to zero, and cursor position *
   //* is set to match 'ip'.                                            *
   //*                                                                  *
   //* Field types for which text data may be modified:                 *
   //*  1) ftPB (Pushbutton), 2) ftTB (Textbox), 3) ftSB Scrollbox      *
   //* Text for other field types is set during instantiation and       *
   //* remains static.                                                  *
   //*                                                                  *
   //* Note On Pushbuttons: Although the text of a pushbutton control   *
   //* may be changed, the existing hotkey designation (if any) is not  *
   //* updated.                                                         *
   //*                                                                  *
   //* Input  : fIndx : index of target field                           *
   //*          srcTxt: text to be written to target field              *
   //*                  Text data may be in the form:                   *
   //*                  1) gString object (by reference)                *
   //*                  2) pointer to wide (wchar_t) text data          *
   //*                  3) pointer to UTF-8 (byte-oriented) text data   *
   //*          refresh : (optional, default: true)                     *
   //*                    if 'true',  refresh the field display         *
   //*                    if 'false', do not refresh the display        *
   //*                                                                  *
   //* Returns: 'true'  if successful                                   *
   //*          'false' if invalid field index specified                *
   bool  SetFieldText ( short fIndx, const gString& srcTxt, bool refresh = true ) ;
   bool  SetFieldText ( short fIndx, const wchar_t* srcTxt, bool refresh = true ) ;
   bool  SetFieldText ( short fIndx, const char* srcTxt, bool refresh = true ) ;

   //* Get a copy of the current contents of the target Textbox (ftTB)  *
   //* field.                                                           *
   //*                                                                  *
   //* Input  : fIndx   : index of target field within the skForm object*
   //*          txtBuf  : (by reference) receives a copy of field text  *
   //*                 OR pointer to wchar_t buffer                     *
   //*                 OR pointer to char (UTF-8) buffer                *
   //*          maxChars: for wchar_t target buffer, maximum number of  *
   //*                    wchar_t characters to write                   *
   //*                 OR                                               *
   //*          maxBytes: for char target buffer, maximum number of     *
   //*                    UTF-8 bytes to write                          *
   //*                                                                  *
   //* Returns: number of characters written to target buffer including *
   //*          null terminator (if target is UTF-8 buffer, byte count  *
   //*          is returned)                                            *
   //*          -- If invalid field index specified OR if field index   *
   //*             does not reference an ftTB field, the target buffer  *
   //*             is set to an empty string, and a zero value is       *
   //*             returned.                                            *
   //*          -- If the text is larger than the target buffer, then   *
   //*             text will be truncated.                              *
   //*                                                                  *
   //* Get a copy of the current contents of the field.                 *
   int GetFieldText ( short fIndx, gString& txtBuf ) const ;
   int GetFieldText ( short fIndx, wchar_t* txtBuf, int maxChars ) ;
   int GetFieldText ( short fIndx, char* txtBuf, int maxBytes ) ;

   //* Erase the displayed text in the specified text field.            *
   //* Optionally, the stored text is also deleted.                     *
   //*                                                                  *
   //* This operation applies ONLY to fields with editable text,        *
   //* specifically, Textbox fields (field type: ftTB).                 *
   //*                                                                  *
   //* Input  : fIndx   : index of target field                         *
   //*          delText : (optional, 'false' by default)                *
   //*                    if 'true',  delete the stored text            *
   //*                    if 'false', stored text is not modified       *
   //*          txtAttr : (optional, acaUSEDFLT by default)             *
   //*                    color attributes for the clear operation      *
   //*                    (logical OR of forground and background color)*
   //*                    (attributes and attribute modifiers          )*
   //*                    -- If not specified, then current field       *
   //*                       attributes will be used.                   *
   //*                    if 'delText' is set: field attributes will    *
   //*                                 be updated                       *
   //*                    if 'delText' is reset: specified attributes   *
   //*                                 will be used for the clear       *
   //*                                 operation, but won't be saved    *
   //*                                                                  *
   //* Returns: 'true'  if target field cleared                         *
   //*          'false' if fIndx out-of-range or if field type of       *
   //*                  target is not supported by this operation       *
   //*                  (data not modified)                             *
   bool ClearField ( short fIndx, bool delText = false, acAttr txtAttr = acaUSEDFLT ) ;

   //* Set the insertion point (IP) for the field. This will set the    *
   //* cursor position over the character at the specified offset.      *
   //*                                                                  *
   //* If 'fIndx' references the field which has input focus, the       *
   //* visible cursor will also be updated.                             *
   //*                                                                  *
   //* Special case: If 'newIp' is greater that the number of characters*
   //* in the field, IP will be set to end-of-text (over the null       *
   //* terminator).                                                     *
   //*                                                                  *
   //* Input  : fIndx   : index of target field                         *
   //*          newIp   : character offset into the text of the field   *
   //*                    ZERO <= newIp <= text characters              *
   //*                    ZERO == field origin and any value at or      *
   //*                    beyond the number of characters in the array  *
   //*                    signals that IP should be set to end-of-text. *
   //*          centered: (optional, default:false) vertically center   *
   //*                    the row containing the IP within the field.   *
   //*          refresh : (optional, default:true) refresh display      *
   //*                    if 'true'  make changes visible               *
   //*                    if 'false' do not update display              *
   //*                                                                  *
   //* Returns: 'true'  if successful                                   *
   //*          'false' if invalid field index specified                *
   bool SetFieldIP ( short fIndx, int newIp, bool centered = false, bool refresh = true ) ;

   //* Get the current insertion point (IP) for the specified field.    *
   //*                                                                  *
   //* Input  : fIndx   : index of target field                         *
   //*                                                                  *
   //* Returns: current character offset into the text of the field     *
   int  GetFieldIP ( short fIndx ) ;

   //* Scroll upward or downward through multi-row text fields.         *
   //* This method applies only to multi-row fields (ftTB. ftSB)        *
   //* and is ignored for single-row fields and other field types.      *
   //*                                                                  *
   //* Examples:                                                        *
   //* (note how the sign of the shift determines direction of scroll)  *
   //* steps ==   1   scroll up by one row (bring rows below into view) *
   //* steps ==  -1   scroll down by one row(bring rows above into view)*
   //* steps ==  hgt  scroll upward by one page                         *
   //* steps == -hgt  scroll downward by one page                       *
   //* steps ==   0   scroll to the first row of text (special case)    *
   //* steps ==  999  scroll to the last row of text. Note that any     *
   //*                value at or beyond the last text row will signal  *
   //*                a move to end-of-text.                            *
   //*                                                                  *
   //* Input  : fIndx   : index of target field                         *
   //*          steps   : number of rows to scroll                      *
   //*                                                                  *
   //* Returns: 'true'  if successful scroll                            *
   //*          'false' if already at limit in specified direction      *
   bool ScrollFieldText ( short fIndx, short steps ) ;

   //* Perform a vertical block shift of Textbox data.                  *
   //* This method applies ONLY to multi-row Textbox controls.          *
   //*                                                                  *
   //* This is similar to the ScrollFieldText() method which scrolls    *
   //* the cursor through the rows of text data, EXCEPT that the cursor *
   //* position continues to reference the same character UNLESS the    *
   //* row containing the cursor is shifted out of visible space.       *
   //*                                                                  *
   //* Input  : fIndx : index of target field                           *
   //*          steps : direction of shift                              *
   //*                  positive value: shift text upward by one row    *
   //*                     (toward bottom of text)                      *
   //*                  negative value: shift text downward by one row  *
   //*                     (toward top of text)                         *
   //*                                                                  *
   //* Returns: 'true'  if successful shift and/or cursor movement      *
   //*          'false' if already at limit in specified direction      *
   //*                  or target control does not support text shift   *
   //*                  or parameterout-of-range                        *
   bool ShiftFieldText ( short fIndx, short steps ) ;

   //* For Textbox controls only (ftTB), highlight a segment of text    *
   //* using an alternate color attribute.                              *
   //*                                                                  *
   //* Note that the target control may not have both highlighted and   *
   //* 'selected' text simultaneously. Setting a highlight will reset   *
   //* any selection, and setting a selection will reset any highlight. *
   //*                                                                  *
   //*                                                                  *
   //* Input  : fIndx : index of target field                           *
   //*          set   : if set, set the highlighted text segment        *
   //*                  if reset, clear highlight                       *
   //*          begin : index of first (leftmost) character to highlight*
   //*                  (ignored if !set)                               *
   //*          len   : number of characters in highlighted segment     *
   //*                  Note: If segment spans rows, be sure to include *
   //*                        the newlines in the count.                *
   //*                  (ignored if !set)                               *
   //*          txtmod: (optional, default:acaUSEDFLT)                  *
   //*                  text modifier attribute for highlighted segment *
   //*                  - If specified, text modifier attribute for     *
   //*                    highlighted text segment.                     *
   //*                  - If not specified, then use previously         *
   //*                    specified modifier (if any), else             *
   //*                    acaREVERSE (fg/bg attributes reversed)        *
   //*          center: (optional, default: true)                       *
   //*                  if set, assure that highlight is within visible *
   //*                          space by adjusting the IP if necessary. *
   //*                  if reset, do not adjust IP (highlighted text    *
   //*                          may or may not  be visible).            *
   //*                                                                  *
   //* Returns: 'true'  if highlight set/cleared                        *
   //*          'false' a) 'fIndx' does not reference a Textbox control *
   //*                  b) 'beg' and/or 'end' index out-of-range        *
   //*                                                                  *
   bool HilightFieldText ( short fIndx, bool set, int begin, int len, 
                           acAttr txtmod = acaUSEDFLT, bool center = true ) ;

   //* For Textbox controls only (ftTB), set the text-modifier attribute*
   //* to be used for highlighting text segments within the field.      *
   //*                                                                  *
   //* Note that no text is actually highlighted by this method; only   *
   //* the attribute is initialized. Please see the HighlightFieldText()*
   //* method for additional information.                               *
   //*                                                                  *
   //* Input  : fIndx : index of target field                           *
   //*          txtmod: text modifier attribute for highlighting        *
   //*                  text segments                                   *
   //*                                                                  *
   //* Returns: 'true'  if highlight set/cleared                        *
   //*          'false' a) 'fIndx' does not reference a Textbox control *
   //*                  b) 'beg' and/or 'end' index out-of-range        *
   bool SetHilightMod ( short fIndx, acAttr txtmod ) ;

   //* Refresh (erase and redraw) the contents of the specified field,  *
   //* or optionally, refresh all fields defined by the skForm object.  *
   //* Input focus remains on the currently active field, and cursor    *
   //* is returned to insertion point within that field.                *
   //*                                                                  *
   //* Input  : fIndx: index of target field                            *
   //*                 If fldIndex >= total of fields defined (fCnt),   *
   //*                 all fields will be refreshed.                    *
   //*                                                                  *
   //* Returns: nothing                                                 *
   void RefreshField ( short fIndx ) ;

   //* Refresh (erase and redraw) the contents of the field which has   *
   //* input focus.                                                     *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: nothing                                                 *
   void RefreshField ( void ) ;

   //* Set the color attributes and modifiers for the specified text    *
   //* field. Refresh the field display using the modified attributes.  *
   //*                                                                  *
   //* On return, the cursor is positioned in field with input focus.   *
   //*                                                                  *
   //* Input  : fIndx   : index of target field within the skForm       *
   //*                    object                                        *
   //*          txtAttr : (acAttr bitfield) a logical OR of forground   *
   //*                    and background color attributes and attribute *
   //*                    modifiers                                     *
   //*                                                                  *
   //* Returns: 'true'  if attribute set successfully                   *
   //*          'false' if invalid field index specified                *
   bool SetFieldAttr ( short fIndx, acAttr txtAttr ) ;

   //* Set the color attributes and modifiers for the specified field.  *
   //* The array of attributes will be applied one per text row within  *
   //* the field. Multi-color attributes apply _only_ to Menus (ftMB)   *
   //* and Scrollbox (ftSB) controls.                                   *
   //*                                                                  *
   //* Input  : fIndx  : index of target field (ftMB or ftSB only)      *
   //*          rowAttr: pointer to an array of acAttr color attributes,*
   //*                   one attribute for each text row of the control.*
   //*          rowCnt : number of attribute values in the 'rowAttr'    *
   //*                   array (>zero). (The minimum _practical_ value  *
   //*                   is two(2).                                     *
   //*                                                                  *
   //* Returns: 'true'  if successful                                   *
   //*          'false' if invalid field index specified, or            *
   //*                  if field type does not support per-row          *
   //*                  attributes, or if 'rowCnt' out-of-range         *
   bool  SetFieldAttr ( short fIndx, const acAttr* rowAttr, short rowCnt ) ;

   //* Set the text-flow type, reformatting the text if necessary, and  *
   //* optionally refresh the display.                                  *
   //*                                                                  *
   //* Input  : fIndx   : index of target field within the skForm object*
   //*          fType   : member of enum FloType                        *
   //*          refresh : (optional, 'false' by default)                *
   //*                    if 'true',  immediately reformat field text   *
   //*                                and update the display            *
   //*                    if 'false', existing text not modified        *
   //*                                display is not updated            *
   //*                                                                  *
   //* Returns: 'true'  if attribute set successfully                   *
   //*          'false' if invalid field index specified or if target   *
   //*                  field is a single-row field, or invalid 'fType/ *
   bool SetFieldFlow ( short fIndx, FloType fType, bool refresh = false ) ;

   //* Set the "state" of a binary field.                               *
   //* Currently, this applies only to Radiobuttons (type==ftRB).       *
   //*                                                                  *
   //* Input  : fIndx   : index of target field within the skForm object*
   //*          state   : if 'true',  set field state                   *
   //*                    if 'false', reset field state                 *
   //*          refresh : (optional, 'false' by default)                *
   //*                    if 'true',  refresh the field                 *
   //*                    if 'false', do not refresh the field          *
   //*                                                                  *
   //* Returns: current state of the field                              *
   bool SetFieldState ( short fIndx, bool state, bool refresh = false ) ;

   //* Get the current "state" of a binary field (or XOR field group).  *
   //* Currently, this applies only to Radiobuttons (type==ftRB).       *
   //*                                                                  *
   //* XOR Groups:                                                      *
   //* -----------                                                      *
   //* For radiobutton XOR groups, the binary state for only one member *
   //* of the group can be "set" i.e. 'true'. If 'fIndx' references     *
   //* a member of an XOR group, _and_ if the 'xorMember' pointer is    *
   //* non-null, then the variable referenced by 'xorMember' receives   *
   //* the index of the group member whose flag is "set". If the control*
   //* referenced by 'fIndx' is not a Radiobutton or is not a member of *
   //* an XOR group, then the 'xorMember' parameter is ignored.         *
   //* Note that in the (unlikely) case where no member of the XOR grop *
   //* has its flag set, *xorMember' will receive the 'fIndx' value.    *
   //*                                                                  *
   //* Input  : fIndx    : index of target field within the skForm      *
   //*                     object                                       *
   //*          xorMember: (optional, default: null pointer)            *
   //*                     for XOR groups only, if specifed, the        *
   //*                     referenced variable receives the index of    *
   //*                     the control whose 'set' flag is 'true.       *
   //*                                                                  *
   //* Returns: current state of 'set' flag for field                   *
   //*          referenced by 'fIndx'                                   *
   bool GetFieldState ( short fIndx, short* xorMember = NULL ) ;

   //* Assign a label, with or without hotkey, to the specified field.  *
   //* - Labels may be assigned only to Textbox and Scrollbox fields    *
   //*   (FldType ftTB/ftSB).                                           *
   //*   -- A label may also be assigned to a Menu (FldType ftMB)       *
   //*      under specific circumstances.                               *
   //*      1) Context menus (multiple-row menus which are not members  *
   //*         of any group.                                            *
   //*      2) Menubars (single-row menus which anchor a menu group.    *
   //*      -- Labels are incompatible with other Menubox controls.     *
   //*         See SetFieldHotkey() for setting hotkeys for these       *
   //*         controls.                                                *
   //* - For Pushbuttons and Radiobutton controls (FldType ftPB/ftRB),  *
   //*   the label is integrated into the control definition, and       *
   //*   therefore are not handled by this method.                      *
   //*                                                                  *
   //* -- Label length: 1 <= length <= labelLEN.                        *
   //*    (will be truncated if necessary)                              *
   //* -- Label width (columns): truncated if necessary to avoid        *
   //*    violation of window border.                                   *
   //* -- Range of valid hotkeys: wcsALT_A <= hotkey <= wcsALT_RB.      *
   //*    This corresponds to ASCII A-Z, a-z, and most punctuation.     *
   //*    The specified hotkey should be unique within the window.      *
   //* -- The label is positioned one row above the target field with   *
   //*    the horizontal offset determined by the 'center' parameter.   *
   //*                                                                  *
   //* Input  : fIndx   : index of target field                         *
   //*          labText : display text, optionally including a "hotkey" *
   //*                    character. A hotkey is specified using the    *
   //*                    CARET character ('^') followed by the ASCII   *
   //*                    character which indicates the keycode to be   *
   //*                    used as a hotkey.                             *
   //*          labAttr : (optional, interior of container window by    *
   //*                    default) color attributes for label text.     *
   //*          center  : (optional, default: false) horiz. offset      *
   //*                    if set, center the label horizontally in the  *
   //*                            row above the field                   *
   //*                    if reset, label offset is in the same column  *
   //*                            as the left edge of the field         *
   //*          outline : (optional, default: false) include outline    *
   //*                    if set, include a field outline for control.  *
   //*                    if reset, the 'lType' parameter is ignored.   *
   //*          lType   : (optional, ltSINGLE by default) line style    *
   //*                     member of enum LineType: ltSINGLE or ltDUAL  *
   //*                    This parameter is referenced _only_ when      *
   //*                    the 'outline' flag is set.                    *
   //*                    Outline takes the attribute of the labe.      *
   //*                                                                  *
   //* Returns: 'true' if label successfully written, else 'false'      *
   bool SetFieldLabel ( short fIndx, const char* labText, 
                        acAttr labAttr = acaUSEDFLT, bool center = false, 
                        bool outline = false, LineType lType = ltSINGLE ) ;

   //* Draw an outline around the outside of the specified field within *
   //* the window border.                                               *
   //* The target field must have at least one space open on all sides. *
   //* That is, it must not be positioned against the window border,    *
   //* and must not be adjacent to any other field.                     *
   //*                                                                  *
   //* Input  : fIndx   : index of target field                         *
   //*          lType   : (optional, ltSINGLE by default) line style    *
   //*                     member of enum LineType: ltSINGLE or ltDUAL  *
   //*          lnAttr  : (optional, acaUSEDFLT by default)             *
   //*                    If specified, color attributes to be used.    *
   //*                    If not specified, stored text attributes used.*
   //*                                                                  *
   //* Returns: 'true'  if successful                                   *
   //*          'false' if invalid field index or insufficient space    *
   //*                  around the field                                *
   bool SetFieldOutline ( short fIndx, LineType lType = ltSINGLE, 
                          acAttr lnAttr = acaUSEDFLT ) ;

   //* Set the "hotkey" for the specified control. A hotkey is a        *
   //* character used to set the input focus to the associated control. *
   //* -- The range of valid hotkeys is:                                *
   //*    wcsALT_A <= hotkey <= wcsALT_RB.                              *
   //*    This corresponds to ASCII A-Z, a-z, and most punctuation      *
   //*    characters.                                                   *
   //* -- The function keys may also be used as hotkeys:                *
   //*    wcsF01 <= hotkey <= wcsCF12                                   *
   //* -- The specified hotkey should be unique within the window.      *
   //*                                                                  *
   //* Note that the standard method for hotkey specification is to     *
   //* embed the hotkey character in the control label so that the user *
   //* has a visual cue, (see SetFieldLabel().                          *
   //*                                                                  *
   //* Menubox controls (ftMB) do not have labels. For this reason,     *
   //* if a hotkey is desired for a menu control, it must be set either *
   //* during skField instantiation ('hkey' member of skField), OR via  *
   //* this method after ACWin instantiation.                           *
   //*                                                                  *
   //* This method may also be used to set the hotkey for some other    *
   //* types of controls (ftTB, ftSB), but this is not recommended.     *
   //* Note that for Pushbutton and Radiobutton controls, the label     *
   //* (and therefore the hotkey) are embedded in the control itself;   *
   //* and therefore this method may not be used to set the hotkey for  *
   //* those control types. Note also that if a hotkey has been         *
   //* previously specified for the target control, it will not be      *
   //* overwritten by this method.                                      *
   //*                                                                  *
   //* Input  : fIndx   : index of target field within the skForm object*
   //*          hotKey  : hotkey character                              *
   //*                                                                  *
   //* Returns: 'true' if hotkey set successfully                       *
   //*          'false' if invalid control index, unsupported control   *
   //*                  type, specified keycode is not one of the valid *
   //*                  hotkey characters, or target control's hotkey   *
   //*                  was previously set.                             *
   bool SetFieldHotkey ( short fIndx, wchar_t hotKey ) ;

   //* Enable or disable read-only state for the specified field.       *
   //*                                                                  *
   //* Input  : fIndx : index of target field within the skForm object  *
   //*          set   : if 'true',  set field as read-only              *
   //*                  if 'false', set field as user-accessible        *
   //*                                                                  *
   //* Returns: current state of the skForm 'ro' flag                   *
   bool  SetReadOnly ( short fIndx, bool set ) ;

   //* Set the visible/hidden state of the target control and optionally*
   //* refresh the display.                                             *
   //*                                                                  *
   //* If target control is set as 'hidden', AND if 'refresh' is        *
   //* specified, then the entire window interior will be refreshed to  *
   //* restore display of any controls or static text that had been     *
   //* obscured by that control.                                        *
   //*                                                                  *
   //* If target control is set as visible (hidden==false), AND if      *
   //* 'refresh' is specified, then only the target control will be     *
   //* refreshed.                                                       *
   //*                                                                  *
   //* Input  : fIndx    : index of target field within skForm object   *
   //*          hidden   ; if 'true',  field will become invisible when *
   //*                                 the window is refreshed          *
   //*                     if 'false', field will become visible when   *
   //*                                 refreshed                        *
   //*          readOnly : if 'true',  field cannot receive input focus *
   //*                     if 'false', field can receive input focus    *
   //*          refresh  : if 'true',  if 'hidden' is set, refresh the  *
   //*                                 entire window interior           *
   //*                                 if 'hidden' is reset, refresh    *
   //*                                 only the target field            *
   //*                     if 'false', display is not updated           *
   //*                                                                  *
   //* Returns: 'true'  if operation successful                         *
   //*          'false' if operation fails:                             *
   //*            a) target field currently has input focus             *
   //*            b) invalid field index                                *
   bool SetFieldHidden ( short fIndx, bool hidden, bool readOnly, bool refresh ) ;

   //* Reformat text of the target field using the specified formatting *
   //* type.                                                            *
   //* This operation applies ONLY to multi-row textbox fields (ftTB).  *
   //* All existing newline characters are removed and the data are     *
   //* reformatted according to the specified formatting option.        *
   //*  1) Set new formatting option if specified.                      *
   //*  2) Remove existing formatting (newline characters).             *
   //*  3) Reformat the data.                                           *
   //*  4) Set IP and logical cursor to field origin (upper-left).      *
   //*  5) Refresh the display.                                         *
   //*                                                                  *
   //* Input  : fIndx  : index of target field                          *
   //*          floType: (optional, 'floDflt' by default) member of     *
   //*                   enum FloType.                                  *
   //*                   specify the type of text formatting to be used *
   //*                   If 'floDflt', use the existing formatting      *
   //*                   option; otherwise, set the formatting type to  *
   //*                   the specified value before reformatting data.  *
   //*                                                                  *
   //* Returns: 'true'  if operation is successful                      *
   //*          'false' a) invalid field index specified                *
   //*                  b) target field is not a multi-row textbox field*
   bool  ReformatFieldText ( short fIndx, FloType floType = floDflt ) ;

   //* Reports the menu (or scrollbox) line item which is referenced    *
   //* by the IP (Insertion Point) of the specified control.            *
   //*                                                                  *
   //* This method will typically be called from the application's      *
   //* callback function after the item-selection signal is received;   *
   //* however, a prior item selection is not necessary.                *
   //*                                                                  *
   //* Input  : fIndx     : index of target control                     *
   //*          itemIndex : (by reference) receives (0-based) index of  *
   //*                      item which is referenced by the IP          *
   //*          itemHotkey: (by reference) receives the "hotkey"        *
   //*                      character (if any) for that item            *
   //*          itemText  :                                             *
   //*                                                                  *
   //* Returns: 'true'  if successful,                                  *
   //*          'false' if invalid field index or target is of          *
   //*                  unsupported control type                        *
   bool GetFieldItem ( short fIndx, short& itemIndex, wchar_t& itemHotkey,
                       gString* itemText = NULL ) const ;

   //* Get the index of the field which currently has the input focus.  *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: index of field with focus                               *
   short GetInputFocus ( void ) ;

   //* Set input focus to the specified field, and refresh field        *
   //* contents. The cursor is placed on the text insertion point.      *
   //* Note: Read-only fields cannot receive the input focus.           *
   //*                                                                  *
   //* Input  : fldIndex: index of target text field                    *
   //*                                                                  *
   //* Returns: index of field with focus                               *
   short SetInputFocus ( short fldIndex ) ;

   //* Set input focus to the next field, and refresh field contents.   *
   //* If already on the last field (index==fCnt-1), wrap around to     *
   //* the first field of the array.                                    *
   //* The cursor is placed on the text insertion point.                *
   //* Note: Read-only fields cannot receive the input focus.           *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: index of field with focus                               *
   short Focus2NextField ( void ) ;

   //* Set input focus to the previous field, and refresh field         *
   //* contents.                                                        *
   //* If already on the first field (index==zero), wrap around to      *
   //* the last field of the array.                                     *
   //* The cursor is placed on the text insertion point.                *
   //* Note: Read-only fields cannot receive the input focus.           *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: index of field with focus                               *
   short Focus2PrevField ( void ) ;

   //* Enable or disable user access to the Insert/Overstrike input     *
   //* mode when user is editing a field, and specify the initial mode. *
   //*                                                                  *
   //* Insert/Overstrike toggle is active by default, and the initial   *
   //* mode is Insert Mode. For some fields, or some kinds of data,     *
   //* however, it is useful to set one mode or the other and lock out  *
   //* user access.                                                     *
   //*                                                                  *
   //* Optionally enable or disable cursor style change when            *
   //* Insert/Overstrike mode is toggled. This provides a visual cue    *
   //* to the user whether Insert mode or Overstrike mode is active.    *
   //* Optionally, the cursor style for each mode may be specified as   *
   //* a member of enum CurStyle (excluding csShow and csHide).         *
   //*                                                                  *
   //* Input  : enable  : 'true'  == enable user access to Insert key   *
   //*                               (this is the default)              *
   //*                    'false' == disable user access to Insert key  *
   //*                               (the mode is locked by application)*
   //*          initMode: initial input mode                            *
   //*                    'true'  == Insert Mode                        *
   //*                    'false' == Overstrike Mode                    *
   //*          styles  : (optional 'false' by default)                 *
   //*                    Enable or disable automatic change of cursor  *
   //*                    style when Insert/Overstrike is toggled.      *
   //*                    'true'  == enable cursor style change         *
   //*                    'false' == disable cursor style change        *
   //*          insStyle: (optional, istyleDFLT by default)             *
   //*                     cursor style for insert mode                 *
   //*                    referenced only when the 'styles' flag is set *
   //*          ovrStyle: (optional, ostyleDFLT by default)             *
   //*                     cursor style for overstrike mode             *
   //*                    referenced only when the 'styles' flag is set *
   //*                                                                  *
   //* Returns: 'true'  if Ins/Ovr toggle enabled, else 'false'         *
   bool InsertKey ( bool enable, bool initMode, bool styles = false, 
                    CurStyle insStyle = istyleDFLT, CurStyle ovrStyle = ostyleDFLT ) ;

   //* Reports the current state of the skForm object's                 *
   //* Insert/Overstrike flag.                                          *
   //*                                                                  *
   //* If set, Insert Mode:                                             *
   //* A character written to the target field will be inserted at the  *
   //* current cursor position, which will push trailing text to the    *
   //* right.                                                           *
   //* If reset, Overstrike Mode:                                       *
   //* A character written to the target field will replace (overwrite) *
   //* the text at the current cursor position.                         *
   //*                                                                  *
   //* Input  : none                                                    *
   //*                                                                  *
   //* Returns: current state of the Insert/Overstrike flag.            *
   bool  isInsertMode ( void ) ;

   //* A locale-aware version of the 'std:isprint' function.            *
   //*                                                                  *
   //* The locale-aware version of 'isprint' takes into account all     *
   //* characters of all languages supported by the Unicode standard.   *
   //* This means that whatever input language is being used for the    *
   //* application, all characters of that language will be handled as  *
   //* expected.                                                        *
   //*                                                                  *
   //* The whitespace characters, Space L' ', Enter L'\n' and Tab '\t'  *
   //* are also recognized as graphing character by this method.        *
   //*                                                                  *
   //* A small range of Unicode codepoints is reserved by the AnsiCmd   *
   //* library for decoding of ANSI escape sequences and combination    *
   //* keys. These _will not_ be reported as graphing characters.       *
   //* Please see the documentation for a discussion of the reserved    *
   //* codepoint group.                                                 *
   //*                                                                  *
   //* Input  : keycode to be tested                                    *
   //*                                                                  *
   //* Returns: true if a "graphing" character, else 'false'            *
   bool isPrint ( wchar_t wkey ) ;

   //* Enable/disable auditory alert when user presses an invalid key.  *
   //*                                                                  *
   //* Input  : enable : if 'true',  enable alert                       *
   //*                   if 'false', disable alert                      *
   //*                                                                  *
   //* Returns: current state of the skForm 'beep' flag                 *
   bool  AlertEnable ( bool enable ) ;

   //* Interactively edit the fields defined within the skForm object.  *
   //*                                                                  *
   //* Input  : focusFld : (by reference, initial value ignored)        *
   //*                     receives the index of the field with input   *
   //*                     focus on return.                             *
   //*          exitField: (optional, default: -1) If specified, this   *
   //*                     is the index of the ftPB (Pushbutton) control*
   //*                     that, when pressed, will cause the loop to   *
   //*                     terminate, and a return to caller.           *
   //*          exitChar : (optional, default: '\0') If specified, when *
   //*                     this character is received, the loop will    *
   //*                     terminate and return to caller.              *
   //*                     Note: If a callback method established which *
   //*                     will determine when to return to caller,     *
   //*                     then 'exitChar' should contain default value.*
   //*                                                                  *
   //* Returns: keycode of last key pressed                             *
   wchar_t EditForm ( short& focusFld, short exitField = -1, 
                      wchar_t exitChar = NULLCHAR ) ;

   //* Set the window title.                                            *
   //* Draw the title centered in the top border of the window.         *
   //*                                                                  *
   //* Input  : newTitle : text of window title                         *
   //*                     (empty string or null pointer erases title)  *
   //*          titAttr  : (optional, existing attributes by default)   *
   //*                     If specified, this is a logical OR of acAttr *
   //*                     values specifying the foreground/background  *
   //*                     color attributes.                            *
   //*                     See the 'acAttr' enumerated type for details.*
   //*          bdrLine  : (optional, ltHORIZ i.e. invalid line type    *
   //*                      by default) If specified, new border style: *
   //*                     ltSINGLE or ltDUAL                           *
   //*                                                                  *
   //* Returns: 'true'  if success                                      *
   //*          'false' if title truncated to fit                       *
   bool SetTitle ( const char* newTitle, acAttr titAttr = acaUSEDFLT, 
                   LineType bdrLine = ltHORIZ ) ;

   //* Reformat the provided text to fit within the specified           *
   //* dimensions.                                                      *
   //*  1) Remove all newlines from the text.                           *
   //*  2) Perform line breaks to limit width of each paragraph row.    *
   //*  3) If necessary, truncate the text to limit the height of the   *
   //*     paragraph. (but see the 'trunc' and 'truncIndex' parameters) *
   //*                                                                  *
   //* Input  : gsTxt    : on entry, contains raw message text          *
   //*                     on return, contains formatted message text   *
   //*          maxRows  : maximum rows for message (>= 1)              *
   //*          maxCols  : maximum columns on any message row (>= 4)    *
   //*          trunc    : (optional, 'true' by default)                *
   //*                     if 'true',  truncate the data if necessary to*
   //*                                 ensure that the data do not      *
   //*                                 extend beyond the specified      *
   //*                                 target area                      *
   //*                     if 'false', format the entire source text    *
   //*                                 array, even if doing so requires *
   //*                                 violating the specified  height  *
   //*                                 of target area (maxRows)         *
   //*                                 (see also 'truncIndex' parameter)*
   //*          hyphenbrk: (optional, 'false' by default)               *
   //*                     if 'false', automatic line breaks occur at   *
   //*                                 space ' ' characters only.       *
   //*                                        U+0020 and U+3000         *
   //*                                 Special Case: the following CJK  *
   //*                                 ideographs are also recognized   *
   //*                                 as whitespace (see documentation)*
   //*                                  '、' comma U+3001 and            *
   //*                                  '。' full stop U+3002            *
   //*                     if 'true',  in addition to the space ' '     *
   //*                                 characters, enable line break at:*
   //*                                  ASCII hyphen    '-' (U+002D)    *
   //*                                  Unicode &mdash; '—' (U+2014)    *
   //*                                  Unicode &ndash; '–' (U+2013)    *
   //*                                  Unicode &minus; '−' (U+2212)    *
   //*                                  Unicode &shy;       (U+00AD)    *
   //*                                                     (soft hyphen)*
   //*          truncIndex: (optional, null pointer by default)         *
   //*                      -- referenced _only_ when the 'trunc' flag  *
   //*                         is reset.                                *
   //*                      if specified, points to a variable to       *
   //*                      receive the index at which the data         *
   //*                      _would_have_been_ truncted to fit the       *
   //*                      specified height of the target area _if_    *
   //*                      the 'trunc' flag had been set.              *
   //*                      a) A positive value indicates that the data *
   //*                         have not been truncated, AND that the    *
   //*                         data extend beyond specified target area.*
   //*                      b) A negative value indicates that it was   *
   //*                         not necessary to truncate the data i.e.  *
   //*                         the data fit entirely within target area.*
   //*                                                                  *
   //* Returns: number of text rows in formatted paragraph              *
   short FormatParagraph ( gString& gsTxt, short maxRows, short maxCols, 
                           bool trunc = true, bool hyphenbrk = false, 
                           int *truncIndex = NULL ) ;

   //* Calculate the dimensions (height and width) of the specified     *
   //* block of text.                                                   *
   //*                                                                  *
   //* Input  : gs        : (by reference) text to be analyzed          *
   //*          msgHeight : (by reference) receives number of text rows *
   //*          msgWidth  : (by reference) receives number of columns   *
   //*                                                                  *
   //* Returns: nothing                                                 *
   void ParagraphSize ( const gString& gs, short& msgHeight, short& msgWidth ) ;
   void ParagraphSize ( const gString& gs, int& msgHeight, int& msgWidth ) ;

   //* Establish (or disable) a callback method which gives the         *
   //* application layer access to user input so that text fields and   *
   //* other controls in the parent window may be dynamically updated.  *
   //* The specified method will be called from within the user-input   *
   //* loop of the EditForm() method.                                   *
   //* The external method handles situations that the parent window    *
   //* cannot. For example:                                             *
   //*  - secondary validation of text data.                            *
   //*  - manual update of non-active controls i.e. display-only        *
   //*    controls that user can view, but cannot access                *
   //*  - signal that the window is to be closed                        *
   //*                                                                  *
   //* Input  : valid pointer to caller's method of the correct type    *
   //*          OR NULL pointer to disable existing callback            *
   //*                                                                  *
   //* Returns: nothing                                                 *
   void EstablishCallback ( CUPTR methodname ) ;

   //* Enable or disable output to the window written through the       *
   //* 'Footnote' group of methods.                                     *
   //*                                                                  *
   //* Input  : enable: set   : enable output from the Footnote method. *
   //*                  reset : disable output from Footnote method.    *
   //*                                                                  *
   //* Returns: current state of the footnote flag                      *
   bool  EnableFootnotes ( bool enable ) ;

   //* Write a message in the lower border of the window, wait a moment,*
   //* then erase the message.                                          *
   //*                                                                  *
   //* Input  : msg   : text of message to be written.                  *
   //*                  -- Message will be truncated if necessary to    *
   //*                     the width of the window minus 4.             *
   //*                  -- If 'msg' is an empty string, then erase any  *
   //*                     existing message and restore the border.     *
   //*          pause : time in tenths-of-a-second to wait before       *
   //*                  message. A value of zero(0) indicates that      *
   //*                  message is to remain visible on return.         *
   //*          color : (optional, default==existing border attributes  *
   //*                  foreground/background color attributes for      *
   //*                  message display                                 *
   //*          center: (optional, 'false' by default)                  *
   //*                  if 'true',  center the message horizontally     *
   //*                  if 'false', message is positioned at left edge  *
   //*                              of the space                        *
   //*                                                                  *
   //* Returns: nothing                                                 *
   void  Footnote ( const gString& msg, short pause, 
                    acAttr color = acaUSEDFLT, bool center = false ) ;
   void  Footnote ( const wchar_t* msg, short pause, 
                    acAttr color = acaUSEDFLT, bool center = false ) ;
   void  Footnote ( const char*    msg, short pause, 
                    acAttr color = acaUSEDFLT, bool center = false ) ;

   //* Display a message in the left or right border of the window.     *
   //*                                                                  *
   //* Input  : msg   : text of message to be written.                  *
   //*                  -- Message will be truncated if necessary to the*
   //*                     height of the window minus 4.                *
   //*                  -- If 'msg' is an empty string, then erase any  *
   //*                     existing message and restore the border.     *
   //*          left  : if 'true',  message is displayed in left border *
   //*                  if 'false', message is displayed in right border*
   //*          color : (optional, existing border attr. by default)    *
   //*                  foreground/background color attributes for      *
   //*                  message display                                 *
   //*          offset: (optional, zero by default) Specify the offset  *
   //*                   (number of rows) from vertically centered      *
   //*                   position.                                      *
   //*                  if  0,  message is vertically centered          *
   //*                  if <0,  message is offset upward from centered  *
   //*                          by specified number of rows.            *
   //*                  if >0,  message is offset downward from centered*
   //*                          by specified number of rows.            *
   //*          clear : (optional, 'false' by default)                  *
   //*                  if 'true',  clear any existing message from the *
   //*                              border before writing new message   *
   //*                  if 'false', existing messages are unaffected    *
   //*                              (unless the new message overwrites  *
   //*                              an old one)                         *
   //*                                                                  *
   //* Returns: nothing                                                 *
   void Sidebar ( const gString& msg, bool left, acAttr color = acaUSEDFLT, 
                  short offset = ZERO, bool clear = false ) ;
   void Sidebar ( const wchar_t* msg, bool left, acAttr color = acaUSEDFLT, 
                  short offset = ZERO, bool clear = false ) ;
   void Sidebar ( const char* msg, bool left, acAttr color = acaUSEDFLT, 
                  short offset = ZERO, bool clear = false ) ;

   //* Push a keycode into the input stream.                            *
   //* All valid wchar_t (wide) keycodes are accepted. The maximum      *
   //* number of keycodes which can be pushed into the input stream     *
   //* FIFO queue is defined as KEYPUSH_MAX (currently 16).             *
   //*                                                                  *
   //* Input  : wKey   : keycode to be placed into the queue            *
   //*                                                                  *
   //* Returns: 'true'  if keycode pushed into the input queue          *
   //*          'false' if input queue is full                          *
   bool KeycodePush ( wchar_t wKey ) ;

   //* Go to command shell.                                             *
   //*   1) Save the application window display data.                   *
   //*   2) Clear the terminal window                                   *
   //*   3) Put the AnsiCmd engine (including ACWin object) into        *
   //*      hibernation mode.                                           *
   //*   4) invoke the specified application (if any)                   *
   //*      a) If no application specified, invoke 'bash' (or current   *
   //*         shell program).In this case, user will need to type      *
   //*         'exit' to return to application.                         *
   //*   5) Wake the AnsiCmd engine from hiberation mode.               *
   //*   6) Restore application window.                                 *
   //*                                                                  *
   //* Important Note:                                                  *
   //*   This method should be called ONLY from the main application    *
   //*   window. AND there should be no sub-dialogs open.               *
   //*   If invoked from a sub-dialog, then the primary window's display*
   //*   data will not be properly saved.                               *
   //*                                                                  *
   //* Input  : shellCmd : (by reference)                               *
   //*                     invoke the specified shell builtin command,  *
   //*                     shell program or console utility program     *
   //*                     - if an empty string, then invoke a copy of  *
   //*                       'bash' shell                               *
   //*                       NOTE: If the default shell IS NOT 'bash',  *
   //*                       then 'shellCmd' should be used to specify  *
   //*                       the target shell program.                  *
   //*          textColor: (optional, default: acaUSE_DFLT)             *
   //*                     [CURRENTLY IGNORED]                          *
   //*                     specify an alternate foreground/background   *
   //*                     color for text data written to standard out. *
   //*                                                                  *
   //* Returns: exit code of child process                              *
   //*           Ideally, this is the exit code of the last utility run *
   //*           in the child process, but this cannot be guaranteed.   *
   int  ShellOut ( const gString& shellCmd, acAttr textColor = acaUSEDFLT ) ;

   //* Launch the system default application for handling the specified *
   //* type of file.                                                    *
   //*                                                                  *
   //* This is done by creating a child process to perform the actual   *
   //* launch, while the parent process continues execution of the      *
   //* application code.                                                *
   //*                                                                  *
   //* Input  : targFile : filespec of file to be processed by the      *
   //*                     external application                         *
   //*          redirect : (optional, 'true' by default)                *
   //*                     if 'true',  redirect stdout and stderr to    *
   //*                                 temp files                       *
   //*                     if 'false', allow stdout and stderr to write *
   //*                                 to the terminal window           *
   //*                                                                  *
   //* Returns: a) the child process ID                                 *
   //*          b) -1 if child process not created                      *
   int  LaunchDefaultApp ( const char* targFile, bool redirect = true ) ;


                  //***********************************
                  //**      Dialog Sub-windows       **
                  //***********************************
   //* Generate a "quick" dialog window within the application's        *
   //* ACWin-class window. Either of two formats may be specified:      *
   //*  1) Information Dialog: Display a dialog with one Pushbutton     *
   //*     control and an informational message.                        *
   //*  2) Decision Dialog: Display a dialog with two Pushbutton        *
   //*     controls. The user must decide between the options presented,*
   //*     Yes/No, Continue/Cancel, Save/Discard, and similar.          *
   //*                                                                  *
   //* For a fully-configurable dialog, see the Dialog method which     *
   //* takes as its parameter a fully-initialized skForm object.        *
   //*                                                                  *
   //* Input  : gsMsg : (by reference) contains the message(s) to be    *
   //*                  displayed.                                      *
   //*          query : 'true'  indicates a decision dialog, and user   *
   //*                          is prompted for a yes/no response       *
   //*                  'false' indicates an information dialog, and    *
   //*                          user is prompted to press Enter to exit *
   //*          title : (optional, default: null pointer)               *
   //*                  If specified, this is the dialog title text     *
   //*                  which will be centered in the top border of     *
   //*                  the dialog.                                     *
   //*          height: (optional, zero (0) by default) height of       *
   //*                  dialog window in rows.                          *
   //*                  A zero value indicates that the dialog is       *
   //*                  automatically sized to accomodate the           *
   //*                  dimensions of the message text (gsMsg)          *
   //*          width : (optional, zero (0) by default) width of the    *
   //*                  dialog window in columns.                       *
   //*                  A zero value indicates that the dialog is       *
   //*                  automatically sized to accomodate the message   *
   //*                  text (gsMsg)                                    *
   //*          vOff  : (optional, default: 0) vertical offset          *
   //*                  into the parent window's text area (0-based)    *
   //*                  A negative value indicates that the dialog is   *
   //*                  to be centered vertically in the parent window. *
   //*          hOff  : (optional, default -1) horizontal offset        *
   //*                  into parent window's text area (0-based).       *
   //*                  A negative value indicates that the dialog is to*
   //*                  be centered horizontally in the parent window.  *
   //*          timeout: (optional, zero by default) automatic timeout  *
   //*                   of dialog display in seconds                   *
   //*                   -- By default, the dialog is closed when one   *
   //*                      of the pushbutton controls is activated.    *
   //*                   -- If a positive value (in seconds) is         *
   //*                      specified, the dialog will close            *
   //*                      automatically after the specified number of *
   //*                      seconds has elapsed OR when any keycode is  *
   //*                      received, whichever comes first.            *
   //*          dbg   : (optional, default: false) for debugging only:  *
   //*                  if reset, refresh the parent window on return   *
   //*                  if set,   dialog remains visible on return      *
   //*                                                                  *
   //* Returns: if 'query' flag is set, then the user response is       *
   //*          returned:                                               *
   //*            'true'  if control at index zero(0) selected          *
   //*            'false' if control at index one(1) selected           *
   //*          if 'query' flag is reset, i.e. dialog has only one      *
   //*          control, then return value is always 'true'.            *
   bool  QuickDialog ( const gString& gsMsg, bool query, 
                       const char* title = NULL, 
                       short height = 0, short width = 0, 
                       short vOff = 0, short hOff = -1, 
                       short timeout = 0, bool dbg = false ) ;

   //* Generate a dialog window within the application ACWin window.    *
   //* The dimensions, position and color attributes are specified      *
   //* directly, while the dialog's controls are defined by passing a   *
   //* pointer to a fully-initialized skForm-class object.              *
   //* The referenced skForm object is updated in response to user      *
   //* interaction, so that when the dialog is closed, caller may       *
   //* interpret any changes the user has made to the controls' status. *
   //*                                                                  *
   //* Note that verification of all parameters is performed by this    *
   //* method, and adjustments will be made to the position and         *
   //* dimensions of the dialog if necessary to make the dialog fit     *
   //* within the parent window.                                        *
   //* In addition, the display text, and the position of the controls  *
   //* will be adjusted if necessary to fit within the dialog.          *
   //* Keep in mind however, that it is impractical to test for all     *
   //* varieties of foolishness, such as overlapping controls, so       *
   //* construct dialogs with care.                                     *
   //*                                                                  *
   //* Input  :                                                         *
   //*   dlgHgt: dialog height (rows)                                   *
   //*           A value of zero (0) indicates that the height of the   *
   //*           dialog is based on the height (rows) of the            *
   //*           PREFORMATTED text it contains, plus necessary padding  *
   //*           (typically an additional three(3) rows).               *
   //*           The height of the dialog may be calculated as the rows *
   //*           needed by the controls plus the height of the static   *
   //*           text data, plus top and bottom borders. Some additional*
   //*           space is recommended to present a pleasing and         *
   //*           easily-readable display.                               *
   //*   dlgWid: dialog width (columns)                                 *
   //*           A value of zero (0) indicates that the width of the    *
   //*           dialog is based on the width (columns) of the          *
   //*           PREFORMATTED text it contains, plus necessary padding  *
   //*           (typically an additional four(4) columns).             *
   //*           The width of the dialog may be calculated as the       *
   //*           columns needed by the widest row of controls, or the   *
   //*           width of the static text, whichever is greatest, plus  *
   //*           the right and left borders. Some additional space is   *
   //*           recommended to present a pleasing and easily-readable  *
   //*           display.                                               *
   //*   formDef:pointer to user-interface control definitions          *
   //*           (skForm object)                                        *
   //*           -- At least one of the defined controls MUST BE a      *
   //*              Pushbutton control; otherwise it is an unrecoverable*
   //*              error.                                              *
   //*           -- Certain member values are overridden by the values  *
   //*              in the skForm object of the parent window.          *
   //*           -- Invalid or out-of-range members will be silently    *
   //*              corrected to maintain dialog integrity.             *
   //*           -- See note below regarding data modified before       *
   //*              return to caller.                                   *
   //*   sTxt  : static text written to be written to dialog interior   *
   //*           (a null pointer or an empty string indicates that      *
   //*            there is no static message)                           *
   //*   tTxt  : dialog title, if specified, will be written centered   *
   //*           in the top border of the dialog.                       *
   //*           (a null pointer or an empty string indicates that      *
   //*            the dialog will have no title)                        *
   //*   vOff  : vertical offset (0-based) in rows from top of parent   *
   //*           window (optional, default: -1) A value of -1 specifies *
   //*           that dialog is centered vertically in parent window.   *
   //*   hOff  : horizontal offset (0-based) in columns, from left edge *
   //*           of parent window.                                      *
   //*           (optional, default: -1) A value of -1 specifies that   *
   //*           dialog is centered horizontally in the parent window.  *
   //*   lType : border style (optional, default: ltSINGLE)             *
   //*           Member of enum LineType (ltSINGLE or ltDUAL)           *
   //*   bAttr : border color attributes                                *
   //*           (optional, default: color attributes are taken from    *
   //*           those of the parent window).                           *
   //*   tAttr : text (dialog interior) color attributes                *
   //*           (optional, default: color attributes are taken from    *
   //*            those of the parent window).                          *
   //*   tvOff : static text position, vertical offset                  *
   //*           (optional, default: 0, top row of dialog)              *
   //*   tHOff : static text [psotopm. horizontal offset                *
   //*           (optional, default: 1, inset one column from left edge *
   //*            of dialog)                                            *
   //*   callbk: pointer to a non-member callback function              *
   //*           (optional, default: null pointer)                      *
   //*           See typedef CUPTR for details.                         *
   //*   dbg   : (optional, false by default) for debugging only:       *
   //*           if reset, refresh the parent window on return          *
   //*           if set,   dialog remains visible on return             *
   //*                                                                  *
   //* Returns: index of selected control                               *
   //*          (this is the same index contained in skfp->fi)          *
   //*          The structure referenced by 'skfp' may have been updated*
   //*          to contain additional information:                      *
   //*          a) Text controls (ftTB): The text of the field may have *
   //*             been modified by user.                               *
   //*          b) Radiobutton controls (ftRB): The 'state' flag which  *
   //*             indicates the binary state of the control            *
   //*             (set or reset) may have changed.                     *
   short Dialog ( short dHgt, short dWid, skForm* formDef, 
                  const char* sTxt = NULL, const char* tTxt = NULL, 
                  short vOff = -1, short hOff = -1, LineType lType = ltSINGLE, 
                  acAttr bAttr = acaUSEDFLT, acAttr tAttr = acaUSEDFLT, 
                  short tvOff = ZERO, short thOff = 1, 
                  CUPTR callbk = NULL, bool dbg = false ) ;

   //*************************************************************
   //** Available _Only_ when a callback function was specified **
   //** for a dialog which is currently under edit.             **
   //** See documentation for a description of these methods.   **
   //*************************************************************
   bool Dialog_GetText ( short ctrlIndx, gString& txtData ) ;
   bool Dialog_SetText ( short ctrlIndx, const gString& txtData, 
                         acAttr color = acaUSEDFLT, bool refresh = true ) ;
   bool Dialog_SetAttr ( short ctrlIndx, const acAttr* acaArray, short acaCnt, 
                         bool refresh = true ) ;
   bool Dialog_Scroll ( short ctrlIndx, int& steps, bool head = false, bool tail = false ) ;
   bool Dialog_Write ( const wchar_t* txt, short yOff, short xOff, 
                       bool clear = false, acAttr color = acaUSEDFLT ) ;
   bool Dialog_Write ( const char*    txt, short yOff, short xOff, 
                       bool clear = false, acAttr color = acaUSEDFLT ) ;
   bool Dialog_Refresh ( bool full = false ) ;
   bool Dialog_GetItem ( short ctrlIndx, gString& itemText, 
                         short& itemNum, bool select = true, bool clear = false ) ;
   bool Dialog_SetItem ( short ctrlIndx, short itemNum, bool refresh = true ) ;
   bool Dialog_GetField ( short ctrlIndx, const skField*& skfPtr ) ;
   bool Dialog_Hilite ( short ctrlIndx, bool set, int begin, int len, 
                        acAttr txtmod = acaUSEDFLT, bool center = true ) ;
   bool Dialog_SetFocus ( short ctrlIndx ) ;
   bool Dialog_GetState ( short ctrlIndx, bool& rbState ) ;
   bool Dialog_GetStateXOR ( short ctrlIndx, short& rbIndx ) ;
   bool Dialog_SetReadOnly ( short ctrlIndx, bool read_only ) ;


                  //***********************************
                  //**     Line Drawing Methods      **
                  //***********************************
   //* Draw a box within the window's text area.                        *
   //*                                                                  *
   //* Input  : pos   : offset from upper-left corner of text area to   *
   //*                  to upper-left corner of box (0-based)           *
   //*          height: number of rows for box                          *
   //*          width : number of columns for box                       *
   //*          lType : (optional, ltSINGLE by default) line style      *
   //*                  member of enum LineType: (ltSINGLE or ltDUAL)   *
   //*          bxAttr: (optional, acaUSEDFLT by default)               *
   //*                  If specified, these are box color attributes.   *
   //*                  If not specified, existing text attributes used.*
   //*          clear : (optional, 'false' by default)                  *
   //*                  if 'false', interior of box is cleared using    *
   //*                             'bxAttr' attributes                  *
   //*                  if 'true',  interior of box is cleared using    *
   //*                              the interior color attributes of    *
   //*                              the parent window                   *
   //*                                                                  *
   //* Returns: 'true'  if box fits within the window text area         *
   //*          'false' if invalid offset or dimensions specified       *
   bool DrawBox ( WinPos wpOrig, short height, short width, 
                  LineType lType = ltSINGLE, 
                  acAttr bxAttr = acaUSEDFLT, bool clear = false ) ;


   //* Draw a horizontal or vertical line in the window.                *
   //*                                                                  *
   //* Note: If the line intersects the window border, the endpoint     *
   //*       character will be automatically selected to match the      *
   //*       intersection of the drawn line and the border line style.  *
   //*                                                                  *
   //* Input  : pos     : offset from upper-left corner of window       *
   //*                    (0-based)                                     *
   //*          length  : length of the line: number of number of rows  *
   //*                    (vertical), or number of columns (horizontal).*
   //*          vertical: 'true'  : vertical line                       *
   //*                    'false' : horizontal line                     *
   //*          lType   : (optional, ltSINGLE by default) line style    *
   //*                     member of enum LineType: ltSINGLE or ltDUAL  *
   //*          begChar : (optional, null character by default)         *
   //*                     specify the beginning endpoint character     *
   //*          endChar : (optional, null character by default)         *
   //*                     specify the final endpoint character         *
   //*          lnAttr  : (optional, acaUSEDFLT by default)             *
   //*                    If specified, color attributes to be used.    *
   //*                    If not specified, stored text attributes used.*
   //*                                                                  *
   //* Returns: cursor position at the end of the line:                 *
   //*          For horizontal lines, the column after last character.  *
   //*          For vertical lines, the column below the last character.*
   WinPos DrawLine ( const WinPos& wpOrig, short length, bool vertical, 
                     LineType lType = ltSINGLE, 
                     wchar_t begChar = L'\0', wchar_t endChar = L'\0', 
                     acAttr lnAttr = acaUSEDFLT ) ;

   //* Debugging method: Get a pointer to the window's skForm object.   *
   //* Note: This is a 'const' pointer. Contents may not be modified.   *
   //*                                                                  *
   //* Input  : nothing                                                 *
   //*                                                                  *
   //* Returns: pointer to the window's skForm object.                  *
   const skForm* GetForm ( void )
   { return ( this->skf ) ; }

   //* Debugging method: Get a pointer to the window's BlockFifo object.*
   //* Note: This is a 'const' pointer. Contents may not be modified.   *
   //*                                                                  *
   //* Input  : nothing                                                 *
   //*                                                                  *
   //* Returns: pointer to the window's BlockFifo object.               *
   const BlockFifo* GetFifo ( void )
   { return ( this->fifo ) ; }

   #if DEBUG_ANSICMD != 0     // For Debugging Only
   //* Debugging method: Get a copy of the window attributes.           *
   //* Input  : txtExp : receives decoded window interior attributes    *
   //*          bdrExp : receives decoded window border attributes      *
   //* Returns: nothing                                                 *
   void GetWinAttributes ( acaExpand& txtExp, acaExpand& bdrExp )
   { txtExp = this->txtAttr ; bdrExp = this->bdrAttr ; }
   //* Debugging method: Get window dimensions and position.            *
   WinPos GetWinConfig ( short& height, short& width )
   { height = this->height ; width = this->width ; return ( this->winBase ) ; }
   //* Debugging method: Override filter for setting soft-echo option.  *
   bool echoOverride ( EchoOpt eopt ) ;

   #if DEBUG_LOG != 0
   //* Debugging method: Write key configuration data to log file.      *
   void dumpConfig2Log ( const wchar_t* title ) ;
   //* Debugging method: Write skField positioning data to log file.    *
   void dumpField2Log ( const skField* fptr, const wchar_t* title, bool verbose = false ) const ;
   //* Debugging method: Write MRParse data to log file.                *
   void dumpMrp2Log ( const skField* fptr, const wchar_t* title = NULL, bool brief = false ) const ;
   //* Debugging method: Write BlockFifo data to log file.              *
   void dumpFifo2Log ( const BlockFifo* bptr, const wchar_t* title = NULL ) const ;
   void dumpFifoRecord2Log ( const DataBlock* dbptr ) const ;
   //* Capture a screenshot to the log file.                            *
   void Screenshot ( bool html = false, const char* desc = NULL ) ;
   #endif   // DEBUG_LOG

   #if DEBUG_KPUSH != 0
   //* Debugging method: Clear (reset) the KecodePush FIFO queue.*
   void KeycodePush_Clear ( void ) ;
   //* Debugging method: Return the number of keycodes *
   //* currently in the keycode pushback FIFO queue.   *
   short KeycodePush_Report ( wchar_t* kfifo = NULL ) ;
   //* Debugging method: Extract a keycode  *
   //* from the keycode pushback FIFO queue.*
   wchar_t KeycodePush_Pull ( void ) ;
   #endif   // DEBUG_KPUSH
   #endif   // DEBUG_ANSICMD


   //****************************
   //* Private methods and data *
   //****************************
   private:
   //* Initialize the window data members.*
   void initialize ( short posRow, short posCol, short winHeight, short winWidth, 
                     const TermConfig *termDef = NULL ) ;
   //* Initialize terminal configuration *
   void init_Term ( const TermConfig *termDef ) ;
   //* Initialize the skForm data member *
   void init_skForm ( const skForm *formDef = NULL ) ;
   //* Range-check the window fields' data, and adjust if necessary.*
   bool init_skFields ( void ) ;
   //* Convert the text of menus into bordered text and initialize stat data.*
   bool init_Menu ( skField* fptr ) ;
   //* Validate the text of Scrollbox controls and initialize stat data.*
   bool init_Scrollbox ( skField* fptr ) ;
   #if DEBUG_SPINNER != 0
   //* Configure the data for Spinner controls.*
   bool init_Spinner ( skField* fptr ) ;
   #endif   // DEBUG_SPINNER
   //* Extract hotkeys from skForm controls, and format text for display.*
   bool init_Hotkeys ( skForm* skfp ) ;
   //* Assign a label, with or without hotkey, to the specified field.  *
   bool setFieldLabel ( skField *fptr, const char* labText, 
                        acAttr labAttr = acaUSEDFLT, bool center = false ) ;
   //* Draw an outline around the outside of the specified field. *
   bool setFieldOutline ( skField *fptr, LineType lType, acAttr lnAttr ) ;
   //* Scan the text data, and if necessary, reformat it to fit the field.*
   bool formatFieldText ( skForm* skfp, short fIndx, bool force = false ) ;
   //* Scan the field text, and if needed, format the text to fit the field. *
   bool fftReformat ( const skField* fptr, gString& gsParse, bool force = false ) const ;
   //* Scan the text of the field and calculate values for each text row. *
   bool parseFieldText ( skField* fptr, short scope = 3 ) ;
   //* Move the input focus to the target control. *
   short setInputFocus ( skForm *skfp, short ftrg ) ;
   //* Move the input focus to the next available field.*
   short focus2NextField ( skForm* skfp ) ;
   //* Move the input focus to the previous available field.*
   short focus2PrevField ( skForm* skfp ) ;
   //* Scan the skField array for next/previous (available) field. *
   short focus2np ( skForm *skfp, wchar_t scanDir, bool inGrp = false ) ;
   //* Set the active/inactive state of the target control.*
   bool setHidden ( skForm *skfp, short fIndx, bool hidden, bool readOnly = false ) ;
   bool setVisible ( skField *fptr ) ;
   //* Set menu or menu group as hidden, set new 'fi' and refresh window. *
   bool menuExit ( skForm *skfp, short fIndx, short fTrg, bool save = false ) ;
   //* Clear (erase) the area defined for the window.*
   void clearWin ( const acaExpand& acaEx, bool all = false ) ;
   //* Write formatted (multi-row) text to the interior of the window. *
   void write ( const WinPos& pos, const gString& txt, bool newln = true ) const ;
   //* Write text (including escape sequences) to the window. *
   void writeSeq ( const WinPos& txtPos, const wchar_t* txtData, acAttr txtAttr ) ;
   void writeSeq ( const WinPos& txtPos, const wchar_t* txtData ) ;
   //* Draw the window border.*
   void drawBorder ( acAttr titAttr = acaUSEDFLT ) ;
   //* Set the color attributes and modifiers to stored terminal-window values.*
   void restoreAttributes ( void ) ;
   //* Determine whether the specified keycode is one of the "special" keys.*
   bool specialkeyTest ( wchar_t& wkey ) const ;
   //* Determine whether 'special' keycode requires conversion.*
   wchar_t specialkeyConvert ( const skForm* skfp, wchar_t wkey ) ;
   //* Determine whether 'normal' keycode requires conversion.*
   wchar_t normalkeyConvert ( const skForm* skfp, wchar_t wkey ) ;
   //* Convert menu item-selection hotkey to a menu item number. *
   wchar_t menuHotkeyConvert ( skField *fptr, wchar_t wkey ) ;
   //* Execute the operation associated with the specified "special" key.*
   bool specialkeyProc ( skForm* skfp, wchar_t wkey ) ;
   void specialkeyProcText ( skForm* skfp, wchar_t wkey ) ;
   bool specialkeyProcCtrl ( skForm* skfp, wchar_t wkey ) ;
   //* Called by specialkeyProc() for multi-row target field.*
   void skpMultirow ( skForm* skfp, wchar_t wkey ) ;
   //* Process special key input for single-row text fields, *
   //* and multi-row text fields configured for floShift.    *
   void  skpShiftedText ( skForm* skfp, wchar_t wkey ) ;
   //* Calculate the 'ip' and 'cur' values for the vertical cursor movement.*
   bool skpInterRow ( skForm* skfp, wchar_t wkey ) ;
   //* Erase the character reference by 'ip'.*
   void skpDeleteChar ( skForm* skfp ) ;
   //* Clear text selection in current field or in all fields.*
   void skpClearSelection ( skForm* skfp, bool refresh = true ) ;
   //* Calculate cursor offset corresponding to insertion point.*
   WinPos skpIp2Cur ( skField *fptr, short iptrg, short *ipval = NULL ) ;
   //* Set the cursor to the insertion point for field with focus.*
   void setCursor2IP ( const skForm *skfp ) const ;
   //* Compare the specified keycode with hotkeys defined for field array.*
   short skpIsHotkey ( const skForm* skfp, wchar_t& wkey, bool conv = true ) const ;
   //* Test the specified keycode for membership in the "hotkey" group.*
   bool isHotkey ( wchar_t& wkey, bool conv = true ) const ;
   //* Test whether the specified keycode is within the Function Key range.*
   bool isFunky ( wchar_t wkey ) const ;
   //* Capture a single keystroke from the user.*
   wchar_t winRead ( void ) ;
   //* Erase the displayed text from the target field.*
   void clearField ( const skForm* skfp, short findx ) ;
   //* Scroll upward or downward through multi-row text fields.*
   bool scrollFieldText ( skForm* skfp, short fIndx, short steps ) ;
   //* Perform a vertical block shift of Textbox data.                  *
   bool shiftFieldText ( skForm* skfp, short fIndx, short steps ) ;
   //* Perform horizontal shift for text fields configured for 'floShift'. *
   bool hshiftFieldText ( skForm* skfp, short fIndx, short steps ) ;
   //* Highlight a segment of text using one or more text-modifier values.*
   bool hilightFieldText ( skForm* skfp, short fIndx, bool set, int begin, int len, 
                           acAttr txtmod = acaREVERSE, bool center = false ) ;
   //* Adjust field text positioning to bring IP within visible space.*
   void centerFieldIP ( skField* fptr, bool horiz = true, bool verti = false ) ;
   //* Refresh the contents of the specified field, or optionally, all fields.*
   void refreshField ( skForm* skfp, short fIndx, bool all = false ) ;
   //* Scan, format and display the text for the specified field object.*
   void refreshText ( const skForm* skfp, short fIndx, bool full = false ) ;
   void refreshShiftedText ( skField* fptr, const WinPos& skfBase ) ;
   //* Re-draw non-text controls (fields). Optionaly, draw field label.*
   void refreshCtrl ( const skForm* skfp, short fIndx, bool focus, bool full = false ) ;
   //* Draw/redraw border around the specified field. *
   void drawFieldOutline ( const skForm* skfp, short fIndx ) ;
   //* Set the "state" of a binary field.*
   bool setFieldState ( skField *fptr, bool state ) ;
   //* Get the current "state" of a binary field (or XOR field group).*
   bool getFieldState ( const skForm *skfp, short fIndx, short* xorMember ) ;
   //* Add a normal (printing, "graphing") character to the target field.*
   void normalkeyProc ( skForm* skfp, wchar_t wkey ) ;
   //* Display dialog window, then wait for user response.*
   short genericDialog ( ACDlg* dlg, short timeout = ZERO ) ;
   bool  refreshDialog ( ACDlg* dlg, bool full = true ) ;
   //* Called by the dialog methods to get a response from the user.*
   short editDialog ( ACDlg* dlg ) ;

   //** Clipboard Group **
   //* Copy the 'selected' text of the target field to the clipboard.*
   int cbCopy ( skForm* skfp, short fIndx, bool cut = false ) ;
   //* Paste the contents of the clipboard to the target field.*
   int cbPaste ( skForm* skfp, short fIndx ) ;
   //* Get a copy of 'selected' text and optionally delete the selection.*
   void copySelection ( skForm* skfp, short fIndx, gString& gsSel, bool cut ) ;

   //**************************
   //* Protected Data Members *
   //**************************
   protected:
   WinPos winBase ;              //* Terminal window offset (1-based)
   WinPos txtBase ;              //* Upper left corner of interior (text area) (1-based)
   WinPos txtOff ;               //* Current cursor position (0-based offset)
   short height ;                //* Height of window object (rows)
   short width ;                 //* Width of window object (columns)
   short txtRows ;               //* Number of text (interior) rows
   short txtCols ;               //* Number of text (interior) columns
   LineType bdrStyle ;           //* Line type for border
   acaExpand bdrAttr ;           //* Color attributes for border
   acaExpand txtAttr ;           //* Color attributes for interior (text & background)
   acaExpand termAttr ;          //* Color attributes for parent terminal window
   BlockFifo* fifo ;             //* Array of data blocks written directly to window interior
   wchar_t title[gsALLOCMIN] ;   //* Title to be displayed in top row of object
   skForm *skf ;                 //* Definition of text fields within the window
   keyPushback kpb ;             //* input stream pushback queue
   AnsiCmd *origaoptr ;          //* Original value of acObjPtr
   CUPTR callbkptr ;             //* Pointer to application's callback method
   bool  saveWrite ;             //* Used by Write() group to enable/disable save to FIFO

} ;   // ACWin class

