Functions and Directives

Function MemoEdit() Foundation

Displays and/or edits text or memo fields.

MemoEdit( [<cString>]   , ;
          [<nTop>]      , ;
          [<nLeft>]     , ;
          [<nBottom>]   , ;
          [<nRight>]    , ;
          [<lEditMode>] , ;
          [<bcUserFunc>], ;
          [<nLineLen>]  , ;
          [<nTabSize>]  , ;
          [<nBufferRow>], ;
          [<nBufferCol>], ;
          [<nWindowRow>], ;
          [<nWindowCol>]  ) --> cTextBuffer
<cString> contains a character string or the contents of a memo field. This character string is copied into the text buffer for MemoEdit() and can then be displayed and/or edited. When <cString>is not specified, MemoEdit() begins with an empty text buffer.
<nTop> is an integer numeric value specifying the top screen row at which the edit window is displayed by MemoEdit(). The four arguments <nTop>, <nLeft>, <nBottom> and <nRight> determine the screen coordinates for the edit window. Row positions for the window can range from zero to MaxRow() and column positions can range from zero to MaxCol().
<nLeft> is an integer numeric value specifying the left screen column for the edit window display. The default value is zero.
<nBottom> is an integer numeric value specifying the bottom row for the edit window display. The default value is MaxRow().
<nRight> is an integer numeric value specifying the right screen column for the edit window display. The default value is MaxCol().
<lEditMode> is used to select either the edit or the display mode. If .T. (true) is specified, the text buffer can be edited. When the value .F. (false) is specified for <lEditMode>, the text buffer is displayed and the user can only browse (not edit) the text buffer. The default value is .T. (true).
<bcUserFunc> can contain a code block, a character string with the name of a user-defined function or the value .F. (false). When <bcUserFunc> contains the value .F., MemoEdit() displays <cString> and then terminates immediately. When <bcUserFunc>contains a code block, it is executed after each keypress not processed by MemoEdit(). Similarly, when the function name of a user function is passed as a character string (without parentheses), this function is called after each keypress not processed by MemoEdit(). If a function name is specified, the function must not be declared STATIC. A code block, however, can call a STATIC FUNCTION.
The argument <nLineLen> specifies the length of a line where MemoEdit() automatically performs a word wrap. When <nLineLen> is greater than the width of the edit window and an attempt is made to move the cursor past the window border, the text is scrolled horizontally. <nRight> - <nLeft> is used as the default value for <nLineLen>.
<nTabSize> specifies the number of blank spaces inserted into the text when the tab key (K_TAB) is pressed. By default four blank spaces are inserted by K_TAB.
<nBufferRow> is an integer numeric value specifying the text row where the cursor is positioned when MemoEdit() is called. The value range for <nBufferRow> is from one to the entire number of rows in <cString>. The default value is one. <nBufferRow> and <nBufferCol> position the cursor within the text buffer, while <nWindowRow> and <nWindowCol> determine the initial position of the cursor in the edit window.
<nBufferCol> is an integer numeric value indicating the column within the text row specified by <nBufferRow> where the cursor is positioned when MemoEdit() is called. The value range for <nBufferCol> is from zero to <nLineLen>. The default value is zero.
<nWindowRow> specifies the row within the edit window where the cursor is positioned when MemoEdit() is called. The value range for <nWindowRow> is from zero to <nBottom> - <nTop>. The default value is zero.
<nWindowCol> specifies the column within the edit window where the cursor is positioned when MemoEdit() is called. The value range for <nWindowCol> is from zero and to <nRight> - <nLeft>. The default value is zero.

The return value of MemoEdit() is dependent on the key used to terminate the editing procedure. When a user terminates with the Esc key (K_ESC), MemoEdit() returns a copy of <cString>. If the editing procedure is terminated by the key combination CTRL+W (K_CTRL_W), MemoEdit() returns the edited text buffer.


The MemoEdit() function allows the display and the editing of formatted character strings. Using this function, a memo field or text string is processed. An edit window is displayed which can be positioned anywhere on the screen. When the edit window is displayed, the previously displayed screen area is overwritten without first being saved.

The MemoEdit() Textbuffer

MemoEdit() manages an internal text buffer into which the text or the memo field to be edited is copied. When no value is specified for <cString>, MemoEdit() begins the editing procedure with an empty text buffer. MemoEdit() terminates the editing procedure when the Esc key (K_ESC) is pressed or when the keys CTRL+W (K_CTRL_W) are pressed. When the keys CTRL+W (K_CTRL_W) are pressed, the content of the text buffer is returned. When the Esc key (K_ESC) is pressed, the text buffer is discarded and the original text is returned.

Browsing text

If the value .F. (false) is specified for the argument <lEditMode>, the text buffer from MemoEdit() cannot be edited. A user can merely browse through the text with the cursor keys.

Editing text

By default the value for <lEditMode> is .T. (true) allowing the text buffer to be edited using MemoEdit(). During editing, MemoEdit() differentiates between overwrite mode and insert mode. In overwrite mode characters are overwritten in the text buffer, while in insert mode characters are inserted in the text buffer at the current cursor position. Pressing the insert key while MemoEdit() is active (K_INS) switches between these two modes.

By default, MemoEdit() writes all alphanumeric keys, all punctuation characters and the characters Carriage-Return Line-Feed (hard return) into the text buffer. The cursor keys for navigating through the text buffer and some other keys are not written into the text buffer, but processed internally. A complete list of the keys which MemoEdit() processes internally is in the following table:

MemoEdit() Service and editing keys
Key Inkey constant Action
Printable character Inserts character
Up Arrow K_UP | K_CTRL_E Next line up
Down Arrow K_DOWN | K_CTRL_X Next line down
Left Arrow K_LEFT | K_CTRL_S Previous character
Right Arrow K_RIGHT | K_CTRL_D Next character
Home K_HOME Beginning of a line
End K_END End of a line
Page Up K_PGUP Next screen up
Page Down K_PGDN Next screen down
Ctrl+Left Arrow K_CTRL_LEFT | K_CTRL_A Previous word
Ctrl+Right Arrow K_CTRL_RIGHT | K_CTRL_F Next word
Ctrl+Home K_CTRL_HOME Beginning of the window
Ctrl+End K_CTRL_END End of the window
Ctrl+Page Up K_CTRL_PGUP Beginning of text buffer
Ctrl+Page Down K_CTRL_PGDN End of text buffer
Return K_RETURN Beginning of next line
Delete K_DEL Deletes current character
Insert K_INS | K_CTRL_V Switches insertion mode
Backspace K_BS Deletes character left
Tab K_TAB Inserts blank spaces
Ctrl+Y K_CTRL_Y Deletes line
Ctrl+T K_CTRL_T Deletes next word
Ctrl+B K_CTRL_B Reformats paragraph
Ctrl+W K_CTRL_W Ends, saves text
Esc K_ESC Ends, text not saved

Mouse navigation with MemoEdit()

If the function SetMouse(.T.) is called before MemoEdit(), the cursor can be positioned within the edit window by a click of the left mouse button. If MemoEdit() is used with Xbase Parts in hybrid mode, events for Xbase Parts are automatically sent to the applicable Xbase Part and not processed by MemoEdit().

Word wrap using MemoEdit()

As soon as the current line in the text buffer is longer than the setting given with <nLineLen>, MemoEdit() automatically performs a word wrap. The characters Chr(141)+Chr(10) are inserted in the text buffer. These characters represent a "soft" return and allow accelerated redisplay of memo fields after they have been edited once. Before the output of memo fields, the soft return must be deleted from the text. The functions HardCR() and MemoTran() can be used to accomplish this. To explicitly include a "hard" return (Chr(13)+Chr(10)) in the text buffer, MemoEdit() must be in insert mode and the Return key must be pressed.

MemoEdit() with a user function

The functionality of MemoEdit() can be modified by the argument <bcUserFunc>. <bcUserFunc> contains either the value .F. (false), a character string with the name of a function, or a code block.

When <bcUserFunc> contains the value .F., MemoEdit() terminates immediately after the edit window has been filled with text. This value is used only to refresh the edit window.

When <bcUserFunc> contains a function name, the corresponding function may not be declared STATIC and must be specified as a character string without parentheses ().

When <bcUserFunc> contains a code block, it must contain the function call of a user function. If called within the code block, a user function can be declared STATIC.

The user function allows the user-specific configuration of individual keys for MemoEdit(). MemoEdit() differentiates between configurable and non-configurable keys. Non-configurable keys are processed automatically by MemoEdit(). Configurable keys are all function keys as well as Ctrl and Alt combinations. When MemoEdit() is passed a value for <bcUserFunc>, MemoEdit() calls the user function (or evaluates the code block) when a key is pressed which MemoEdit() does not automatically process. Such configurable keys can be processed in the user function and the RETURN value of the user function is used to notify MemoEdit() of how to react to the key.

When MemoEdit() calls a user function, it passes three numeric values to the function: the current MemoEdit() mode, the current row, and the current column of the text buffer.

The current row and column indicate the cursor position within the text buffer. The row position begins with the value one and the column position with the value zero. Both values are normally displayed by the function on the screen as information for the user.

The mode designates the present condition of MemoEdit() and depends on the last pressed key or the last action executed by MemoEdit() prior to the call to the user function. In the header file symbolic constants are defined which identify the various conditions of MemoEdit():

Modes of MemoEdit() (see
Constant Description
ME_IDLE Idle, all keys processed
ME_UNKEY Key unknown, text is still unchanged
ME_UNKEYX Key unknown text is already changed
ME_INIT Initialization is running

The value ME_IDLE means that no more keys are available for processing and MemoEdit() is waiting for a new keypress. Each time MemoEdit() does not find another value in the keyboard buffer the user function is called once and then MemoEdit() waits for a new keypress. Before MemoEdit() goes idle, it is customary for the current row and column position (second and third arguments of the user function) to be displayed on the screen.

With the modes ME_UNKEY and ME_UNKEYX MemoEdit() signals that an unknown or configurable key is available for processing. When this occurs, the value ME_UNKEY is passed to the user function if the text buffer has not yet changed. If the text buffer has changed, MemoEdit() passes the value ME_UNKEYX. The action which MemoEdit() is to execute after a configurable key has been pressed is defined by the return value of the user function. A return value of zero causes MemoEdit() to execute the default action. If a value not equal to zero is returned, MemoEdit() executes the specified action. Symbolic constants are defined in the header file for the possible return values of the user function. These identify the various MemoEdit() actions which can be requested based on the value returned from the user function:

Return values of the MemoEdit() user function (see Action
ME_DEFAULT Executes default action
ME_UNKEY Executes action corresponding to the key value
ME_IGNORE Ignores key
ME_DATA Treats key as a character
ME_TOGGLEWRAP Turns word wrap on or off
ME_TOGGLESCROLL Turns scroll on or off
ME_WORDRIGHT Goes to the next word to the right
ME_BOTTOMRIGHT Goes to the last character in the window

When processing configurable keys, MemoEdit() executes the action specified by the return value of the user function. When <bcUserFunc> is specified, the following keys are configurable, but MemoEdit() processes these keys itself when no user function exists:

Configurable keys for MemoEdit()
Key Inkey constant Default action
Insert K_INS | K_CTRL_V Switches insertion mode
Ctrl+Y K_CTRL_Y Deletes line
Ctrl+T K_CTRL_T Deletes word right
Ctrl+B K_CTRL_B Reformats paragraph
Ctrl+W K_CTRL_W Ends, saves text
Esc K_ESC Ends, does not save text

Initialization of MemoEdit() in the user function

When <bcUserFunc> is specified, the user function is executed immediately after the call of MemoEdit(). MemoEdit() passes the value ME_INIT to the user function as the first parameter to indicate that the function is in the initialization phase. The user function is called repeatedly during the initialization phase until it returns the value ME_DEFAULT to MemoEdit().

During the initialization, MemoEdit() can be modified by the return value of the user function. The automatic word wrap (ME_TOGGLEWRAP) or the scroll (ME_TOGGLESCROLL) can be switched off, for example.

As soon as the user function returns the value ME_DEFAULT, the text buffer is displayed and, depending on <lEditMode>, MemoEdit() allows editing or browsing the text buffer.

Other notes for MemoEdit()

The automatic word wrap can be turned on or off in the user function when the value ME_TOGGLEWRAP is returned to MemoEdit(). When the word wrap is turned on (default value), MemoEdit() inserts a "soft" return (Chr(141)+Chr(10)) into a line as soon as the current line is longer than <nLineLen>. Individual words are not broken at <nLineLen>. Instead, the entire word is wrapped to the next line.

When word wrap is turned off, the text buffer is scrolled horizontally until the cursor is at the end of the line. The return key must then be pressed to bring the cursor to the start of the next line.

The key combination Ctrl+B causes MemoEdit() to reformat and redisplay the current paragraph up to the paragraph end (Chr(13)+Chr(10)). This causes all "soft" returns (Chr(141)+Chr(10)) within the paragraph to be reorganized.

Processing text files with MemoEdit()

The contents of text files can be edited with MemoEdit(). The file must be read into a memory variable with MemoRead() and after editing the memory variable must be written back into the file with the function MemoWrit(). There is no limitation to the size of text files edited with MemoEdit().

// The example shows two possible uses of MemoEdit() in 
// connection with memo fields. 
// The first call of MemoEdit() merely displays the contents of a 
// memo field, the second call allows the memo field to be edited. 


   USE Address NEW 

   MemoEdit( Address->Memo, 5, 10, 20, 60, .F., .F.) 

   REPLACE Address->Memo WITH ; 
      MemoEdit( Address->Memo, 5, 10, 20, 60, .T.) 

MemoEdit() with a user function

// In the example, a UDF is illustrated which will edit 
// text files. MemoEdit() calls a user function in which 
// the row and column position are displayed on the screen, 
// the cursor indicates the insert mode, and some configurable 
// keys are provided with a MemoEdit() action. 
#include "" 
#include "" 
#include "" 

STATIC snLeft, snBottom 


   ? FileEdit( "TEST.PRG", 2, 2, 22, 76 ) 


* Edit function for text files 
FUNCTION FileEdit( cFilename, nTop, nLeft, nBottom, nRight ) 
   LOCAL cString  := MemoRead( cFilename ) 
   LOCAL cScreen  := SaveScreen( nTop, nLeft, nBottom, nRight ) 

   snBottom := nBottom          // row and column for 
   snLeft   := nLeft + 1        // screen output in UserFunc() 

   DispBox( nTop, nLeft, nBottom, nRight, 2 ) 
   @ nTop, nLeft+1 SAY PadC(cFileName, nRight-nLeft-1, Chr(205) ) 

   cString := MemoEdit( cString    , ; 
                        nTop   + 1 , ; 
                        nLeft  + 1 , ; 
                        nBottom- 1 , ; 
                        nRight - 1 , ; 
                        .T.        , ; 
                        "UserFunc"   ) 

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

RETURN MemoWrit( cFilename, cString ) 

* User function for MemoEdit() 
FUNCTION UserFunc( nMode, nRow, nCol ) 
   LOCAL nKey    := LastKey() 
   LOCAL nReturn := ME_DEFAULT         // default return value 

   CASE nMode == ME_IDLE               // display position in the 
      SetPos( snBottom, snLeft )       // text buffer 
      ?? "Row:", Str(nRow,4), "Column:", Str(nCol,2) 

   CASE nMode == ME_UNKEY .OR. nMode == ME_UNKEYX 

      DO CASE 
      CASE nKey == K_F7                // word right with F7 
         nReturn:= ME_WORDRIGHT 

      CASE nKey == K_F8                // last character in the 
         nReturn:= ME_BOTTOMRIGHT      // window with F8 

      CASE nKey == K_F9                // switch word wrap 
         nReturn:= ME_TOGGLEWRAP       // with F9 

      CASE nKey == K_F10               // switch scroll 
         nReturn:= ME_TOGGLESCROLL     // with F10 

      CASE nKey == K_CTRL_RET          // save with Ctrl-Return 
         nReturn:= K_CTRL_W 

      CASE nKey == K_INS               // display cursor based 
         IF SetCursor() == SC_SPECIAL1 // on insert mode 
            SetCursor( SC_NORMAL ) 
            SetCursor( SC_SPECIAL1 ) 

   OTHERWISE                           // on initialization 
      nReturn := IIf( Set(_SET_INSERT), 0, K_INS ) 
                                       // switch to the insertion 
      SetCursor( SC_SPECIAL1 )         // mode by default 


RETURN nReturn 

MemoEdit() with a search function

// An extensive MemoEdit() routine with search function is 
// shown as an example for the function MlCtoPos(). 

// See function MlCtoPos() or the example "Search routine for 
// MemoEdit()" in the online help. 

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