// Name : Motif Text Editor // Author : Terrence Ma // Email : terrence@terrence.com // Web : http://www.terrence.com // Date : V1.0 11/16/2002 // Modified : CDE and Motif, scrolled.c p.225 /* * Program: scrolledtext - This program illustrates the use of a * scrolled text widget. * * Author : Antonino N. Mione * * Date : 22-Nov-1995 * */ #include #include #include #include #include #include #include /* X and Motif headers */ #include #include #include #include #include #include #include #include #include #include #include /* * Some commonly used buffer sizes for strings and data. */ #define SMALL_BUF_SIZE 64 #define LARGE_BUF_SIZE 256 #define HUGE_BUF_SIZE 1024 #define MAX_BUTTONS 3 #define MAX_READ 2048 #define MAX_WRITE 2048 /* Some key X, toolkit, and Motif variables */ /* Widget ids */ Widget toplevel; /* toplevel shell widget id */ Widget buttons[ MAX_BUTTONS ]; /* Buttons for functions: WorkingDialog, etc. */ Widget mainw; /* Main window to hold everything */ Widget form; /* Form widget */ Widget scrolledtext; /* Scrolled Text widget */ Widget separate; /* Separator widget */ Widget rowcol; /* Rowcol for quit button */ Widget filesb; /* File selection box widget */ Widget msgtext; /* Text widget for the message area */ XtAppContext app_context; /* Application context info (used by toolkit) */ /* * Following are button labels and enumerated variables for button * choices. */ char *buttonlabels[] = { "Open", "Save", "Quit" }; enum button_nums { opOpen=1, opSave, opQuit }; #define open_button 0 #define save_button 1 #define quit_button 2 enum file_operations { none, openning, saving }; enum file_operations fileop; #define okButton 0 #define cancelButton 1 FILE *filehandle; /* Prototypes */ void msgText ( char * ); Boolean read_file ( FILE *filehandle ); Boolean save_file ( FILE *filehandle ); void buttonCallback ( Widget, XtPointer, XtPointer ); void filesbButtonCallback ( Widget, XtPointer, XtPointer ); void init_widgets ( void ); int main ( int, char ** ); /* * procedure : msgText - Write a message to the message area. * * arguments : msg ( in / (char *) ) - Text to be written to message area. * * return : void * * side effects : */ void msgText ( char *msg ) { XmTextPosition text_pos; /* Last position in text area */ /* * Find last position used in the message area and insert the new message * there. */ text_pos = XmTextGetLastPosition ( msgtext ); XmTextInsert ( msgtext, text_pos, msg ); } /* * procedure : read_file - This procedure reads a file into the * scrolled text widget. * * arguments : filehandle - The filehandle from which to read. * * return : True/False indicating the success of the operation. * * side effects : none. */ Boolean read_file ( FILE *filehandle ) { XmTextPosition pos = 0; /* Last position filled in text widget */ char buf[ MAX_READ ]; /* Buffer for reading characters from file */ /* * Clear any text in the scrolled text widget. */ XmTextSetString ( scrolledtext, "" ); /* * As long as fgets succeeds, continue appending what is read to the * scrolled text widget's value. Use pos to track last filled position * so the XmTextInsert function appends to the existing value. */ while ( fgets ( buf, MAX_READ, filehandle ) != NULL ) { XmTextInsert ( scrolledtext, pos, buf ); pos += strlen ( buf ); } return True; } /* * procedure : save_file - This procedure writes the contents of the * scrolled text widget into a file. * * arguments : filehandle - The filehandle to which to write. * * return : True/False indicating the success of the operation. * * side effects : none. */ Boolean save_file ( FILE *filehandle ) { char *stext_string; /* Temporary storage for text widgets' value */ int status; /* Status returned from fputs */ /* * Fetch the entire text value from the widget and write it to the file * in one operation. */ stext_string = XmTextGetString ( scrolledtext ); status = fputs ( stext_string, filehandle ); XtFree ( stext_string ); /* * Check the return status from the file write. If it succeeded, clear * the widget's value and return true. Otherwise, return false. */ if ( status ) { XmTextSetString ( scrolledtext, "" ); return True; } else { return False; } } /* * procedure : buttonCallback - Callback when user activates a button. * * arguments : widgetId ( in / (Widget) ) - widgetId of widget causing * the callback. * clientData ( in / (XtPointer) ) - value passed to routine * by the widget. * cbr ( in / (XtPointer) ) - the callbackRecord. This * contains additional information pertinent to the * event causing the callback. * * return : none. * * side effects : none. */ void buttonCallback ( Widget widgetId, XtPointer clientData, XtPointer cbr ) { /* Cast callback record and client data to the correct type. */ XmPushButtonCallbackStruct *callbackRecord = (XmPushButtonCallbackStruct *) cbr; enum button_nums button_num = (enum button_nums) clientData; XmString tempCString; Arg args[ 10 ]; Cardinal arg_count; /* * Select process based on button number. */ switch ( button_num ) { case opOpen: /* Open a file */ fileop = openning; /* * Configure the file selection dialog and post it. */ #if XmVERSION >= 2 tempCString = XmStringGenerate ( "File to open", NULL, XmCHARSET_TEXT, NULL ); #else tempCString = XmStringCreateLocalized ( "File to open" ); #endif XtVaSetValues ( filesb, XmNselectionLabelString, tempCString, NULL ); XtManageChild ( filesb ); XmStringFree ( tempCString ); break; case opSave: /* Save text to a file */ fileop = saving; /* * Configure the file selection dialog and post it. */ #if XmVERSION >= 2 tempCString = XmStringGenerate ( "File to save", NULL, XmCHARSET_TEXT, NULL ); #else tempCString = XmStringCreateLocalized ( "File to save" ); #endif XtVaSetValues ( filesb, XmNselectionLabelString, tempCString, NULL ); XtManageChild ( filesb ); XmStringFree ( tempCString ); break; case opQuit: /* Exit the application */ exit ( 0 ); break; } return; } /* * procedure : filesbButtonCallback - This routine is called when a * file selection box button has been * activated. * * arguments : none * * return : void * * side effects : none */ void filesbButtonCallback ( Widget widgetId, XtPointer clientData, XtPointer cbr ) { /* Cast callback record and client data to the correct type. */ XmFileSelectionBoxCallbackStruct *callbackRecord = (XmFileSelectionBoxCallbackStruct *) cbr; int button_num = (int) clientData; char *filename; Boolean status; /* Convert the filename to ascii */ status = XmStringGetLtoR ( callbackRecord->value, XmFONTLIST_DEFAULT_TAG, &filename ); /* * If there was an error retrieving the filename, ring the bell and return. * If the filename was empty, do the same. */ if ( !status ) { XBell ( XtDisplay ( toplevel ), 50 ); return; } if ( !*filename ) { XtFree ( filename ); XBell ( XtDisplay ( toplevel ), 50 ); return; } /* * If the user clicked 'ok', check whether we are openning or saving to * the file. Perform the appropriate operations for each. */ if ( button_num == okButton ) { if ( fileop == openning ) { filehandle = fopen ( filename, "r" ); read_file ( filehandle ); fclose ( filehandle ); } else { filehandle = fopen ( filename, "w" ); save_file ( filehandle ); fclose ( filehandle ); } fileop = none; } } /* * procedure : init_widgets - This routine initializes all of the * widgets for the application. * * arguments : none * * return : void * * side effects : none */ void init_widgets ( void ) { Arg args[ 10 ]; /* Argument array for widget creation */ Cardinal arg_count; /* Count of valid arguments */ char tempName[ LARGE_BUF_SIZE ]; /* Work space to build widget names */ int temp_idx; /* Loop index */ int button_num; /* Button num for activate callback */ Widget temp_id_hs, temp_id_vs; /* * Create a main window. */ arg_count = 0; mainw = XmCreateMainWindow ( toplevel, "mainw", args, arg_count ); /* * Create the form to hold everything else. */ arg_count = 0; form = XmCreateForm ( mainw, "form", args, arg_count ); /* XtManageChild ( form ); */ /* * Create a scrolled text widget as a child of the form. * Make it an editable Multi-line text widget (24x80). */ arg_count = 0; /* XtSetArg ( args[ arg_count ], XmNrows, 24 ); arg_count++; XtSetArg ( args[ arg_count ], XmNcolumns, 80 ); arg_count++; */ XtSetArg ( args[ arg_count ], XmNeditMode, XmMULTI_LINE_EDIT ); arg_count++; XtSetArg ( args[ arg_count ], XmNeditable, True ); arg_count++; XtSetArg ( args[ arg_count ], XmNtopAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNleftAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNrightAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNbottomAttachment, XmATTACH_NONE ); arg_count++; scrolledtext = XmCreateScrolledText ( form, "scrolledtext", args, arg_count ); /* Manage the scrolledtext widget */ XtManageChild ( scrolledtext ); /* * Create a separator to separate the scrolledtext and rowcolumn widgets. */ arg_count = 0; XtSetArg ( args[ arg_count ], XmNtopAttachment, XmATTACH_WIDGET ); arg_count++; XtSetArg ( args[ arg_count ], XmNtopWidget, scrolledtext ); arg_count++; XtSetArg ( args[ arg_count ], XmNleftAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNrightAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNbottomAttachment, XmATTACH_NONE ); arg_count++; separate = XmCreateSeparator ( form, "separate", args, arg_count ); XtManageChild ( separate ); /* * Create a rowcolumn widget as a child of the main window to hold any * buttons. */ arg_count = 0; XtSetArg ( args[ arg_count ], XmNtopAttachment, XmATTACH_WIDGET ); arg_count++; XtSetArg ( args[ arg_count ], XmNtopWidget, separate ); arg_count++; XtSetArg ( args[ arg_count ], XmNleftAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNrightAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNbottomAttachment, XmATTACH_FORM ); arg_count++; XtSetArg ( args[ arg_count ], XmNorientation, XmHORIZONTAL ); arg_count++; rowcol = XmCreateRowColumn ( form, "rowcol", args, arg_count ); XtManageChild ( rowcol ); /* * For each item in buttonlabels, * - generate a name for the new button widget. * - create a button child for the rowcolumn * - add an activate callback. * - manage the new button. */ for ( temp_idx = 0; temp_idx < XtNumber ( buttonlabels ); temp_idx++ ) { button_num = temp_idx + 1; sprintf ( tempName, "button_%d", button_num ); arg_count = 0; buttons[ temp_idx ] = XmCreatePushButton ( rowcol, tempName, args, arg_count ); XtAddCallback ( buttons[ temp_idx ], XmNactivateCallback, buttonCallback, (XtPointer) button_num ); XtManageChild ( buttons[ temp_idx ] ); } /* * Create a text widget for the message area. */ arg_count = 0; XtSetArg ( args[ arg_count ], XmNeditMode, XmMULTI_LINE_EDIT ); arg_count++; XtSetArg ( args[ arg_count ], XmNeditable, False ); arg_count++; msgtext = XmCreateText ( mainw, "msgtext", args, arg_count ); XtManageChild ( msgtext ); /* * Set the various areas for the main window. Also, since we are using * a scrolled text widget, we do not need the Main Window's scrollbars * so unmanage them as well. */ XtVaSetValues ( mainw, XmNmessageWindow, msgtext, XmNworkWindow, form, XmNshowSeparator, True, NULL ); XtVaGetValues ( mainw, XmNhorizontalScrollBar, &temp_id_hs, XmNverticalScrollBar, &temp_id_vs, NULL ); XtUnmanageChild ( temp_id_hs ); XtUnmanageChild ( temp_id_vs ); XtManageChild ( form ); /* XtUnmanageChild ( XtNameToWidget ( mainw, "*HorScrollBar" ) ); XtUnmanageChild ( XtNameToWidget ( mainw, "*VertScrollBar" ) ); */ /* * Create (but don't manage) a file selection box. This dialog will be * used to get filenames for read and save operations. */ arg_count = 0; XtSetArg ( args[ arg_count ], XmNautoUnmanage, True ); arg_count++; filesb = XmCreateFileSelectionDialog ( toplevel, "filesb", args, arg_count ); XtAddCallback ( filesb, XmNokCallback, filesbButtonCallback, (XtPointer) okButton ); XtAddCallback ( filesb, XmNcancelCallback, filesbButtonCallback, (XtPointer) cancelButton ); XtManageChild ( mainw ); } /* * procedure : main - The main routine. This is where it all begins. * * arguments : argc (in / (int)) - number of command line arguments. * argv (in / (char **)) - pointer to the argument strings. * * return : (int) - status value. success/failure of program * * side effects : lots */ int main ( int argc, char *argv[] ) { /* * In case the app-defaults file is not there, these resources will make * the application usable. */ String fallbacks[] = { "Scrolledtext*separate.shadowThickness: 3", "Scrolledtext*separate.SeparatorType: SHADOW_ETCHED_IN_DASH", "Scrolledtext*separate.topOffset: 5", "Scrolledtext*scrolledtext.rows: 24", "Scrolledtext*scrolledtext.columns: 80", "Scrolledtext*scrolledtextSW.scrollingPolicy: AUTOMATIC", "Scrolledtext*scrolledtextSW.visualPolicy: CONSTANT", "Scrolledtext*scrolledtextSW.scrollBarDisplayPolicy: AS_NEEDED", "Scrolledtext*button_1.labelString: Open", "Scrolledtext*button_2.labelString: Save", "Scrolledtext*button_3.labelString: Quit", "Scrolledtext*filesb.dialogTitle: File Open/Save dialog", (char *) NULL }; toplevel = XtAppInitialize ( &app_context, /* Application context */ "Scrolledtext", /* Application class string */ NULL, /* Options */ 0, /* Number of Options */ &argc, /* Command line arg cnt in/out */ argv, /* Command line args in/out */ fallbacks, /* Fallback (last chance) resources */ NULL, /* Arguments */ 0 ); /* Number of Arguments */ init_widgets (); /* Build the interface */ fileop = none; /* Currently not reading or saving any file */ XtRealizeWidget ( toplevel ); /* Realize the widgets (i.e. create the widget data structures */ XtAppMainLoop ( app_context ); /* Jump into the main loop. This never returns. */ }