>Fl_Window *window; > >window = new Fl_Window(640, 480, "Text Editor"); >
>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] = ""; >The >window> variable >is >our >top-level >window > described > previously. >We'll >cover >the >other > variables >as >we >build >the > application. >
>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 }, > { 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 }, > { "&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 }, > { 0 }, > > { 0 } >}; >Once >we >have >the >menus >defined >we >can >create > the >Fl_Menu_Bar> widget >and >assign >the >menus > to >it >with: >
>Fl_Menu_Bar *menubar = new Fl_Menu_Bar(0, 0, 640, 30); >menubar->menu(menuitems); >We'll >define >the >callback >functions >later. >
>Fl_Multiline_Input *input = new Fl_Multiline_Input(0, 30, 640, 450); >So >that >we >can >keep >track >of >changes >to >the > file, >we >also >want >to >add > a >"changed" > callback: >
>input->callback(changed_cb); >input->when(FL_WHEN_CHANGED); >Finally, >we >want >to >use >a >mono-spaced >font > like >FL_COURIER>: >
>input->textfont(FL_COURIER); >
>Fl_Window *replace_dlg = new Fl_Window(300, 105, "Replace"); >Fl_Input *replace_find = new Fl_Input(70, 10, 200, 25, "Find:"); >Fl_Input *replace_with = new Fl_Input(70, 40, 200, 25, "Replace:"); >Fl_Button *replace_all = new Fl_Button(10, 70, 90, 25, "Replace All"); >Fl_Button *replace_next = new Fl_Button(105, 70, 120, 25, "Replace Next"); >Fl_Button *replace_cancel = new Fl_Button(230, 70, 60, 25, "Cancel"); >
>void changed_cb(void) { > set_changed(1); >} >The >set_changed()> function >is >one >that >we > will >write >to >set > the >changed >status >on >the > current >file. > We're >doing >it >this >way > because > some >of >the >other >callbacks >will >set >the > changed >status >to >0, > and >also >because >we >want > to >show >the >changed >status >in >the >window's > title >bar. >
>void copy_cb(void) { > input->copy(); >} >
>void cut_cb(void) { > input->copy(); > input->cut(); >} >
>void delete_cb(void) { > input->cut(); >} >
>void find_cb(void) { > const char *val; > > val = fl_input("Search String:", search); > if (val != NULL) { > // User entered a string - go find it! > strcpy(search, val); > find2_cb(); > } >} >
>void find2_cb(void) { > const char *val, *found; > int pos; > > if (search[0] == '\0') { > // Search string is blank; get a new one... > find_cb(); > return; > } > > val = input->value() + input->mark(); > found = strstr(val, search); > > if (found != NULL) { > // Found a match; update the position and mark... > pos = input->mark() + found - val; > input->position(pos, pos + strlen(search)); > } > else fl_alert("No occurrences of \'%s\' found!", search); >} >If >the >search >string >cannot >be >found >we >use > the > fl_alert()> convenience > function >to >display >a >message >to >that > effect. >
>void new_cb(void) { > if (changed) > if (!check_save()) return; > > filename[0] = '\0'; > input->value(""); > set_changed(0); >} >
>void open_cb(void) { > char *newfile; > > if (changed) > if (!check_save()) return; > > newfile = fl_file_chooser("Open File?", "*", filename); > if (newfile != NULL) load_file(newfile); >} >We >call >the >load_file()> function >to > actually >load >the >file. >
>void paste_cb(void) { > Fl::paste(*input); >} >
>void quit_cb(void) { > if (changed) > if (!check_save()) > return; > > window->hide(); >} >
>void replace_cb(void) { > replace_dlg->show(); >} >
>void replace2_cb() { > const char *find, *val, *found; > int pos; > > find = replace_find->value(); > if (find[0] == '\0') { > // Search string is blank; get a new one... > replace_dlg->show(); > return; > } > > val = input->value() + input->position(); > found = strstr(val, find); > > if (found != NULL) { > // 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())); > } > else fl_alert("No occurrences of \'%s\' found!", find); >} >
>void replall_cb() { > const char *find, *val, *found; > int pos; > int times; > > find = replace_find->value(); > if (find[0] == '\0') { > // Search string is blank; get a new one... > replace_dlg->show(); > return; > } > > input->position(0); > times = 0; > > // Loop through the whole string > do { > val = input->value() + input->position(); > found = strstr(val, find); > > if (found != NULL) { > // 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())); > } > } while (found != NULL); > > if (times > 0) fl_message("Replaced %d occurrences.", times); > else fl_alert("No occurrences of \'%s\' found!", find); >} >
>void replcan_cb() { > replace_dlg->hide(); >} >
>void save_cb(void) { > if (filename[0] == '\0') { > // No filename - get one! > saveas_cb(); > return; > } > else save_file(filename); >} >The >save_file()> function >saves >the >current > file >to >the > specified >filename. >
>void saveas_cb(void) { > char *newfile; > > newfile = fl_file_chooser("Save File As?", "*", filename); > if (newfile != NULL) save_file(newfile); >} >The >save_file()> function >saves >the >current > file >to >the > specified >filename. >
>void undo_cb(void) { > input->undo(); >} >
>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(); > > return !changed; > } > else return (1); >} >
>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!"); > } >} >When >loading >the >file >we >use >the > input->replace()> method >to >"replace" >the > text >at >the >end > of >the >buffer. > The >pos> variable >keeps >track >of >the >end >of >the > buffer. >
>void save_file(char *newfile) { > FILE *fp; > > fp = fopen(newfile, "w"); > if (fp != NULL) { > // Was able to create file; let's write to it... > 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!"); > } >} >
>void set_changed(int c) { > if (c != changed) { > char title[1024]; > char *slash; > > changed = c; > > if (filename[0] == '\0') strcpy(title, "Untitled"); > else { > slash = strrchr(filename, '/'); > if (slash == NULL) slash = strrchr(filename, '\\'); > > if (slash != NULL) strcpy(title, slash + 1); > else strcpy(title, filename); > } > > if (changed) strcat(title, " (modified)"); > > window->label(title); > } >} >
>CC -o editor editor.cxx -lfltk -lXext -lX11 -lm >As >noted >in >Chapter >1>, > you >may >need >to > include >compiler >and >linker > options >to >tell >them >where >to >find >the >FLTK > library. >Also, >the >CC> command >may >also > be >called >gcc> or >c++> on >your > system. >
Congratulations, >you've >just >built >your >own >text > editor! >