# vTextEditor

A complete text editing canvas pane.

## Synopsis

Header:
  `<v/vtexted.h>`
Class name:
  vTextEditor
Hierarchy:
  vCanvasPane ->vTextCanvasPane ->vTextEditor

## Description

This class is a completely functional line oriented text editor. It can edit any file with lines less than 300 characters wide that use a linefeed, carriage return, or combination of those to mark the end of each line.

While you need to create your own class derived from `vTextEditor`, your class can be very minimal. You will need to provide some service methods for the parent `vCmdWindow`, such as methods to open, read, save, and close files. Other than actually working with the real text source and providing that source to `vTextEditor`, you can get a fully functional text editor with no additional work.

However, `vTextEditor` has been designed to allow you to extend and add functionality to the editor if you need to. The `vTextEditor` also sends messages that will allow you to place various status messages on a status bar if you wish. The hard stuff is done for you. You don't need to worry about mouse movements, scroll bars or scroll messages, updating the screen, handling keystrokes, or anything else associated with actual editing. The `vTextEditor` class takes care of all those details, and provides a standard editing interface.

The following steps are required to use `vTextEditor`. First, you create an instance of your derived class from your `vCmdWindow` class, something like this:

       ...

       // The Text Editor Canvas
        vedCanvas = new vedTextEditor(this);
        AddPane(vedCanvas);
       ...

       // Show Window

        ShowWindow();
        vedCanvas->ShowVScroll(1);  // Show Vert Scroll for vTextEditor

        ...

Your derived `vTextEditor` class should provide the methods needed for opening and reading the text file you want to edit. (Actually, you can edit any text source you wish.) `VTextEditor` doesn't actually read or write any text itself. It maintains an internal line buffer. (The default version of the internal buffer is essentially limited by the amount of memory your system can provide. The buffer methods can be overridden to provide totally unlimited file size, if you wish.) The idea is to have your application control where the text comes from, and then add it a line at a time to the `vTextEditor` buffer. You retrieve the text a line at a time when you want to save the edited text. Thus, your if your code is working with disk files, it can read the text a line at a time, and let `vTextEditor` worry about the buffering.

The following code shows how to add the contents of a text file to the `vTextEditor` buffer, and display it in the canvas for the first time. Calls to `vTextEditor` methods are marked with **.

    //===================>>> vedTextEditor::ReadFile <<<====================
      int vedTextEditor::ReadFile(char* name)
      {
        const int maxBuff = 300;    // Line length
        char buff[maxBuff];

        if (!name || !*name)
            return 0;
        ifstream inFile(name);      // Open the file

        if (!inFile)
            return 0;               // file not there

        resetBuff();                // ** Tell vTextEditor to init buffer

        while (inFile.getline(buff,maxBuff))  // read file
          {
            if (!addLine(buff))     // ** Add the line to the buffer
              {
                ERROR_MESSAGE("File too big -- only partially read.");
                break;
              }
          }
        inFile.close();             // Close the file
        displayBuff();              // ** Now, display the buffer
        return 1;
      }

To load text into the editor buffer, you first call `resetBuff` to initialize the buffer, then add a line at a time with calls to `addLine`, and finally display the text by calling `displayBuff`.

When your are editing (e.g., the user enters a Close command), you retrieve the text from the `vTextEditor` buffer with calls to `getLine`.

Then, to use the editor, you pass keystrokes from the `KeyIn` method of your `vCmdWindow` to the `EditKeyIn` method of the `vTextEditor`. `EditKeyIn` interprets the conventional meanings of the arrow keys, etc., and lets you edit the text in the buffer. You will also probably implement other commands, such as Find, by using the `EditCommand` method.

`VTextEditor` also calls several methods to notify of text state changes, such as current line, insert or overtype, etc. You can receive these messages by overriding the default methods, and display appropriate information on a status bar.

While `vTextEditor` is very complete, there are some things missing. The major hole is cut and paste support. This will be added when cut and paste support is added to V. There is also no real undo support. Maybe someday.

## Constructor

#### vTextEditor(vBaseWindow* parent)

The `vTextEditor` constructor requires that you specify the parent `vCmdWindow`. Since you usually create the text editor object in your `vCmdWindow` object, this is easy. You will probably need to cast the `this` to a `vBaseWindow*`.

## Utility Methods

#### resetBuff()

Before you load new text into the buffer, you must first call this method. It initializes the internal state of the text buffer.

#### MAX_LINE

This is a constant that defines the maximum width of a line that the text editor can handle. You should not use `addLine` to add lines wider than this constant.

#### virtual int addLine(char* line)

This method is called repeatedly to add lines to the text buffer. The default method is limited by the amount of memory available on the system, and this method return 0 when it runs out of memory.

Note that the entire text buffer package can be overridden if you need to provide unlimited file size handling. You should examine the source code for `vTextEditor` to determine the specifications of the methods you'd need to override.

#### virtual void displayBuff()

After you have added the complete file, call `displayBuff` to display the text in the window.

#### virtual int getLine(char* line, int maxChars, long lineNum)

#### virtual int getFirstLine(char* line, int maxChars)

#### virtual int getNextLine(char* line, int maxChars)

These are used to retrieve the edited text from the buffer. You can use `getFirstLine` with `getNextLine` for easy sequential retrieval, or `getLine` for specific lines (note: the first `lineNum` will be 1, not 0). These methods return -1 when all lines have been recovered.

#### virtual int EditCommand(int id, long val)

This method provides a complete interface to the functions provided by `vTextEditor`. While the basic editing functions are also handled by `EditKeyIn`, `EditCommand` gives access to functions that typically are either usually invoked from a menu command (such as Find), or don't have a standard mapping to a functions key (such as lineGoto). If you want the functionality of these commands in your application, you will have to provide an appropriate menu or command pane item to support them.

Each function supported by `vTextEditor` has an associated id (symbolically defined in `v/vtexted.h`), each beginning with `ed`. Many of the functions also take an associated value. Many editors allow a repetition count to be specified with many commands. For example, it is sometimes useful to be able to specify a command to move right some specific number of characters. The `val` parameter can be used to specify a value as desired. The only function that really need a value other than 1 (or -1 in the case of directional movement commands) is `edLineGoto`.

`EditCommand` returns 1 if the command was executed successfully, 0 if the command was recognized, but not successful (the find fails, for example), and -1 if the command was not recognized as valid.

At the time this manual was written, the following commands are supported. Because `vTextEditor` is evolving, it is likely more commands will be added. Check the `v/vtexted.h` file for specification of new editor commands. In the following descriptions, the note ``no val'' means that the `val` parameter is not used. A notation of ``+/-'' means the sign of `val` indicates direction.

edBalMatch
  find matching paren (if val > 1, up to val lines away, otherwise within a reasonable range)
edBufferBottom
  move to bottom of file (no val)
edCharDelete
  delete +/- val chars
edCharFoldCase
  swap case of +/- val letters
edCharInsert
  insert char val
edCharRight
  move +/- val chars right
edFind
  invoke TextEd's find dialog (no val)
edFindNext
  find next occurrence of prev (no val)
edLineBeginning
  move to line beginning (no val)
edLineDown
  move down +/- val lines in column
edLineDownBeg
  move down +/- val lines
edLineDelete
  delete +/- val lines
edLineDeleteFront
  delete to beginning of line (no val)
edLineDeleteToEnd
  delete to end of line (no val)
edLineEnd
  move to end of line (no val)
edLineGoto
  move cursor to line val
edLineOpen
  open val new blank lines
edScrollDown
  scroll +/- val lines without changing cursor
edVerify
  force repaint of screen (no val)
edWordRight
  move cursor +/- val words right

For a basic editor, the simplest way to use `EditCommand` is to use the `ed*` id's to define the associated menu items and controls, and then call `EditCommand` as the default case of the `switch` in the `WindowCommand` method of your `vCmdWindow`. Thus, you might have code that looks like this:

       ...
      static vMenu EditMenu[] = {
      ...
        {"Find", edFind, isSens,notChk,noKeyLbl,noKey,noSub},
        {"Find Next", edFindNext, isSens,notChk,noKeyLbl,noKey,noSub},
        {"Find Matching Paren", edBalMatch, isSens,notChk,
          noKeyLbl,noKey,noSub},
      ...
      };

       ...

    //===========>>> vedCmdWindow::WindowCommand <<<====================
     void vedCmdWindow::WindowCommand(ItemVal id, ItemVal val,
          CmdType cType)
     {
       switch (id)
        {
         ...

          default:  // route unhandled commands through editor
           {
             if (vedCanvas->EditCommand(id, 1) < 0)
                vCmdWindow::WindowCommand(id, val, cType);
            break;
           }

        }
       ...
     }

    //====================>>> vedCmdWindow::KeyIn <<<====================
      void vedCmdWindow::KeyIn(vKey keysym, unsigned int shift)
      {
        if (vedCanvas->EditKeyIn(keysym, shift) < 0)
            vCmdWindow::KeyIn(keysym, shift);
      }

#### virtual int EditKeyIn(vKey key, unsigned int shift)

This method is usually called from the `KeyIn` method of your derived `vCmdWindow` class. See the above code example.

The default implementation of `EditKeyIn` handles most of the standard keys, such as the arrow keys, the page keys, backspace, home, delete, insert, and end keys. It will also insert regular character keys into the text. It ignores function keys and non-printing control key values except tab and newline.

You can override this method to provide your own look and feel to the editor.

#### edState GetEdState()

#### void SetEdState()

`VTextEditor` maintains a state structure with relevant state information associated with various operating options of `vTextEditor`. It is defined in `v/vtexted.h`, and has the following fields:

        typedef struct edState
          {
            long changes,           // count of changes
                 cmdCount;          // how many times to repeat command
            int
                findAtBeginning,    // leave find at beginning of pattern
                fixed_scroll,       // flag if using fixed scroll
                ins_mode,           // true if insert mode
                counter,            // counter for + insert
                echof,              // whether or not to echo action
                tabspc,             // tab spacing
                wraplm;             // right limit
          } edState;

You can query and set the state with `GetEdState` and `SetEdState`.

#### long GetLines()

Returns the number of lines in the current buffer.

## Methods to Override

#### virtual void ChangeLoc(long line, int col)

This method is called by `vTextEditor` whenever the current line or current column is changed. This information could be displayed on a status bar, for example.

#### virtual void ChangeInsMode(int IsInsMode)

This method is called by `vTextEditor` whenever the insert mode is changed. If `IsInsMode` is true, then the editor is in insert mode. Otherwise, it is in overtype mode. The editor starts in insert mode. This information could be displayed on a status bar, for example.

#### virtual void StatusMessage(char* Msg)

The editor will call this message with a non-critical message such as ``Pattern Not Found'' for certain operations. This information could be displayed on a status bar, for example.

#### virtual void ErrorMessage(char* Msg)

The editor will call this message with a critical error message such as ``Bad parameter value'' for certain operations. This information could be displayed in a warning dialog, for example.

## See Also

vTextCanvasPane