20 January 2012

Gfa_Line doesn't always redraw the caret

The GFA-BASIC implementation of the editor-extension contains a large set of Gfa_* functions and commands. However, in contrast with the term 'editor extension', the Gfa_* statements are not restricted to the (text) editor only. The GFA-BASIC IDE application itself is divided into several entities such as an application part, a form-editor, a compiler, and a text-editor. Only a part of the Gfa_ statements apply to the text-editor only, and the most important terms in this respect are 'text-selection' and 'insertion point'.

The active point
The text-selection represents a selection in the code text in the editor window. Note that a selection can be a single point (the insertion point) or a contiguous range of text. Using Gfa_ commands you can move the insertion point, control which text is selected, and modify the contents of the selection. When the text-selection is restricted to a single point, Gfa_Line and Gfa_Col return its position. Also, since there is no selection, Gfa_Line equals Gfa_SelLine and Gfa_Col equals Gfa_SelCol.

Whether or not the text is selected, the Gfa_Line and Gfa_Col always indicate the active point. This is the point where all other text actions are performed. When a range of text is selected the insertion point can be located at the beginning or at the end of the selection.

Command Description
Gfa_Line Gets/sets the line where the insertion point is.
Gfa_Col Gets/sets the column where the insertion point is.
Gfa_SelLine Gets/sets the line at the bottom of a selection. The bottom line is not necessarily at the active end of the selection.
Gfa_SelCol Gets/sets the column at the bottom of a selection. The bottom line is not necessarily at the active end of the selection.

Moving the caret
The insertion point is represented by a caret, is a blinking line, block, or bitmap in the client area of a window. The caret typically indicates the place at which text (or graphics) will be inserted. The caret is a system resource and controlled by invoking Windows system API calls such as ShowCaret() and SetCaretPosition(). Each time the caret is moved SetCaretPosition() is invoked.
Programmatically, you move the caret using one of the following Gfa_ commands:

Command Key Press
Gfa_Left [count ] LEFT ARROW
Gfa_Right [count] RIGHT ARROW
Gfa_Down [count] DOWN ARROW
Gfa_Up [count] UP ARROW
Gfa_PageDown PAGE DOWN
Gfa_PageUp PAGE UP

count is optional. A Long that specifies the number of times you want to repeat this action. The default is one.

  • When executing one of these commands (or pressing the key(s)) the current selection is canceled before the action is performed.
  • These are relative movements. They move the caret relative to the current active insertion point represented by Gfa_Col and Gfa_Line.
  • Many key press actions are not represented by a Gfa_ command. For instance: word-left, word-right; end-of-line, start-of-line; etc.

So, how do you move the caret to an absolute position, rather than to a relative one? Within a text line the Gfa_Col = newcolumn command will do the trick. It cancels any selection and updates the caret position. By assigning 0 to Gfa_Col the caret moves to the start-of-the-line and by setting it to some large number (_maxInt) is moves to the end-of-the-line. Consequently, you expect Gfa_Line to do the same for lines. Well it does modify the current line, but it sometimes 'forget" to update the caret visually. Meaning, it forgets to put the caret into its new position.

Gfa_Line = doesn't redraw caret
The Gfa_Line = command differs in two aspects from all other commands. First it doesn't cancel a selection, and, secondly, it doesn't always redraw the caret in it's new position. It does however change the current line used for text operations, which is important because some text operations are line oriented. So, without displaying the caret at the new position (combined with a possible scrolling) the current active line can be changed to perform actions on the text line (Gfa_Update, Gfa_Text = , delete and insert lines, setting a bookmark, clipboard actions, etc). The problem is that the editor extension implementation lacks a command to update the caret explicitly.

Workaround to redraw caret
To explicitly make the caret visible after invoking Gfa_Line = we must take into account that as portion of the text maybe selected. So, first we must cancel any selection and after invoking Gfa_Line =  we must redraw the caret ourselves.

Global Gfa_SetCaret As Pointer Byte
Pointer(Gfa_SetCaret)       = $4DC41C
Global Const Ed_SetCaretPos = $409B99

' Cancel selection (if any)
Gfa_Col = 0 ' Set/Goto new line Gfa_Line = iGotoLine ' Set global flag (when in OnWMCommand) Gfa_SetCaret = 1 ' Or call directly ~StdCall(Ed_SetCaretPos)()

Most (if not all) IDE commands are processed in the IDE's OnWMCommand() function. This is a central routine to execute all accelerator key commands, menu commands, and the GLL's key and menu events. Besides this, it adds the commands to the UNDO-buffer and stores them in a keyboard macro when Gfa_IsRecording = True. At the end of IDE's OnWMCommand() function the global variable Gfa_IsCaret is checked to see if any of the executed commands did set this flag (to have the caret redrawn). If so, before returning from OnWMCommand() the IDE's Ed_SetCaretPos() function is invoked to redraw the caret and Gfa_SetCaret is cleared.

Now you have some background knowledge of Gfa_Line you have the tools to properly redraw the caret.

No comments:

Post a Comment