The XmNscrollHorizontal resource controls whether or not a horizontal ScrollBar is displayed. If the resource
is set to False, the ScrollBar is not displayed, but that does not stop text from being displayed beyond the visible
area. In order to have text wrap appropriately, the XmNwordWrap resource must be set to True. When this resource
is set, the Text widget breaks lines at spaces, tabs, and newlines. While line breaking is fine for previewing files and
other output−only Text widgets, you should not enforce such a policy for Text widgets that are used for text editing,
as the user may want to edit wide files.
The XmNscrollVertical resource controls whether or not a vertical ScrollBar is displayed. This resource
defaults to True when a Text widget is created as a child of a ScrolledWindow. The XmNscrollLeftSide and
XmNscrollTopSide resources take Boolean values that control the location of the ScrollBars within the
ScrolledWindow. By default, XmNscrollTopSide is set to False, which causes the ScrollBar to be placed below
the ScrolledWindow. The default value of XmNscrollLeftSide depends upon the value of
XmNstringDirection. These two resources should not be set by the application, but left to users to specify
themselves. The XmNresizeWidth and XmNresizeHeight resources control whether or not a Text widget
should resize itself vertically or horizontally in order to display the entire text stream. Both of the resources default to
False. If XmNresizeWidth is set to True and new text is added such that the number of columns needs to grow,
the width of the widget grows to contain the new text. Similarly, if XmNresizeHeight is set to True and the
number of lines increases, the height of the widget increases so that it can display all of the lines. These resources
have no effect in a ScrolledText object, since the ScrollBars are managing the widget's size. Also, if line breaking is
active, XmNresizeWidth has no effect.
In most cases, it is not appropriate to set these resources, as it is regarded as poor user−interface design to have a Text
widget that dynamically resizes as the text is being edited. It is also impolite for a window to resize itself except as the
result of an explicit user action. One example of an acceptable use of these resources involves using a Text widget to
display text for a help dialog. In this situation, the Text widget can resize itself silently before it is mapped to the
screen, so that by the time it is visible, its size is constant.
15.2.4 Text Positions
A position in a Text widget specifies the number of characters from the beginning of the text in the widget, where the
first character position is defined as zero (0). All whitespace and newline characters are considered part of the text and
are counted as single characters. For example, in the figure, the insertion cursor in the TextField widget is at position
14. When the user types in a Text widget, the new text is always added at the position of the insertion cursor and the
insertion cursor is advanced. If the user does not move the cursor, it is always positioned at the end of the text in the
widget.
You can set the position of the insertion cursor explicitly using XmTextSetInsertionPosition(), which takes
the following form:
void
XmTextSetInsertionPosition(text_w, position)
Widget text_w;
XmTextPosition position;
This function is identical to XmTextSetCursorPosition(). The XmTextPosition type is a long value, so
it can represent all of the positions in a Text widget. You can get the current cursor position using
XmTextGetInsertionPosition() or XmTextGetCursorPosition(). As with most of the Text widget
functions, there are corresponding TextField functions for setting and getting the position of the insertion cursor. The
TextField routines only work with TextField widgets, while the Text routines work with both Text and TextField
widgets.
15 Text Widgets 15.2.4 Text Positions
390
the source code shows an application that uses these routines as part of a search operation. The program searches the
Text widget for a specified pattern and then positions the insertion cursor so that the pattern is displayed.
XtSetLanguageProc() is only available in X11R5; there is no corresponding function in X11R4.
/* search_text.c −− demonstrate how to position a cursor at a
* particular location. The position is determined by a pattern
* match search.
*/
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/LabelG.h>
#include <Xm/RowColumn.h>
#include <X11/Xos.h> /* for the index() function */
Widget text_w, search_w, text_output;
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, rowcol_v, rowcol_h;
XtAppContext app;
int i, n;
void search_text();
Arg args[10];
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
rowcol_v = XtVaCreateWidget ("rowcol_v",
xmRowColumnWidgetClass, toplevel, NULL);
rowcol_h = XtVaCreateWidget ("rowcol_h",
xmRowColumnWidgetClass, rowcol_v,
XmNorientation, XmHORIZONTAL,
NULL);
XtVaCreateManagedWidget ("Search Pattern:",
xmLabelGadgetClass, rowcol_h, NULL);
search_w = XtVaCreateManagedWidget ("search_text",
xmTextFieldWidgetClass, rowcol_h, NULL);
XtManageChild (rowcol_h);
text_output = XtVaCreateManagedWidget ("text_output",
xmTextWidgetClass, rowcol_v,
XmNeditable, False,
XmNcursorPositionVisible, False,
XmNshadowThickness, 0,
XmNhighlightThickness, 0,
NULL);
n = 0;
XtSetArg (args[n], XmNrows, 10); n++;
XtSetArg (args[n], XmNcolumns, 80); n++;
XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
XtSetArg (args[n], XmNscrollHorizontal, False); n++;
XtSetArg (args[n], XmNwordWrap, True); n++;
text_w = XmCreateScrolledText (rowcol_v, "text_w", args, n);
XtManageChild (text_w);
15 Text Widgets 15.2.4 Text Positions
391
XtAddCallback (search_w, XmNactivateCallback, search_text, NULL);
XtManageChild (rowcol_v);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* search_text() −− called when the user activates the TextField. */
void
search_text(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
char *search_pat, *p, *string, buf[32];
XmTextPosition pos;
int len;
Boolean found = False;
/* get the text that is about to be searched */
if (!(string = XmTextGetString (text_w)) || !*string) {
XmTextSetString (text_output, "No text to search.");
XtFree (string); /* may have been ""; free it */
return;
}
/* get the pattern we're going to search for in the text. */
if (!(search_pat = XmTextGetString (search_w)) || !*search_pat) {
XmTextSetString (text_output, "Specify a search pattern.");
XtFree (string); /* this we know is a string; free it */
XtFree (search_pat); /* this may be "", XtFree() checks.. */
return;
}
len = strlen (search_pat);
/* start searching at current cursor position + 1 to find
* the −next− occurrance of string. we may be sitting on it.
*/
pos = XmTextGetCursorPosition (text_w);
for (p = &string[pos+1]; p = index (p, *search_pat); p++)
if (!strncmp (p, search_pat, len)) {
found = True;
break;
}
if (!found) { /* didn't find pattern? */
/* search from beginning till we've passed "pos" */
for (p = string;
(p = index (p, *search_pat)) && p − string <= pos; p++)
if (!strncmp (p, search_pat, len)) {
found = True;
break;
}
}
if (!found)
XmTextSetString (text_output, "Pattern not found.");
else {
pos = (XmTextPosition)(p − string);
sprintf (buf, "Pattern found at position %ld.", pos);
XmTextSetString (text_output, buf);
XmTextSetInsertionPosition (text_w, pos);
15 Text Widgets 15.2.4 Text Positions
392
}
XtFree (string);
XtFree (search_pat);
}
In this example, the user can search for strings in a ScrolledText, as shown in the figure.
Output of search_text.c
This program doesn't provide a way to load a file, so if you want to experiment, you need to type or paste some text
into the widget. Once there is some text in the widget, type a string pattern in the Search Pattern TextField widget
and press RETURN to activate the search. The text is searched starting at the position immediately following the
current cursor position. If the search routine reaches the end of the text before it finds the pattern, it resumes searching
from the beginning of the text and continues until it finds the pattern or reaches the cursor position. If the routine finds
the pattern, it moves the insertion point to that location using XmTextSetInsertionPosition(). Otherwise,
the routine prints an error message and does not move the cursor.
The search_text() routine shown in the source code searches the text using various string routines. In Motif 1.2,
there is a new Text routine that provides the same functionality. XmTextFindString() searches a Text widget for
a specified string. This routine takes the following form:
Boolean
XmTextFindString(text_w, start, string, direction, position)
Widget text_w;
XmTextPosition start;
char *string;
XmTextDirection direction;
XmTextPosition *position;
The start argument specifies the starting position for the search, while direction indicates whether the routine
searches forward or backward in the text. This parameter can have the value XmTEXT_FORWARD or
XmTEXT_BACKWARD. The routine returns True if it finds the string, and in this case, the position parameter
returns the position where the string starts in the text. If the string is not found, the routine returns False, and the
value of position is undefined. It is easy to rewrite search_text() to take advantage of
XmTextFindString(). In Section #stexteditor, we implement a full text editor and use XmTextFindString()
to handle the various search operations.
15 Text Widgets 15.2.4 Text Positions
393
The text_output widget in search_text.c is also a Text widget, even though it looks more like a Label widget. By
setting XmNshadowThickness to 0 and XmNeditable to False, we create the Text widget that doesn't look
like a normal Text widget, and the user cannot edit the text. We demonstrate this technique not to advocate such
usage, but to point out the versatility of this widget class.
If you paste a large amount of text into the main Text widget and search repeatedly for a common pattern, you should
notice that the Text widget may scroll automatically to make the specified text visible. This action is controlled by the
XmNautoShowCursorPosition resource. This resource has a default value of True, which means that the Text
widget adjusts the visible text to make sure that the cursor is always visible. When the resource is set to False, the
widget does not scroll to compensate for the cursor's invisibility. This resource also works in single−line Text widgets
and TextField widgets; these widgets may scroll their displays horizontally to display the insertion cursor.
It is easy to scroll a Text widget to a particular position in the text stream by setting the cursor position and then
calling XmTextShowPosition(). This routine takes the following form:
void
XmTextShowPosition(text_w, position)
Widget text_w;
XmTextPosition position;
To scroll to the end of the text, you need to scroll to the last position, which can be retrieved using
XmTextGetLastPosition(). It is also possible to perform relative scrolling using the function
XmTextScroll(), which takes the following form:
void
XmTextScroll(text_w, lines)
Widget text_w;
int lines;
A positive value for lines causes a Text widget to scroll upward by that many lines, while a negative value causes
downward scrolling. The Text widget does not have to be a child of ScrolledWindow for this routine to work; the
widget simply adjusts the viewable text.
Now that we have a routine that searches for text, the next logical step is to implement a function that performs a
search−and−replace operation. Motif makes this task fairly easy by providing the XmTextReplace() routine,
which takes the following form:
void
XmTextReplace(text_w, from_pos, to_pos, value)
Widget text_w;
XmTextPosition from_pos;
XmTextPosition to_pos;
char *value;
This function identifies the text to be replaced in the Text widget starting at the position from_pos and ending at,
but not including, the position to_pos. This text is replaced by the text in value. If value is NULL or an empty
string, the text between the two positions is simply deleted. If you want to remove all of the text from the widget, call
XmTextSetString() with a NULL string as the text value.
To add search−and−replace functionality to the program in the source code we need to add a new TextField widget
that prompts for the replacement text and provide a callback routine for the widget. the source code shows the
additional code that is necessary.
15 Text Widgets 15.2.4 Text Positions
394

Get Volume 6A: Motif Programming Manual now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.