Single-line text
PtWidget --> PtBasic --> PtLabel --> PtText
For more information, see the diagram of the widget hierarchy.
<photon/PtText.h>
The Photon text widgets let you type textual information into a text-entry box. Basic editing features are provided so you can alter text that has been entered. A point-and-click model of editing is also supported so that blocks of text can be operated on as a unit.
A PtText widget.
Photon provides two different text widgets:
The text entered in the text widget is either inserted into or overwrites the existing text, depending on the insertion mode. The location where text is inserted or replaced is visually represented by a cursor.
In insert mode, the cursor appears as a vertical bar or pipe (|) between two characters. When you enter a character, it appears at the cursor location, and the cursor is moved to the right of that character.
In replace mode, the cursor appears as an underline (_) beneath a character. When you enter a new character, it replaces the character at the cursor location, and the cursor is moved to the next character in the text.
Clicking the mouse button once changes the cursor location to the character position nearest the pointer location. Dragging the pointer with the button pressed causes a range of text to be selected as the object of a subsequent operation. The selected range of text, which begins at the cursor position and ends at the pointer location, is highlighted by inverting the foreground and background colors used to display the text. Releasing the button completes the range selection.
The range of text selected can be extended by dragging with the Shift key pressed. The selected range of text is changed to the text between the current cursor position and the pointer location. The extension of the range of text is completed when the button is released.
Any character you type after a range of text has been selected replaces the selected range. A string specified by the application may also replace the selected range.
To modify the text widget's contents within a program, you must be able to access the text widget's internal storage. The primary means of access to this text is through the Pt_ARG_TEXT_STRING resource.
You can set the widget's text using the Pt_ARG_TEXT_STRING resource. You must give this resource a null-terminated C string as a value.
The following short program creates a text widget whose initial contents are the string "hello, world...":
#include <Pt.h> #include <Ph.h> PhArea_t area = { {0, 0}, {200,40} }; main(int argc, char *argv[]) { PtAppContext_t app; int nargs = 0; PtArg_t args[4]; PtWidget_t window; PtSetArg(&args[nargs++], Pt_ARG_POS, &area.pos, 0); PtSetArg(&args[nargs++], Pt_ARG_DIM, &area.size, 0); PtSetArg(&args[nargs++], Pt_ARG_WINDOW_TITLE, "hello", 0); if ((window = PtAppInit(&app, &argc, argv, nargs, args)) == NULL) exit(EXIT_FAILURE); nargs = 0; area.pos.y = 15; PtSetArg(&args[nargs++], Pt_ARG_POS, &area.pos, 0); PtSetArg(&args[nargs++], Pt_ARG_DIM, &area.size, 0); PtSetArg(&args[nargs++], Pt_ARG_TEXT_STRING, "hello, world...", 0); PtCreateWidget(PtText, window, nargs, args); PtRealizeWidget(window); PtMainLoop(); }
The widget's text can also be retrieved as a null-terminated C string by getting the value of the Pt_ARG_TEXT_STRING resource with the PtGetResources() function.
For more information, see "Getting resources" in the Manipulating Resources in Application Code chapter of the Photon Programmer's Guide.
You can obtain the range of characters in the current selection by using the PtTextGetSelection() function. This function takes the widget as the first parameter and returns the start and end position in the remaining two parameters. The range may be passed to other convenience functions to modify the selected text.
Any block of text in the widget can be programmatically replaced by a string using the PtTextModifyText() function. The parameters to this function are:
Your application can monitor and control changes made to the widget's text using the text modification callbacks. These callbacks are invoked when you type new text. If the widget has the Pt_CALLBACKS_ACTIVE bit set in its Pt_ARG_FLAGS resource, these callbacks are also invoked when the text is changed by a call to PtSetResources() or to a text widget function such as PtTextModifyText(). There are two text modification callbacks:
The Pt_CB_MODIFY_VERIFY callback is useful for validating changes before they're made to the widget. You can use this callback to alter the text modification or prevent it entirely.
This callback can manipulate the text modification via the cbdata member of the PtCallbackInfo_t structure passed to it. The cbdata member is a pointer to a text-callback structure. This is a PtTextCallback_t structure if the widget is a PtText, and a PtMultiTextCallback_t structure if the widget is a PtMultiText widget.
The following example shows how the text member of the above structure can be modified to alter the text inserted into the widget. The example uses the allcaps() callback function to convert any lowercase characters to uppercase before they're inserted into the widget.
#include <Pt.h> #include <stdlib.h> #include <ctype.h> int allcaps(PtWidget_t *, void *, PtCallbackInfo_t *); main(int argc, char *argv[]) { PtAppContext_t app; PhRect_t extent; PhPoint_t pos; PhPoint_t dim; PtArg_t args[6]; int nargs; PtWidget_t *window, *text, *label; /* Labels work with UTF-8 (multibyte character) strings. International characters can be entered only from an editor that supports UTF-8 */ nargs = 0; PtSetArg(&args[nargs], Pt_ARG_MARGIN_HEIGHT, 4, 0); nargs++; if ((window = PtAppInit(&app, &argc, argv, nargs, args)) == NULL) exit(EXIT_FAILURE); nargs = 0; PtSetArg(&args[nargs], Pt_ARG_TEXT_STRING, "Enter Text:", 0); nargs++; label = PtCreateWidget(PtLabel, window, nargs, args); PtWidgetExtent(label, &extent); pos = extent.lr; pos.x += 4; nargs = 0; PtSetArg(&args[nargs], Pt_ARG_COLUMNS, 20, 0); nargs++; PtSetArg(&args[nargs], Pt_ARG_POS, &pos, 0); nargs++; text = PtCreateWidget(PtText, window, nargs, args); PtAddCallback(text, Pt_CB_MODIFY_VERIFY, allcaps, NULL); PtRealizeWidget(window); PtMainLoop(); } int allcaps( PtWidget_t *w, void *client_data, PtCallbackInfo_t *info) { int len; PtTextCallback_t *cbs = (PtTextCallback_t *)info->cbdata; if (cbs->text == NULL) return Pt_CONTINUE; for ( len = 0; len < cbs->length; len++ ) if (islower(cbs->text[len])) cbs->text[len] = toupper(cbs->text[len]); return Pt_CONTINUE; }
You can prevent the text from being added to the widget by setting the doit member of the PtTextCallback_t structure to zero or by setting the length member to zero.
Setting the length to 0 stops the widget from inserting the text; it doesn't prevent any deletion included in the modification. |
You can determine if a modification is replacing or deleting a block of text by checking start_pos and end_pos. If these values differ, then a block of text is being removed from the widget and may potentially be replaced by new text contained in the text member.
Be sure to handle backspaces correctly. As well as checking for a different start and end position, an application can determine which of Backspace or Delete was pressed by checking the length, cur_insert, and new_insert:
The following simple example of accepting a password as input illustrates how to handle all editing operations (including pasting) correctly:
/* This program creates two text widgets for entering a password: - one offscreen to collect the password - one onscreen in which to type. All characters are displayed as stars in the onscreen widget but are saved in the offscreen widget. This is done by making the displayed widget's callbacks manipulate the offscreen widget's text. */ #include <Pt.h> #include <stdio.h> #include <stdlib.h> int check_passwd(PtWidget_t *, void *, PtCallbackInfo_t *); int update_passwd(PtWidget_t *, void *, PtCallbackInfo_t *); PtWidget_t *displayed_text, *offscreen_text; main(int argc, char *argv[]) { PhRect_t extent; PhPoint_t pos; PtArg_t args[2]; int nargs; PtWidget_t *window, *label; nargs = 0; PtSetArg(&args[nargs++], Pt_ARG_MARGIN_HEIGHT, 4, 0); if ((window = PtAppInit(NULL, &argc, argv, nargs, args)) == NULL) exit(EXIT_FAILURE); nargs = 0; PtSetArg( &args[nargs++], Pt_ARG_TEXT_STRING, "Enter Text:", 0); label = PtCreateWidget(PtLabel, NULL, nargs, args); PtExtentWidget(label); PtWidgetExtent(label, &extent); pos = extent.lr; pos.x += 4; pos.y = 0; // Create the displayed text widget: nargs = 0; PtSetArg(&args[nargs++], Pt_ARG_POS, &pos, 0); PtSetArg(&args[nargs++], Pt_ARG_COLUMNS, 20, 0); displayed_text = PtCreateWidget(PtText, NULL, nargs, args); PtAddCallback(displayed_text, Pt_CB_MODIFY_VERIFY, update_passwd, NULL); PtAddCallback(displayed_text, Pt_CB_ACTIVATE, check_passwd, NULL); // Create an offscreen text widget: pos.x = -1000; nargs = 0; PtSetArg(&args[nargs++], Pt_ARG_POS, &pos, 0); offscreen_text = PtCreateWidget(PtText, NULL, nargs, args); PtRealizeWidget(window); PtMainLoop(); } int check_passwd( PtWidget_t *widget, void *client_data, PtCallbackInfo_t *info ) { // This callback gets the password out of the offscreen // widget. It's invoked when you activate the displayed // widget (e.g. by pressing Enter). PtTextCallback_t *cbs = (PtTextCallback_t *)info->cbdata; char *passwd; PtArg_t args[1]; PtSetArg (&args[0], Pt_ARG_TEXT_STRING, &passwd, 0 ); PtGetResources ( offscreen_text, 1, args ); if (info->reason_subtype == Pt_EDIT_ACTIVATE) printf("Password: %s\n", passwd); return Pt_CONTINUE; } int update_passwd( PtWidget_t *widget, void *client_data, PtCallbackInfo_t *info ) { // This callback is invoked when you type in the displayed // widget, but it passes the typing to the offscreen widget. // The characters are replaced by stars in the displayed // widget. PtTextCallback_t *tcb = (PtTextCallback_t *)info->cbdata; static const char stars[] = "********************"; PtArg_t args[1]; PtSetArg( &args[0], Pt_ARG_TEXT_SUBSTRING, tcb, 0 ); PtSetResources( offscreen_text, 1, args ); tcb->text = stars; return Pt_CONTINUE; }
After the user has entered the new text into the widget, the Pt_CB_TEXT_CHANGED or Pt_CB_MODIFY_NOTIFY callback list is invoked. You can use this callback to keep track of changes after they've been made. This is useful in form-filling applications and text editors to determine if the contents of the text buffer are "dirty" (i.e. they've been modified by the user).
This callback uses the same text modification callback structure as the Pt_CB_MODIFY_VERIFY callback. The text member of this structure contains a UTF-8 string indicating the current contents of the text widget (i.e. the entire text buffer).
An example of using this callback in form-filling applications is to provide a visual cue to the user to indicate that one or more fields within the form have changed. The user then knows that the pending changes won't take effect until they're applied - usually by pressing an Apply or OK button.
To use this callback in this way:
Another possibility is to create a check button beside each field in the form when the user alters the field's contents. Activating the check button causes the new value to take effect.
The text widget provides callbacks that tell the application either that the text widget has gained or lost focus.
The text widget gains focus when the user either clicks on the text widget or presses the Tab key to move from another text field into this one.
When the text widget obtains the focus by either of these two means, any callbacks defined in the Pt_CB_GOT_FOCUS callback list for the widget are called. This is useful if the application wishes to alter the appearance of a text widget that the user is entering text into, or to trigger the update of a status field providing hints to a user using a "novice" mode of the interface.
The Pt_CB_LOST_FOCUS callback is invoked any time the user switches focus away from the text widget, either by tabbing to the next field or by clicking within another widget. This callback can be used to undo any change in the text widget's appearance that the application made to indicate that the widget had focus. The callback can also be useful in performing any syntax checking done on the fields within a form.
You can track changes to the text cursor position representing the current insertion point by adding a cursor movement callback to the Pt_CB_MOTION_VERIFY callback list. The callback is invoked every time:
Or:
Or:
The reason member given in the callback info for this callback is Pt_CB_MOTION_VERIFY. The event member indicates the type of action that caused the callback to be invoked.
You can determine the type of action that caused the callback to be invoked by making a comparison on the event member. If it's set to NULL, the callback was invoked as a result of an application function call. Otherwise, the callback was invoked as a result of a user action (such as a pointer button press or keypress event).
The event member is a pointer to a PhEvent_t structure describing the user action. To differentiate between a pointer event and a keypress event, look at the type of that event.
The cbdata member of info is a pointer to the same type of text modification callback structure used by the other text widget callbacks. This callback uses the cur_insert, new_insert, and doit members of the structure. The doit member can be set to zero to prevent the cursor movement from taking place.
The PtText widget provides an activate callback, Pt_CB_ACTIVATE, that's invoked when one of the following occurs:
The reason_subtype in the callback information is Pt_EDIT_ACTIVATE. The callback data is a pointer to the same text-modification callback structure as used by the text-modification callbacks. The text member of that structure contains a UTF-8 string indicating the contents of the buffer.
In this case, the reason_subtype in the callback information is 0, and the callback is as described for PtBasic.
The reason_subtype in the callback information is Pt_CHANGE_ACTIVATE. The callback data is a pointer to the same text-modification callback structure as used by the text-modification callbacks. The text member of that structure contains a UTF-8 string indicating the contents of the buffer.
The reason code in the callback information is always Pt_CB_ACTIVATE.
When only one text field is contained within a container widget (e.g. a dialog), the activate callback is often chained to the activate action on the dialog. In other words, for a prompt dialog, entering a new value in the text field and pressing the Enter key has the same effect as pressing the dialog's OK button after entering the new value.
The PtText widget provides an edit mask that allows a pattern to be specified for the text entered into the text field. Any characters the user enters must conform to this pattern or they'll be rejected.
Edit masks can be difficult to use and aren't very flexible. It's better to use a Pt_CB_MODIFY_VERIFY callback than an edit mask to constrain input. |
The string entered into a data-entry field often conforms to some format. Edit masks are provided within the text widget to enforce the entry of the information in the correct format.
A single edit mask may be provided for the text widget by setting the Pt_ARG_EDIT_MASK resource. This resource is a null-terminated text string that acts as a template for text entered in the text field. Each character the user enters must match the corresponding character in the edit mask.
Here are the characters that may be specified in the edit mask, along with the characters they match:
This character: | Matches: |
---|---|
# | Any single numeric digit. |
X | Any character (don't care). |
A | Any alphabetic character (the letters A-Z). |
n | Any alphanumeric character (the letters A-Z or any numeric digit). All alphabetic characters are converted to lowercase. |
N | Any alphanumeric character (the letters A-Z or any numeric digit). All alphabetic characters are converted to uppercase. |
c | Any alphabetic character (the letters A-Z). All characters are converted to lowercase. |
C | Any alphabetic character (the letters A-Z). All characters are converted to uppercase. |
d | Any alphanumeric character (the letters A-Z or any numeric digit), but without case conversion. |
Any other character that appears in the edit mask is assumed to be a constant character that must appear at that position in the text field. When the user has entered enough characters to reach that position, the character is automatically inserted. After that, the character may not be deleted or altered by the user.
As an example, Canadian postal codes must consist of uppercase alphabetic characters and numbers in the following order: character, digit, character, space, digit, character, digit. For example, QNX Software System's postal code is K2M 1W8. So, a text field for entering a postal code might specify C#C #C# as the edit mask. The text field widget enforces the constraints on the characters the user enters and automatically adds the space character.
If the user: | The widget: |
---|---|
Presses the mouse button | Gets input focus |
Presses the mouse button and drags the mouse | Extends the text selection |
Releases the mouse button | Ends the text selection |
If the user presses: | The widget: |
---|---|
Any character | Inserts the typed character |
--> | Moves the cursor to the right |
<-- | Moves the cursor to the left |
Home | Moves the cursor to the beginning of the line |
End | Moves the cursor to the end of the line |
Shift ---> | Extends the text selection to the right |
Shift -<-- | Extends the text selection to the left |
Shift -Home | Extends the text selection to the beginning of the line |
Shift -End | Extends the text selection to the end of the line |
Backspace | Deletes the previous character |
Delete | Deletes the current character |
Enter | Processes the text |
Tab | Moves the cursor to the next text field |
Shift -Tab | Moves the cursor to the previous text field |
Ctrl ---> | Moves the cursor to the next word |
Ctrl -<-- | Moves the cursor to the previous word |
Ins | Toggles between insert and replace modes |
Resource | C type | Pt type | Default |
---|---|---|---|
Pt_ARG_COLUMNS | short | Scalar | 0 |
Pt_ARG_CURSOR_POSITION | int | Scalar | -1 |
Pt_ARG_EDIT_MASK | char * | Scalar | NULL |
Pt_ARG_MAX_LENGTH | short | Scalar | SHRT_MAX |
Pt_ARG_SELECTION_RANGE | See below | Complex | See below |
Pt_ARG_TEXT_CURSOR_WIDTH | char | Scalar | 1 |
Pt_ARG_TEXT_FLAGS | unsigned long | Flag | Pt_CURSOR_VISIBLE | Pt_EDITABLE | Pt_INSERT_MODE |
Pt_ARG_TEXT_HIGHLIGHT_BACKGROUND_COLOR | PgColor_t | Scalar | Pt_DEFAULT_COLOR |
Pt_ARG_TEXT_HIGHLIGHT_TEXT_COLOR | PgColor_t | Scalar | Pt_DEFAULT_COLOR |
Pt_ARG_TEXT_SUBSTRING | See below | Complex | See below |
Pt_CB_MODIFY_NOTIFY | PtCallback_t * | Link | NULL |
Pt_CB_MODIFY_VERIFY | PtCallback_t * | Link | NULL |
Pt_CB_MOTION_NOTIFY | PtCallback_t * | Link | NULL |
Pt_CB_MOTION_VERIFY | PtCallback_t * | Link | NULL |
Pt_CB_TEXT_CHANGED | PtCallback_t * | Link | NULL |
C type | Pt type | Default |
---|---|---|
short | Scalar | 0 |
The number of "M" characters that fit in the field horizontally. The widget uses this resource only if the width component of the Pt_ARG_DIM resource is 0.
C type | Pt type | Default |
---|---|---|
int | Scalar | -1 |
The cursor position. A value of 0 indicates that the cursor is placed before the first character, 1 before the second character, and so on.
C type | Pt type | Default |
---|---|---|
char * | Scalar | NULL |
A string that serves as an input filter for the text field. Each character in the string determines the acceptable input for the corresponding character position in the text field. The edit mask can contain the following:
Edit masks can be difficult to use and aren't very flexible. It's better to use a Pt_CB_MODIFY_VERIFY callback than an edit mask to verify input. |
C type | Pt type | Default |
---|---|---|
short | Scalar | SHRT_MAX |
The maximum text length the widget accepts.
C type | Pt type | Default |
---|---|---|
See below | Complex | See below |
This resource can be used to select a range of text or determine what text is currently selected. This resource is complex, and requires special handling:
The len isn't used when setting or getting this resource.
You can call PtTextGetSelection() or PtTextSetSelection() instead of using this resource.
C type | Pt type | Default |
---|---|---|
char | Scalar | 1 |
The width, in pixels, of the cursor.
C type | Pt type | Default |
---|---|---|
unsigned long | Flag | Pt_CURSOR_VISIBLE | Pt_EDITABLE | Pt_INSERT_MODE |
Valid flags:
C type | Pt type | Default |
---|---|---|
PgColor_t | Scalar | Pt_DEFAULT_COLOR |
The background color for highlighting. If this is Pt_DEFAULT_COLOR, the default background color is used.
C type | Pt type | Default |
---|---|---|
PgColor_t | Scalar | Pt_DEFAULT_COLOR |
The text color for highlighting. If this is Pt_DEFAULT_COLOR, the default text color is used.
C type | Pt type | Default |
---|---|---|
See below | Complex | See below |
This resource can be used to get or set a substring of the widget's text. It's a complex resource, so it needs special handling:
Instead of setting this resource, you can call PtTextModifyText().
The len isn't used when setting or getting this resource.
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of callbacks that the widget invokes after the value of the text string changes.
It doesn't matter which name you use for this resource. |
If the widget has the Pt_CALLBACKS_ACTIVE bit set in its Pt_ARG_FLAGS resource, this callback is also invoked when the text is changed by a call to PtSetResources() or to a text widget function such as PtTextModifyText().
Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
These callbacks should return Pt_CONTINUE.
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of callbacks that the widget invokes before the value of the text string changes. To alter the input to the widget, you can modify the members of the callback structure.
If the widget has the Pt_CALLBACKS_ACTIVE bit set in its Pt_ARG_FLAGS resource, this callback is also invoked when the text is changed by a call to PtSetResources() or to a text widget function such as PtTextModifyText().
Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
For more information, see PtTextModifyText().
These callbacks should return Pt_CONTINUE.
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of callbacks that the widget invokes after the cursor is repositioned.
If the widget has the Pt_CALLBACKS_ACTIVE bit set in its Pt_ARG_FLAGS resource, this callback is also invoked when the cursor is repositioned by a call to PtSetResources().
Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
C type | Pt type | Default |
---|---|---|
PtCallback_t * | Link | NULL |
A list of callbacks that the widget invokes before the cursor is repositioned. Using this callback resource, you can modify or even disallow cursor repositioning.
If the widget has the Pt_CALLBACKS_ACTIVE bit set in its Pt_ARG_FLAGS resource, this callback is also invoked when the cursor is repositioned by a call to PtSetResources().
Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
These callbacks should return Pt_CONTINUE.
If the widget modifies an inherited resource, the "Default override" column indicates the new value. This modification affects any subclasses of the widget.
Pt_CB_ACTIVATE is inherited from PtBasic, but its behavior is different for a PtText widget. Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
If reason_subtype is Pt_EDIT_ACTIVATE or Pt_CHANGE_ACTIVATE, cbdata points to a PtTextCallback_t structure that contains at least the following members:
These callbacks should return Pt_CONTINUE.
Pt_CB_GOT_FOCUS and Pt_CB_LOST_FOCUS are inherited from PtBasic, but the callback data is different for a PtText widget. Each callback is passed a PtCallbackInfo_t structure that contains at least the following members:
These callbacks should return Pt_CONTINUE.
The PtText widget defines several convenience functions and data structures that make it easier to use the widget once it's been created. Here's a brief overview: