// // "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $" // // FLUID main entry for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2010 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems on the following page: // // http://www.fltk.org/str.php // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // time(), localtime(), etc. #include "../src/flstring.h" #include "alignment_panel.h" #include "function_panel.h" #include "template_panel.h" #if !defined(WIN32) || defined(__CYGWIN__) # include "print_panel.cxx" #endif // !WIN32 || __CYGWIN__ #if defined(WIN32) && !defined(__CYGWIN__) # include # include # include # include # include # include # ifndef __WATCOMC__ // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs // on Windows, which is supposed to be POSIX compliant... # define access _access # define chdir _chdir # define getcwd _getcwd # endif // !__WATCOMC__ #else # include #endif #ifdef __EMX__ # include #endif #include "about_panel.h" #include "undo.h" #include "Fl_Type.h" extern "C" { #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) # include # ifdef HAVE_PNG_H # include # else # include # endif // HAVE_PNG_H #endif // HAVE_LIBPNG && HAVE_LIBZ } static Fl_Help_Dialog *help_dialog = 0; Fl_Preferences fluid_prefs(Fl_Preferences::USER, "fltk.org", "fluid"); int gridx = 5; int gridy = 5; int snap = 1; int show_guides = 1; int show_comments = 1; int show_coredevmenus = 1; // File history info... char absolute_history[10][FL_PATH_MAX]; char relative_history[10][FL_PATH_MAX]; void load_history(); void update_history(const char *); // Shell command support... void show_shell_window(); Fl_Menu_Item *save_item = 0L; Fl_Menu_Item *history_item = 0L; Fl_Menu_Item *widgetbin_item = 0L; Fl_Menu_Item *sourceview_item = 0L; //////////////////////////////////////////////////////////////// static const char *filename; void set_filename(const char *c); void set_modflag(int mf); int modflag; static char* pwd; static char in_source_dir; void goto_source_dir() { if (in_source_dir) return; if (!filename || !*filename) return; const char *p = fl_filename_name(filename); if (p <= filename) return; // it is in the current directory char buffer[FL_PATH_MAX]; strlcpy(buffer, filename, sizeof(buffer)); int n = p-filename; if (n>1) n--; buffer[n] = 0; if (!pwd) { pwd = getcwd(0,FL_PATH_MAX); if (!pwd) {fprintf(stderr,"getwd : %s\n",strerror(errno)); return;} } if (chdir(buffer)<0) {fprintf(stderr, "Can't chdir to %s : %s\n", buffer, strerror(errno)); return;} in_source_dir = 1; } void leave_source_dir() { if (!in_source_dir) return; if (chdir(pwd)<0) {fprintf(stderr, "Can't chdir to %s : %s\n", pwd, strerror(errno));} in_source_dir = 0; } char position_window(Fl_Window *w, const char *prefsName, int Visible, int X, int Y, int W=0, int H=0 ) { Fl_Preferences pos(fluid_prefs, prefsName); if (prevpos_button->value()) { pos.get("x", X, X); pos.get("y", Y, Y); if ( W!=0 ) { pos.get("w", W, W); pos.get("h", H, H); w->resize( X, Y, W, H ); } else w->position( X, Y ); } pos.get("visible", Visible, Visible); return Visible; } void save_position(Fl_Window *w, const char *prefsName) { Fl_Preferences pos(fluid_prefs, prefsName); pos.set("x", w->x()); pos.set("y", w->y()); pos.set("w", w->w()); pos.set("h", w->h()); pos.set("visible", (int)(w->shown() && w->visible())); } Fl_Window *main_window; Fl_Menu_Bar *main_menubar; static char* cutfname(int which = 0) { static char name[2][FL_PATH_MAX]; static char beenhere = 0; if (!beenhere) { beenhere = 1; fluid_prefs.getUserdataPath(name[0], sizeof(name[0])); strlcat(name[0], "cut_buffer", sizeof(name[0])); fluid_prefs.getUserdataPath(name[1], sizeof(name[1])); strlcat(name[1], "dup_buffer", sizeof(name[1])); } return name[which]; } void save_cb(Fl_Widget *, void *v) { const char *c = filename; if (v || !c || !*c) { fl_file_chooser_ok_label("Save"); c=fl_file_chooser("Save To:", "FLUID Files (*.f[ld])", c); fl_file_chooser_ok_label(NULL); if (!c) return; if (!access(c, 0)) { const char *basename; if ((basename = strrchr(c, '/')) != NULL) basename ++; #if defined(WIN32) || defined(__EMX__) if ((basename = strrchr(c, '\\')) != NULL) basename ++; #endif // WIN32 || __EMX__ else basename = c; if (fl_choice("The file \"%s\" already exists.\n" "Do you want to replace it?", "Cancel", "Replace", NULL, basename) == 0) return; } if (v != (void *)2) set_filename(c); } if (!write_file(c)) { fl_alert("Error writing %s: %s", c, strerror(errno)); return; } if (v != (void *)2) { set_modflag(0); undo_save = undo_current; } } void save_template_cb(Fl_Widget *, void *) { // Setup the template panel... if (!template_panel) make_template_panel(); template_clear(); template_browser->add("New Template"); template_load(); template_name->show(); template_name->value(""); template_instance->hide(); template_delete->show(); template_delete->deactivate(); template_submit->label("Save"); template_submit->deactivate(); template_panel->label("Save Template"); // Show the panel and wait for the user to do something... template_panel->show(); while (template_panel->shown()) Fl::wait(); // Get the template name, return if it is empty... const char *c = template_name->value(); if (!c || !*c) return; // Convert template name to filename_with_underscores char safename[FL_PATH_MAX], *safeptr; strlcpy(safename, c, sizeof(safename)); for (safeptr = safename; *safeptr; safeptr ++) { if (isspace(*safeptr)) *safeptr = '_'; } // Find the templates directory... char filename[FL_PATH_MAX]; fluid_prefs.getUserdataPath(filename, sizeof(filename)); strlcat(filename, "templates", sizeof(filename)); #if defined(WIN32) && !defined(__CYGWIN__) if (access(filename, 0)) mkdir(filename); #else if (access(filename, 0)) mkdir(filename, 0777); #endif // WIN32 && !__CYGWIN__ strlcat(filename, "/", sizeof(filename)); strlcat(filename, safename, sizeof(filename)); char *ext = filename + strlen(filename); if (ext >= (filename + sizeof(filename) - 5)) { fl_alert("The template name \"%s\" is too long!", c); return; } // Save the .fl file... strcpy(ext, ".fl"); if (!access(filename, 0)) { if (fl_choice("The template \"%s\" already exists.\n" "Do you want to replace it?", "Cancel", "Replace", NULL, c) == 0) return; } if (!write_file(filename)) { fl_alert("Error writing %s: %s", filename, strerror(errno)); return; } #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) // Get the screenshot, if any... Fl_Type *t; for (t = Fl_Type::first; t; t = t->next) { // Find the first window... if (t->is_window()) break; } if (!t) return; // Grab a screenshot... Fl_Window_Type *wt = (Fl_Window_Type *)t; uchar *pixels; int w, h; if ((pixels = wt->read_image(w, h)) == NULL) return; // Save to a PNG file... strcpy(ext, ".png"); FILE *fp; if ((fp = fl_fopen(filename, "wb")) == NULL) { delete[] pixels; fl_alert("Error writing %s: %s", filename, strerror(errno)); return; } png_structp pptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_infop iptr = png_create_info_struct(pptr); png_bytep ptr = (png_bytep)pixels; png_init_io(pptr, fp); png_set_IHDR(pptr, iptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_sRGB(pptr, iptr, PNG_sRGB_INTENT_PERCEPTUAL); png_write_info(pptr, iptr); for (int i = h; i > 0; i --, ptr += w * 3) { png_write_row(pptr, ptr); } png_write_end(pptr, iptr); png_destroy_write_struct(&pptr, &iptr); fclose(fp); # if 0 // The original PPM output code... strcpy(ext, ".ppm"); fp = fl_fopen(filename, "wb"); fprintf(fp, "P6\n%d %d 255\n", w, h); fwrite(pixels, w * h, 3, fp); fclose(fp); # endif // 0 delete[] pixels; #endif // HAVE_LIBPNG && HAVE_LIBZ } void revert_cb(Fl_Widget *,void *) { if (modflag) { if (!fl_choice("This user interface has been changed. Really revert?", "Cancel", "Revert", NULL)) return; } undo_suspend(); if (!read_file(filename, 0)) { undo_resume(); fl_message("Can't read %s: %s", filename, strerror(errno)); return; } undo_resume(); set_modflag(0); undo_clear(); } void exit_cb(Fl_Widget *,void *) { if (modflag) switch (fl_choice("Do you want to save changes to this user\n" "interface before exiting?", "Cancel", "Save", "Don't Save")) { case 0 : /* Cancel */ return; case 1 : /* Save */ save_cb(NULL, NULL); if (modflag) return; // Didn't save! } save_position(main_window,"main_window_pos"); if (widgetbin_panel) { save_position(widgetbin_panel,"widgetbin_pos"); delete widgetbin_panel; } if (sourceview_panel) { Fl_Preferences svp(fluid_prefs, "sourceview"); svp.set("autorefresh", sv_autorefresh->value()); svp.set("autoposition", sv_autoposition->value()); svp.set("tab", sv_tab->find(sv_tab->value())); save_position(sourceview_panel,"sourceview_pos"); delete sourceview_panel; } if (about_panel) delete about_panel; if (help_dialog) delete help_dialog; undo_clear(); exit(0); } #ifdef __APPLE__ # include void apple_open_cb(const char *c) { if (modflag) { switch (fl_choice("Do you want to save changes to this user\n" "interface before opening another one?", "Don't Save", "Save", "Cancel")) { case 0 : /* Cancel */ return; case 1 : /* Save */ save_cb(NULL, NULL); if (modflag) return; // Didn't save! } } const char *oldfilename; oldfilename = filename; filename = NULL; set_filename(c); undo_suspend(); if (!read_file(c, 0)) { undo_resume(); fl_message("Can't read %s: %s", c, strerror(errno)); free((void *)filename); filename = oldfilename; if (main_window) main_window->label(filename); return; } // Loaded a file; free the old filename... set_modflag(0); undo_resume(); undo_clear(); if (oldfilename) free((void *)oldfilename); } #endif // __APPLE__ void open_cb(Fl_Widget *, void *v) { if (!v && modflag) { switch (fl_choice("Do you want to save changes to this user\n" "interface before opening another one?", "Cancel", "Save", "Don't Save")) { case 0 : /* Cancel */ return; case 1 : /* Save */ save_cb(NULL, NULL); if (modflag) return; // Didn't save! } } const char *c; const char *oldfilename; fl_file_chooser_ok_label("Open"); c = fl_file_chooser("Open:", "FLUID Files (*.f[ld])", filename); fl_file_chooser_ok_label(NULL); if (!c) return; oldfilename = filename; filename = NULL; set_filename(c); if (v != 0) undo_checkpoint(); undo_suspend(); if (!read_file(c, v!=0)) { undo_resume(); fl_message("Can't read %s: %s", c, strerror(errno)); free((void *)filename); filename = oldfilename; if (main_window) set_modflag(modflag); return; } undo_resume(); if (v) { // Inserting a file; restore the original filename... free((void *)filename); filename = oldfilename; set_modflag(1); } else { // Loaded a file; free the old filename... set_modflag(0); undo_clear(); if (oldfilename) free((void *)oldfilename); } } void open_history_cb(Fl_Widget *, void *v) { if (modflag) { switch (fl_choice("Do you want to save changes to this user\n" "interface before opening another one?", "Cancel", "Save", "Don't Save")) { case 0 : /* Cancel */ return; case 1 : /* Save */ save_cb(NULL, NULL); if (modflag) return; // Didn't save! } } const char *oldfilename = filename; filename = NULL; set_filename((char *)v); undo_suspend(); if (!read_file(filename, 0)) { undo_resume(); undo_clear(); fl_message("Can't read %s: %s", filename, strerror(errno)); free((void *)filename); filename = oldfilename; if (main_window) main_window->label(filename); return; } set_modflag(0); undo_resume(); undo_clear(); if (oldfilename) free((void *)oldfilename); } void new_cb(Fl_Widget *, void *v) { // Check if the current file has been modified... if (!v && modflag) { // Yes, ask the user what to do... switch (fl_choice("Do you want to save changes to this user\n" "interface before creating a new one?", "Cancel", "Save", "Don't Save")) { case 0 : /* Cancel */ return; case 1 : /* Save */ save_cb(NULL, NULL); if (modflag) return; // Didn't save! } } // Setup the template panel... if (!template_panel) make_template_panel(); template_clear(); template_browser->add("Blank"); template_load(); template_name->hide(); template_name->value(""); template_instance->show(); template_instance->deactivate(); template_instance->value(""); template_delete->hide(); template_submit->label("New"); template_submit->deactivate(); template_panel->label("New"); // Show the panel and wait for the user to do something... template_panel->show(); while (template_panel->shown()) Fl::wait(); // See if the user chose anything... int item = template_browser->value(); if (item < 1) return; // Clear the current data... delete_all(); set_filename(NULL); // Load the template, if any... const char *tname = (const char *)template_browser->data(item); if (tname) { // Grab the instance name... const char *iname = template_instance->value(); if (iname && *iname) { // Copy the template to a temp file, then read it in... char line[1024], *ptr, *next; FILE *infile, *outfile; if ((infile = fl_fopen(tname, "r")) == NULL) { fl_alert("Error reading template file \"%s\":\n%s", tname, strerror(errno)); set_modflag(0); undo_clear(); return; } if ((outfile = fl_fopen(cutfname(1), "w")) == NULL) { fl_alert("Error writing buffer file \"%s\":\n%s", cutfname(1), strerror(errno)); fclose(infile); set_modflag(0); undo_clear(); return; } while (fgets(line, sizeof(line), infile)) { // Replace @INSTANCE@ with the instance name... for (ptr = line; (next = strstr(ptr, "@INSTANCE@")) != NULL; ptr = next + 10) { fwrite(ptr, next - ptr, 1, outfile); fputs(iname, outfile); } fputs(ptr, outfile); } fclose(infile); fclose(outfile); undo_suspend(); read_file(cutfname(1), 0); unlink(cutfname(1)); undo_resume(); } else { // No instance name, so read the template without replacements... undo_suspend(); read_file(tname, 0); undo_resume(); } } set_modflag(0); undo_clear(); } int exit_early = 0; int compile_only = 0; int compile_strings = 0; int header_file_set = 0; int code_file_set = 0; const char* header_file_name = ".h"; const char* code_file_name = ".cxx"; int i18n_type = 0; const char* i18n_include = ""; const char* i18n_function = ""; const char* i18n_file = ""; const char* i18n_set = ""; char i18n_program[FL_PATH_MAX] = ""; void write_cb(Fl_Widget *, void *) { if (!filename) { save_cb(0,0); if (!filename) return; } char cname[FL_PATH_MAX]; char hname[FL_PATH_MAX]; strlcpy(i18n_program, fl_filename_name(filename), sizeof(i18n_program)); fl_filename_setext(i18n_program, sizeof(i18n_program), ""); if (*code_file_name == '.' && strchr(code_file_name, '/') == NULL) { strlcpy(cname, fl_filename_name(filename), sizeof(cname)); fl_filename_setext(cname, sizeof(cname), code_file_name); } else { strlcpy(cname, code_file_name, sizeof(hname)); } if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) { strlcpy(hname, fl_filename_name(filename), sizeof(hname)); fl_filename_setext(hname, sizeof(hname), header_file_name); } else { strlcpy(hname, header_file_name, sizeof(hname)); } if (!compile_only) goto_source_dir(); int x = write_code(cname,hname); if (!compile_only) leave_source_dir(); strlcat(cname, " and ", sizeof(cname)); strlcat(cname, hname, sizeof(cname)); if (compile_only) { if (!x) {fprintf(stderr,"%s : %s\n",cname,strerror(errno)); exit(1);} } else { if (!x) { fl_message("Can't write %s: %s", cname, strerror(errno)); } else if (completion_button->value()) { fl_message("Wrote %s", cname); } } } void write_strings_cb(Fl_Widget *, void *) { static const char *exts[] = { ".txt", ".po", ".msg" }; if (!filename) { save_cb(0,0); if (!filename) return; } char sname[FL_PATH_MAX]; strlcpy(sname, fl_filename_name(filename), sizeof(sname)); fl_filename_setext(sname, sizeof(sname), exts[i18n_type]); if (!compile_only) goto_source_dir(); int x = write_strings(sname); if (!compile_only) leave_source_dir(); if (compile_only) { if (x) {fprintf(stderr,"%s : %s\n",sname,strerror(errno)); exit(1);} } else { if (x) { fl_message("Can't write %s: %s", sname, strerror(errno)); } else if (completion_button->value()) { fl_message("Wrote %s", sname); } } } void openwidget_cb(Fl_Widget *, void *) { if (!Fl_Type::current) { fl_message("Please select a widget"); return; } Fl_Type::current->open(); } void toggle_overlays(Fl_Widget *,void *); void select_all_cb(Fl_Widget *,void *); void select_none_cb(Fl_Widget *,void *); void group_cb(Fl_Widget *, void *); void ungroup_cb(Fl_Widget *, void *); extern int pasteoffset; static int ipasteoffset; void copy_cb(Fl_Widget*, void*) { if (!Fl_Type::current) { fl_beep(); return; } ipasteoffset = 10; if (!write_file(cutfname(),1)) { fl_message("Can't write %s: %s", cutfname(), strerror(errno)); return; } } extern void select_only(Fl_Type *); void cut_cb(Fl_Widget *, void *) { if (!Fl_Type::current) { fl_beep(); return; } if (!write_file(cutfname(),1)) { fl_message("Can't write %s: %s", cutfname(), strerror(errno)); return; } undo_checkpoint(); set_modflag(1); ipasteoffset = 0; Fl_Type *p = Fl_Type::current->parent; while (p && p->selected) p = p->parent; delete_all(1); if (p) select_only(p); } void delete_cb(Fl_Widget *, void *) { if (!Fl_Type::current) { fl_beep(); return; } undo_checkpoint(); set_modflag(1); ipasteoffset = 0; Fl_Type *p = Fl_Type::current->parent; while (p && p->selected) p = p->parent; delete_all(1); if (p) select_only(p); } extern int force_parent; void paste_cb(Fl_Widget*, void*) { //if (ipasteoffset) force_parent = 1; pasteoffset = ipasteoffset; if (gridx>1) pasteoffset = ((pasteoffset-1)/gridx+1)*gridx; if (gridy>1) pasteoffset = ((pasteoffset-1)/gridy+1)*gridy; undo_checkpoint(); undo_suspend(); if (!read_file(cutfname(), 1)) { fl_message("Can't read %s: %s", cutfname(), strerror(errno)); } undo_resume(); pasteoffset = 0; ipasteoffset += 10; force_parent = 0; } // Duplicate the selected widgets... void duplicate_cb(Fl_Widget*, void*) { if (!Fl_Type::current) { fl_beep(); return; } if (!write_file(cutfname(1),1)) { fl_message("Can't write %s: %s", cutfname(1), strerror(errno)); return; } pasteoffset = 0; force_parent = 1; undo_checkpoint(); undo_suspend(); if (!read_file(cutfname(1), 1)) { fl_message("Can't read %s: %s", cutfname(1), strerror(errno)); } unlink(cutfname(1)); undo_resume(); force_parent = 0; } void earlier_cb(Fl_Widget*,void*); void later_cb(Fl_Widget*,void*); Fl_Type *sort(Fl_Type *parent); static void sort_cb(Fl_Widget *,void *) { sort((Fl_Type*)0); } void show_project_cb(Fl_Widget *, void *); void show_grid_cb(Fl_Widget *, void *); void show_settings_cb(Fl_Widget *, void *); void show_global_settings_cb(Fl_Widget *, void *); void align_widget_cb(Fl_Widget *, long); void widget_size_cb(Fl_Widget *, long); void about_cb(Fl_Widget *, void *) { if (!about_panel) make_about_panel(); about_panel->show(); } void show_help(const char *name) { const char *docdir; char helpname[FL_PATH_MAX]; if (!help_dialog) help_dialog = new Fl_Help_Dialog(); if ((docdir = getenv("FLTK_DOCDIR")) == NULL) { #ifdef __EMX__ // Doesn't make sense to have a hardcoded fallback static char fltk_docdir[FL_PATH_MAX]; strlcpy(fltk_docdir, __XOS2RedirRoot("/XFree86/lib/X11/fltk/doc"), sizeof(fltk_docdir)); docdir = fltk_docdir; #else docdir = FLTK_DOCDIR; #endif // __EMX__ } snprintf(helpname, sizeof(helpname), "%s/%s", docdir, name); // make sure that we can read the file FILE *f = fopen(helpname, "rb"); if (f) { fclose(f); help_dialog->load(helpname); } else { // if we can not read the file, we display the canned version instead // or ask the native browser to open the page on www.fltk.org if (strcmp(name, "fluid.html")==0) { if (!Fl_Shared_Image::find("embedded:/fluid-org.png")) new Fl_PNG_Image("embedded:/fluid-org.png", fluid_org_png, sizeof(fluid_org_png)); help_dialog->value ( "\n" "FLTK: Programming with FLUID\n" "

What is FLUID?

\n" "The Fast Light User Interface Designer, or FLUID, is a graphical editor " "that is used to produce FLTK source code. FLUID edits and saves its state " "in .fl files. These files are text, and you can (with care) " "edit them in a text editor, perhaps to get some special effects.

\n" "FLUID can \"compile\" the .fl file into a .cxx " "and a .h file. The .cxx file defines all the " "objects from the .fl file and the .h file " "declares all the global ones. FLUID also supports localization " "(Internationalization) of label strings using message files and the GNU " "gettext or POSIX catgets interfaces.

\n" "A simple program can be made by putting all your code (including a " "main() function) into the .fl file and thus making the " ".cxx file a single source file to compile. Most programs are " "more complex than this, so you write other .cxx files that " "call the FLUID functions. These .cxx files must " "#include the .h file or they can #include " "the .cxx file so it still appears to be a single source file.

" "

" "

More information is available online at http://www.fltk.org/" "" ); } else if (strcmp(name, "license.html")==0) { fl_open_uri("http://www.fltk.org/doc-1.3/license.html"); return; } else if (strcmp(name, "index.html")==0) { fl_open_uri("http://www.fltk.org/doc-1.3/index.html"); return; } else { snprintf(helpname, sizeof(helpname), "http://www.fltk.org/%s", name); fl_open_uri(helpname); return; } } help_dialog->show(); } void help_cb(Fl_Widget *, void *) { show_help("fluid.html"); } void manual_cb(Fl_Widget *, void *) { show_help("index.html"); } //////////////////////////////////////////////////////////////// #if defined(WIN32) && !defined(__CYGWIN__) // Draw a shaded box... static void win_box(int x, int y, int w, int h) { fl_color(0xc0, 0xc0, 0xc0); fl_rectf(x, y, w, h); fl_color(0, 0, 0); fl_rect(x, y, w, h); fl_color(0xf0, 0xf0, 0xf0); fl_rectf(x + 1, y + 1, 4, h - 2); fl_rectf(x + 1, y + 1, w - 2, 4); fl_color(0x90, 0x90, 0x90); fl_rectf(x + w - 5, y + 1, 4, h - 2); fl_rectf(x + 1, y + h - 5, w - 2, 4); } // Load and show the print dialog... void print_menu_cb(Fl_Widget *, void *) { PRINTDLG dialog; // Print dialog DOCINFO docinfo; // Document info int first, last; // First and last page int page; // Current page int winpage; // Current window page int num_pages; // Number of pages Fl_Type *t; // Current widget int num_windows; // Number of windows Fl_Window_Type *windows[1000]; // Windows to print // Show print dialog... for (t = Fl_Type::first, num_pages = 0; t; t = t->next) { if (t->is_window()) num_pages ++; } memset(&dialog, 0, sizeof(dialog)); dialog.lStructSize = sizeof(dialog); dialog.hwndOwner = fl_xid(main_window); dialog.Flags = PD_ALLPAGES | PD_RETURNDC; dialog.nFromPage = 1; dialog.nToPage = num_pages; dialog.nMinPage = 1; dialog.nMaxPage = num_pages; dialog.nCopies = 1; if (!PrintDlg(&dialog)) return; // Get the base filename... const char *basename = strrchr(filename, '/'); if (basename) basename ++; else basename = filename; // Do the print job... memset(&docinfo, 0, sizeof(docinfo)); docinfo.cbSize = sizeof(docinfo); docinfo.lpszDocName = basename; StartDoc(dialog.hDC, &docinfo); // Figure out how many pages we'll have to print... if (dialog.Flags & PD_PAGENUMS) { // Get from and to page numbers... first = dialog.nFromPage; last = dialog.nToPage; if (first > last) { // Swap first/last page page = first; first = last; last = page; } } else { // Print everything... first = 1; last = dialog.nMaxPage; } for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) { if (t->is_window()) { winpage ++; windows[num_windows] = (Fl_Window_Type *)t; num_windows ++; #if 0 if (dialog.Flags & PD_ALLPAGES) num_windows ++; else if ((dialog.Flags & PD_PAGENUMS) && winpage >= first && winpage <= last) num_windows ++; else if ((dialog.Flags & PD_SELECTION) && t->selected) num_windows ++; #endif // 0 } } num_pages = num_windows; // Figure out the page size and margins... int width, length; // Size of page int xdpi, ydpi; // Output resolution char buffer[1024]; width = GetDeviceCaps(dialog.hDC, HORZRES); length = GetDeviceCaps(dialog.hDC, VERTRES); xdpi = GetDeviceCaps(dialog.hDC, LOGPIXELSX); ydpi = GetDeviceCaps(dialog.hDC, LOGPIXELSY); // fl_message("width=%d, length=%d, xdpi=%d, ydpi=%d, num_windows=%d\n", // width, length, xdpi, ydpi, num_windows); HDC save_dc = fl_gc; HWND save_win = fl_window; int fontsize = 14 * ydpi / 72; fl_gc = dialog.hDC; fl_window = (HWND)dialog.hDC; fl_push_no_clip(); // Get the time and date... time_t curtime = time(NULL); struct tm *curdate = localtime(&curtime); char date[1024]; strftime(date, sizeof(date), "%c", curdate); // Print each of the windows... for (winpage = 0; winpage < num_windows; winpage ++) { // Draw header... StartPage(dialog.hDC); fl_font(FL_HELVETICA_BOLD, fontsize); fl_color(0, 0, 0); fl_draw(basename, 0, fontsize); fl_draw(date, (width - (int)fl_width(date)) / 2, fontsize); sprintf(buffer, "%d/%d", winpage + 1, num_windows); fl_draw(buffer, width - (int)fl_width(buffer), fontsize); // Get window image... uchar *pixels; // Window image data int w, h; // Window image dimensions int ww, hh; // Scaled size int ulx, uly; // Upper-lefthand corner Fl_Window *win; // Window widget BITMAPINFO info; // Bitmap information win = (Fl_Window *)(windows[winpage]->o); pixels = windows[winpage]->read_image(w, h); // Swap colors: FLTK uses R-G-B --> Windows GDI uses B-G-R { uchar *p = pixels; for (int i=0; i width) { ww = width; hh = h * ww * ydpi / xdpi / w; } if (hh > (length - ydpi / 2)) { hh = length - ydpi / 2; ww = w * hh / h; } // Position the window in the center... ulx = (width - ww) / 2; uly = (length - hh) / 2; // fl_message("winpage=%d, ulx=%d, uly=%d, ww=%d, hh=%d", // winpage, ulx, uly, ww, hh); // Draw a simulated window border... int xborder = 4 * ww / w; int yborder = 4 * hh / h; win_box(ulx - xborder, uly - 5 * yborder, ww + 2 * xborder, hh + 6 * yborder); fl_color(0, 0, 255); fl_rectf(ulx, uly - 4 * yborder, ww, 4 * yborder); fl_font(FL_HELVETICA_BOLD, 2 * yborder); fl_color(255, 255, 255); fl_draw(win->label() ? win->label() : "Window", ulx + xborder, uly - 3 * yborder); int x = ulx + ww - 4 * xborder; win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder); fl_color(0, 0, 0); fl_line(x + xborder, uly - yborder, x + 3 * xborder, uly - 3 * yborder); fl_line(x + xborder, uly - 3 * yborder, x + 3 * xborder, uly - yborder); x -= 4 * xborder; if (win->resizable()) { win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder); fl_color(0, 0, 0); fl_rect(x + xborder, uly - 3 * yborder, 2 * xborder, 2 * yborder); x -= 4 * xborder; } if (!win->modal()) { win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder); fl_color(0, 0, 0); fl_line(x + xborder, uly - yborder, x + 3 * xborder, uly - yborder); x -= 4 * xborder; } // Color image... memset(&info, 0, sizeof(info)); info.bmiHeader.biSize = sizeof(info); info.bmiHeader.biWidth = w; info.bmiHeader.biHeight = 1; info.bmiHeader.biPlanes = 1; info.bmiHeader.biBitCount = 24; info.bmiHeader.biCompression = BI_RGB; for (int y = 0; y < h; y ++) { StretchDIBits(dialog.hDC, ulx, uly + y * hh / h, ww, (hh + h - 1) / h, 0, 0, w, 1, pixels + y * w * 3, &info, DIB_RGB_COLORS, SRCCOPY); } delete[] pixels; // Show the page... EndPage(dialog.hDC); } // Finish up... EndDoc(dialog.hDC); fl_gc = save_dc; fl_window = save_win; fl_pop_clip(); // Free the print DC and return... DeleteDC(dialog.hDC); } #else // Load and show the print dialog... void print_menu_cb(Fl_Widget *, void *) { if (!print_panel) make_print_panel(); print_load(); print_selection->deactivate(); for (Fl_Type *t = Fl_Type::first; t; t = t->next) { if (t->selected && t->is_window()) { print_selection->activate(); break; } } print_all->setonly(); print_all->do_callback(); print_panel->show(); } // Quote a string for PostScript printing static const char *ps_string(const char *s) { char *bufptr; static char buffer[FL_PATH_MAX]; if (!s) { buffer[0] = '\0'; } else { for (bufptr = buffer; bufptr < (buffer + sizeof(buffer) - 3) && *s;) { if (*s == '(' || *s == ')' || *s == '\\') *bufptr++ = '\\'; *bufptr++ = *s++; } *bufptr = '\0'; } return (buffer); } // Actually print... void print_cb(Fl_Return_Button *, void *) { FILE *outfile; // Output file or pipe to print command char command[1024]; // Print command int copies; // Collated copies int first, last; // First and last page int page; // Current page int winpage; // Current window page int num_pages; // Number of pages Fl_Type *t; // Current widget int num_windows; // Number of windows Fl_Window_Type *windows[1000]; // Windows to print // Show progress, deactivate controls... print_panel_controls->deactivate(); print_progress->show(); // Figure out how many pages we'll have to print... if (print_collate_button->value()) copies = (int)print_copies->value(); else copies = 1; if (print_pages->value()) { // Get from and to page numbers... if ((first = atoi(print_from->value())) < 1) first = 1; if ((last = atoi(print_to->value())) < 1) last = 1000; if (first > last) { // Swap first/last page page = first; first = last; last = page; } } else { // Print everything... first = 1; last = 1000; } for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) { if (t->is_window()) { winpage ++; windows[num_windows] = (Fl_Window_Type *)t; if (!((Fl_Window*)(windows[num_windows]->o))->shown()) continue; if (print_all->value()) num_windows ++; else if (print_pages->value() && winpage >= first && winpage <= last) num_windows ++; else if (print_selection->value() && t->selected) num_windows ++; } } num_pages = num_windows * copies; print_progress->minimum(0); print_progress->maximum(num_pages); print_progress->value(0); Fl::check(); // Get the base filename... const char *basename = strrchr(filename, '/'); if (basename) basename ++; else basename = filename; // Open the print stream... if (print_choice->value()) { // Pipe the output into the lp command... const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data(); snprintf(command, sizeof(command), "lp -s -d %s -n %.0f -t '%s' -o media=%s", printer, print_collate_button->value() ? 1.0 : print_copies->value(), basename, print_page_size->text(print_page_size->value())); outfile = popen(command, "w"); } else { // Print to file... fl_file_chooser_ok_label("Print"); const char *outname = fl_file_chooser("Print To", "PostScript (*.ps)", NULL, 1); fl_file_chooser_ok_label(NULL); if (outname && !access(outname, 0)) { if (fl_choice("The file \"%s\" already exists.\n" "Do you want to replace it?", "Cancel", "Replace", NULL, outname) == 0) outname = NULL; } if (outname) outfile = fl_fopen(outname, "w"); else outfile = NULL; } if (outfile) { // Figure out the page size and margins... int width, length; // Size of page int left, bottom, // Bottom lefthand corner right, top; // Top righthand corner if (print_page_size->value()) { // A4 width = 595; length = 842; } else { // Letter width = 612; length = 792; } int output_mode; for (output_mode = 0; output_mode < 4; output_mode ++) { if (print_output_mode[output_mode]->value()) break; } if (output_mode & 1) { // Landscape left = 36; bottom = 18; right = length - 36; top = width - 18; } else { // Portrait left = 18; bottom = 36; right = width - 18; top = length - 36; } // Get the time and date... time_t curtime = time(NULL); struct tm *curdate = localtime(&curtime); char date[1024]; strftime(date, sizeof(date), "%c", curdate); // Write the prolog... fprintf(outfile, "%%!PS-Adobe-3.0\n" "%%%%BoundingBox: 18 36 %d %d\n" "%%%%Pages: %d\n" "%%%%LanguageLevel: 1\n" "%%%%DocumentData: Clean7Bit\n" "%%%%DocumentNeededResources: font Helvetica-Bold\n" "%%%%Creator: FLUID %.4f\n" "%%%%CreationDate: %s\n" "%%%%Title: (%s)\n" "%%%%EndComments\n" "%%%%BeginProlog\n" "%%languagelevel 1 eq {\n" " /rectfill {\n" " newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n" " neg 0 exch rlineto closepath fill\n" " } bind def\n" " /rectstroke {\n" " newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n" " neg 0 exch rlineto closepath stroke\n" " } bind def\n" "%%} if\n" "%%%%EndProlog\n" "%%%%BeginSetup\n" "%%%%BeginFeature: *PageSize %s\n" "languagelevel 1 ne {\n" " <>setpagedevice\n" "} {\n" " %s\n" "} ifelse\n" "%%%%EndFeature\n" "%%%%EndSetup\n", width - 18, length - 36, num_pages, FL_VERSION, date, basename, print_page_size->text(print_page_size->value()), width, length, print_page_size->value() ? "a4tray" : "lettertray"); // Print each of the windows... char progress[255]; // Progress text int copy; // Current copy for (copy = 0, page = 0; copy < copies; copy ++) { for (winpage = 0; winpage < num_pages; winpage ++) { // Start next page... page ++; sprintf(progress, "Printing page %d/%d...", page, num_pages); print_progress->value(page); print_progress->label(progress); Fl::check(); // Add common page stuff... fprintf(outfile, "%%%%Page: %d %d\n" "gsave\n", page, page); if (output_mode & 1) { // Landscape... fprintf(outfile, "%d 0 translate 90 rotate\n", width); } // Draw header... fprintf(outfile, "0 setgray\n" "/Helvetica-Bold findfont 14 scalefont setfont\n" "%d %d moveto (%s) show\n" "%.1f %d moveto (%s) dup stringwidth pop -0.5 mul 0 rmoveto show\n" "%d %d moveto (%d/%d) dup stringwidth pop neg 0 rmoveto show\n", left, top - 15, ps_string(basename), 0.5 * (left + right), top - 15, date, right, top - 15, winpage + 1, num_windows); // Get window image... uchar *pixels; // Window image data int w, h; // Window image dimensions float ww, hh; // Scaled size float border; // Width of 1 pixel float llx, lly, // Lower-lefthand corner urx, ury; // Upper-righthand corner Fl_Window *win; // Window widget win = (Fl_Window *)(windows[winpage]->o); pixels = windows[winpage]->read_image(w, h); // Figure out the window size, first at 100 PPI and then scaled // down if that is too big... ww = w * 72.0 / 100.0; hh = h * 72.0 / 100.0; if (ww > (right - left)) { ww = right - left; hh = h * ww / w; } if (hh > (top - bottom - 36)) { hh = top - bottom; ww = w * hh / h; } border = ww / w; // Position the window in the center... llx = 0.5 * (right - left - ww); lly = 0.5 * (top - bottom - hh); urx = 0.5 * (right - left + ww); ury = 0.5 * (top - bottom + hh); // Draw a simulated window border... fprintf(outfile, "0.75 setgray\n" // Gray background "newpath %.2f %.2f %.2f 180 90 arcn\n" // Top left "%.2f %.2f %.2f 90 0 arcn\n" // Top right "%.2f %.2f %.2f 0 -90 arcn\n" // Bottom right "%.2f %.2f %.2f -90 -180 arcn\n" // Bottom left "closepath gsave fill grestore\n" // Fill "0 setlinewidth 0 setgray stroke\n", // Outline llx, ury + 12 * border, 4 * border, urx, ury + 12 * border, 4 * border, urx, lly, 4 * border, llx, lly, 4 * border); // Title bar... if (output_mode & 2) { fputs("0.25 setgray\n", outfile); } else { fputs("0.1 0.2 0.6 setrgbcolor\n", outfile); } fprintf(outfile, "%.2f %.2f %.2f %.2f rectfill\n", llx + 12 * border, ury, ww - (24 + 16 * (!win->modal() || win->resizable()) + 16 * (!win->modal() && win->resizable())) * border, 16 * border); if (win->resizable()) { fprintf(outfile, "%.2f %.2f %.2f -90 -180 arcn\n" // Bottom left "0 %.2f rlineto %.2f 0 rlineto 0 -%.2f rlineto closepath fill\n" "%.2f %.2f %.2f 0 -90 arcn\n" // Bottom right "-%.2f 0 rlineto 0 %.2f rlineto %.2f 0 rlineto closepath fill\n", llx, lly, 4 * border, 12 * border, 16 * border, 16 * border, urx, lly, 4 * border, 12 * border, 16 * border, 16 * border); } // Inside outline and button shading... fprintf(outfile, "%.2f setlinewidth 0.5 setgray\n" "%.2f %.2f %.2f %.2f rectstroke\n" "%.2f %.2f moveto 0 %.2f rlineto\n" "%.2f %.2f moveto 0 %.2f rlineto\n", border, llx - 0.5 * border, lly - 0.5 * border, ww + border, hh + border, llx + 12 * border, ury, 16 * border, urx - 12 * border, ury, 16 * border); if (!win->modal() || win->resizable()) { fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n", urx - 28 * border, ury, 16 * border); } if (!win->modal() && win->resizable()) { fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n", urx - 44 * border, ury, 16 * border); } fprintf(outfile, "%.2f %.2f moveto %.2f 0 rlineto stroke\n", llx - 3.5 * border, ury + 0.5 * border, ww + 7 * border); // Button icons... fprintf(outfile, "%.2f setlinewidth 0 setgray\n" "%.2f %.2f moveto %.2f -%.2f rlineto %.2f %.2f rlineto\n" "%.2f %.2f moveto -%.2f -%.2f rlineto 0 %.2f rmoveto %.2f -%.2f rlineto\n", 2 * border, llx, ury + 10 * border, 4 * border, 4 * border, 4 * border, 4 * border, urx, ury + 12 * border, 8 * border, 8 * border, 8 * border, 8 * border, 8 * border); float x = urx - 16 * border; if (win->resizable()) { // Maximize button fprintf(outfile, "%.2f %.2f moveto -%.2f 0 rlineto 0 -%.2f rlineto " "%.2f 0 rlineto 0 %.2f rlineto\n", x, ury + 12 * border, 8 * border, 8 * border, 8 * border, 8 * border); x -= 16 * border; } if (!win->modal()) { // Minimize button fprintf(outfile, "%.2f %.2f moveto -%.2f 0 rlineto\n", x, ury + 4 * border, 8 * border); } fputs("stroke\n", outfile); if (win->label()) { // Add window title... fprintf(outfile, "1 setgray\n" "/Helvetica-Bold findfont %.2f scalefont setfont\n" "(%s) %.2f %.2f moveto show\n", 12 * border, ps_string(win->label()), llx + 16 * border, ury + 4 * border); } fprintf(outfile, "gsave\n" "%.2f %.2f translate %.2f %.2f scale\n", llx, ury - border, border, border); if (output_mode & 2) { // Grayscale image... fprintf(outfile, "/imgdata %d string def\n" "%d %d 8[1 0 0 -1 0 1] " "{currentfile imgdata readhexstring pop} image\n", w, w, h); uchar *ptr = pixels; int i, count = w * h; for (i = 0; i < count; i ++, ptr += 3) { fprintf(outfile, "%02X", (31 * ptr[0] + 61 * ptr[1] + 8 * ptr[2]) / 100); if (!(i % 40)) putc('\n', outfile); } } else { // Color image... fprintf(outfile, "/imgdata %d string def\n" "%d %d 8[1 0 0 -1 0 1] " "{currentfile imgdata readhexstring pop} false 3 colorimage\n", w * 3, w, h); uchar *ptr = pixels; int i, count = w * h; for (i = 0; i < count; i ++, ptr += 3) { fprintf(outfile, "%02X%02X%02X", ptr[0], ptr[1], ptr[2]); if (!(i % 13)) putc('\n', outfile); } } fputs("\ngrestore\n", outfile); delete[] pixels; // Show the page... fputs("grestore showpage\n", outfile); } } // Finish up... fputs("%%EOF\n", outfile); if (print_choice->value()) pclose(outfile); else fclose(outfile); } else { // Unable to print... fl_alert("Error printing: %s", strerror(errno)); } // Hide progress, activate controls, hide print panel... print_panel_controls->activate(); print_progress->hide(); print_panel->hide(); } #endif // WIN32 && !__CYGWIN__ //////////////////////////////////////////////////////////////// extern Fl_Menu_Item New_Menu[]; void toggle_widgetbin_cb(Fl_Widget *, void *); void toggle_sourceview_cb(Fl_Double_Window *, void *); Fl_Menu_Item Main_Menu[] = { {"&File",0,0,0,FL_SUBMENU}, {"&New...", FL_COMMAND+'n', new_cb, 0}, {"&Open...", FL_COMMAND+'o', open_cb, 0}, {"&Insert...", FL_COMMAND+'i', open_cb, (void*)1, FL_MENU_DIVIDER}, {"&Save", FL_COMMAND+'s', save_cb, 0}, {"Save &As...", FL_COMMAND+FL_SHIFT+'s', save_cb, (void*)1}, {"Sa&ve A Copy...", 0, save_cb, (void*)2}, {"Save &Template...", 0, save_template_cb}, {"&Revert...", 0, revert_cb, 0, FL_MENU_DIVIDER}, {"&Print...", FL_COMMAND+'p', print_menu_cb}, {"Write &Code...", FL_COMMAND+FL_SHIFT+'c', write_cb, 0}, {"&Write Strings...", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, 0, FL_MENU_DIVIDER}, {relative_history[0], FL_COMMAND+'0', open_history_cb, absolute_history[0]}, {relative_history[1], FL_COMMAND+'1', open_history_cb, absolute_history[1]}, {relative_history[2], FL_COMMAND+'2', open_history_cb, absolute_history[2]}, {relative_history[3], FL_COMMAND+'3', open_history_cb, absolute_history[3]}, {relative_history[4], FL_COMMAND+'4', open_history_cb, absolute_history[4]}, {relative_history[5], FL_COMMAND+'5', open_history_cb, absolute_history[5]}, {relative_history[6], FL_COMMAND+'6', open_history_cb, absolute_history[6]}, {relative_history[7], FL_COMMAND+'7', open_history_cb, absolute_history[7]}, {relative_history[8], FL_COMMAND+'8', open_history_cb, absolute_history[8]}, {relative_history[9], FL_COMMAND+'9', open_history_cb, absolute_history[9], FL_MENU_DIVIDER}, {"&Quit", FL_COMMAND+'q', exit_cb}, {0}, {"&Edit",0,0,0,FL_SUBMENU}, {"&Undo", FL_COMMAND+'z', undo_cb}, {"&Redo", FL_COMMAND+FL_SHIFT+'z', redo_cb, 0, FL_MENU_DIVIDER}, {"C&ut", FL_COMMAND+'x', cut_cb}, {"&Copy", FL_COMMAND+'c', copy_cb}, {"&Paste", FL_COMMAND+'v', paste_cb}, {"Dup&licate", FL_COMMAND+'u', duplicate_cb}, {"&Delete", FL_Delete, delete_cb, 0, FL_MENU_DIVIDER}, {"Select &All", FL_COMMAND+'a', select_all_cb}, {"Select &None", FL_COMMAND+FL_SHIFT+'a', select_none_cb, 0, FL_MENU_DIVIDER}, {"Pr&operties...", FL_F+1, openwidget_cb}, {"&Sort",0,sort_cb}, {"&Earlier", FL_F+2, earlier_cb}, {"&Later", FL_F+3, later_cb}, {"&Group", FL_F+7, group_cb}, {"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER}, {"Hide O&verlays",FL_COMMAND+FL_SHIFT+'o',toggle_overlays}, {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb}, {"Show Source Code...",FL_ALT+FL_SHIFT+'s', (Fl_Callback*)toggle_sourceview_cb, 0, FL_MENU_DIVIDER}, {"Pro&ject Settings...",FL_ALT+'p',show_project_cb}, {"GU&I Settings...",FL_ALT+FL_SHIFT+'p',show_settings_cb,0,FL_MENU_DIVIDER}, {"Global &FLTK Settings...",FL_ALT+FL_SHIFT+'g',show_global_settings_cb}, {0}, {"&New", 0, 0, (void *)New_Menu, FL_SUBMENU_POINTER}, {"&Layout",0,0,0,FL_SUBMENU}, {"&Align",0,0,0,FL_SUBMENU}, {"&Left",0,(Fl_Callback *)align_widget_cb,(void*)10}, {"&Center",0,(Fl_Callback *)align_widget_cb,(void*)11}, {"&Right",0,(Fl_Callback *)align_widget_cb,(void*)12}, {"&Top",0,(Fl_Callback *)align_widget_cb,(void*)13}, {"&Middle",0,(Fl_Callback *)align_widget_cb,(void*)14}, {"&Bottom",0,(Fl_Callback *)align_widget_cb,(void*)15}, {0}, {"&Space Evenly",0,0,0,FL_SUBMENU}, {"&Across",0,(Fl_Callback *)align_widget_cb,(void*)20}, {"&Down",0,(Fl_Callback *)align_widget_cb,(void*)21}, {0}, {"&Make Same Size",0,0,0,FL_SUBMENU}, {"&Width",0,(Fl_Callback *)align_widget_cb,(void*)30}, {"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31}, {"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32}, {0}, {"&Center In Group",0,0,0,FL_SUBMENU}, {"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40}, {"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41}, {0}, {"Set &Widget Size",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER}, {"&Tiny",FL_ALT+'1',(Fl_Callback *)widget_size_cb,(void*)8,0,FL_NORMAL_LABEL,FL_HELVETICA,8}, {"&Small",FL_ALT+'2',(Fl_Callback *)widget_size_cb,(void*)11,0,FL_NORMAL_LABEL,FL_HELVETICA,11}, {"&Normal",FL_ALT+'3',(Fl_Callback *)widget_size_cb,(void*)14,0,FL_NORMAL_LABEL,FL_HELVETICA,14}, {"&Medium",FL_ALT+'4',(Fl_Callback *)widget_size_cb,(void*)18,0,FL_NORMAL_LABEL,FL_HELVETICA,18}, {"&Large",FL_ALT+'5',(Fl_Callback *)widget_size_cb,(void*)24,0,FL_NORMAL_LABEL,FL_HELVETICA,24}, {"&Huge",FL_ALT+'6',(Fl_Callback *)widget_size_cb,(void*)32,0,FL_NORMAL_LABEL,FL_HELVETICA,32}, {0}, {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb}, {0}, {"&Shell",0,0,0,FL_SUBMENU}, {"Execute &Command...",FL_ALT+'x',(Fl_Callback *)show_shell_window}, {"Execute &Again...",FL_ALT+'g',(Fl_Callback *)do_shell_command}, {0}, {"&Help",0,0,0,FL_SUBMENU}, {"&Rapid development with FLUID...",0,help_cb}, {"&FLTK Programmers Manual...",0,manual_cb, 0, FL_MENU_DIVIDER}, {"&About FLUID...",0,about_cb}, {0}, {0}}; #define BROWSERWIDTH 300 #define BROWSERHEIGHT 500 #define WINWIDTH 300 #define MENUHEIGHT 25 #define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT) extern void fill_in_New_Menu(); void scheme_cb(Fl_Choice *, void *) { if (compile_only) return; } void toggle_widgetbin_cb(Fl_Widget *, void *) { if (!widgetbin_panel) { make_widgetbin(); if (!position_window(widgetbin_panel,"widgetbin_pos", 1, 320, 30)) return; } if (widgetbin_panel->visible()) { widgetbin_panel->hide(); widgetbin_item->label("Show Widget &Bin..."); } else { widgetbin_panel->show(); widgetbin_item->label("Hide Widget &Bin"); } } void toggle_sourceview_cb(Fl_Double_Window *, void *) { if (!sourceview_panel) { make_sourceview(); sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb); Fl_Preferences svp(fluid_prefs, "sourceview"); int autorefresh; svp.get("autorefresh", autorefresh, 1); sv_autorefresh->value(autorefresh); int autoposition; svp.get("autoposition", autoposition, 1); sv_autoposition->value(autoposition); int tab; svp.get("tab", tab, 0); if (tab>=0 && tabchildren()) sv_tab->value(sv_tab->child(tab)); if (!position_window(sourceview_panel,"sourceview_pos", 0, 320, 120, 550, 500)) return; } if (sourceview_panel->visible()) { sourceview_panel->hide(); sourceview_item->label("Show Source Code..."); } else { sourceview_panel->show(); sourceview_item->label("Hide Source Code..."); update_sourceview_cb(0,0); } } void toggle_sourceview_b_cb(Fl_Button*, void *) { toggle_sourceview_cb(0,0); } void make_main_window() { if (!compile_only) { fluid_prefs.get("snap", snap, 1); fluid_prefs.get("gridx", gridx, 5); fluid_prefs.get("gridy", gridy, 5); fluid_prefs.get("show_guides", show_guides, 0); fluid_prefs.get("widget_size", Fl_Widget_Type::default_size, 14); fluid_prefs.get("show_comments", show_comments, 1); make_layout_window(); make_shell_window(); } if (!main_window) { Fl_Widget *o; main_window = new Fl_Double_Window(WINWIDTH,WINHEIGHT,"fluid"); main_window->box(FL_NO_BOX); o = make_widget_browser(0,MENUHEIGHT,BROWSERWIDTH,BROWSERHEIGHT); o->box(FL_FLAT_BOX); o->tooltip("Double-click to view or change an item."); main_window->resizable(o); main_menubar = new Fl_Menu_Bar(0,0,BROWSERWIDTH,MENUHEIGHT); main_menubar->menu(Main_Menu); // quick access to all dynamic menu items save_item = (Fl_Menu_Item*)main_menubar->find_item(save_cb); history_item = (Fl_Menu_Item*)main_menubar->find_item(open_history_cb); widgetbin_item = (Fl_Menu_Item*)main_menubar->find_item(toggle_widgetbin_cb); sourceview_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_sourceview_cb); main_menubar->global(); fill_in_New_Menu(); main_window->end(); } if (!compile_only) { load_history(); make_settings_window(); make_global_settings_window(); } } // Load file history from preferences... void load_history() { int i; // Looping var int max_files; fluid_prefs.get("recent_files", max_files, 5); if (max_files > 10) max_files = 10; for (i = 0; i < max_files; i ++) { fluid_prefs.get( Fl_Preferences::Name("file%d", i), absolute_history[i], "", sizeof(absolute_history[i])); if (absolute_history[i][0]) { // Make a relative version of the filename for the menu... fl_filename_relative(relative_history[i], sizeof(relative_history[i]), absolute_history[i]); if (i == 9) history_item[i].flags = FL_MENU_DIVIDER; else history_item[i].flags = 0; } else break; } for (; i < 10; i ++) { if (i) history_item[i-1].flags |= FL_MENU_DIVIDER; history_item[i].hide(); } } // Update file history from preferences... void update_history(const char *flname) { int i; // Looping var char absolute[FL_PATH_MAX]; int max_files; fluid_prefs.get("recent_files", max_files, 5); if (max_files > 10) max_files = 10; fl_filename_absolute(absolute, sizeof(absolute), flname); for (i = 0; i < max_files; i ++) #if defined(WIN32) || defined(__APPLE__) if (!strcasecmp(absolute, absolute_history[i])) break; #else if (!strcmp(absolute, absolute_history[i])) break; #endif // WIN32 || __APPLE__ if (i == 0) return; if (i >= max_files) i = max_files - 1; // Move the other flnames down in the list... memmove(absolute_history + 1, absolute_history, i * sizeof(absolute_history[0])); memmove(relative_history + 1, relative_history, i * sizeof(relative_history[0])); // Put the new file at the top... strlcpy(absolute_history[0], absolute, sizeof(absolute_history[0])); fl_filename_relative(relative_history[0], sizeof(relative_history[0]), absolute_history[0]); // Update the menu items as needed... for (i = 0; i < max_files; i ++) { fluid_prefs.set( Fl_Preferences::Name("file%d", i), absolute_history[i]); if (absolute_history[i][0]) { if (i == 9) history_item[i].flags = FL_MENU_DIVIDER; else history_item[i].flags = 0; } else break; } for (; i < 10; i ++) { fluid_prefs.set( Fl_Preferences::Name("file%d", i), ""); if (i) history_item[i-1].flags |= FL_MENU_DIVIDER; history_item[i].hide(); } } // ********** portable process class definition ********** class Fl_Process { public: // construction / destruction Fl_Process() {_fpt= NULL;} ~Fl_Process() {if (_fpt) close();} // FIXME: popen needs the utf8 equivalen fl_popen FILE * popen (const char *cmd, const char *mode="r"); //not necessary here: FILE * fl_fopen (const char *file, const char *mode="r"); int close(); FILE * desc() const { return _fpt;} // non null if file is open char * get_line(char * line, size_t s) const {return _fpt ? fgets(line, s, _fpt) : NULL;} #if defined(WIN32) && !defined(__CYGWIN__) protected: HANDLE pin[2], pout[2], perr[2]; char ptmode; PROCESS_INFORMATION pi; STARTUPINFO si; static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE); private: FILE * freeHandles() { clean_close(pin[0]); clean_close(pin[1]); clean_close(pout[0]); clean_close(pout[1]); clean_close(perr[0]); clean_close(perr[1]); return NULL; // convenient for error management } static void clean_close(HANDLE& h); #endif protected: FILE * _fpt; }; #if defined(WIN32) && !defined(__CYGWIN__) bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = bInheritHnd; return CreatePipe (&h[0],&h[1],&sa,0) ? true : false; } #endif // portable open process: FILE * Fl_Process::popen(const char *cmd, const char *mode) { #if defined(WIN32) && !defined(__CYGWIN__) // PRECONDITIONS if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL; if (_fpt) close(); // close first before reuse ptmode = *mode; pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE; // stderr to stdout wanted ? int fusion = (strstr(cmd,"2>&1") !=NULL); // Create windows pipes if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) ) return freeHandles(); // error // Initialize Startup Info ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = pin[0]; si.hStdOutput = pout[1]; si.hStdError = fusion ? pout[1] : perr [1]; if ( CreateProcess(NULL, (LPTSTR) cmd,NULL,NULL,TRUE, DETACHED_PROCESS,NULL,NULL, &si, &pi)) { // don't need theses handles inherited by child process: clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]); HANDLE & h = *mode == 'r' ? pout[0] : pin[1]; _fpt = _fdopen(_open_osfhandle((fl_intptr_t) h,_O_BINARY),mode); h= INVALID_HANDLE_VALUE; // reset the handle pointer that is shared // with _fpt so we don't free it twice } if (!_fpt) freeHandles(); return _fpt; #else _fpt=::popen(cmd,mode); return _fpt; #endif } int Fl_Process::close() { #if defined(WIN32) && !defined(__CYGWIN__) if (_fpt) { fclose(_fpt); clean_close(perr[0]); clean_close(pin[1]); clean_close(pout[0]); _fpt = NULL; return 0; } return -1; #else int ret = ::pclose(_fpt); _fpt=NULL; return ret; #endif } #if defined(WIN32) && !defined(__CYGWIN__) void Fl_Process::clean_close(HANDLE& h) { if (h!= INVALID_HANDLE_VALUE) CloseHandle(h); h = INVALID_HANDLE_VALUE; } #endif // ********** Fl_Process class end ********** static Fl_Process s_proc; // Shell command support... static bool prepare_shell_command(const char * &command) { // common pre-shell command code all platforms shell_window->hide(); if (s_proc.desc()) { fl_alert("Previous shell command still running!"); return false; } if ((command = shell_command_input->value()) == NULL || !*command) { fl_alert("No shell command entered!"); return false; } if (shell_savefl_button->value()) { save_cb(0, 0); } if (shell_writecode_button->value()) { compile_only = 1; write_cb(0, 0); compile_only = 0; } if (shell_writemsgs_button->value()) { compile_only = 1; write_strings_cb(0, 0); compile_only = 0; } return true; } #if !defined(__MWERKS__) // Support the full piped shell command... void shell_pipe_cb(int, void*) { char line[1024]=""; // Line from command output... if (s_proc.get_line(line, sizeof(line)) != NULL) { // Add the line to the output list... shell_run_buffer->append(line); } else { // End of file; tell the parent... Fl::remove_fd(fileno(s_proc.desc())); s_proc.close(); shell_run_buffer->append("... END SHELL COMMAND ...\n"); } shell_run_display->scroll(shell_run_display->count_lines(0, shell_run_buffer->length(), 1), 0); } void do_shell_command(Fl_Return_Button*, void*) { const char *command=NULL; // Command to run if (!prepare_shell_command(command)) return; // Show the output window and clear things... shell_run_buffer->text(""); shell_run_buffer->append(command); shell_run_buffer->append("\n"); shell_run_window->label("Shell Command Running..."); if (s_proc.popen((char *)command) == NULL) { fl_alert("Unable to run shell command: %s", strerror(errno)); return; } shell_run_button->deactivate(); shell_run_window->hotspot(shell_run_display); shell_run_window->show(); Fl::add_fd(fileno(s_proc.desc()), shell_pipe_cb); while (s_proc.desc()) Fl::wait(); shell_run_button->activate(); shell_run_window->label("Shell Command Complete"); fl_beep(); while (shell_run_window->shown()) Fl::wait(); } #else // Just do basic shell command stuff, no status window... void do_shell_command(Fl_Return_Button*, void*) { const char *command; // Command to run int status; // Status from command... if (!prepare_shell_command(command)) return; if ((status = system(command)) != 0) { fl_alert("Shell command returned status %d!", status); } else if (completion_button->value()) { fl_message("Shell command completed successfully!"); } } #endif // !__MWERKS__ void show_shell_window() { shell_window->hotspot(shell_command_input); shell_window->show(); } void set_filename(const char *c) { if (filename) free((void *)filename); filename = c ? strdup(c) : NULL; if (filename) update_history(filename); set_modflag(modflag); } // // The Source View system offers an immediate preview of the code // files that will be generated by FLUID. It also marks the code // generated for the last selected item in the header and the source // file. // // Can we patent this? ;-) - Matt, mm@matthiasm.com // // // Update the header and source code highlighting depending on the // currently selected object // void update_sourceview_position() { if (!sourceview_panel || !sourceview_panel->visible()) return; if (sv_autoposition->value()==0) return; if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) { int pos0, pos1; if (sv_source->visible_r()) { pos0 = Fl_Type::current->code_position; pos1 = Fl_Type::current->code_position_end; if (pos0>=0) { if (pos1buffer()->highlight(pos0, pos1); int line = sv_source->buffer()->count_lines(0, pos0); sv_source->scroll(line, 0); } } if (sv_header->visible_r()) { pos0 = Fl_Type::current->header_position; pos1 = Fl_Type::current->header_position_end; if (pos0>=0) { if (pos1buffer()->highlight(pos0, pos1); int line = sv_header->buffer()->count_lines(0, pos0); sv_header->scroll(line, 0); } } } } void update_sourceview_position_cb(Fl_Tabs*, void*) { update_sourceview_position(); } static char *sv_source_filename = 0; static char *sv_header_filename = 0; // // Generate a header and source file in a temporary directory and // load those into the Code Viewer widgets. // void update_sourceview_cb(Fl_Button*, void*) { if (!sourceview_panel || !sourceview_panel->visible()) return; // generate space for the source and header file filenames if (!sv_source_filename) { sv_source_filename = (char*)malloc(FL_PATH_MAX); fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX); strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX); } if (!sv_header_filename) { sv_header_filename = (char*)malloc(FL_PATH_MAX); fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX); strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX); } strlcpy(i18n_program, fl_filename_name(sv_source_filename), sizeof(i18n_program)); fl_filename_setext(i18n_program, sizeof(i18n_program), ""); const char *code_file_name_bak = code_file_name; code_file_name = sv_source_filename; const char *header_file_name_bak = header_file_name; header_file_name = sv_header_filename; // generate the code and load the files write_sourceview = 1; // generate files if (write_code(sv_source_filename, sv_header_filename)) { // load file into source editor int pos = sv_source->top_line(); sv_source->buffer()->loadfile(sv_source_filename); sv_source->scroll(pos, 0); // load file into header editor pos = sv_header->top_line(); sv_header->buffer()->loadfile(sv_header_filename); sv_header->scroll(pos, 0); // update the source code highlighting update_sourceview_position(); } write_sourceview = 0; code_file_name = code_file_name_bak; header_file_name = header_file_name_bak; } void update_sourceview_timer(void*) { update_sourceview_cb(0,0); } // Set the "modified" flag and update the title of the main window... void set_modflag(int mf) { const char *basename; static char title[FL_PATH_MAX]; modflag = mf; if (main_window) { if (!filename) basename = "Untitled.fl"; else if ((basename = strrchr(filename, '/')) != NULL) basename ++; #if defined(WIN32) || defined(__EMX__) else if ((basename = strrchr(filename, '\\')) != NULL) basename ++; #endif // WIN32 || __EMX__ else basename = filename; if (modflag) { snprintf(title, sizeof(title), "%s (modified)", basename); main_window->label(title); } else main_window->label(basename); } // if the UI was modified in any way, update the Source View panel if (sourceview_panel && sourceview_panel->visible() && sv_autorefresh->value()) { // we will only update ealiest 0.5 seconds after the last change, and only // if no other change was made, so dragging a widget will not generate any // CPU load Fl::remove_timeout(update_sourceview_timer, 0); Fl::add_timeout(0.5, update_sourceview_timer, 0); } // Enable/disable the Save menu item... if (modflag) save_item->activate(); else save_item->deactivate(); } //////////////////////////////////////////////////////////////// static int arg(int argc, char** argv, int& i) { if (argv[i][1] == 'c' && !argv[i][2]) {compile_only = 1; i++; return 1;} if (argv[i][1] == 'c' && argv[i][2] == 's' && !argv[i][3]) {compile_only = 1; compile_strings = 1; i++; return 1;} if (argv[i][1] == 'o' && !argv[i][2] && i+1 < argc) { code_file_name = argv[i+1]; code_file_set = 1; i += 2; return 2; } if (argv[i][1] == 'h' && !argv[i][2]) { header_file_name = argv[i+1]; header_file_set = 1; i += 2; return 2; } Fl_Plugin_Manager pm("commandline"); int j, n = pm.plugins(); for (j=0; jarg(argc, argv, i); if (r) return r; } return 0; } #if ! (defined(WIN32) && !defined (__CYGWIN__)) int quit_flag = 0; #include #ifdef _sigargs #define SIGARG _sigargs #else #ifdef __sigargs #define SIGARG __sigargs #else #define SIGARG int // you may need to fix this for older systems #endif #endif extern "C" { static void sigint(SIGARG) { signal(SIGINT,sigint); quit_flag = 1; } } #endif int main(int argc,char **argv) { int i = 1; if (!Fl::args(argc,argv,i,arg) || i < argc-1) { static const char *msg = "usage: %s name.fl\n" " -c : write .cxx and .h and exit\n" " -cs : write .cxx and .h and strings and exit\n" " -o : .cxx output filename, or extension if starts with '.'\n" " -h : .h output filename, or extension if starts with '.'\n"; int len = strlen(msg) + strlen(argv[0]) + strlen(Fl::help); Fl_Plugin_Manager pm("commandline"); int i, n = pm.plugins(); for (i=0; ihelp()); } char *buf = (char*)malloc(len+1); sprintf(buf, msg, argv[0]); for (i=0; ihelp()); } strcat(buf, Fl::help); #ifdef _MSC_VER fl_message("%s\n", buf); #else fprintf(stderr, "%s\n", buf); #endif free(buf); return 1; } if (exit_early) exit(0); const char *c = argv[i]; fl_register_images(); make_main_window(); if (c) set_filename(c); if (!compile_only) { #ifdef __APPLE__ fl_open_callback(apple_open_cb); #endif // __APPLE__ Fl::visual((Fl_Mode)(FL_DOUBLE|FL_INDEX)); Fl_File_Icon::load_system_icons(); main_window->callback(exit_cb); position_window(main_window,"main_window_pos", 1, 10, 30, WINWIDTH, WINHEIGHT ); main_window->show(argc,argv); toggle_widgetbin_cb(0,0); toggle_sourceview_cb(0,0); if (!c && openlast_button->value() && absolute_history[0][0]) { // Open previous file when no file specified... open_history_cb(0, absolute_history[0]); } } undo_suspend(); if (c && !read_file(c,0)) { if (compile_only) { fprintf(stderr,"%s : %s\n", c, strerror(errno)); exit(1); } fl_message("Can't read %s: %s", c, strerror(errno)); } undo_resume(); if (compile_only) { if (compile_strings) write_strings_cb(0,0); write_cb(0,0); exit(0); } set_modflag(0); undo_clear(); #ifndef WIN32 signal(SIGINT,sigint); #endif grid_cb(horizontal_input, 0); // Makes sure that windows get snap params... #ifdef WIN32 Fl::run(); #else while (!quit_flag) Fl::wait(); if (quit_flag) exit_cb(0,0); #endif // WIN32 undo_clear(); return (0); } // // End of "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $". //