Subsections

Text Widgets

   

Text editing is a key task in many applications. For example, Single-line editors are a convenient and flexible means of string data entry for many applications. Indeed, the FileSelectionDialog widget (Chapter 9) and other composite widgets have a single text widget as constituent components. More complete multi-line text entry may also be required for many applications.

Motif, conveniently provides a fully functional text widget. This saves the application programmer a lot of work, since tasks such as cut and paste editing, text search and insertion are provided within the widget class.

Note: Coupled with other advanced facilities such as FileSelection widgets etc., we could easily assemble our own fully working text editor application program from component widget classes and little other code.

Motif 1.2 provides two classes of text widgets:

Text widget
   -- A fully functional multiline windows based text editor.
TextField
   -- A single line text editor.

Both the above widgets use the (standard C) String data type as the base structure for all text operations. This is different from most other Motif widgets. Motif 2.0 provides an additional text widget, CSText  , which is basically similar to the Text widget except that the XmString data type is used in text processing.

We will study the Text widget in detail in this Chapter. The TextField is, essentially, a simpler version of this and will therefore only be addressed when appropriate. In fact, we can actually make the Text widget a single line type by setting the resource XmNeditMode   to XmSINGLE_LINE_EDIT .

Text Widget Creation

 

There are a variety of ways to create a Text widget:

There are various resources that can be usefully set for a Text widget:

XmNrows
  -- The visible number of rows.
XmNcolumns
  -- The visible number of columns.
XmNeditable
  -- True or False: determines whether editing of displayed text is allowed.
XmNscrollHorizontal
  -- True or False: Turn scrolling On/Off in this direction.
XmNscrollVertical
  -- True or False: Turn scrolling On/Off in this direction.

Putting text into a Text Widget

 

The Text widget is a dynamic structure and text may be inserted into the widget at any time. There are many text editing and insertion functions that will be introduced shortly. The simplest operation is actually setting the text that will be used by the Text widget.

The function XmTextSetString()  puts a specified ordinary (C type) string into a specified widget. It has two arguments:

Widget
-- the Text widget,
String
-- The text being placed in the widget.

Example Text Program - text.c

  This program is a fairly simple example of the Text widget in use.

 

Fig. 10.1 ScrolledText Widget

#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/MainW.h>
#include <Xm/CascadeB.h>

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>


/* Prototype Callback and other functions */

void  quit_call(), 
      help_call(), 
      read_file(Widget);

main(int argc, char *argv[])

{   Widget        top_wid, main_w, menu_bar, 
                  menu, quit, help, text_wid;
    XtAppContext  app;
    Arg           args[4];

    /* initialize */
    top_wid = XtVaAppInitialize(&app, "Text",
        NULL, 0, &argc, argv, NULL, NULL);

        main_w = XtVaCreateManagedWidget("main_w",
        xmMainWindowWidgetClass, top_wid,
        /* XmNscrollingPolicy,   XmVARIABLE, */
        NULL);
   
    menu_bar = XmCreateMenuBar(main_w, "main_list", 
        NULL, 0);        
    XtManageChild(menu_bar);
      
     /* create quit widget + callback */
        
    quit = XtVaCreateManagedWidget( "Quit",
        xmCascadeButtonWidgetClass, menu_bar,
        XmNmnemonic, 'Q',
        NULL);

        
    XtAddCallback(quit, XmNactivateCallback, 
        quit_call, NULL);

    /* Create ScrolledText -- this is work area for the 
       MainWindow */
    
    XtSetArg(args[0], XmNrows,      30);
    XtSetArg(args[1], XmNcolumns,   80);
    XtSetArg(args[2], XmNeditable,  False);
    XtSetArg(args[3], XmNeditMode,  XmMULTI_LINE_EDIT);
    text_wid = XmCreateScrolledText(main_w, "text_wid", 
                                    args, 4);
    XtManageChild(text_wid);

    /*  read file and put data in text widget */
    read_file(text_wid);
    
    XtRealizeWidget(top_wid);
    XtAppMainLoop(app);
}

void read_file(Widget  text_wid)

{
    static char *filename = "text.c";
    char  *text;
    struct stat statb;
    FILE *fp;

   /* check file is a regular text file and open it */

    if ( (stat(filename, &statb) == -1) 
         || !(fp = fopen(filename, "r"))) 
    {   fprintf(stderr, "Cannot open file: %s\n", filename);
        XtFree(filename);
        return;
    }

    /* Map file text in the TextWidget */    
    
    if (!(text = XtMalloc((unsigned)(statb.st_size+1)))) 
    {   fprintf(stderr, "Can't alloc enough space for %s", 
                filename);
        XtFree(filename);
        fclose(fp);
        return;
    }

    if (!fread(text, sizeof(char), statb.st_size+1, fp))
        fprintf(stderr, "File read error\n");

    text[statb.st_size] = 0; /* be sure to NULL-terminate */

    /* insert file contents in TextWidget */
    
    XmTextSetString(text_wid, text);
  
    /* free memory 
    */
    XtFree(text);
    XtFree(filename);
    fclose(fp);
}

void quit_call()

{   printf("Quitting program\n");
    exit(0);
}

Editing Text

 

Motif provides many functions that allow the editing of the text (String) stored in the widget. Text can be searched, inserted and replaced.

To replace all or parts of the text in a Text widget use the XmTextReplace()  function. It has four arguments:

Widget
-- The Text widget.
Start Position (XmTextPosition type)
-- A long int measured in bytes. Specifies where to begin inserting text.
End Position (XmTextPosition type)
-- The end insertion point.
New text
-- The String that will replace existing text.

No matter how long the specified replacement text string is, text is only replaced (character-by-character) between the 2 positions. However, if the start and end positions are equal then text is inserted after the given position.

An alternative method to insert text , is to use the XmTextInsert()  function. This takes 3 arguments:

Widget
-- the Text Widget,
Insert Position
-- the XmTextPosition for the insertion,
Insertion Text
-- the text String.

To Search for a string in the Text widget , use the XmTextFindString()  function with the following arguments:

Text Widget
-- to be searched,
Start Position
-- as before,
Search String,
Search Direction
-- either XmTEXT_FORWARD or XmTEXT_BACKWARD,
Position
-- a XmTextPosition pointer that returns the position found.

XmTextFindString() returns a Boolean value which is False if no string was found.



To obtain text  (in full) from a Text widget use the XmTextGetString()  function to return a String for a specified widget. An example use of this function is to save text stored in the Text widget to a file. This can be simply achieved by:

The function XmTextGetSubstring() can be used to get a portion of text from a widget. It takes 5 arguments:

Text Widget
-- from where the substring is to be obtained.
Start Position
-- the XmTextPostition of the first character in the substring to be returned.
Number of Characters
-- to be copied from the substring.
Buffer Size
-- the number of characters in the String buffer where the substring is copied to.
String
-- a pointer to a String buffer which will hold the substring value when this function is returned.

Similar functions exist for both the TextField and the CSText widgets. An example of these functions in use with the TextField widget is given is Section 10.7.

Scrolling Control

  Motif provides a variety of functions to control the scrolling of the text within a Text widget. Thus, the application programmer has control over which portions of text can be displayed at a given time. The following options are available:

Similar functions exist for both the TextField and the CSText widgets. An example of these functions in use with the TextField widget is given is Section 10.7.

Text Callbacks

 

Behind almost all of the Text widget functions, described above, lie default callback resources. These control the basic text editing facilities: cut and paste, searching etc. However, there may be occasions when the application may need greater control over things. Several callback resources are provided for this purpose. Briefly theses are:

XmNactivateCallback
  -- Called on Enter key press (only single-line Text widgets).
XmNverifyCallback
  -- Used to verify a change to text before it is made.
XmNvalueChangedCallback
  -- Called after a change to text has been made.
XmNmotionCallback
  -- Called when the user has altered the cursor position, or made a text selection with mouse .
XmNfocusCallback
  -- Called when the user wants to begin input.
XmNlosingfocusCallback
  -- Called when the widget is losing keyboard focus.

We can use verifyCallbacks for checking user inputs -- for example for password verification.

Editing and Scrolling in Practice

 

The test_for_echo.c program (Section 8.3) illustrates the use of some of the editing and scrolling functions described. The program basically operates as follows:

Exercises

Exercise 7025

Modify the text.c (Section 10.3) so that it employs a FileSelection widget to allow the user to select a file, which it then reads and displays in a ScrolledText Widget .

MORE EXERCISES


Dave Marshall
1/5/1999