fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fluid.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fluid.cxx 8202 2011-01-06 21:36:04Z matt $"
00003 //
00004 // FLUID main entry for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 #include <FL/Fl.H>
00029 #include <FL/Fl_Double_Window.H>
00030 #include <FL/Fl_Box.H>
00031 #include <FL/Fl_Button.H>
00032 #include <FL/Fl_File_Icon.H>
00033 #include <FL/Fl_Help_Dialog.H>
00034 #include <FL/Fl_Hold_Browser.H>
00035 #include <FL/Fl_Menu_Bar.H>
00036 #include <FL/Fl_Input.H>
00037 #include <FL/Fl_Plugin.H>
00038 #include <FL/fl_ask.H>
00039 #include <FL/fl_draw.H>
00040 #include <FL/Fl_File_Chooser.H>
00041 #include <FL/fl_message.H>
00042 #include <FL/filename.H>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <errno.h>
00046 #include <sys/stat.h>
00047 #include <time.h> // time(), localtime(), etc.
00048 
00049 #include "../src/flstring.h"
00050 #include "alignment_panel.h"
00051 #include "function_panel.h"
00052 #include "template_panel.h"
00053 #if !defined(WIN32) || defined(__CYGWIN__)
00054 #  include "print_panel.cxx"
00055 #endif // !WIN32 || __CYGWIN__
00056 
00057 #if defined(WIN32) && !defined(__CYGWIN__)
00058 #  include <direct.h>
00059 #  include <windows.h>
00060 #  include <io.h>
00061 #  include <fcntl.h>
00062 #  include <commdlg.h>
00063 #  include <FL/x.H>
00064 #  ifndef __WATCOMC__
00065 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
00066 // on Windows, which is supposed to be POSIX compliant...
00067 #    define access _access
00068 #    define chdir _chdir
00069 #    define getcwd _getcwd
00070 #  endif // !__WATCOMC__
00071 #else
00072 #  include <unistd.h>
00073 #endif
00074 #ifdef __EMX__
00075 #  include <X11/Xlibint.h>
00076 #endif
00077 
00078 #include "about_panel.h"
00079 #include "undo.h"
00080 
00081 #include "Fl_Type.h"
00082 
00083 extern "C"
00084 {
00085 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
00086 #  include <zlib.h>
00087 #  ifdef HAVE_PNG_H
00088 #    include <png.h>
00089 #  else
00090 #    include <libpng/png.h>
00091 #  endif // HAVE_PNG_H
00092 #endif // HAVE_LIBPNG && HAVE_LIBZ
00093 }
00094 
00095 static Fl_Help_Dialog *help_dialog = 0;
00096 
00097 Fl_Preferences  fluid_prefs(Fl_Preferences::USER, "fltk.org", "fluid");
00098 int gridx = 5;
00099 int gridy = 5;
00100 int snap = 1;
00101 int show_guides = 1;
00102 int show_comments = 1;
00103 int show_coredevmenus = 1;
00104 
00105 // File history info...
00106 char    absolute_history[10][FL_PATH_MAX];
00107 char    relative_history[10][FL_PATH_MAX];
00108 
00109 void    load_history();
00110 void    update_history(const char *);
00111 
00112 // Shell command support...
00113 void    show_shell_window();
00114 
00115 Fl_Menu_Item *save_item = 0L;
00116 Fl_Menu_Item *history_item = 0L;
00117 Fl_Menu_Item *widgetbin_item = 0L;
00118 Fl_Menu_Item *sourceview_item = 0L;
00119 
00121 
00122 static const char *filename;
00123 void set_filename(const char *c);
00124 void set_modflag(int mf);
00125 int modflag;
00126 
00127 static char* pwd;
00128 static char in_source_dir;
00129 void goto_source_dir() {
00130   if (in_source_dir) return;
00131   if (!filename || !*filename) return;
00132   const char *p = fl_filename_name(filename);
00133   if (p <= filename) return; // it is in the current directory
00134   char buffer[FL_PATH_MAX];
00135   strlcpy(buffer, filename, sizeof(buffer));
00136   int n = p-filename; if (n>1) n--; buffer[n] = 0;
00137   if (!pwd) {
00138     pwd = getcwd(0,FL_PATH_MAX);
00139     if (!pwd) {fprintf(stderr,"getwd : %s\n",strerror(errno)); return;}
00140   }
00141   if (chdir(buffer)<0) {fprintf(stderr, "Can't chdir to %s : %s\n",
00142                                 buffer, strerror(errno)); return;}
00143   in_source_dir = 1;
00144 }
00145 
00146 void leave_source_dir() {
00147   if (!in_source_dir) return;
00148   if (chdir(pwd)<0) {fprintf(stderr, "Can't chdir to %s : %s\n",
00149                              pwd, strerror(errno));}
00150   in_source_dir = 0;
00151 }
00152 
00153 char position_window(Fl_Window *w, const char *prefsName, int Visible, int X, int Y, int W=0, int H=0 ) {
00154   Fl_Preferences pos(fluid_prefs, prefsName);
00155   if (prevpos_button->value()) {
00156     pos.get("x", X, X);
00157     pos.get("y", Y, Y);
00158     if ( W!=0 ) {
00159       pos.get("w", W, W);
00160       pos.get("h", H, H);
00161       w->resize( X, Y, W, H );
00162     }
00163     else
00164       w->position( X, Y );
00165   }
00166   pos.get("visible", Visible, Visible);
00167   return Visible;
00168 }
00169 
00170 void save_position(Fl_Window *w, const char *prefsName) {
00171   Fl_Preferences pos(fluid_prefs, prefsName);
00172   pos.set("x", w->x());
00173   pos.set("y", w->y());
00174   pos.set("w", w->w());
00175   pos.set("h", w->h());
00176   pos.set("visible", (int)(w->shown() && w->visible()));
00177 }
00178 
00179 Fl_Window *main_window;
00180 Fl_Menu_Bar *main_menubar;
00181 
00182 static char* cutfname(int which = 0) {
00183   static char name[2][FL_PATH_MAX];
00184   static char beenhere = 0;
00185 
00186   if (!beenhere) {
00187     beenhere = 1;
00188     fluid_prefs.getUserdataPath(name[0], sizeof(name[0]));
00189     strlcat(name[0], "cut_buffer", sizeof(name[0]));
00190     fluid_prefs.getUserdataPath(name[1], sizeof(name[1]));
00191     strlcat(name[1], "dup_buffer", sizeof(name[1]));
00192   }
00193 
00194   return name[which];
00195 }
00196 
00197 void save_cb(Fl_Widget *, void *v) {
00198   const char *c = filename;
00199   if (v || !c || !*c) {
00200     fl_file_chooser_ok_label("Save");
00201     c=fl_file_chooser("Save To:", "FLUID Files (*.f[ld])", c);
00202     fl_file_chooser_ok_label(NULL);
00203     if (!c) return;
00204 
00205     if (!access(c, 0)) {
00206       const char *basename;
00207       if ((basename = strrchr(c, '/')) != NULL)
00208         basename ++;
00209 #if defined(WIN32) || defined(__EMX__)
00210       if ((basename = strrchr(c, '\\')) != NULL)
00211         basename ++;
00212 #endif // WIN32 || __EMX__
00213       else
00214         basename = c;
00215 
00216       if (fl_choice("The file \"%s\" already exists.\n"
00217                     "Do you want to replace it?", "Cancel",
00218                     "Replace", NULL, basename) == 0) return;
00219     }
00220 
00221     if (v != (void *)2) set_filename(c);
00222   }
00223   if (!write_file(c)) {
00224     fl_alert("Error writing %s: %s", c, strerror(errno));
00225     return;
00226   }
00227 
00228   if (v != (void *)2) {
00229     set_modflag(0);
00230     undo_save = undo_current;
00231   }
00232 }
00233 
00234 void save_template_cb(Fl_Widget *, void *) {
00235   // Setup the template panel...
00236   if (!template_panel) make_template_panel();
00237 
00238   template_clear();
00239   template_browser->add("New Template");
00240   template_load();
00241 
00242   template_name->show();
00243   template_name->value("");
00244 
00245   template_instance->hide();
00246 
00247   template_delete->show();
00248   template_delete->deactivate();
00249 
00250   template_submit->label("Save");
00251   template_submit->deactivate();
00252 
00253   template_panel->label("Save Template");
00254 
00255   // Show the panel and wait for the user to do something...
00256   template_panel->show();
00257   while (template_panel->shown()) Fl::wait();
00258 
00259   // Get the template name, return if it is empty...
00260   const char *c = template_name->value();
00261   if (!c || !*c) return;
00262 
00263   // Convert template name to filename_with_underscores
00264   char safename[FL_PATH_MAX], *safeptr;
00265   strlcpy(safename, c, sizeof(safename));
00266   for (safeptr = safename; *safeptr; safeptr ++) {
00267     if (isspace(*safeptr)) *safeptr = '_';
00268   }
00269 
00270   // Find the templates directory...
00271   char filename[FL_PATH_MAX];
00272   fluid_prefs.getUserdataPath(filename, sizeof(filename));
00273 
00274   strlcat(filename, "templates", sizeof(filename));
00275 #if defined(WIN32) && !defined(__CYGWIN__)
00276   if (access(filename, 0)) mkdir(filename);
00277 #else
00278   if (access(filename, 0)) mkdir(filename, 0777);
00279 #endif // WIN32 && !__CYGWIN__
00280 
00281   strlcat(filename, "/", sizeof(filename));
00282   strlcat(filename, safename, sizeof(filename));
00283 
00284   char *ext = filename + strlen(filename);
00285   if (ext >= (filename + sizeof(filename) - 5)) {
00286     fl_alert("The template name \"%s\" is too long!", c);
00287     return;
00288   }
00289 
00290   // Save the .fl file...
00291   strcpy(ext, ".fl");
00292 
00293   if (!access(filename, 0)) {
00294     if (fl_choice("The template \"%s\" already exists.\n"
00295                   "Do you want to replace it?", "Cancel",
00296                   "Replace", NULL, c) == 0) return;
00297   }
00298 
00299   if (!write_file(filename)) {
00300     fl_alert("Error writing %s: %s", filename, strerror(errno));
00301     return;
00302   }
00303 
00304 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
00305   // Get the screenshot, if any...
00306   Fl_Type *t;
00307 
00308   for (t = Fl_Type::first; t; t = t->next) {
00309     // Find the first window...
00310     if (t->is_window()) break;
00311   }
00312 
00313   if (!t) return;
00314 
00315   // Grab a screenshot...
00316   Fl_Window_Type *wt = (Fl_Window_Type *)t;
00317   uchar *pixels;
00318   int w, h;
00319 
00320   if ((pixels = wt->read_image(w, h)) == NULL) return;
00321 
00322   // Save to a PNG file...
00323   strcpy(ext, ".png");
00324 
00325   FILE *fp;
00326 
00327   if ((fp = fl_fopen(filename, "wb")) == NULL) {
00328     delete[] pixels;
00329     fl_alert("Error writing %s: %s", filename, strerror(errno));
00330     return;
00331   }
00332 
00333   png_structp pptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00334   png_infop iptr = png_create_info_struct(pptr);
00335   png_bytep ptr = (png_bytep)pixels;
00336 
00337   png_init_io(pptr, fp);
00338   png_set_IHDR(pptr, iptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
00339                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00340   png_set_sRGB(pptr, iptr, PNG_sRGB_INTENT_PERCEPTUAL);
00341 
00342   png_write_info(pptr, iptr);
00343 
00344   for (int i = h; i > 0; i --, ptr += w * 3) {
00345     png_write_row(pptr, ptr);
00346   }
00347 
00348   png_write_end(pptr, iptr);
00349   png_destroy_write_struct(&pptr, &iptr);
00350 
00351   fclose(fp);
00352 
00353 #  if 0 // The original PPM output code...
00354   strcpy(ext, ".ppm");
00355   fp = fl_fopen(filename, "wb");
00356   fprintf(fp, "P6\n%d %d 255\n", w, h);
00357   fwrite(pixels, w * h, 3, fp);
00358   fclose(fp);
00359 #  endif // 0
00360 
00361   delete[] pixels;
00362 #endif // HAVE_LIBPNG && HAVE_LIBZ
00363 }
00364 
00365 void revert_cb(Fl_Widget *,void *) {
00366   if (modflag) {
00367     if (!fl_choice("This user interface has been changed. Really revert?",
00368                    "Cancel", "Revert", NULL)) return;
00369   }
00370   undo_suspend();
00371   if (!read_file(filename, 0)) {
00372     undo_resume();
00373     fl_message("Can't read %s: %s", filename, strerror(errno));
00374     return;
00375   }
00376   undo_resume();
00377   set_modflag(0);
00378   undo_clear();
00379 }
00380 
00381 void exit_cb(Fl_Widget *,void *) {
00382   if (modflag)
00383     switch (fl_choice("Do you want to save changes to this user\n"
00384                       "interface before exiting?", "Cancel",
00385                       "Save", "Don't Save"))
00386     {
00387       case 0 : /* Cancel */
00388           return;
00389       case 1 : /* Save */
00390           save_cb(NULL, NULL);
00391           if (modflag) return;  // Didn't save!
00392     }
00393 
00394   save_position(main_window,"main_window_pos");
00395 
00396   if (widgetbin_panel) {
00397     save_position(widgetbin_panel,"widgetbin_pos");
00398     delete widgetbin_panel;
00399   }
00400   if (sourceview_panel) {
00401     Fl_Preferences svp(fluid_prefs, "sourceview");
00402     svp.set("autorefresh", sv_autorefresh->value());
00403     svp.set("autoposition", sv_autoposition->value());
00404     svp.set("tab", sv_tab->find(sv_tab->value()));
00405     save_position(sourceview_panel,"sourceview_pos");
00406     delete sourceview_panel;
00407   }
00408   if (about_panel)
00409     delete about_panel;
00410   if (help_dialog)
00411     delete help_dialog;
00412 
00413   undo_clear();
00414 
00415   exit(0);
00416 }
00417 
00418 #ifdef __APPLE__
00419 #  include <FL/x.H>
00420 
00421 void
00422 apple_open_cb(const char *c) {
00423   if (modflag) {
00424     switch (fl_choice("Do you want to save changes to this user\n"
00425                       "interface before opening another one?", "Don't Save",
00426                       "Save", "Cancel"))
00427     {
00428       case 0 : /* Cancel */
00429           return;
00430       case 1 : /* Save */
00431           save_cb(NULL, NULL);
00432           if (modflag) return;  // Didn't save!
00433     }
00434   }
00435   const char *oldfilename;
00436   oldfilename = filename;
00437   filename    = NULL;
00438   set_filename(c);
00439   undo_suspend();
00440   if (!read_file(c, 0)) {
00441     undo_resume();
00442     fl_message("Can't read %s: %s", c, strerror(errno));
00443     free((void *)filename);
00444     filename = oldfilename;
00445     if (main_window) main_window->label(filename);
00446     return;
00447   }
00448 
00449   // Loaded a file; free the old filename...
00450   set_modflag(0);
00451   undo_resume();
00452   undo_clear();
00453   if (oldfilename) free((void *)oldfilename);
00454 }
00455 #endif // __APPLE__
00456 
00457 void open_cb(Fl_Widget *, void *v) {
00458   if (!v && modflag) {
00459     switch (fl_choice("Do you want to save changes to this user\n"
00460                       "interface before opening another one?", "Cancel",
00461                       "Save", "Don't Save"))
00462     {
00463       case 0 : /* Cancel */
00464           return;
00465       case 1 : /* Save */
00466           save_cb(NULL, NULL);
00467           if (modflag) return;  // Didn't save!
00468     }
00469   }
00470   const char *c;
00471   const char *oldfilename;
00472   fl_file_chooser_ok_label("Open");
00473   c = fl_file_chooser("Open:", "FLUID Files (*.f[ld])", filename);
00474   fl_file_chooser_ok_label(NULL);
00475   if (!c) return;
00476   oldfilename = filename;
00477   filename    = NULL;
00478   set_filename(c);
00479   if (v != 0) undo_checkpoint();
00480   undo_suspend();
00481   if (!read_file(c, v!=0)) {
00482     undo_resume();
00483     fl_message("Can't read %s: %s", c, strerror(errno));
00484     free((void *)filename);
00485     filename = oldfilename;
00486     if (main_window) set_modflag(modflag);
00487     return;
00488   }
00489   undo_resume();
00490   if (v) {
00491     // Inserting a file; restore the original filename...
00492     free((void *)filename);
00493     filename = oldfilename;
00494     set_modflag(1);
00495   } else {
00496     // Loaded a file; free the old filename...
00497     set_modflag(0);
00498     undo_clear();
00499     if (oldfilename) free((void *)oldfilename);
00500   }
00501 }
00502 
00503 void open_history_cb(Fl_Widget *, void *v) {
00504   if (modflag) {
00505     switch (fl_choice("Do you want to save changes to this user\n"
00506                       "interface before opening another one?", "Cancel",
00507                       "Save", "Don't Save"))
00508     {
00509       case 0 : /* Cancel */
00510           return;
00511       case 1 : /* Save */
00512           save_cb(NULL, NULL);
00513           if (modflag) return;  // Didn't save!
00514     }
00515   }
00516   const char *oldfilename = filename;
00517   filename = NULL;
00518   set_filename((char *)v);
00519   undo_suspend();
00520   if (!read_file(filename, 0)) {
00521     undo_resume();
00522     undo_clear();
00523     fl_message("Can't read %s: %s", filename, strerror(errno));
00524     free((void *)filename);
00525     filename = oldfilename;
00526     if (main_window) main_window->label(filename);
00527     return;
00528   }
00529   set_modflag(0);
00530   undo_resume();
00531   undo_clear();
00532   if (oldfilename) free((void *)oldfilename);
00533 }
00534 
00535 void new_cb(Fl_Widget *, void *v) {
00536   // Check if the current file has been modified...
00537   if (!v && modflag) {
00538     // Yes, ask the user what to do...
00539     switch (fl_choice("Do you want to save changes to this user\n"
00540                       "interface before creating a new one?", "Cancel",
00541                       "Save", "Don't Save"))
00542     {
00543       case 0 : /* Cancel */
00544           return;
00545       case 1 : /* Save */
00546           save_cb(NULL, NULL);
00547           if (modflag) return;  // Didn't save!
00548     }
00549   }
00550 
00551   // Setup the template panel...
00552   if (!template_panel) make_template_panel();
00553 
00554   template_clear();
00555   template_browser->add("Blank");
00556   template_load();
00557 
00558   template_name->hide();
00559   template_name->value("");
00560 
00561   template_instance->show();
00562   template_instance->deactivate();
00563   template_instance->value("");
00564 
00565   template_delete->hide();
00566 
00567   template_submit->label("New");
00568   template_submit->deactivate();
00569 
00570   template_panel->label("New");
00571 
00572   // Show the panel and wait for the user to do something...
00573   template_panel->show();
00574   while (template_panel->shown()) Fl::wait();
00575 
00576   // See if the user chose anything...
00577   int item = template_browser->value();
00578   if (item < 1) return;
00579 
00580   // Clear the current data...
00581   delete_all();
00582   set_filename(NULL);
00583 
00584   // Load the template, if any...
00585   const char *tname = (const char *)template_browser->data(item);
00586 
00587   if (tname) {
00588     // Grab the instance name...
00589     const char *iname = template_instance->value();
00590 
00591     if (iname && *iname) {
00592       // Copy the template to a temp file, then read it in...
00593       char line[1024], *ptr, *next;
00594       FILE *infile, *outfile;
00595 
00596       if ((infile = fl_fopen(tname, "r")) == NULL) {
00597         fl_alert("Error reading template file \"%s\":\n%s", tname,
00598                  strerror(errno));
00599         set_modflag(0);
00600         undo_clear();
00601         return;
00602       }
00603 
00604       if ((outfile = fl_fopen(cutfname(1), "w")) == NULL) {
00605         fl_alert("Error writing buffer file \"%s\":\n%s", cutfname(1),
00606                  strerror(errno));
00607         fclose(infile);
00608         set_modflag(0);
00609         undo_clear();
00610         return;
00611       }
00612 
00613       while (fgets(line, sizeof(line), infile)) {
00614         // Replace @INSTANCE@ with the instance name...
00615         for (ptr = line; (next = strstr(ptr, "@INSTANCE@")) != NULL; ptr = next + 10) {
00616           fwrite(ptr, next - ptr, 1, outfile);
00617           fputs(iname, outfile);
00618         }
00619 
00620         fputs(ptr, outfile);
00621       }
00622 
00623       fclose(infile);
00624       fclose(outfile);
00625 
00626       undo_suspend();
00627       read_file(cutfname(1), 0);
00628       unlink(cutfname(1));
00629       undo_resume();
00630     } else {
00631       // No instance name, so read the template without replacements...
00632       undo_suspend();
00633       read_file(tname, 0);
00634       undo_resume();
00635     }
00636   }
00637 
00638   set_modflag(0);
00639   undo_clear();
00640 }
00641 
00642 int exit_early = 0;
00643 int compile_only = 0;
00644 int compile_strings = 0;
00645 int header_file_set = 0;
00646 int code_file_set = 0;
00647 const char* header_file_name = ".h";
00648 const char* code_file_name = ".cxx";
00649 int i18n_type = 0;
00650 const char* i18n_include = "";
00651 const char* i18n_function = "";
00652 const char* i18n_file = "";
00653 const char* i18n_set = "";
00654 char i18n_program[FL_PATH_MAX] = "";
00655 
00656 void write_cb(Fl_Widget *, void *) {
00657   if (!filename) {
00658     save_cb(0,0);
00659     if (!filename) return;
00660   }
00661   char cname[FL_PATH_MAX];
00662   char hname[FL_PATH_MAX];
00663   strlcpy(i18n_program, fl_filename_name(filename), sizeof(i18n_program));
00664   fl_filename_setext(i18n_program, sizeof(i18n_program), "");
00665   if (*code_file_name == '.' && strchr(code_file_name, '/') == NULL) {
00666     strlcpy(cname, fl_filename_name(filename), sizeof(cname));
00667     fl_filename_setext(cname, sizeof(cname), code_file_name);
00668   } else {
00669     strlcpy(cname, code_file_name, sizeof(hname));
00670   }
00671   if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) {
00672     strlcpy(hname, fl_filename_name(filename), sizeof(hname));
00673     fl_filename_setext(hname, sizeof(hname), header_file_name);
00674   } else {
00675     strlcpy(hname, header_file_name, sizeof(hname));
00676   }
00677   if (!compile_only) goto_source_dir();
00678   int x = write_code(cname,hname);
00679   if (!compile_only) leave_source_dir();
00680   strlcat(cname, " and ", sizeof(cname));
00681   strlcat(cname, hname, sizeof(cname));
00682   if (compile_only) {
00683     if (!x) {fprintf(stderr,"%s : %s\n",cname,strerror(errno)); exit(1);}
00684   } else {
00685     if (!x) {
00686       fl_message("Can't write %s: %s", cname, strerror(errno));
00687     } else if (completion_button->value()) {
00688       fl_message("Wrote %s", cname);
00689     }
00690   }
00691 }
00692 
00693 void write_strings_cb(Fl_Widget *, void *) {
00694   static const char *exts[] = { ".txt", ".po", ".msg" };
00695   if (!filename) {
00696     save_cb(0,0);
00697     if (!filename) return;
00698   }
00699   char sname[FL_PATH_MAX];
00700   strlcpy(sname, fl_filename_name(filename), sizeof(sname));
00701   fl_filename_setext(sname, sizeof(sname), exts[i18n_type]);
00702   if (!compile_only) goto_source_dir();
00703   int x = write_strings(sname);
00704   if (!compile_only) leave_source_dir();
00705   if (compile_only) {
00706     if (x) {fprintf(stderr,"%s : %s\n",sname,strerror(errno)); exit(1);}
00707   } else {
00708     if (x) {
00709       fl_message("Can't write %s: %s", sname, strerror(errno));
00710     } else if (completion_button->value()) {
00711       fl_message("Wrote %s", sname);
00712     }
00713   }
00714 }
00715 
00716 void openwidget_cb(Fl_Widget *, void *) {
00717   if (!Fl_Type::current) {
00718     fl_message("Please select a widget");
00719     return;
00720   }
00721   Fl_Type::current->open();
00722 }
00723 
00724 void toggle_overlays(Fl_Widget *,void *);
00725 
00726 void select_all_cb(Fl_Widget *,void *);
00727 void select_none_cb(Fl_Widget *,void *);
00728 
00729 void group_cb(Fl_Widget *, void *);
00730 
00731 void ungroup_cb(Fl_Widget *, void *);
00732 
00733 extern int pasteoffset;
00734 static int ipasteoffset;
00735 
00736 void copy_cb(Fl_Widget*, void*) {
00737   if (!Fl_Type::current) {
00738     fl_beep();
00739     return;
00740   }
00741   ipasteoffset = 10;
00742   if (!write_file(cutfname(),1)) {
00743     fl_message("Can't write %s: %s", cutfname(), strerror(errno));
00744     return;
00745   }
00746 }
00747 
00748 extern void select_only(Fl_Type *);
00749 void cut_cb(Fl_Widget *, void *) {
00750   if (!Fl_Type::current) {
00751     fl_beep();
00752     return;
00753   }
00754   if (!write_file(cutfname(),1)) {
00755     fl_message("Can't write %s: %s", cutfname(), strerror(errno));
00756     return;
00757   }
00758   undo_checkpoint();
00759   set_modflag(1);
00760   ipasteoffset = 0;
00761   Fl_Type *p = Fl_Type::current->parent;
00762   while (p && p->selected) p = p->parent;
00763   delete_all(1);
00764   if (p) select_only(p);
00765 }
00766 
00767 void delete_cb(Fl_Widget *, void *) {
00768   if (!Fl_Type::current) {
00769     fl_beep();
00770     return;
00771   }
00772   undo_checkpoint();
00773   set_modflag(1);
00774   ipasteoffset = 0;
00775   Fl_Type *p = Fl_Type::current->parent;
00776   while (p && p->selected) p = p->parent;
00777   delete_all(1);
00778   if (p) select_only(p);
00779 }
00780 
00781 extern int force_parent;
00782 
00783 void paste_cb(Fl_Widget*, void*) {
00784   //if (ipasteoffset) force_parent = 1;
00785   pasteoffset = ipasteoffset;
00786   if (gridx>1) pasteoffset = ((pasteoffset-1)/gridx+1)*gridx;
00787   if (gridy>1) pasteoffset = ((pasteoffset-1)/gridy+1)*gridy;
00788   undo_checkpoint();
00789   undo_suspend();
00790   if (!read_file(cutfname(), 1)) {
00791     fl_message("Can't read %s: %s", cutfname(), strerror(errno));
00792   }
00793   undo_resume();
00794   pasteoffset = 0;
00795   ipasteoffset += 10;
00796   force_parent = 0;
00797 }
00798 
00799 // Duplicate the selected widgets...
00800 void duplicate_cb(Fl_Widget*, void*) {
00801   if (!Fl_Type::current) {
00802     fl_beep();
00803     return;
00804   }
00805 
00806   if (!write_file(cutfname(1),1)) {
00807     fl_message("Can't write %s: %s", cutfname(1), strerror(errno));
00808     return;
00809   }
00810 
00811   pasteoffset  = 0;
00812   force_parent = 1;
00813 
00814   undo_checkpoint();
00815   undo_suspend();
00816   if (!read_file(cutfname(1), 1)) {
00817     fl_message("Can't read %s: %s", cutfname(1), strerror(errno));
00818   }
00819   unlink(cutfname(1));
00820   undo_resume();
00821 
00822   force_parent = 0;
00823 }
00824 
00825 void earlier_cb(Fl_Widget*,void*);
00826 
00827 void later_cb(Fl_Widget*,void*);
00828 
00829 Fl_Type *sort(Fl_Type *parent);
00830 
00831 static void sort_cb(Fl_Widget *,void *) {
00832   sort((Fl_Type*)0);
00833 }
00834 
00835 void show_project_cb(Fl_Widget *, void *);
00836 void show_grid_cb(Fl_Widget *, void *);
00837 void show_settings_cb(Fl_Widget *, void *);
00838 void show_global_settings_cb(Fl_Widget *, void *);
00839 
00840 void align_widget_cb(Fl_Widget *, long);
00841 void widget_size_cb(Fl_Widget *, long);
00842 
00843 void about_cb(Fl_Widget *, void *) {
00844   if (!about_panel) make_about_panel();
00845   about_panel->show();
00846 }
00847 
00848 void show_help(const char *name) {
00849   const char    *docdir;
00850   char          helpname[FL_PATH_MAX];
00851 
00852   if (!help_dialog) help_dialog = new Fl_Help_Dialog();
00853 
00854   if ((docdir = getenv("FLTK_DOCDIR")) == NULL) {
00855 #ifdef __EMX__
00856     // Doesn't make sense to have a hardcoded fallback
00857     static char fltk_docdir[FL_PATH_MAX];
00858 
00859     strlcpy(fltk_docdir, __XOS2RedirRoot("/XFree86/lib/X11/fltk/doc"),
00860             sizeof(fltk_docdir));
00861 
00862     docdir = fltk_docdir;
00863 #else
00864     docdir = FLTK_DOCDIR;
00865 #endif // __EMX__
00866   }
00867   snprintf(helpname, sizeof(helpname), "%s/%s", docdir, name);
00868 
00869   help_dialog->load(helpname);
00870   help_dialog->show();
00871 }
00872 
00873 void help_cb(Fl_Widget *, void *) {
00874   show_help("fluid.html");
00875 }
00876 
00877 void manual_cb(Fl_Widget *, void *) {
00878   show_help("main.html");
00879 }
00880 
00881 
00883 
00884 #if defined(WIN32) && !defined(__CYGWIN__)
00885 // Draw a shaded box...
00886 static void win_box(int x, int y, int w, int h) {
00887   fl_color(0xc0, 0xc0, 0xc0);
00888   fl_rectf(x, y, w, h);
00889   fl_color(0, 0, 0);
00890   fl_rect(x, y, w, h);
00891   fl_color(0xf0, 0xf0, 0xf0);
00892   fl_rectf(x + 1, y + 1, 4, h - 2);
00893   fl_rectf(x + 1, y + 1, w - 2, 4);
00894   fl_color(0x90, 0x90, 0x90);
00895   fl_rectf(x + w - 5, y + 1, 4, h - 2);
00896   fl_rectf(x + 1, y + h - 5, w - 2, 4);
00897 }
00898 
00899 // Load and show the print dialog...
00900 void print_menu_cb(Fl_Widget *, void *) {
00901   PRINTDLG      dialog;                 // Print dialog
00902   DOCINFO       docinfo;                // Document info
00903   int           first, last;            // First and last page
00904   int           page;                   // Current page
00905   int           winpage;                // Current window page
00906   int           num_pages;              // Number of pages
00907   Fl_Type       *t;                     // Current widget
00908   int           num_windows;            // Number of windows
00909   Fl_Window_Type *windows[1000];        // Windows to print
00910 
00911 
00912   // Show print dialog...
00913   for (t = Fl_Type::first, num_pages = 0; t; t = t->next) {
00914     if (t->is_window()) num_pages ++;
00915   }
00916 
00917   memset(&dialog, 0, sizeof(dialog));
00918   dialog.lStructSize = sizeof(dialog);
00919   dialog.hwndOwner   = fl_xid(main_window);
00920   dialog.Flags       = PD_ALLPAGES |
00921                        PD_RETURNDC;
00922   dialog.nFromPage   = 1;
00923   dialog.nToPage     = num_pages;
00924   dialog.nMinPage    = 1;
00925   dialog.nMaxPage    = num_pages;
00926   dialog.nCopies     = 1;
00927 
00928   if (!PrintDlg(&dialog)) return;
00929 
00930   // Get the base filename...
00931   const char *basename = strrchr(filename, '/');
00932   if (basename) basename ++;
00933   else basename = filename;
00934 
00935   // Do the print job...
00936   memset(&docinfo, 0, sizeof(docinfo));
00937   docinfo.cbSize      = sizeof(docinfo);
00938   docinfo.lpszDocName = basename;
00939 
00940   StartDoc(dialog.hDC, &docinfo);
00941 
00942   // Figure out how many pages we'll have to print...
00943   if (dialog.Flags & PD_PAGENUMS) {
00944     // Get from and to page numbers...
00945     first = dialog.nFromPage;
00946     last  = dialog.nToPage;
00947 
00948     if (first > last) {
00949       // Swap first/last page
00950       page  = first;
00951       first = last;
00952       last  = page;
00953     }
00954   } else {
00955     // Print everything...
00956     first = 1;
00957     last  = dialog.nMaxPage;
00958   }
00959 
00960   for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) {
00961     if (t->is_window()) {
00962       winpage ++;
00963       windows[num_windows] = (Fl_Window_Type *)t;
00964       num_windows ++;
00965 #if 0
00966       if (dialog.Flags & PD_ALLPAGES) num_windows ++;
00967       else if ((dialog.Flags & PD_PAGENUMS) && winpage >= first &&
00968                winpage <= last) num_windows ++;
00969       else if ((dialog.Flags & PD_SELECTION) && t->selected) num_windows ++;
00970 #endif // 0
00971     }
00972   }
00973 
00974   num_pages = num_windows;
00975 
00976   // Figure out the page size and margins...
00977   int   width, length;                  // Size of page
00978   int   xdpi, ydpi;                     // Output resolution
00979   char  buffer[1024];
00980 
00981   width  = GetDeviceCaps(dialog.hDC, HORZRES);
00982   length = GetDeviceCaps(dialog.hDC, VERTRES);
00983   xdpi   = GetDeviceCaps(dialog.hDC, LOGPIXELSX);
00984   ydpi   = GetDeviceCaps(dialog.hDC, LOGPIXELSY);
00985 
00986 //  fl_message("width=%d, length=%d, xdpi=%d, ydpi=%d, num_windows=%d\n",
00987 //             width, length, xdpi, ydpi, num_windows);
00988 
00989   HDC   save_dc = fl_gc;
00990   HWND  save_win = fl_window;
00991   int   fontsize = 14 * ydpi / 72;
00992 
00993   fl_gc = dialog.hDC;
00994   fl_window = (HWND)dialog.hDC;
00995   fl_push_no_clip();
00996 
00997   // Get the time and date...
00998   time_t curtime = time(NULL);
00999   struct tm *curdate = localtime(&curtime);
01000   char date[1024];
01001 
01002   strftime(date, sizeof(date), "%c", curdate);
01003 
01004   // Print each of the windows...
01005   for (winpage = 0; winpage < num_windows; winpage ++) {
01006     // Draw header...
01007     StartPage(dialog.hDC);
01008 
01009     fl_font(FL_HELVETICA_BOLD, fontsize);
01010     fl_color(0, 0, 0);
01011 
01012     fl_draw(basename, 0, fontsize);
01013 
01014     fl_draw(date, (width - (int)fl_width(date)) / 2, fontsize);
01015 
01016     sprintf(buffer, "%d/%d", winpage + 1, num_windows);
01017     fl_draw(buffer, width - (int)fl_width(buffer), fontsize);
01018 
01019     // Get window image...
01020     uchar       *pixels;                // Window image data
01021     int         w, h;                   // Window image dimensions
01022     int         ww, hh;                 // Scaled size
01023     int         ulx, uly;               // Upper-lefthand corner
01024     Fl_Window   *win;                   // Window widget
01025     BITMAPINFO  info;                   // Bitmap information
01026 
01027     win    = (Fl_Window *)(windows[winpage]->o);
01028     pixels = windows[winpage]->read_image(w, h);
01029 
01030     // Swap colors: FLTK uses R-G-B --> Windows GDI uses B-G-R
01031 
01032     { uchar *p = pixels;
01033       for (int i=0; i<w*h; i++, p+=3) {
01034         uchar temp = p[0]; p[0] = p[2]; p[2] = temp;
01035       }
01036     }
01037 
01038     // Figure out the window size, first at 100 PPI and then scaled
01039     // down if that is too big...
01040     ww = w * xdpi / 100;
01041     hh = h * ydpi / 100;
01042 
01043     if (ww > width) {
01044       ww = width;
01045       hh = h * ww * ydpi / xdpi / w;
01046     }
01047 
01048     if (hh > (length - ydpi / 2)) {
01049       hh = length - ydpi / 2;
01050       ww = w * hh / h;
01051     }
01052 
01053     // Position the window in the center...
01054     ulx = (width - ww) / 2;
01055     uly = (length - hh) / 2;
01056 
01057 //    fl_message("winpage=%d, ulx=%d, uly=%d, ww=%d, hh=%d",
01058 //               winpage, ulx, uly, ww, hh);
01059 
01060     // Draw a simulated window border...
01061     int xborder = 4 * ww / w;
01062     int yborder = 4 * hh / h;
01063 
01064     win_box(ulx - xborder, uly - 5 * yborder,
01065             ww + 2 * xborder, hh + 6 * yborder);
01066 
01067     fl_color(0, 0, 255);
01068     fl_rectf(ulx, uly - 4 * yborder, ww, 4 * yborder);
01069 
01070     fl_font(FL_HELVETICA_BOLD, 2 * yborder);
01071     fl_color(255, 255, 255);
01072     fl_draw(win->label() ? win->label() : "Window",
01073             ulx + xborder, uly - 3 * yborder);
01074 
01075     int x = ulx + ww - 4 * xborder;
01076 
01077     win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
01078     fl_color(0, 0, 0);
01079     fl_line(x + xborder, uly - yborder,
01080             x + 3 * xborder, uly - 3 * yborder);
01081     fl_line(x + xborder, uly - 3 * yborder,
01082             x + 3 * xborder, uly - yborder);
01083     x -= 4 * xborder;
01084 
01085     if (win->resizable()) {
01086       win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
01087       fl_color(0, 0, 0);
01088       fl_rect(x + xborder, uly - 3 * yborder, 2 * xborder, 2 * yborder);
01089       x -= 4 * xborder;
01090     }
01091 
01092     if (!win->modal()) {
01093       win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
01094       fl_color(0, 0, 0);
01095       fl_line(x + xborder, uly - yborder, x + 3 * xborder, uly - yborder);
01096       x -= 4 * xborder;
01097     }
01098 
01099     // Color image...
01100     memset(&info, 0, sizeof(info));
01101     info.bmiHeader.biSize        = sizeof(info);
01102     info.bmiHeader.biWidth       = w;
01103     info.bmiHeader.biHeight      = 1;
01104     info.bmiHeader.biPlanes      = 1;
01105     info.bmiHeader.biBitCount    = 24;
01106     info.bmiHeader.biCompression = BI_RGB;
01107 
01108     for (int y = 0; y < h; y ++) {
01109       StretchDIBits(dialog.hDC, ulx, uly + y * hh / h, ww, (hh + h - 1) / h, 0, 0, w, 1,
01110                     pixels + y * w * 3, &info, DIB_RGB_COLORS, SRCCOPY);
01111     }
01112 
01113     delete[] pixels;
01114 
01115     // Show the page...
01116     EndPage(dialog.hDC);
01117   }
01118 
01119   // Finish up...
01120   EndDoc(dialog.hDC);
01121 
01122   fl_gc = save_dc;
01123   fl_window = save_win;
01124   fl_pop_clip();
01125 
01126   // Free the print DC and return...
01127   DeleteDC(dialog.hDC);
01128 }
01129 #else
01130 // Load and show the print dialog...
01131 void print_menu_cb(Fl_Widget *, void *) {
01132   if (!print_panel) make_print_panel();
01133 
01134   print_load();
01135 
01136   print_selection->deactivate();
01137 
01138   for (Fl_Type *t = Fl_Type::first; t; t = t->next) {
01139     if (t->selected && t->is_window()) {
01140       print_selection->activate();
01141       break;
01142     }
01143   }
01144 
01145   print_all->setonly();
01146   print_all->do_callback();
01147 
01148   print_panel->show();
01149 }
01150 
01151 // Quote a string for PostScript printing
01152 static const char *ps_string(const char *s) {
01153   char *bufptr;
01154   static char buffer[FL_PATH_MAX];
01155 
01156 
01157   if (!s) {
01158     buffer[0] = '\0';
01159   } else {
01160     for (bufptr = buffer; bufptr < (buffer + sizeof(buffer) - 3) && *s;) {
01161       if (*s == '(' || *s == ')' || *s == '\\') *bufptr++ = '\\';
01162       *bufptr++ = *s++;
01163     }
01164 
01165     *bufptr = '\0';
01166   }
01167 
01168   return (buffer);
01169 }
01170 
01171 // Actually print...
01172 void print_cb(Fl_Return_Button *, void *) {
01173   FILE          *outfile;               // Output file or pipe to print command
01174   char          command[1024];          // Print command
01175   int           copies;                 // Collated copies
01176   int           first, last;            // First and last page
01177   int           page;                   // Current page
01178   int           winpage;                // Current window page
01179   int           num_pages;              // Number of pages
01180   Fl_Type       *t;                     // Current widget
01181   int           num_windows;            // Number of windows
01182   Fl_Window_Type *windows[1000];        // Windows to print
01183 
01184   // Show progress, deactivate controls...
01185   print_panel_controls->deactivate();
01186   print_progress->show();
01187 
01188   // Figure out how many pages we'll have to print...
01189   if (print_collate_button->value()) copies = (int)print_copies->value();
01190   else copies = 1;
01191 
01192   if (print_pages->value()) {
01193     // Get from and to page numbers...
01194     if ((first = atoi(print_from->value())) < 1) first = 1;
01195     if ((last = atoi(print_to->value())) < 1) last = 1000;
01196 
01197     if (first > last) {
01198       // Swap first/last page
01199       page  = first;
01200       first = last;
01201       last  = page;
01202     }
01203   } else {
01204     // Print everything...
01205     first = 1;
01206     last  = 1000;
01207   }
01208 
01209   for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) {
01210     if (t->is_window()) {
01211       winpage ++;
01212       windows[num_windows] = (Fl_Window_Type *)t;
01213 
01214       if (print_all->value()) num_windows ++;
01215       else if (print_pages->value() && winpage >= first &&
01216                winpage <= last) num_windows ++;
01217       else if (print_selection->value() && t->selected) num_windows ++;
01218     }
01219   }
01220 
01221   num_pages = num_windows * copies;
01222 
01223   print_progress->minimum(0);
01224   print_progress->maximum(num_pages);
01225   print_progress->value(0);
01226   Fl::check();
01227 
01228   // Get the base filename...
01229   const char *basename = strrchr(filename, '/');
01230   if (basename) basename ++;
01231   else basename = filename;
01232 
01233   // Open the print stream...
01234   if (print_choice->value()) {
01235     // Pipe the output into the lp command...
01236     const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data();
01237 
01238     snprintf(command, sizeof(command), "lp -s -d %s -n %.0f -t '%s' -o media=%s",
01239              printer, print_collate_button->value() ? 1.0 : print_copies->value(),
01240              basename, print_page_size->text(print_page_size->value()));
01241     outfile = popen(command, "w");
01242   } else {
01243     // Print to file...
01244     fl_file_chooser_ok_label("Print");
01245     const char *outname = fl_file_chooser("Print To", "PostScript (*.ps)", NULL, 1);
01246     fl_file_chooser_ok_label(NULL);
01247 
01248     if (outname && !access(outname, 0)) {
01249       if (fl_choice("The file \"%s\" already exists.\n"
01250                     "Do you want to replace it?", "Cancel",
01251                     "Replace", NULL, outname) == 0) outname = NULL;
01252     }
01253 
01254     if (outname) outfile = fl_fopen(outname, "w");
01255     else outfile = NULL;
01256   }
01257 
01258   if (outfile) {
01259     // Figure out the page size and margins...
01260     int width, length;                  // Size of page
01261     int left, bottom,                   // Bottom lefthand corner
01262         right, top;                     // Top righthand corner
01263 
01264     if (print_page_size->value()) {
01265       // A4
01266       width  = 595;
01267       length = 842;
01268     } else {
01269       // Letter
01270       width  = 612;
01271       length = 792;
01272     }
01273 
01274     int output_mode;
01275     for (output_mode = 0; output_mode < 4; output_mode ++) {
01276       if (print_output_mode[output_mode]->value()) break;
01277     }
01278 
01279     if (output_mode & 1) {
01280       // Landscape
01281       left   = 36;
01282       bottom = 18;
01283       right  = length - 36;
01284       top    = width - 18;
01285     } else {
01286       // Portrait
01287       left   = 18;
01288       bottom = 36;
01289       right  = width - 18;
01290       top    = length - 36;
01291     }
01292 
01293     // Get the time and date...
01294     time_t curtime = time(NULL);
01295     struct tm *curdate = localtime(&curtime);
01296     char date[1024];
01297 
01298     strftime(date, sizeof(date), "%c", curdate);
01299 
01300     // Write the prolog...
01301     fprintf(outfile,
01302             "%%!PS-Adobe-3.0\n"
01303             "%%%%BoundingBox: 18 36 %d %d\n"
01304             "%%%%Pages: %d\n"
01305             "%%%%LanguageLevel: 1\n"
01306             "%%%%DocumentData: Clean7Bit\n"
01307             "%%%%DocumentNeededResources: font Helvetica-Bold\n"
01308             "%%%%Creator: FLUID %.4f\n"
01309             "%%%%CreationDate: %s\n"
01310             "%%%%Title: (%s)\n"
01311             "%%%%EndComments\n"
01312             "%%%%BeginProlog\n"
01313             "%%languagelevel 1 eq {\n"
01314             "  /rectfill {\n"
01315             "    newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
01316             "    neg 0 exch rlineto closepath fill\n"
01317             "  } bind def\n"
01318             "  /rectstroke {\n"
01319             "    newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
01320             "    neg 0 exch rlineto closepath stroke\n"
01321             "  } bind def\n"
01322             "%%} if\n"
01323             "%%%%EndProlog\n"
01324             "%%%%BeginSetup\n"
01325             "%%%%BeginFeature: *PageSize %s\n"
01326             "languagelevel 1 ne {\n"
01327             "  <</PageSize[%d %d]/ImagingBBox null>>setpagedevice\n"
01328             "} {\n"
01329             "  %s\n"
01330             "} ifelse\n"
01331             "%%%%EndFeature\n"
01332             "%%%%EndSetup\n",
01333             width - 18, length - 36,
01334             num_pages,
01335             FL_VERSION,
01336             date,
01337             basename,
01338             print_page_size->text(print_page_size->value()),
01339             width, length,
01340             print_page_size->value() ? "a4tray" : "lettertray");
01341 
01342     // Print each of the windows...
01343     char        progress[255];          // Progress text
01344     int         copy;                   // Current copy
01345 
01346     for (copy = 0, page = 0; copy < copies; copy ++) {
01347       for (winpage = 0; winpage < num_pages; winpage ++) {
01348         // Start next page...
01349         page ++;
01350         sprintf(progress, "Printing page %d/%d...", page, num_pages);
01351         print_progress->value(page);
01352         print_progress->label(progress);
01353         Fl::check();
01354 
01355         // Add common page stuff...
01356         fprintf(outfile,
01357                 "%%%%Page: %d %d\n"
01358                 "gsave\n",
01359                 page, page);
01360 
01361         if (output_mode & 1) {
01362           // Landscape...
01363           fprintf(outfile, "%d 0 translate 90 rotate\n", width);
01364         }
01365 
01366         // Draw header...
01367         fprintf(outfile,
01368                 "0 setgray\n"
01369                 "/Helvetica-Bold findfont 14 scalefont setfont\n"
01370                 "%d %d moveto (%s) show\n"
01371                 "%.1f %d moveto (%s) dup stringwidth pop -0.5 mul 0 rmoveto show\n"
01372                 "%d %d moveto (%d/%d) dup stringwidth pop neg 0 rmoveto show\n",
01373                 left, top - 15, ps_string(basename),
01374                 0.5 * (left + right), top - 15, date,
01375                 right, top - 15, winpage + 1, num_windows);
01376 
01377         // Get window image...
01378         uchar   *pixels;                // Window image data
01379         int     w, h;                   // Window image dimensions
01380         float   ww, hh;                 // Scaled size
01381         float   border;                 // Width of 1 pixel
01382         float   llx, lly,               // Lower-lefthand corner
01383                 urx, ury;               // Upper-righthand corner
01384         Fl_Window *win;                 // Window widget
01385 
01386         win    = (Fl_Window *)(windows[winpage]->o);
01387         pixels = windows[winpage]->read_image(w, h);
01388 
01389         // Figure out the window size, first at 100 PPI and then scaled
01390         // down if that is too big...
01391         ww = w * 72.0 / 100.0;
01392         hh = h * 72.0 / 100.0;
01393 
01394         if (ww > (right - left)) {
01395           ww = right - left;
01396           hh = h * ww / w;
01397         }
01398 
01399         if (hh > (top - bottom - 36)) {
01400           hh = top - bottom;
01401           ww = w * hh / h;
01402         }
01403 
01404         border = ww / w;
01405 
01406         // Position the window in the center...
01407         llx = 0.5 * (right - left - ww);
01408         lly = 0.5 * (top - bottom - hh);
01409         urx = 0.5 * (right - left + ww);
01410         ury = 0.5 * (top - bottom + hh);
01411 
01412         // Draw a simulated window border...
01413         fprintf(outfile,
01414                 "0.75 setgray\n"                        // Gray background
01415                 "newpath %.2f %.2f %.2f 180 90 arcn\n"  // Top left
01416                 "%.2f %.2f %.2f 90 0 arcn\n"            // Top right
01417                 "%.2f %.2f %.2f 0 -90 arcn\n"           // Bottom right
01418                 "%.2f %.2f %.2f -90 -180 arcn\n"        // Bottom left
01419                 "closepath gsave fill grestore\n"       // Fill
01420                 "0 setlinewidth 0 setgray stroke\n",    // Outline
01421                 llx, ury + 12 * border, 4 * border,
01422                 urx, ury + 12 * border, 4 * border,
01423                 urx, lly, 4 * border,
01424                 llx, lly, 4 * border);
01425 
01426         // Title bar...
01427         if (output_mode & 2) {
01428           fputs("0.25 setgray\n", outfile);
01429         } else {
01430           fputs("0.1 0.2 0.6 setrgbcolor\n", outfile);
01431         }
01432 
01433         fprintf(outfile, "%.2f %.2f %.2f %.2f rectfill\n",
01434                 llx + 12 * border, ury,
01435                 ww - (24 + 16 * (!win->modal() || win->resizable()) +
01436                       16 * (!win->modal() && win->resizable())) * border,
01437                 16 * border);
01438 
01439         if (win->resizable()) {
01440           fprintf(outfile,
01441                   "%.2f %.2f %.2f -90 -180 arcn\n"      // Bottom left
01442                   "0 %.2f rlineto %.2f 0 rlineto 0 -%.2f rlineto closepath fill\n"
01443                   "%.2f %.2f %.2f 0 -90 arcn\n" // Bottom right
01444                   "-%.2f 0 rlineto 0 %.2f rlineto %.2f 0 rlineto closepath fill\n",
01445                   llx, lly, 4 * border,
01446                   12 * border, 16 * border, 16 * border,
01447                   urx, lly, 4 * border,
01448                   12 * border, 16 * border, 16 * border);
01449         }
01450 
01451         // Inside outline and button shading...
01452         fprintf(outfile,
01453                 "%.2f setlinewidth 0.5 setgray\n"
01454                 "%.2f %.2f %.2f %.2f rectstroke\n"
01455                 "%.2f %.2f moveto 0 %.2f rlineto\n"
01456                 "%.2f %.2f moveto 0 %.2f rlineto\n",
01457                 border,
01458                 llx - 0.5 * border, lly - 0.5 * border, ww + border, hh + border,
01459                 llx + 12 * border, ury, 16 * border,
01460                 urx - 12 * border, ury, 16 * border);
01461 
01462         if (!win->modal() || win->resizable()) {
01463           fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n",
01464                   urx - 28 * border, ury, 16 * border);
01465         }
01466 
01467         if (!win->modal() && win->resizable()) {
01468           fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n",
01469                   urx - 44 * border, ury, 16 * border);
01470         }
01471 
01472         fprintf(outfile, "%.2f %.2f moveto %.2f 0 rlineto stroke\n",
01473                 llx - 3.5 * border, ury + 0.5 * border, ww + 7 * border);
01474 
01475         // Button icons...
01476         fprintf(outfile,
01477                 "%.2f setlinewidth 0 setgray\n"
01478                 "%.2f %.2f moveto %.2f -%.2f rlineto %.2f %.2f rlineto\n"
01479                 "%.2f %.2f moveto -%.2f -%.2f rlineto 0 %.2f rmoveto %.2f -%.2f rlineto\n",
01480                 2 * border,
01481                 llx, ury + 10 * border, 4 * border, 4 * border, 4 * border, 4 * border,
01482                 urx, ury + 12 * border, 8 * border, 8 * border, 8 * border, 8 * border, 8 * border);
01483 
01484         float x = urx - 16 * border;
01485 
01486         if (win->resizable()) {
01487           // Maximize button
01488           fprintf(outfile,
01489                   "%.2f %.2f moveto -%.2f 0 rlineto 0 -%.2f rlineto "
01490                   "%.2f 0 rlineto 0 %.2f rlineto\n",
01491                   x, ury + 12 * border, 8 * border, 8 * border,
01492                   8 * border, 8 * border);
01493 
01494           x -= 16 * border;
01495         }
01496 
01497         if (!win->modal()) {
01498           // Minimize button
01499           fprintf(outfile,
01500                   "%.2f %.2f moveto -%.2f 0 rlineto\n",
01501                   x, ury + 4 * border, 8 * border);
01502         }
01503 
01504         fputs("stroke\n", outfile);
01505 
01506         if (win->label()) {
01507           // Add window title...
01508           fprintf(outfile,
01509                   "1 setgray\n"
01510                   "/Helvetica-Bold findfont %.2f scalefont setfont\n"
01511                   "(%s) %.2f %.2f moveto show\n",
01512                   12 * border,
01513                   ps_string(win->label()), llx + 16 * border, ury + 4 * border);
01514         }
01515 
01516         fprintf(outfile,
01517                 "gsave\n"
01518                 "%.2f %.2f translate %.2f %.2f scale\n",
01519                 llx, ury - border, border, border);
01520 
01521         if (output_mode & 2) {
01522           // Grayscale image...
01523           fprintf(outfile,
01524                   "/imgdata %d string def\n"
01525                   "%d %d 8[1 0 0 -1 0 1] "
01526                   "{currentfile imgdata readhexstring pop} image\n",
01527                   w,
01528                   w, h);
01529 
01530           uchar *ptr = pixels;
01531           int i, count = w * h;
01532 
01533           for (i = 0; i < count; i ++, ptr += 3) {
01534             fprintf(outfile, "%02X",
01535                     (31 * ptr[0] + 61 * ptr[1] + 8 * ptr[2]) / 100);
01536             if (!(i % 40)) putc('\n', outfile);
01537           }
01538         } else {
01539           // Color image...
01540           fprintf(outfile,
01541                   "/imgdata %d string def\n"
01542                   "%d %d 8[1 0 0 -1 0 1] "
01543                   "{currentfile imgdata readhexstring pop} false 3 colorimage\n",
01544                   w * 3,
01545                   w, h);
01546 
01547           uchar *ptr = pixels;
01548           int i, count = w * h;
01549 
01550           for (i = 0; i < count; i ++, ptr += 3) {
01551             fprintf(outfile, "%02X%02X%02X", ptr[0], ptr[1], ptr[2]);
01552             if (!(i % 13)) putc('\n', outfile);
01553           }
01554         }
01555 
01556         fputs("\ngrestore\n", outfile);
01557 
01558         delete[] pixels;
01559 
01560         // Show the page...
01561         fputs("grestore showpage\n", outfile);
01562       }
01563     }
01564 
01565     // Finish up...
01566     fputs("%%EOF\n", outfile);
01567 
01568     if (print_choice->value()) pclose(outfile);
01569     else fclose(outfile);
01570   } else {
01571     // Unable to print...
01572     fl_alert("Error printing: %s", strerror(errno));
01573   }
01574 
01575   // Hide progress, activate controls, hide print panel...
01576   print_panel_controls->activate();
01577   print_progress->hide();
01578   print_panel->hide();
01579 }
01580 #endif // WIN32 && !__CYGWIN__
01581 
01583 
01584 extern Fl_Menu_Item New_Menu[];
01585 
01586 void toggle_widgetbin_cb(Fl_Widget *, void *);
01587 void toggle_sourceview_cb(Fl_Double_Window *, void *);
01588 
01589 Fl_Menu_Item Main_Menu[] = {
01590 {"&File",0,0,0,FL_SUBMENU},
01591   {"&New...", FL_COMMAND+'n', new_cb, 0},
01592   {"&Open...", FL_COMMAND+'o', open_cb, 0},
01593   {"&Insert...", FL_COMMAND+'i', open_cb, (void*)1, FL_MENU_DIVIDER},
01594   {"&Save", FL_COMMAND+'s', save_cb, 0},
01595   {"Save &As...", FL_COMMAND+FL_SHIFT+'s', save_cb, (void*)1},
01596   {"Sa&ve A Copy...", 0, save_cb, (void*)2},
01597   {"Save &Template...", 0, save_template_cb},
01598   {"&Revert...", 0, revert_cb, 0, FL_MENU_DIVIDER},
01599   {"&Print...", FL_COMMAND+'p', print_menu_cb},
01600   {"Write &Code...", FL_COMMAND+FL_SHIFT+'c', write_cb, 0},
01601   {"&Write Strings...", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, 0, FL_MENU_DIVIDER},
01602   {relative_history[0], FL_COMMAND+'0', open_history_cb, absolute_history[0]},
01603   {relative_history[1], FL_COMMAND+'1', open_history_cb, absolute_history[1]},
01604   {relative_history[2], FL_COMMAND+'2', open_history_cb, absolute_history[2]},
01605   {relative_history[3], FL_COMMAND+'3', open_history_cb, absolute_history[3]},
01606   {relative_history[4], FL_COMMAND+'4', open_history_cb, absolute_history[4]},
01607   {relative_history[5], FL_COMMAND+'5', open_history_cb, absolute_history[5]},
01608   {relative_history[6], FL_COMMAND+'6', open_history_cb, absolute_history[6]},
01609   {relative_history[7], FL_COMMAND+'7', open_history_cb, absolute_history[7]},
01610   {relative_history[8], FL_COMMAND+'8', open_history_cb, absolute_history[8]},
01611   {relative_history[9], FL_COMMAND+'9', open_history_cb, absolute_history[9], FL_MENU_DIVIDER},
01612   {"&Quit", FL_COMMAND+'q', exit_cb},
01613   {0},
01614 {"&Edit",0,0,0,FL_SUBMENU},
01615   {"&Undo", FL_COMMAND+'z', undo_cb},
01616   {"&Redo", FL_COMMAND+FL_SHIFT+'z', redo_cb, 0, FL_MENU_DIVIDER},
01617   {"C&ut", FL_COMMAND+'x', cut_cb},
01618   {"&Copy", FL_COMMAND+'c', copy_cb},
01619   {"&Paste", FL_COMMAND+'v', paste_cb},
01620   {"Dup&licate", FL_COMMAND+'u', duplicate_cb},
01621   {"&Delete", FL_Delete, delete_cb, 0, FL_MENU_DIVIDER},
01622   {"Select &All", FL_COMMAND+'a', select_all_cb},
01623   {"Select &None", FL_COMMAND+FL_SHIFT+'a', select_none_cb, 0, FL_MENU_DIVIDER},
01624   {"Pr&operties...", FL_F+1, openwidget_cb},
01625   {"&Sort",0,sort_cb},
01626   {"&Earlier", FL_F+2, earlier_cb},
01627   {"&Later", FL_F+3, later_cb},
01628   {"&Group", FL_F+7, group_cb},
01629   {"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER},
01630   {"Hide O&verlays",FL_COMMAND+FL_SHIFT+'o',toggle_overlays},
01631   {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb},
01632   {"Show Source Code...",FL_ALT+FL_SHIFT+'s', (Fl_Callback*)toggle_sourceview_cb, 0, FL_MENU_DIVIDER},
01633   {"Pro&ject Settings...",FL_ALT+'p',show_project_cb},
01634   {"GU&I Settings...",FL_ALT+FL_SHIFT+'p',show_settings_cb,0,FL_MENU_DIVIDER},
01635   {"Global &FLTK Settings...",FL_ALT+FL_SHIFT+'g',show_global_settings_cb},
01636   {0},
01637 {"&New", 0, 0, (void *)New_Menu, FL_SUBMENU_POINTER},
01638 {"&Layout",0,0,0,FL_SUBMENU},
01639   {"&Align",0,0,0,FL_SUBMENU},
01640     {"&Left",0,(Fl_Callback *)align_widget_cb,(void*)10},
01641     {"&Center",0,(Fl_Callback *)align_widget_cb,(void*)11},
01642     {"&Right",0,(Fl_Callback *)align_widget_cb,(void*)12},
01643     {"&Top",0,(Fl_Callback *)align_widget_cb,(void*)13},
01644     {"&Middle",0,(Fl_Callback *)align_widget_cb,(void*)14},
01645     {"&Bottom",0,(Fl_Callback *)align_widget_cb,(void*)15},
01646     {0},
01647   {"&Space Evenly",0,0,0,FL_SUBMENU},
01648     {"&Across",0,(Fl_Callback *)align_widget_cb,(void*)20},
01649     {"&Down",0,(Fl_Callback *)align_widget_cb,(void*)21},
01650     {0},
01651   {"&Make Same Size",0,0,0,FL_SUBMENU},
01652     {"&Width",0,(Fl_Callback *)align_widget_cb,(void*)30},
01653     {"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31},
01654     {"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32},
01655     {0},
01656   {"&Center In Group",0,0,0,FL_SUBMENU},
01657     {"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40},
01658     {"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41},
01659     {0},
01660   {"Set &Widget Size",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER},
01661     {"&Tiny",FL_ALT+'1',(Fl_Callback *)widget_size_cb,(void*)8,0,FL_NORMAL_LABEL,FL_HELVETICA,8},
01662     {"&Small",FL_ALT+'2',(Fl_Callback *)widget_size_cb,(void*)11,0,FL_NORMAL_LABEL,FL_HELVETICA,11},
01663     {"&Normal",FL_ALT+'3',(Fl_Callback *)widget_size_cb,(void*)14,0,FL_NORMAL_LABEL,FL_HELVETICA,14},
01664     {"&Medium",FL_ALT+'4',(Fl_Callback *)widget_size_cb,(void*)18,0,FL_NORMAL_LABEL,FL_HELVETICA,18},
01665     {"&Large",FL_ALT+'5',(Fl_Callback *)widget_size_cb,(void*)24,0,FL_NORMAL_LABEL,FL_HELVETICA,24},
01666     {"&Huge",FL_ALT+'6',(Fl_Callback *)widget_size_cb,(void*)32,0,FL_NORMAL_LABEL,FL_HELVETICA,32},
01667     {0},
01668   {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb},
01669   {0},
01670 {"&Shell",0,0,0,FL_SUBMENU},
01671   {"Execute &Command...",FL_ALT+'x',(Fl_Callback *)show_shell_window},
01672   {"Execute &Again...",FL_ALT+'g',(Fl_Callback *)do_shell_command},
01673   {0},
01674 {"&Help",0,0,0,FL_SUBMENU},
01675   {"&Rapid development with FLUID...",0,help_cb},
01676   {"&FLTK Programmers Manual...",0,manual_cb, 0, FL_MENU_DIVIDER},
01677   {"&About FLUID...",0,about_cb},
01678   {0},
01679 {0}};
01680 
01681 #define BROWSERWIDTH 300
01682 #define BROWSERHEIGHT 500
01683 #define WINWIDTH 300
01684 #define MENUHEIGHT 25
01685 #define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT)
01686 
01687 extern void fill_in_New_Menu();
01688 
01689 void scheme_cb(Fl_Choice *, void *) {
01690   if (compile_only)
01691     return;
01692 
01693   switch (scheme_choice->value()) {
01694     case 0 : // Default
01695       Fl::scheme(NULL);
01696       break;
01697     case 1 : // None
01698       Fl::scheme("none");
01699       break;
01700     case 2 : // Plastic
01701       Fl::scheme("plastic");
01702       break;
01703     case 3 : // GTK+
01704       Fl::scheme("gtk+");
01705       break;
01706   }
01707 
01708   fluid_prefs.set("scheme", scheme_choice->value());
01709 }
01710 
01711 void toggle_widgetbin_cb(Fl_Widget *, void *) {
01712   if (!widgetbin_panel) {
01713     make_widgetbin();
01714     if (!position_window(widgetbin_panel,"widgetbin_pos", 1, 320, 30)) return;
01715   }
01716 
01717   if (widgetbin_panel->visible()) {
01718     widgetbin_panel->hide();
01719     widgetbin_item->label("Show Widget &Bin...");
01720   } else {
01721     widgetbin_panel->show();
01722     widgetbin_item->label("Hide Widget &Bin");
01723   }
01724 }
01725 
01726 
01727 void toggle_sourceview_cb(Fl_Double_Window *, void *) {
01728   if (!sourceview_panel) {
01729     make_sourceview();
01730     sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb);
01731     Fl_Preferences svp(fluid_prefs, "sourceview");
01732     int autorefresh;
01733     svp.get("autorefresh", autorefresh, 1);
01734     sv_autorefresh->value(autorefresh);
01735     int autoposition;
01736     svp.get("autoposition", autoposition, 1);
01737     sv_autoposition->value(autoposition);
01738     int tab;
01739     svp.get("tab", tab, 0);
01740     if (tab>=0 && tab<sv_tab->children()) sv_tab->value(sv_tab->child(tab));
01741     if (!position_window(sourceview_panel,"sourceview_pos", 0, 320, 120, 550, 500)) return;
01742   }
01743 
01744   if (sourceview_panel->visible()) {
01745     sourceview_panel->hide();
01746     sourceview_item->label("Show Source Code...");
01747   } else {
01748     sourceview_panel->show();
01749     sourceview_item->label("Hide Source Code...");
01750     update_sourceview_cb(0,0);
01751   }
01752 }
01753 
01754 void toggle_sourceview_b_cb(Fl_Button*, void *) {
01755   toggle_sourceview_cb(0,0);
01756 }
01757 
01758 void make_main_window() {
01759   if (!compile_only) {
01760     fluid_prefs.get("snap", snap, 1);
01761     fluid_prefs.get("gridx", gridx, 5);
01762     fluid_prefs.get("gridy", gridy, 5);
01763     fluid_prefs.get("show_guides", show_guides, 0);
01764     fluid_prefs.get("widget_size", Fl_Widget_Type::default_size, 14);
01765     fluid_prefs.get("show_comments", show_comments, 1);
01766     make_layout_window();
01767     make_shell_window();
01768   }
01769 
01770   if (!main_window) {
01771     Fl_Widget *o;
01772     main_window = new Fl_Double_Window(WINWIDTH,WINHEIGHT,"fluid");
01773     main_window->box(FL_NO_BOX);
01774     o = make_widget_browser(0,MENUHEIGHT,BROWSERWIDTH,BROWSERHEIGHT);
01775     o->box(FL_FLAT_BOX);
01776     o->tooltip("Double-click to view or change an item.");
01777     main_window->resizable(o);
01778     main_menubar = new Fl_Menu_Bar(0,0,BROWSERWIDTH,MENUHEIGHT);
01779     main_menubar->menu(Main_Menu);
01780     // quick access to all dynamic menu items
01781     save_item = (Fl_Menu_Item*)main_menubar->find_item(save_cb);
01782     history_item = (Fl_Menu_Item*)main_menubar->find_item(open_history_cb);
01783     widgetbin_item = (Fl_Menu_Item*)main_menubar->find_item(toggle_widgetbin_cb);
01784     sourceview_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_sourceview_cb);
01785     main_menubar->global();
01786     fill_in_New_Menu();
01787     main_window->end();
01788   }
01789 
01790   if (!compile_only) {
01791     load_history();
01792     make_settings_window();
01793     make_global_settings_window();
01794   }
01795 }
01796 
01797 // Load file history from preferences...
01798 void load_history() {
01799   int   i;              // Looping var
01800   int   max_files;
01801 
01802 
01803   fluid_prefs.get("recent_files", max_files, 5);
01804   if (max_files > 10) max_files = 10;
01805 
01806   for (i = 0; i < max_files; i ++) {
01807     fluid_prefs.get( Fl_Preferences::Name("file%d", i), absolute_history[i], "", sizeof(absolute_history[i]));
01808     if (absolute_history[i][0]) {
01809       // Make a relative version of the filename for the menu...
01810       fl_filename_relative(relative_history[i], sizeof(relative_history[i]),
01811                            absolute_history[i]);
01812 
01813       if (i == 9) history_item[i].flags = FL_MENU_DIVIDER;
01814       else history_item[i].flags = 0;
01815     } else break;
01816   }
01817 
01818   for (; i < 10; i ++) {
01819     if (i) history_item[i-1].flags |= FL_MENU_DIVIDER;
01820     history_item[i].hide();
01821   }
01822 }
01823 
01824 // Update file history from preferences...
01825 void update_history(const char *flname) {
01826   int   i;              // Looping var
01827   char  absolute[FL_PATH_MAX];
01828   int   max_files;
01829 
01830 
01831   fluid_prefs.get("recent_files", max_files, 5);
01832   if (max_files > 10) max_files = 10;
01833 
01834   fl_filename_absolute(absolute, sizeof(absolute), flname);
01835 
01836   for (i = 0; i < max_files; i ++)
01837 #if defined(WIN32) || defined(__APPLE__)
01838     if (!strcasecmp(absolute, absolute_history[i])) break;
01839 #else
01840     if (!strcmp(absolute, absolute_history[i])) break;
01841 #endif // WIN32 || __APPLE__
01842 
01843   if (i == 0) return;
01844 
01845   if (i >= max_files) i = max_files - 1;
01846 
01847   // Move the other flnames down in the list...
01848   memmove(absolute_history + 1, absolute_history,
01849           i * sizeof(absolute_history[0]));
01850   memmove(relative_history + 1, relative_history,
01851           i * sizeof(relative_history[0]));
01852 
01853   // Put the new file at the top...
01854   strlcpy(absolute_history[0], absolute, sizeof(absolute_history[0]));
01855 
01856   fl_filename_relative(relative_history[0], sizeof(relative_history[0]),
01857                        absolute_history[0]);
01858 
01859   // Update the menu items as needed...
01860   for (i = 0; i < max_files; i ++) {
01861     fluid_prefs.set( Fl_Preferences::Name("file%d", i), absolute_history[i]);
01862     if (absolute_history[i][0]) {
01863       if (i == 9) history_item[i].flags = FL_MENU_DIVIDER;
01864       else history_item[i].flags = 0;
01865     } else break;
01866   }
01867 
01868   for (; i < 10; i ++) {
01869     fluid_prefs.set( Fl_Preferences::Name("file%d", i), "");
01870     if (i) history_item[i-1].flags |= FL_MENU_DIVIDER;
01871     history_item[i].hide();
01872   }
01873 }
01874 
01875 // ********** portable process class definition **********
01876 
01877 class Fl_Process {
01878 public:
01879   // construction / destruction
01880   Fl_Process() {_fpt= NULL;}
01881   ~Fl_Process() {if (_fpt) close();}
01882 
01883   // FIXME: popen needs the utf8 equivalen fl_popen
01884   FILE * popen  (const char *cmd, const char *mode="r");
01885   //not necessary here: FILE * fl_fopen (const char *file, const char *mode="r");
01886   int  close();
01887 
01888   FILE * desc() const { return _fpt;} // non null if file is open
01889   char * get_line(char * line, size_t s) const {return _fpt ? fgets(line, s, _fpt) : NULL;}
01890 
01891 #if defined(WIN32)  && !defined(__CYGWIN__)
01892 protected:
01893   HANDLE pin[2], pout[2], perr[2];
01894   char ptmode;
01895   PROCESS_INFORMATION pi;
01896   STARTUPINFO si;
01897 
01898   static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE);
01899 
01900 private:
01901   FILE * freeHandles()  {
01902     clean_close(pin[0]);    clean_close(pin[1]);
01903     clean_close(pout[0]);   clean_close(pout[1]);
01904     clean_close(perr[0]);   clean_close(perr[1]);
01905     return NULL; // convenient for error management
01906   }
01907   static void clean_close(HANDLE& h);
01908 #endif
01909 
01910 protected:
01911   FILE * _fpt;
01912 };
01913 
01914 #if defined(WIN32)  && !defined(__CYGWIN__)
01915 bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) {
01916   SECURITY_ATTRIBUTES sa;
01917   sa.nLength = sizeof(sa);
01918   sa.lpSecurityDescriptor = NULL;
01919   sa.bInheritHandle = bInheritHnd;
01920   return CreatePipe (&h[0],&h[1],&sa,0) ? true : false;
01921 }
01922 #endif
01923 // portable open process:
01924 FILE * Fl_Process::popen(const char *cmd, const char *mode) {
01925 #if defined(WIN32)  && !defined(__CYGWIN__)
01926   // PRECONDITIONS
01927   if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL;
01928   if (_fpt) close(); // close first before reuse
01929 
01930   ptmode = *mode;
01931   pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE;
01932   // stderr to stdout wanted ?
01933   int fusion = (strstr(cmd,"2>&1") !=NULL);
01934 
01935   // Create windows pipes
01936   if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) )
01937         return freeHandles(); // error
01938 
01939   // Initialize Startup Info
01940   ZeroMemory(&si, sizeof(STARTUPINFO));
01941   si.cb           = sizeof(STARTUPINFO);
01942   si.dwFlags    = STARTF_USESTDHANDLES;
01943   si.hStdInput    = pin[0];
01944   si.hStdOutput   = pout[1];
01945   si.hStdError  = fusion ? pout[1] : perr [1];
01946 
01947   if ( CreateProcess(NULL, (LPTSTR) cmd,NULL,NULL,TRUE,
01948                      DETACHED_PROCESS,NULL,NULL, &si, &pi)) {
01949     // don't need theses handles inherited by child process:
01950     clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]);
01951     HANDLE & h = *mode == 'r' ? pout[0] : pin[1];
01952     _fpt = _fdopen(_open_osfhandle((fl_intptr_t) h,_O_BINARY),mode);
01953     h= INVALID_HANDLE_VALUE;  // reset the handle pointer that is shared
01954     // with _fpt so we don't free it twice
01955   }
01956 
01957   if (!_fpt)  freeHandles();
01958   return _fpt;
01959 #else
01960   _fpt=::popen(cmd,mode);
01961   return _fpt;
01962 #endif
01963 }
01964 
01965 int Fl_Process::close() {
01966 #if defined(WIN32)  && !defined(__CYGWIN__)
01967   if (_fpt) {
01968     fclose(_fpt);
01969     clean_close(perr[0]);
01970     clean_close(pin[1]);
01971     clean_close(pout[0]);
01972     _fpt = NULL;
01973     return 0;
01974   }
01975   return -1;
01976 #else
01977   int ret = ::pclose(_fpt);
01978   _fpt=NULL;
01979   return ret;
01980 #endif
01981 }
01982 
01983 #if defined(WIN32)  && !defined(__CYGWIN__)
01984 void Fl_Process::clean_close(HANDLE& h) {
01985   if (h!= INVALID_HANDLE_VALUE) CloseHandle(h);
01986   h = INVALID_HANDLE_VALUE;
01987 }
01988 #endif
01989 // ********** Fl_Process class end **********
01990 
01991 static Fl_Process s_proc;
01992 
01993 // Shell command support...
01994 
01995 static bool prepare_shell_command(const char * &command)  { // common pre-shell command code all platforms
01996   shell_window->hide();
01997   if (s_proc.desc()) {
01998     fl_alert("Previous shell command still running!");
01999     return false;
02000   }
02001   if ((command = shell_command_input->value()) == NULL || !*command) {
02002     fl_alert("No shell command entered!");
02003     return false;
02004   }
02005   if (shell_savefl_button->value()) {
02006     save_cb(0, 0);
02007   }
02008   if (shell_writecode_button->value()) {
02009     compile_only = 1;
02010     write_cb(0, 0);
02011     compile_only = 0;
02012   }
02013   if (shell_writemsgs_button->value()) {
02014     compile_only = 1;
02015     write_strings_cb(0, 0);
02016     compile_only = 0;
02017   }
02018   return true;
02019 }
02020 
02021 #if !defined(__MWERKS__)
02022 // Support the full piped shell command...
02023 void
02024 shell_pipe_cb(int, void*) {
02025   char  line[1024]="";          // Line from command output...
02026 
02027   if (s_proc.get_line(line, sizeof(line)) != NULL) {
02028     // Add the line to the output list...
02029     shell_run_buffer->append(line);
02030   } else {
02031     // End of file; tell the parent...
02032     Fl::remove_fd(fileno(s_proc.desc()));
02033     s_proc.close();
02034     shell_run_buffer->append("... END SHELL COMMAND ...\n");
02035   }
02036 
02037   shell_run_display->scroll(shell_run_display->count_lines(0,
02038                             shell_run_buffer->length(), 1), 0);
02039 }
02040 
02041 void
02042 do_shell_command(Fl_Return_Button*, void*) {
02043   const char    *command=NULL;  // Command to run
02044 
02045   if (!prepare_shell_command(command)) return;
02046 
02047   // Show the output window and clear things...
02048   shell_run_buffer->text("");
02049   shell_run_buffer->append(command);
02050   shell_run_buffer->append("\n");
02051   shell_run_window->label("Shell Command Running...");
02052 
02053   if (s_proc.popen((char *)command) == NULL) {
02054     fl_alert("Unable to run shell command: %s", strerror(errno));
02055     return;
02056   }
02057 
02058   shell_run_button->deactivate();
02059   shell_run_window->hotspot(shell_run_display);
02060   shell_run_window->show();
02061 
02062   Fl::add_fd(fileno(s_proc.desc()), shell_pipe_cb);
02063 
02064   while (s_proc.desc()) Fl::wait();
02065 
02066   shell_run_button->activate();
02067   shell_run_window->label("Shell Command Complete");
02068   fl_beep();
02069 
02070   while (shell_run_window->shown()) Fl::wait();
02071 }
02072 #else
02073 // Just do basic shell command stuff, no status window...
02074 void
02075 do_shell_command(Fl_Return_Button*, void*) {
02076   const char    *command;       // Command to run
02077   int           status;         // Status from command...
02078 
02079   if (!prepare_shell_command(command)) return;
02080 
02081   if ((status = system(command)) != 0) {
02082     fl_alert("Shell command returned status %d!", status);
02083   } else if (completion_button->value()) {
02084     fl_message("Shell command completed successfully!");
02085   }
02086 }
02087 #endif // !__MWERKS__
02088 
02089 void
02090 show_shell_window() {
02091   shell_window->hotspot(shell_command_input);
02092   shell_window->show();
02093 }
02094 
02095 void set_filename(const char *c) {
02096   if (filename) free((void *)filename);
02097   filename = c ? strdup(c) : NULL;
02098 
02099   if (filename) update_history(filename);
02100 
02101   set_modflag(modflag);
02102 }
02103 
02104 //
02105 // The Source View system offers an immediate preview of the code
02106 // files that will be generated by FLUID. It also marks the code
02107 // generated for the last selected item in the header and the source
02108 // file.
02109 //
02110 // Can we patent this?  ;-)  - Matt, mm@matthiasm.com
02111 //
02112 
02113 //
02114 // Update the header and source code highlighting depending on the
02115 // currently selected object
02116 //
02117 void update_sourceview_position()
02118 {
02119   if (!sourceview_panel || !sourceview_panel->visible())
02120     return;
02121   if (sv_autoposition->value()==0)
02122     return;
02123   if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) {
02124     int pos0, pos1;
02125     if (sv_source->visible_r()) {
02126       pos0 = Fl_Type::current->code_position;
02127       pos1 = Fl_Type::current->code_position_end;
02128       if (pos0>=0) {
02129         if (pos1<pos0)
02130           pos1 = pos0;
02131         sv_source->buffer()->highlight(pos0, pos1);
02132         int line = sv_source->buffer()->count_lines(0, pos0);
02133         sv_source->scroll(line, 0);
02134       }
02135     }
02136     if (sv_header->visible_r()) {
02137       pos0 = Fl_Type::current->header_position;
02138       pos1 = Fl_Type::current->header_position_end;
02139       if (pos0>=0) {
02140         if (pos1<pos0)
02141           pos1 = pos0;
02142         sv_header->buffer()->highlight(pos0, pos1);
02143         int line = sv_header->buffer()->count_lines(0, pos0);
02144         sv_header->scroll(line, 0);
02145       }
02146     }
02147   }
02148 }
02149 
02150 void update_sourceview_position_cb(Fl_Tabs*, void*)
02151 {
02152   update_sourceview_position();
02153 }
02154 
02155 static char *sv_source_filename = 0;
02156 static char *sv_header_filename = 0;
02157 
02158 //
02159 // Generate a header and source file in a temporary directory and
02160 // load those into the Code Viewer widgets.
02161 //
02162 void update_sourceview_cb(Fl_Button*, void*)
02163 {
02164   if (!sourceview_panel || !sourceview_panel->visible())
02165     return;
02166   // generate space for the source and header file filenames
02167   if (!sv_source_filename) {
02168     sv_source_filename = (char*)malloc(FL_PATH_MAX);
02169     fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX);
02170     strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX);
02171   }
02172   if (!sv_header_filename) {
02173     sv_header_filename = (char*)malloc(FL_PATH_MAX);
02174     fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX);
02175     strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX);
02176   }
02177 
02178   strlcpy(i18n_program, fl_filename_name(sv_source_filename), sizeof(i18n_program));
02179   fl_filename_setext(i18n_program, sizeof(i18n_program), "");
02180   const char *code_file_name_bak = code_file_name;
02181   code_file_name = sv_source_filename;
02182   const char *header_file_name_bak = header_file_name;
02183   header_file_name = sv_header_filename;
02184 
02185   // generate the code and load the files
02186   write_sourceview = 1;
02187   // generate files
02188   if (write_code(sv_source_filename, sv_header_filename))
02189   {
02190     // load file into source editor
02191     int pos = sv_source->top_line();
02192     sv_source->buffer()->loadfile(sv_source_filename);
02193     sv_source->scroll(pos, 0);
02194     // load file into header editor
02195     pos = sv_header->top_line();
02196     sv_header->buffer()->loadfile(sv_header_filename);
02197     sv_header->scroll(pos, 0);
02198     // update the source code highlighting
02199     update_sourceview_position();
02200   }
02201   write_sourceview = 0;
02202 
02203   code_file_name = code_file_name_bak;
02204   header_file_name = header_file_name_bak;
02205 }
02206 
02207 void update_sourceview_timer(void*)
02208 {
02209   update_sourceview_cb(0,0);
02210 }
02211 
02212 // Set the "modified" flag and update the title of the main window...
02213 void set_modflag(int mf) {
02214   const char    *basename;
02215   static char   title[FL_PATH_MAX];
02216 
02217   modflag = mf;
02218 
02219   if (main_window) {
02220     if (!filename) basename = "Untitled.fl";
02221     else if ((basename = strrchr(filename, '/')) != NULL) basename ++;
02222 #if defined(WIN32) || defined(__EMX__)
02223     else if ((basename = strrchr(filename, '\\')) != NULL) basename ++;
02224 #endif // WIN32 || __EMX__
02225     else basename = filename;
02226 
02227     if (modflag) {
02228       snprintf(title, sizeof(title), "%s (modified)", basename);
02229       main_window->label(title);
02230     } else main_window->label(basename);
02231   }
02232   // if the UI was modified in any way, update the Source View panel
02233   if (sourceview_panel && sourceview_panel->visible() && sv_autorefresh->value())
02234   {
02235     // we will only update ealiest 0.5 seconds after the last change, and only
02236     // if no other change was made, so dragging a widget will not generate any
02237     // CPU load
02238     Fl::remove_timeout(update_sourceview_timer, 0);
02239     Fl::add_timeout(0.5, update_sourceview_timer, 0);
02240   }
02241 
02242   // Enable/disable the Save menu item...
02243   if (modflag) save_item->activate();
02244   else save_item->deactivate();
02245 }
02246 
02248 
02249 static int arg(int argc, char** argv, int& i) {
02250   if (argv[i][1] == 'c' && !argv[i][2]) {compile_only = 1; i++; return 1;}
02251   if (argv[i][1] == 'c' && argv[i][2] == 's' && !argv[i][3]) {compile_only = 1; compile_strings = 1; i++; return 1;}
02252   if (argv[i][1] == 'o' && !argv[i][2] && i+1 < argc) {
02253     code_file_name = argv[i+1];
02254     code_file_set  = 1;
02255     i += 2;
02256     return 2;
02257   }
02258   if (argv[i][1] == 'h' && !argv[i][2]) {
02259     header_file_name = argv[i+1];
02260     header_file_set  = 1;
02261     i += 2;
02262     return 2;
02263   }
02264   Fl_Plugin_Manager pm("commandline");
02265   int j, n = pm.plugins();
02266   for (j=0; j<n; j++) {
02267     Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(j);
02268     int r = pi->arg(argc, argv, i);
02269     if (r) return r;
02270   }
02271   return 0;
02272 }
02273 
02274 #if ! (defined(WIN32) && !defined (__CYGWIN__))
02275 
02276 int quit_flag = 0;
02277 #include <signal.h>
02278 #ifdef _sigargs
02279 #define SIGARG _sigargs
02280 #else
02281 #ifdef __sigargs
02282 #define SIGARG __sigargs
02283 #else
02284 #define SIGARG int // you may need to fix this for older systems
02285 #endif
02286 #endif
02287 
02288 extern "C" {
02289 static void sigint(SIGARG) {
02290   signal(SIGINT,sigint);
02291   quit_flag = 1;
02292 }
02293 }
02294 #endif
02295 
02296 
02297 int main(int argc,char **argv) {
02298   int i = 1;
02299   
02300   if (!Fl::args(argc,argv,i,arg) || i < argc-1) {
02301     static const char *msg = 
02302       "usage: %s <switches> name.fl\n"
02303       " -c : write .cxx and .h and exit\n"
02304       " -cs : write .cxx and .h and strings and exit\n"
02305       " -o <name> : .cxx output filename, or extension if <name> starts with '.'\n"
02306       " -h <name> : .h output filename, or extension if <name> starts with '.'\n";
02307     int len = strlen(msg) + strlen(argv[0]) + strlen(Fl::help);
02308     Fl_Plugin_Manager pm("commandline");
02309     int i, n = pm.plugins();
02310     for (i=0; i<n; i++) {
02311       Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(i);
02312       if (pi) len += strlen(pi->help());
02313     }
02314     char *buf = (char*)malloc(len+1);
02315     sprintf(buf, msg, argv[0]);
02316     for (i=0; i<n; i++) {
02317       Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(i);
02318       if (pi) strcat(buf, pi->help());
02319     }
02320     strcat(buf, Fl::help);
02321 #ifdef _MSC_VER
02322     fl_message("%s\n", buf);
02323 #else
02324     fprintf(stderr, "%s\n", buf);
02325 #endif
02326     free(buf);
02327     return 1;
02328   }
02329   if (exit_early)
02330     exit(0);
02331   
02332   const char *c = argv[i];
02333 
02334   fl_register_images();
02335 
02336   make_main_window();
02337 
02338 
02339   if (c) set_filename(c);
02340   if (!compile_only) {
02341 #ifdef __APPLE__
02342     fl_open_callback(apple_open_cb);
02343 #endif // __APPLE__
02344     Fl::visual((Fl_Mode)(FL_DOUBLE|FL_INDEX));
02345     Fl_File_Icon::load_system_icons();
02346     main_window->callback(exit_cb);
02347     position_window(main_window,"main_window_pos", 1, 10, 30, WINWIDTH, WINHEIGHT );
02348     main_window->show(argc,argv);
02349     toggle_widgetbin_cb(0,0);
02350     toggle_sourceview_cb(0,0);
02351     if (!c && openlast_button->value() && absolute_history[0][0]) {
02352       // Open previous file when no file specified...
02353       open_history_cb(0, absolute_history[0]);
02354     }
02355   }
02356   undo_suspend();
02357   if (c && !read_file(c,0)) {
02358     if (compile_only) {
02359       fprintf(stderr,"%s : %s\n", c, strerror(errno));
02360       exit(1);
02361     }
02362     fl_message("Can't read %s: %s", c, strerror(errno));
02363   }
02364   undo_resume();
02365   if (compile_only) {
02366     if (compile_strings) write_strings_cb(0,0);
02367     write_cb(0,0);
02368     exit(0);
02369   }
02370   set_modflag(0);
02371   undo_clear();
02372 #ifndef WIN32
02373   signal(SIGINT,sigint);
02374 #endif
02375 
02376   grid_cb(horizontal_input, 0); // Makes sure that windows get snap params...
02377 
02378 #ifdef WIN32
02379   Fl::run();
02380 #else
02381   while (!quit_flag) Fl::wait();
02382 
02383   if (quit_flag) exit_cb(0,0);
02384 #endif // WIN32
02385 
02386   undo_clear();
02387 
02388   return (0);
02389 }
02390 
02391 //
02392 // End of "$Id: fluid.cxx 8202 2011-01-06 21:36:04Z matt $".
02393 //