The <textedit.h> header file
This header file contains the following functions:
TE_checkSlack TE_close TE_empty TE_focus
TE_handleEvent TE_indicateReadOnly TE_isBlank TE_open
TE_openFixed TE_pasteText TE_reopen TE_reopenPlain
TE_select TE_shrinkWrap TE_unfocus TE_updateCommand
and the following predefined types:
Bool EVENT HANDLE SCR_RECT
size_t TEXT_EDIT WIN_RECT WINDOW
Functions
short TE_open (TEXT_EDIT *te, WINDOW *w,
WIN_RECT *rect, HANDLE BufHandle,
unsigned short cur_offset, unsigned short ReadOnly, unsigned short Flags);
Initializes the text editor.
TE_open initializes the text editor and displays the initial content of the editor. All
text editor operations are controled using a structure of type TEXT_EDIT.
TE_open will initialize such structure pointed to by parameter te, which later need
to be passed to all text editor operations. It returns TRUE if the
initialization was successful, else returns FALSE.
w is a pointer to the parent window of the editor: you
can create a new window to be the parent using WinOpen, or you can pass
DeskTop as the parameter, if you are happy with
its settings (which is usually the case). rect is a pointer to the
WIN_RECT structure which describes actual dimensions of the
rectangular text editor area. Note that if you use your own window as a parent window, this
window must not be "dirty" (i.e. it must not have WF_DIRTY
flag set). Windows created by WinOpen are "dirty" by default,
so you need to clear "dirty" flag manually before calling TE_open. For example, you can do
w->Flags &= ~WF_DIRTY;
BufHandle is the handle of the text editor buffer, which may be pre-filled with the
text (if you want to edit existing text), or filled with zeros (if you want to create a new
text). BufHandle may be, for example, a result of HeapAlloc
operation. Note that in contrary what I said in the documentation of TIGCCLIB releases prior
to 2.2, it can not be a handle of a text variable, because text variables
contain additional system data on the begining, and the editor expect a raw data (see
Frequently Asked Questions to learn how you can pass a text variable to
the editor however).
The content of text buffer is a standard zero-terminated string, in which lines of
text are separated with '\r' character (0xD). The size of the buffer is managed automatically
by the editor: it will be expanded if necessary to add more text, so you need not to worry
about the allocated size. Parameter cur_offset is the initial position of the cursor
(counted from the begining of the buffer), and ReadOnly is the count of characters
at the begining of the buffer which can't be modified (i.e. which are read-only). ReadOnly
is usually set to zero, except in some special applications.
Flags is a set of binary flags which controls the editor. Some of these flags are
changed automatically during the operation of the editor. As I currently know, the following
bits have sense for usage in parameter Flags of this function (maybe there are more
of them, but I am not sure; keep all other bits to zero):
-
Bit b0 should be set for the standard operation of the editor. If this is reset, the editor
will operate in "compact" mode, in which the editor is only one character high, and where the
content of the editor will scroll left/right when necessary (such mode is used in request boxes
in dialogs). In "compact" mode, the content of the editor buffer must not contain '\r' characters,
else the editor will be fooled.
-
When b1 = 1, each line of the editor will be preceded with a colon (":"),
like in "Text editor" or "Program editor". When b1 = 0, there will not be a preceding
colon.
-
Bit 2 is used only if b1 = 1. When b2 is also 1, the first character of
each line will be regarded as "command character", and it will be displayed before the colon.
"Text editor" application uses such mode to store editor commands (like "P" = "PrintObj" etc.).
Note that when b2 = 1, parameter cur_offset must not be zero (it is usually
set to 1 in this case).
-
When b3 = 1, the editor enters some strange mode in which each line is preceded with
a left arrow. As I am not sure about such mode, I suggest to you to avoid this.
-
Bit b7 is set for text editors opened with TE_openFixed: you don't
need to use this bit!
-
When b11 = 1, the editor enters read-only mode, i.e. you can not insert or delete
characters, etc.
NOTE: TE_open just initializes the editor, displays the intial content of it and exits.
It does not enter the editor loop in which keypresses are processed. In fact, there is no
such loop: you need to get keypresses manually (using ngetchx
or, even better, using EV_getc) and to pass them to
TE_handleEvent which will process them. Such approach gives
much more flexibility. See TE_handleEvent for an example of usage.
See also very similar command TE_openFixed.
short TE_handleEvent (TEXT_EDIT *te, EVENT *event);
Dispatches an event to the text editor to be processed by it.
The text editor is an event driven application (see events.h for more
info about events). It does not have a "main loop" in which keypresses are collected and
processed. Instead, the user need to collect keypresses, and to dispatch them to the editor
using TE_handleEvent. The editor will then process the keypress (for example, it will insert a new
character, delete a character, scroll the editor area upwards/downwards
etc. depending of the concrete keypress). In other words, the "main loop" is part of the user program. This
approach is much more flexible, because the user may decide which
keys will be processed and which will not be, and the user may program a lot of special
actions which are not pre-programmed in the editor. For example, the user can redefine keys,
forbid all keys except uppercase letters, etc. TE_handleEvent returns TRUE
if the event was sucessfully processed by the editor, else returns FALSE.
TE_handleEvent needs a pointer to the editor control structure te, and a pointer to
the EVENT structure event which represents the event to be processed. Basically,
after calling TE_open, the program should enter a loop which does
keyboard reading, and sending (wanted) keypress events to the editor using TE_handleEvent. The keyboard
may be read using ngetchx, but this requires manual converting
of integer keycode to an event structure. It is better idea to use
EV_getc which is similar to ngetchx
but in addition to the returned keycode, it also fills as an event structure. So, the text
editor operations should be programmed as follows:
EVENT ev;
TEXT_EDIT te;
HANDLE h = HeapAlloc (200); // initial buffer size
memset (HeapDeref (h), 0, 200);
TE_open (&te, DeskTop, MakeWinRect (30, 30, 130, 70), h, 0, 0, 3);
CU_start (); // Enable the cursor
while (EV_getc (ACTIVITY_BUSY, &ev) != KEY_ESC) // Get keypress and translate it to
{ // the event (until ESC pressed)
TE_handleEvent (&te, &ev); // Send the event to the editor
} // to be processed
In this example, all keypresses are passed to the editor. This need not to be always true; in
fact, the main loop may contain whatever the user wants. The editor can handle a lot of
special keypresses, like marking with shift+arrows, cut, copy and paste operations etc, not
only inserting, deleting and scrolling (note that you can later access the clipboard using
CB_fetchTEXT and
CB_replaceTEXT if necessary).
However, TE_handleEvent can not handle keypresses
which represents tokens (like "sin" etc.) nor system keypresses which open menus like "CHAR" etc.
Fortunately, this problem can be solved easily (see the next example).
The example given above is not a typical example of event driven program. All events in this
example are restricted to simple keypresses. Typical event driven program uses
EV_eventLoop function, which is an endless loop in which
all timers, I/O ports etc. are checked for every possible event, and when an event appears, it
is dispatched to the active application. The program need to install an event handler using
EV_captureEvents function, which will capture all
events, and which need to decide what to do with every particular event. This approach is used
in the following example, which is written in typical "event driven" maneer.
In this example, all events are dispatched to the text editor, except pressing on ESC key (this
event will exit the event loop), and all events which were not processed sucessfully by the
editor are dispatched to the default event handler (see EV_defaultHandler)
which for example split tokens to single characters, open menus, etc:
TEXT_EDIT te = {}; // Global data must be initialized in "nostub" mode
void EventHandler (EVENT *ev)
{
if (ev->Type == CM_KEYPRESS && ev->extra.Key.Code == KEY_ESC)
ER_throwVar(1);
if (!TE_handleEvent (&te, ev))
EV_defaultHandler (ev);
}
void _main(void)
{
HANDLE h = HeapAlloc (200);
...
memset (HeapDeref (h), 0, 200);
TE_open (&te, DeskTop, MakeWinRect (30, 30, 130, 70), h, 0, 0, 3);
CU_start ();
EV_captureEvents (EventHandler);
TRY
EV_eventLoop (); // The only way to exit from "EV_eventLoop" is
ONERR // to throw an error from the event handler
EV_captureEvents (NULL);
ENDTRY
...
}
So, event driven programs using the text edit manager typically process events in three
phases. First, the application event handler examines the event for action it needs to
take. Either the application handler handles the event and returns to the event
manager or it proceeds further. Second, the application event handler calls
TE_handleEvent to allow the text edit manager to process the event. Either
TE_handleEvent handles the event and returns TRUE, or it does not
understand the event and returns FALSE. If TE_handleEvent does not
handle the event, the application proceeds further. Third, the application calls
EV_defaultHandler to let the event
manager have one last try at handling the event. System-wide default
behavior is implemented in EV_defaultHandler.
Programs may drive the text editor by calling TE_handleEvent with their own created event
messages (as in previous example), but in practice, the application just forwards events it
received from the event manager (i.e. from the EV_eventLoop
loop). Also note that calling TE_handleEvent may cause the heap compression.
Beware that EV_eventLoop is an endless loop, so the only
way to exit from it is to throw an error from the event handler. This error will be captured later by
TRY...ONERR...ENDTRY
construction.
NOTE: For the most of applications, you need not to use any text editor functions except
TE_open (or TE_openFixed) and TE_handleEvent,
because TE_handleEvent can do even relatively
complicated operations like cut/copy/paste, etc. Other text editor functions are needed only
if the user wants to program some special actions.
short TE_openFixed (TEXT_EDIT *te, WINDOW *w,
WIN_RECT *rect, char *buffer, unsigned short maxlen, unsigned short Flags);
Initializes the text editor, with fixed buffer.
TE_openFixed is very similar to TE_open, except it uses a fixed allocated
buffer pointed to by buffer instead of dinamically created buffer associated with handle.
So, the text buffer can not expand automatically when necessary. The parameter maxlen
determines the length of the buffer (the editor will not accept more characters than specified).
That's why functions TE_checkSlack and TE_shrinkWrap
can not be applied to text editors opened with TE_openFixed.
NOTE: After opening text editor using TE_openFixed, it is recommended to manually set position of
the cursor using TE_select (TE_openFixed has not a parameter for
initial cursor position in opposite to TE_open), else strange things
may happen.
void TE_select (TEXT_EDIT *te, unsigned short Low, unsigned short High);
Selects a block of text in the editor, or positions the cursor.
If Low != High, then TE_select selects all character in the text
editor described by structure pointed to by te, starting from the character with offset
Low up to character with offset High (counted from the begining of the text
buffer). This is the operation which editor usually performs when the user uses shift + arrows.
Note that you don't need to call TE_select often; usually TE_handleEvent will perform wanted
job. This is only needed if you want to select a block of text in the editor independently of
pressing of shift + arrows. Note that selected text will not automatically get a
focus: you need to call TE_focus to achieve this.
If Low is equal to High, then TE_select
positions the cursor to the position Low (counted from the begining of the text
buffer).
short TE_focus (TEXT_EDIT *te);
Highlightes the selected text in the editor, and gives the focus to it.
TE_focus is usually called after TE_select. It highlightes the
selected text in the editor (associated with the structure pointed to by te), and
gives the focus to it, so the selected text will become
active (after this, any keypress will replace selected text with the newly pressed
key). Returns TRUE if focusing was performed, and returns
FALSE if not (for example, if the text was already focused).
NOTE: TE_focus also enables the cursor using CU_start
if it was disabled. So, it is sometimes used after calling TE_select
with Low == High, just to
display the cursor.
short TE_unfocus (TEXT_EDIT *te);
Removes the focus from the selected text in the ediror.
TE_unfocus cancels the effect of TE_focus. Returns TRUE if
unfocusing was performed, and returns
FALSE if not (for example, if the text was already unfocused).
void TE_pasteText (TEXT_EDIT *te, const char *text , unsigned short len);
Pastes a text into the editor.
TE_pasteText inserts len bytes of the text pointed to by text into the text editor
buffer (associated with the structure pointed to by te) at the current cursor position.
These functions may be used together with CB_fetchTEXT
and CB_replaceTEXT if necessary. Also, this function
may be used for implementing various (very useful) functions like TE_printf
which works like printf but "prints" the formatted output
into the text editor. Among various ways of implementing such functions, I suggested the
following one (which uses unusual but powerful function vcbprintf):
void TE_pasteChar (char c,TEXT_EDIT *te)
{
char str[2] = {c, 0};
TE_pasteText (te, str, 1);
}
void TE_printf (TEXT_EDIT *te, char *format, ...)
{
va_list arglist;
va_start (arglist, format);
vcbprintf ((void(*)(char, void**))TE_pasteChar, (void**)te, format, arglist);
va_end (arglist);
}
This example is not so simple, so you need to be familiar with (standard) C to understand it.
void TE_empty (TEXT_EDIT *te);
Empties the text editor buffer.
TE_empty empties the text editor buffer (associated with the structure pointed to by te).
Note that this routine turns off cursor blink before emptying the edit buffer, but
does not repaint the edit region. It only makes its parent window dirty
(i.e. clears its WF_DIRTY bit) so, the edit region will be eventually
updated when the next paint message arrives.
short TE_isBlank (TEXT_EDIT *te);
Check whether the editor buffer is empty.
TE_isBlank returns TRUE if the text editor buffer (associated with the
structure pointed to by te) is empty, else returns FALSE. Note that
the content of the editor is regarded as "blank" if there is no characters in it, or if
all characters in it are blanks (spaces).
void TE_checkSlack (TEXT_EDIT *te);
Reallocates the text editor buffer if there is not much space left in it.
TE_checkSlack checks how many free space is present in the text editor buffer (associated with the
structure pointed to by te). If there is not much space left, then the buffer is reallocated
(expanded). Note that the editor will expand buffer if necessary during normal processing of
keypresses using TE_handleEvent, so the user need not to call
this function, except if it is necessary to check and eventually expand the buffer independently
of event dispatching procedure. Of course, the editor must not be opened with
TE_openFixed if you want to use this function.
Shrinks the text editor buffer.
TE_shrinkWrap shrinks the text editor buffer
(associated with the structure pointed to by te) to the minimal possible size. After
calling this function, the size of the buffer will be equal to the actual number of characters
in the buffer. This function must not be applied to text buffers opened with
TE_openFixed function. TE_shrinkWrap returns the handle of
the text editor buffer as the result. In addition, this function cancels selection highlight
and turns off the cursor. The edit buffer memory is not freed. Use this routine to prepare the
edit buffer for further processing or to be stored as a variable.
void TE_reopen (TEXT_EDIT *te, unsigned short Focus);
Re-opens the text editor.
TE_reopen first checks free space in the text editor buffer (associated with the structure
pointed to by te) by calling TE_checkSlack, selects all
characters in the editor buffer using TE_select, and eventually
gives the focus to them if Focus is TRUE (Focus is
Boolean parameter). This function is a good method to re-open previously edited text on
such way that all text is selected and focused, so the eventual keypress will replace the
selected text. It is usually used to reopen a text edit record which has been closed by
TE_shrinkWrap.
void TE_reopenPlain (TEXT_EDIT *te, unsigned short Focus);
Re-opens the text editor (plain).
TE_reopenPlain is similar like TE_reopen, but it doesn't call
TE_select funciton. I am not very sure about usage of this function.
void TE_updateCommand (TEXT_EDIT *te, unsigned char cmd);
Updates the command byte in the current line of the text.
TE_updateCommand sets the first byte of the current line (i.e. the line in which the cursor
is located) of the text editor associated to the structure pointed to by te to cmd,
i.e. sets the "command byte". This function works correctly only if the editor is opened in "command byte"
mode, i.e. if if b2 = 1 in parameter Flags of the TE_open
function).
void TE_indicateReadOnly (TEXT_EDIT *te);
Indicates read-only mode of the editor.
TE_indicateReadOnly indicates read-only mode of the editor (associated with the structure
pointed to by te) by disabling commands
"Cut", "Paste", "Clear" and "Del" in all menus registred with the current applications
(see EV_registerMenu), and setting the
status line (using ST_readOnly).
Note that this command works only if the editor is opened in read-only mode
(i.e. if b11 = 1 in parameter Flags of the TE_open
function). Also note that you need to call ST_readOnly
manually later, when you decide to remove the read-only indicator from the status line.
void TE_close (TEXT_EDIT *te);
Closes the text editor.
TE_close closes the text editor structure pointed to by te. I am not sure whether
calling this routine is necessary: it performs mainly some irrelevant operations
(like calling TE_unfocus). I also know that TE_close tries
to free the memory occupied by the buffer (by calling HeapFreeIndir)
if the editor was opened using TE_openFixed, and if the buffer
was allocated dinamically. So, it seems that it tries to close out a text edit record and to
release its memory automatically. It seems better to me to release the memory manually
(it is more safe anyway).
Predefined types
Bool is enumerated type for describing true or false values. It is defined as
enum Bool {FALSE, TRUE};
size_t is a type proposed in ANSI C for defining size of strings and
memory blocks. It is defined here as
typedef unsigned long size_t;
HANDLE is a type which represents handles associated to allocated memory
blocks. It is defined as
typedef unsigned short HANDLE;
TEXT_EDIT is a structure necessary to coordinate all text editor operations. It is defined as:
typedef struct TextEditStruct
{
WINDOW *Parent; // Pointer to the parent window
unsigned short ReadOnly; // Number of bytes at start that are read only
WIN_RECT Rect; // Editor area descriptor
unsigned short BufSize; // Number of currently allocated bytes
unsigned short CurSize; // Current number of characters in the editor
unsigned short CursorOffset; // Offset of the cursor
unsigned short StartOffset; // ScrollX, position at which text is displayed
unsigned short PreChars; // Number of characters to display before ":"
unsigned short CharWidth; // Width in characters
unsigned short CharHeight; // Height in characters
unsigned short LineNum; // Line number: cursor is on 0..CharHeight-1
unsigned short CursorX; // Horizontal char position
unsigned short Flags; // Editor flags
union
{
HANDLE h; // Handle of the editor buffer, if opened with TE_open
const char *p; // Ptr to the editor buffer, if opened with TE_openFixed
} Text;
} TEXT_EDIT;
NOTE: CursorX is the horizontal character position in the line, or position relative to StartOffset.
EVENT is a structure which describes an event message which is used in event driven applications.
It is defined as
typedef struct EventStruct
{
unsigned short Type; // ID code of the message, see EventIDs
unsigned short RunningApp; // Task ID of the sender of the message
unsigned short Side; // Side from which message is send
unsigned short StatusFlags; // Status line flags
union
{ // Message-dependent extra information: see EventIDs
WINDOW *w;
WIN_RECT *r;
char *pasteText;
HANDLE hPasteText;
struct
{
unsigned short Mod; // Key modifiers (SHIFT, etc.)
unsigned short Code; // Key code
} Key;
} extra;
unsigned char StartType; // Used only in CM_STARTTASK message
} EVENT;
See events.h header file for more info about this structure and
dispatching of event messages.
WINDOW is the main window-describing structure which is used in all window-based TIOS
functions. It is defied as
typedef struct WindowStruct
{
unsigned short Flags; // Window flags
unsigned char CurFont; // Current font
unsigned char CurAttr; // Current attribute
unsigned char Background; // Current background attribute
short TaskId; // Task ID of owner
short CurX, CurY; // Current (x,y) position (relative coordinates)
short CursorX, CursorY; // Cursor (x,y) position
SCR_RECT Client; // Client region of the window (excludes border)
SCR_RECT Window; // Entire window region including border
SCR_RECT Clip; // Current clipping region
SCR_RECT Port; // Port region for duplicate screen
unsigned short DupScr; // Handle of the duplicated or saved screen area
struct WindowStruct *Next; // Pointer to the next window in linked list
char *Title; // Pointer to the (optional) title
} WINDOW;
See wingraph.h header file for more info.
SCR_RECT is a scructure (more precise, an union) for defining a rectangular area
using psysical screen coordinates. It is defined as
typedef union
{
struct
{
unsigned char x0, y0, x1, y1;
} xy;
unsigned long l;
} SCR_RECT;
Instead of giving four coordinates x0, y0, x1 and y1,
it is possible to give all together using a field l which is a packed long
number. See graph.h and
wingraph.h header files for more info.
WIN_RECT is a scructure for defining a rectangular area using logical screen coordinates.
It is defined as
typedef struct
{
short x0, y0, x1, y1;
} WIN_RECT;
NOTE: TIGCC is a GNU C, so it allows cast constructors.
That's why, constructions like
TE_open (&te, DeskTop, &(WIN_RECT){30, 30, 130, 70}, h, 0, 0 3);
are legal (see TE_open). See also graph.h and
wingraph.h header files for more info.