@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.0.00 ACWin Class   - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c         Structured high-level user interface  - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node ACWin Class
@unnumbered ACWin Class
@cindex 04.0.00 ACWin Class
@cindex ACWin derived class
@cindex derived class, ACWin
@cindex class, ACWin

The AnsiCmd Window class, @b{@t{ACWin}}, is a @LDQ{}derived@RDQ{} class 
based upon the @t{AnsiCmd} class. This means that it includes all the public 
methods of its parent and methods which are unique to the new class.

ACWin implements a more sophisticated level of abstraction from the basic 
reading and writing of @t{ANSI} escape sequences. It defines a @LDQ{}window@RDQ{}, 
a bordered rectangular area within the terminal display. The interior of the 
window can be used directly to display text data, or may contain various 
user-interface constructs (@pxref{skForm Class}), or both direct display 
and user interface fields. In addition, @LDQ{}dialogs@RDQ{} (sub-windows) 
@ifnothtml
@*
@end ifnothtml
(@pxref{Dialog sub-Windows}) may be created within the primary window either to 
display informational messages or to interact with the user via 
@LDQ{}control@RDQ{} objects such as Pushbuttons.

@menu
* ACWin Public Methods::         Public methods of the ACWin class
* skForm Class::                 Using the skForm and skField classes
* Dialog sub-Windows::           Configure and invoke sub-windows
@end menu
@sp 2


@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@lowersections
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.1.00 ACWin Public Methods  - - - - - - - - - - - - - - - - - - - - - - - -
@c         Public methods of the ACWin class - - - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node ACWin Public Methods
@unnumbered ACWin Public Methods
@cindex 04.1.00 ACWin Public Methods

This table lists the public methods of the ACWin class.

@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
@headitem @ Method Name                   @tab @ Description
@item @t{───} Window-Oriented Methods @t{───}   @tab @t{ ────────────────────────────────────── }
@item @ @ref{ACWin constructor}  @tab @ Constructors
@item @ @ref{ACWin destructor}   @tab @ Destructor
@item @ @ref{OpenWindow}         @tab @ Open the window (make it visible)
@item @ @ref{CloseWindow}        @tab @ Close the window
@item @ @ref{RefreshWin}         @tab @ Redraw the window
@item @ @ref{HideWin}            @tab @ Erase window from display
@item @ @ref{MoveWin}            @tab @ Move window to another position
@item @ @ref{ClearWin}           @tab @ Erase interior of window
@item @ @ref{ClearRow}           @tab @ Erase specified interior row
@item @ @ref{Write}              @tab @ Write directly to window interior
@item @ @ref{GetCursorPos}       @tab @ Get cursor position in the window
@item @ @ref{SetCursorPos}       @tab @ Set cursor position in the window
@item @ @ref{SetTitle}           @tab @ Specify window title text
@item @ @ref{SetTextAttr}        @tab @ Specify window interior colors
@item @ @ref{SetBorderAttr}      @tab @ Specify window border colors
@item @ @ref{WinInfo}            @tab @ Report basic window information
@item @                          @tab @ 
@item @t{───} Form-Oriented Methods @t{─────}   @tab @t{ ────────────────────────────────────── }
@item @ @ref{EditForm}           @tab @ User edit of skForm object
@item @ @ref{GetForm}            @tab @ Get a pointer to skForm object
@item @ @ref{GetInputFocus}      @tab @ Get index of field with focus
@item @ @ref{SetInputFocus}      @tab @ Set input focus to a field
@item @ @ref{Focus2NextField}    @tab @ Move input focus to next field
@item @ @ref{Focus2PrevField}    @tab @ Move input focus to prev field
@item @ @ref{InsertKey}          @tab @ Configure the Insert key
@item @ @ref{isInsertMode}       @tab @ Report insert/overstrike flag
@item @ @ref{AlertEnable}        @tab @ Enable/disable auditory alert
@item @ @ref{EstablishCallback}  @tab @ Specify a callback function 
@item @ @ref{KeycodePush}        @tab @ Push a keycode into input stream
@item @                          @tab @ 
@item @t{───} Field-Oriented Methods @t{────}   @tab @t{ ────────────────────────────────────── }
@item @ @ref{SetFieldText}       @tab @ Replace text in specified field
@item @ @ref{GetFieldText}       @tab @ Get a copy of text in field
@item @ @ref{SetFieldAttr}       @tab @ Set color attributes for a field
@item @ @ref{SetFieldIP}         @tab @ Set insertion point and cursor
@item @ @ref{GetFieldIP}         @tab @ Get current insertion point
@item @ @ref{GetFieldItem}       @tab @ Report highlighted item
@item @ @ref{SetFieldState}      @tab @ Set binary state of field
@item @ @ref{GetFieldState}      @tab @ Get binary state of field
@item @ @ref{SetFieldFlow}       @tab @ Specify auto word wrap option
@item @ @ref{SetFieldLabel}      @tab @ Attach a label to the field
@item @ @ref{SetFieldOutline}    @tab @ Draw a border around a field
@item @ @ref{SetFieldHotkey}     @tab @ Assign a hotkey to the field
@item @ @ref{SetFieldHidden}     @tab @ Set/reset visibility of field
@item @ @ref{SetReadOnly}        @tab @ Set/reset field to read-only
@item @ @ref{SetFieldData}       @tab @ Set field text, color and IP
@item @ @ref{GetFieldData}       @tab @ Report current field stats
@item @ @ref{RefreshField}       @tab @ Redraw text in a field
@item @ @ref{ClearField}         @tab @ Delete text in specified field
@item @ @ref{ReformatFieldText}  @tab @ Reformat text to fit field
@item @ @ref{ScrollFieldText}    @tab @ Auto scroll for multi-row data
@item @ @ref{ShiftFieldText}     @tab @ Block shift for multi-row data
@item @ @ref{HilightFieldText}   @tab @ Highlight a segment of text data
@item @                          @tab @ 
@item @t{───} Dialog-Oriented Methods @t{───}   @tab @t{ ────────────────────────────────────── }
@item @ @ref{QuickDialog}        @tab @ Simple Info/Decision dialog
@item @ @ref{Dialog}             @tab @ Full-initialization dialog
@item @ @ref{Dialog_GetText}     @tab @ Get data from dialog textbox
@item @ @ref{Dialog_SetText}     @tab @ Set data of dialog textbox
@item @ @ref{Dialog_SetAttr}     @tab @ Set multi-color attributes
@item @ @ref{Dialog_GetItem}     @tab @ Get dialog menu item
@item @ @ref{Dialog_SetItem}     @tab @ Set dialog menu selection
@item @ @ref{Dialog_GetState}    @tab @ Get state of dialog radiobutton
@item @ @ref{Dialog_GetStateXOR} @tab @ Get state of radiobutton XOR group
@item @ @ref{Dialog_GetField}    @tab @ Get pointer to dialog field object
@item @ @ref{Dialog_Hilite}      @tab @ Highlight a segment of text data
@item @ @ref{Dialog_SetFocus}    @tab @ Set input focus to target field
@item @ @ref{Dialog_SetReadOnly} @tab @ Set/Reset field's read-only flag
@item @ @ref{Dialog_Scroll}      @tab @ Adjust control's insertion point
@item @ @ref{Dialog_Write}       @tab @ Write text to dialog window
@item @ @ref{Dialog_Refresh}     @tab @ Redraw the dialog window
@item @                          @tab @ 
@item @t{───────} Utility Methods @t{───────}   @tab @t{ ────────────────────────────────────── }
@item @ @ref{FormatParagraph}    @tab @ Automatic text formatting
@item @ @ref{ParagraphSize}      @tab @ Calculate text dimensions
@item @ @ref{isPrint}            @tab @ Test for @LDQ{}graphing@RDQ{} characters
@item @ @ref{EnableFootnotes}    @tab @ Enable/disable output of footnotes
@item @ @ref{Footnote}           @tab @ Write message in bottom border
@item @ @ref{Sidebar}            @tab @ Write message in left/right border
@item @ @ref{DrawBox}            @tab @ Draw a rectangle in text area
@item @ @ref{DrawLine}           @tab @ Draw a line in the text area
@item @ @ref{LaunchDefaultApp}   @tab @ Invoke an external application
@item @ @ref{ShellOut}           @tab @ Invoke an app in current window
@item @                          @tab @ 
@item @t{─────} Development Support @t{─────}   @tab @t{ ────────────────────────────────────── }
@item @ @ref{GetWinAttributes}   @tab @ Report color attributes
@item @ @ref{GetWinConfig}       @tab @ Report height, width and position
@item @ @ref{GetFifo}            @tab @ Report saved static text
@item @ @ref{dumpConfig2Log}     @tab @ Write config data to log
@item @ @ref{dumpField2Log}      @tab @ Write skField stats to log
@item @ @ref{dumpMrp2Log}        @tab @ Write MRParse data to log
@item @ @ref{dumpFifo2Log}       @tab @ Write BlockFifo data to log
@item @ @ref{dumpFifoRecord2Log} @tab @ Write a single FIFO record to log
@item @ @ref{Screenshot}         @tab @ Take a screenshot of the window
@end multitable

@ignore
Public Methods - AnsiCmdWin.hpp - 28-Jan 2025
---------------------------------------------
OK ACWin ( void ) ;
OK ACWin ( short posRow, short posCol, short winHeight, short winWidth, ...
OK virtual ~ACWin () ;
OK WinPos OpenWindow ( const char* initText = NULL, short initField = -1 ) ;
OK void CloseWindow ( bool clear = true, acAttr fillAttr = acaUSEDFLT ) ;
OK void RefreshWin ( bool all = true ) ;
OK void HideWin ( acAttr fillAttr = acaUSEDFLT ) ;
OK bool MoveWin ( const WinPos& newPos, const char *newText = NULL ) ;
OK WinPos ClearWin ( acAttr newAttr = acaUSEDFLT ) ;
OK WinPos ClearRow ( short trgRow, acAttr txtAttr = acaUSEDFLT ) ;
OK WinPos Write ( WinPos txtPos, const gString& txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
OK WinPos Write ( WinPos txtPos, const wchar_t* txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
OK WinPos Write ( WinPos txtPos, const char* txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
OK WinPos Write ( WinPos txtPos, wchar_t txtData, acAttr txtAttr = acaUSEDFLT, bool clear = false ) ;
OK WinPos GetCursorPos ( void ) ;
OK WinPos SetCursorPos ( const WinPos& wPos ) ;
OK WinPos SetCursorPos ( short rOff, short cOff ) ;
OK bool SetTitle ( const char* newTitle, acAttr titAttr = acaUSEDFLT, LineType bdrLine = ltHORIZ );
OK void SetTextAttr ( acAttr txtAttr ) ;
OK void SetBorderAttr ( acAttr bdrAttr, LineType bdrStyle = ltHORIZ ) ;
OK void WinInfo ( winInfo& wInfo ) ;

   //** skForm-Oriented Methods
OK wchar_t EditForm ( short& focusFld, wchar_t exitChar ) ;
OK const skForm* GetForm ( void ) ;
OK short GetInputFocus ( void ) ;
OK short SetInputFocus ( short fldIndex ) ;
OK short Focus2NextField ( void ) ;
OK short Focus2PrevField ( void ) ;
OK bool InsertKey ( bool enable, bool initMode, bool styles = false, ...
OK bool  isInsertMode ( void ) ;
OK bool  AlertEnable ( bool enable ) ;
OK void EstablishCallback ( CUPTR methodname ) ;


   //** skField-Oriented Methods **
   bool SetFieldOutline ( short fIndx, LineType lType = ltSINGLE, acAttr lnAttr = acaUSEDFLT ) ;

   //** Dialog Sub-Window **
   bool  QuickDialog ( const gString& gsMsg, bool query, xxx, short height = 0, 
                       short width = 0, short vOff = 0, short hOff = -1, 
                       short timeout = 0, bool dbg = false ) ;
   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 bdrAttr = acaUSEDFLT, acAttr txtAttr = acaUSEDFLT, 
                  short stvoff = ZERO, short sthoff = 1, bool dbg = false ) ;

   //** Utility Methods **
OK short FormatParagraph ( gString& gsTxt, short maxRows, short maxCols, 
                           bool trunc = true, bool hyphenbrk = false, 
                           int *truncIndex = NULL ) ;
OK void ParagraphSize ( const gString& gs, short& msgHeight, short& msgWidth ) ;
OK void ParagraphSize ( const gString& gs, int& msgHeight, int& msgWidth ) ;
OK void  Footnote ( const gString& msg, short pause, 
                    acAttr color = acaUSEDFLT, bool center = false ) ;
OK void  Footnote ( const wchar_t* msg, short pause, 
                    acAttr color = acaUSEDFLT, bool center = false ) ;
OK void  Footnote ( const char*    msg, short pause, 
                    acAttr color = acaUSEDFLT, bool center = false ) ;
OK void Sidebar ( const gString& msg, bool left, acAttr color = acaUSEDFLT, 
                  short offset = ZERO, bool clear = false ) ;
OK void Sidebar ( const wchar_t* msg, bool left, acAttr color = acaUSEDFLT, 
                  short offset = ZERO, bool clear = false ) ;
OK void Sidebar ( const char* msg, bool left, acAttr color = acaUSEDFLT, 
                  short offset = ZERO, bool clear = false ) ;
OK bool DrawBox ( WinPos wpOrig, short height, short width, 
                  LineType lType = ltSINGLE, 
                  acAttr bxAttr = acaUSEDFLT, bool clear = false ) ;
OK 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 ) ;
// AnsiCmd Clipboard Access
OBSOLETE int GetClipboardText ( gString& gsTxt ) ;
OBSOLETE int SetClipboardText ( const gString& gsTxt ) ;
OBSOLETE int GetClipboardBytes ( void ) ;
OBSOLETE int GetClipboardChars ( void ) ;


   //** ACWin && ACDlg Debugging/Development **
OK void GetWinAttributes ( acaExpand& txtExp, acaExpand& bdrExp );
OK WinPos GetWinConfig ( short& height, short& width );
OK const BlockFifo* GetFifo ( void );
OK void dumpConfig2Log ( const wchar_t* title ) ;
OK void dumpField2Log ( const skField* fptr, const wchar_t* title, bool verbose = false ) ;
OK void dumpMrp2Log ( const skField* fptr, const wchar_t* title = NULL ) ;
OK void dumpFifo2Log ( const BlockFifo* bptr, const wchar_t* title = NULL ) ;
OK void dumpFifoRecord2Log ( const DataBlock* dbptr ) ;
OK void Screenshot ( bool html = false, const char* description == NULL ) ;
@end ignore

@hr90

@c - - - Section - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section Window-Oriented Methods

@anchor{ACWin constructor}
@cindex ACWin constructor
@itemize @BSQUARE
@item @b{ACWin ( void );}

@verbatim
  Input  : none

  Returns: implicitly returns pointer to object
@end verbatim

Default Constructor:@*
Create a default window defined as:@*
@verb{|    posRow  : |}offset one row from top of terminal window@*
@verb{|    posCol  : |}centered in the terminal window@*
@verb{|    winHgt  : |}height == eight(8) rows@*
@verb{|    winWid  : |}width  == thirty-six(36) columns@*
@verb{|    |}All other parameters use the initialization defaults.

The default window is rather useless, so the initialization constructor, 
below, is recommended.
@spi

@item @b{ACWin ( short posRow, short posCol, short winHeight, short winWidth,}@*
@verb{|        |}@b{LineType bdrLine = ltSINGLE, acAttr bdrAttrib = acaATTR_DFLT, }
@ifnothtml
@*@verb{|       |}
@end ifnothtml
@b{acAttr txtAttrib = acaATTR_DFLT,}@*
@verb{|        |}@b{const char* winTitle = NULL, skForm *formDef = NULL );}

@verbatim
  Input  : posRow    : Row    - position of window within the terminal window
           posCol    : Column - position of window within the terminal window
           winHeight : Height of window in rows
           winWidth  : Width of window in columns
           bdrLine   : (optional, member enum LineType, ltSINGLE by default)
                       border style i.e. type of line for border
                       Note: specifying either ltHORIZ OR ltVERT will cause
                       the border to be drawn with spaces only (no line).
           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

  Returns: implicitly returns pointer to object
@end verbatim

Initialization Constructor:@*
Four parameters are required: upper-left row, upper-left column, window 
height (rows) and window width (columns).

Other parameters, if not specified, are set to default values.

Example Instantiation:@*
@b{@verb{|   ACWin *winPtr = new ACWin( 1, 1, 24, 80 );|}@*}

@b{Important Note:} @t{'OpenWindow'} should be the @b{@emph{first}} ACWin 
method called after instantiation because it completes initialization of 
the internal data; however, all standard AnsiCmd-class methods are available 
through the window object pointer immediately after instantiation.@*
For instance: @w{@t{winPtr->acCaptureBreakSignal ( true, cchtIgnore, true );}}
@spi

@H5heading{Notes:,▔▔▔▔▔▔}

@enumerate a
@item @t{'posRow' and 'posCol'} specify the absolute (1-based) position 
of the window within the terminal display area. This is referred to as the 
window @LSQ{}origin@RDQ{} which is the upper-left corner of the window. 
If the argument specifies a zero value, it will be silently set to one(1).

@item @t{'winHeight' and 'winWidth'} specify the number of rows and columns, 
respectively defining the dimensions of the window, @b{@emph{including}} the 
border.

@item @t{'bdrAttrib'} defines the color attributes for the window border, 
and accepts all foreground/background color attributes and text modifiers; 
however, certain text modifiers are not compatible with line-drawing data, 
and are silently disabled.

@item @t{'txtAttrib'} defines the color attributes for the window interior, 
and accepts all foreground/background color attributes and text modifiers.

@item @t{'winTitle'} specifies an optional title which is centered in the 
top border of the window.@*
Example: @verb{|┌───────┤ Wolfie's Favorite Chew Toys ├───────┐|}@*
It is recommended that the first and last characters of the title text be 
space characters. This is not enforced, but it allows the title text to be 
offset from the border line glyphs which makes for better readability.

@item Initialization of the default @t{'@b{skForm}'} object within the text area 
of the window is described in the next section. Direct initialization of the 
skForm gives full control of the number, dimesions and position of the user 
input fields within the window.@*
Please @pxref{skForm Class}, below for more information.

@item Within the ACWin object the user input stream (@t{stdin}) is configured for 
unbuffered input, non-blocking read of input data and uses the @t{softEchoA} 
option to filter keyboard input and echo input to the display.@*
Please @pxref{acBufferedInput} and @ref{Soft Echo Options} for more 
information on configuration of the input stream.
@end enumerate
@spi

@anchor{ACWin destructor}
@cindex ACWin destructor
@item @b{~ACWin ( void );}

@verbatim
  Input  : none

  Returns: nothing 
@end verbatim

Destructor: Return all allocated resources to the system before exit.

The destructor is invoked by deleting the ACWin object. This example 
creates the default ACWin object, opens the window, closes the window, 
then deletes the object.@*
@verb{|   ACWin *winPtr = new ACWin;|}@*
@verb{|   winPtr->OpenWindow( "Hello World!" );|}@*
@verb{|   winPtr->acRead(); |} // wait for keypress@*
@verb{|   winPtr->CloseWindow();|}@*
@verb{|   delete winPtr;|}

If the ACWin object was created as an automatic variable, then the 
destructor is called when the object goes out-of-scope; that is, when 
the execution thread exits the scope in which the object was created.@*
@verb{|   void myProgram ( void )|}@*
@verb{|   {|}@*
@verb{|      ACWin acw;|}@*
@verb{|      acw.OpenWindow( "Hello World!" );|}@*
@verb{|      acw.acRead(); |} // wait for keypress@*
@verb{|      acw.CloseWindow();|}@*
@verb{|      return; |} // object goes out-of-scope here@*
@verb{|   }|}@*
@spi

@anchor{OpenWindow}
@cindex OpenWindow
@item @b{WinPos OpenWindow ( const char* initText = NULL, short initField = -1 );}

@verbatim
  Input  : initText : (optional, null pointer by default)
                      initial text to be written to window
           initField: (optional, -1 by default) [CURRENTLY IGNORED]
                      index of target field for storing 'initText' data
                      Ignored if 'initText' not specified.

  Returns: cursor position (offset) i.e. text insertion point
           This is the character cell following the text in 'initText',
           or if no initial text was specified, the upper-left corner.
@end verbatim

Complete the window setup sequence and display the window within the 
terminal display.

For user input fields of the window's skForm object which have been initialized 
with text data, the text will be displayed.

On return, the visible cursor will be positioned at the text insertion point 
(@t{IP}) of the field which has the input focus.

@b{Important Note:} @t{'OpenWindow'} should be the @b{@emph{first}} ACWin 
method called because it completes initialization of the internal data. 
If any other ACWin method is called before @t{'OpenWindow'}, it may cause 
a reference to uninitialized data.@*
All standard AnsiCmd-class methods are available through the window object 
pointer immediately after instantiation.
@spi

@anchor{CloseWindow}
@cindex CloseWindow
@item @b{void CloseWindow ( bool clear = true, acAttr fillColor = acaUSEDFLT );}

@verbatim
  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 the window.

  Returns: nothing
@end verbatim

Close the window. Relinquish control of the window object.

By default, the window is erased from the terminal display as part of the 
closing sequence; but the visual display may optionally be retained, even 
though control over the space has been returned to the system. 
This includes returning control of input stream buffering to the system.

Note that the window object still exists in memory. To release the window's 
resources, invoke the destructor i.e. delete the ACWin object.@*
@verb{|  Example: ACWin *winPtr new ACWin ;  ...  delete winPtr ;|}@*
or if the window was created as an automatic variable, the object will 
be deleted when it goes out-of-scope. (@pxref{ACWin destructor})
@spi

@anchor{RefreshWin}
@cindex RefreshWin
@item @b{void RefreshWin ( void );}

@verbatim
  Input  : none

  Returns: nothing
@end verbatim

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 @t{RefreshWin} after a previoius call to @t{HideWin}.

The border will be redrawn, the interior of the window will be cleared, 
and the static text (if any) will be written, and the fields of the skForm 
object will be redrawn.
@spi

@anchor{HideWin}
@cindex HideWin
@item @b{void HideWin ( acAttr fillAttr = acaUSEDFLT );}

@verbatim
  Input  : fillAttr : (optional, default: terminal default attributes)
                      color attribute used to erase data from window.

  Returns: nothing
@end verbatim

Temporarily erase the window from the terminal display.@*
All window data are retained but are not visible to the user.

To make the window visible again, call @ref{RefreshWin}.
@spi

@anchor{MoveWin}
@cindex MoveWin
@item @b{void MoveWin ( const WinPos& newPos, const char *newText = NULL );}

@verbatim
  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' window position not updated if specified position 
                   would place any part of the window beyond the edges 
                   of the terminal window.
@end verbatim

Move the window to another position within the terminal display.@*
This is simply erasing the window, updating the base position and redrawing 
the window at the new position.

The author has found this to be a useful way to draw the user's attention 
to some needed action, and of course a moving window could be the basis for 
a customized screen-saver application.
@spi

@anchor{ClearWin}
@cindex ClearWin
@item @b{WinPos ClearWin ( acAttr newAttr = acaUSEDFLT );}

@verbatim
  Input  : newAttr : (optional, acaUSEDFLT by default)
                     new color attributes for text area of window
                     (logical OR of forground and background color)
                     (attributes and text modifiers               )

  Returns: Cursor position (text insertion point)
           This is the upper-left corner of the text area (0/0).
@end verbatim

Erase all text from the interior (text area) of the window.

The text in the skForm object (if any) is retained, but is not redrawn.@*
See also @ref{RefreshWin}.
@spi

@anchor{ClearRow}
@cindex ClearRow
@item @b{WinPos ClearRow ( short trgRow, acAttr txtAttr = acaUSEDFLT );}

@verbatim
  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.
@end verbatim

Erase text from the specified row of the text area.

@b{Note:} @t{ClearRow} does not clear the stored text-field data associated with 
the target row. To clear a single text field within the window, use 
the @ref{ClearField} method instead.
@spi

@anchor{Write}
@cindex Write
@item @b{WinPos Write ( WinPos txtPos, const wchar_t* txtData, }
@ifnothtml
@*@verb{|              |}
@end ifnothtml
@b{acAttr txtAttr = acaUSEDFLT, bool clear = false );}
@item @b{WinPos Write ( WinPos txtPos, const gString& txtData, }
@ifnothtml
@*@verb{|              |}
@end ifnothtml
@b{acAttr txtAttr = acaUSEDFLT, bool clear = false );}
@item @b{WinPos Write ( WinPos txtPos, const char* txtData, }
@ifnothtml
@*@verb{|              |}
@end ifnothtml
@b{acAttr txtAttr = acaUSEDFLT, bool clear = false );}
@item @b{WinPos Write ( WinPos txtPos, wchar_t txtData, }
@ifnothtml
@*@verb{|              |}
@end ifnothtml
@b{acAttr txtAttr = acaUSEDFLT, bool clear = false );}

@verbatim
  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
                    -- a single wchar_t character
           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)
@end verbatim

Write text to the interior of the window.@*
This group of methods writes directly into the window's text area, bypassing 
and obscuring any defined text fields.

These methods will automatically reformat the text if necessary to ensure 
that the text does not extend into or beyond the window border.@*
Please @pxref{acFormatParagraph} for more information on automatic text 
formatting.

To write text into one of the input fields within the window, 
@ifnothtml
@*
@end ifnothtml
@pxref{SetFieldText}.
@spi

@anchor{GetCursorPos}
@cindex GetCursorPos
@item @b{WinPos GetCursorPos ( void );}

@verbatim
  Input  : none

  Returns: current cursor position (window offset)
@end verbatim

Get the current cursor offset within the window's text area.
@spi

@anchor{SetCursorPos}
@cindex SetCursorPos
@item @b{WinPos SetCursorPos ( const WinPos& wPos );}
@item @b{WinPos SetCursorPos ( short rOff, short cOff );}

@verbatim
          
  Input  : Cursor position may be specified in either of 2 ways:
           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)
@end verbatim

Set the cursor offset within the window's text area.
@spi

@anchor{SetTitle}
@cindex SetTitle
@item @b{bool SetTitle ( const char* newTitle, acAttr titAttr = acaUSEDFLT, }
@ifnothtml
@*@verb{|               |}
@end ifnothtml
@b{LineType bdrLine = ltHORIZ );}

@verbatim
  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
@end verbatim

Set the window title.@*
Draw the title centered in the top border of the window.
@spi

@anchor{SetTextAttr}
@cindex SetTextAttr
@item @b{void SetTextAttr ( acAttr txtAttr );}

@verbatim
  Input  : txtAttr : (acAttr bitfield) a logical OR of forground and
                     background color attributes and attribute modifiers

  Returns: nothing
@end verbatim

Set the color attributes and modifiers for the window interior (text area).
@spi

@anchor{SetBorderAttr}
@cindex SetBorderAttr
@item @b{void SetBorderAttr ( acAttr bdrAttr, LineType bdrStyle = ltHORIZ );}

@verbatim
  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
@end verbatim

Set the color attributes and modifiers for the window border.

Optionally, the line style of the border may be changed by specifying 
one of the valid border line styles, either ltSINGLE or ltDUAL.
@spi

@anchor{WinInfo}
@cindex WinInfo
@item @b{void WinInfo ( winInfo& wInfo );}

@verbatim
  Input  : wInfo: (by reference) a winInfo-class object to receive the data

  Returns: nothing
@end verbatim

Returns a copy of the window's current size, position, attributes and other 
basic information.

This information is used primarly for development and debugging; 
however, it often may be useful to get a snapshot of the window configuration, 
especially the @t{'skf'} and @t{'tcfg'} structures.

@verbatim
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  wcbConnect ;    //* Set if connected with Wayland clipboard
   termConfig tcfg ;     //* Terminal configuration data
} ;
@end verbatim

  Note that the current window dimensions and position are not guaranteed to 
  be those specified during instantiation. This is because the constructor 
  range checks and automatically adjusts these values as necessary to fit 
  within the terminal window.
@spi
@end itemize

@hr90w

@c - - - Section - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section Form-Oriented Methods

@anchor{EditForm}
@cindex EditForm
@itemize @BSQUARE
@item @b{wchar_t EditForm ( short& focusFld, short exitField = -1, 
@ifnothtml
@*@verb{|                  |}
@end ifnothtml
wchar_t exitChar = NULLCHAR );}

@verbatim
  Input  : focusFld : (by reference) receives the index of the field with
                      input focus on return to caller.
                      (initial value ignored)
           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 has been established which 
                      will determine when to return to caller, then 'exitChar'
                      should contain the default value.

  Returns: keycode of last key pressed
@end verbatim

Interactively edit the fields defined within the skForm object.

The skForm class defines an array of user-interface fields within the window 
which can be used to create an interactive user interface within a 
console application.

Keyboard input is captured, formatted and written into the fields. Certain 
@LDQ{}special keys@RDQ{} are defined for navigating within and among the 
fields. These keycodes are discussed in the chapter on terminal configuration.@*
Please @pxref{Soft Echo Options} for more information.

A technical description of the skForm class and the associated skField class 
as well as a discussion of user interaction with these objects can be found at: 
@ifnothtml
@*
@end ifnothtml
@ref{skForm Class} and @ref{skField Class}.

@H6heading{There are three ways to exit the user-interface loop:,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
@enumerate 1
@item When the Pushbutton control specified by 'exitField' is pressed.@*
Typically, a window will include an 'Exit', 'Quit', 'Close' or 
similar pushbutton that may be selected by the user to close the 
window. If defined, the index of this Pushbutton may be specified 
by the optional 'exitField' parameter. Then when user selects this 
control, the loop will terminate and control will be returned 
to caller. If 'exitField' contains the default value (-1), then 
the parameter will be ignored.

@item When the character specified by 'exitChar' is received from the user.@*
The optional 'exitChar' parameter may be used to specify that when the 
specified keycode is received, the loop will terminate and control will be 
returned to caller. If 'exitChar' contains the default value ('\0'), then 
the parameter will be ignored. This is an experimental parameter, and 
thusfar has not proven to be very useful; however, it remains a valid option.

@item Via a signal from the callback method.@*
To directly monitor user activity within the @t{EditForm} loop, a 
@ifnothtml
@LDQ{}@emph{callback}@RDQ{} 
@end ifnothtml
@ifhtml
@LDQ{}@b{@i{callback}}@RDQ{} 
@end ifhtml
method may be established at the application level. 
The user interface loop will then invoke the callback method for each 
keystroke entered by the user.@*
Please @pxref{EstablishCallback} for additional information.
@end enumerate
@spi

@anchor{GetForm}
@cindex GetForm
@item @b{const skForm* GetForm ( void );}

@verbatim
  Input  : nothing

  Returns: pointer to the window's skForm object.
@end verbatim

Get a pointer to the window's skForm object.@*
@i{@b{Note:} This is a 'const' pointer. Contents may not be modified.}

This method is useful when the call to @ref{EditForm} has returned, because 
it reports the final contents and states of the @t{skForm} control array.

It is also useful during the development process.

A technical description of the skForm class and the associated skField class 
as well as a discussion of user interaction with these objects can be found at: 
@ifnothtml
@*
@end ifnothtml
@ref{skForm Class} and @ref{skField Class}.
@spi

@anchor{GetInputFocus}
@cindex GetInputFocus
@item @b{short Get@t{I}nputFocus ( void );}

@verbatim
  Input  : none

  Returns: index of field with focus
@end verbatim

Returns the index of the field within the @t{skForm} object which currently 
has the input focus.@*
This value may also be obtained directly if a previous call to @t{GetForm} has 
initialized a pointer to the internal skForm-class data.@*
@xref{GetForm}, for more information.
@spi

@anchor{SetInputFocus}
@cindex SetInputFocus
@item @b{WinPos Set@t{I}nputFocus ( short fld@t{I}ndex );}

@verbatim
  Input  : fldIndex: index of target text field
                     The specified field becomes the active field.

  Returns: index of field with focus
@end verbatim

Set input focus to the specified field, and refresh field contents.@*
The cursor is placed on the text insertion point (@t{IP}) of the field.

Note: Read-only fields cannot receive the input focus.
@spi

@anchor{Focus2NextField}
@cindex Focus2NextField
@item @b{WinPos Focus2NextField ( void );}

@verbatim
  Input  : none
  Returns: index of field with focus
@end verbatim

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.

On return, the cursor is positioned in the field with input focus.

Note: Read-only fields cannot receive the input focus.
@spi

@anchor{Focus2PrevField}
@cindex Focus2PrevField
@item @b{WinPos Focus2PrevField ( void );}

@verbatim
  Input  : none
  Returns: index of field with focus
@end verbatim

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.

On return, the cursor is positioned in the field with input focus.

Note: Read-only fields cannot receive the input focus.
@spi

@anchor{InsertKey}
@cindex InsertKey
@item @b{bool InsertKey ( bool enable, bool initMode, bool styles = false,}@*
@ifnothtml
@verb{|  |}
@end ifnothtml
@verb{|              |}@b{CurStyle insStyle = istyleDFLT, }
@ifnothtml
@*@verb{|                |}
@end ifnothtml
@b{CurStyle ovrStyle = ostyleDFLT );}

@verbatim
  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 Insert/Overstrike toggle enabled, else 'false'
@end verbatim

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).
@spi

@anchor{isInsertMode}
@cindex isInsertMode
@item @b{bool ACWin::isInsertMode ( void );}

@verbatim
  Input  : none

  Returns: current state of the Insert/Overstrike flag
@end verbatim

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.

See also the @t{InsertKey} method, above.
@spi

@anchor{AlertEnable}
@cindex AlertEnable
@item @b{bool AlertEnable ( bool enable );}

@verbatim
  Input  : enable : if 'true',  enable alert
                    if 'false', disable alert

  Returns: current state of the alert flag
@end verbatim

Enable/disable auditory alert when user presses an invalid key.

The auditory alert is specified during instantiation of the ACWin/skForm 
object; however, the alert may be enabled or disabled using this method.@*
Please @pxref{skForm Class} for more information.
@spi

@anchor{EstablishCallback}
@cindex EstablishCallback
@cindex callback function
@item @b{EstablishCallback ( CUPTR methodname );}

@verbatim
  Input  : valid pointer to caller's method of the correct type
           OR NULL pointer to disable existing callback

  Returns: nothing
@end verbatim

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 
@ref{EditForm} method.

The external method handles situations that the parent window cannot. 
@ifnothtml
@*
@end ifnothtml
For example:@*
@verb{| - secondary validation of text data.|}@*
@verb{| - respond in real time to user keyboard input|}@*
@verb{| - manual update of read-only or hidden controls|}@*
@verb{| - signal that the window is to be closed|}

The following example of specifying a callback function is taken 
from the @b{@t{Test_Menu}} method in @t{AnsiCmdTest.cpp}.

@verbatim
   // static non-member pointer providing the non-member
   // callback function with access to the ACWin object.
   static ACWin* tmwPtr = NULL ;

   ACWin *win = new ACWin
         ( winROW, winCOL,          // position (upper-left corner) 
           winHEIGHT, winWIDTH,     // dimensions (height, width)
           ltSINGLE,                // border style
           acaBorder,               // border attributes
           acaInterior,             // interior attributes
           " ACWin MenuBar and Context Menu ", // window title
           skfPtr                   // skForm data template
         ) ;

   win->OpenWindow () ;             // make the window visible
   tmwPtr = win ;                   // give callback method access to ACWin object

   // Specify the callback function to be 
   // invoked from within the user-input loop.
   win->EstablishCallback ( &tmw_Callback ) ;

   win->EditForm ( f, NULLCHAR ) ;  // interact with the user
   win->CloseWindow ( false ) ;     // close the window

   tmwPtr = NULL ;                  // reset the external pointer (be safe)
   delete ( win ) ;                 // release the allocated resourses
@end verbatim

The callback function is based on the the following template:@*
@b{@verb{|  typedef wchar_t (*CUPTR)( short ctrlIndex, |}
@ifnothtml
@*@verb{|                           |}
@end ifnothtml
@verb{|wchar_t wkey, bool firstTime );|}}@*
The @t{'@b{ctrlIndex}'} parameter reports the index of the field which 
currently has the input focus.@*
The @t{'@b{wkey}'} parameter reports the keycode from the user interface.@*
The @t{'@b{firstTime}'} flag is set @emph{ONLY} during the initial call 
which allow the callback function to initialize its internal data.

The callback function monitors keyboard input and responds to user requests 
which cannot be handled automatically by @t{EditForm}.@*
For example, if the user @LDQ{}presses@RDQ{} a Pushbutton or sets/resets 
a Radiobutton, the associated action is performed.

The most obvious of the callback actions is responding to the Pushbutton control 
which closes the window and returns control to the terminal window shell 
program. In this example, the @b{@t{Exit}} pushbutton is selected by the 
user, either by:@*
@verb{| 1) moving the input focus to that pushbutton and pressing|}@*
@verb{|    the 'Enter' (or 'Space') key, or|}@*
@verb{| 2) Pressing the "hotkey" associated with the control, which|}@*
@verb{|    which in this case is ALT+X.|}@*
Note that @t{EditForm} automatically interprets the @LDQ{}hotkeys@RDQ{} 
associated with individual controls and moves the input focus to that 
control. Then the @t{Enter} key is passed to the callback indicating that 
that control has been @LDQ{}selected@RDQ{}.@*
As shown in the example, if the control with focus is the @t{Exit} pushbutton 
and if the keycode indicates that the control has been @LDQ{}selected@RDQ{}, 
then the special @t{'exit'} keycode is returned, signalling that @t{EditForm} 
should terminate the loop and return control to the application level.

@verbatim
   const short fldPB_MBAR = ZERO ;  // index of pushbutton activating menu bar
   const short fldPB_EXIT = ZERO ;  // index of 'Exit' pushbutton

   if ( firstTime )                 // first call
   {
      // initialize static data (if any)
   }

   if ( (wkey == wcsENTER) || (wkey == wcsSPACE) )
   {
      if ( ctrlIndex == fldPB_MBAR )
      {
         . . .
         wkey = L'\0' ;             // signal that keycode was handled
      }
      else if ( ctrlIndex == fldPB_EXIT )
         wkey = wcsCTL_4 ;          // signal loop termination
   }

   return wkey ;
@end verbatim

The received keycode (@t{'wkey'}) can be returned as received, or 
can be modified as a signal to the @t{EditForm} loop.

If the operation has been fully handled, the callback will return the 
null character (@t{L'\0'}). 

If the callback method returns @b{@t{wcsCTL_4}}, it is the signal that 
@t{EditForm} should terminate the loop and return to caller. Note that 
@t{wcsCTL_4} is the ASCII code for the SIGQUIT signal, and will never be 
transmitted @emph{to} the callback method as the @t{'wkey'} parameter.
@hr20s
Note: A callback template defining an @i{application-class member method} 
is under development. This will complement the non-member callback described 
above, and will provide a simpler mechanism for monitoring user activity. 
This requires @t{C++17} support, so we have delayed implementation until 
the community has made the transition.
@spi

@anchor{KeycodePush}
@cindex KeycodePush
@cindex input stream FIFO
@cindex FIFO, input stream
@item @b{KeycodePush ( wchar_t wKey );}

@verbatim
  Input  :
     wKey   : keycode to be placed into the queue

  Returns: 
     'true'  if keycode successfully pushed into the input queue
     'false' if input queue is full
@end verbatim

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 without an 
intervening read is defined as KEYPUSH_MAX (currently 16).

@indentedblock
@H6heading{Keycode FIFO Queue Development,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
Three additional methods are defined for management of the input stream 
FIFO queue. These are under a conditional compile directive and are used 
only during development.

Clear (reset) the KecodePush FIFO queue.@*
All keycodes in the queue will be discarded. Note that this does not affect 
data in the system key input stream.@*
@b{@ @BSQUARE @ void KeycodePush_Clear ( void );}

Return the number of keycodes currently in the keycode pushback FIFO queue, 
and  optionally, return a copy of the current contents of the queue.@*
@b{@ @BSQUARE @ short KeycodePush_Report ( wchar_t* kfifo = NULL );}@*
@verb{|    wchar_t fifoCopy[KEYCODE_MAX] ;|}@*
@verb{|    short kpCount = win->KeycodePush_Report ( fifoCopy ) ;|}@*

Extract a keycode from the keycode pushback FIFO queue.@*
(If the queue is empty, wait for key input from the keyboard.@*
@b{@ @BSQUARE @ wchar_t KeycodePush_Pull ( void );}

Please study the keyPushback class for an example of how a FIFO queue works. 
Because this is a very small FIFO, it is implemented the easy way, with data 
shifted each time an item is removed. In a more sophisticated implementation, 
a dual-indexed wrap-around sequence would be used to enhance performance.
@end indentedblock
@end itemize
@hr90w

@c - - - Section - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section Field-Oriented Methods

@anchor{SetFieldText}
@cindex SetFieldText
@itemize @BSQUARE
@item @b{bool SetFieldText ( short f@t{I}ndx, const gString& srcTxt, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
bool refresh = true );}
@item @b{bool SetFieldText ( short f@t{I}ndx, const wchar_t* srcTxt, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
bool refresh = true );}
@item @b{bool SetFieldText ( short f@t{I}ndx, const char* srcTxt, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
bool refresh = true );}

@verbatim
  Input  : fIndx : index of target field within the skForm object
           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, or if operation
                   is not supported for target field type
@end verbatim

Replace the current contents of the field with new data.@*
The 'ip' (text insertion point) of the field is set to zero, and the 
cursor is set to the field origin.

Field types for which text data may be modified:@*
@verb{| 1) ftTB (Textbox), 2) ftSB Scrollbox, 3) ftPB (Pushbutton)|}@*
Text for other field types is set during instantiation and remains static.
@spi

@anchor{GetFieldText}
@cindex GetFieldText
@item @b{int GetFieldText ( short f@t{I}ndx, gString& txtBuf ) const;}
@item @b{int GetFieldText ( short f@t{I}ndx, wchar_t* txtBuf, int maxChars ) const;}
@item @b{int GetFieldText ( short f@t{I}ndx, char* txtBuf, int maxBytes ) const;}

@verbatim
  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 operation is not
              supported for target field type, 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 to fit the target.
@end verbatim

Get a copy of the current contents of the target Textbox (ftTB) field.

@b{@i{IMPORTANT NOTE:}} Target buffer must be large enough to hold 
@b{@emph{AT LEAST}} two(2) wchar_t characters OR five(5) UTF-8 bytes.@*
@i{Otherwise, you may as well be working for Microsoft.}
@spi

@anchor{SetFieldAttr}
@cindex SetFieldAttr
@item @b{bool SetFieldAttr ( short f@t{I}ndx, acAttr txtAttr );}

@verbatim
  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
                     (note: use of 'underline' modifier not recommended)

  Returns: 'true'  if attribute set successfully
           'false' if invalid field index specified
@end verbatim

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 the field with input focus.
@spi

@item @b{bool SetFieldAttr ( short f@t{I}ndx, const acAttr* rowAttr, short rowCnt );}

@verbatim
  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 attribute set successfully
           'false' if invalid field index specified, or
                   if field type does not support per-row
                   attributes, or if 'rowCnt' out-of-range
@end verbatim

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 @b{@emph{only}} to Menus (ftMB) and 
Scrollbox (ftSB) controls. These control types contain data which is not 
edited, and therefore the color specified for each row will remain unchanged 
until the window is closed.

It is recommended that this method be called AFTER instantiation of the 
ACWin object, but BEFORE the call to @t{OpenWindow}. If called after the 
window has been opened, then on return from the call, the application should 
refresh the display explicitly. This will ensure that the changes are visible.

To specify per-row color attributes for controls within an @t{ACDlg} 
sub-window, please @pxref{colorConfig}.

@spi

@anchor{SetFieldIP}
@cindex SetFieldIP
@item @b{bool SetField@t{IP} ( short f@t{I}ndx, short new@t{I}p, 
@ifnothtml
@*@verb{|                 |}
@end ifnothtml
bool centered = false, bool refresh = true );}

@verbatim
  Input  :
     fIndx   : index of target field
     newIp   : character offset into the text of the field
               ZERO <= newIp <= text characters
               where 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
@end verbatim

Set the insertion point (@t{IP}) for the field. This will set the cursor 
position over the character at the specified offset.

Field types supported by this method are:@*
@verb{| 1) ftTB (Textbox) 2) ftSB (Scrollbox).|}@*
Insertion point for other field types is managed programatically.

Scrolling to ensure that new IP position is within visible space:
@enumerate 1
@item If target IP is already within visible space no scrolling will occur; 
the cursor will simply be placed over the target character.
@item If target IP is above visible space, the row containing the cursor 
will be positioned at the top row of the field.
@item If target IP is below visible space, the row containing the cursor 
will be positioned at the bottom row of the field.
@item The optional @t{'centered'} parameter will further adjust the 
position of the row containing the target IP so that it will be vertically 
centered within the field.@*
@b{Technical Note:} The vertical centering option is fully functional; 
however, the implementation requires three(3) display updates rather 
than the one update needed if centering is not specified. (It's cute, 
but it's slow, so be aware!)
@end enumerate

If @t{'fIndx'} references the field which has input focus, the visible cursor 
will also be updated by default, but see the @t{'refresh'} parameter.

Special case: If @t{'newIp'} is greater that the number of characters in the 
field, IP will be set to end-of-text (referencing the null terminator).

@H5heading{Example,▔▔▔▔▔▔▔}
For example, if user wants to find a tune in the playlist, she will type 
in a keyword or phrase and the application will locate the token and 
bring that song title into the visible space.

@example
╔══════╣  Bryan Adams Play List  ╠══════╗
║▶ All for One, All for Love            ║
║  Baby When You're Gone                ║
║  Back To You                          ║
║  Brothers Under The Sun               ║
║  Can't Stop This Thing We Started     ║
║  Christmas Time                       ║
║  Cloud Number Nine                    ║
║  Desire                               ║
║  Do I Have To Say The Words           ║
║ ──────────────────────────────────────║
║ Find: Get Off                         ║
║ ──────────────────────────────────────║
║           PLAY       CANCEL           ║
╚═══════════════════════════════════════╝
@end example

@H6heading{(Simplified) Code,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
@verbatim
enum fieldNames : short
{
   fnLIST = ZERO,
   fnFIND,
   fnPLAY,
   fnCANCEL,
   fnFIELDS
}

int trgetIp ;
gString gsList, gsFind ;
// Get text of "List" field
win->GetFieldText ( fnLIST, gsList ) ;
// Get text of "Find" field
win->GetFieldText ( fnFIND, gsFind ) ;
// Set focus to list field
win->SetInputFocus ( fnLIST ) ;

// Search for token in the list
if ( (targetIp = gsList.find( gsFind.gstr() )) >= ZERO )
{
   // Set Insertion Point to first character of token
   win->SetFieldIP ( fnLIST, targetIP, true, true ) ;
   // Clear the search text
   win->SetFieldText ( fnFIND, "", true ) ;
}
// Display error message
else
   win->SetFieldText( fnFIND, "Title Not Found", true ) ;
@end verbatim

@example
╔══════╣  Bryan Adams Play List  ╠══════╗
║  Desire                               ║
║  Do I Have To Say The Words           ║
║  Don't Let Go                         ║
║  Everything I Do                      ║
║▶ Get Off My Back                      ║
║  Have You Ever Really Loved A Woman   ║
║  Heaven                               ║
║  Here I Am                            ║
║  I Finally Found Someone              ║
║ ──────────────────────────────────────║
║ Find:                                 ║
║ ──────────────────────────────────────║
║           PLAY       CANCEL           ║
╚═══════════════════════════════════════╝
@end example

@c ║  I Will Always Return                 ║
@c ║  Inside Out                           ║
@c ║  Kids Wanna Rock                      ║
@c ║  Let's Make A Night To Remember       ║
@c ║ ──────────────────────────────────────║
@c ║ Find:                                 ║
@c ║ ──────────────────────────────────────║
@c ║           PLAY       CANCEL           ║
@c ╚═══════════════════════════════════════╝

For a more complex example, see @t{'gotoLine'} method of the 
@ifnothtml
@*
@end ifnothtml
@ref{AcEdit Demo App}.
@spi

@anchor{GetFieldIP}
@cindex GetFieldIP
@item @b{int GetFieldIP ( short f@t{I}ndx );}
@verbatim
  Input  : fIndx   : index of target field

  Returns: current character offset into the text of the field
           (if invalid field index specified, zero will be returned)
@end verbatim

Get the current insertion point (IP) for the specified field.

Note that although this method returns the IP value for all control types, 
this value will be meaningful @emph{only} for Textbox (ftTB) fields, 
and @i{possibly} Scrollbox (ftSB) fields.
For other types of controls IP and cursor position are not meaningful.@*
For controls with @LDQ{}selectable items@RDQ{} i.e. menus (ftMB) and 
Scrollbox (ftSB) controls, refer to the @t{GetFieldItem} below, or to the 
@t{skField-class} @ref{getItem} method.
@spi

@anchor{GetFieldItem}
@cindex GetFieldItem
@item @b{bool GetFieldItem ( short fIndx, short& itemIndex, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
wchar_t& itemHotkey, gString* itemText = NULL );}

@verbatim
  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. 
                 If no hotkey indicator found, '?' is returned.
     itemText  : (optional, default: null pointer)
                 If specified, this is a pointer to a gString object 
                 which will receive the text of the target item.

  Returns:
     'true'  if successful
     'false' if invalid field index or target is of unsupported 
             control type
             'itemIndex' will be set to -1 and
             'itemHotkey' will be set to '?', and
             'itemText' if specified, will be set to an empty string.
@end verbatim

For Menus (ftMB) and Scrollbox controls (ftSB), retrieve the index 
of the @t{"item"} (row) containing the insertion point (@t{'ip'}).
Generally, this is the currently hightlighted item or the item 
which was highlighted when the control lost focus. The @LDQ{}hotkey@RDQ{} 
character for the item (if any) is also extracted from the item text.

This method will typically be called from the application's callback 
function after the item-selection signal (Enter key) is received; however, 
a prior item selection is not necessary. It is also useful after return 
from the @ref{EditForm} method.

This method calls the low level (but still public) @t{skField}-class
@b{@t{getItem}} method. This low-level method is intended primarily for 
use by dialog-oriented callback functions, and is somewhat more 
difficult to use. The @t{GetFieldItem} method makes the operation 
somewhat less painful.@*
Please @pxref{skField Public Methods} for more information.
@spi

@anchor{SetFieldState}
@cindex SetFieldState
@item @b{bool SetFieldState ( short fIndx, bool state, bool refresh = false );}
@verbatim
  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 display
                     if 'false', do not refresh the field

  Returns: current state of the field
@end verbatim

Set the "state" of a binary field.@*
Currently, this applies only to Radiobuttons (type==ftRB).

When the binary state is @t{'set'}, the indicator character is displayed 
between the delimiters:@*
@b{@verb{|   [♦]|}} @i{Allow your internet provider to sell your personal info.}@*
When the state is @t{'reset'}, the indicator character is replaced by 
a space character.@*
@b{@verb{|   [ ]|}} @i{Allow your internet provider to sell your personal info.}@*
@spi

@anchor{GetFieldState}
@cindex GetFieldState
@item @b{bool GetFieldState ( short fIndx, short* xorMember = NULL );}
@verbatim
  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 'state' flag for field referenced by 'fIndx'
@end verbatim

Get the current "state" of a binary field.@*
Currently, this applies only to Radiobuttons (type==ftRB).

@H5heading{XOR Groups:,▔▔▔▔▔▔▔▔▔▔▔}

For radiobutton XOR groups, the binary state for only one member of the group 
can be @LDQ{}set@RDQ{} i.e. @LSQ{}true@RSQ{}. If @t{'fIndx'} references 
a member of an XOR group, @b{@emph{and}} if the @t{'xorMember'} pointer is 
non-null, then the variable referenced by @t{'xorMember'} receives the 
index of the group member whose flag is @LDQ{}set@RDQ{}.
@itemize @EMDASH
@item If the control referenced by 'fIndx' is not a Radiobutton or is not a 
member of an XOR group, then 'xorMember' is ignored.
@item Note that in the (unlikely) case where no member of the XOR group has 
its flag set, @t{'xorMember'} will receive the @t{'fIndx'} value.
@end itemize
@spi

@anchor{SetFieldFlow}
@cindex SetFieldFlow
@item @b{void SetFieldFlow ( short f@t{I}ndx, FloType fType, bool refresh = false );}

@verbatim
  Input  : fIndx   : index of target text field
           fType   : member of enum FloType
           refresh : (optional, 'false' by default)
                     if 'true',  immediately reformat field text
                                 and update the display
                     if 'false', text is reformatted, as needed but
                                 display is not updated

  Returns: 'true'  if flow option set successfully
           'false' if invalid field index specified or if target field
                   is a single-row field or invalid 'fType'
@end verbatim

Set the text-flow type and optionally reformat the existing text.@*
Note that this option applies only to multi-row text fields. Text of 
single-row fields is always truncated at the edge of the field 
(see flowShift option).

@cindex enum FloType
The available text-flow options are specified by enum FloType and are:
@enumerate a
@item @b{@t{floToken}} @NDASH Automatic text wrap by token. A @LDQ{}token@RDQ{} 
is a sequence of characters delimited by whitespace or in certain cases, 
also by punctuation.@*
In general, the application should format the text in the @t{'txt'} member 
as desired; however, if necessary, the text will be automatically reformatted 
to fit within the field.@*
To do this, any existing newline characters ('\n') in the source text are 
removed, and the text data are reformated to fit within the specified height 
and width of the field. If lines of text must be wrapped to keep them within 
the boundaries of the field, then line breaks will be inserted @b{@emph{after}} 
the last whitespace character that fits on the line. Whitespace characters 
are defined as one of the following:@*
@verb{|   ASCII Space (U+0020)|}@*
@verb{|   CJKSPACE    (U+3000)|}@*
@verb{|   CJKCOMMA    (U+3001)|}@*
@verb{|   CJKSTOP     (U+3002)|}@*
@item @b{@t{floHyphen}} @NDASH Same as @t{'floToken'} above, with the addition of 
the following hyphen-like characters being recognized as whitespace.@*
@verb{|   ASCII Minus (U+002D)|}@*
@verb{|   uMINUS      (U+2212) HTML &minus;|}@*
@verb{|   nDASH       (U+2013) HTML &ndash;|}@*
@verb{|   mDASH       (U+2014) HTML &mdash;|}@*
@verb{|   sDASH       (U+00AD) HTML &shy;|}@*
@item @b{@t{floChar}} @NDASH Automatic text wrap by character.@*
This is the brain-damaged form of inserting line breaks, in that the breaks 
are inserted after the last @b{@emph{character}} that will fit on the line. 
Although this is not pretty, it is faster than scanning for whitespace, and 
is useful if you are not sure whether each text row will fit the available space.@*
Note that if the text has been preformatted to fit within the field, then 
this option will not alter formatting of the output.@*
@item @b{@t{floShift}} @NDASH This option disables word wrap. Instead, each 
text row that is too wide to fit in the field will be truncated for display 
to avoid violating the field boundaries. Note that the source text itself is 
not altered; only the @b{@emph{displayed}} data are affected.@*
This is what might be described as @LDQ{}text-editor mode.@RDQ{} The data 
are shifted both vertically and horizontally as the user scrolls through the 
data. This is in contrast to the @t{'floToken'} formatting described above 
in that @t{'floToken'} data are only scrolled vertically.
@item @b{@t{floDflt}} @NDASH This option is used as a placeholder for optional 
call parameters, and is interpreted to mean that the existing word-wrap option 
is not to be modified.
@end enumerate

For more information on auto-formatting please refer to 
@ifnothtml
@*
@end ifnothtml
@ref{acFormatParagraph} 
@ifnothtml
@*
@end ifnothtml
or the gString-class method, @ref{formatParagraph}.
@spi

@anchor{SetFieldLabel}
@cindex SetFieldLabel
@item @b{bool SetFieldLabel ( short fIndx, const char* labText, 
@ifnothtml
@*@verb{|                    |}
@end ifnothtml
acAttr labAttr = acaUSEDFLT, bool center = false );}
@verbatim
  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. (see examples) 
     labAttr : (optional, default: text attributes of parent window) 
               color attributes for label text. 
     center  : (optional, 'false' by default) horizontal offset 
               if set, center the label horizontally in the row above 
                       the field 
               if reset, label is positioned one row above and in 
                       the same column as the left edge of the field 

  Returns: 'true' if label successfully written, else 'false'
@end verbatim

Assign a label, with or without embedded hotkey, to the specified field.
 
@itemize @SDISC
@item Labels may be assigned only to Textbox (ftTB) and Scrollbox (ftSB) 
controls.
@item Labels are incompatible with Menubox controls (FldType ftMB).@*
@pxref{SetFieldHotkey} for setting hotkeys for menu controls. 
@item This method may not be used for Pushbuttons and Radiobuttons.@*
This is because for Pushbutton (ftPB) and Radiobutton (ftRB) controls, 
the label (and optional hotkey) are integrated into the control definition.
@item Label length: @t{1 <= length <= labelLEN}. This is the storage 
capacity expressed as the maximum number of @emph{characters} (currently 64) 
for a label. Text will be truncated if necessary to fit the storage array.
@item Label width (columns): Text will be truncated if necessary to 
avoid violation of window border. 
@item The range of valid hotkeys is: @t{wcsALT_A <= hotkey <= wcsALT_RB}. 
This corresponds to @t{ASCII A-Z, a-z}, and most punctuation characters.@* 
The specified hotkey should be unique within the window. 
@item The label is positioned one row above the target field with 
the horizontal offset determined by the 'center' parameter.@*
If the position conflicts with another object in the window, the display 
data may be corrupted. You have been warned! 
@item Example of a label containing a hotkey specification: @*
@verb{|   "Gra^pefruit"|}@* 
where the caret preceeds @t{'p'}, indicating that the hotkey is the 
@t{ALT+p} key combination which is assigned to the @t{wcsALT_P} keycode 
constant. 
@item Technical Notes:
@itemize @SCIRCLE
@item Label may not extend into the window border. 
@item Label may not be an empty string. 
@item Label may not contain newline characters. If it does, they will 
be silently removed. 
@item If label includes a hotkey, it must be one of the defined 
valid hotkeys. The specified hotkey must be unique to the window. 
No other control may be assigned the same hotkey. 
@item It is the application's responsibility to ensure that the label 
does not violate the space reserved for any other item. A programatic 
test for such a violation would just be too expensive.
@item If the target field is to have BOTH a border and a label, 
then call the @ref{SetFieldOutline} method instead. 
@end itemize
@end itemize

The following is a screenshot of a window demonstrating both field labels 
and field outlines. This test window may be found in the @t{Test_Form} 
method in @t{AnsiCmdTest.cpp}.

@ifnothtml
@example
 ┌──────┤  Window Formatted With "skForm" ├─────┐
 │   Animals(ALT+A)   Vegetables(ALT+V)         │
 │                                              │
 │ Tab among fields. Edit the fields as desired.│
 │ "Hotkeys" == ALT key + underlined character. │
 │ ┌Multi-row Field───────────────────────────┐ │
 │ │Edit keys are: Left, Right, Home, End,    │ │
 │ │Tab, Shift+Tab, PageUp, PageDown, plus    │ │
 │ │Backspace, Delete and Insert.             │ │
 │ └──────────────────────────────────────────┘ │
 │ ┌Empty Field─────────┐┌TiengViet Field─────┐ │
 │ │                    ││Gặp tôi ở Sai Gon.  │ │
 │ └────────────────────┘└────────────────────┘ │
 │ ┌Zhongwen Field────────────────────────────┐ │
 │ │这他妈的并不像看起来那么容易。            │ │
 │ └──────────────────────────────────────────┘ │
 │  [◆] Blue Border       [ ] Alt. Interior     │
 │  [ ] Yellow Border      Alternate Outlines   │
 │  [ ] Green Border      [◆] Ins/Ovr Key       │
 │     ╔══════Scrolling - View Only════════╗    │
 │     ║ There once was a man from Kirkuk, ║    │
 │     ║ Known far and wide for his luck,  ║    │
 │     ║ Till while jogging one day,       ║    │
 │     ╚═══════════════════════════════════╝    │
 │           ╔══════════════════════╗           │
 │           ║ EXIT - 出口 - Salida ║           │
 │           ╚══════════════════════╝           │
 └──────────────────────────────────────────────┘

@end example
Note that the pretty colors and text underlining are not supported 
in the Texinfo document. Please see the HTML documents to view 
the window in all its glory. :-)
@end ifnothtml
@ifhtml
@html
<div style=padding-left:4em;">
<div class="tscap" style="background-color:#33FFCC; max-width:28.85em; line-height:1.165em;"><span class="brbl">┌──────┤  Window Formatted With "skForm" ├─────┐</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;"> </span><span class=ma_y>  Animals(ALT+A)   Vegetables(ALT+V)        </span><span style="background-color:#33FFCC;"> </span><span class="bl_r">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;">                                              </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;"> Tab among fields. Edit the fields as desired.</span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;"> "Hotkeys" == ALT key + underlined character. </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;"> ┌<span style="text-decoration:underline;">M</span>ulti-row Field───────────────────────────┐ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;"> │</span><span style="color:blue; background-color:#CCCC;">Edit keys are: Left, Right, Home, End,    </span><span style="color:blue; background-color:#33FFCC;">│ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;"> │</span><span style="color:blue; background-color:#CCCC;">Tab, Shift+Tab, PageUp, PageDown, plus    </span><span style="color:blue; background-color:#33FFCC;">│ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;"> │</span><span style="color:blue; background-color:#CCCC;">Backspace, Delete and Insert.             </span><span style="color:blue; background-color:#33FFCC;">│ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;"> └──────────────────────────────────────────┘ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:green; background-color:#33FFCC;"> ┌<span style="text-decoration:underline;">E</span>mpty Field─────────┐</span><span style="color:red; background-color:#33FFCC;">┌<span style="text-decoration:underline;">T</span>iengViet Field─────┐ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:green; background-color:#33FFCC;"> │<span style="background-color:#CCCC;">                    </span>│</span><span style="color:red; background-color:#33FFCC;">│</span><span style="color:red; background-color:#CCCCCC;">Gặp tôi ở Sai Gon.  </span><span style="color:red; background-color:#33FFCC;">│ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:green; background-color:#33FFCC;"> └────────────────────┘</span><span style="color:red; background-color:#33FFCC;">└────────────────────┘ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:fuchsia; background-color:#33FFCC;"> ┌<span style="text-decoration:underline;">Z</span>hongwen Field────────────────────────────┐ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:fuchsia; background-color:#33FFCC;"> │<span style="background-color:#CCCC;"><span style="letter-spacing:0.200em;">这他妈的并不像看起来那么容易。</span>            </span>│ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:fuchsiabackground-color:#33FFCC;"> └──────────────────────────────────────────┘ </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;">  [♦]</span> <span style="text-decoration:underline;">B</span>lue Border       <span style="color:blue;">[ ]</span> Alt<span style="text-decoration:underline;">.</span> Interior     </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;">  [ ]</span> <span style="text-decoration:underline;">Y</span>ellow Border     <span style="color:red; background-color:#99FF00"> Alternate <span style="text-decoration:underline;">O</span>utlines </span><span style="background-color:#33FFCC;">  </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:#33FFCC;">  [ ]</span> <span style="text-decoration:underline;">G</span>reen Border      [♦] Ins/Ovr Key       </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;">     </span><span style="color:lime; background-color:#CC0099">╔══════Sc<span style="text-decoration:underline;">r</span>olling - View Only════════╗</span>    </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;">     </span><span style="color:lime; background-color:#CC0099">║</span><span style="background-color:#FF66FF;"> There once was a man from Kirkuk, </span><span style="color:lime; background-color:#CC0099">║</span>    </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;">     </span><span style="color:lime; background-color:#CC0099">║</span><span style="background-color:#FF66FF;"> Known far and wide for his luck,  </span><span style="color:lime; background-color:#CC0099">║</span>    </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;">     </span><span style="color:lime; background-color:#CC0099">║</span><span style="background-color:#FF66FF;"> Till while jogging one day,       </span><span style="color:lime; background-color:#CC0099">║</span>    </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:#33FFCC;">     </span><span style="color:lime; background-color:#CC0099">╚═══════════════════════════════════╝</span><span style="background-color:#33FFCC;">    </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:fuchsia; background-color:#33FFCC;">           ╔══════════════════════╗           </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:fuchsia; background-color:#33FFCC;">           ║<span style="font-weight:bold; color:#99FF00; background-color:red;"> E<span style="text-decoration:underline;">X</span>IT - <span style="letter-spacing:0.200em;">出口</span> - Salida </span>║           </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:fuchsia; background-color:#33FFCC;">           ╚══════════════════════╝           </span><span class="brbl">│</span>
<span class="brbl">└──────────────────────────────────────────────┘</span>
</div></div>
@end html
@end ifhtml

@spi

@anchor{SetFieldOutline}
@cindex SetFieldOutline
@item @b{bool SetFieldOutline ( short fIndx, LineType lType, acAttr lnAttr );}

@verbatim
  Input  : fIndx   : index of target field
                     if 'fIndx' == number of fields defined, then draw an
                     outline around each 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 target field
@end verbatim

Draw an outline around the outside of the specified field within the window 
border. The contents of the field will be refreshed after the border is drawn.

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.

This method calculates the position and dimensions for the outline and then 
calls the @ref{DrawBox} method described elsewhere in this document.

@b{Note:} Potential incursion into the border is range checked; however, 
potential incursion into other fields @b{@emph{is not}} tested. Beware!

For Textbox (ftTB) and Scrollbox (ftSB) controls, a label may optionally 
be assigned to the field. This label will be positioned in the upper border 
of the field outline.@*
Please @pxref{SetFieldLabel} for additional information.

@ifnothtml
@H5heading{Example,▔▔▔▔▔▔▔}

@verbatim
   ┌───────────────────┤ Outline Demo ├────────────────────┐
   │┌─ Oscar Wilde ───────────────────────────────────────┐│
   ││▒▒▒▒Be yourself; everyone else is already taken.▒▒▒▒▒││
   │└─────────────────────────────────────────────────────┘│
   │                                                       │
   │┌─────────────────── Old Uncle Ben ───────────────────┐│
   ││With great power comes great responsibility.▒▒▒▒▒▒▒▒▒││
   │└─────────────────────────────────────────────────────┘│
   │                                                       │
   │ ╔══════ Quiet Garden ══════╗                          │
   │ ║                          ║                          │
   │ ║ In my quiet garden       ║                          │
   │ ║ The fish are so polite   ║                          │
   │ ║ They seldom speak        ║                          │
   │ ║ To interrupt my reverie. ║                          │
   │ ║              马伦 — 2013 ║                          │
   │ ╚══════════════════════════╝                          │
   │                     ╔══════════╗                      │
   │                     ║   EXIT   ║                      │
   │                     ╚══════════╝                      │
   └───────────────────────────────────────────────────────┘
@end verbatim
@end ifnothtml
@ifhtml
@html
<div style=padding-left:4em;">
<div class="tscap" style="background-color:#CCFFFF; max-width:33.85em; line-height:1.165em;"><span class="cygy">┌───────────────────┤<span class="gybl"> Outline Demo </span>├────────────────────┐</span>
<span class="cygy">│</span><span style="font-weight:bolder; color:#FF0033; background-color:#CCFFFF;">┌─ Oscar Wilde ───────────────────────────────────────┐</span><span class="cygy">│</span>
<span class="cygy">│</span><span style="font-weight:bolder; color:#FF0033; background-color:#CCFFFF;">│<span style="color:blue;">▒▒▒▒Be yourself; everyone else is already taken.▒▒▒▒▒</span>│</span><span class="cygy">│</span>
<span class="cygy">│</span><span style="font-weight:bolder; color:#FF0033; background-color:#CCFFFF;">└─────────────────────────────────────────────────────┘</span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;">                                                       </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="font-weight:bolder; color:#FF0033; background-color:#CCFFFF;">┌───────────────────<span style="color:#009900; background-color:#FF66FF;"> Old Uncle Ben </span>───────────────────┐</span><span class="cygy">│</span>
<span class="cygy">│</span><span style="font-weight:bolder; color:#FF0033; background-color:#CCFFFF;">│<span style="color:blue;">With great power comes great responsibility.▒▒▒▒▒▒▒▒▒</span>│</span><span class="cygy">│</span>
<span class="cygy">│</span><span style="font-weight:bolder; color:#FF0033; background-color:#CCFFFF;">└─────────────────────────────────────────────────────┘</span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;">                                                       </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="font-weight:bold; color:black;">╔══════<span style="color:#CCFFFF; background-color:black;"> Quiet Garden </span>══════╗</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">║</span><span style="background-color:#FFCCFF">                          </span><span style="color:black;">║</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">║</span><span style="background-color:#FFCCFF"> In my quiet garden       </span><span style="color:black;">║</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">║</span><span style="background-color:#FFCCFF"> The fish are so polite   </span><span style="color:black;">║</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">║</span><span style="background-color:#FFCCFF"> They seldom speak        </span><span style="color:black;">║</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">║</span><span style="background-color:#FFCCFF"> To interrupt my reverie. </span><span style="color:black;">║</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">║</span><span style="background-color:#FFCCFF">              <span style="letter-spacing:0.200em;">马伦</span> — 2013 </span><span style="color:black;">║</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;"> <span style="color:black;">╚══════════════════════════╝</span>                          </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;">                     </span><span style="color:#CC0099">╔══════════╗</span>                      </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;">                     </span><span style="color:#CC0099">║<span style="font-weight:bold; color:#99FF00; background-color:red;">   EXIT   </span>║</span>                      </span><span class="cygy">│</span>
<span class="cygy">│</span><span style="background-color:#CCFFFF;">                     </span><span style="color:#CC0099">╚══════════╝</span>                      </span><span class="cygy">│</span>
<span class="cygy">└───────────────────────────────────────────────────────┘</span>
</div></div>
@end html
@end ifhtml
@spi

@anchor{SetFieldHotkey}
@cindex SetFieldHotkey
@cindex hotkeys, set
@item @b{bool SetFieldHotkey ( short fIndx, wchar_t hotKey );}
@verbatim
  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, target control's hotkey was previously set 
@end verbatim

Set the @t{"hotkey"} for the specified control. A hotkey is a character used to 
move the input focus to the associated control.
@itemize @NDASH
@item The range of valid hotkeys is: @t{wcsALT_A <= hotkey <= wcsALT_RB}.@* 
This corresponds to the @t{'ALT'} key plus @t{ASCII A-Z, a-z,} and most 
punctuation characters.
@item The majority of @t{CONTROL+ A-Z} characters are also available as hotkeys.

@i{@b{Technical Note:} A conditional compile directive controls whether these 
keycodes when received, will be automatically converted to the equivalent 
ALT+n keycode. See the private @t{isHotkey} method for details.}

When this conversion is enabled, if user presses one of the CTL+n keys, it 
will be automatically converted to the equivalent ALT+n keycode, and the 
converted keycode will be used to perform the action specified for that 
hotkey.@*
For example: If the hotkey @t{ALT+B} is assigned to a Pushbutton control via 
the text of the control:@*
@ @ @ @LDQ{}@b{@verb{|   ^BACKUP   |}}@RDQ{},@*
then the control would be displayed with the @t{'@b{B}'} underlined.@*
@ifnothtml
@verb{|   ▒▒▒BACKUP▒▒▒|}@*
@verb{|      ▔|}@*
@end ifnothtml
@ifhtml
@indentedblock
@html
<div class="tscap" style="background-color:#33FFCC; max-width:10.65em; line-height:1.165em;"><span style="color:fuchsia; background-color:#33FFCC;">                </span>
<span style="color:fuchsia; background-color:#33FFCC;">   <span style="font-weight:bold; color:#99FF00; background-color:red;">   <span style="text-decoration:underline;">B</span>ACKUP   </span>
<span style="color:fuchsia; background-color:#33FFCC;">                </span>
</div>
@end html
@end indentedblock
@end ifhtml
The user may then select the control using either @t{ALT+B} (wcsALT_B) or 
@t{CTL+B} (wcsCTL_B) which will have been converted to wcsALT_B.

When this conversion is disabled, then @t{CTL+B} and @t{ALT+B} are seen as 
@b{different} hotkeys.

Certain Control+n keycodes are reserved as specific command keys. For example, 
the @t{'wcsCTL_C', 'wcsCTL_X', 'wcsCTL_V'} are reserved for @LDQ{}Copy@RDQ{}, 
@LDQ{}Cut@RDQ{} and @LDQ{}Paste@RDQ{} respectively. 
@ifnothtml
@*
@end ifnothtml
Please @pxref{ASCII Control Codes} for a further information.
@item The function keys may also be used as hotkeys: @w{@t{wcsF01 <= hotkey <= wcsCF12}} 
@item The specified hotkey should be unique within the window.
@end itemize

Please @pxref{test A} which describes these keycodes in further detail.@*
Refer also to the source code for the private methods @t{isHotkey} and 
@t{isFunky} which define the full range of available hotkeys.
 
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, 
(@pxref{SetFieldLabel}).@*
Menubox controls (ftMB) do not have labels. For this reason, if a hotkey 
is desired for a menu control, it must be set during skField instantiation 
(@pxref{skForm Class}), 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 because there would be 
no visible cue to assist the user. 

Note that for Pushbutton and Radiobutton controls, the label (and therefore 
the hotkey, if any) 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. 
@spi

@anchor{SetFieldHidden}
@cindex SetFieldHidden
@item @b{bool SetFieldHidden ( short fIndx, bool hidden, 
@ifnothtml
@*@verb{|                     |}
@end ifnothtml
bool readOnly, bool refresh );}
@verbatim
  Input  : 
     fIndx    : index of target field within the 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 (invalid field index)
@end verbatim

Set the visible/hidden state of the target control and optionally refresh 
the display.

Except for menu controls, all controls are set as visible by default; however, 
for complex user interface configurations, it is common for some inactive 
controls to be obscured by other controls. Those obscured controls become 
visible and active when needed and then return to the background. In this 
way, a creative use of the @t{'hidden'} and @t{'read-only'} flags can 
make efficient use of the limited space within the terminal window.

As an example, the @t{AcEdit} application included in this package defines 
at least fourteen controls which share the application window: a menu group, 
a line-number field, a gutter field, a context menu and five overlapping 
controls for editing text: upper/lower, left/right and full-window textbox 
controls. @xref{AcEdit Demo App} for details.

@H6heading{Making the changes visible:,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
@enumerate 1
@item 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.
@item If target control is set visible, AND if 'refresh' is specified, 
then only the target control will be refreshed.
@end enumerate
@spi

@anchor{SetReadOnly}
@cindex SetReadOnly
@item @b{bool SetReadOnly ( short f@t{I}ndx, bool set );}

@verbatim
  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 read-only flag
@end verbatim

Enable or disable read-only state for the specified field.

If a field is set as read-only, then it cannot receive the input focus; 
and therefore cannot be accessed by the user. A field which has been set as 
read-only may or may not be visible (@pxref{SetFieldHidden} above).
@spi

@anchor{SetFieldData}
@cindex SetFieldData
@item @b{bool SetFieldData ( short f@t{I}ndx, const gString& srcTxt, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
acAttr txtAttr = acaUSEDFLT,@*
@ifnothtml
@verb{|                   |}
@end ifnothtml
@ifhtml
@verb{|                |}
@end ifhtml
short new@t{I}p = ZERO, bool refresh = true );}
@item @b{bool SetFieldData ( short f@t{I}ndx, const wchar_t* srcTxt, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
acAttr txtAttr = acaUSEDFLT,@*
@ifnothtml
@verb{|                   |}
@end ifnothtml
@ifhtml
@verb{|                |}
@end ifhtml
short new@t{I}p = ZERO, bool refresh = true );}
@item @b{bool SetFieldData ( short f@t{I}ndx, const char* srcTxt, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
acAttr txtAttr = acaUSEDFLT,@*
@ifnothtml
@verb{|                   |}
@end ifnothtml
@ifhtml
@verb{|                |}
@end ifhtml
short new@t{I}p = ZERO, bool refresh = true );}

@verbatim
  Input  : 
     fIndx   : index of target field within the skForm object
     srcTxt  : (by reference) new text data for field
     txtAttr : (optional, default: acaUSEDFLT, indicating that
               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
               where 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
@end verbatim

Set or modify the setup data for the specified field.

The effect is the same as seperately calling three individual methods:@*
@ @ @ SetFieldText, SetFieldAttr and SetFieldIP (see above),@*
except that this method is more efficient if modifying multiple parameters.

Not all parameters apply equally to all field types. Some combinations of 
field-type and configuration settings are fixed on instantiation, and some 
configuration settings are managed internally by the library methods.

@example
Legend:
  1) "@b{modify}" value may be modified under application control. 
     (Note that timing may be an issue, so make modifications) 
     (only when target field does not have focus.            ) 
  2) "@b{static}" indicates that value is set during 
     instantiation and cannot be modified. 
  3) "@b{program}" value is programatically managed by 
     the library. 

  Field  Text    Color   Ins. 
  Type   Data    Attr    Point
  -----  ------  -----   ------
  ftTB   modify  modify  modify
  ftSB   modify  modify  modify
  ftPB   modify  modify  static
  ftRB   static  modify  static
  ftMB   static  modify  program
@end example
@spi

@anchor{GetFieldData}
@cindex GetFieldData
@item @b{   bool GetFieldData ( short fIndx, skField& skfld ) const;}

@verbatim
  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
@end verbatim

Get a copy of the current settings for the specified field.@*
This method is intended primarily for reporting data during development; 
however, this method may also be useful at the application level for 
analysis of the field data after the @ref{EditForm} method has returned 
control to the application.

@b{NOTE:} All data members @b{@emph{including}} protected members are reported.

Please @pxref{skForm Class} for details on the structure and usage of the 
@b{@t{skField-class}} data members.
@spi

@anchor{RefreshField}
@cindex RefreshField
@item @b{void RefreshField ( short f@t{I}ndx );}

@verbatim
  Input  :
     fIndx: index of target field
            If fIndx < ZERO || fIndx >= total of fields defined (fCnt),
            then all fields will be refreshed.

  Returns: nothing
@end verbatim

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.

@H5heading{Technical Note:,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
There are two ways to refresh the field labels or field outlines in 
addition to the field itself. The first is to set @t{'fIndx'} to @t{'fCnt'} 
when calling this method, so that all fields will be refreshed. The other 
is to call @ref{RefreshWin} instead. Either option will redraw the data for 
all fields, while @t{RefreshWin} will @emph{also} redraw any static text 
in the window.
@spi

@item @b{void RefreshField ( void );}

@verbatim
  Input  : none

  Returns: nothing
@end verbatim

Refresh (erase and redraw) the contents of the field which currently 
has input focus. 
@spi

@anchor{ClearField}
@cindex ClearField
@item @b{bool ClearField ( short f@t{I}ndx, bool delText = false, 
@ifnothtml
@*@verb{|                 |}
@end ifnothtml
acAttr txtAttr = acaUSEDFLT );}

@verbatim
  Input  : 
     fIndx   : index of target field
     delText : (optional, 'false' by default)
               if 'true',  delete the stored text of the field
               if 'false', stored text is not modified
     txtAttr : (optional, acaUSEDFLT by default)
              color attributes for the operation
              (logical OR of forground and background color)
              (attributes and text 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)
@end verbatim

Erase text from the specified text-field display. Optionally, the stored 
text is also deleted.

This operation applies @b{@emph{ONLY}} to fields with editable text, 
specifically, Textbox fields (field type: ftTB).
@spi

@anchor{ReformatFieldText}
@cindex ReformatFieldText
@item @b{bool ReformatFieldText ( short fIndx, FloType floType = floDflt );}
@verbatim
  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 the data. 
 
  Returns: 'true'  if operation is successful 
           'false' if a) invalid field index specified
                      b) target field is not a multi-row textbox
                         field (ftTB) 
@end verbatim

Reformat text of the target field using the specified formatting type. 
All existing newline characters are removed and the data are reformatted 
according to the specified formatting option.@*
@verb{| 1)|} Set new formatting option if specified.@* 
@verb{| 2)|} Remove existing formatting (newline characters).@*
@verb{| 3)|} Reformat the data.@*
@verb{| 4)|} Set IP and logical cursor to field origin (upper-left corner).@*
@verb{| 5)|} Refresh the display.
 
This operation applies ONLY to multi-row textbox fields (ftTB).@*
Note also that target field should not have the input focus when data 
are reformatted because it could easily confuse the poor user.

See also: @ref{SetFieldFlow} which sets the formatting option, and 
reformats the data @b{@emph{only}} if necessary to keep the text within 
the field boundaries. 
@spi

@anchor{ScrollFieldText}
@cindex ScrollFieldText
@item @b{bool ScrollFieldText ( short fIndx, short steps );}
@verbatim
  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
@end verbatim

Scroll upward or downward through multi-row text fields under program control.

This method applies only to multi-row fields Textbox (ftTB) and Scrollbox 
(ftSB), and is ignored for single-row fields and other field types.

@b{Examples:}@*
(note how the sign of the shift determines direction of scroll)@*
@verb{|steps ==   1  |} scroll up by one row (bring rows below into view)@*
@verb{|steps ==  -1  |} scroll down by one row(bring rows above into view)@*
@verb{|steps ==  hgt |} scroll upward by one page@*
@verb{|steps == -hgt |} scroll downward by one page@*
@verb{|steps ==   0  |} scroll to the first row of text@*
@verb{|steps ==  999 |} scroll to the last row of text. Note that any value@*
@verb{|              |} at or beyond the last text row will signal a move@*
@verb{|              |} to end-of-text.
@example
This @b{@emph{much-too-complex}} example demonstrates the concept:
// Create and open the window
ACWin* win = new ACWin ( ... );
 ...
win->OpenWindow ();
// Get a pointer to the live data
const skForm* skfp = win->GetForm ();
short trg = 4,   // target field
      txtHeight, // text dimensions
      txtWidth ;
win->ParagraphSize ( skfp->fld[trg].txt, txtHeight, txtWidth );
// Scroll downward by one row
win->ScrollFieldText ( trg, 1 );
// Scroll upward by one row
win->ScrollFieldText ( trg, -1 );
// Scroll downward by one page
win->ScrollFieldText ( trg, skfp->fld[trg].hgt );
// Scroll upward by on page
win->ScrollFieldText ( trg, -(skfp->fld[trg].hgt) );
// Scroll to end-of-text
win->ScrollFieldText ( trg, txtHeight );
// Scroll to top-of-text
win->ScrollFieldText ( trg, 0 );
@end example
@spi

@anchor{ShiftFieldText}
@cindex ShiftFieldText
@item @b{bool ShiftFieldText ( short fIndx, short steps );}
@verbatim
  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
@end verbatim

Perform a vertical block shift of Textbox data, either upward or downward.@*
This method applies @emph{only} to multi-row Textbox (ftTB) controls.

This is similar to the @ref{ScrollFieldText} method which steps the 
cursor through the rows of text data, @i{EXCEPT} that for @t{ShiftFieldText}, 
the cursor position remains constant (continues to reference the same character) 
unless the shift would place it outside of the visible space.

@i{@b{Technical Note:} The @LSQ{}steps@RSQ{} parameter is currently limited 
to a single-row shift: @t{-1 <= steps <= 1}. It would be possible to implement 
a multi-row shift; however, the usefulness of that enhancement is not 
currently apparent.}
@spi

@anchor{HilightFieldText}
@cindex HilightFieldText
@item @b{bool HilightFieldText ( short fIndx, bool set, int begin, int len, 
@ifnothtml
@*@verb{|                       |}
@end ifnothtml
acAttr txtmod = acaUSEDFLT, 
@ifnothtml
@*@verb{|                       |}
@end ifnothtml
bool center = false );}

@verbatim
  Input  :
     fIndx : index of target field
     set   : if 'true',  highlight the text segment
             if 'false', clear the highlight
     begin : index of first (leftmost) character to highlight
             (referenced only when 'set' != 'false')
     len   : number of characters in highlighted segment
             Note: If segment spans rows, be sure to include
                   the newlines in the count.
             (referenced only when 'set' != 'false')
     txtmod: (optional, default:acaUSEDFLT)
             text modifier attribute for highlighted text segment
             - If specified, text modifier attribute for highlighted
               text segment. One of the following:
                acaBOLD      bold-text modifier
                acaITALIC    italic-text modifier
                acaUNDERLINE underline-text modifier
                acaOVERLINE  overline-text modifier
                acaXOUT      x-out (strikethrough) text modifier
                acaBLINK     blinking-text modifier
                acaCONCEAL   concealed (invisible) text
                acaREVERSE   reversed fgnd/bkgnd (default attribute)
                Note: OR'd combinations of these modifiers are not allowed.
             - 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' references an upsupported control type
             b) parameter out-of-range
@end verbatim

For Textbox controls only (ftTB), highlight a segment of text using one of 
the text-modifier attributes.
If the target field is currently visible, the field will be refreshed 
before return.

Note that while any combination of the @b{@t{acAttr}} color attributes 
may be freely OR'd under most circumstances, for this method, exactly 
one text-modifier attribute may be specified as the highlight attribute.

@example
Example:
// For a field containg a list of animals, highlight 
// the word 'kangaroo' if found in the text:

const char* Kanga = "kangaroo" ;
const int   KangaLen = 8 ;
const acAttr txtMod = acaREVERSE ;
gString gsTxt ;
int hl_begin ;
win->GetFieldText ( ZOO_TBOX, gsTxt ) ; // get a copy of field text

// If the target word is present in the text, highlight it
// by specifying the index of the first character and the 
// number of characters to be highlighted.
if ( (hl_begin = gsTxt.find( Kanga )) >= ZERO )
@{
   win->HilightFieldText ( ZOO_ANIMALS, true, 
                           hl_begin, KangaLen, txtMod, true ) ;
@}
@end example

For a functional example, please execute the highlighting test:@*
@b{@verb{|   ./epts --test=Wh|}}
@spi

@H5heading{Technical Notes:,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
@enumerate a
@item Text highlighting uses the same algorithm as the text-selection 
(copy/cut/paste) functionality, and shares some data members with that 
function. For this reason, within a single Textbox field, @LDQ{}highlighted@RDQ{} 
text cannot be present simultaneously with @LDQ{}selected@RDQ{} text.
Highlighted data and selected data may be present simultaneously in 
@emph{different} Textbox fields. 

Calling this method will release any @LDQ{}selected@RDQ{} segment in 
the target field. If the user selects text using any of the selection keys:@*
@t{(Shift + Left/Right/Up/Down or ALT + A)}, it will release any 
highlight within the field.@*
Please @pxref{AnsiCmd Clipboard Access} for a discussion of text selection 
and moving text to and from the clipboard.

@item Note that if the highlighted segment is positioned outside the 
visible text area of the field, then by default (@b{@t{'center=true'}}), 
the text will be scrolled to bring the highlighted segment into view 
and will be (approximately) centered within the visible space.@*
If centering is not specified, no scrolling will occur, and the highlighted 
segment may or may not be visible.

@item The text-selection modifier is acaUNDERLINE, so this modifier is 
not recommended as a highlight modifier because it would tend to confuse 
the poor user.

@item Using the same text-modifier attribute in both the base color 
attribute for field text @emph{and} as highlight modifier will cause 
visual anomalies, so please choose a highlight attribute which will 
avoid this conflict. For instance, if the base attribute for the field is:@*
@verb{&   acAttr(acaFG_BLUE | acaBG_CYAN | acaITALIC) &}@*
then @t{acaITALIC} should not be used as the highlight attribute.

@item For dialog windows, please @pxref{Dialog_Hilite}.

@item Text hilighting is currently available only for Textbox (ftTB) controls; 
however, support for highlighted text within Scrollbox (ftSB) controls may be 
added in a future release.
@end enumerate
@spi


@anchor{SetHilightMod}
@cindex SetHilightMod
@item @b{bool SetHilightMod ( short fIndx, acAttr txtmod );}

@verbatim
  Input  : 
     fIndx : index of target field
     txtmod: text modifier attribute for highlighting text segments

  Returns:
     'true'  if highlight attribute initialized
     'false' a) 'fIndx' references an upsupported control type
             b) parameter out-of-range (default parameter set)
@end verbatim

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 @ref{HilightFieldText} method, above for additional 
information.@*
See also the @t{skField} @ref{setHiliteMod} method.
@spi


@c Currently unused
@ignore
@anchor{GetCursorPos (field)}
@cindex GetCursorPos(field)
@item @b{WinPos GetCursorPos ( short fld@t{I}ndx );}

@verbatim
  Input  : fldIndx : index of target field

  Returns: current cursor position (field offset)
@end verbatim

Get the current cursor offset within the specified field.
@spi
@end ignore
@c Currently unused
@end itemize
@hr90w

@c - - - Section - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@anchor{Dialog-Oriented Methods}
@section Dialog-Oriented Methods

A dialog is a small window within the parent window which provides 
information to the user, and optionally asks for a decision or gathers 
other information from the user. 
@ifnothtml
@*
@end ifnothtml
Please @pxref{Dialog sub-Windows} for a more detailed discussion of 
Dialog window functionality.
@sp 1

@anchor{QuickDialog}
@cindex QuickDialog
@itemize @BSQUARE
@ifnothtml
@item @b{bool QuickDialog ( const gString& gsMsg, bool query, @*
@verb{|                   |}const char* title = NULL, @*
@verb{|                   |}short height = 0, short width = 0, @*
@verb{|                   |}short vOff = 0, short hOff = -1, @*
@verb{|                   |}short timeout = 0, bool dbg = false );}
@end ifnothtml
@ifhtml
@item @b{bool QuickDialog ( const gString& gsMsg, bool query, const char* title = NULL, @*
@verb{|                |}short height = 0, short width = 0, short vOff = 0, short hOff = -1, @*
@verb{|                |}short timeout = 0, bool dbg = false );}
@end ifhtml

@verbatim
  Input  : 
      gsMsg : (by reference) contains the message(s) to be displayed.
              The text may be a formatted paragraph with each text 
              row terminated by a newline character (\n), OR may be 
              unformatted text which will be automatically formatted 
              to fit within the dimensions as specified below.
      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 in the 'gsMsg' parameter
      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 
              in the 'gsMsg' parameter
      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'.
@end verbatim

Generate a @LDQ{}quick@RDQ{} dialog window within the application's 
ACWin-class window.

QuickDialog invocations are the simpler of the two dialog types, requiring fewer 
configuration parameters. 
@ifhtml
@*
@end ifhtml
QuickDialogs are generated in either of two modes 
(see @t{'query'} parameter).
@format
  1) information mode
     An information dialog displays a message and has one pushbutton 
     control. The user selects that control to close the dialog and 
     return execution to the parent window.
  2) decision mode
     A decision dialog displays a question, and has two pushbutton 
     controls which allows the user to make a binary choice:
     (yes/no , save/discard , continue/abort , etc.).
@end format

Working examples of the quick dialog may be found in the AnsiCmd test suite.@* 
Invoke the EarthPoints test application with:@*
@b{@verb{|  ./epts --test=Dq|}}@*
for a list of quick-dialog tests.

For a fully-configurable dialog, see the Dialog method below, which 
accepts customized values for all configuration parameters.
@spi

@anchor{Dialog}
@cindex Dialog method
@ifnothtml
@item @b{bool Dialog ( short dlgHgt, short dlgWid, skForm* formDef, @*
@verb{|             |} const char* sTxt = NULL, const char* tTxt = NULL, @*
@verb{|             |} short vOff = -1, short hOff = -1, @*
@verb{|             |} LineType ltype = ltSINGLE, @*
@verb{|             |} acAttr bdrAttr = acaUSEDFLT, @*
@verb{|             |} acAttr txtAttr = acaUSEDFLT, @*
@verb{|             |} short tvOff = 0, short thOff = 1, @*
@verb{|             |} bool dbg = false );}
@end ifnothtml
@ifhtml
@item @b{bool Dialog ( short dlgHgt, short dlgWid, skForm* formDef, @*
@verb{|          |} const char* sTxt = NULL, const char* tTxt = NULL, @*
@verb{|          |} short vOff = -1, short hOff = -1, LineType ltype = ltSINGLE, @*
@verb{|          |} acAttr bdrAttr = acaUSEDFLT, acAttr txtAttr = acaUSEDFLT, @*
@verb{|          |} short tvOff = 0, short thOff = 1, bool dbg = false );}
@end ifhtml

@verbatim
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 the 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 interior) 
   thOff : static text position. horizontal offset 
           (optional, default: 1, inset one column from left edge of dialog)
   callbk: (optional, default: null pointer) pointer to a non-member callback 
           function. (See typedef CUPTR for details.)
           If specified, this function will be called by the EditDialog method
           each time the user presses a key.
   dbg   : (optional, false by default) for debugging only: 
           if reset, refresh the parent window on return 
           if set,   dialog remains visible for analysis
 
Returns:
   index of control with focus when dialog is closed 
   (this is the same value contained in formDef->fi) 

   The structure referenced by 'formDef' may have been updated 
   to contain additional information: 
     a) Text controls (ftTB): The text of the field may have been 
         modified by user.  The data may be retrieved directly from
         the skField object.
     b) Radiobutton controls (ftRB): The 'set' flag which indicates 
        the binary state of the control (set or reset) may have changed.
        This flag may be read directly from the skField object.
     c) Context Menu controls (ftMB): If a menu item has been selected, 
        a call to the skField-class getItem() method will return the item.
     d) Scrollbox controls (ftSB): If a scrollbox item has been selected, 
        a call to the skField-class getItem() method will return the item.

   If the formDef object as received has been malformed, certain 
   parameters will have been corrected if possible; or if corrections 
   are not possible: 
     a) formDef will be ignored, 
     b) a warning will be displayed, and 
     c) a minus one (-1) will be returned. 
@end verbatim

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. (see notes below) 
 
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. 

Working examples of the full-initialization dialog may be found in the 
AnsiCmd test suite.@* 
Invoke the EarthPoints test application with:@*
@b{@verb{|  ./epts --test=Dd|}}@*
for a list of dialog tests.

Please @pxref{Dialog sub-Windows} for a more detailed discussion of 
Dialog window functionality.
@end itemize
@hr40
@spi

@indentedblock
@ifnothtml
@example
┌─────────────────────────────────────────────────────────────┐
│ The following group of methods is intended specifically     │
│ for use by callback functions, and are active only when a   │
│ dialog window is currently open.                            │
│ The methods of this group are used to access the dialog's   │
│ internal data structures in response to user input.         │
│ Please @pxref{Dialog Callback} for additional information.  │
└─────────────────────────────────────────────────────────────┘
@end example
@end ifnothtml
@ifhtml
@CartHtml{@embedTOKEN{ai}
The following group of methods is intended specifically for use by callback 
functions, and are active only when a dialog window is currently open.
The methods of this group are used to access the dialog's internal data 
structures in response to user input.
Please @pxref{Dialog Callback} for additional information.}
@end ifhtml
@end indentedblock

@anchor{Dialog_GetText}
@cindex Dialog_GetText
@itemize @BSQUARE
@item @b{bool Dialog_GetText ( short ctrlIndx, gString& txtData );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     txtData  : (by reference) receives a copy of the Textbox text

  Returns:
     'true' if a dialog is currently under edit, AND
            if 'ctrlIndx' refrences a control of the correct type
            for the operation
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For Textbox controls (ftTB) within a dialog, retrieve a copy of 
current text data.
@spi

@anchor{Dialog_SetText}
@cindex Dialog_SetText
@item @b{bool Dialog_SetText ( short ctrlIndx, const gString& txtData, @*
@verb{|                      |}acAttr color = acaUSEDFLT, bool refresh = true );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     txtData  : (by reference) text which will replace the current text
     color    : (optional, default: acaUSEDFLT)
                if specified this is the new color attribute for the
                control, else control attribute is unchanged
     refresh  : (optional, default: true)
                if 'true',  refresh the display after update
                if 'false', display is not refreshed

  Returns:
     'true' if a dialog is currently under edit, AND
            if 'ctrlIndx' refrences a control of the correct type
            for the operation
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For Textbox (ftTB) and Scrollbox (ftSB) controls only, replace existing 
display text for the control.@*
Optionally, set new base color attribute for the control.

The display is updated by default, but update can be delayed by resetting 
the @t{'refresh'} parameter.
@spi

@anchor{Dialog_SetAttr}
@cindex Dialog_SetAttr
@item @b{bool Dialog_SetAttr ( short ctrlIndx, const acAttr* acaArray, @*
@verb{|                      |}short acaCnt, bool refresh = true );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     acaArray : pointer to an array of acAttr color attributes, one
                attribute for each text row of the control.
     acaCnt   : number of attribute values in the 'rowAttr' array (>zero)
                The minimum _practical_ value is two(2).
     refresh  : (optional, default: true)
                if 'true',  refresh the display after update
                if 'false', display is not refreshed

  Returns:
     'true' if a dialog is currently under edit, AND
            if 'ctrlIndx' refrences a control of the correct type
            for the operation
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

Specify an array of color attributes, one for each item (row) displayed 
in the control. Only certain control types accept multi-color attributes:@*
@ @ @ Scrollbox controls (ftSB)@*
@ @ @ Multi-row Menus (ftMB)@*
Please @pxref{colorConfig} and @ref{skField config example} for details 
on constructing an array of color attributes for use within the target control.

The display is updated by default, but update can be delayed by resetting 
the @t{'refresh'} parameter.
@spi

@anchor{Dialog_GetItem}
@cindex Dialog_GetItem
@item @b{bool Dialog_GetItem ( short ctrlIndx, gString& itemText, @*
@verb{|                      |}short& itemNum, bool select = true );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     itemText : (by reference) receives text of the highlighted line item
     itemNum  : (by reference) receives the (0-based) item number (index)
                of the highlighted item
     select   : (optional, default: true)
                if 'true'  return the user 'selected' item (if any)
                           else, return highlighted item
                if 'false' return the highlighted item
     clear    : (optional, default: false)
                if 'true'  clear (reset) any current "selection" and
                           refresh the control to erase the selection
                           indicator.
                if 'false' selection is not modified

  Returns:
     'true' if a dialog is currently under edit, AND
            if 'ctrlIndx' refrences a control of the correct type
            for the operation
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For Menus and Scrollbox controls within a dialog, return the data for the 
highlighted @LDQ{}item@RDQ{}. 

@enumerate 1
@item An @b{@t{"item"}} is the data for a display row within the control. 
Generally, this is the highlighted item i.e. the text under the cursor.@*
Exception: If the user has @LDQ{}selected@RDQ{} a menu item via the 
@t{Enter or Space} keys, then the @LDQ{}selected@RDQ{} item, rather 
than the highlighted item will be returned.

@item The @b{@t{"item number"}} is the index of the of the row containing 
the item.
@enumerate a
@item The optional @t{'select'} parameter specifies whether the 
@LDQ{}selected@RDQ{} item (if any) should be returned or if the highlighted 
item should always be the returned item.@*
A "selected" item is an item for which the user has highlighted an item 
and then pressed the Enter or Space key.
@end enumerate

@item The @b{@t{"item text"}} is the text displayed on that row.@*
@enumerate a
@item For Menu controls, this is the display text @emph{excluding} the 
border characters. Any newline character and leading/trailing whitespace 
will also be removed.@*
@verb{|Example: "│Clear Bookmarks  │\n" becomes|}@*
@verb{|         "Clear Bookmarks"|}@*
If the menu item includes a @LDQ{}hotkey@RDQ{} indicator (caret @t{'^'}), 
then the menu text will include the caret:@*
@verb{|         "Clear ^Bookmarks"|}.

@item For Scrollbox controls, this is the display text @emph{excluding} 
the newline character and any leading/trailing whitespace.@*
@verb{|Example: " The cow in the meadow goes moo.     \n" becomes|}@*
@verb{|         "The cow in the meadow goes moo."|}
@end enumerate

@H6heading{Clear Parameter,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
If the @t{'clear'} parameter is set, then before return, the current item 
selection (if any) will be cleared and the associated selection indicator, 
if visible will be removed.@*
This is useful if the item selection has already been handled or if item 
selection is unneeded.@*
Note that there is a potential timing issue for clearing the 'sitem' 
selection member. If this method is called from within a callback in 
response to selection keystroke (Enter/Space), then the actual selection 
has not yet occurred. In this case, the callback would need to signal that 
the selection keycode has been handled. To do this, the callback would 
return an alternate keycode instead of the Enter/Space. Suggestions: 
return NULLCHAR to indicate that the keycode has been handled, or return 
wcsTAB to move the input focus to the next field.@*
Please @pxref{Dialog Callback} for more information on callback functions.

Please refer to the @ref{getItem} method in the chapter on skField 
Public Methods for a technical description of @t{'items'} and item selection.
@end enumerate
@spi

@anchor{Dialog_SetItem}
@cindex Dialog_GetItem
@item @b{bool Dialog_SetItem ( short ctrlIndx, short itemNum, 
@ifnothtml
@*@verb{|                     |}
@end ifnothtml
bool refresh = true );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     itemNum  : index (0-based) of the item to be set as selected
                Note: If valueos out-of-range, then nearest _valid_
                      item will be selected.
     refresh  : (optional, default: true)
                if 'true'  refresh the display
                if 'false' display is not updated

  Returns:
     'true' if: a) a dialog is currently under edit,
                b) 'ctrlIndx' refrences a control of the correct type
                   for the operation
                c) the target control _does not_ have input focus
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For Menus and Scrollbox controls within a dialog: set the @t{"@b{selected item}"}
explicitly. This will draw user's attention to the item and indicate the 
current selection. Note that items are zero-based; that is, the first item 
is item zero(0).

The target control must not have input focus when this method is called.
@spi

@ifnothtml
@verbatim
 ----------------Scrollbox-----------------     Context Menu
┌──────────────────────────────────────────┐   ╔════════════╗
│ There once was a man from Kirkuk,        │   ║Pigs Grunt  ║
│▷Who was known far and wide for his luck, │━┳━║Birds Fly   ║
│ Till while jogging one day,              │ ┃ ║Cows Moo    ║
└──────────────────────────────────────────┘ ┃ ║Goats Bleat ║
                                             ┃ ╚════════════╝
        Item #1 is "selected":  ━━━━━━━━━━━━━┛
@end verbatim
@end ifnothtml
@ifhtml
@html
<div class="tscap" style="text-color:000000; background-color:#99FFFF; max-width:38.60em; line-height:1.165em;">                  Scrollbox                      Context Menu
 <span class="brgy">┌──────────────────────────────────────────┐</span>   <span class="brgy">╔═════════════╗</span>
 <span class="brgy">│<span class="cy_n"> There once was a man from Kirkuk,        </span>│</span>   <span class="brgy">║</span><span style="background-color:#3399FF;"> Pigs Grunt  </span><span class="brgy">║</span>
 <span class="brgy">│<span class="bw_n">▷</span><span class="cy_n">Who was known far and wide for his luck, </span>│</span>━┳━<span class="brgy">║</span><span style="background-color:#3399FF; font-weight:bold; font-style:italic;"> Birds Fly   </span><span class="brgy">║</span>
 <span class="brgy">│<span class="cy_n"> Till while jogging one day,              </span>│</span> ┃ <span class="brgy">║</span><span style="background-color:#3399FF;"> Cows Moo    </span><span class="brgy">║</span>
 <span class="brgy">└──────────────────────────────────────────┘</span> ┃ <span class="brgy">║</span><span style="background-color:#3399FF;"> Goats Bleat </span><span class="brgy">║</span>
                                              ┃ </span><span class="brgy">╚═════════════╝</span>
         <span style="font-weight:bolder;">Item #1 is "selected":</span>  ━━━━━━━━━━━━━┛
</div>
@end html
@end ifhtml

Within Scrollbox controls, the @LDQ{}selected@RDQ{} item is indicated by an 
arrow at the left edge of the text; while for Menus, the @LDQ{}selected@RDQ{} 
item is displayed in bold/italic font.

If successful, control is refreshed to visually indicate the selected item.

@ifnothtml
Note that the Menu selection indicator is not visible in@*
the 'info' docs. See the HTML docs for a better representation.
@end ifnothtml

@spi

@anchor{Dialog_GetState}
@cindex Dialog_GetState
@item @b{bool Dialog_GetState ( short ctrlIndx, bool& rbState );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     rbState  : (by reference) receives the current state of the control

  Returns:
     'true' if a dialog is currently under edit, AND
            if 'ctrlIndx' refrences a control of the correct type
            for the operation
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For binary-state controls within a dialog, return the current 'state' 
flag value: @t{'set'} or @t{'reset'}.@*
Currently, the binary state flag applies only to Radiobutton controls.
@spi

@anchor{Dialog_GetStateXOR}
@cindex Dialog_GetStateXOR
@item @b{bool Dialog_GetStateXOR ( short ctrlIndx, short& rbIndx );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     rbIndx   : (by reference) receives index of XOR group member
                whose state flag is currently set

  Returns:
     'true' if a dialog is currently under edit, AND
            if 'ctrlIndx' refrences a control of the correct type
               for the operation, AND
            if the target control is a member of an XOR group
               then 'rbIndx' receives the target index
     else 'false' ('rbIndx' receives 'fCnt')
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For binary-state controls within a dialog which are configured as XOR group 
members, return the index of the control within the group whose binary state 
is 'set'.@*
If the target is not a member of an XOR group, then the 
@ifnothtml
@*
@end ifnothtml
@ref{Dialog_GetState} method should be called instead.

Currently, the binary state flag applies only to Radiobutton controls.
@spi

@anchor{Dialog_GetField}
@cindex Dialog_GetField
@item @b{bool Dialog_GetField ( short ctrlIndx, const skField*& skfPtr );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     skfPtr   : (by reference) receives a pointer to _constant_ skField
                object. Access to all public data members is available.
                Access to 'const' methods (if any) is also available.

  Returns:
     'true'  if a dialog is currently under edit, AND
             if 'ctrlIndx' refrences a control of the correct type
             for the operation
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For controls within a dialog, return a pointer to the specified control 
object. This is a const pointer, meaning that the public data may be 
analyzed, but no data within the object may be modified.

The example below retrieves the dimensions of the control and formats 
a paragraph of text according to the dimensions. The new text is then 
written to the target control.
@verbatim
   gString gs( "Four score and seven years ago"
               "...shall not perish from the earth." ) ;
   const skField* skfPtr = NULL ;
   if ( (this->win->Dialog_GetField ( fldTXTBOX, skfPtr )) )
   {
      short fldHeight = skfPtr->hgt ;
            fldWidth  = skfPtr->wid ;
      this->win->FormatParagraph ( gs, fldHeight, fldWidth,
                                   false, false ) ;
      this->Dialog_SetText ( fldTXTBOX, gs,
                             acAttr(acaFG_BLUE | acaBGb_RED) ) ;
   }
@end verbatim
@spi

@anchor{Dialog_Hilite}
@cindex Dialog_Hilite
@item @b{Dialog_Hilite ( short ctrlIndx, bool set, int begin, int len, 
@ifnothtml
@*@verb{|               |}
@end ifnothtml
acAttr txtmod = acaREVERSE );}

@verbatim
  Input  :
     ctrlIndx : index of target field
     set   : if 'true',  highlight the text segment
             if 'false', clear the highlight
     begin : index of first (leftmost) character to highlight
             (referenced only when 'set' != 'false')
     len   : number of characters in highlighted segment
             Note: If segment spans rows, be sure to include
                   the newlines in the count.
             (referenced only when 'set' != 'false')
     txtmod: (optional, default:acaUSEDFLT)
             text modifier attribute for highlighted text segment
             - If specified, text modifier attribute for highlighted
               text segment. One of the following:
                acaBOLD      bold-text modifier
                acaITALIC    italic-text modifier
                acaUNDERLINE underline-text modifier
                acaOVERLINE  overline-text modifier
                acaXOUT      x-out (strikethrough) text modifier
                acaBLINK     blinking-text modifier
                acaCONCEAL   concealed (invisible) text
                acaREVERSE   reversed fgnd/bkgnd (default)
                Note: OR'd combinations of these modifiers are not allowed.
             - 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' references an upsupported control type
             b) parameter out-of-range
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For Textbox controls only (ftTB), highlight a segment of text using one of 
the text-modifier attributes.
If the target field is currently visible, the field will be refreshed 
before return.

Note that while any combination of the @b{@t{acAttr}} color attributes 
may be freely OR'd under most circumstances, for this method, exactly 
one text-modifier attribute may be specified as the highlight attribute.

Please @pxref{HilightFieldText} for a techninal description of this 
functionality.
@spi

@anchor{Dialog_SetFocus}
@cindex Dialog_SetFocus
@item @b{bool Dialog_SetFocus ( short ctrlIndx );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog

  Returns: 
     'true' if a dialog is currently under edit, AND if 'ctrlIndx'
           refrences a control of the correct type for the operation
           AND if the target control is not set as read-only
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For controls within a dialog, set the input focus to the specified control.
@spi

@anchor{Dialog_SetReadOnly}
@cindex Dialog_SetReadOnly
@item @b{bool Dialog_SetReadOnly ( short ctrlIndx, bool read_only );}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     read_only: if 'true',  set field as read-only
                            (cannot receive input focus)
                if 'false', reset the read-only flag
                            (can receive input focus)

  Returns: 
     'true' if a dialog is currently under edit, AND if 'ctrlIndx'
           refrences a control of the correct type for the operation
           AND if the target control does not currently have input focus
     else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For controls within a dialog, set or reset the read-only flag.@*
If the read-only flag is set, then control cannot receive the input focus.
@spi

@anchor{Dialog_Scroll}
@cindex Dialog_Scroll
@item @b{bool Dialog_Scroll ( short ctrlIndx, int& steps, 
@ifnothtml
@*@verb{|                    |}
@end ifnothtml
bool head = false, bool tail = false);}

@verbatim
  Input  :
     ctrlIndx : index of target control within the dialog
     steps    : (by reference) number of steps to scroll
                This value is ignored if 'head' or 'tail' flag is set.
                  scroll == 0, no scrolling will occur, but on return,
                               value will be _current_ item/IP.
                  scroll >  0, scroll forward toward tail of data
                  scroll <  0, scroll backward toward head of data
     head     : (optional, default: false) if specified, move to head
                of data (overrides value in 'steps')
     tail     : (optional, default: false) if specified, move to tail
                of data (overrides value in 'steps')

  Returns: 
     'true' if a dialog is currently under edit, AND if 'ctrlIndx'
           refrences a control of the correct type for the operation
            -- On return, 'steps' will contain the currently referenced
               item number, or for Textbox controls, the IP.

     else 'false' ('steps' is not modified)
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

For controls with a visible cursor position: Textbox (ftTB), 
Scrollbox (ftSB) or Context Menus (ftMB) only.
@enumerate 1
@item Textbox Controls:
Scroll horizontally, right or left, one character per step.
@item Scrollbox Controls:@*
Scroll vertically, up or down, one line item per step.
@item Menu Controls:@*
Scroll vertically, up or down, one item per step. Wrap-around will not occur. 
Note that only "context" menus (multi-row, stand-alone menus) are supported 
by this method.
@end enumerate

Scrolling is managed by the control's @t{'ip'} (Insertion Point) member.
Position of the highlight (Menus or Scrollbox controls) or visible cursor 
(Textbox controls) is calculated based on the value of @t{'ip'}.@*
The @t{'steps'} value is range checked to prevent the insertion point 
from overruning the data.

The @t{'head'} and @t{'tail'} flags override the value in @t{'steps'}, 
and the @t{'head'} flag overrides the @t{'tail'} flag.

Special case: If both @t{'head'} and @t{'tail'} are reset and if @t{'steps'} 
is set to zero, then the current position is reported, but not modified.
@spi

@anchor{Dialog_Write}
@cindex Dialog_Write
@item @b{bool Dialog_Write ( const wchar_t* txt, short yOff, short xOff, @*
@verb{|                    |}bool clear = false, acAttr color = acaUSEDFLT );}
@item @b{bool Dialog_Write ( const char*    txt, short yOff, short xOff, @*
@verb{|                    |}bool clear = false, acAttr color = acaUSEDFLT );}

@verbatim
  Input  :
     txt    : text to be written to dialog interior.
              Either: wchar_t* or char*
     yOff   : position: offset in rows from top of dialog interior
              with zero(0) being the top row.
     xOff   : position: offset in columns from left edge of dialog
              Note that all dialog text is automatically indented by
              one column from both the left and right borders, so an
              xOff value of zero will display text starting in column 1.
     clear  : (optional, default: false) clear the target row before
              writing the data.
     color  : (optional, default: acaUSEDFLT)
              if specified this is the color attribute used to write
              the text. Otherwise, text will be written using the
              dialog's interior attribute.

  Returns: 'true' if a dialog is currently under edit
            else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

Write one line of text to the interior of the dialog.
@enumerate a
@item Text will be truncated if necessary to fit within the available space.
@item Static text may not occupy the same space as a control object.
If it does, it will be invisible.
@item Note that the text is written directly to the display.@*
Neither the text nor the color attribute are stored.
@item @b{@emph{CAUTION!}} - Do not overwrite control objects within the 
dialog!@*
Although the text data are truncated if necessary to prevent incursion into 
the dialog border, at this time, programatic testing for overwrite of 
control objects is considered too expensive an operation.

If you are uncertain about positioning of static text data within 
the dialog, it is recommended that a read-only Textbox control be 
defined for display of transitory messages.
@end enumerate
@spi

@anchor{Dialog_Refresh}
@cindex Dialog_Refresh
@item @b{bool Dialog_Refresh ( bool full = false );}@*

@verbatim
  Input  : full : (optional, default: false)
                  if 'false' redraw the interior of the dialog only
                             this includes the static text data and
                             all controls
                  if 'true', redraw the dialog border, then redraw
                             the dialog interior

  Returns: 'true' if a dialog is currently under edit
            else 'false'
@end verbatim

@i{@b{Note:} This method is active @b{@emph{only}} when a dialog (ACDlg object) is open;@*
and @b{@emph{only}} if a callback method was specified when dialog was created.}

Refresh (redraw) the dialog. This method may be called from within the 
application-level callback to restore the display in case the dialog has 
been obscured by another operation.

If the parent window has also been obscured by the operation, 
@b{@emph{refresh the parent window first}}, then refresh the dialog window.
@end itemize
@hr90w

@c - - - Section - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section Utility Methods

@anchor{FormatParagraph}
@cindex FormatParagraph
@itemize @BSQUARE
@item @b{short FormatParagraph ( gString& gsTxt, short maxRows, short maxCols, }
@*
@ifnothtml
@verb{|                       |}
@end ifnothtml
@ifhtml
@verb{|                    |}
@end ifhtml
@b{bool trunc = true, bool hypenbrk = false, }
@ifnothtml
@*@verb{|                       |}
@end ifnothtml
@b{short *truncIndex = NULL );}

This is a pass-through to the @ref{acFormatParagraph} method.
@spi

@anchor{ParagraphSize}
@cindex ParagraphSize
@item @b{void ParagraphSize ( const gString& gs, short& msgHeight, short& msgWidth );}
@item @b{void ParagraphSize ( const gString& gs, int& msgHeight, int& msgWidth );}

@verbatim
  Input  :
     gs        : (by reference) text to be analyzed
     msgHeight : (by reference) receives number of text rows
     msgWidth  : (by reference) receives number of text columns

  Returns: nothing
@end verbatim

Calculate the dimensions (height and width) of the specified block of text.

This method can be used to measure the height in rows and width in columns 
for a paragraph of text data. This is useful for determining how the text 
will fit within the window, or the dimensions required for a field in 
which to display the text. 
Note that the number of text rows is determined by the number of newline 
characters (@t{'\n'}) found (excluding trailing newline, if any).@*
Dimensions are calculated as shown in the following example.

@verbatim
  ACWin *win( . . . ) ;
  short txtRows, txtCols ;

  gString gsText = 
    "There once was a man from Kirkuk, \n"
    "Who was known far and wide for his luck, \n"
    "Till while jogging one day, \n"
    "he looked the wrong way, \n"
    "Whereupon he was hit by a truck." ;

  win->ParagraphSize ( gsText, txtRows, txtCols ) ;
  gString bsOut( "\n\"Text Dimensions are %hd rows by %hd columns.\"\n",
                 &txtRows, &txtCols ) ;
  win->ttyWrite ( bsOut ) ;

  Yields:
    "Text Dimensions are 5 rows by 41 columns."
@end verbatim

@smalldisplay
@b{Programmer's Note:} This method is overloaded for pointers to int32_t. 
The author has found that it is too easy to get confused between 32-bit 
text indices and 16-bit window coordinates.
@end smalldisplay
@spi

@anchor{isPrint}
@cindex isPrint
@cindex Unicode codepoint
@cindex codepoint, Unicode
@item @b{bool isPrint ( wchar_t wkey );}

@verbatim
  Input  : keycode to be tested

  Returns: true if a "graphing" character, else 'false'
@end verbatim

A locale-aware version of the @t{'std::isprint'} function.

The locale-aware version of 'isprint' takes into account all graphing 
characters of all languages supported by the Unicode standard. This means 
that whatever input language is being used for the application, all 
codepoints of that language will be handled as expected.

@H5heading{Whitespace Keycodes:,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
Canon says that the Space @t{' '}, Enter @t{'\n'}, Tab @t{'\t'} and similar
codepoints are classed as whitespace rather than graphing characters; however, 
canon is wrong on this issue.@*
This method recognizes these as graphing characters simply because when 
written, they cause updates to the display.

@H5heading{Keycodes reserved by the AnsiCmd library:,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
A small range of Unicode codepoints is reserved by the library for assignment 
to decoded ANSI escape sequence, control codes, @LDQ{}conditioned@RDQ{} keys 
and ALT-key combinations.@*
These reserved keycodes consist primarily of arrows, geometric shapes, 
and typographic symbols. These keycodes are not integral to any written 
language, and should seldom, if ever be needed in daily user interactions.

The range of keycodes in this group are technically graphing characters 
but have been reassigned by the AnsiCmd library, and will not be reported 
as graphing characters by this method. Most of these are assigned to:@*
@verb{|   1) wcsALT_A - wcsALT_RB|}@*
@verb{|   2) wcsCTL_A - wcsCTL_7|}@*
@verb{|   3) wcsF01   - wcsCF12|}@*
@verb{|   4) various "conditioned" keys, cursor-movement keys, etc.|}@*
The exclusion range is defined by the constants RESKEY_MIN and RESKEY_MAX 
which correspond to keycode assignments wcsF01 and wcsALT_RB, respectively. 
Note that not all keycodes within this range are currently assigned. 
Some are reserved for future development.

Line-drawing characters, bullet characters and similar keycodes defined by 
the AnsiCmd library fall outside the reserved range, and therefore 
@emph{ARE} reported as graphing characters.

If any codepoints within the reserved range needs to be displayed within a 
specific project, this should not be a problem so long as the AnsiCmd 
user-interface methods do not see them and try to @LDQ{}@i{interpret}@RDQ{} them.

It may be educational to study the full Unicode character table which 
can be found at: @b{@t{https://www.utf8-chartable.de/}}
@spi

@anchor{EnableFootnotes}
@cindex EnableFootnotes
@item @b{bool EnableFootnotes ( bool enable );}

@verbatim
  Input  : enable: set   : enable output from the Footnote method.
                   reset : disable output from Footnote method.

  Returns: current state of the footnote flag
@end verbatim

Enable or disable output to the window written through the 'Footnote' 
group of methods described below.
@spi

@anchor{Footnote}
@cindex Footnote
@item @b{void Footnote ( const gString& msg, short pause, 
@ifnothtml
@*@verb{|               |}
@end ifnothtml
acAttr color = acaUSEDFLT, bool center = false );}
@item @b{void Footnote ( const wchar_t* msg, short pause, 
@ifnothtml
@*@verb{|               |}
@end ifnothtml
acAttr color = acaUSEDFLT, bool center = false );}
@item @b{void Footnote ( const char*    msg, short pause, 
@ifnothtml
@*@verb{|               |}
@end ifnothtml
acAttr color = acaUSEDFLT, bool center = false );}

@verbatim
  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 erasing message
             a value of zero(0) indicates that message is to
             remain visible on return.
     color : (optional, existing border attributes by default)
             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
@end verbatim

Write a message in the lower border of the window. This could be a message 
to the user, or could be a temporary diagnostic message used during development.
Optionally, wait, a moment, then erase the message, (see @t{'pause'} argument).

For best visual presentation, the first and last characters of the message 
should be spaces, but this is not enforced.

Pleasse refer to the @t{Test_SoftEcho} method or refer to the example 
output in the diagram below.
@spi

@anchor{Sidebar}
@cindex Sidebar
@item @b{void Sidebar ( const gString& msg, bool left, acAttr color = acaUSEDFLT, 
@ifnothtml
@*@verb{|              |}
@end ifnothtml
short offset = ZERO, bool clear = false ) ;}
@item @b{void Sidebar ( const wchar_t* msg, bool left, acAttr color = acaUSEDFLT, 
@ifnothtml
@*@verb{|              |}
@end ifnothtml
short offset = ZERO, bool clear = false );}
@item @b{void Sidebar ( const char* msg, bool left, acAttr color = acaUSEDFLT, 
@ifnothtml
@*@verb{|              |}
@end ifnothtml
short offset = ZERO, bool clear = false );}

@verbatim
  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 edge border
             if 'false', message is displayed in right edge border
     color : (optional, existing border attributes 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 the new message
             if 'false', existing messages are unaffected
                         (unless the new message overwrites an old one)

  Returns: nothing
@end verbatim

Display a message in the left or right border of the window.@*
The Sidebar may have no practical value, but it's fun. :-)

@verbatim
    ┌────────┤  Title  ├──────────┐
    ┴                             │
    H                             │
    i                             ┴
    ┬                             M
    │                             o
    │                             m
    │                             !
    │                             ┬
    │                             │
    │                             │
    └─────┤ Smelly Footnote ├─────┘

  ACWin *win = new ACWin ( ... ) ;
  win->SetTitle ( "  Title  " ) ;
  win->Sidebar ( "Hi", true, acaATTR_DFLT, -2) ;
  win->Footnote ( " Smelly Footnote ", 0, acaATTR_DFLT, false ) ;
  win->Sidebar ( "Mom!", false, acAttr(acaFG_GREEN | acaBG_BLUE), 0) ;
@end verbatim
@b{NOTE:} A live test is under conditional compile in the Test_Dialog method.

@smallformat
@i{@b{Technical note on original cursor position.}
Ideally, the cursor position on exit should be the position on 
entry; however, saving the original position via a call to 
acGetCursor() is functional, but UNBEARABLY slow (> 0.5 seconds).
Instead, before return, the field with focus is refreshed, 
positioning the cursor in that field. There is no guarantee that 
is where the cursor originally was; therefore, it is recommended 
that caller consider explicitly setting cursor position on return.}
@end smallformat
@spi

@anchor{DrawBox}
@cindex DrawBox
@item @b{bool DrawBox ( WinPos wpOrig, short height, short width,}
@ifnothtml
@*@verb{|              |}
@end ifnothtml
@b{LineType lType, acAttr bxAttr, bool clear );}

@verbatim
  Input  : pos   : offset from upper-left corner of text area 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 the color attributes used.
                   If not specified, stored text attributes are used.
           clear : (optional, 'false' by default)
                   if 'false', interior of box is cleared using 'bxAttr'
                   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
@end verbatim

Draw a rectangle within the window's text area.

The position, dimensions, line style and color attributes may be specified. 
See the example below.

Note that the minimum dimensions for the rectangle are two rows by two 
columns (2x2). At the minimum dimension, of course there is no space for 
text within the box.
@spi

@anchor{DrawLine}
@cindex DrawLine
@item @b{WinPos DrawLine ( const WinPos& wpOrig, short length, bool vertical, }
@ifnothtml
@*@verb{|                 |}
@end ifnothtml
@b{LineType lType, }
@ifhtml
@*@verb{|               |}
@end ifhtml
@b{wchar_t begChar, wchar_t endChar, }
@ifnothtml
@*@verb{|                 |}
@end ifnothtml
@b{acAttr lnAttr );}

@verbatim
  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: either 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, these are the color attributes used.
                     If not specified, stored text attributes are used.

  Returns: cursor position at the end of the line:
           For horizontal lines, the column following the last character
           (limited at right edge of window)
           For vertical lines, the column below the last character
           (limited at bottom edge of window)
@end verbatim

Draw a horizontal or vertical line within the window's text area.@*
@EMDASH Horizontal lines are drawn left-to-right.@*
@EMDASH Vertical lines are drawn top-to-bottom.

This is a specialized instance of the AnsiCmd acDrawLine() method.
The only difference is that the parameters are range checked to fit entirely 
within the window.
Note that if an endpoint of the line intersects the border of the window, 
the endpoint will be drawn using the color attributes of the border, while 
the portion of the line within the text area of the window will be drawn 
using the color attributes of the window interior, or the attributes specified 
by the optional @t{'lnAttr'} parameter.

@quotation 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. As a corollary to this automatic character 
selection, avoid positioning the start of a line such that it would 
obscure the window title (if any). Definitions for the line-drawing 
characters may be found in @t{AnsiCmdDef.hpp}.
@end quotation

@Subsubheading{Line-drawing Examples,
               .....................}

@ifnothtml
@verbatim
     ┌───┬────────┤ Line-drawing Tests ├────────╥───┐
     ├───┼──────────────────────────────────────╫───┤
     │   │       ├──────────────────────┤       ║   │
     │   │      ╠════════════════════════╣      ║   │
     ╞═══╪══════════════════════════════════════╬═══╡
     │   │  ┬   ╔════════════════════════╗   ╦  ║   │
     │   │  │   ║ ║ ────────────────── │ ║   ║  ║   │
     │   │  │   ║ ║ ══════════════════ │ ║   ║  ║   │
     │   │  ┴   ╚════════════════════════╝   ╩  ║   │
     └───┴──────────────────────────────────────╨───┘
@end verbatim
@end ifnothtml
@ifhtml
@html
<div class="tscap" style="background-color:#993300; max-width:28.85em; line-height:1.165em;"><span class="grbl">┌───┬────────┤ Line-drawing Tests ├────────╥───┐</span>
<span class="grbl">├</span><span class="grbr">───┼──────────────────────────────────────╫───</span><span class="grbl">┤</span>
<span class="grbl">│</span><span class="grbr">   │       ├──────────────────────┤       ║   </span><span class="grbl">│</span>
<span class="grbl">│</span><span class="grbr">   │      ╠════════════════════════╣      ║   </span><span class="grbl">│</span>
<span class="grbl">╞</span><span class="grbr">═══╪══════════════════════════════════════╬═══</span><span class="grbl">╡</span>
<span class="grbl">│</span><span class="grbr">   │  ┬   </span><span class="cybr">╔════════════════════════╗</span><span class="grbr">   ╦  ║   </span><span class="grbl">│</span>
<span class="grbl">│</span><span class="grbr">   │  │   </span><span class="cybr">║ ║ ────────────────── │ ║</span><span class="grbr">   ║  ║   </span><span class="grbl">│</span>
<span class="grbl">│</span><span class="grbr">   │  │   </span><span class="cybr">║ ║ ══════════════════ │ ║</span><span class="grbr">   ║  ║   </span><span class="grbl">│</span>
<span class="grbl">│</span><span class="grbr">   │  ┴   </span><span class="cybr">╚════════════════════════╝</span><span class="grbr">   ╩  ║   </span><span class="grbl">│</span>
<span class="grbl">└───┴──────────────────────────────────────╨───┘</span>
</div>
@end html
@end ifhtml
@spi

@anchor{LaunchDefaultApp}
@cindex LaunchDefaultApp
@item @b{int  LaunchDefaultApp ( const char* targFile, bool redirect = true );}

@verbatim
  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: 
     the child process ID (an integer value)
     returns minus one (-1) if child process was not created
@end verbatim

Launch the system default application for handling the specified type of file.

@H5heading{Technical Description:,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
Launching an external application is done by creating a child process to 
perform the actual launch, while the parent process continues execution of 
the application code. This operation is done via a call to the standard 
library's @t{'@b{vfork'}} function. 
@enumerate a
@item The @t{'@b{targFile}'} parameter:@*
This is the filespec for the file to be processed by the external 
application. This may be either a full-path specification or a 
relative path; or if a @t{URL} is specified, then that page will be 
opened in the browser.@*
@verb{|   /home/sam/Documents/XmasList.html|}@*
@verb{|   ./XmasList.html|}@*
@verb{|   "../../Music/Kansas/Dust In the Wind"|}
@item The @t{'@b{redirect}'} parameter:@*
By default, the displayed startup information (if any) for the child 
process is redirected to temporary files to avoid trashing the parent 
application's display. If desired, the startup information will be 
written to the terminal window (redirect==false); but in this case, 
the application's display data should be saved before calling 
@t{LaunchDefaultApp}. 
(@xref{HideWin}).
@item The @t{'@b{xdg-open}'} system utility:@*
When called, this utility scans the system's MIME-type (Multipurpose 
Internet Mail Extension) database to determine the user's specified 
default application for processing files of that MIME type. For example:@*
@verb{|   win->LaunchDefaultApp ( ../Texinfo/ansicmd.html );|}@*
This will invoke the user's default browser to display the specified 
HTML file. If the browser is not open, it will be opened. If the browser 
is already open, a new tab (or a new instance of the browser) will be 
created to display the file. The precise action is determined by the 
settings of the target application.
@item Redirecting @t{stdin/stderr} streams:@*
Redirection of a data stream is handled by the standard library's 
@t{'@b{dup2}'} function. This is somewhat more complex than redirection 
using @t{'pipes'}. See the @t{'dup2'} documentation for details. 
@item See also @ref{ShellOut}, below, which opens an external application 
in the current terminal window.
@end enumerate
@spi

@anchor{ShellOut}
@cindex ShellOut
@item @b{int ShellOut ( const gString& shellCmd, 
@ifnothtml
@*@verb{|              |}
@end ifnothtml
acAttr textColor = acaUSEDFLT );}

@verbatim
  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 
                  the '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)
                specify an alternate foreground/background
                color for text data written to stdout.
                [This parameter is currently ignored.]

  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.
@end verbatim

Go to command shell in the current terminal window.
@enumerate 1
@item Save the application window display data.
@item Clear the terminal window
@item Put the AnsiCmd engine (including ACWin object) into hibernation mode.
@item Invoke the specified application (if any)@*
If no application is specified, invoke @t{'bash'} (or current shell program).@*
In this case, user will need to type @t{'exit'} to return to application.
@item Wake the AnsiCmd engine from hiberation mode.
@item Return control of the Input stream to the ACWin object.
@item Redraw the application window.@*
As a side effect, this also restores the color attributes.
@end enumerate

@b{Important Note:} This method should be called ONLY from the main application 
window. @emph{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.
@end itemize
@spi
@hr90

@c - - - Section - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@section Development Support Methods

@indentedblock
@ifhtml
@indentedblock
@CartHtml{
A beginning developer may ask:
@LDQ{}Why are the debugging routines so fancy?@RDQ{}

Answer:
Writing the debugging routines is a concrete expression of the 
thought process which informs the overall project development.
@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ Highly recommended for all developers.
@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ (It's almost as important as coffee :)}
@end indentedblock
@end ifhtml
@ifnothtml
@verbatim
┌────────────────────────────────────────────────────────────────┐
│ A beginning developer may ask:                                 │
│ "Why are the debugging routines so fancy?"                     │
│                                                                │
│ Answer:                                                        │
│ Writing the debugging routines is a concrete expression of the │
│ thought process which informs the overall project development. │
│            Highly recommended for all developers.              │
│            (It's almost as important as coffee :)              │
└────────────────────────────────────────────────────────────────┘
@end verbatim
@end ifnothtml
@end indentedblock
@spi

@anchor{GetWinAttributes}
@cindex GetWinAttributes
@itemize @BSQUARE
@item @b{void GetWinAttributes ( acaExpand& txtExp, acaExpand& bdrExp );}
@verbatim
  Input  :
     txtExp : (by reference) acaExpand object to receive text attributes
     bdrExp : (by reference) acaExpand object to receive border attributes
  Returns: nothing
@end verbatim
Debugging method: Get a copy of the window attributes.
@spi

@anchor{GetWinConfig}
@cindex GetWinConfig
@item @b{WinPos GetWinConfig ( short& height, short& width );}
@verbatim
  Input  :
     txtExp : (by reference) receives window height (rows)
     bdrExp : (by reference) receives window width (columns)
  Returns: window position (offset into terminal window)
@end verbatim
Debugging method: Get a copy of the window dimensions and position.
@spi

@anchor{GetFifo}
@cindex GetFifo
@item @b{const BlockFifo* GetFifo ( void );}

@verbatim
  Input  : none
  Returns: const pointer to the private @b{BlockFifo} object.
@end verbatim
Debugging method: Get a pointer to the FIFO queue which contains the 
static text of the window. For an example, please refer to the @t{Test_Fifo} 
method in @t{AnsiCmdTest.cpp}. Run this test using: @w{@t{epts --test=Ws}.}

@anchor{dumpConfig2Log}
@anchor{dumpField2Log}
@anchor{dumpMrp2Log}
@anchor{dumpFifo2Log}
@anchor{dumpFifoRecord2Log}
@cindex dumpConfig2Log
@cindex dumpField2Log
@cindex dumpMrp2Log
@cindex dumpFifo2Log
@cindex dumpFifoRecord2Log
@item @b{void dumpConfig2Log ( const wchar_t* title );}
@item @b{void dumpField2Log ( const skField* fptr, const wchar_t* title, 
@ifnothtml
@*@verb{|                    |}
@end ifnothtml
bool verbose = false );}
@item @b{void dumpMrp2Log ( const skField* fptr, 
@ifnothtml
@*@verb{|                  |}
@end ifnothtml
const wchar_t* title = NULL, bool brief = false );}
@item @b{void dumpFifo2Log ( const BlockFifo* bptr, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
const wchar_t* title = NULL );}
@item @b{void dumpFifoRecord2Log ( const DataBlock* dbptr );}

Debugging methods: Write various diagnostic data to the debugging log file.

During development a log file is created when the application is launched. 
This file is cryptically named: @t{"dbg.log"}. Startup and shutdown data are 
written to this file, and depending on which conditional-compilation 
declarations are enabled, a large amout of additional data are recorded 
in the log. @xref{Build Options} for more information.

Please refer to the individual methods listed for an explanation of the data 
written in each case.
@spi

@anchor{Screenshot}
@cindex Screenshot
@item @b{void ACWin::Screenshot ( bool html = false, const char* desc = NULL );}
@verbatim
  Input  :
     html : (optional, default == false) output format 
            true  : HTML markup 
            false : plain text 
     desc : (optional, default == null pointer) discriptive text 

  Returns: nothing 
@end verbatim

Capture a screenshot of the specified @t{ACWin} object to the log file.@*
The capture is performed in a sectioned format as shown, and the developer 
is then responsible for integrating the sections to produce the finished 
screenshot.
@enumerate 1 
@item Window border (including optional window title) 
@item Static text block(s)@*
These are sequences of text which have been written directly to the 
interior of the window, bypassing the control objects.
@item Array of controls, in indexed order. Each control is written with 
outline and label, if specified.
@end enumerate 
 
This procedure is significantly different from the author's NcDialog library 
(based on ncurses) which performs window capture in a fully-integrated way, 
including color attributes. The @t{AnsiCmd/ACWin/ACDlg} library, however, 
is a much simpler creature.

@H6heading{Plain-text Screenshots,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
For monochrome plain-text screenshots (Texinfo @t{'.info'} documents), 
it is likely more efficient to simply copy-and-paste from the terminal 
window, but if the @t{'html'} parameter is reset, a plain-text capture will 
be performed. See the Linux documentation for @b{@t{Ctrl+Shift+c}} and 
@b{@t{Ctrl+Shift+v}} copy-and-paste commands.

@H6heading{HTML Screenshots,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
For HTML documentation, copy-and-paste is inefficient and error prone, so 
it is likely more efficient to use this capture method. This is especially 
true for a developer who is not fluent in HTML/CSS markup because 
placeholder @t{HTML/CSS3} style instructions are embedded in the screen-capture.

The HTML output is placed inside a @w{@b{@t{<div class="tscap">...</div>}}} 
pair of tags which defines the dimensions, font family, basic color scheme 
and so on.

Each row of the window border is bracketed by a placeholder sequence:@*
@verb{|<span class="xxxx">...</span>|} which provides a method for 
specification of color attributes for the left and right borders. Example:@*
@verb{|<span class="bl_r">┌─────┐</span>|}@*
@verb{|<span class="bl_r">│</span> Hi! <span class="bl_r">│</span>|}@*
@verb{|<span class="bl_r">└─────┘</span>|}@*
which specifies blue text with foreground and background attributes reversed.
@ifnothtml
@example
   ┌─────┐
   │ Hi! │
   └─────┘
@end example
@end ifnothtml
@ifhtml
@indentedblock
@indentedblock
@html
<div class="tscap" style="background-color:inherit; max-width:4.00em; line-height:1.165em;"><span class="bl_r">┌─────┐</span>
<span class="bl_r">│</span> Hi! <span class="bl_r">│</span>
<span class="bl_r">└─────┘</span>
</div>
@end html
@end indentedblock
@end indentedblock
@end ifhtml
Please refer to the CSS class definitions in @b{@t{infodoc-styles.css}} for 
a description of the color-attribute classes.

Each object within the window is also enclosed within a similar sequence.

For greater control over the color palette, instead of calling out the 
pre-defined color attribute classes, the @w{@t{<span class="xxxx;">}} 
tag may be replaced with something similar to:@*
@verb{|   <span style="color:#0033FF; background-color:#99FF99;">|}@*
This tag specifies @LDQ{}web-safe@RDQ{} foreground and background color 
attributes. Please run the color tests (@ref{test C}) included in this package, and 
visit the author's website for a document @w{@LDQ{}HTML/CSS Color Chart@RDQ{}} 
describing web-safe colors.

Hotkey designators are displayed using the 'underline' text-modifier attribute. 
For these characters, a callout for the the CSS @t{"@b{ulin}"} class is embedded in the 
HTML output. For example the text of a Pushbutton may be written as: 
@verb{|             "Buy Some ^Jiǎozǐ Today"|}@* 
The caret character @t{('^')} indicates that the next character is the hotkey 
character, 'J' in this example. Thus the HTML would be: @*
@verb{|<span class="xxxx">Buy Some <span class="ulin">J</span>iǎozǐ Today</span>|}@*
This will cause the 'J' to be underlined in the output. 

The primary test window for this functionality is @ref{Test_Cookie}, which is 
a simple window used in the Texinfo documentation.@*
(@xref{skForm Class}.)
 
Note that the @t{Screenshot} method is @b{@emph{huge}} compared to its actual 
usefulness, so be sure its conditional-compilation is disabled:@*
@verb{|      #define DEBUG_PHOTO (0)  |}@*
when the method is not in use. @xref{Building from Source} for details.

@indentedblock
@CartHtml{@embedTOKEN{as}@i{@b{Editor's Note:} Your humble author designed, tested and wrote the documentation for 
this routine in two days, all on battery-backup, while the power was out and snow and ice 
covered everything. Some exciting Spring Festival (春节假期) for 2025, Year of the Snake!}}
@end indentedblock
@end itemize
@sp 2


@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.00 skForm Class  - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c         Using the skForm and skField classes  - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node skForm Class
@unnumbered skForm Class
@cindex 04.2.00 skForm Class
@cindex skForm class
@cindex class, skForm

Communication between the application and the user is the most complex 
(and most error prone) task for the application developer. 
Most of us would prefer to avoid user interactions as much as possible; 
however, without users (filthy beasts as they may be) there wouldn't be 
much need for applications.

When designing an application, it must be assumed that the user interface 
section will not only require more code and more development time than 
any other section; it will require the developer to compensate for users' 
(often illogical) assumptions about the program, and their blithe 
refusal to read the documentation.@*
The @b{@t{skForm}} and @b{@t{skField}} interface classes are your humble 
author's attempt to make this process as painless as possible.

@c The HTML markup above the "mini-toc" class used for the sub-menu
@c includes too many <br> tokens. In addition, the HTML places the menu 
@c below the paragraph text even if the source positions it above.
@menu
* User Interaction::             Communication with the user
* skForm Public Methods::        Public methods of the skForm class
* skForm Data Members::          Initialization of skForm data members
* skField Public Methods::       Public methods of the skField class
* skField Data Members::         Initialization of skField data members
* UI Control Types::             User interface controls
* skForm Initialization::        Sample initialization of skForm
@end menu

@sp 2

@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@lowersections
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.01 User Interaction  - - - - - - - - - - - - - - - - - - - - - - - - - -
@c         Communication with the user - - - - - - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node User Interaction
@unnumbered User Interaction
@cindex 04.2.01 User Interaction
Some developers will want to write directly into the terminal window, and 
read the user's responses directly from the window. The @t{AnsiCmd} 
primitives @ref{acRead}, @ref{acWrite}, @ref{ttyWrite}, etc. are designed 
for this type of interaction.

Others will want to design an array of text-input fields and other 
types of controls for user interactions.@*
These controls are defined by Some-Kind-of-Form i.e. the @t{'@b{skForm}'} class.@*
Both the @b{@t{ACWin}} class (window) and the @b{@t{ACDlg}} class (dialog) 
support skForm-class objects. Within the skForm object, an array of 
@t{'@b{skField}'} objects defines the individual controls for user interaction.

If the ACWin constructor is called without specifying an skForm object, a 
default skForm object is created based on the size of the window. The default 
skForm object will be created with one(1) text-box (ftTB) skField object which 
takes the dimensions of the window interior.

To achieve direct control over the way the skForm object is configured, a 
pointer to an initialized skForm object is passed to the @t{ACWin} 
or @t{ACDlg} constructor.

@verbatim
// Define and initialize an skForm/skField object.
skForm* skfp = new skForm
{
   FLD_COUNT,
   new skField[FLD_COUNT]
   {
      . . .
   },
   // Initialize remaining skForm parameters to default values.
   . . .
} ;

// Create a window.
ACWin *win = new ACWin
      ( winROW, winCOL,                // position (upper-left corner) 
        winHEIGHT, winWIDTH,           // dimensions (height, width)
        ltSINGLE,                      // border style
        bdrAttr,                       // border attributes
        intAttr,                       // interior attributes
        "  Secrets of the Universe  ", // window title
        skfp                           // pointer to skForm object
      ) ;

// Create a dialog within a parent window
this->win->Dialog
      ( dlgHgt, dlgWid,       // dialog dimensions
        skfp,                 // pointer to skForm object
        staticText,           // text written directly to dialog interior
        dlgTitle,             // dialog title
        ZERO, -1,             // dialog offset within parent window
        ltDUAL,               // border style
        acaUSEDFLT,           // border color attribute
        this->dlgAttr,        // interior color attribute
        0, 1,                 // interior text offset
        nonmember_dlgCallback // address of callback function
      ) ;
@end verbatim

The position and dimensions of each field must fall entirely within the 
text area of the window, and the fields should not overlap (unless the 
obscured field(s) are set as @LDQ{}hidden@RDQ{}).

Although range checking and automatic positioning and size adjustments of the 
controls is performed, an over-caffinated developer could still cause chaos, 
so it is important to carefully verify the parameters which define the 
individual controls.

There are several ACWin objects and ACDlg invocations created in the 
test code included in this package. Some tests write text directly into 
the window, while others write into the defined fields (or some combination 
of the two). Please refer to those examples, as well as the discussion of 
skForm and skField classes below.
@sp 2

@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.02 skForm Public Methods - - - - - - - - - - - - - - - - - - - - - - - -
@c         Public methods of the skForm class  - - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node skForm Public Methods
@unnumbered skForm Public Methods
@cindex 04.2.02 skForm Public Methods

The skForm-class object is a mostly passive construct, that is, the object 
doesn't perform many tasks directly. Its primary function is to store and 
display information in an orderly and predictable way. The ACWin or ACDlg 
object updates this information in response to user activity.@*
Please @pxref{EditForm} which acts as the gateway to the skForm data.

@anchor{skForm constructor}
@cindex skForm constructor
@itemize @BSQUARE
@item @b{skForm ( short fieldCount );}

@verbatim
  Input  : fieldCount : number of skField objects
                        Range: 1 through 99

  Returns: implicitly returns a pointer to the object
@end verbatim

Simple constructor. Allocate resources for the skForm object and an array of 
skField objects. All data members receive default values.

It is assumed that the application will populate all necessary data members 
after instantiation. Please see the initialization constructor below for 
more detailed information on the initialization of the individual data members.

@i{@b{Technical Note:} The default constructor (the constructor with no 
arguments) is set as private in order to protect the application layer 
from creating an unusable object.}
@spi

@item @b{skForm ( short fieldCount, skField* fldArray, @*
@verb{|         |}short fldIndex = ZERO, acAttr fldAttr = acaUSEDFLT,@*
@verb{|         |}bool noisy = true, bool  ioFlag = true, bool ioToggle = true, @*
@verb{|         |}bool ioCursor = false, @*
@verb{|         |}CurStyle insCursor = csBblock, CurStyle ovrCursor = csBuline );}

@verbatim
  Input  : fldCount: number of objects in 'fldArray' (1-99)
           fldArray: pointer to an array of skField objects defining 
                     the form
           //** Optional Arguments **
           fldIndex: (optional, default: zero)
                     index of field which receives initial input focus 
           fldAttr : (optional, default: acaUSEDFLT)
                     For fields which change color when they receive 
                     input focus, this is the focus color attribute.
                     -- acaUSEDFLT: If default attributes specified, then 
                        when field receives input focus, the field's 
                        embedded foreground and background attributes are 
                        swapped.
                     -- If focus-color attributes are specified, then 
                        when field receives input focus, this attribute 
                        overrides the field's embedded attributes for as 
                        long as the field holds focus, at which time the 
                        embedded attributes are restored.
           noisy   : (optional, default: true)
                     if 'true',  beep on unhandled keycode received
                     if 'false', silently discard the unhandled keycode
           ioFlag  : (optional, default: set)
                     initial state of Insert/Overstrike flag
                     set  : Insert mode
                     reset: Overstrike mode
           ioToggle: (optional, default: true)
                     if 'true',  user may toggle between Insert mode and 
                                 Overstrike mode
                     if 'false', mode is fixed, and cannot be modified 
                                 by user 
           ioCursor: (optional, default: false)
                     if 'true', shape of cursor changes to indicate 
                                current state of Insert/Overstrike flag
                     if 'false', cursor shape is not modified for 
                                 Insert/Overstrike mode
           insCursor: (optional, default: csBblock)
                      member of enum CurStyle indicating the cursor shape 
                      to be used when in Insert mode.
                      (If 'ioCursor' flag is reset, then )
                      (only this cursor style is used.   )
           ovrCursor: (optional, default: csBuline)
                      member of enum CurStyle indicating the cursor shape 
                      to be used when in Overstrike mode.

  Returns: constructors _implicitly_ return a pointer to the object

@end verbatim

Initialization constructor.@*
This constructor fully initializes the skForm data members AND transfers the data 
from caller's skField array to the internal skField array.

@i{@b{Important Note:} The number of elements in @t{'fldArray'} must match the 
value in @t{'fldCount'}. If the array is larger than @LSQ{}fldCount@RSQ{}, then 
some field definitions may be discarded. If the array is smaller than 
@LSQ{}fldCount@RSQ{}, then a segmentation fault will be the likely result. 
@b{Be Aware!}}

Note that range checking and error correction are not performed by this 
constructor. Any needed corrections are made during instantiation of the 
parent window so that the values may be compared to the window definition.
@spi

@anchor{skForm operator=}
@cindex skForm operator=
@cindex assignment, skForm
@item @b{void operator= ( const skForm *skfp );}

@verbatim
  Input  : (by reference) the skForm object containing source data

  Returns: nothing
@end verbatim

Assignment Operator: make a copy of the specified skForm object.@*
The copy will include both the public and protected data members.

If the assignment operator is used correctly, then source and target 
arrays should have the same number of elements; however, if the dynamic 
allocations do not match, the target allocations will be released and 
re-allocated to accomodate the data to be copied.
@spi

@item @b{~skForm( void );}@*

@verbatim
  Input  : none

  Returns: none
@end verbatim

Destructor: Release the dynamic allocation and delete the skForm object.

For an @LDQ{}automatic@RDQ{} constructor allocation:@*
@verb{|  skForm skf( 6,|}@*
@verb{|              new skField[6] = { ... },|}@*
@verb{|              ... );|}@*
The destructor will be invoked when the object goes out of scope.

For a constructor created in dynamic memory:@*
@verb{|  sdForm* skf_ptr = new skForm|}@*
@verb{|          ( 6, |}@*
@verb{|            new skField[6] = { ... },|}@*
@verb{|            ... );|}@*
The destructor is invoked directly:@*
@verb{|  delete skf_ptr;|}@*

@ifnothtml
@verbatim
┌──────────────────────────────────────────────────────────────────────┐
│ Teacher Rant:                                                        │
│ Note that forgetting to delete a dynamically-allocated object when   │
│ the task is complete would be considered as a "memory leak", a       │
│ failure to return system resources once they are no longer needed.   │
│ The author once spent five weeks chasing memory leaks in a           │
│ multi-node Solaris system. It was not pretty. Please use extra care  │
│ when working with dynamic memory allocations.                        │
└──────────────────────────────────────────────────────────────────────┘
@end verbatim
@end ifnothtml
@ifhtml
@indentedblock
@indentedblock
@CartHtml{@embedTOKEN{as}@b{Teacher Rant:}
Note that forgetting to delete a dynamically-allocated object when 
the task is complete would be considered as a "memory leak", a 
failure to return system resources once they are no longer needed. 
The author once spent five weeks chasing memory leaks in a 
multi-node Solaris system. It was not pretty. Please use extra care 
when working with dynamic memory allocations.}
@end indentedblock
@end indentedblock
@end ifhtml
@spi

@item @b{bool skfProtectedMembers ( WinPos& p_base, wchar_t& p_pKey, 
@ifnothtml
@*@verb{|                          |}
@end ifnothtml
short& p_seli, bool& p_foot, bool& p_dlg ) const;}

@verbatim
  Input  : 
     p_base : (by reference) receives offset for upper left 
               corner of parent window
     p_pKey : (by reference) receives most recent 'special'
               keycode processed
     p_seli : (by reference) receives index of field containing
               'selected' text (if any)
     p_foot : (by reference) receives the 'footer' flag
               'true'  if Footer messages are enabled
               'false' if Footer messages are disabled
     p_dlg  : (by reference) receives the 'dialog' flag
               'true'  if skForm container is an ACDlg object
               'false' if skForm container is an ACWin object

  Returns: 'true'  if AnsiCmd library debugging code is enabled:
                   (caller's parameters have been initialized)
           'false' if AnsiCmd library debugging code is disabled:
                   (caller's parameters returned uninitialized)
@end verbatim

@b{For Debugging Only.}

This method reports the @LDQ{}protected@RDQ{} data members of the skForm class.@*
These values are not directly available at the application level, but may be 
useful during development.
@end itemize
@sp 2


@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.03 skForm Data Members - - - - - - - - - - - - - - - - - - - - - - - - -
@c         Initialization of skForm data members - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node skForm Data Members
@unnumbered skForm Data Members
@cindex 04.2.03 skForm Data Members

@itemize @EMDASH
@item @b{fCnt} (internal use only)@*
This is the number of elements in the @t{'fld'} array of skField objects. 
While this value is technically a public data member, it is set only once, 
during instantiation of the skForm object, and may not be modified after 
that.

@item @b{fld}@*
Pointer to an array of one or more @t{skField} objects which is dynamically 
allocated by the skForm constructor. Templates for these fields may be 
individually initialized by the application, then passed to the ACWin or ACDlg 
constructor, which performs range checking and adjustmens as necessary, and 
then copies the application's values to the internal skForm object.

@item @b{fi}@*
Field Index. This value is used internally to track the index of the 
field which currently has the input focus. (default: zero)@*
The initial value may be set to indicate the field with initial input focus, 
but is under control of the window during user interactions.

@item @b{faca}@*
If the field uses different color attributes based on whether the field 
has the input focus, this is the color attribute for when the field has 
input focus.@*
For fields which do not include a visible cursor, use of this color 
is a visual indication of which field has focus.

@item @b{beep}@*
If set, this flag indicates that an auditory warning will sound when the 
user presses an invalid key. When reset, invalid keystrokes are silently 
discarded. (default: @t{'true'})@*
To modify this value, please @pxref{AlertEnable}.

@item @b{ins}@*
Insert flag. When set, indicates Insert mode. When reset, indicates 
Overstrike mode. (default: @t{'true'})@*
This flag is referenced when user is modifying the text within a 
Textbox field (ftTB) to determine the input @LDQ{}mode@RDQ{}. The user 
can toggle between the modes by pressing the @t{Insert} key @emph{unless} 
the @t{'togg'} flag is reset. (see below)@*
To modify Insert key setup, please @pxref{InsertKey}.

@item @b{togg}@*
If set, user may toggle the Insert/Overstrike mode. If reset, Ins/Ovr mode 
is locked in its current state and may not be modified by the user. 
(default: @t{'true'})

@item @b{insc}@*
If set, this flag indicates that the cursor style changes when the 
insert/overstrike mode is toggled. (default: @t{'false'}.)@*
The cursor style for each mode may be specified using the @t{'icur'} 
and @t{'ocur'} members described below.

@item @b{icur}@*
If @t{'insc'} is set, this is the cursor style used when in Insert Mode.@*
Default: @t{'csBblock'}. (ignored when @t{'insc'} is reset)

@item @b{ocur}@*
If @t{'insc'} is set, this is the cursor style used when in Overstrike Mode.@*
Default: @t{'csBuline'}. (ignored when @t{'insc'} is reset)
@end itemize

@indentedblock
@H6heading{Protected Data Members,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
@end indentedblock

@itemize @EMDASH
@item @b{base} (@LSQ{}protected@RSQ{}, internal use only)@*
This is the zero-based offset from the upper-left corner of the ACWin 
(or ACDlg) object's interior. Used for calculating the position of the 
visible cursor.

@item @b{pkey} (@LSQ{}protected@RSQ{}, internal use only)@*
Previous Key: This value tracks the most recent user input value.

@item @b{seli} (@LSQ{}protected@RSQ{}, internal use only)@*
Selection Index: This value tracks the index of the field (if any) 
which contains @LDQ{}selected@RDQ{} text. This facilitates communication 
with the system clipboard.

@item @b{foot} (@LSQ{}protected@RSQ{}, internal use only)@*
Enables or disables the method used to write @LDQ{}footnotes@RDQ{}, 
that is, diagnostic messages to the lower border of the window.@*
@xref{EnableFootnotes} for setting and resetting this flag.

@item @b{dlg} (@LSQ{}protected@RSQ{}, internal use only)@*
Used to distinguish whether operating in the parent window or a child 
dialog window. (The @t{ACDlg} class is a derived class based on the 
@t{ACWin} class.)@*
@xref{ACDlg Class} for additional information.
@end itemize
@sp 2

@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.04 skField Public Methods  - - - - - - - - - - - - - - - - - - - - - - -
@c         Public methods of the skField class   - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node skField Public Methods
@unnumbered skField Public Methods
@cindex 04.2.04 skField Public Methods
@cindex skField class
@cindex class, skField
@anchor{skField Class}

@anchor{skField constructor}
@cindex skField constructor
@itemize @BSQUARE
@item @b{skField ( FldType fldType, short fldHeight, short fldWidth,@*
@verb{|         |} short fldOffsetY, short fldOffsetX,}@*
@verb{|         |} //* Optional Arguments *@*
@b{@verb{|         |} const char* fldText = NULL, acAttr fldAttr = acaATTR_DFLT,@*
@verb{|         |} FloType fldFlow = floChar, bool readOnly = false,@*
@verb{|         |} bool fldBorder = false, bool fldHidden = false,@*
@verb{|         |} bool fldLocked = true, bool binState = false,@*
@verb{|         |} wchar_t hotKey = NULLCHAR, wchar_t groupId = noGROUP );}

@verbatim
  Input  :
     fldType    : field type, member of enum FldType
     fldHeight  : field height in rows
     fldWidth   : field width in columns
     fldOffsetY : vertical offset from parent window origin
     fldOffsetX : horizontal offset from parent window origin
     fldText    : (optional, default: an empty string "\0")
                  Initial text data. Data configuration is dependent 
                  on the field type. See documentation for details.
     fldAttr    : (optional, default: acaATTR_DFLT)
                  color attribute for field
                  Note that for field types which change color when they 
                  receive input focus, this is the non-focus color.
     fldFlow    : (optional, default: floDflt) text flow
                  Automatic text formatting option for the field.
                  Formatting option is dependent on field type, and is 
                  fully configurable only for Textbox controls (ftTB).
     readOnly   : (optional, default: false)
                  if set,  field is view only, cannot receive focus
     fldBorder  : (optional, default: false)
                   if false, field has no border.
                      Exception: Menubox controls always have a border.
                   if true,  draw an outline around the field
                      Note: Default line type and color attribute will be 
                            used to draw the outline. For a non-default 
                            line type or attribute, see SetFieldOutline().
     fldHidden  : (optional, default: false)
                  if set, field is not displayed and cannot receive focus
     fldLocked  : (optional, default: true)
                  if set, field is always visible (unless obscured by 
                          another field.)
                  if reset, field becomes invisible when it loses focus. 
                          (This is primarily for menus.)
     binState   : (optional, default: false)
                  For binary-state controls only (Radiobuttons), 
                  specifies the initial state: "set" or "reset".
     hotKey     : (optional, default: null L'\0')
                  if specified, this is the hotkey character for setting 
                  focus to field. Please see documentation about 
                  specification and use of hotkeys.
     groupId    : (optional, default: noGROUP)
                  For fields whih can be grouped(Menubox and Radiobutton)
                  this is the character used to identify the members 
                  of the group.

  Returns: constructors _implicitly_ return a pointer to the object
@end verbatim

Initialization constructor.@*
The first five(5) arguments are required. The remaining arguments are 
optional and if not specified, will receive default values.

The @t{ACWin} class test methods provide several examples of @t{skField} 
initialization.@*
A representative sample initialization (@ref{skForm Initialization}) is 
shown below.@*
@xref{test W}, sub-test @t{'f'} for additional information.
@spi

@item @b{skField ( void );}

@verbatim
  Input  : none

  Returns: constructors _implicitly_ return a pointer to the object
@end verbatim

The default constructor creates an skField object and initializes all 
members to their default values. This constructor has little practical value, 
but it remains a public method for those who wish to experiment.@*
See the initialization constructor above for a more robust implementation.
@spi

@anchor{~skField}
@cindex ~skField
@item @b{~skField ( void );}

@verbatim
  Input  : none

  Returns: nothing
@end verbatim

Destructor.

The destructor is like the cleaning crew that comes into your Cabo hotel 
room after Spring Break. All resources allocated from the system are 
returned to the system, the mini-fridge is restocked and the iguana you 
forgot was in the shower is returned to the wild.@*
(Lo siento mucho, Abue; tenía 19 años y estaba un poco fuera de control.)
@spi

@anchor{skField operator=}
@cindex skField operator=
@cindex assignment, skField
@item @b{void operator= ( const skField& skf );}

@verbatim
  Input  : (by reference) the skField object containing source data

  Returns: nothing
@end verbatim

Assignment Operator: make a copy of the specified skField object.@*
The copy will include both the public and protected data members.@*
See also the skForm operator=() above.
@spi

@anchor{outlineConfig}
@cindex outlineConfig
@item @b{bool outlineConfig ( LineType lType, acAttr lAttr = acaUSEDFLT );}

@verbatim
  Input  :
     lType   : line type for border, member of enum LineType
               ltSINGLE (default), ltDUAL, ltHORIZ (invisible border)
     lAttr   : (optional, default: acaUSEDFLT) border color attribute
               if not specified, takes attribute of window interior
               -- Note that this parameter does not apply to menu
                  controls which take their outline color from the
                  menu data.

  Returns: 'true'  if successful
           'false' if field type does not allow borders
@end verbatim

Set the line type and attribute for the field outline.

The data members which contain these values are 'protected', that is, they 
are not available at the application level. This skField public method is 
provided so these values can be initialized before the window or dialog is 
instantiated. The configured fields will be displayed when the window(dialog)
is opened.

@enumerate a
@item Note that this method should be called ONLY before the window (or dialog) 
constructor is called. To initialize the border @b{@emph{after}} the window/dialog 
is created, call the ACWin-class SetFieldOutline method instead.
@item Field outlines are incompatible for Menu controls (ftMB) because menus 
have integrated borders.
@item Because this call does not reference the parent window(dialog), error 
checking of positioning or interference with the border and with other 
fields cannot be performed here. For this reason, use caution when 
initiating these values.
@item This method is intended primarily for initializing the skForm/skField 
object to be used as a parameter when invoking a full-initialization 
dialog; however, it is possible to use this method when initializing the 
skForm/skField object to be used as a parameter when defining an ACWin 
object. In this case, use extra care in positioning the specified control.
@end enumerate

Please @pxref{skField config example} below for an example of using 
@t{outlineConfig}.
@spi

@anchor{labelConfig}
@cindex labelConfig
@item @b{bool labelConfig ( const char* labText, 
@ifnothtml
@*@verb{|                   |}
@end ifnothtml
acAttr labAttr = acaUSEDFLT, bool center = false);}

@verbatim
  Input  :
     labText : display text, optionally including a "hotkey" character.
               A hotkey is specified using the CARET character ('^')
               followed by the ASCII character which indicates the@item
               keycode to be used as a hotkey. (see example above)
     labAttr : (optional, default: acaUSEDFLT) color attribute for label
               If not specified label color is set to color of parent
               window interior
     center  : (optional, default:'false') horizontal offset
               if set, center the label horizontally above the field
               if reset, label offset is in the same column as the
                         left edge of the field

  Returns: 'true'  if successful
           'false' if field type does not allow external label
@end verbatim

Specify label text, color and position.

The data members which contain these values are 'protected', that is, they 
are not available at the application level. This skField public method is 
provided so these values can be initialized before the window or dialog is 
instantiated. The configured fields will be displayed when the window 
(or dialog) is opened.

Note that this method should be called ONLY before the window (or dialog) 
constructor is called. To initialize the border @b{@emph{after}} the window 
is created, call the ACWin-class SetFieldLabel method instead.

@format
The following control types will accept labels:
 1) ftTB - Textbox
 2) ftSB - Scrollbox
 3) ftMB - Menu
    Note that only certain menus may have labels.
     a) Context menus i.e. multi-row menus which are not group members.
     b) Menubar menus i.e. single-row menus which anchor a group 
        of menu controls.
 External labels are incompatible for Pushbuttons (ftPB) and Radiobuttons 
 (ftRB) because the field text @b{@emph{is}} the label.
 See below for a label configuration method specifically for Radiobuttons.
@end format

Please @pxref{skField config example} below for an example of using 
@t{labelConfig}.
@spi

@item @b{bool labelConfig ( acAttr labAttr, bool lableft = false );}

@verbatim
  Input  :
     labAttr : color attributes for Radiobutton label
               If acaUSEDFLT specified, then label color is set to color
               of parent window interior
     lableft : (optional, default:'false') horizontal offset
               if set, label is displayed to the left of the control
               if reset, label is displayed to the right of the control

  Returns: 'true'  if successful
           'false' if incorrect field type
@end verbatim

Specify label color attributes  and position.

This  overload is designed for Radiobutton controls (ftRB) only.@*
To initialize labels for other types of controls, see above.

By default Radiobutton labels inherit the color attributes of the parent 
window/dialog @emph{and} the label is positioned to the right of the field.@*
This method allows direct specification of the label attributes and 
optionally allows the label to be positioned to the left of the control.

The data members which contain these values are 'protected', that is, they 
are not available at the application level. This skField public method is 
provided so these values can be initialized before the window or dialog is 
instantiated. The configured fields will be displayed when the window(dialog) 
is opened.

Note that this method should be called ONLY before the window (or dialog)
constructor is called.

@verbatim
  skForm* skfp( ... ) ;
  // Field definition and formatting for a Radiobutton control:
  // The caret character, if present, indicates the hotkey 
  // character for setting input focus to target field.
  // Define the text and position of the control
  short row_offset = 2, col_offset 14 ;
  const char* rbDef = "[♦] Comp^uter Science" ;

  // By default the field and label would be displayed as:
        [♦] Computer Science
              ▔
  // If label configuration with field/label swap, the overall
  // position within the window will be unchanged, but field 
  // and label will swap positions as shown.:
  skfp->fld[n].labelConfig ( acAttr(acaFG_BLUE|acaUSEDFLT), true );
        Computer Science [♦]
            ▔
@end verbatim

Note that a space after the closing brace will automatically be removed, 
and a space will be appended to the label text:@*
@verb{|   "[♦] Computer Science"|} becomes@* 
@verb{|   "Computer Science [♦]"|}@*
@xref{AcEdit Demo App}, @t{'Compare Files'} dialog for a working example 
of this option.
@spi

@anchor{colorConfig}
@cindex colorConfig
@cindex custom colors
@cindex colors, custom
@item @b{bool colorConfig ( const acAttr* rowAttr, short rowCnt );}

@verbatim
  Input  :
     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
              Value must be greater than zero, and the minimum
              _practical_ value is two(2)

  Returns:
     'true'  if successful
     'false' if field type does not support per-row attributes
             or if 'rowCnt' less than minimum
@end verbatim

Specify an array of color attributes, one for each item (row of text data) 
within the control.

Customization of text color attributes is often useful to enhance readability 
of multi-row controls which contain fixed display text. For multi-row 
Menu controls (ftMB) and Scrollbox controls (ftSB) @b{@emph{only}}, color 
attributes for each individual display row may be specified.

The data member which contains these color values is 'protected', that is, 
it is not available at the application level. This skField public method is 
provided so that custom color attributes may be specified, one attribute 
per text row, @b{@emph{after}} the skField object has been instantiated, 
but @b{@emph{before}} the window (or dialog) constructor is called.@*
The reonfigured field will be displayed when the window(dialog) is opened.

The following control types support custom color attributes:@*
These control types are designed to contain read-only data; (the data may 
may not be edited under user control); therefore, it is possible to embed 
color attributes within the displayed text.

@enumerate 1
@item ftMB - Menu
@format
 - All items within a menu are visible simultaneously whenever the menu 
   itself is visible. Therefore one custom color must be specified for 
   each item. Do not specify attributes for the upper or lower borders.
 - Note that the specified attributes apply @b{@emph{only}} to the text 
   displayed within the control, and @b{@emph{not}} to the borders 
   drawn around the text.
 - Only multi-row (multi-item) menus support custom colors. 
   A single-row menu (menu bar) is excluded, because it has only 
   one row, and therefore only one color.
@end format

@item ftSB - Scrollbox
@format
 - Scrollbox controls may contain any number of text items, although 
   the number of items visible at any moment is determined by the 
   height of the control. Therefore, a custom color must be specified 
   for each item (row) whether it is visible or not.
 - Please note that if text data provided for a Scrollbox control is 
   incorrectly formatted, it will be automatically reformatted to 
   fit the control. If this happens, the color attribute specified 
   for each row may not be as expected. Beware!
@end format
@end enumerate

Any valid @t{acAttr} color attribute bitfield may be specified.@*
The acUSEDFLT value indicates that the target item will use the attribute 
specified in the skField's 'aca' member. This is the attribute for the 
control as a whole.

Please refer to the example below.
@spi

@H6heading{IMPORTANT NOTE:,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

This method includes some defensive programming; however, it is not 
possible to anticipate all potential foolishness, so be careful! 
Applying per-item color attributes must rely on text data formatting 
which has not yet been programatically validated.

This method should only be called for controls within a dialog (ACDlg) object, 
and @b{@emph{only}} if you are certain that the text to be displayed within 
the control has been properly dimensioned, ensuring that the attribute count 
will equal item count.

For controls within a window (ACWin) object, please use the @ref{SetFieldAttr} 
method instead. Using @t{SetFieldAttr} will be safer because it will be called 
after the control dimensions and text formatting have been verified.
@spi

@anchor{skField config example}
@H5heading{skField config example,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

@verbatim
// Create and initialize an skForm object with an array of three(3)
// skField objects: a Textbox, a Context Menu and a Pushbutton.
sdForm* skf_ptr = new skForm
        ( 3, 
          new skField[3] = 
          {
            { ftTB, ... }, // Textbox      (index 0)
            { ftMB, ... }, // Context Menu (index 1)
            { ftPB, ... }, // Pushbutton   (index 2)
          },
          ... );

// Specify that an outline is to be drawn around 
// the Textbox control.
skf_ptr->fld[0].outlineConfig ( ltDUAL,
                                acAttr(acaFG_BLUE | acaBG_CYAN) );

// Specify a label for the Textbox control 
skf_ptr->fld[0].labelConfig ( "Date Of Birth " );

// Specify a label for the Menu control,
// (centered, with contrasting color).
skf_ptr->fld[0].labelConfig ( "  Education Level  ",
                              acaFG_BLACK | acaBG_GREY), true );

// Specify an array of per-item color attributes for the Menu.
// In this example, progressive web-safe RGB colors are built.
// The divider item inherits the color of the menu control.
// (Note the extra element appended for safety.)
acaExpand acex ;
el00 = acex.buildRgb( true, wsrgbBLACK, 
                      true, WebSafeRGB(wsrgbBROWN + wsrgbSHADE_MED));
 ...
el10 = acex.buildRgb( true, WebSafeRGB(wsrgbRED + 9), 
                      true, WebSafeRGB(wsrgbGREY + wsrgbSHADE_MED));

short COLOR_ELEMENTS = 11;
acAttr acArray[COLOR_ELEMENTS + 1] =
   { el00, el01, el02, el03, el04, el05, el06, 
     acaUSEDFLT, el08, el09, el10, acaUSEDFLT };

skf_ptr->fld[1].colorConfig ( acArray, COLOR_ELEMENTS );
@end verbatim
@ifnothtml
@verbatim
┌────────────────── Biographical Data ──────────────────┐
│                                                       │
│                               Education Level         │
│  ╔Date Of Birth ═════╗  ┌──────────────────────────┐  │
│  ║02/29/1996         ║  │ Primary School Primate   │  │
│  ╚═══════════════════╝  │ Middle School Muskrat    │  │
│                         │ High School Hyena        │  │
│                         │ Associate of Animals     │  │
│                         │ Bachelor of Bulldookie   │  │
│                         │ Master of Monkey Dung    │  │
│                         │ Piled Higher and Deeper  │  │
│                         │ ──────────────────────── │  │
│                         │ School of Hard Knocks    │  │
│                         │ Ain't Got None           │  │
│                         │ Don't Wanna Know Nothin' │  │
│                         └──────────────────────────┘  │
│                                                       │
│                      ▒▒▒CLOSE▒▒▒                      │
└───────────────────────────────────────────────────────┘
@end verbatim
(Color attributes are not visible in the )@*
(info document but see the HTML document.)
@end ifnothtml
@ifhtml
@html
<div style=padding-left:4em;">
<div class="tscap" style="background-color:aqua; max-width:34.00em; line-height:1.165em;"><span class="brbl">┌────────────────── Biographical Data ──────────────────┐</span>
<span class="brbl">│</span><span style="background-color:aqua;">                                                       </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:aqua;">                            <span style="background-color:silver; font-weight:bold;">  Education Level  </span>        </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">┌──────────────────────────┐</span><span style="background-color:aqua;">   </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;"> ╔Date Of Birth ═════╗  </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:white; background-color:maroon;"> Primary School Primate   </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="background-color:aqua;">   </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;"> ║<span style="color:black; background-color:#FFFF00;">02/29/1996         </span>║  <span style="color:navy; background-color:#FF33FF;">│</span><span style="color:white; background-color:red;"> Middle School Muskrat    </span><span style="color:navy; background-color:#FF33FF;">│</span>   </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;"> ╚═══════════════════╝  </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:white; background-color:orange;"> High School Hyena        </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:black; background-color:yellow;"> Associate of Animals     </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:black; background-color:olive; "> Bachelor of Bulldookie   </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:white; background-color:purple;"> Master of Monkey Dung    </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:black; background-color:lime; font-weight:bold;"> Piled Higher and Deeper  </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│ ──────────────────────── │</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:maroon; background-color:gray;"> School of Hard Knocks    </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:red;    background-color:gray;"> Ain't Got None           </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">│</span><span style="color:orange; background-color:gray;"> Don't Wanna Know Nothin' </span><span style="color:navy; background-color:#FF33FF;">│</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="color:blue; background-color:aqua;">                        </span><span style="color:navy; background-color:#FF33FF;">└──────────────────────────┘</span>   <span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:aqua;">                                                       </span><span class="brbl">│</span>
<span class="brbl">│</span><span style="background-color:aqua;">                       <span style="font-weight:bold; color:#99FF00; background-color:red;">  CLOSE  </span>                       </span><span class="brbl">│</span>
<span class="brbl">└───────────────────────────────────────────────────────┘</span>
</div></div>
@end html
@end ifhtml
@spi

@anchor{getItem}
@cindex getItem
@cindex menu item
@item @b{bool getItem ( gString& iTxt, short& iNum, bool selnum = false ) const;}

@verbatim
  Input  :
     iTxt  : (by reference) receives item text data
     iNum  : (by reference) receives the index of the "item" referenced
             by the 'ip' member (item referenced by the cursor)
             (This is the 0-based item index.)
     selnum: (optional, default: false) for multi-row controls only 
             if set AND if a previously "selected" item (sitem >= zero), 
                return index of "selected" item.
             if reset, return index of item containing the IP.

  Returns: 'true'  if supported target control type (ftMB || ftSB), AND
                   if item identified
           else 'false'
@end verbatim

For Menus (ftMB) and Scrollbox controls (ftSB), retrieve the index 
of the @t{"item"} (row) containing the insertion point (@t{'ip'}).
Generally, this is the currently hightlighted item or the item 
which was highlighted when the control lost focus.

The @t{'@b{getItem}'} method returns both the item index and the 
actual text of the item.

The optional @t{'selnum'} parameter may be used to report either the 
target control's highlighted item @b{@emph{or}} the item (if any) 
@LDQ{}selected@RDQ{} by the user via the @t{Enter} or @t{Space} key.

The text of a menu item may contain an embedded hotkey indicator which 
is identified as the character following the caret (@t{'^'}). 
@w{Example @t{"Sa^ve file"}} where the @t{'v'} is the hotkey character.@*
This is described more fully in the chapter @ref{skField Data Members}.

This method will typically be called from an application callback function 
or immediately after a dialog window has closed.@*
@xref{EstablishCallback} or the @ref{Dialog} method's @t{'@b{callbk}'} 
parameter for more information on establishing and using callbacks.

Also, @pxref{GetFieldItem} which is a form-oriented method which provides 
information similar to @t{getItem}.
@spi

@H5heading{Understanding @LDQ{}Items@RDQ{},
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}
For purposes of this discussion, an @LDQ{}item@RDQ{} is a row of text 
displayed within the control.@*
For example, the following diagram shows the different types of menus: 
@b{a)} context menu, @b{b)} menu group sub-menu, and @b{c)} the 
@LSQ{}Menubar@RSQ{} (single-row menu).

@verbatim
     Context Menu          Group Submenu
   ┌────────────────┐
   │Open a file     │    │Open a file     │ <-- iNum == zero
   │Save file       │    │Save file       │
   │Close file      │    │Close file      │
   │Exit Application│    │Exit Application│ <-- iNum == 3
   └────────────────┘    └────────────────┘

   Example menubar:
   ----------------
          | File  Edit  View  Help |
            ↥     ↥     ↥     ↥
     item:  0     1     2     3

@end verbatim

Scrollbox controls (ftSB) typically contain plain, paragraph-oriented 
text data, not itemized data records; however, if desired, the application 
may define each display row of the Scrollbox control as a data item. 
This implements what is essentially a scrolling menu for situations 
where there are a large number of items to be displayed.@*
The following example is taken from the @ref{AcEdit Demo App} which displays 
a list of files in the current directory, and asks the user to 
select a file to be edited. This type of control can accomodate any 
reasonable number of items.@*
The @t{'▶'} indicator character, identifies the current item, and when the 
user presses the @t{Enter} or @t{Space} key, that item is @LDQ{}selected@RDQ{}. 
In the example, the indicator is on @t{AcEdit.cpp} and its item index 
is four(4).@*
When the Scrollbox loses focus, the selection indicator will be replaced by 
the @t{'▷'} character.

@verbatim
╔══════╣  Open a File For Editing  ╠════════╗
║  .. parent directory                      ║
║  > 1_TestData                             ║
║  · ace                                    ║
║  · ace.cfg                                ║
║▶ · AcEdit.cpp                             ║ <-- iNum == 4
║  · AcEdit.hpp                             ║
║  · AcEdit.o                               ║
║  · AcEditCfg.cpp                          ║
║  · AcEditCfg.o                            ║
║  · dbg.log                                ║
║  · gString.hpp                            ║
║ ───────────────────────────────────────── ║
║             OPEN       CANCEL             ║
╚═══════════════════════════════════════════╝
@end verbatim
@spi

@anchor{setHiliteMod}
@cindex setHiliteMod
@item @b{bool skField::setHiliteMod ( acAttr txtMod );}

@verbatim
  Input  :
     txtmod:
        text modifier attribute for highlighting text segments.
        One of the following text modifier attributes:
         acaBOLD      bold-text modifier
         acaITALIC    italic-text modifier
         acaUNDERLINE underline-text modifier (not recommended)
         acaOVERLINE  overline-text modifier
         acaXOUT      x-out (strikethrough) text modifier
         acaBLINK     blinking-text modifier
         acaCONCEAL   concealed (invisible) text
         acaREVERSE   reversed fgnd/bkgnd (default)
        The specified modifier flag _should not_ also be set
        as an element of control's base color attribute.
        Note: OR'd combinations of these modifiers are not allowed.

  Returns:
     'true'  if highlight attribute set successfully
     'false' if a) invalid modifier specified and discarded.
                   (default modifier, acaREVERSE, will be used)
                b) field type does not support text highlighting
@end verbatim

For Textbox (ftTB) controls, set the text-modifier attribute to be used for 
highlighted substrings.

The data member which contains this value is 'protected', that is, it 
is not available at the application level. This method can be called 
for any Textbox field in an initialized skForm object, before the 
window/dialog has been defined.

@verbatim
//* Define an skForm object with two controls. *
skForm* skfp = new skForm
(
   fldCOUNT,
   new skField[fldCOUNT]
   {
      //* Field index 0: ftTB (Textbox: fldTB_SEGMENT) *
      {
         ftTB,             // field type
         . . .
      },
      //* Field index 1: ftPB (Pushbutton: fldPB_FWRD) *
      {
         ftPB,                            // field type
         . . .
      },
   } ;
   . . .
);

//* Set the modifier for text highlight *
skfp->fld[0].setHiliteMod ( acaITALIC );

//* Define an ACWin object *
ACWin *win = new ACWin
      ( winROW, winCOL,           // position (upper-left corner) 
        winHEIGHT, winWIDTH,      // dimensions (height, width)
        ltDUAL,                   // border style
        acaBorder,                // border attributes
        acaInterior,              // interior attributes
        " Highlight Field Text ", // window title
        skfPtr
      ) ;
@end verbatim

To set the hilight modifier after the window has been created,@*
please @pxref{SetHilightMod} or @ref{HilightFieldText}.


@H6heading{Notes:,▔▔▔▔▔▔}

@enumerate a
@item The specified value will replace any previous highlight attribute.
@item If the HilightFieldText() method is called with any attribute value 
other than the default (acaUSEDFLT), that value will replace any value 
set by this method.
@item This method does not refresh the display, so the new highlight 
attribute will not be visible until the next time the field is refreshed.
@end enumerate
@spi


@anchor{getHilite}
@cindex getHilite
@item @b{bool getHilite ( int& begin, int& len, gString& gsTxt );}

@verbatim
  Input  :
     begin : (by reference) receives index of first (leftmost)
             character of highlighted text segment
     len   : (by reference) receives the number of characters in 
             the highlighted segment
     gsTxt : (by reference) receives a copy of the highlighted text
     hmod  : (optional, default:null pointer) if specified, target
             receives current text-modifier attribute used to highlight
             the text segment

  Returns:
     'true'  if highlighted text data successfullly captured.
     'false' a) target field contains no highlighted/selected text data
             b) field type does not support text highlighting
             If 'false', then 'begin' and 'len' are set to zero, 
             'hmod' is set to acaPLAINTEXT and 'gsTxt' is cleared
             (set to empty string).
@end verbatim

Returns a copy of highlighted text segment within a Textbox (ftTB) field.@*
This method was developed primarily for use during development; however, 
it may have other uses.

Conceptually similar to copying a @LDQ{}selected@RDQ{} text substring to 
the clipboard, except that the data are returned directly to caller without 
accessing the clipboard.

@i{@b{Technical Note:} This method does not distinguish between 
@LDQ{}highlighted@RDQ{} text and @LDQ{}selected@RDQ{} text.@*
The text delimited by the @t{'sela'} and @t{'selb'} members is returned 
regardless.}

Example:@*
This method is used in the callback function for the @ref{Test_Hilite} 
method of the @t{AnsiCmd} test suite. 
Refer to @t{thtCallback() in AnsiCmdTest.cpp} for details.

@example
gString gsOut, gs ;
skField skfld ;
int get_beg, get_len ;
acAttr get_hmod ;

win->GetFieldData ( ctrlIndex, skfld ) ;
skfld.getHilite ( get_beg, get_len, gs, &get_hmod ) ;
gsOut.compose( " Capture Highlight '%S' beg:%d len:%d hmod:%08X ",
               gs.gstr(), &get_beg, &get_len, &get_hmod ) ;
win->Footnote ( gsOut.gstr(), 35 ) ;
@end example

Please @pxref{HilightFieldText} for more information on text highlighting.
@end itemize
@sp 2

@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.05 skField Data Members  - - - - - - - - - - - - - - - - - - - - - - - -
@c         Initialization of skField data members  - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node skField Data Members
@unnumbered skField Data Members
@cindex 04.2.05 skField Data Members

The data members of the @t{skField} class support multiple types of 
user interface controls (@pxref{UI Control Types}).

Most of the members are public, that is, the application can initialize 
them and monitor modification arising from user interactions. Other 
members are @LDQ{}protected@RDQ{}, meaning that they are not directly 
available to the application. These members must be protected to 
maintain data integrity; however, most can be read and modified indirectly 
using public methods of the @t{ACWin} class, the @t{skForm} class, the 
@t{skField} class, or some combination of these.

Some public members must be initialized explicitly, while others can 
be used with default values. These defaults are listed here. 
@spi

@H5heading{Public Data Members,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

@itemize @EMDASH
@item @b{type}@*
Field Type: Specifies the type of field as a member of enum FldType.
The type of field defines how the user interacts with the field.@*
@xref{UI Control Types} for notes on the individual control types.

@item @b{hgt}@*
Height: This is the number of vertical rows for the field.@*
Minimum: 1 row for most types, but 2 rows for Menus@*
@verb{|        |} and Scrollbox controls.@*
Maximum: Height of parent window minus 2.

@item @b{wid}@*
Width : This is the number horizontal columns for the field.@*@*
Minimum: 1 column, but 3-6 columns is the @emph{practical}@*
@verb{|        |} minimum for most types.@*
Maximum: Width of parent window minus 2.

@item @b{orig}@*
This is the 0-based offset from the skForm's @t{'base'} coordinates,
which in turn is the 1-based offset from the upper-left corner 
of the terminal window.@*
Note that within an ACWin object, @t{'skForm.base'} is the same as 
the @t{'txtBase'} member of the ACWin object.@*
Minimum: 0,0 which is the upper left corner of the container.@*
Maximum: Height of (container-2) @emph{minus} @t{'hgt'}.@*
@verb{|        |} Width of (container-2) @emph{minus} @t{'wid'}.@*

@item @b{txt}@*
Text displayed in the field.@*
The initial text required for a control depends upon the control type, 
its dimensions and other factors. Pushbuttons, Radiobuttons, Menus and 
Scrolbox controls, for instance, contain only fixed text which is set 
when the control is initialized.@*
In contrast, Textbox controls may initially be empty or may contain any 
reasonable amount of formatted or unformatted text, which may then be 
updated either programatically or through user interaction.

The text of each field is managed within a gString object.@*
Please @pxref{gString Text Tool} for more information.@*
The amount of storage space allocated is calculated dynamically 
up to a limit if gsALLOCMAX (1.0 Megabyte).@*
To modify field text, please @pxref{SetFieldText}.

@item @b{aca}@*
Optional parameter, default: acaUSEDFLT.@*
This member holds the color attributes of the field, which is a 
@t{@b{logical OR}} of enum acAttr values.
If the default value is used, then field colors will inherited from 
the window interior attributes.@*
To modify this value, please @pxref{SetFieldAttr}.

@item @b{flow}@*
Optional parameter, default: floChar for multi-row textbox, 
floShift for all other types.@*
Flow control (multi-row Textbox fields only): This field contains a value from 
@b{enum FloType} and indicates the type of automatic formatting to be 
performed.@*
Please @pxref{SetFieldFlow} for a description of formatting options.

@item @b{ip}@*
Optional parameter, default: zero(0), upper left corner of field.@*
Insertion Point: This is the character index for the logical cursor 
position within the field. The position of the visible cursor is 
calculated from this value, and user input is inserted into the text 
at that point.@*
To modify this value, please @pxref{SetFieldIP}.

@item @b{ro}@*
Optional parameter, default: false.@*
Read Only: If set, the field cannot receive input focus. This means 
that the contents may be read but the data may not be modified under 
user control.@*
If reset, the field can receive input focus, and for Textbox controls, 
the user can modify the text of the field.@*
To modify this value, please @pxref{SetReadOnly}.

@item @b{bdr}@*
Optional parameter, default: false.@*
This flag may be set (@t{'true'}) to indicate that a border is to be 
drawn around the field.@*
Note that the @t{'bdr'} flag is public and may therefore be specified 
during instantiation; however the @t{'btype'} (border line type) and 
@t{'battr'} (border line color) are protected members, so if a 
non-default border is needed, it should be set after opening the window.@*
All types of controls support borders, @emph{except} Menus (ftMB), for 
which the border is built into the text of the control.@*
Please @pxref{SetFieldOutline} method for details.

@item @b{hide}@*
Optional parameter, default: false (except for menus).@*
If the field is set to hidden, it is not visible, and it will become 
visible and available to the user only if the associated hotkey 
(if any) is pressed; or if the application re-enables display of the field.@*
Menu controls are a special case, in that they are automatically set 
as invisible when they lose focus.@*
Please @pxref{SetFieldHidden} method for details.

@item @b{lock}@*
Optional parameter, default: true (except for menus).@*
The @t{'lock'} flag is primarily used to control visibility and 
accessibility of menu controls when they receive and lose the input focus.@*
When the @t{'lock'} flag is set, it indicates that the control is always 
visible in the window regardless of whether it has focus (unless is obscured 
by another control). When @t{'lock'} is reset, the menu field will be set as 
invisible and inactive when it loses focus (see 'hide' flag).@*
Exception: A Menubar control stays open if any member of its group 
has focus. This flag may also be used in combination with the @t{'hide'} 
flag to de-activate other types of fields which are not currently in use. 
This prevents wasted time refreshing fields which are fully obscured 
by other fields.@*
Currently, this flag is initialized during instantiation and may 
not be modified under program control. This decision may be revisited 
in a later release.

@item @b{state}@*
Optional parameter, default: false.@*
For Radiobuttons and other binary-state controls, this flag indicates 
the current state (set or reset i.e. @t{'true'} or @t{'false'}).@*
Please @pxref{SetFieldState} for more information.

@cindex hotkeys, direct
@item @b{hkey}@*
Optional parameter, default: null character ('\0'), no hotkey assigned.@*
Hotkey assigned to the control.@*
Valid values are the @t{GUI} keys (wcsALT_A, etc.) and function keys 
(wcsF01, etc.).@*
For Pushbuttons (ftPB) and Radiobuttons (ftRB), the hotkey (if any) is 
embedded within the text of the control, so for those control types, 
the @t{'hkey'} value is ignored.

While direct specification of hotkeys is valid for all other 
control types, this is recommended @emph{only} for Menu controls 
because Menu controls have no label.@*
For all other control types it is recommended that if a hotkey is 
desired, it should be embedded in the field label.@*
@xref{SetFieldLabel} and @ref{SetFieldHotkey} methods for details.

@item @b{grp}@*
Optional parameter, default: noGROUP i.e. null character ('\0')@*
For Radiobuttons, Menus and other control types which can be grouped.@*
Group members are identified by their shared use of this character. 
Any wchar_t (wide) character may be specified as the group indicator. 
This value is set during initialization and may not be modified afterward.

@item @b{mrptr}@*
This is a public const pointer to the protected MRParse object defined 
within this class. Because it is a @LDQ{}@b{const MRParse*}@RDQ, this 
means that the application layer may @t{VIEW BUT NOT MODIFY} the 
text-parsing data. Please study the MRParse class for a description of 
these data.@*
Please @pxref{GetFieldData} for accessing these data.@*
See also the @ref{dumpMrp2Log} method.
@end itemize
@spi

@hr40

@H5heading{Protected Data Members,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

@itemize @EMDASH
@item @b{mrp} (@LSQ{}protected@RSQ{} member, internal use only)@*
The @t{MRParse} object contains analytical data on the field contents 
including the number of text rows and the relative display position of 
the data within the control. Also included is both the logical and 
physical cursor position within the field.@*
These data are primarily for multi-row text fields; however, the 
information is also used to initialize the data contained by other 
control types.@*
To examine how this analysis is performed in the source code, see 
the private method: @t{'parseFieldText'}.@*
Please @pxref{GetFieldData} for accessing a copy of these data.

@item @b{lab} (@LSQ{}protected@RSQ{} member, internal use only)@*
This member contains the label text (if any) for the control.@*
Please @pxref{SetFieldLabel} for initializing a control label.

@item @b{lpos} (@LSQ{}protected@RSQ{} member, internal use only)@*
This is the display position for the control label relative to 
the container window.

@item @b{lattr} (@LSQ{}protected@RSQ{} member, internal use only)@*
Color attributes for the label text (if any).@*
Please @pxref{SetFieldLabel} for initializing a control label.

@item @b{battr} (@LSQ{}protected@RSQ{} member, internal use only)@*
Color attributes for the control outline (if any).@*
Please @pxref{SetFieldOutline} for initializing a control outline.

@item @b{cur} (@LSQ{}protected@RSQ{} member, internal use only)@*
This is a WinPos object and contains the 0-based offset from the 
control's @t{'orig'} coordinates which defines the position of 
the visible cursor. This value is dynamically calculated from the 
@t{'ip'} (insertion point) member.

@item @b{btype} (@LSQ{}protected@RSQ{} member, internal use only)@*
If an outline for the control has been specified, this is the 
outline type, a member of @t{enum LineType}, either @t{ltSINGLE} or 
@t{ltDUAL}.@*
Please @pxref{SetFieldOutline} for initializing a control outline.

@item @b{sitem} (@LSQ{}protected@RSQ{} member, internal use only)@*
For Menu (ftMB) controls and Scrollbox (ftSB) control only, the index 
of the @LSQ{}selected@RSQ{} item.@*
Please @pxref{GetFieldItem} for retrieving this value.

@item @b{iAttr} (@LSQ{}protected@RSQ{} member, internal use only)@*
By default, text data within a control is displayed using a single color 
attribute. For item-oriented data however, (specifically menu items), 
each item may be displayed in a different color. Both menus (ftMB) and 
scrollbox (ftSB) controls support item-oriented, multi-color data.@*
Please @pxref{SetFieldAttr} or the @ref{colorConfig} @t{skField}-class 
method for details.@*

@item @b{rbch} (@LSQ{}protected@RSQ{} member, internal use only)@*
For Radiobutton (ftRB) controls only, the display character used to 
indicate the @LDQ{}set@RDQ{} state of the control. Note that this 
character is extracted from the initialization text for the Radiobutton 
control.@*
Example: @t{"[♦] ^Authorize daily cookie delivery"}

@item @b{off} (@LSQ{}protected@RSQ{} member, internal use only)@*
Text Offset: Used when scrolling text vertically within a field to 
indicate the index of the first character of the top visible row.

@item @b{shft} (@LSQ{}protected@RSQ{} member, internal use only)@*
Text Shift: Used when scrolling text horizontally within a field to 
indicate the offset from the beginning of the text row to the first 
(leftmost) visible character.

@item @b{sela} and @b{selb} (@LSQ{}protected@RSQ{} members, internal use only)@*
These members are delimeters (indices) for @LDQ{}selected@RDQ{} 
text within the field. Selected text is identified by being 
@emph{underlined} within the control.@*
Selecting text is related to copy-and-paste operations. Text selection and 
the Copy, Cut and Paste operations are performed within Textbox (ftTB) 
controls only. Please @pxref{test T} for functional examples 
of these operations.@*
Invoke this test using: @w{@b{@t{./epts --test=Tea}}}
@end itemize
@sp 2

@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.06 UI Control Types  - - - - - - - - - - - - - - - - - - - - - - - - - -
@c         User interface controls - - - - - - - - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node UI Control Types
@unnumbered UI Control Types
@cindex 04.2.06 UI Control Types

@anchor{Field Types}
@anchor{enum FldType}
@cindex enum FldType
@cindex control types
@cindex field types
@cindex user interface controls
@H5heading{Field Types,▔▔▔▔▔▔▔▔▔▔▔}

The types of user-interface controls @t{"fields"} are defined by the 
@b{@t{FldType}} enumerated type.

@example
// Field Type for controls defined by the skField class
enum FldType : short
@{
   ftPB,          // PushButton (select)
   ftRB,          // Radio Button (on/off)
   ftTB,          // Text Box (edit text)
   ftSB,          // ScrollBox (view and scroll text)
   ftMB,          // Menu Box (select item)
@} ;
@end example

The data for each control type is initialized as an instance of the 
@b{@t{skField}} class.@*
@xref{skField Data Members} for a discussion of each data member.

@b{@verb{|   "Your focus determines your reality."|}}@*
@b{@verb{|   -- Qui-Gon Jinn|}}

To understand input fields, it is important to understand the concept 
of @LDQ{}@b{input focus}@RDQ{}. Input focus, or just @LDQ{}focus@RDQ{} 
can be defined as the point where keyboard input is received and processed. 

Just at the terminal's @t{'stdin'} stream receives key input 
from the user, the control which is currently monitoring the @t{stdin} 
stream (the control with focus) receives the key input and decides 
whether to process it directly (retain focus), or pass it on to another 
control (transfer focus). 

In general focus is transferred in response to one of the cursor keys:@*
Tab, Shift+Tab, Up/Down/Right/Left Arrow, PageUp, PageDown, Home, End; 
or by receipt of the @LDQ{}@b{hotkey}@RDQ{} assigned to a control. 
Under some circumstances, the Enter or Space keys can also trigger a 
shift in focus.

@itemize @SDIAMOND
@item @b{Pushbutton (ftPB):}@*
The most simple type of control is the @t{"@b{Pushbutton}"}.@*
Pusbutton controls process only two keycodes: @t{'Enter' and 'Space'}. 
Thus to @LDQ{}push@RDQ{} a Pushbutton means to press the Enter or 
Space key while the control has focus. The application will then 
determine what action is taken in response.@*
@verb{|   ▒▒▒OK▒▒▒  ▒▒CANCEL▒▒|}
@ifhtml
@sp 2
@end ifhtml

@item @b{Radiobutton (ftRB):}@*
Radiobuttons are very similar in function to Pushbuttons in that 
they respond directly only to the @t{'Enter' and 'Space'} keys.@*

Radiobuttons are so called because their function resembles that of 
the buttons on archaic car radios. They have two states: either 
@LDQ{}ON@RDQ{} or @LDQ{}OFF@RDQ{}.

A Radiobutton can be a stand-alone control, or can be configured as 
a member of an XOR Radiobutton group. The term@LDQ{}XOR@RDQ{} is 
nerd-speak for @LDQ{}Exclusive OR@RDQ{}, meaning that exacty one 
button of the group may be ON at any given moment. All other buttons 
of the group are reset (OFF) when any member of the group is set (ON).@*
@verb{|   [ ] Small|}@*
@verb{|   [◆] Medium|}@*
@verb{|   [ ] Large|}@*
@verb{|   [ ] Extra Large|}@*
@verb{|   [ ] XX Large|}@*
@verb{|   [ ] XXX Large|}

If an application-level callback function is active, it can immediately 
respond to the control's change in state, or action can be deferred 
until the window or dialog is closed, or until some other criteria 
are met.

@item @b{Textbox (ftTB):}@*
Textbox controls are as the name implies a way to collect text data 
from the user. The input can be monitored on a per-character basis or 
collected as a unit when user shifts the focus to another control.
Textbox controls may optionally be outlined.
@example
┌─────────────────┤ ZMail - Create ├─────────────────┐
│Dear Mom and Dad,                                   │
│Sorry I won't be able to make it home for Christmas │
│this year, but if you could send me $500, I'd be    │
│happy to get you a Christmas gift.                  │
│ -- Your loving daughter, Anita                     │
└────────────────────────────────────────────────────┘
@end example

One special characteristic of Textbox controls is that they can 
receive data directly from the clipboard or send data to the clipboard.@*
@xref{Communicate With System Clipboard} for more information.

@item @b{Scrollbox (ftSB):}@*
The function of a Scrollbox control depends upon the type of data 
it contains. The Scrollbox can display plain, paragraph-oriented text 
data, @b{@emph{or}} it can be configured as a scrolling list of items. 
Scrollbox controls may optionally be outlined.

When configured to display ordinary text, the user may scroll upward 
and downward through the data. Horizontal scrolling is not supported.
@example
┌─────────────────────────────────────────────────────┐
│ There once was a man from Kirkuk,                   │
│ Who was known far and wide for his luck,            │
│ Till while jogging one day, he looked the wrong way,│
│ Whereupon he was hit by a truck.                    │
└─────────────────────────────────────────────────────┘
@end example

When configured as a list of individual item (one per line), then 
the user can scroll through the data and @LDQ{}select@RDQ{} any 
item, just as an item is selected from a Menu control (see below).
@example
┌Select Your Ride────────────────────┐
│  1951 Studebaker Starlight Coupe   │
│▶ 1967 Chevy Camero                 │
│  1971 Dodbge Super Bee             │
│  1977 Ford Bronco                  │
└────────────────────────────────────┘
@end example

@item @b{Menu (ftMB):}@*
Menu controls are a special case in that there are three 
distinct types of menus, each performing a different task:

@enumerate 1
@item @b{Menubar:}@
The Menubar is a single-row menu that acts as a anchor point for a 
group of menus which are functionally tied together. This is a common 
construct used in almost every @t{GUI} application.@*
A Menubar may be initially invisible, but if desired, can be locked 
in the visible state.@*
The Firefox browser menubar is:@*
@verb{|File  Edit  View  History  Bookmarks  Tools  Help|}@*
@verb{|▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔|}@*
Each item in the Menu bar is associated with at least one sub-menu, 
which together form the menu system for the application.

@item @b{Sub-menu:}@*
Sub-menus are menus attached to a Menubar (as described above). 
A sub-menu is invisible by default, and is opened by an action 
taken on the Menubar, or in combination with the Menubar 
via an application-defined hotkey.
@example
FILE   EDIT   HELP
▔▔▔▔▔▔▔│▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔│▔▔▔▔▔▔▔▔
       │Copy Selection   (C-c)│
       │Cut Selection    (C-x)│
       │Paste Clipboard  (C-v)│
       │Find Text        (C-f)│
       └──────────────────────┘
@end example

@item @b{Context Menu}@*
A @LDQ{}Context menu@RDQ{} is a stand-alone menu that operates in 
a specific @LDQ{}context@RDQ{}. (duh!)

A context menu is generally defined as invisible until it is needed; and 
becomes invisible again after a selection is made. It is possible, 
however, to lock a context menu in the visible state.
@example
┌─────────────────┐
│View Contents    │
│View file Stats  │
│Open (execute)   │
│Find Link Target │
│Cancel           │
└─────────────────┘
@end example

The context menu shown is from the author's @t{FileMangler} application@*
@xref{By the Same Author} for a description.

@end enumerate
@end itemize

Numerous functional examples of these controls are available throughout 
the test applications included in the @t{AnsiCmd} library.@*
Please @pxref{Development and Testing} for a general description of 
the tests available. Specifically, the tests listed under @ref{test W} 
and @ref{test D}, which contain subtests for Windows, skForm/skField 
and Dialogs invoked with:@*
@verb{|   ./epts --test=W|}@*
@verb{|   ./epts --test=D|}@*
The @t{AcEdit} application includes a functional set of controls 
in an (almost) real-world context.@*
@verb{|   cd AcEdit|}@*
@verb{|   ./ace|}@*
@sp 2

@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.2.07 skForm Initialization   - - - - - - - - - - - - - - - - - - - - - - -
@c         Sample initialization of skForm - - - - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node skForm Initialization
@unnumbered skForm Initialization
@cindex 04.2.07 skForm Initialization

To create an skForm template, allocate a new object specifying the number 
of fields, the global parameters and the definition for each field. 

@ifnothtml
@verbatim
   ┌─────────┤ ACWin-class Window ├─────────┐
   │ ┌────────────────────────────────────┐ │
   │ │▒▒▒▒▒▒Me love cookies! Cookie!▒▒▒▒▒▒│ │
   │ └────────────────────────────────────┘ │
   │                                        │
   │  [◆] Authorize daily cookie delivery   │
   │      ▔                                 │
   │            ▒▒Close Window▒▒            │
   │              ▔                         │
   └────────────────────────────────────────┘
@end verbatim
@end ifnothtml
@ifhtml
@html
<div style=padding-left:18em;">
<div class="tscap" style="text-color:inherit; background-color:inherit; max-width:22.85em; line-height:1.165em;">
<span class="brgy">┌─────────┤<span class="xxxx"> ACWin-class Window </span>├─────────┐</span>
<span class="brgy">│</span><span class="br_n"> <span class="br_n">┌────────────────────────────────────┐</span> </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n"> <span class="br_n">│</span><span class="cy_r">      Me love cookies! Cookie!      </span><span class="br_n">│</span> </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n"> <span class="br_n">└────────────────────────────────────┘</span> </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                                        </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">  <span class="bl_n">[♦]</span><span class="br_n"> <span class="ulin">A</span>uthorize daily cookie delivery</span>   </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                                        </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">            <span class="re_r">  <span style="text-decoration:underline">C</span>lose Window  </span>            </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                                        </span><span class="brgy">│</span>
<span class="brgy">└────────────────────────────────────────┘</span>
</div></div>
@end html
@end ifhtml

Define the skForm template:@*
This example creates an skForm object with three(3) fields: a Textbox (ftTB), 
a Radiobutton control (ftRB) and a Pushbutton control (ftPB).

Note that many parameters of these constructors have default values, but for 
clarity, they are explicity initialized here. See skForm and skField 
initialization constructors, above for details.

The working code for this example can be found in the @t{'Test_Cookie'} method 
in @t{AnsiCmdTest.cpp}.

@example
//* Focus Color: for controls which can change color when *
//* they have input focus. (Pushbuttons, Radiobuttons)    *
acAttr focusAttr = acAttr(acaFGb_GREY | acaBG_RED) ;
//* Non-Focus (embedded) color for Pushbuttons and Radiobuttons. *
acAttr nonFocus  = acAttr(acaFG_BLACK | acaBG_RED) ;
WinPos wpul( 1, 2 ) ;                  // vertical/horizontal offsets
const short pbFIELD   = 2 ;            // index of pushbutton field
const short FLD_COUNT = 3 ;            // number of fields

skForm *skfPtr = new skForm
(
   FLD_COUNT,                 // number of skField objects in 'fldArray'
   new skField[FLD_COUNT]     // array of field definitions
   @{
      //* Field index 0: ftTB (Textbox) *
      @{
      ftTB,                            // field type
      1,                               // field height (in rows)
      winWIDTH - 6,                    // field width (in columns)
      wpul.row, wpul.col,              // Y/X offset in window
      "      Me love cookies! Cookie!",// initial field text
      acAttr(acaFG_DFLT | acaBG_CYAN), // color attributes for text
      floShift,               // text formatting option (text-editor mode)
      ZERO,                            // insertion point (cursor offset)
      false,                           // user accessible (not read-only)
      true,                            // field outline enabled
      false,                           // field is visible (not hidden)
      true,                            // access lock enabled
      false,                  // binary state not applicable to ftTB
      NULLCHAR,                        // no hotkey specified
      noGROUP                          // not a group member
      @},
      //* Field index 1: ftRB (Radiobutton) *
      @{
      ftRB,                            // field type
      1,                               // field height (in rows)
      winWIDTH - 6,                    // field width (in columns)
      short(wpul.row += 3), wpul.col,  // Y/X offset in window
                                       // field text with Hotkey '^A'
      "[♦] ^Authorize daily cookie delivery", 
      acAttr(acaFG_BLUE | acaBG_GREY), // color attributes (non-focus)
      floShift,                        // text formatting option
      ZERO,                            // insertion point (cursor offset)
      false,                           // user accessible (not read-only)
      false,                           // field outline enabled
      false,                           // field is visible (not hidden)
      true,                            // access lock enabled
      true,                            // initial binary state: 'set'
      NULLCHAR,                        // no hotkey (embedded in text)
      noGROUP                          // not a group member
      @},
      //* Field index 2: ftPB (Pushbutton) *
      @{
      ftPB,                            // field type
      1,                               // field height (in rows)
      16,                              // field width (in columns)
      short(wpul.row += 2),            // Y/X offset in window
      short(winWIDTH / 2 - 9),
      "  ^Close Window  ",             // field text with Hotkey '^C'
      nonFocus,                        // color attributes
      floShift,                        // text formatting option
      ZERO,                            // insertion point (cursor offset)
      false,                           // user accessible (not read-only)
      false,                           // field outline enabled
      false,                           // field is visible (not hidden)
      true,                            // access lock enabled
      false,                           // initial binary state: 'reset'
      NULLCHAR,                        // no hotkey (embedded in text)
      noGROUP                          // not a group member
      @}
   @},
   //* Optional skForm arguments *
   // 'fldIndex'  index of field with initial focus (the Pushbutton)
   pbFIELD,
   // 'fldAttr'   color attributes for control with focus
   focusAttr,
   // 'noisy'     beep on unhandled keycode received
   true,
   // 'ioFlag'    initial state of Insert/Overstrike flag
   true,
   // 'ioToggle'  user access to Insert/Overstrike mode
   true,
   // 'ioCursor'  enable cursor shape change for Insert/Overstrike
   true,
   // 'insCursor' cursor shape when Insert mode
   csBblock,
   // 'ovrCursor' cursor shape when Overstrike mode
   csBuline
) ;                                    
@end example

The initialized skForm template is then passed as a parameter for the 
ACWin constructor. @xref{ACWin constructor}.

@example
ACWin *winPtr = new ACWin
      ( winROW, winCOL, 
        winHEIGHT, winWIDTH,
        ltSINGLE,
        acAttr(acaFGb_BROWN | acaBG_BLUE),
        acAttr(acaFG_RED | acaBG_GREY),
        " ACWin-class Window ",
        skfPtr  // partially-initialized skForm object
      ) ;
      
//* The setup data may now be safely deleted. (prevent memory leaks) *
delete skfPtr ; skfPtr = NULL ;

//* Open the window (make it visible) *
winPtr->OpenWindow () ;

//* Get User Input : Returns when Pushbutton control is selected,*
//* either by "pressing it" (Enter/Space) or via hotkey (ALT+C). *
short fieldIndex ;   // on return contains index of exit field
winPtr->EditForm ( fieldIndex, pbFIELD ) ;

//* Close the window and delete the ACWin object.*
winPtr->CloseWindow ();
delete winPtr;
@end example

Note that the example above does not specify a callback function. The 
@t{'EditForm'} method returns when user the selects the Pushbutton control. 
In the more sophisticated examples, the callback function determines 
when the edit loop should be terminated.@*
Please @pxref{EstablishCallback} for more information.
@sp 1

@H5heading{User Interaction - the skForm class and skField class,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

Initialization of an @t{skForm} object as a parameter for creating an 
@t{ACWin} window is shown above.

Accessing the form provides a user interface, via the fields defined by 
the @t{skForm} object.

After the ACWin object has been created, and the window has been opened, 
the @ref{EditForm} method is called to give the user access to the field(s).

Example of calling the EditForm method. This is a copy of the code 
used in the @ref{Test_Cookie} test method. See screenshot above.

@smallverbatim{
  //* Define an ACWin object *
  ACWin *winPtr = new ACWin
        ( winROW, winCOL, 
          winHEIGHT, winWIDTH,
          ltSINGLE,
          acAttr(acaFGb_BROWN | acaBG_BLUE),
          acAttr(acaFG_RED | acaBG_GREY),
          "  Window Formatted With \"skForm\" ",
          skfPtr  // partially-initialized skForm object
        ) ;

  //* Open the window (make it visible) *
  winPtr->OpenWindow () ;

  //* Get User Input : Returns when enter key is pressed.*
  short fieldIndex ;   // on return contains index of exit field
  winPtr->EditForm ( fldIndex, wcsENTER ) ;

  //* Get a pointer to final field configuration, *
  //* and retrive final text and button state.    *
  const skForm* skfp = winPtr->GetForm () ;
  gString finalText = skfp->fld[0].txt ; // contexts of textbox
  bool finalRadio = skfp->fld[1].state ; // state of radiobutton flag

  //* Close the window and delete the object.*
  winPtr->CloseWindow () ;
  delete winPtr ;}
@spi

@verb{|--- --- --- --- ---|}@*
@i{The @t{skForm} object is fully integrated into the ACWin-class window; 
however, it is possible to make it visually @b{@emph{appear}} that the fields 
defined within the @t{skForm} object are independent from the enclosing 
window.@*
If desired, the @t{skForm} object can be displayed in an 
@LDQ{}@b{@emph{invisible}}@RDQ{} (borderless) window. In fact, many of the 
@t{skForm} tests included with the AnsiCmd library use a borderless window. 
See the @t{Test_SoftEcho} tests for examples of this usage.}
@sp 2

@raisesections
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@c 04.3.00 Dialog sub-Windows  - - - - - - - - - - - - - - - - - - - - - - - - -
@c         Configure and invoke sub-windows  - - - - - - - - - - - - - - - - - -
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node Dialog sub-Windows
@unnumbered Dialog sub-Windows
@cindex 04.3.00 Dialog sub-Windows
@anchor{ACDlg Class}
@cindex ACDlg class
@cindex class, ACDlg

@Subsubheading{What is a Dialog?,.................}

A @LDQ{}window@RDQ{}, (@ref{ACWin Class}) is a sub-window within the 
terminal window. In turn, a @LDQ{}dialog@RDQ{}, as defined within 
this project, is a sub-window created within the @t{ACWin} parent window.

Dialog sub-windows are based on the @b{@t{ACDlg}} class. The @t{ACDlg} 
class is constructed as a simplified version of the @t{ACWin} class and 
shares many characteristics with @t{ACWin}.

The greatest difference is that all methods and data of the @t{ACDlg} 
class are @LDQ{}protected@RDQ{}. This means that it's methods and data 
are not directly available at the application level. All access is 
through specialized methods of the @t{ACWin} parent class.

A dialog may be invoked to alert the user to some issue or to gather 
information from the user which it would be inconvenient for the 
parent window to request directly.

Dialogs are self-contained objects@EMDASH{}that is, there are no 
post-launch methods for modification of the displayed data, and for 
the @LDQ{}quick@RDQ{} dialog, there is no callback method for monitoring user 
activity within the dialog.@*
This is in contrast to the ACWin-class window which may be updated at any 
time under application control. 

Two types of dialogs are defined:@*
@ @ 1) the @LDQ{}quick@RDQ{} dialog, and@*
@ @ 2) the @LDQ{}full initialization@RDQ{} dialog.

A common type of information dialog is to alert the user that she has 
made an invalid request.
@example
 ┌───────────────────────────────────────────────┐ 
 │ You may not delete the boot partition, Dummy! │ 
 │                                               │ 
 │                     CLOSE                     │ 
 └───────────────────────────────────────────────┘
@end example

A common type of decision dialog is to ask the user a yes-or-no question.
@example
┌───────────────────────────────────────────────┐ 
│ Are you sure you want to discard your changes │ 
│ to this document?                             │ 
│               DISCARD   CANCEL                │ 
└───────────────────────────────────────────────┘ 
@end example

It is of course possible to configure the dialog to ask more complex 
questions, such as: 
@example
┌───────────────────────────────────────────────┐
│    >>>  When will you pay your taxes?  <<<    │
│                                               │
│      [◆] April 15th   [ ] December 31st       │
│      [ ] When Hell Freezes Over               │
│                                               │
│      ASK_AGAIN_TOMORROW    BUZZ_OFF!          │
└───────────────────────────────────────────────┘
@end example

Please refer to the chapter describing Dialog testing @pxref{test D} 
for functional dialog examples.

The user interface for a dialog is an @b{@t{skForm}} structure, the same 
type of structure used by the parent window; however, for Quick dialogs, 
the skForm structure is automatically generated. For the full-initialization 
dialog, the application designer may specify all user-interface 
configuration parameters.@*
Please @pxref{skForm Class} for a discussion of configuring the user interface.
@sp 1

@Subheading{Technical Info About Dialog Objects,
            -----------------------------------}

@Subsubheading{Size and position of the dialog:,
               ................................}

Three factors determine the dimensions of the dialog:
@format 
 1) the dimensions of the parent window 
 2) the space needed to display the static text and dialog controls 
 3) the position of the dialog (offset within the parent window)
@end format
 
Validating the Parameters: A significant amount of defensive programming is 
needed to ensure that the dialog does not extend into or beyond the borders 
of the parent window. Even so, the application programer could trash the 
display if determined to do so. @i{(Your mother would be so proud...)} 

Dialog height, width, vertical offset and horizontal offset may be 
specified directly as invocation parameters, or may be dynamically 
calculated based upon the dimensions of the static text to be displayed.

@enumerate 1
@item A height of zero (0) indicates that the vertical dimension should 
be derived from the height of the static text plus top and bottom 
borders (plus one row which is assumed to be occupied by one or more controls).
@enumerate a
@item If the dimensions of the received text will not fit within 
the available space, the text will be automatically reformatted 
based on the specified dialog width and vertical/horizontal offsets 
(if specified) and the space available for the dialog.
@end enumerate
@item If a VALID height is specified (ZERO < dlgHgt < maxHgt), then that 
      value will anchor the dimensioning calculations.
@enumerate a
@item If specified height is out-of-range, it will be set to 
the available height.
@end enumerate
@item A width of zero (0) indicates that the horizontal 
dimension should be derived from the width of the static 
text plus left and right borders (plus 2 columns for 
left/right indentation).
@item If a VALID width is specified (ZERO < dlgWid < maxWid), 
the static text will be automatically reformatted as necessary 
to fit the specified dimension.
@item The number, width and position of the controls are also 
factors in determining the height and width of the dialog.@*
Note that it is impractical to programatically resize the dialog 
to accomodate the defined controls. The only check is whether the 
size and position of controls violate the borders of the dialog object. 
Please use care in specifying the dialog dimensions to contain the 
defined controls. 
@item Yes, there is method to this madness. This design fascilitates 
automatic resizing of the dialog (if necessary) while maintaining the 
relative positions of the dialog controls. 

If neither positioning nor dimensioning adjustments will keep the 
dialog within the available space, then the static text will be 
truncated and if necessary, the controls will be discarded. 
This guarantees that the dialog will open successfully, although 
its appearance may come as a surprise.
@end enumerate

@Subsubheading{Positioning of Dialog Controls:,
               ...............................}

@enumerate A
@item Vertical offset: orig.row@*
@enumerate a
@item Positive values specify an offset from the top border of the dialog.@*
Range: 1 through dialog height minus one@*
A value of zero(0) is not valid, and will be converted to 1.@*
Example: For a dialog of 12 rows, the range would be:@*
@verb{|      1 <= offset <= 10|}
 
@item Negative values specify an offset from the bottom border of the dialog.@*
Range: -1 through negative dialog height minus one@*
Example: For a dialog of 12 rows, the range would be:@* 
@verb{|      -1 >= offset >= -10|}
@end enumerate
 
@item Horizontal offset: orig.col@* 
This value represents the offset in columns from the center of the dialog.
@enumerate a
@item A zero(0) indicates that the control is centered between the left 
        and right borders. 
@item A positive value is a rightward offset from the center. 
@item A negative value is a leftward offset from the center.@*
@verbatim
Example: 
For a dialog with a width of 31 columns, the range would be:
-14 <= offset <= 14 
  11111987654321012345678911111 
  43210         -         01234 

For a dialog of 30 columns, the range would be: 
-14 <= offset <= 13 
  1111198765432101234567891111 
  43210         -         0123
@end verbatim
@end enumerate
@end enumerate
@spi

@hr40
@sp 1

@cindex QuickDialog
@Subheading{Quick Dialog Configuration,..........................}

@ifnothtml
@b{bool QuickDialog ( const gString& gsMsg, bool query, @*
@verb{|                   |}const char* title = NULL, @*
@verb{|                   |}short height = 0, short width = 0, @*
@verb{|                   |}short vOff = 0, short hOff = -1, @*
@verb{|                   |}short timeout = 0, bool dbg = false );}
@end ifnothtml
@ifhtml
@b{bool QuickDialog ( const gString& gsMsg, bool query, const char* title = NULL, @*
@verb{|                |}short height = 0, short width = 0, short vOff = 0, short hOff = -1, @*
@verb{|                |}short timeout = 0, bool dbg = false );}
@end ifhtml
@sp 1

@H5heading{Description of Parameters,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

@enumerate A
@item Only two(2) parameters are required:@*
@ @ 1) the message to be displayed@*
@ @ 2) the type of user interaction: informational or query.@*
All other parameters are optional.

@item A title for the dialog window may optionally be specified.@*
If specified, the dialog title will be displayed in the top border of 
the dialog and horizontally centered. See example below.

@item The dimensions (height and width) of the dialog are based on 
the text rows and columns required to display the formatted message data@*
@w{                    @b{@emph{unless}}}@*
text would extend beyond the available vertical or horizontal space 
@b{@emph{or}} would extend beyond the dimensions specified by the 
optional dimension parameters, in which case, the text will be automatically 
reformatted.@*
@ @ - Note that if the text must be reformatted, the flag enabling@*
@ @ @ @ line breaks on hyphen-like characters is set.@*
Please @pxref{acFormatParagraph} for a discussion of automatic text 
formatting.@*

The optional @t{'@b{height}'} and @t{'@b{width}'} may be used to override 
the formatting of the message text @t{'@b{gsMsg}'}.

@item Minimum Dimensions:@*
@itemize @EMDASH
@item The dialog height must be at least four(4) rows: top border, text row, 
pushbutton row and bottom border.
@item The dialog width must be at least four(4) columns PLUS the width of the 
pushbutton(s). The width of the pushbuttons is determined by the the 
label text and whether there is one pushbutton (info dialog) or two 
(decision dialog). The default (English) label text is of the form:@*
@w{                  @t{@b{"__OK__  _CANCEL_"}}}@*
(16 columns for a decision dialog, or six columns for an info dialog)
@end itemize

@item Maximum Dimensions:
@itemize @EMDASH
@item The width of the dialog plus the horizontal offset must not cause the 
dialog to extend into the border of the parent window.
@item The height of the dialog plus the vertical offset must not cause the 
dialog to extend into the border of the parent window.
@end itemize

@item Dialog offset from from origin (upper-left corner) of parent window.@*
The @t{'@b{vOff}'} parameter is the vertical offset from the top of the 
parent window.@*
By default, @t{'vOff'} is set to zero, which means that the dialog is 
positioned at the top row of the parent window.@*
The special value of -1 indicates that the dialog is to be vertically 
centered in the parent window.

The @t{'@b{hOff}'} parameter is the horizontal offset from the left 
edge of the parent window.@*
By default, @t{'hOff'} is set to -1 indicating that the dialog is to be 
horizontally centered in the parent window.

If the combined offset and dialog dimension would obscure the parent 
window's border, the dialog offset and/or dialog dimensions will be adjusted 
so that the dialog will be displayed entirely within the parent window.
@itemize @EMDASH
@item In no case will the parent window's border be obscured.
@item In no case will the dialog be less than minimum size in either dimension.
@item In no case will the dialog fail to open.
@end itemize

@item A QuickDialog window has either one or two Pushbutton controls which are 
automatically generated by the call.

The language for the text of the pushbutton controls is matched to the 
active "locale" (at least for the languages we know): English, Spanish, 
Chinese (simplified) and Vietnamese. The language defaults to English 
if the locale is not one of the recognized locales.@*
@i{@ @ @ @ Our ancient Greek and Sanskrit would probably be worthless@*
@ @ @ @ here, as they are under most circumstances. :-)}@*
@verb{|         |} संस्कृतं भव्यं लिखितभाषा अस्ति
@c Sanskrit is a magnificent written language.

@verbatim
  const short LANGS = 4 ;
  const wchar_t *ymsg[LANGS] =  // default pushbutton messages
  {
     L"  ^OK  ",                // English
     L" ^.好的 ",               // Zhongwen (Hǎo de)
     L" De ^Acuerdo ",          // Español
     L" ^Tốt "                  // Tieng Viet
  } ;
  const wchar_t *nmsg[LANGS] = 
  {
     L" ^CANCEL ",              // English
     L"  ^,取消  ",             // Zhongwen (Qǔxiāo)
     L" ^Cancelar ",            // Español
     L" ^Hủy Bỏ  "              // Tieng Viet
  } ;
@end verbatim
Support for additional languages may be added easily by extending these 
arrays; testing for the associated system locale, and setting the 
language index accordingly.

@i{A special case of the information dialog is the @LDQ{}automatic-timeout@RDQ{} 
dialog which has no user-interface controls. It is displayed for a specified 
amount of time, then closes automatically.}

@item The dialog's message text (gsMsg) is positioned vertically at the 
top interior row of the dialog, and is indented horizontally by one column 
from the left edge of the dialog interior.

@end enumerate
@spi

@hr40

@cindex Dialog method
@Subheading{Full-initialization Dialog Configuration,
            ........................................}

@ifnothtml
@b{bool Dialog ( short dlgHgt, short dlgWid, @*
@verb{|             |} skForm* formDef, @*
@verb{|             |} const char* sTxt = NULL, @*
@verb{|             |} const char* tTxt = NULL, @*
@verb{|             |} short vOff = -1, short hOff = -1, @*
@verb{|             |} LineType ltype = ltSINGLE, @*
@verb{|             |} acAttr bdrAttr = acaUSEDFLT, @*
@verb{|             |} acAttr txtAttr = acaUSEDFLT, @*
@verb{|             |} short tvOff = 0, short thOff = 1, @*
@verb{|             |} CUPTR callbk = NULL, @*
@verb{|             |} bool dbg = false );}
@end ifnothtml
@ifhtml
@b{bool Dialog ( short dlgHgt, short dlgWid, skForm* formDef, @*
@verb{|          |} const char* sTxt = NULL, const char* tTxt = NULL, @*
@verb{|          |} short vOff = -1, short hOff = -1, LineType ltype = ltSINGLE, @*
@verb{|          |} acAttr bdrAttr = acaUSEDFLT, acAttr txtAttr = acaUSEDFLT, @*
@verb{|          |} short tvOff = 0, short thOff = 1, @*
@verb{|          |} CUPTR callbk = NULL, bool dbg = false );}
@end ifhtml
@sp 1

@H5heading{Description of Parameters,
           ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

Three(3) parameters are required: dlgHgt, dlgWid and formDef.@*
All other parameters are optional, and if not specified, receive default 
values as described above.

@enumerate A
@item @LSQ{}@b{dlgHgt}@RSQ{} Dialog Height@*
An absolute height (number of display rows) may be specified by setting 
the 'dHgt' parameter to a value >= the arbitrary minimum of four(4) rows 
and less than the height of the parent window MINUS 'vOff'.

@format
Automatic calculation of the dialog height is specified by setting 
the 'dHgt' parameter to zero.
-- If the display text is pre-formatted, then the height of the text 
   (plus padding) determines the height of the dialog.
   -- "padding" includes the upper and lower borders plus one(1) 
      internal row.
-- If the dialog height cannot be determined directly from the source 
   text, or if the source text is taller than the available space, 
   then the text may be automatically reformatted (and if necessary, 
   truncated) to fit within the available space.
   The dialog height will then be the height of the reformatted text 
   plus padding.
-- See also the note below about dialog controls.
@end format

@item @LSQ{}@b{dlgWid}@RSQ{} Dialog Width@*
An absolute width number of display columns) may be specified by setting 
the 'dlgWid' parameter to a value >= the arbitrary minimum of eight(8) 
columns and no larger than the interior width of the parent window 
@emph{MINUS} 'hOff'.

@format
Automatic calculation of the dialog width is specified by setting the 
'dWid' parameter to zero.
-- If the display text is pre-formatted, then the width of the text 
   (plus padding) determines the width of the dialog.
   -- "padding" includes the left and right borders plus two(2) 
      internal columns.
-- If the dialog width cannot be determined directly from the source 
   text, or if the source text is wider than the available space, 
   then the text may be automatically reformatted to fit within 
   the available space.
   The dialog width will then be the width of the reformatted text 
   plus padding.
-- See also the note below about dialog controls.
@end format

@item @LSQ{}@b{formDef}@RSQ{} Controls defined by an skForm object@*
For a detailed discussion of the @t{skForm} class and its @t{skField}-class 
array, please @pxref{skForm Class}.

All control types defined by @ref{enum FldType} are supported within 
a dialog window, with the following limitations:

@itemize @SSQUARE
@item Although the skForm class does not place an upper limit on the number 
of controls, the range of controls in a dialog is limited to: 
@ifnothtml
@*
@ @ @ 
@end ifnothtml
@verb{|1 <= count <= MAX_DLG_CTRLS|}

@item At least one defined control must be a Pushbutton (ftPB)@*
To exit the dialog, the user must select any defined Pushbutton control, 
either by placing focus on the control and pressing the Enter (or Space) 
key, or via the hotkey defined for the control.@*
Optionally, exiting the dialog can be signalled from within the callback 
function if specified. In that case, dialog exit via Pushbutton is not 
mandatory.

@item Textbox control (ftTB) height is limited to one row.@*
@smalltext{(Although Textbox controls are designed as multi-row controls, the 
decision was made to limit the height within dialog windows in order 
to greatly simplify the user-interface algorithm. We may revisit 
this decision in a later release.)}

@item Menu controls (ftMB) are supported, but are limited to 
@b{@t{'context'}} menus (multi-item stand-alone menus) only; AND 
unlike context menus defined in the parent window, the menu will 
automatically be set as always visible.@*
@smalltext{(Enforcing menu visibility in this way significantly enhances 
the efficiency of the display refresh routine. We may revisit this 
decision in a later release.)}

@item Control outlines and external labels:@*
Within a dialog, the data members that define outlines and labels are 
@LSQ{}protected@RSQ{} members; that is, they may not be directly modified 
at the application level. Two specialized public methods of the skField 
class are available to configure these options:
@sp 1
@verbatim
  bool outlineConfig ( LineType lType, acAttr lAttr );
  bool labelConfig ( const char* labText, acAttr labAttr, bool center );
@end verbatim

Please @pxref{skField Public Methods} for details.

@item Color attribute customization:@*
Customization of text color attributes is often useful to enhance readability. 
For multi-row controls which contain fixed display text, color attributes 
for each individual display row may be specified. These are multi-row 
Menu controls (ftMB) and Scrollbox controls (ftSB) @b{@emph{only}}.

Within a dialog, the data member which defines per-item color attributes 
is @LSQ{}protected@RSQ{}, that is, it may not be directly modified at the 
application level. A specialized method of the @t{skField} class is 
available to configure this option:
@verb{|  bool colorConfig ( const acAttr* rowAttr, short rowCnt );|}@*
Please @pxref{skField Public Methods} for details.
@end itemize
@spi

@item @LSQ{}@b{sTxt}@RSQ{} Static text within the dialog@*
Static text is any text written directly to the dialog interior and 
that is not within any dialog control object.

The static text and the controls may occupy the same space without 
error. For instance the text may be above, below and on either side 
of a control. Just be sure that the text is not obscured by the control. 
To do this, the static text should contain only spaces (or newlines @t{'\n'}) 
under the area occupied by the control and the control label (if any).

For example, the following static text data will be rendered 
in a dialog with two Pushbutton controls as shown.

@ifhtml
@sp 1
@end ifhtml

@smallexample
 "This application cannot honor your request\n"
 "for cookie delivery. Use DoorDash, OR:\n"
 "\n"
 "You may actually need to leave your parents'\n"
 "basement to find them. Sorry about that...\n"
 " " ;

@ifnothtml 
┌──────────────┤ ACWin-class Window ├──────────────┐
│                                                  │
│ ┌──────────────┤  Nerd Alert!  ├───────────────┐ │
│ │ This application cannot honor your request   │ │
│ │ for cookie delivery. Use DoorDash, OR:       │ │
│ │             ▒▒Call A Therapist▒▒             │ │
│ │ You may actually need to leave your parents' │ │
│ │ basement to find them. Sorry about that...   │ │
│ │                                              │ │
│ │               ▒▒Exit Dialog▒▒                │ │
│ └──────────────────────────────────────────────┘ │
│                                                  │
│           ▒▒▒▒▒▒Me love cookies!▒▒▒▒▒▒           │
│                                                  │
│       [◆] Authorize daily cookie delivery        │
│                                                  │
│                 ▒▒Close Window▒▒                 │
└──────────────────────────────────────────────────┘
@end ifnothtml
@ifhtml
@html
<div class="tscap" style="text-color:inherit; background-color:inherit; max-width:22.85em; line-height:1.165em;">
<span class="brgy">┌──────────────┤<span class="xxxx"> ACWin-class Window </span>├──────────────┐</span>
<span class="brgy">│</span><span class="br_n">                                                  </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> ┌──────────────┤  Nerd Alert!  ├───────────────┐ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │</span><span class="bl_n"> This application cannot honor your request   </span><span class="bl_n">│</span><span class="br_n"> </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │</span><span class="bl_n"> for cookie delivery. Use DoorDash, OR:       </span><span class="bl_n">│ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │             <span class="gy_r">  Call_A_Therapist  </span>             │ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │</span><span class="bl_n"> You may actually need to leave your parents' </span><span class="bl_n">│ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │</span><span class="bl_n"> basement to find them. Sorry about that...   </span><span class="bl_n">│ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │                                              │ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> │               <span class="re_r">  Exit_Dialog  </span>                │ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="bl_n"> └──────────────────────────────────────────────┘ </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">      <span class="br_n">┌────────────────────────────────────┐</span>      </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">      <span class="br_n">│</span><span class="cy_r">      Me love cookies! Cookie!      </span><span class="br_n">│</span>      </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">      <span class="br_n">└────────────────────────────────────┘</span>      </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                                                  </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">      <span class="bl_n">[♦]</span><span class="br_n"> <span class="ulin">A</span>uthorize daily cookie delivery</span>         </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                                                  </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                <span class="re_r">  <span style="text-decoration:underline">C</span>lose Window  </span>                  </span><span class="brgy">│</span>
<span class="brgy">│</span><span class="br_n">                                                  </span><span class="brgy">│</span>
<span class="brgy">└──────────────────────────────────────────────────┘</span>
</div>
@end html
@end ifhtml
@end smallexample

@item @LSQ{}@b{tTxt}@RSQ{} Text of dialog title@*
If specified, the dialog title will be displayed in the top border of 
the dialog and horizontally centered.

For optimal display, it is recommended that the first and last characters 
of the title text be spaces, although this is not enforced.@*
@ @ @ Example: @t{ "  Nerd Alert!  "}.@*
The text will be truncated if necessary to fit within the width of the dialog.

The title text will be bracketed by delimiter characters corresponding 
to the border style and color specified for the dialog as shown in the 
example above.

@item @LSQ{}@b{vOff}@RSQ{} Vertical offset of dialog in parent window@*
This is the (0-based) offset in rows from top of parent window. 
This parameter is optional, and the default value is minus one (-1), 
indicating that the dialog is to be centered vertically in the parent window.

@item @LSQ{}@b{hOff}@RSQ{} Horizontal offset of dialog in parent window@*
This is the (0-based) offset in columns, from left edge of the 
parent window. This parameter is optional, and the default value 
is minus one (-1), indicating that the dialog is to be centered 
horizontally in the parent window.

@item @LSQ{}@b{lType}@RSQ{} Border style@*
This optional parameter specifies the border style as a member of 
@t{enum LineType}. By default, the border is drawn with a single-width 
line (ltSINGLE), but a dual-width line (ltDUAL) may be specified.

@item @LSQ{}@b{bAttr}@RSQ{} Border color@*
This optional parameter specifies the border color attributes.@*
By default, the dialog inherits the border colors from the parent 
window; however, any foreground/background color attribute may be 
specified.@*
@xref{enum acAttr, acAttr Enumerated Type}, for more information 
on color attribute specification.

@item @LSQ{}@b{tAttr}@RSQ{} Interior text color@*
This optional parameter specifies the color attributes for the 
interior of the dialog (static text and dialog background).@*
By default, the dialog inherits the interior color attributes 
from the parent window; however, any foreground/background color 
attribute may be specified.@*
@xref{enum acAttr, acAttr Enumerated Type}, for more information 
on color attribute specification.

@item @LSQ{}@b{tvOff}@RSQ{} Vertical offfset for static text@*
This optional parameter specifies the vertical offset at which 
to draw the dialog static text.@*
By default, @t{'tvOff'} is set to zero, indicating that the 
static text is to be drawn starting on the top row of the 
dialog interior.@*
A positive value indicates an additional vertical offset.@*

@item @LSQ{}@b{thOff}@RSQ{} Horizontal offfset for static text@*
This optional parameter specifies the horizontal offset at which 
to draw the dialog static text.@*
By default, @t{'thOff'} is set to one(1), indicating that the 
static text is to be drawn starting at one column from the 
left edge of the dialog interior. A positive value indicates 
an additional horizontal offset.

@anchor{Dialog Callback}
@cindex dialog callback
@cindex callback, dialog
@item @LSQ{}@b{callbk}@RSQ{} Pointer to a non-member callback function.@*
The full-initialization dialog supports an external callback function 
which can be used to monitor user activity within the dialog window.

The callback functionality for a dialog is identical in most respects 
to a callback function for the the parent window. 

@enumerate a
@item The callback is invoked using the same @t{CUPTR} template 
(macro), but instead of calling the @ref{EstablishCallback} method, 
the @t{CUPTR} is passed as a parameter to the @t{Dialog} method.@*
The callback function is based on the the following template:@*
@b{@verb{|  typedef wchar_t (*CUPTR)( short ctrlIndex, |}
@ifnothtml
@*@verb{|                           |}
@end ifnothtml
@verb{|wchar_t wkey, bool firstTime );|}}@*

@item User interactions with the dialog's controls can be monitored 
and directed just as they are in the parent window; however, 
window-specific methods of the @t{ACWin} class are not applicable to dialogs.

@item For this reason, the @t{ACWin} class defines several dialog-specific 
methods for use by dialog callback functions:
@example
Dialog_GetText
Dialog_SetText
Dialog_GetItem
Dialog_GetState
Dialog_GetStateXOR
Dialog_GetField
Dialog_Write
Dialog_Refresh
@end example
Please @pxref{Dialog-Oriented Methods} for details.

@item Each of these methods is demonstrated in the @ref{AcEdit Demo App} 
utility. The developer may find it instructive to study this method; 
therefore, the full callback source (version 0.0.04) is presented 
below: (@pxref{example callback}).
@end enumerate

@item @LSQ{}@b{dbg}@RSQ{} (for debugging only)
If this flag is set, it allows the dialog window to remain open after 
control is returned to the application. This is useful during testing 
for verification that the reported results correspond to the visual data.
@end enumerate
@spi

@anchor{example callback}
@cindex callback example
@H5heading{Example Dialog Callback,▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔}

The working code for this example is located in the @b{@t{AcEditMenu.cpp}} 
module, @b{@t{sfaCallback}} method. This callback monitors user 
specification of a filename for the @w{save-file-as} operation. 
The user may traverse the the filesystem tree to select the target 
directory and specify a filename for the data to be written to that 
directory.

@smallverbatim{//***** Static, non-member function directing *****
//***** callback to member method.            *****
static wchar_t nonmember_dlgCallback ( short ctrlIndex, wchar_t wkey, 
                                       bool firstTime )
{
   return ( (aceditPtr->sfaCallback ( ctrlIndex, wkey, firstTime )) ) ;
}  //* End nonmember_dlgCallback() *
}

@smallverbatim{//***** AcEdit member method invoked as the *****
//***** Callback method for saveFileAs()    *****
wchar_t AcEdit::sfaCallback ( short ctrlIndex, wchar_t wkey, 
                              bool firstTime )
{
   static const char* Warn_Dupe[uilENV] =
   { // Warn field width is 28 columns.
      "Error, file already exists.",   // English
      "错误，文件已存在。",               // Zhongwen
   } ;
   static const char* Warn_Name[uilENV] = 
   {
      "Invalid filename characters.",  // English
      "错误，文件名中包含无效字符。",      // Zhongwen
   } ;
   static const char* Warn_Access[uilENV] =
   {
      "Unable to access target dir!",  // English
      "无法访问目标目录！",               // Zhongwen
   } ;
   static const char* noName[uilENV] = 
   {
      "  Filename not specified.",     // English
      "       未指定文件名。",           // Zhongwen
   } ;
   static const char* Cancel_Msg[uilENV] = 
   {
      "    Operation Cancelled.",      // English
      "      重命名操作已取消。",         // Zhongwen
   } ;

   // dialog row where filter message is displayed
   const short filterMsgRow = 10 ;
   // set if warning message is visible
   static bool warnMsg = false ;
   gString gs, gsCwd, gsName, gsList ;
   const skField* skfPtr = NULL ;// pointer to a control within the dialog
   acAttr* acArray = NULL ;   // pointer to array of Scrollbox attributes
   short itemCnt ;            // number of items in Scrollbox control
   short item ;               // Scrollbox item selected
   bool  vfat ;               // state of text filter Radiobutton
                              // (set==VFAT compatible)

   //*------------*
   //* First call *
   //*------------*
   if ( firstTime )
   { /* Nothing to do at this time. */ }

   //* If a warning message is currently displayed, erase it. *
   if ( warnMsg )
   {
      gs.clear() ;
      this->win->Dialog_SetText( sfaWARN, gs ) ;
      warnMsg = false ;
   }

   //* Note that the hotkey for a field has been automagically  *
   //* converted to wcsENTER.                                   *
   if ( (wkey == wcsENTER) || (wkey == wcsSPACE) )
   {
      switch ( ctrlIndex )
      {
         case sfaSAVE:
            // retrieve filename data
            this->win->Dialog_GetText ( sfaTEXT, gsName ) ;
            if ( (gsName.gschars()) > 1 )
            {
               //* Validate the filename characters.                *
               //* Radiobutton state determines which filter to use.*
               this->win->Dialog_GetState ( sfaVFAT, vfat ) ;
               if ( !(this->isFilename ( gsName, false, vfat )) )
               {
                  //* Warn of invalid filename character(s) *
                  gs = Warn_Name[this->lang] ;
                  this->win->Dialog_SetText( sfaWARN, gs ) ;
                  warnMsg = true ;  // remember that warning was posted
                  wkey = NULLCHAR ; // keycode handled
               }
               else
               {
                  // Get Scrollbox text. Compare user-provided filename
                  // with each filename in the array of filenames in CWD.
                  this->win->Dialog_GetField ( sfaCWD, skfPtr ) ;
                  gsCwd = skfPtr->txt ;
                  // pointer to source data
                  const wchar_t* wsrc = gsCwd.gstr() ;
                  wchar_t wtrg[MAX_FNAME] ;      // filename target buffer
                  int   wchars = gsCwd.gschars(),// source characters
                        si = ZERO,
                        ti = ZERO ;              // target index
                  bool match = false ;           // set if duplicate name
                  //* Step over the "parent-dir" item at top of list.*
                  while ( (si < wchars) && (wsrc[si] != NEWLINE) )
                     ++si ;
                  ++si ;

                  //* Extract each filename *
                  for( ; si < wchars ; ++si )
                  {
                     while ( (wsrc[si] != NEWLINE) && 
                             (wsrc[si] != NULLCHAR) )
                        wtrg[ti++] = wsrc[si++] ;
                     wtrg[ti] = NULLCHAR ; // terminate the string
                     ti = ZERO ;           // reset target index
                     gs = wtrg ;           // load raw data item
                     gs.shiftChars( -3 ) ; // discard item prefix
                     gs.strip() ; // strip leading/trailing whitespace
                     //* Compare with user's filename *
                     if ( (gsName.compare( gs )) == ZERO )
                     { match = true ; break ; }
                  }

                  //* If user's data matches an existing    *
                  //* filename in CWD, warn of duplication. *
                  if ( match )
                  {
                     gs = Warn_Dupe[this->lang] ;
                     this->win->Dialog_SetText( sfaWARN, gs ) ;
                     warnMsg = true ;  // remember that warning was posted
                     wkey = NULLCHAR ; // keycode handled
                  }

                  //* Else, a valid, non-duplicate filename    *
                  //* specified. Signal that dialog s/b closed.*
                  //* Filename is in Textbox control.          *
                  else
                     wkey = wcsCTL_4 ;
               }
            }
            else     // empty filename string
            {
               gs = noName[this->lang] ;
               this->win->Dialog_SetText( sfaWARN, gs ) ;
               this->win->nsleep ( 20 ) ;
               wkey = wcsCTL_4 ;
            }
            break ;

         case sfaCANCEL:                  // Cancel pushbutton
            gs = Cancel_Msg[this->lang] ;
            this->win->Dialog_SetText( sfaWARN, gs ) ;
            this->win->nsleep ( 16 ) ;
            wkey = wcsCTL_4 ;
            break ;

         case sfaCWD:         // Scrollbox display of CWD files
            //* Get a copy of "selected" item *
            if ( (this->win->Dialog_GetItem ( sfaCWD, gs, item )) )
            {
               // isolate indicator character
               wchar_t indyChar = *gs.gstr() ;
               gsName = &gs.gstr()[2] ;    // item text without prefix

               //* Move to parent directory or subdirectory *
               if ( (indyChar == PCHAR) || (indyChar == DCHAR) )
               {
                  //* Get filespec of CWD *
                  if ( !(this->getCWD ( gsCwd )) ) { gsCwd = L"." ; }
                  if ( indyChar == PCHAR )   // moving to parent directory
                  {
                     gs = gsCwd ;
                     this->ExtractPathname ( gsCwd, gs ) ;
                  }
                  else                       // moving to subdirectory
                     gsCwd.append( "/%S", gsName.gstr() ) ;

                  if ( (this->setCWD ( gsCwd )) )
                  {
                     //* Scan new CWD and format the entries.  *
                     // Create an array of color attributes to *
                     //* match the records                     *
                     this->win->Dialog_GetField ( sfaCWD, skfPtr ) ;
                     itemCnt = this->readCwd ( gsList, acArray, 
                                               skfPtr->wid ) ;
                     // Update text data, and array of color attributes.
                     // Programmer's Note: Refresh is not performed after
                     // text update, but is performed only after attribute
                     // update.
                     this->win->Dialog_SetText ( ctrlIndex, gsList, 
                                                 acaUSEDFLT, false ) ;
                     this->win->Dialog_SetAttr ( ctrlIndex, acArray, 
                                                 itemCnt ) ;

                     // release the dynamic allocation
                     if ( acArray != NULL )
                     { delete[] acArray ; acArray = NULL ; }
                     //* Signal caller that operation is compete.*
                     wkey = NULLCHAR ;
                  }
                  else
                  { //* Malformed filespec OR user lacks read access *
                     gs = Warn_Access[this->lang] ;
                     this->win->Dialog_SetText( sfaWARN, gs ) ;
                     warnMsg = true ;  // remember that warning was posted
                     wkey = NULLCHAR ; // keycode handled
                  }
               }
               else                    // non-directory filename
                  this->win->Dialog_SetText ( sfaTEXT, gsName ) ;
            }
            // else(call is unlikely to fail)
            break ;

         case sfaVFAT:
            //* State of Radiobutton is being toggled.          *
            //* Match the filter message with Radiobutton state *
            //* NOTE: The state flag has not yet been updated   *
            //* at this point, so the sense is reversed.        *
            this->win->Dialog_GetState ( sfaVFAT, vfat ) ;
            gs = sfaFilterMsg[this->lang][(vfat ? 0 : 1)] ;
            this->win->Dialog_Write ( gs.gstr(), filterMsgRow, 0, true ) ;
            break ;
      } ;
   }
   return wkey ;

}  //* End sfaCallback() *
}
@sp 2
@raisesections
@c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


