diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 2001-10-18 19:21:45 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 2001-10-18 19:21:45 +0000 |
| commit | a6ffe9abc01d4747dae35555cc21db421cdfdf95 (patch) | |
| tree | 74b35e6e2afd51b3bcbdd3a8903592d19ada0805 | |
| parent | 9da85233f979b8c73f8714e094feb01e12bd0587 (diff) | |
Fix the editor demo and associated documentation.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1638 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | CHANGES | 3 | ||||
| -rw-r--r-- | documentation/editor.html | 276 | ||||
| -rw-r--r-- | test/editor.cxx | 10 |
3 files changed, 144 insertions, 145 deletions
@@ -35,6 +35,9 @@ CHANGES IN FLTK 1.1.0b4 caused problems with the FLUID main window (flashing tooltip windows and serious problems with KDE 2.2) + - The editor demo had the save and discard button + actions reversed. + CHANGES IN FLTK 1.1.0b3 diff --git a/documentation/editor.html b/documentation/editor.html index 737afce62..236bc8162 100644 --- a/documentation/editor.html +++ b/documentation/editor.html @@ -1,6 +1,6 @@ <HTML><BODY> <H1 ALIGN=RIGHT><A NAME=editor>4 - Designing a Simple Text Editor</A></H1> - This chapter takes you through the design of a simple FLTK-based text +This chapter takes you through the design of a simple FLTK-based text editor. <H2>Determining the Goals of the Text Editor</H2> Since this will be the first big project you'll be doing with FLTK, @@ -15,68 +15,74 @@ lets define what we want our text editor to do: <LI>Keep track of when the file has been changed. </LI> </OL> <H2>Designing the Main Window</H2> - Now that we've outlined the goals for our editor, we can begin with +Now that we've outlined the goals for our editor, we can begin with the design of our GUI. Obviously the first thing that we need is a window: <UL> <PRE> -Fl_Window *window; - -window = new Fl_Window(640, 480, "Text Editor"); +class EditorWindow : public Fl_Double_Window { + public: + EditorWindow(int w, int h, const char* t); + ~EditorWindow(); + + Fl_Window *replace_dlg; + Fl_Input *replace_find; + Fl_Input *replace_with; + Fl_Button *replace_all; + Fl_Return_Button *replace_next; + Fl_Button *replace_cancel; + + Fl_Text_Editor *editor; + char search[256]; +}; </PRE> </UL> <H2>Variables</H2> - Our text editor will need some global variables to keep track of +Our text editor will need some global variables to keep track of things: <UL> <PRE> -Fl_Window *window; -Fl_Menu_Bar *menubar; -Fl_Multiline_Input *input; -Fl_Window *replace_dlg; -Fl_Input *replace_find; -Fl_Input *replace_with; -Fl_Button *replace_all; -Fl_Return_Button *replace_next; -Fl_Button *replace_cancel; - int changed = 0; char filename[1024] = ""; char search[256] = ""; +Fl_Text_Buffer *textbuf; </PRE> </UL> - The <TT>window</TT> variable is our top-level window described -previously. We'll cover the other variables as we build the -application. +The <TT>textbuf</TT> variable is the text editor buffer for our +window described previously. We'll cover the other variables as +we build the application. <H2>Menubars and Menus</H2> - The first goal requires us to use a menubar and menus that define each +The first goal requires us to use a menubar and menus that define each function the editor needs to perform. The <A href=Fl_Menu_Item.html#Fl_Menu_Item> <TT>Fl_Menu_Item</TT></A> structure is used to define the menus and items in a menubar: <UL> <PRE> Fl_Menu_Item menuitems[] = { - { "&File", 0, 0, 0, FL_SUBMENU }, - { "&New", FL_ALT + 'n', (Fl_Callback *)new_cb }, - { "&Open...", FL_ALT + 'o', (Fl_Callback *)open_cb, 0, FL_MENU_DIVIDER }, - { "&Save", FL_ALT + 's', (Fl_Callback *)save_cb }, - { "Save &As...", FL_ALT + FL_SHIFT + 's', (Fl_Callback *)saveas_cb, 0, FL_MENU_DIVIDER }, - { "&Quit", FL_ALT + 'q', (Fl_Callback *)quit_cb }, + { "&File", 0, 0, 0, FL_SUBMENU }, + { "&New File", 0, (Fl_Callback *)new_cb }, + { "&Open File...", FL_CTRL + 'o', (Fl_Callback *)open_cb }, + { "&Insert File...", FL_CTRL + 'i', (Fl_Callback *)insert_cb, 0, FL_MENU_DIVIDER }, + { "&Save File", FL_CTRL + 's', (Fl_Callback *)save_cb }, + { "Save File &As...", FL_CTRL + FL_SHIFT + 's', (Fl_Callback *)saveas_cb, 0, FL_MENU_DIVIDER }, + { "New &View", FL_ALT + 'v', (Fl_Callback *)view_cb, 0 }, + { "&Close View", FL_CTRL + 'w', (Fl_Callback *)close_cb, 0, FL_MENU_DIVIDER }, + { "E&xit", FL_CTRL + 'q', (Fl_Callback *)quit_cb, 0 }, { 0 }, { "&Edit", 0, 0, 0, FL_SUBMENU }, - { "&Undo", FL_ALT + 'z', (Fl_Callback *)undo_cb, 0, FL_MENU_DIVIDER }, - { "Cu&t", FL_ALT + 'x', (Fl_Callback *)cut_cb }, - { "&Copy", FL_ALT + 'c', (Fl_Callback *)copy_cb }, - { "&Paste", FL_ALT + 'v', (Fl_Callback *)paste_cb }, + { "&Undo", FL_CTRL + 'z', (Fl_Callback *)undo_cb, 0, FL_MENU_DIVIDER }, + { "Cu&t", FL_CTRL + 'x', (Fl_Callback *)cut_cb }, + { "&Copy", FL_CTRL + 'c', (Fl_Callback *)copy_cb }, + { "&Paste", FL_CTRL + 'v', (Fl_Callback *)paste_cb }, { "&Delete", 0, (Fl_Callback *)delete_cb }, { 0 }, { "&Search", 0, 0, 0, FL_SUBMENU }, - { "&Find...", FL_ALT + 'f', (Fl_Callback *)find_cb }, - { "F&ind Again", FL_ALT + 'g', (Fl_Callback *)find2_cb }, - { "&Replace...", FL_ALT + 'r', (Fl_Callback *)replace_cb }, - { "Re&place Again", FL_ALT + 't', (Fl_Callback *)replace2_cb }, + { "&Find...", FL_CTRL + 'f', (Fl_Callback *)find_cb }, + { "F&ind Again", FL_CTRL + 'g', find2_cb }, + { "&Replace...", FL_CTRL + 'r', replace_cb }, + { "Re&place Again", FL_CTRL + 't', replace2_cb }, { 0 }, { 0 } @@ -84,38 +90,40 @@ Fl_Menu_Item menuitems[] = { </PRE> </UL> Once we have the menus defined we can create the <TT>Fl_Menu_Bar</TT> - widget and assign the menus to it with: +widget and assign the menus to it with: <UL> <PRE> -Fl_Menu_Bar *menubar = new Fl_Menu_Bar(0, 0, 640, 30); -menubar->menu(menuitems); +Fl_Menu_Bar *m = new Fl_Menu_Bar(0, 0, 512, 30); +m->copy(menuitems); </PRE> </UL> - We'll define the callback functions later. +We'll define the callback functions later. <H2>Editing the Text</H2> - To keep things simple our text editor will use the <A href=Fl_Multiline_Input.html#Fl_Multiline_Input> -<TT>Fl_Multiline_Input</TT></A> widget to edit the text: +To keep things simple our text editor will use the +<A HREF="Fl_Text_Editor.html#Fl_Text_Editor"><TT>Fl_Text_Editor</TT></A> +widget to edit the text: <UL> <PRE> -Fl_Multiline_Input *input = new Fl_Multiline_Input(0, 30, 640, 450); +w->editor = new Fl_Text_Editor(0, 30, 512, 354); +w->editor->buffer(textbuf); </PRE> </UL> - So that we can keep track of changes to the file, we also want to add -a "changed" callback: +So that we can keep track of changes to the file, we also want to add +a "modify" callback: <UL> <PRE> -input->callback(changed_cb); -input->when(FL_WHEN_CHANGED); +textbuf->add_modify_callback(changed_cb, w); +textbuf->call_modify_callbacks(); </PRE> </UL> - Finally, we want to use a mono-spaced font like <TT>FL_COURIER</TT>: +Finally, we want to use a mono-spaced font like <TT>FL_COURIER</TT>: <UL> <PRE> -input->textfont(FL_COURIER); +w->editor->textfont(FL_COURIER); </PRE> </UL> <H2>The Replace Dialog</H2> - We can use the FLTK convenience functions for many of the editor's +We can use the FLTK convenience functions for many of the editor's dialogs, however the replace dialog needs its own custom window. To keep things simple we will have a "find" string, a "replace" string, and "replace all", "replace next", and "cancel" buttons. The strings @@ -134,7 +142,7 @@ Fl_Button *replace_cancel = new Fl_Button(230, 70, 60, 25, "Cancel"); </PRE> </UL> <H2>Callbacks</H2> - Now that we've defined the GUI components of our editor, we need to +Now that we've defined the GUI components of our editor, we need to define our callback functions. <H3>changed_cb()</H3> This function will be called whenever the user changes any text in the <TT> @@ -298,91 +306,102 @@ void quit_cb(void) { The replace callback just shows the replace dialog: <UL> <PRE> -void replace_cb(void) { - replace_dlg->show(); +void replace_cb(Fl_Widget*, void* v) { + EditorWindow* e = (EditorWindow*)v; + e->replace_dlg->show(); } </PRE> </UL> <H3>replace2_cb()</H3> - This callback will replace the next occurence of the replacement +This callback will replace the next occurence of the replacement string. If nothing has been entered for the replacement string, then the replace dialog is displayed instead: <UL> <PRE> -void replace2_cb() { - const char *find, *val, *found; - int pos; +void replace2_cb(Fl_Widget*, void* v) { + EditorWindow* e = (EditorWindow*)v; + const char *find = e->replace_find->value(); + const char *replace = e->replace_with->value(); - find = replace_find->value(); if (find[0] == '\0') { // Search string is blank; get a new one... - replace_dlg->show(); + e->replace_dlg->show(); return; } - val = input->value() + input->position(); - found = strstr(val, find); + e->replace_dlg->hide(); - if (found != NULL) { + int pos = e->editor->insert_position(); + int found = textbuf->search_forward(pos, find, &pos); + + if (found) { // Found a match; update the position and replace text... - pos = input->position() + found - val; - input->replace(pos, pos + strlen(find), replace_with->value()); - input->position(pos + strlen(replace_with->value())); + textbuf->select(pos, pos+strlen(find)); + textbuf->remove_selection(); + textbuf->insert(pos, replace); + textbuf->select(pos, pos+strlen(replace)); + e->editor->insert_position(pos+strlen(replace)); + e->editor->show_insert_position(); } else fl_alert("No occurrences of \'%s\' found!", find); } </PRE> </UL> <H3>replall_cb()</H3> - This callback will replace all occurences of the search string in the +This callback will replace all occurences of the search string in the file: <UL> <PRE> -void replall_cb() { - const char *find, *val, *found; - int pos; - int times; +void replall_cb(Fl_Widget*, void* v) { + EditorWindow* e = (EditorWindow*)v; + const char *find = e->replace_find->value(); + const char *replace = e->replace_with->value(); - find = replace_find->value(); + find = e->replace_find->value(); if (find[0] == '\0') { // Search string is blank; get a new one... - replace_dlg->show(); + e->replace_dlg->show(); return; } - input->position(0); - times = 0; + e->replace_dlg->hide(); + + e->editor->insert_position(0); + int times = 0; // Loop through the whole string - do { - val = input->value() + input->position(); - found = strstr(val, find); + for (int found = 1; found;) { + int pos = e->editor->insert_position(); + found = textbuf->search_forward(pos, find, &pos); - if (found != NULL) { + if (found) { // Found a match; update the position and replace text... - times ++; - pos = input->position() + found - val; - input->replace(pos, pos + strlen(find), replace_with->value()); - input->position(pos + strlen(replace_with->value())); + textbuf->select(pos, pos+strlen(find)); + textbuf->remove_selection(); + textbuf->insert(pos, replace); + e->editor->insert_position(pos+strlen(replace)); + e->editor->show_insert_position(); + times++; } - } while (found != NULL); + } - if (times > 0) fl_message("Replaced %d occurrences.", times); + if (times) fl_message("Replaced %d occurrences.", times); else fl_alert("No occurrences of \'%s\' found!", find); } </PRE> </UL> <H3>replcan_cb()</H3> - This callback just hides the replace dialog: +This callback just hides the replace dialog: <UL> <PRE> -void replcan_cb() { - replace_dlg->hide(); +void replcan_cb(Fl_Widget*, void* v) { + EditorWindow* e = (EditorWindow*)v; + e->replace_dlg->hide(); } </PRE> </UL> <H3>save_cb()</H3> - This callback saves the current file. If the current filename is +This callback saves the current file. If the current filename is blank it calls the "save as" callback: <UL> <PRE> @@ -433,14 +452,16 @@ so, it asks the user if they want to save it: int check_save(void) { if (!changed) return 1; - if (fl_ask("The current file has not been saved.\n" - "Would you like to save it now?")) { - // Save the file... - save_cb(); + int r = fl_choice("The current file has not been saved.\n" + "Would you like to save it now?", + "Cancel", "Save", "Discard"); + if (r == 1) { + save_cb(); // Save the file... return !changed; } - else return (1); + + return (r == 2) ? 1 : 0; } </PRE> </UL> @@ -448,63 +469,38 @@ int check_save(void) { This function loads the specified file into the <TT>input</TT> widget: <UL> <PRE> -void load_file(char *newfile) { - FILE *fp; - char buffer[8192]; - int nbytes; - int pos; - - input->value(""); - - fp = fopen(newfile, "r"); - if (fp != NULL) { - // Was able to open file; let's read from it... - strcpy(filename, newfile); - pos = 0; - - while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) { - input->replace(pos, pos, buffer, nbytes); - pos += nbytes; - } - - fclose(fp); - input->position(0); - set_changed(0); - } else { - // Couldn't open file - say so... - fl_alert("Unable to open \'%s\' for reading!"); - } +int loading = 0; +void load_file(char *newfile, int ipos) { + loading = 1; + int insert = (ipos != -1); + changed = insert; + if (!insert) strcpy(filename, ""); + int r; + if (!insert) r = textbuf->loadfile(newfile); + else r = textbuf->insertfile(newfile, ipos); + if (r) + fl_alert("Error reading from file \'%s\':\n%s.", newfile, strerror(errno)); + else + if (!insert) strcpy(filename, newfile); + loading = 0; + textbuf->call_modify_callbacks(); } </PRE> </UL> - When loading the file we use the <A href=Fl_Input_.html#Fl_Input_.replace> -<TT>input->replace()</TT></A> method to "replace" the text at the end -of the buffer. The <TT>pos</TT> variable keeps track of the end of the -buffer. +When loading the file we use the +<A href="Fl_Text_Buffer.html#Fl_Text_Buffer.insertfile"><TT>loadfile()</TT></A> +method to "replace" the text in the buffer. <H3>save_file()</H3> - This function saves the current buffer to the specified file: +This function saves the current buffer to the specified file: <UL> <PRE> void save_file(char *newfile) { - FILE *fp; - - fp = fopen(newfile, "w"); - if (fp != NULL) { - // Was able to create file; let's write to it... + if (textbuf->savefile(newfile)) + fl_alert("Error writing to file \'%s\':\n%s.", newfile, strerror(errno)); + else strcpy(filename, newfile); - - if (fwrite(input->value(), 1, input->size(), fp) < 1) { - fl_alert("Unable to write file!"); - fclose(fp); - return; - } - - fclose(fp); - set_changed(0); - } else { - // Couldn't open file - say so... - fl_alert("Unable to create \'%s\' for writing!"); - } + changed = 0; + textbuf->call_modify_callbacks(); } </PRE> </UL> diff --git a/test/editor.cxx b/test/editor.cxx index 8ee30b17d..13faad636 100644 --- a/test/editor.cxx +++ b/test/editor.cxx @@ -1,5 +1,5 @@ // -// "$Id: editor.cxx,v 1.2.2.3.2.2 2001/09/30 17:37:06 easysw Exp $" +// "$Id: editor.cxx,v 1.2.2.3.2.3 2001/10/18 19:21:45 easysw Exp $" // // A simple text editor program for the Fast Light Tool Kit (FLTK). // @@ -109,12 +109,12 @@ int check_save(void) { "Would you like to save it now?", "Cancel", "Save", "Discard"); - if (r == 2) { + if (r == 1) { save_cb(); // Save the file... return !changed; - }; + } - return (r == 1) ? 1 : 0; + return (r == 2) ? 1 : 0; } int loading = 0; @@ -424,5 +424,5 @@ int main(int argc, char **argv) { } // -// End of "$Id: editor.cxx,v 1.2.2.3.2.2 2001/09/30 17:37:06 easysw Exp $". +// End of "$Id: editor.cxx,v 1.2.2.3.2.3 2001/10/18 19:21:45 easysw Exp $". // |
