} XmTextScanType;
XmSELECT_WHITESPACE works in the same way as XmSELECT_WORD. Each successive button click in a Text
widget selects the text according to the corresponding item in the array. The default array is defined as follows:
static XmTextScanType sarray[] = {
XmSELECT_POSITION, XmSELECT_WORD, XmSELECT_LINE, XmSELECT_ALL
};
You should keep the items in the array in ascending order, so as not to confuse the user. The following code fragment
shows an acceptable change to the array:
static XmTextScanType sarray[] = {
XmSELECT_POSITION, XmSELECT_WORD, XmSELECT_LINE, XmSELECT_PARAGRAPH,
XmSELECT_ALL
};
...
XtVaSetValues (text_w,
XmNselectionArray, selectionArray,
XmNselectionArrayCount, 5,
NULL);
The maximum time interval between button clicks in a multi−click action is specified by the multiClickTime
resource. This resource is maintained by the X server and set for all applications; it is not a Motif resource. The value
of the resource can be retrieved using XtGetMultiClickTime() and changed with
XtSetMultiClickTime(). For more discussion on this value, see Chapter 11, Labels and Buttons.
The XmNselectThreshold resource can be used to modify the behavior of click−and−drag actions. This resource
specifies the number of pixels that the user must move the pointer before a character can be selected. The default
value is 5, which means that the user must move the mouse at least 5 pixels before the Text widget decides whether or
not to select a character. This threshold is used throughout a selection operation to determine when characters are
added or deleted from the selection. If you are using an extremely large font, you may want to increase the value of
this resource to cut down on the number of calculations that are necessary to determine if a character should be added
or deleted from the selection.
15.4 A Text Editor
Before we describe the Text widget callback routines, we are going to present an example that combines all the
information covered so far. The example is a full−featured text editor built from the examples presented so far in this
chapter. You should recognize most of the code in the example; the code that you don't recognize should be
understandable from the context in which it is used. The output of the program is shown in the figure; the code is
shown in the source code XtSetLanguageProc() is only available in X11R5; there is no corresponding function
in X11R4. XmStringCreateLocalized() is only available in Motif 1.2; XmStringCreateSimple() is the
corresponding function in Motif 1.1. XmFONTLIST_DEFAULT_TAG replaces XmSTRING_DEFAULT_CHARSET in
Motif 1.2. XmTextFindString() is only available in Motif 1.2; there is no corresponding function in Motif 1.1,
so you have to implement your own search capabilities.
15 Text Widgets 15.4 A Text Editor
404
Output of editor.c
/* editor.c −− create a full−blown Motif editor application complete
* with a menubar, facilities to read and write files, text search
* and replace, clipboard support and so forth.
*/
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/LabelG.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/FileSB.h>
#include <X11/Xos.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
Widget text_edit, search_text, replace_text, text_output;
#define FILE_OPEN 0
#define FILE_SAVE 1
#define FILE_EXIT 2
#define EDIT_CUT 0
#define EDIT_COPY 1
#define EDIT_PASTE 2
#define EDIT_CLEAR 3
#define SEARCH_FIND_NEXT 0
#define SEARCH_SHOW_ALL 1
#define SEARCH_REPLACE 2
#define SEARCH_CLEAR 3
main(argc, argv)
int argc;
char *argv[];
15 Text Widgets 15.4 A Text Editor
405
{
XtAppContext app_context;
Widget toplevel, main_window, menubar, form, search_panel;
void file_cb(), edit_cb(), search_cb();
Arg args[10];
int n = 0;
XmString open, save, exit, exit_acc, file, edit, cut,
clear, copy, paste, search, next, find, replace;
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app_context, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
XmRepTypeInstallTearOffModelConverter ();
main_window = XtVaCreateWidget ("main_window",
xmMainWindowWidgetClass, toplevel, NULL);
/* Create a simple MenuBar that contains three menus */
file = XmStringCreateLocalized ("File");
edit = XmStringCreateLocalized ("Edit");
search = XmStringCreateLocalized ("Search");
menubar = XmVaCreateSimpleMenuBar (main_window, "menubar",
XmVaCASCADEBUTTON, file, 'F',
XmVaCASCADEBUTTON, edit, 'E',
XmVaCASCADEBUTTON, search, 'S',
NULL);
XmStringFree (file);
XmStringFree (edit);
XmStringFree (search);
/* First menu is the File menu −− callback is file_cb() */
open = XmStringCreateLocalized ("Open...");
save = XmStringCreateLocalized ("Save...");
exit = XmStringCreateLocalized ("Exit");
exit_acc = XmStringCreateLocalized ("Ctrl+C");
XmVaCreateSimplePulldownMenu (menubar, "file_menu", 0, file_cb,
XmVaPUSHBUTTON, open, 'O', NULL, NULL,
XmVaPUSHBUTTON, save, 'S', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, exit, 'x', "Ctrl<Key>c", exit_acc,
NULL);
XmStringFree (open);
XmStringFree (save);
XmStringFree (exit);
XmStringFree (exit_acc);
/* ...create the "Edit" menu −− callback is edit_cb() */
cut = XmStringCreateLocalized ("Cut");
copy = XmStringCreateLocalized ("Copy");
clear = XmStringCreateLocalized ("Clear");
paste = XmStringCreateLocalized ("Paste");
XmVaCreateSimplePulldownMenu (menubar, "edit_menu", 1, edit_cb,
XmVaPUSHBUTTON, cut, 't', NULL, NULL,
XmVaPUSHBUTTON, copy, 'C', NULL, NULL,
XmVaPUSHBUTTON, paste, 'P', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, clear, 'l', NULL, NULL,
NULL);
XmStringFree (cut);
15 Text Widgets 15.4 A Text Editor
406
XmStringFree (copy);
XmStringFree (paste);
/* create the "Search" menu −− callback is search_cb() */
next = XmStringCreateLocalized ("Find Next");
find = XmStringCreateLocalized ("Show All");
replace = XmStringCreateLocalized ("Replace Text");
XmVaCreateSimplePulldownMenu (menubar, "search_menu", 2, search_cb,
XmVaPUSHBUTTON, next, 'N', NULL, NULL,
XmVaPUSHBUTTON, find, 'A', NULL, NULL,
XmVaPUSHBUTTON, replace, 'R', NULL, NULL,
XmVaSEPARATOR,
XmVaPUSHBUTTON, clear, 'C', NULL, NULL,
NULL);
XmStringFree (next);
XmStringFree (find);
XmStringFree (replace);
XmStringFree (clear);
XtManageChild (menubar);
/* create a form work are */
form = XtVaCreateWidget ("form",
xmFormWidgetClass, main_window, NULL);
/* create horizontal RowColumn inside the form */
search_panel = XtVaCreateWidget ("search_panel",
xmRowColumnWidgetClass, form,
XmNorientation, XmHORIZONTAL,
XmNpacking, XmPACK_TIGHT,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL);
/* Create two TextField widgets with Labels... */
XtVaCreateManagedWidget ("Search Pattern:",
xmLabelGadgetClass, search_panel, NULL);
search_text = XtVaCreateManagedWidget ("search_text",
xmTextFieldWidgetClass, search_panel, NULL);
XtVaCreateManagedWidget (" Replace Pattern:",
xmLabelGadgetClass, search_panel, NULL);
replace_text = XtVaCreateManagedWidget ("replace_text",
xmTextFieldWidgetClass, search_panel, NULL);
XtManageChild (search_panel);
text_output = XtVaCreateManagedWidget ("text_output",
xmTextFieldWidgetClass, form,
XmNeditable, False,
XmNcursorPositionVisible, False,
XmNshadowThickness, 0,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
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], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNtopWidget, search_panel); n++;
15 Text Widgets 15.4 A Text Editor
407
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, text_output); n++;
text_edit = XmCreateScrolledText (form, "text_edit", args, n);
XtManageChild (text_edit);
XtManageChild (form);
XtManageChild (main_window);
XtRealizeWidget (toplevel);
XtAppMainLoop (app_context);
}
/* file_select_cb() −− callback routine for "OK" button in
* FileSelectionDialogs.
*/
void
file_select_cb(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
char buf[256], *filename, *text;
struct stat statb;
long len;
FILE *fp;
int reason = (int) client_data;
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) call_data;
if (!XmStringGetLtoR (cbs−>value, XmFONTLIST_DEFAULT_TAG, &filename))
return; /* must have been an internal error */
if (*filename == NULL) {
XtFree (filename);
XBell (XtDisplay (text_edit), 50);
XmTextSetString (text_output, "Choose a file.");
return; /* nothing typed */
}
if (reason == FILE_SAVE) {
if (!(fp = fopen (filename, "w"))) {
perror (filename);
sprintf (buf, "Can't save to %s.", filename);
XmTextSetString (text_output, buf);
XtFree (filename);
return;
}
/* saving −− get text from Text widget... */
text = XmTextGetString (text_edit);
len = XmTextGetLastPosition (text_edit);
/* write it to file (check for error) */
if (fwrite (text, sizeof (char), len, fp) != len)
strcpy (buf, "Warning: did not write entire file!");
else {
/* make sure a newline terminates file */
if (text[len−1] != '0)
fputc ('0, fp);
sprintf (buf, "Saved %ld bytes to %s.", len, filename);
}
15 Text Widgets 15.4 A Text Editor
408
Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.