1 //
2 // "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $"
3 //
4 // FLUID main entry for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 #include <FL/Fl.H>
29 #include <FL/Fl_Double_Window.H>
30 #include <FL/Fl_Box.H>
31 #include <FL/Fl_Button.H>
32 #include <FL/Fl_File_Icon.H>
33 #include <FL/Fl_Help_Dialog.H>
34 #include <FL/Fl_Hold_Browser.H>
35 #include <FL/Fl_Menu_Bar.H>
36 #include <FL/Fl_Input.H>
37 #include <FL/Fl_Plugin.H>
38 #include <FL/fl_ask.H>
39 #include <FL/fl_draw.H>
40 #include <FL/Fl_File_Chooser.H>
41 #include <FL/Fl_PNG_Image.H>
42 #include <FL/fl_message.H>
43 #include <FL/filename.H>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <errno.h>
47 #include <sys/stat.h>
48 #include <time.h> // time(), localtime(), etc.
49 
50 #include "../src/flstring.h"
51 #include "alignment_panel.h"
52 #include "function_panel.h"
53 #include "template_panel.h"
54 #if !defined(WIN32) || defined(__CYGWIN__)
55 #  include "print_panel.cxx"
56 #endif // !WIN32 || __CYGWIN__
57 
58 #if defined(WIN32) && !defined(__CYGWIN__)
59 #  include <direct.h>
60 #  include <windows.h>
61 #  include <io.h>
62 #  include <fcntl.h>
63 #  include <commdlg.h>
64 #  include <FL/x.H>
65 #  ifndef __WATCOMC__
66 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
67 // on Windows, which is supposed to be POSIX compliant...
68 #    define access _access
69 #    define chdir _chdir
70 #    define getcwd _getcwd
71 #  endif // !__WATCOMC__
72 #else
73 #  include <unistd.h>
74 #endif
75 #ifdef __EMX__
76 #  include <X11/Xlibint.h>
77 #endif
78 
79 #include "about_panel.h"
80 #include "undo.h"
81 
82 #include "Fl_Type.h"
83 
84 extern "C"
85 {
86 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
87 #  include <zlib.h>
88 #  ifdef HAVE_PNG_H
89 #    include <png.h>
90 #  else
91 #    include <libpng/png.h>
92 #  endif // HAVE_PNG_H
93 #endif // HAVE_LIBPNG && HAVE_LIBZ
94 }
95 
96 static Fl_Help_Dialog *help_dialog = 0;
97 
98 Fl_Preferences	fluid_prefs(Fl_Preferences::USER, "fltk.org", "fluid");
99 int gridx = 5;
100 int gridy = 5;
101 int snap = 1;
102 int show_guides = 1;
103 int show_comments = 1;
104 int show_coredevmenus = 1;
105 
106 // File history info...
107 char	absolute_history[10][FL_PATH_MAX];
108 char	relative_history[10][FL_PATH_MAX];
109 
110 void	load_history();
111 void	update_history(const char *);
112 
113 // Shell command support...
114 void	show_shell_window();
115 
116 Fl_Menu_Item *save_item = 0L;
117 Fl_Menu_Item *history_item = 0L;
118 Fl_Menu_Item *widgetbin_item = 0L;
119 Fl_Menu_Item *sourceview_item = 0L;
120 
121 ////////////////////////////////////////////////////////////////
122 
123 static const char *filename;
124 void set_filename(const char *c);
125 void set_modflag(int mf);
126 int modflag;
127 
128 static char* pwd;
129 static char in_source_dir;
goto_source_dir()130 void goto_source_dir() {
131   if (in_source_dir) return;
132   if (!filename || !*filename) return;
133   const char *p = fl_filename_name(filename);
134   if (p <= filename) return; // it is in the current directory
135   char buffer[FL_PATH_MAX];
136   strlcpy(buffer, filename, sizeof(buffer));
137   int n = p-filename; if (n>1) n--; buffer[n] = 0;
138   if (!pwd) {
139     pwd = getcwd(0,FL_PATH_MAX);
140     if (!pwd) {fprintf(stderr,"getwd : %s\n",strerror(errno)); return;}
141   }
142   if (chdir(buffer)<0) {fprintf(stderr, "Can't chdir to %s : %s\n",
143 				buffer, strerror(errno)); return;}
144   in_source_dir = 1;
145 }
146 
leave_source_dir()147 void leave_source_dir() {
148   if (!in_source_dir) return;
149   if (chdir(pwd)<0) {fprintf(stderr, "Can't chdir to %s : %s\n",
150 			     pwd, strerror(errno));}
151   in_source_dir = 0;
152 }
153 
position_window(Fl_Window * w,const char * prefsName,int Visible,int X,int Y,int W=0,int H=0)154 char position_window(Fl_Window *w, const char *prefsName, int Visible, int X, int Y, int W=0, int H=0 ) {
155   Fl_Preferences pos(fluid_prefs, prefsName);
156   if (prevpos_button->value()) {
157     pos.get("x", X, X);
158     pos.get("y", Y, Y);
159     if ( W!=0 ) {
160       pos.get("w", W, W);
161       pos.get("h", H, H);
162       w->resize( X, Y, W, H );
163     }
164     else
165       w->position( X, Y );
166   }
167   pos.get("visible", Visible, Visible);
168   return Visible;
169 }
170 
save_position(Fl_Window * w,const char * prefsName)171 void save_position(Fl_Window *w, const char *prefsName) {
172   Fl_Preferences pos(fluid_prefs, prefsName);
173   pos.set("x", w->x());
174   pos.set("y", w->y());
175   pos.set("w", w->w());
176   pos.set("h", w->h());
177   pos.set("visible", (int)(w->shown() && w->visible()));
178 }
179 
180 Fl_Window *main_window;
181 Fl_Menu_Bar *main_menubar;
182 
cutfname(int which=0)183 static char* cutfname(int which = 0) {
184   static char name[2][FL_PATH_MAX];
185   static char beenhere = 0;
186 
187   if (!beenhere) {
188     beenhere = 1;
189     fluid_prefs.getUserdataPath(name[0], sizeof(name[0]));
190     strlcat(name[0], "cut_buffer", sizeof(name[0]));
191     fluid_prefs.getUserdataPath(name[1], sizeof(name[1]));
192     strlcat(name[1], "dup_buffer", sizeof(name[1]));
193   }
194 
195   return name[which];
196 }
197 
save_cb(Fl_Widget *,void * v)198 void save_cb(Fl_Widget *, void *v) {
199   const char *c = filename;
200   if (v || !c || !*c) {
201     fl_file_chooser_ok_label("Save");
202     c=fl_file_chooser("Save To:", "FLUID Files (*.f[ld])", c);
203     fl_file_chooser_ok_label(NULL);
204     if (!c) return;
205 
206     if (!access(c, 0)) {
207       const char *basename;
208       if ((basename = strrchr(c, '/')) != NULL)
209         basename ++;
210 #if defined(WIN32) || defined(__EMX__)
211       if ((basename = strrchr(c, '\\')) != NULL)
212         basename ++;
213 #endif // WIN32 || __EMX__
214       else
215         basename = c;
216 
217       if (fl_choice("The file \"%s\" already exists.\n"
218                     "Do you want to replace it?", "Cancel",
219 		    "Replace", NULL, basename) == 0) return;
220     }
221 
222     if (v != (void *)2) set_filename(c);
223   }
224   if (!write_file(c)) {
225     fl_alert("Error writing %s: %s", c, strerror(errno));
226     return;
227   }
228 
229   if (v != (void *)2) {
230     set_modflag(0);
231     undo_save = undo_current;
232   }
233 }
234 
save_template_cb(Fl_Widget *,void *)235 void save_template_cb(Fl_Widget *, void *) {
236   // Setup the template panel...
237   if (!template_panel) make_template_panel();
238 
239   template_clear();
240   template_browser->add("New Template");
241   template_load();
242 
243   template_name->show();
244   template_name->value("");
245 
246   template_instance->hide();
247 
248   template_delete->show();
249   template_delete->deactivate();
250 
251   template_submit->label("Save");
252   template_submit->deactivate();
253 
254   template_panel->label("Save Template");
255 
256   // Show the panel and wait for the user to do something...
257   template_panel->show();
258   while (template_panel->shown()) Fl::wait();
259 
260   // Get the template name, return if it is empty...
261   const char *c = template_name->value();
262   if (!c || !*c) return;
263 
264   // Convert template name to filename_with_underscores
265   char safename[FL_PATH_MAX], *safeptr;
266   strlcpy(safename, c, sizeof(safename));
267   for (safeptr = safename; *safeptr; safeptr ++) {
268     if (isspace(*safeptr)) *safeptr = '_';
269   }
270 
271   // Find the templates directory...
272   char filename[FL_PATH_MAX];
273   fluid_prefs.getUserdataPath(filename, sizeof(filename));
274 
275   strlcat(filename, "templates", sizeof(filename));
276 #if defined(WIN32) && !defined(__CYGWIN__)
277   if (access(filename, 0)) mkdir(filename);
278 #else
279   if (access(filename, 0)) mkdir(filename, 0777);
280 #endif // WIN32 && !__CYGWIN__
281 
282   strlcat(filename, "/", sizeof(filename));
283   strlcat(filename, safename, sizeof(filename));
284 
285   char *ext = filename + strlen(filename);
286   if (ext >= (filename + sizeof(filename) - 5)) {
287     fl_alert("The template name \"%s\" is too long!", c);
288     return;
289   }
290 
291   // Save the .fl file...
292   strcpy(ext, ".fl");
293 
294   if (!access(filename, 0)) {
295     if (fl_choice("The template \"%s\" already exists.\n"
296                   "Do you want to replace it?", "Cancel",
297 		  "Replace", NULL, c) == 0) return;
298   }
299 
300   if (!write_file(filename)) {
301     fl_alert("Error writing %s: %s", filename, strerror(errno));
302     return;
303   }
304 
305 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
306   // Get the screenshot, if any...
307   Fl_Type *t;
308 
309   for (t = Fl_Type::first; t; t = t->next) {
310     // Find the first window...
311     if (t->is_window()) break;
312   }
313 
314   if (!t) return;
315 
316   // Grab a screenshot...
317   Fl_Window_Type *wt = (Fl_Window_Type *)t;
318   uchar *pixels;
319   int w, h;
320 
321   if ((pixels = wt->read_image(w, h)) == NULL) return;
322 
323   // Save to a PNG file...
324   strcpy(ext, ".png");
325 
326   FILE *fp;
327 
328   if ((fp = fl_fopen(filename, "wb")) == NULL) {
329     delete[] pixels;
330     fl_alert("Error writing %s: %s", filename, strerror(errno));
331     return;
332   }
333 
334   png_structp pptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
335   png_infop iptr = png_create_info_struct(pptr);
336   png_bytep ptr = (png_bytep)pixels;
337 
338   png_init_io(pptr, fp);
339   png_set_IHDR(pptr, iptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
340                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
341   png_set_sRGB(pptr, iptr, PNG_sRGB_INTENT_PERCEPTUAL);
342 
343   png_write_info(pptr, iptr);
344 
345   for (int i = h; i > 0; i --, ptr += w * 3) {
346     png_write_row(pptr, ptr);
347   }
348 
349   png_write_end(pptr, iptr);
350   png_destroy_write_struct(&pptr, &iptr);
351 
352   fclose(fp);
353 
354 #  if 0 // The original PPM output code...
355   strcpy(ext, ".ppm");
356   fp = fl_fopen(filename, "wb");
357   fprintf(fp, "P6\n%d %d 255\n", w, h);
358   fwrite(pixels, w * h, 3, fp);
359   fclose(fp);
360 #  endif // 0
361 
362   delete[] pixels;
363 #endif // HAVE_LIBPNG && HAVE_LIBZ
364 }
365 
revert_cb(Fl_Widget *,void *)366 void revert_cb(Fl_Widget *,void *) {
367   if (modflag) {
368     if (!fl_choice("This user interface has been changed. Really revert?",
369                    "Cancel", "Revert", NULL)) return;
370   }
371   undo_suspend();
372   if (!read_file(filename, 0)) {
373     undo_resume();
374     fl_message("Can't read %s: %s", filename, strerror(errno));
375     return;
376   }
377   undo_resume();
378   set_modflag(0);
379   undo_clear();
380 }
381 
exit_cb(Fl_Widget *,void *)382 void exit_cb(Fl_Widget *,void *) {
383   if (modflag)
384     switch (fl_choice("Do you want to save changes to this user\n"
385                       "interface before exiting?", "Cancel",
386                       "Save", "Don't Save"))
387     {
388       case 0 : /* Cancel */
389           return;
390       case 1 : /* Save */
391           save_cb(NULL, NULL);
392 	  if (modflag) return;	// Didn't save!
393     }
394 
395   save_position(main_window,"main_window_pos");
396 
397   if (widgetbin_panel) {
398     save_position(widgetbin_panel,"widgetbin_pos");
399     delete widgetbin_panel;
400   }
401   if (sourceview_panel) {
402     Fl_Preferences svp(fluid_prefs, "sourceview");
403     svp.set("autorefresh", sv_autorefresh->value());
404     svp.set("autoposition", sv_autoposition->value());
405     svp.set("tab", sv_tab->find(sv_tab->value()));
406     save_position(sourceview_panel,"sourceview_pos");
407     delete sourceview_panel;
408   }
409   if (about_panel)
410     delete about_panel;
411   if (help_dialog)
412     delete help_dialog;
413 
414   undo_clear();
415 
416   exit(0);
417 }
418 
419 #ifdef __APPLE__
420 #  include <FL/x.H>
421 
422 void
apple_open_cb(const char * c)423 apple_open_cb(const char *c) {
424   if (modflag) {
425     switch (fl_choice("Do you want to save changes to this user\n"
426                       "interface before opening another one?", "Don't Save",
427                       "Save", "Cancel"))
428     {
429       case 0 : /* Cancel */
430           return;
431       case 1 : /* Save */
432           save_cb(NULL, NULL);
433 	  if (modflag) return;	// Didn't save!
434     }
435   }
436   const char *oldfilename;
437   oldfilename = filename;
438   filename    = NULL;
439   set_filename(c);
440   undo_suspend();
441   if (!read_file(c, 0)) {
442     undo_resume();
443     fl_message("Can't read %s: %s", c, strerror(errno));
444     free((void *)filename);
445     filename = oldfilename;
446     if (main_window) main_window->label(filename);
447     return;
448   }
449 
450   // Loaded a file; free the old filename...
451   set_modflag(0);
452   undo_resume();
453   undo_clear();
454   if (oldfilename) free((void *)oldfilename);
455 }
456 #endif // __APPLE__
457 
open_cb(Fl_Widget *,void * v)458 void open_cb(Fl_Widget *, void *v) {
459   if (!v && modflag) {
460     switch (fl_choice("Do you want to save changes to this user\n"
461                       "interface before opening another one?", "Cancel",
462                       "Save", "Don't Save"))
463     {
464       case 0 : /* Cancel */
465           return;
466       case 1 : /* Save */
467           save_cb(NULL, NULL);
468 	  if (modflag) return;	// Didn't save!
469     }
470   }
471   const char *c;
472   const char *oldfilename;
473   fl_file_chooser_ok_label("Open");
474   c = fl_file_chooser("Open:", "FLUID Files (*.f[ld])", filename);
475   fl_file_chooser_ok_label(NULL);
476   if (!c) return;
477   oldfilename = filename;
478   filename    = NULL;
479   set_filename(c);
480   if (v != 0) undo_checkpoint();
481   undo_suspend();
482   if (!read_file(c, v!=0)) {
483     undo_resume();
484     fl_message("Can't read %s: %s", c, strerror(errno));
485     free((void *)filename);
486     filename = oldfilename;
487     if (main_window) set_modflag(modflag);
488     return;
489   }
490   undo_resume();
491   if (v) {
492     // Inserting a file; restore the original filename...
493     free((void *)filename);
494     filename = oldfilename;
495     set_modflag(1);
496   } else {
497     // Loaded a file; free the old filename...
498     set_modflag(0);
499     undo_clear();
500     if (oldfilename) free((void *)oldfilename);
501   }
502 }
503 
open_history_cb(Fl_Widget *,void * v)504 void open_history_cb(Fl_Widget *, void *v) {
505   if (modflag) {
506     switch (fl_choice("Do you want to save changes to this user\n"
507                       "interface before opening another one?", "Cancel",
508                       "Save", "Don't Save"))
509     {
510       case 0 : /* Cancel */
511           return;
512       case 1 : /* Save */
513           save_cb(NULL, NULL);
514 	  if (modflag) return;	// Didn't save!
515     }
516   }
517   const char *oldfilename = filename;
518   filename = NULL;
519   set_filename((char *)v);
520   undo_suspend();
521   if (!read_file(filename, 0)) {
522     undo_resume();
523     undo_clear();
524     fl_message("Can't read %s: %s", filename, strerror(errno));
525     free((void *)filename);
526     filename = oldfilename;
527     if (main_window) main_window->label(filename);
528     return;
529   }
530   set_modflag(0);
531   undo_resume();
532   undo_clear();
533   if (oldfilename) free((void *)oldfilename);
534 }
535 
new_cb(Fl_Widget *,void * v)536 void new_cb(Fl_Widget *, void *v) {
537   // Check if the current file has been modified...
538   if (!v && modflag) {
539     // Yes, ask the user what to do...
540     switch (fl_choice("Do you want to save changes to this user\n"
541                       "interface before creating a new one?", "Cancel",
542                       "Save", "Don't Save"))
543     {
544       case 0 : /* Cancel */
545           return;
546       case 1 : /* Save */
547           save_cb(NULL, NULL);
548 	  if (modflag) return;	// Didn't save!
549     }
550   }
551 
552   // Setup the template panel...
553   if (!template_panel) make_template_panel();
554 
555   template_clear();
556   template_browser->add("Blank");
557   template_load();
558 
559   template_name->hide();
560   template_name->value("");
561 
562   template_instance->show();
563   template_instance->deactivate();
564   template_instance->value("");
565 
566   template_delete->hide();
567 
568   template_submit->label("New");
569   template_submit->deactivate();
570 
571   template_panel->label("New");
572 
573   // Show the panel and wait for the user to do something...
574   template_panel->show();
575   while (template_panel->shown()) Fl::wait();
576 
577   // See if the user chose anything...
578   int item = template_browser->value();
579   if (item < 1) return;
580 
581   // Clear the current data...
582   delete_all();
583   set_filename(NULL);
584 
585   // Load the template, if any...
586   const char *tname = (const char *)template_browser->data(item);
587 
588   if (tname) {
589     // Grab the instance name...
590     const char *iname = template_instance->value();
591 
592     if (iname && *iname) {
593       // Copy the template to a temp file, then read it in...
594       char line[1024], *ptr, *next;
595       FILE *infile, *outfile;
596 
597       if ((infile = fl_fopen(tname, "r")) == NULL) {
598 	fl_alert("Error reading template file \"%s\":\n%s", tname,
599         	 strerror(errno));
600 	set_modflag(0);
601 	undo_clear();
602 	return;
603       }
604 
605       if ((outfile = fl_fopen(cutfname(1), "w")) == NULL) {
606 	fl_alert("Error writing buffer file \"%s\":\n%s", cutfname(1),
607         	 strerror(errno));
608 	fclose(infile);
609 	set_modflag(0);
610 	undo_clear();
611 	return;
612       }
613 
614       while (fgets(line, sizeof(line), infile)) {
615 	// Replace @INSTANCE@ with the instance name...
616 	for (ptr = line; (next = strstr(ptr, "@INSTANCE@")) != NULL; ptr = next + 10) {
617 	  fwrite(ptr, next - ptr, 1, outfile);
618 	  fputs(iname, outfile);
619 	}
620 
621 	fputs(ptr, outfile);
622       }
623 
624       fclose(infile);
625       fclose(outfile);
626 
627       undo_suspend();
628       read_file(cutfname(1), 0);
629       unlink(cutfname(1));
630       undo_resume();
631     } else {
632       // No instance name, so read the template without replacements...
633       undo_suspend();
634       read_file(tname, 0);
635       undo_resume();
636     }
637   }
638 
639   set_modflag(0);
640   undo_clear();
641 }
642 
643 int exit_early = 0;
644 int compile_only = 0;
645 int compile_strings = 0;
646 int header_file_set = 0;
647 int code_file_set = 0;
648 const char* header_file_name = ".h";
649 const char* code_file_name = ".cxx";
650 int i18n_type = 0;
651 const char* i18n_include = "";
652 const char* i18n_function = "";
653 const char* i18n_file = "";
654 const char* i18n_set = "";
655 char i18n_program[FL_PATH_MAX] = "";
656 
write_cb(Fl_Widget *,void *)657 void write_cb(Fl_Widget *, void *) {
658   if (!filename) {
659     save_cb(0,0);
660     if (!filename) return;
661   }
662   char cname[FL_PATH_MAX];
663   char hname[FL_PATH_MAX];
664   strlcpy(i18n_program, fl_filename_name(filename), sizeof(i18n_program));
665   fl_filename_setext(i18n_program, sizeof(i18n_program), "");
666   if (*code_file_name == '.' && strchr(code_file_name, '/') == NULL) {
667     strlcpy(cname, fl_filename_name(filename), sizeof(cname));
668     fl_filename_setext(cname, sizeof(cname), code_file_name);
669   } else {
670     strlcpy(cname, code_file_name, sizeof(hname));
671   }
672   if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) {
673     strlcpy(hname, fl_filename_name(filename), sizeof(hname));
674     fl_filename_setext(hname, sizeof(hname), header_file_name);
675   } else {
676     strlcpy(hname, header_file_name, sizeof(hname));
677   }
678   if (!compile_only) goto_source_dir();
679   int x = write_code(cname,hname);
680   if (!compile_only) leave_source_dir();
681   strlcat(cname, " and ", sizeof(cname));
682   strlcat(cname, hname, sizeof(cname));
683   if (compile_only) {
684     if (!x) {fprintf(stderr,"%s : %s\n",cname,strerror(errno)); exit(1);}
685   } else {
686     if (!x) {
687       fl_message("Can't write %s: %s", cname, strerror(errno));
688     } else if (completion_button->value()) {
689       fl_message("Wrote %s", cname);
690     }
691   }
692 }
693 
write_strings_cb(Fl_Widget *,void *)694 void write_strings_cb(Fl_Widget *, void *) {
695   static const char *exts[] = { ".txt", ".po", ".msg" };
696   if (!filename) {
697     save_cb(0,0);
698     if (!filename) return;
699   }
700   char sname[FL_PATH_MAX];
701   strlcpy(sname, fl_filename_name(filename), sizeof(sname));
702   fl_filename_setext(sname, sizeof(sname), exts[i18n_type]);
703   if (!compile_only) goto_source_dir();
704   int x = write_strings(sname);
705   if (!compile_only) leave_source_dir();
706   if (compile_only) {
707     if (x) {fprintf(stderr,"%s : %s\n",sname,strerror(errno)); exit(1);}
708   } else {
709     if (x) {
710       fl_message("Can't write %s: %s", sname, strerror(errno));
711     } else if (completion_button->value()) {
712       fl_message("Wrote %s", sname);
713     }
714   }
715 }
716 
openwidget_cb(Fl_Widget *,void *)717 void openwidget_cb(Fl_Widget *, void *) {
718   if (!Fl_Type::current) {
719     fl_message("Please select a widget");
720     return;
721   }
722   Fl_Type::current->open();
723 }
724 
725 void toggle_overlays(Fl_Widget *,void *);
726 
727 void select_all_cb(Fl_Widget *,void *);
728 void select_none_cb(Fl_Widget *,void *);
729 
730 void group_cb(Fl_Widget *, void *);
731 
732 void ungroup_cb(Fl_Widget *, void *);
733 
734 extern int pasteoffset;
735 static int ipasteoffset;
736 
copy_cb(Fl_Widget *,void *)737 void copy_cb(Fl_Widget*, void*) {
738   if (!Fl_Type::current) {
739     fl_beep();
740     return;
741   }
742   ipasteoffset = 10;
743   if (!write_file(cutfname(),1)) {
744     fl_message("Can't write %s: %s", cutfname(), strerror(errno));
745     return;
746   }
747 }
748 
749 extern void select_only(Fl_Type *);
cut_cb(Fl_Widget *,void *)750 void cut_cb(Fl_Widget *, void *) {
751   if (!Fl_Type::current) {
752     fl_beep();
753     return;
754   }
755   if (!write_file(cutfname(),1)) {
756     fl_message("Can't write %s: %s", cutfname(), strerror(errno));
757     return;
758   }
759   undo_checkpoint();
760   set_modflag(1);
761   ipasteoffset = 0;
762   Fl_Type *p = Fl_Type::current->parent;
763   while (p && p->selected) p = p->parent;
764   delete_all(1);
765   if (p) select_only(p);
766 }
767 
delete_cb(Fl_Widget *,void *)768 void delete_cb(Fl_Widget *, void *) {
769   if (!Fl_Type::current) {
770     fl_beep();
771     return;
772   }
773   undo_checkpoint();
774   set_modflag(1);
775   ipasteoffset = 0;
776   Fl_Type *p = Fl_Type::current->parent;
777   while (p && p->selected) p = p->parent;
778   delete_all(1);
779   if (p) select_only(p);
780 }
781 
782 extern int force_parent;
783 
paste_cb(Fl_Widget *,void *)784 void paste_cb(Fl_Widget*, void*) {
785   //if (ipasteoffset) force_parent = 1;
786   pasteoffset = ipasteoffset;
787   if (gridx>1) pasteoffset = ((pasteoffset-1)/gridx+1)*gridx;
788   if (gridy>1) pasteoffset = ((pasteoffset-1)/gridy+1)*gridy;
789   undo_checkpoint();
790   undo_suspend();
791   if (!read_file(cutfname(), 1)) {
792     fl_message("Can't read %s: %s", cutfname(), strerror(errno));
793   }
794   undo_resume();
795   pasteoffset = 0;
796   ipasteoffset += 10;
797   force_parent = 0;
798 }
799 
800 // Duplicate the selected widgets...
duplicate_cb(Fl_Widget *,void *)801 void duplicate_cb(Fl_Widget*, void*) {
802   if (!Fl_Type::current) {
803     fl_beep();
804     return;
805   }
806 
807   if (!write_file(cutfname(1),1)) {
808     fl_message("Can't write %s: %s", cutfname(1), strerror(errno));
809     return;
810   }
811 
812   pasteoffset  = 0;
813   force_parent = 1;
814 
815   undo_checkpoint();
816   undo_suspend();
817   if (!read_file(cutfname(1), 1)) {
818     fl_message("Can't read %s: %s", cutfname(1), strerror(errno));
819   }
820   unlink(cutfname(1));
821   undo_resume();
822 
823   force_parent = 0;
824 }
825 
826 void earlier_cb(Fl_Widget*,void*);
827 
828 void later_cb(Fl_Widget*,void*);
829 
830 Fl_Type *sort(Fl_Type *parent);
831 
sort_cb(Fl_Widget *,void *)832 static void sort_cb(Fl_Widget *,void *) {
833   sort((Fl_Type*)0);
834 }
835 
836 void show_project_cb(Fl_Widget *, void *);
837 void show_grid_cb(Fl_Widget *, void *);
838 void show_settings_cb(Fl_Widget *, void *);
839 void show_global_settings_cb(Fl_Widget *, void *);
840 
841 void align_widget_cb(Fl_Widget *, long);
842 void widget_size_cb(Fl_Widget *, long);
843 
about_cb(Fl_Widget *,void *)844 void about_cb(Fl_Widget *, void *) {
845   if (!about_panel) make_about_panel();
846   about_panel->show();
847 }
848 
show_help(const char * name)849 void show_help(const char *name) {
850   const char	*docdir;
851   char		helpname[FL_PATH_MAX];
852 
853   if (!help_dialog) help_dialog = new Fl_Help_Dialog();
854 
855   if ((docdir = getenv("FLTK_DOCDIR")) == NULL) {
856 #ifdef __EMX__
857     // Doesn't make sense to have a hardcoded fallback
858     static char fltk_docdir[FL_PATH_MAX];
859 
860     strlcpy(fltk_docdir, __XOS2RedirRoot("/XFree86/lib/X11/fltk/doc"),
861             sizeof(fltk_docdir));
862 
863     docdir = fltk_docdir;
864 #else
865     docdir = FLTK_DOCDIR;
866 #endif // __EMX__
867   }
868   snprintf(helpname, sizeof(helpname), "%s/%s", docdir, name);
869 
870   // make sure that we can read the file
871   FILE *f = fopen(helpname, "rb");
872   if (f) {
873     fclose(f);
874     help_dialog->load(helpname);
875   } else {
876     // if we can not read the file, we display the canned version instead
877     // or ask the native browser to open the page on www.fltk.org
878     if (strcmp(name, "fluid.html")==0) {
879       if (!Fl_Shared_Image::find("embedded:/fluid-org.png"))
880         new Fl_PNG_Image("embedded:/fluid-org.png", fluid_org_png, sizeof(fluid_org_png));
881       help_dialog->value
882       (
883        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
884        "<html><head><title>FLTK: Programming with FLUID</title></head><body>\n"
885        "<h2>What is FLUID?</h2>\n"
886        "The Fast Light User Interface Designer, or FLUID, is a graphical editor "
887        "that is used to produce FLTK source code. FLUID edits and saves its state "
888        "in <code>.fl</code> files. These files are text, and you can (with care) "
889        "edit them in a text editor, perhaps to get some special effects.<p>\n"
890        "FLUID can \"compile\" the <code>.fl</code> file into a <code>.cxx</code> "
891        "and a <code>.h</code> file. The <code>.cxx</code> file defines all the "
892        "objects from the <code>.fl</code> file and the <code>.h</code> file "
893        "declares all the global ones. FLUID also supports localization "
894        "(Internationalization) of label strings using message files and the GNU "
895        "gettext or POSIX catgets interfaces.<p>\n"
896        "A simple program can be made by putting all your code (including a <code>"
897        "main()</code> function) into the <code>.fl</code> file and thus making the "
898        "<code>.cxx</code> file a single source file to compile. Most programs are "
899        "more complex than this, so you write other <code>.cxx</code> files that "
900        "call the FLUID functions. These <code>.cxx</code> files must <code>"
901        "#include</code> the <code>.h</code> file or they can <code>#include</code> "
902        "the <code>.cxx</code> file so it still appears to be a single source file.<p>"
903        "<img src=\"embedded:/fluid-org.png\"></p>"
904        "<p>More information is available online at <a href="
905        "\"http://www.fltk.org/doc-1.3/fluid.html\">http://www.fltk.org/</a>"
906        "</body></html>"
907        );
908     } else if (strcmp(name, "license.html")==0) {
909       fl_open_uri("http://www.fltk.org/doc-1.3/license.html");
910       return;
911     } else if (strcmp(name, "index.html")==0) {
912       fl_open_uri("http://www.fltk.org/doc-1.3/index.html");
913       return;
914     } else {
915       snprintf(helpname, sizeof(helpname), "http://www.fltk.org/%s", name);
916       fl_open_uri(helpname);
917       return;
918     }
919   }
920   help_dialog->show();
921 }
922 
help_cb(Fl_Widget *,void *)923 void help_cb(Fl_Widget *, void *) {
924   show_help("fluid.html");
925 }
926 
manual_cb(Fl_Widget *,void *)927 void manual_cb(Fl_Widget *, void *) {
928   show_help("index.html");
929 }
930 
931 
932 ////////////////////////////////////////////////////////////////
933 
934 #if defined(WIN32) && !defined(__CYGWIN__)
935 // Draw a shaded box...
win_box(int x,int y,int w,int h)936 static void win_box(int x, int y, int w, int h) {
937   fl_color(0xc0, 0xc0, 0xc0);
938   fl_rectf(x, y, w, h);
939   fl_color(0, 0, 0);
940   fl_rect(x, y, w, h);
941   fl_color(0xf0, 0xf0, 0xf0);
942   fl_rectf(x + 1, y + 1, 4, h - 2);
943   fl_rectf(x + 1, y + 1, w - 2, 4);
944   fl_color(0x90, 0x90, 0x90);
945   fl_rectf(x + w - 5, y + 1, 4, h - 2);
946   fl_rectf(x + 1, y + h - 5, w - 2, 4);
947 }
948 
949 // Load and show the print dialog...
print_menu_cb(Fl_Widget *,void *)950 void print_menu_cb(Fl_Widget *, void *) {
951   PRINTDLG	dialog;			// Print dialog
952   DOCINFO	docinfo;		// Document info
953   int		first, last;		// First and last page
954   int		page;			// Current page
955   int		winpage;		// Current window page
956   int		num_pages;		// Number of pages
957   Fl_Type	*t;			// Current widget
958   int		num_windows;		// Number of windows
959   Fl_Window_Type *windows[1000];	// Windows to print
960 
961 
962   // Show print dialog...
963   for (t = Fl_Type::first, num_pages = 0; t; t = t->next) {
964     if (t->is_window()) num_pages ++;
965   }
966 
967   memset(&dialog, 0, sizeof(dialog));
968   dialog.lStructSize = sizeof(dialog);
969   dialog.hwndOwner   = fl_xid(main_window);
970   dialog.Flags       = PD_ALLPAGES |
971                        PD_RETURNDC;
972   dialog.nFromPage   = 1;
973   dialog.nToPage     = num_pages;
974   dialog.nMinPage    = 1;
975   dialog.nMaxPage    = num_pages;
976   dialog.nCopies     = 1;
977 
978   if (!PrintDlg(&dialog)) return;
979 
980   // Get the base filename...
981   const char *basename = strrchr(filename, '/');
982   if (basename) basename ++;
983   else basename = filename;
984 
985   // Do the print job...
986   memset(&docinfo, 0, sizeof(docinfo));
987   docinfo.cbSize      = sizeof(docinfo);
988   docinfo.lpszDocName = basename;
989 
990   StartDoc(dialog.hDC, &docinfo);
991 
992   // Figure out how many pages we'll have to print...
993   if (dialog.Flags & PD_PAGENUMS) {
994     // Get from and to page numbers...
995     first = dialog.nFromPage;
996     last  = dialog.nToPage;
997 
998     if (first > last) {
999       // Swap first/last page
1000       page  = first;
1001       first = last;
1002       last  = page;
1003     }
1004   } else {
1005     // Print everything...
1006     first = 1;
1007     last  = dialog.nMaxPage;
1008   }
1009 
1010   for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) {
1011     if (t->is_window()) {
1012       winpage ++;
1013       windows[num_windows] = (Fl_Window_Type *)t;
1014       num_windows ++;
1015 #if 0
1016       if (dialog.Flags & PD_ALLPAGES) num_windows ++;
1017       else if ((dialog.Flags & PD_PAGENUMS) && winpage >= first &&
1018                winpage <= last) num_windows ++;
1019       else if ((dialog.Flags & PD_SELECTION) && t->selected) num_windows ++;
1020 #endif // 0
1021     }
1022   }
1023 
1024   num_pages = num_windows;
1025 
1026   // Figure out the page size and margins...
1027   int	width, length;			// Size of page
1028   int   xdpi, ydpi;			// Output resolution
1029   char	buffer[1024];
1030 
1031   width  = GetDeviceCaps(dialog.hDC, HORZRES);
1032   length = GetDeviceCaps(dialog.hDC, VERTRES);
1033   xdpi   = GetDeviceCaps(dialog.hDC, LOGPIXELSX);
1034   ydpi   = GetDeviceCaps(dialog.hDC, LOGPIXELSY);
1035 
1036 //  fl_message("width=%d, length=%d, xdpi=%d, ydpi=%d, num_windows=%d\n",
1037 //             width, length, xdpi, ydpi, num_windows);
1038 
1039   HDC	save_dc = fl_gc;
1040   HWND	save_win = fl_window;
1041   int	fontsize = 14 * ydpi / 72;
1042 
1043   fl_gc = dialog.hDC;
1044   fl_window = (HWND)dialog.hDC;
1045   fl_push_no_clip();
1046 
1047   // Get the time and date...
1048   time_t curtime = time(NULL);
1049   struct tm *curdate = localtime(&curtime);
1050   char date[1024];
1051 
1052   strftime(date, sizeof(date), "%c", curdate);
1053 
1054   // Print each of the windows...
1055   for (winpage = 0; winpage < num_windows; winpage ++) {
1056     // Draw header...
1057     StartPage(dialog.hDC);
1058 
1059     fl_font(FL_HELVETICA_BOLD, fontsize);
1060     fl_color(0, 0, 0);
1061 
1062     fl_draw(basename, 0, fontsize);
1063 
1064     fl_draw(date, (width - (int)fl_width(date)) / 2, fontsize);
1065 
1066     sprintf(buffer, "%d/%d", winpage + 1, num_windows);
1067     fl_draw(buffer, width - (int)fl_width(buffer), fontsize);
1068 
1069     // Get window image...
1070     uchar	*pixels;		// Window image data
1071     int		w, h;			// Window image dimensions
1072     int		ww, hh;			// Scaled size
1073     int		ulx, uly;		// Upper-lefthand corner
1074     Fl_Window	*win;			// Window widget
1075     BITMAPINFO	info;			// Bitmap information
1076 
1077     win    = (Fl_Window *)(windows[winpage]->o);
1078     pixels = windows[winpage]->read_image(w, h);
1079 
1080     // Swap colors: FLTK uses R-G-B --> Windows GDI uses B-G-R
1081 
1082     { uchar *p = pixels;
1083       for (int i=0; i<w*h; i++, p+=3) {
1084 	uchar temp = p[0]; p[0] = p[2]; p[2] = temp;
1085       }
1086     }
1087 
1088     // Figure out the window size, first at 100 PPI and then scaled
1089     // down if that is too big...
1090     ww = w * xdpi / 100;
1091     hh = h * ydpi / 100;
1092 
1093     if (ww > width) {
1094       ww = width;
1095       hh = h * ww * ydpi / xdpi / w;
1096     }
1097 
1098     if (hh > (length - ydpi / 2)) {
1099       hh = length - ydpi / 2;
1100       ww = w * hh / h;
1101     }
1102 
1103     // Position the window in the center...
1104     ulx = (width - ww) / 2;
1105     uly = (length - hh) / 2;
1106 
1107 //    fl_message("winpage=%d, ulx=%d, uly=%d, ww=%d, hh=%d",
1108 //               winpage, ulx, uly, ww, hh);
1109 
1110     // Draw a simulated window border...
1111     int xborder = 4 * ww / w;
1112     int yborder = 4 * hh / h;
1113 
1114     win_box(ulx - xborder, uly - 5 * yborder,
1115             ww + 2 * xborder, hh + 6 * yborder);
1116 
1117     fl_color(0, 0, 255);
1118     fl_rectf(ulx, uly - 4 * yborder, ww, 4 * yborder);
1119 
1120     fl_font(FL_HELVETICA_BOLD, 2 * yborder);
1121     fl_color(255, 255, 255);
1122     fl_draw(win->label() ? win->label() : "Window",
1123             ulx + xborder, uly - 3 * yborder);
1124 
1125     int x = ulx + ww - 4 * xborder;
1126 
1127     win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
1128     fl_color(0, 0, 0);
1129     fl_line(x + xborder, uly - yborder,
1130             x + 3 * xborder, uly - 3 * yborder);
1131     fl_line(x + xborder, uly - 3 * yborder,
1132             x + 3 * xborder, uly - yborder);
1133     x -= 4 * xborder;
1134 
1135     if (win->resizable()) {
1136       win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
1137       fl_color(0, 0, 0);
1138       fl_rect(x + xborder, uly - 3 * yborder, 2 * xborder, 2 * yborder);
1139       x -= 4 * xborder;
1140     }
1141 
1142     if (!win->modal()) {
1143       win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
1144       fl_color(0, 0, 0);
1145       fl_line(x + xborder, uly - yborder, x + 3 * xborder, uly - yborder);
1146       x -= 4 * xborder;
1147     }
1148 
1149     // Color image...
1150     memset(&info, 0, sizeof(info));
1151     info.bmiHeader.biSize        = sizeof(info);
1152     info.bmiHeader.biWidth       = w;
1153     info.bmiHeader.biHeight      = 1;
1154     info.bmiHeader.biPlanes      = 1;
1155     info.bmiHeader.biBitCount    = 24;
1156     info.bmiHeader.biCompression = BI_RGB;
1157 
1158     for (int y = 0; y < h; y ++) {
1159       StretchDIBits(dialog.hDC, ulx, uly + y * hh / h, ww, (hh + h - 1) / h, 0, 0, w, 1,
1160                     pixels + y * w * 3, &info, DIB_RGB_COLORS, SRCCOPY);
1161     }
1162 
1163     delete[] pixels;
1164 
1165     // Show the page...
1166     EndPage(dialog.hDC);
1167   }
1168 
1169   // Finish up...
1170   EndDoc(dialog.hDC);
1171 
1172   fl_gc = save_dc;
1173   fl_window = save_win;
1174   fl_pop_clip();
1175 
1176   // Free the print DC and return...
1177   DeleteDC(dialog.hDC);
1178 }
1179 #else
1180 // Load and show the print dialog...
print_menu_cb(Fl_Widget *,void *)1181 void print_menu_cb(Fl_Widget *, void *) {
1182   if (!print_panel) make_print_panel();
1183 
1184   print_load();
1185 
1186   print_selection->deactivate();
1187 
1188   for (Fl_Type *t = Fl_Type::first; t; t = t->next) {
1189     if (t->selected && t->is_window()) {
1190       print_selection->activate();
1191       break;
1192     }
1193   }
1194 
1195   print_all->setonly();
1196   print_all->do_callback();
1197 
1198   print_panel->show();
1199 }
1200 
1201 // Quote a string for PostScript printing
ps_string(const char * s)1202 static const char *ps_string(const char *s) {
1203   char *bufptr;
1204   static char buffer[FL_PATH_MAX];
1205 
1206 
1207   if (!s) {
1208     buffer[0] = '\0';
1209   } else {
1210     for (bufptr = buffer; bufptr < (buffer + sizeof(buffer) - 3) && *s;) {
1211       if (*s == '(' || *s == ')' || *s == '\\') *bufptr++ = '\\';
1212       *bufptr++ = *s++;
1213     }
1214 
1215     *bufptr = '\0';
1216   }
1217 
1218   return (buffer);
1219 }
1220 
1221 // Actually print...
print_cb(Fl_Return_Button *,void *)1222 void print_cb(Fl_Return_Button *, void *) {
1223   FILE		*outfile;		// Output file or pipe to print command
1224   char		command[1024];		// Print command
1225   int		copies;			// Collated copies
1226   int		first, last;		// First and last page
1227   int		page;			// Current page
1228   int		winpage;		// Current window page
1229   int		num_pages;		// Number of pages
1230   Fl_Type	*t;			// Current widget
1231   int		num_windows;		// Number of windows
1232   Fl_Window_Type *windows[1000];	// Windows to print
1233 
1234   // Show progress, deactivate controls...
1235   print_panel_controls->deactivate();
1236   print_progress->show();
1237 
1238   // Figure out how many pages we'll have to print...
1239   if (print_collate_button->value()) copies = (int)print_copies->value();
1240   else copies = 1;
1241 
1242   if (print_pages->value()) {
1243     // Get from and to page numbers...
1244     if ((first = atoi(print_from->value())) < 1) first = 1;
1245     if ((last = atoi(print_to->value())) < 1) last = 1000;
1246 
1247     if (first > last) {
1248       // Swap first/last page
1249       page  = first;
1250       first = last;
1251       last  = page;
1252     }
1253   } else {
1254     // Print everything...
1255     first = 1;
1256     last  = 1000;
1257   }
1258 
1259   for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) {
1260     if (t->is_window()) {
1261       winpage ++;
1262       windows[num_windows] = (Fl_Window_Type *)t;
1263       if (!((Fl_Window*)(windows[num_windows]->o))->shown()) continue;
1264       if (print_all->value()) num_windows ++;
1265       else if (print_pages->value() && winpage >= first &&
1266                winpage <= last) num_windows ++;
1267       else if (print_selection->value() && t->selected) num_windows ++;
1268     }
1269   }
1270 
1271   num_pages = num_windows * copies;
1272 
1273   print_progress->minimum(0);
1274   print_progress->maximum(num_pages);
1275   print_progress->value(0);
1276   Fl::check();
1277 
1278   // Get the base filename...
1279   const char *basename = strrchr(filename, '/');
1280   if (basename) basename ++;
1281   else basename = filename;
1282 
1283   // Open the print stream...
1284   if (print_choice->value()) {
1285     // Pipe the output into the lp command...
1286     const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data();
1287 
1288     snprintf(command, sizeof(command), "lp -s -d %s -n %.0f -t '%s' -o media=%s",
1289              printer, print_collate_button->value() ? 1.0 : print_copies->value(),
1290 	     basename, print_page_size->text(print_page_size->value()));
1291     outfile = popen(command, "w");
1292   } else {
1293     // Print to file...
1294     fl_file_chooser_ok_label("Print");
1295     const char *outname = fl_file_chooser("Print To", "PostScript (*.ps)", NULL, 1);
1296     fl_file_chooser_ok_label(NULL);
1297 
1298     if (outname && !access(outname, 0)) {
1299       if (fl_choice("The file \"%s\" already exists.\n"
1300                     "Do you want to replace it?", "Cancel",
1301 		    "Replace", NULL, outname) == 0) outname = NULL;
1302     }
1303 
1304     if (outname) outfile = fl_fopen(outname, "w");
1305     else outfile = NULL;
1306   }
1307 
1308   if (outfile) {
1309     // Figure out the page size and margins...
1310     int	width, length;			// Size of page
1311     int	left, bottom,			// Bottom lefthand corner
1312 	right, top;			// Top righthand corner
1313 
1314     if (print_page_size->value()) {
1315       // A4
1316       width  = 595;
1317       length = 842;
1318     } else {
1319       // Letter
1320       width  = 612;
1321       length = 792;
1322     }
1323 
1324     int output_mode;
1325     for (output_mode = 0; output_mode < 4; output_mode ++) {
1326       if (print_output_mode[output_mode]->value()) break;
1327     }
1328 
1329     if (output_mode & 1) {
1330       // Landscape
1331       left   = 36;
1332       bottom = 18;
1333       right  = length - 36;
1334       top    = width - 18;
1335     } else {
1336       // Portrait
1337       left   = 18;
1338       bottom = 36;
1339       right  = width - 18;
1340       top    = length - 36;
1341     }
1342 
1343     // Get the time and date...
1344     time_t curtime = time(NULL);
1345     struct tm *curdate = localtime(&curtime);
1346     char date[1024];
1347 
1348     strftime(date, sizeof(date), "%c", curdate);
1349 
1350     // Write the prolog...
1351     fprintf(outfile,
1352             "%%!PS-Adobe-3.0\n"
1353 	    "%%%%BoundingBox: 18 36 %d %d\n"
1354 	    "%%%%Pages: %d\n"
1355 	    "%%%%LanguageLevel: 1\n"
1356 	    "%%%%DocumentData: Clean7Bit\n"
1357 	    "%%%%DocumentNeededResources: font Helvetica-Bold\n"
1358 	    "%%%%Creator: FLUID %.4f\n"
1359 	    "%%%%CreationDate: %s\n"
1360 	    "%%%%Title: (%s)\n"
1361 	    "%%%%EndComments\n"
1362 	    "%%%%BeginProlog\n"
1363 	    "%%languagelevel 1 eq {\n"
1364 	    "  /rectfill {\n"
1365 	    "    newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
1366 	    "    neg 0 exch rlineto closepath fill\n"
1367 	    "  } bind def\n"
1368 	    "  /rectstroke {\n"
1369 	    "    newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
1370 	    "    neg 0 exch rlineto closepath stroke\n"
1371 	    "  } bind def\n"
1372 	    "%%} if\n"
1373 	    "%%%%EndProlog\n"
1374 	    "%%%%BeginSetup\n"
1375 	    "%%%%BeginFeature: *PageSize %s\n"
1376 	    "languagelevel 1 ne {\n"
1377 	    "  <</PageSize[%d %d]/ImagingBBox null>>setpagedevice\n"
1378 	    "} {\n"
1379 	    "  %s\n"
1380 	    "} ifelse\n"
1381 	    "%%%%EndFeature\n"
1382 	    "%%%%EndSetup\n",
1383 	    width - 18, length - 36,
1384 	    num_pages,
1385 	    FL_VERSION,
1386 	    date,
1387 	    basename,
1388 	    print_page_size->text(print_page_size->value()),
1389 	    width, length,
1390 	    print_page_size->value() ? "a4tray" : "lettertray");
1391 
1392     // Print each of the windows...
1393     char	progress[255];		// Progress text
1394     int		copy;			// Current copy
1395 
1396     for (copy = 0, page = 0; copy < copies; copy ++) {
1397       for (winpage = 0; winpage < num_pages; winpage ++) {
1398         // Start next page...
1399         page ++;
1400 	sprintf(progress, "Printing page %d/%d...", page, num_pages);
1401 	print_progress->value(page);
1402 	print_progress->label(progress);
1403 	Fl::check();
1404 
1405         // Add common page stuff...
1406 	fprintf(outfile,
1407 	        "%%%%Page: %d %d\n"
1408 		"gsave\n",
1409 		page, page);
1410 
1411         if (output_mode & 1) {
1412 	  // Landscape...
1413 	  fprintf(outfile, "%d 0 translate 90 rotate\n", width);
1414 	}
1415 
1416         // Draw header...
1417 	fprintf(outfile,
1418 		"0 setgray\n"
1419 		"/Helvetica-Bold findfont 14 scalefont setfont\n"
1420 		"%d %d moveto (%s) show\n"
1421 		"%.1f %d moveto (%s) dup stringwidth pop -0.5 mul 0 rmoveto show\n"
1422 		"%d %d moveto (%d/%d) dup stringwidth pop neg 0 rmoveto show\n",
1423 	        left, top - 15, ps_string(basename),
1424 		0.5 * (left + right), top - 15, date,
1425 		right, top - 15, winpage + 1, num_windows);
1426 
1427         // Get window image...
1428 	uchar	*pixels;		// Window image data
1429         int	w, h;			// Window image dimensions
1430 	float	ww, hh;			// Scaled size
1431 	float	border;			// Width of 1 pixel
1432         float	llx, lly,		// Lower-lefthand corner
1433 		urx, ury;		// Upper-righthand corner
1434 	Fl_Window *win;			// Window widget
1435 
1436         win    = (Fl_Window *)(windows[winpage]->o);
1437 	pixels = windows[winpage]->read_image(w, h);
1438 
1439         // Figure out the window size, first at 100 PPI and then scaled
1440 	// down if that is too big...
1441         ww = w * 72.0 / 100.0;
1442 	hh = h * 72.0 / 100.0;
1443 
1444         if (ww > (right - left)) {
1445 	  ww = right - left;
1446 	  hh = h * ww / w;
1447 	}
1448 
1449         if (hh > (top - bottom - 36)) {
1450 	  hh = top - bottom;
1451 	  ww = w * hh / h;
1452 	}
1453 
1454         border = ww / w;
1455 
1456 	// Position the window in the center...
1457 	llx = 0.5 * (right - left - ww);
1458 	lly = 0.5 * (top - bottom - hh);
1459 	urx = 0.5 * (right - left + ww);
1460 	ury = 0.5 * (top - bottom + hh);
1461 
1462         // Draw a simulated window border...
1463         fprintf(outfile,
1464 	        "0.75 setgray\n"			// Gray background
1465 	        "newpath %.2f %.2f %.2f 180 90 arcn\n"	// Top left
1466 		"%.2f %.2f %.2f 90 0 arcn\n"		// Top right
1467 		"%.2f %.2f %.2f 0 -90 arcn\n"		// Bottom right
1468 		"%.2f %.2f %.2f -90 -180 arcn\n"	// Bottom left
1469 		"closepath gsave fill grestore\n"	// Fill
1470 		"0 setlinewidth 0 setgray stroke\n",	// Outline
1471 		llx, ury + 12 * border, 4 * border,
1472 		urx, ury + 12 * border, 4 * border,
1473 		urx, lly, 4 * border,
1474 		llx, lly, 4 * border);
1475 
1476         // Title bar...
1477 	if (output_mode & 2) {
1478 	  fputs("0.25 setgray\n", outfile);
1479 	} else {
1480 	  fputs("0.1 0.2 0.6 setrgbcolor\n", outfile);
1481 	}
1482 
1483         fprintf(outfile, "%.2f %.2f %.2f %.2f rectfill\n",
1484 	        llx + 12 * border, ury,
1485 		ww - (24 + 16 * (!win->modal() || win->resizable()) +
1486 		      16 * (!win->modal() && win->resizable())) * border,
1487 		16 * border);
1488 
1489         if (win->resizable()) {
1490 	  fprintf(outfile,
1491 		  "%.2f %.2f %.2f -90 -180 arcn\n"	// Bottom left
1492 	          "0 %.2f rlineto %.2f 0 rlineto 0 -%.2f rlineto closepath fill\n"
1493 		  "%.2f %.2f %.2f 0 -90 arcn\n"	// Bottom right
1494 	          "-%.2f 0 rlineto 0 %.2f rlineto %.2f 0 rlineto closepath fill\n",
1495 		  llx, lly, 4 * border,
1496 		  12 * border, 16 * border, 16 * border,
1497 		  urx, lly, 4 * border,
1498 		  12 * border, 16 * border, 16 * border);
1499 	}
1500 
1501         // Inside outline and button shading...
1502         fprintf(outfile,
1503 	        "%.2f setlinewidth 0.5 setgray\n"
1504 		"%.2f %.2f %.2f %.2f rectstroke\n"
1505 		"%.2f %.2f moveto 0 %.2f rlineto\n"
1506 		"%.2f %.2f moveto 0 %.2f rlineto\n",
1507 		border,
1508 		llx - 0.5 * border, lly - 0.5 * border, ww + border, hh + border,
1509 		llx + 12 * border, ury, 16 * border,
1510 		urx - 12 * border, ury, 16 * border);
1511 
1512         if (!win->modal() || win->resizable()) {
1513 	  fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n",
1514 	          urx - 28 * border, ury, 16 * border);
1515 	}
1516 
1517         if (!win->modal() && win->resizable()) {
1518 	  fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n",
1519 	          urx - 44 * border, ury, 16 * border);
1520 	}
1521 
1522         fprintf(outfile, "%.2f %.2f moveto %.2f 0 rlineto stroke\n",
1523 		llx - 3.5 * border, ury + 0.5 * border, ww + 7 * border);
1524 
1525         // Button icons...
1526         fprintf(outfile,
1527 	        "%.2f setlinewidth 0 setgray\n"
1528 		"%.2f %.2f moveto %.2f -%.2f rlineto %.2f %.2f rlineto\n"
1529 		"%.2f %.2f moveto -%.2f -%.2f rlineto 0 %.2f rmoveto %.2f -%.2f rlineto\n",
1530 		2 * border,
1531 		llx, ury + 10 * border, 4 * border, 4 * border, 4 * border, 4 * border,
1532 		urx, ury + 12 * border, 8 * border, 8 * border, 8 * border, 8 * border, 8 * border);
1533 
1534         float x = urx - 16 * border;
1535 
1536         if (win->resizable()) {
1537 	  // Maximize button
1538 	  fprintf(outfile,
1539 	          "%.2f %.2f moveto -%.2f 0 rlineto 0 -%.2f rlineto "
1540 		  "%.2f 0 rlineto 0 %.2f rlineto\n",
1541 		  x, ury + 12 * border, 8 * border, 8 * border,
1542 		  8 * border, 8 * border);
1543 
1544           x -= 16 * border;
1545         }
1546 
1547         if (!win->modal()) {
1548 	  // Minimize button
1549 	  fprintf(outfile,
1550 	          "%.2f %.2f moveto -%.2f 0 rlineto\n",
1551 		  x, ury + 4 * border, 8 * border);
1552         }
1553 
1554         fputs("stroke\n", outfile);
1555 
1556         if (win->label()) {
1557 	  // Add window title...
1558 	  fprintf(outfile,
1559 		  "1 setgray\n"
1560 		  "/Helvetica-Bold findfont %.2f scalefont setfont\n"
1561 		  "(%s) %.2f %.2f moveto show\n",
1562 		  12 * border,
1563 		  ps_string(win->label()), llx + 16 * border, ury + 4 * border);
1564 	}
1565 
1566         fprintf(outfile,
1567 	        "gsave\n"
1568 		"%.2f %.2f translate %.2f %.2f scale\n",
1569 		llx, ury - border, border, border);
1570 
1571         if (output_mode & 2) {
1572 	  // Grayscale image...
1573 	  fprintf(outfile,
1574 	          "/imgdata %d string def\n"
1575 		  "%d %d 8[1 0 0 -1 0 1] "
1576 		  "{currentfile imgdata readhexstring pop} image\n",
1577 		  w,
1578 		  w, h);
1579 
1580           uchar *ptr = pixels;
1581 	  int i, count = w * h;
1582 
1583           for (i = 0; i < count; i ++, ptr += 3) {
1584 	    fprintf(outfile, "%02X",
1585 	            (31 * ptr[0] + 61 * ptr[1] + 8 * ptr[2]) / 100);
1586 	    if (!(i % 40)) putc('\n', outfile);
1587 	  }
1588 	} else {
1589 	  // Color image...
1590 	  fprintf(outfile,
1591 	          "/imgdata %d string def\n"
1592 		  "%d %d 8[1 0 0 -1 0 1] "
1593 		  "{currentfile imgdata readhexstring pop} false 3 colorimage\n",
1594 		  w * 3,
1595 		  w, h);
1596 
1597           uchar *ptr = pixels;
1598 	  int i, count = w * h;
1599 
1600           for (i = 0; i < count; i ++, ptr += 3) {
1601 	    fprintf(outfile, "%02X%02X%02X", ptr[0], ptr[1], ptr[2]);
1602 	    if (!(i % 13)) putc('\n', outfile);
1603 	  }
1604 	}
1605 
1606         fputs("\ngrestore\n", outfile);
1607 
1608         delete[] pixels;
1609 
1610         // Show the page...
1611 	fputs("grestore showpage\n", outfile);
1612       }
1613     }
1614 
1615     // Finish up...
1616     fputs("%%EOF\n", outfile);
1617 
1618     if (print_choice->value()) pclose(outfile);
1619     else fclose(outfile);
1620   } else {
1621     // Unable to print...
1622     fl_alert("Error printing: %s", strerror(errno));
1623   }
1624 
1625   // Hide progress, activate controls, hide print panel...
1626   print_panel_controls->activate();
1627   print_progress->hide();
1628   print_panel->hide();
1629 }
1630 #endif // WIN32 && !__CYGWIN__
1631 
1632 ////////////////////////////////////////////////////////////////
1633 
1634 extern Fl_Menu_Item New_Menu[];
1635 
1636 void toggle_widgetbin_cb(Fl_Widget *, void *);
1637 void toggle_sourceview_cb(Fl_Double_Window *, void *);
1638 
1639 Fl_Menu_Item Main_Menu[] = {
1640 {"&File",0,0,0,FL_SUBMENU},
1641   {"&New...", FL_COMMAND+'n', new_cb, 0},
1642   {"&Open...", FL_COMMAND+'o', open_cb, 0},
1643   {"&Insert...", FL_COMMAND+'i', open_cb, (void*)1, FL_MENU_DIVIDER},
1644   {"&Save", FL_COMMAND+'s', save_cb, 0},
1645   {"Save &As...", FL_COMMAND+FL_SHIFT+'s', save_cb, (void*)1},
1646   {"Sa&ve A Copy...", 0, save_cb, (void*)2},
1647   {"Save &Template...", 0, save_template_cb},
1648   {"&Revert...", 0, revert_cb, 0, FL_MENU_DIVIDER},
1649   {"&Print...", FL_COMMAND+'p', print_menu_cb},
1650   {"Write &Code...", FL_COMMAND+FL_SHIFT+'c', write_cb, 0},
1651   {"&Write Strings...", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, 0, FL_MENU_DIVIDER},
1652   {relative_history[0], FL_COMMAND+'0', open_history_cb, absolute_history[0]},
1653   {relative_history[1], FL_COMMAND+'1', open_history_cb, absolute_history[1]},
1654   {relative_history[2], FL_COMMAND+'2', open_history_cb, absolute_history[2]},
1655   {relative_history[3], FL_COMMAND+'3', open_history_cb, absolute_history[3]},
1656   {relative_history[4], FL_COMMAND+'4', open_history_cb, absolute_history[4]},
1657   {relative_history[5], FL_COMMAND+'5', open_history_cb, absolute_history[5]},
1658   {relative_history[6], FL_COMMAND+'6', open_history_cb, absolute_history[6]},
1659   {relative_history[7], FL_COMMAND+'7', open_history_cb, absolute_history[7]},
1660   {relative_history[8], FL_COMMAND+'8', open_history_cb, absolute_history[8]},
1661   {relative_history[9], FL_COMMAND+'9', open_history_cb, absolute_history[9], FL_MENU_DIVIDER},
1662   {"&Quit", FL_COMMAND+'q', exit_cb},
1663   {0},
1664 {"&Edit",0,0,0,FL_SUBMENU},
1665   {"&Undo", FL_COMMAND+'z', undo_cb},
1666   {"&Redo", FL_COMMAND+FL_SHIFT+'z', redo_cb, 0, FL_MENU_DIVIDER},
1667   {"C&ut", FL_COMMAND+'x', cut_cb},
1668   {"&Copy", FL_COMMAND+'c', copy_cb},
1669   {"&Paste", FL_COMMAND+'v', paste_cb},
1670   {"Dup&licate", FL_COMMAND+'u', duplicate_cb},
1671   {"&Delete", FL_Delete, delete_cb, 0, FL_MENU_DIVIDER},
1672   {"Select &All", FL_COMMAND+'a', select_all_cb},
1673   {"Select &None", FL_COMMAND+FL_SHIFT+'a', select_none_cb, 0, FL_MENU_DIVIDER},
1674   {"Pr&operties...", FL_F+1, openwidget_cb},
1675   {"&Sort",0,sort_cb},
1676   {"&Earlier", FL_F+2, earlier_cb},
1677   {"&Later", FL_F+3, later_cb},
1678   {"&Group", FL_F+7, group_cb},
1679   {"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER},
1680   {"Hide O&verlays",FL_COMMAND+FL_SHIFT+'o',toggle_overlays},
1681   {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb},
1682   {"Show Source Code...",FL_ALT+FL_SHIFT+'s', (Fl_Callback*)toggle_sourceview_cb, 0, FL_MENU_DIVIDER},
1683   {"Pro&ject Settings...",FL_ALT+'p',show_project_cb},
1684   {"GU&I Settings...",FL_ALT+FL_SHIFT+'p',show_settings_cb,0,FL_MENU_DIVIDER},
1685   {"Global &FLTK Settings...",FL_ALT+FL_SHIFT+'g',show_global_settings_cb},
1686   {0},
1687 {"&New", 0, 0, (void *)New_Menu, FL_SUBMENU_POINTER},
1688 {"&Layout",0,0,0,FL_SUBMENU},
1689   {"&Align",0,0,0,FL_SUBMENU},
1690     {"&Left",0,(Fl_Callback *)align_widget_cb,(void*)10},
1691     {"&Center",0,(Fl_Callback *)align_widget_cb,(void*)11},
1692     {"&Right",0,(Fl_Callback *)align_widget_cb,(void*)12},
1693     {"&Top",0,(Fl_Callback *)align_widget_cb,(void*)13},
1694     {"&Middle",0,(Fl_Callback *)align_widget_cb,(void*)14},
1695     {"&Bottom",0,(Fl_Callback *)align_widget_cb,(void*)15},
1696     {0},
1697   {"&Space Evenly",0,0,0,FL_SUBMENU},
1698     {"&Across",0,(Fl_Callback *)align_widget_cb,(void*)20},
1699     {"&Down",0,(Fl_Callback *)align_widget_cb,(void*)21},
1700     {0},
1701   {"&Make Same Size",0,0,0,FL_SUBMENU},
1702     {"&Width",0,(Fl_Callback *)align_widget_cb,(void*)30},
1703     {"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31},
1704     {"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32},
1705     {0},
1706   {"&Center In Group",0,0,0,FL_SUBMENU},
1707     {"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40},
1708     {"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41},
1709     {0},
1710   {"Set &Widget Size",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER},
1711     {"&Tiny",FL_ALT+'1',(Fl_Callback *)widget_size_cb,(void*)8,0,FL_NORMAL_LABEL,FL_HELVETICA,8},
1712     {"&Small",FL_ALT+'2',(Fl_Callback *)widget_size_cb,(void*)11,0,FL_NORMAL_LABEL,FL_HELVETICA,11},
1713     {"&Normal",FL_ALT+'3',(Fl_Callback *)widget_size_cb,(void*)14,0,FL_NORMAL_LABEL,FL_HELVETICA,14},
1714     {"&Medium",FL_ALT+'4',(Fl_Callback *)widget_size_cb,(void*)18,0,FL_NORMAL_LABEL,FL_HELVETICA,18},
1715     {"&Large",FL_ALT+'5',(Fl_Callback *)widget_size_cb,(void*)24,0,FL_NORMAL_LABEL,FL_HELVETICA,24},
1716     {"&Huge",FL_ALT+'6',(Fl_Callback *)widget_size_cb,(void*)32,0,FL_NORMAL_LABEL,FL_HELVETICA,32},
1717     {0},
1718   {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb},
1719   {0},
1720 {"&Shell",0,0,0,FL_SUBMENU},
1721   {"Execute &Command...",FL_ALT+'x',(Fl_Callback *)show_shell_window},
1722   {"Execute &Again...",FL_ALT+'g',(Fl_Callback *)do_shell_command},
1723   {0},
1724 {"&Help",0,0,0,FL_SUBMENU},
1725   {"&Rapid development with FLUID...",0,help_cb},
1726   {"&FLTK Programmers Manual...",0,manual_cb, 0, FL_MENU_DIVIDER},
1727   {"&About FLUID...",0,about_cb},
1728   {0},
1729 {0}};
1730 
1731 #define BROWSERWIDTH 300
1732 #define BROWSERHEIGHT 500
1733 #define WINWIDTH 300
1734 #define MENUHEIGHT 25
1735 #define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT)
1736 
1737 extern void fill_in_New_Menu();
1738 
scheme_cb(Fl_Choice *,void *)1739 void scheme_cb(Fl_Choice *, void *) {
1740   if (compile_only)
1741     return;
1742 
1743   switch (scheme_choice->value()) {
1744     case 0 : // Default
1745       Fl::scheme(NULL);
1746       break;
1747     case 1 : // None
1748       Fl::scheme("none");
1749       break;
1750     case 2 : // Plastic
1751       Fl::scheme("plastic");
1752       break;
1753     case 3 : // GTK+
1754       Fl::scheme("gtk+");
1755       break;
1756   }
1757 
1758   fluid_prefs.set("scheme", scheme_choice->value());
1759 }
1760 
toggle_widgetbin_cb(Fl_Widget *,void *)1761 void toggle_widgetbin_cb(Fl_Widget *, void *) {
1762   if (!widgetbin_panel) {
1763     make_widgetbin();
1764     if (!position_window(widgetbin_panel,"widgetbin_pos", 1, 320, 30)) return;
1765   }
1766 
1767   if (widgetbin_panel->visible()) {
1768     widgetbin_panel->hide();
1769     widgetbin_item->label("Show Widget &Bin...");
1770   } else {
1771     widgetbin_panel->show();
1772     widgetbin_item->label("Hide Widget &Bin");
1773   }
1774 }
1775 
1776 
toggle_sourceview_cb(Fl_Double_Window *,void *)1777 void toggle_sourceview_cb(Fl_Double_Window *, void *) {
1778   if (!sourceview_panel) {
1779     make_sourceview();
1780     sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb);
1781     Fl_Preferences svp(fluid_prefs, "sourceview");
1782     int autorefresh;
1783     svp.get("autorefresh", autorefresh, 1);
1784     sv_autorefresh->value(autorefresh);
1785     int autoposition;
1786     svp.get("autoposition", autoposition, 1);
1787     sv_autoposition->value(autoposition);
1788     int tab;
1789     svp.get("tab", tab, 0);
1790     if (tab>=0 && tab<sv_tab->children()) sv_tab->value(sv_tab->child(tab));
1791     if (!position_window(sourceview_panel,"sourceview_pos", 0, 320, 120, 550, 500)) return;
1792   }
1793 
1794   if (sourceview_panel->visible()) {
1795     sourceview_panel->hide();
1796     sourceview_item->label("Show Source Code...");
1797   } else {
1798     sourceview_panel->show();
1799     sourceview_item->label("Hide Source Code...");
1800     update_sourceview_cb(0,0);
1801   }
1802 }
1803 
toggle_sourceview_b_cb(Fl_Button *,void *)1804 void toggle_sourceview_b_cb(Fl_Button*, void *) {
1805   toggle_sourceview_cb(0,0);
1806 }
1807 
make_main_window()1808 void make_main_window() {
1809   if (!compile_only) {
1810     fluid_prefs.get("snap", snap, 1);
1811     fluid_prefs.get("gridx", gridx, 5);
1812     fluid_prefs.get("gridy", gridy, 5);
1813     fluid_prefs.get("show_guides", show_guides, 0);
1814     fluid_prefs.get("widget_size", Fl_Widget_Type::default_size, 14);
1815     fluid_prefs.get("show_comments", show_comments, 1);
1816     make_layout_window();
1817     make_shell_window();
1818   }
1819 
1820   if (!main_window) {
1821     Fl_Widget *o;
1822     main_window = new Fl_Double_Window(WINWIDTH,WINHEIGHT,"fluid");
1823     main_window->box(FL_NO_BOX);
1824     o = make_widget_browser(0,MENUHEIGHT,BROWSERWIDTH,BROWSERHEIGHT);
1825     o->box(FL_FLAT_BOX);
1826     o->tooltip("Double-click to view or change an item.");
1827     main_window->resizable(o);
1828     main_menubar = new Fl_Menu_Bar(0,0,BROWSERWIDTH,MENUHEIGHT);
1829     main_menubar->menu(Main_Menu);
1830     // quick access to all dynamic menu items
1831     save_item = (Fl_Menu_Item*)main_menubar->find_item(save_cb);
1832     history_item = (Fl_Menu_Item*)main_menubar->find_item(open_history_cb);
1833     widgetbin_item = (Fl_Menu_Item*)main_menubar->find_item(toggle_widgetbin_cb);
1834     sourceview_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_sourceview_cb);
1835     main_menubar->global();
1836     fill_in_New_Menu();
1837     main_window->end();
1838   }
1839 
1840   if (!compile_only) {
1841     load_history();
1842     make_settings_window();
1843     make_global_settings_window();
1844   }
1845 }
1846 
1847 // Load file history from preferences...
load_history()1848 void load_history() {
1849   int	i;		// Looping var
1850   int	max_files;
1851 
1852 
1853   fluid_prefs.get("recent_files", max_files, 5);
1854   if (max_files > 10) max_files = 10;
1855 
1856   for (i = 0; i < max_files; i ++) {
1857     fluid_prefs.get( Fl_Preferences::Name("file%d", i), absolute_history[i], "", sizeof(absolute_history[i]));
1858     if (absolute_history[i][0]) {
1859       // Make a relative version of the filename for the menu...
1860       fl_filename_relative(relative_history[i], sizeof(relative_history[i]),
1861                            absolute_history[i]);
1862 
1863       if (i == 9) history_item[i].flags = FL_MENU_DIVIDER;
1864       else history_item[i].flags = 0;
1865     } else break;
1866   }
1867 
1868   for (; i < 10; i ++) {
1869     if (i) history_item[i-1].flags |= FL_MENU_DIVIDER;
1870     history_item[i].hide();
1871   }
1872 }
1873 
1874 // Update file history from preferences...
update_history(const char * flname)1875 void update_history(const char *flname) {
1876   int	i;		// Looping var
1877   char	absolute[FL_PATH_MAX];
1878   int	max_files;
1879 
1880 
1881   fluid_prefs.get("recent_files", max_files, 5);
1882   if (max_files > 10) max_files = 10;
1883 
1884   fl_filename_absolute(absolute, sizeof(absolute), flname);
1885 
1886   for (i = 0; i < max_files; i ++)
1887 #if defined(WIN32) || defined(__APPLE__)
1888     if (!strcasecmp(absolute, absolute_history[i])) break;
1889 #else
1890     if (!strcmp(absolute, absolute_history[i])) break;
1891 #endif // WIN32 || __APPLE__
1892 
1893   if (i == 0) return;
1894 
1895   if (i >= max_files) i = max_files - 1;
1896 
1897   // Move the other flnames down in the list...
1898   memmove(absolute_history + 1, absolute_history,
1899           i * sizeof(absolute_history[0]));
1900   memmove(relative_history + 1, relative_history,
1901           i * sizeof(relative_history[0]));
1902 
1903   // Put the new file at the top...
1904   strlcpy(absolute_history[0], absolute, sizeof(absolute_history[0]));
1905 
1906   fl_filename_relative(relative_history[0], sizeof(relative_history[0]),
1907                        absolute_history[0]);
1908 
1909   // Update the menu items as needed...
1910   for (i = 0; i < max_files; i ++) {
1911     fluid_prefs.set( Fl_Preferences::Name("file%d", i), absolute_history[i]);
1912     if (absolute_history[i][0]) {
1913       if (i == 9) history_item[i].flags = FL_MENU_DIVIDER;
1914       else history_item[i].flags = 0;
1915     } else break;
1916   }
1917 
1918   for (; i < 10; i ++) {
1919     fluid_prefs.set( Fl_Preferences::Name("file%d", i), "");
1920     if (i) history_item[i-1].flags |= FL_MENU_DIVIDER;
1921     history_item[i].hide();
1922   }
1923 }
1924 
1925 // ********** portable process class definition **********
1926 
1927 class Fl_Process {
1928 public:
1929   // construction / destruction
Fl_Process()1930   Fl_Process() {_fpt= NULL;}
~Fl_Process()1931   ~Fl_Process() {if (_fpt) close();}
1932 
1933   // FIXME: popen needs the utf8 equivalen fl_popen
1934   FILE * popen	(const char *cmd, const char *mode="r");
1935   //not necessary here: FILE * fl_fopen	(const char *file, const char *mode="r");
1936   int  close();
1937 
desc() const1938   FILE * desc() const { return _fpt;} // non null if file is open
get_line(char * line,size_t s) const1939   char * get_line(char * line, size_t s) const {return _fpt ? fgets(line, s, _fpt) : NULL;}
1940 
1941 #if defined(WIN32)  && !defined(__CYGWIN__)
1942 protected:
1943   HANDLE pin[2], pout[2], perr[2];
1944   char ptmode;
1945   PROCESS_INFORMATION pi;
1946   STARTUPINFO si;
1947 
1948   static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE);
1949 
1950 private:
freeHandles()1951   FILE * freeHandles()  {
1952     clean_close(pin[0]);    clean_close(pin[1]);
1953     clean_close(pout[0]);   clean_close(pout[1]);
1954     clean_close(perr[0]);   clean_close(perr[1]);
1955     return NULL; // convenient for error management
1956   }
1957   static void clean_close(HANDLE& h);
1958 #endif
1959 
1960 protected:
1961   FILE * _fpt;
1962 };
1963 
1964 #if defined(WIN32)  && !defined(__CYGWIN__)
createPipe(HANDLE * h,BOOL bInheritHnd)1965 bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) {
1966   SECURITY_ATTRIBUTES sa;
1967   sa.nLength = sizeof(sa);
1968   sa.lpSecurityDescriptor = NULL;
1969   sa.bInheritHandle = bInheritHnd;
1970   return CreatePipe (&h[0],&h[1],&sa,0) ? true : false;
1971 }
1972 #endif
1973 // portable open process:
popen(const char * cmd,const char * mode)1974 FILE * Fl_Process::popen(const char *cmd, const char *mode) {
1975 #if defined(WIN32)  && !defined(__CYGWIN__)
1976   // PRECONDITIONS
1977   if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL;
1978   if (_fpt) close(); // close first before reuse
1979 
1980   ptmode = *mode;
1981   pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE;
1982   // stderr to stdout wanted ?
1983   int fusion = (strstr(cmd,"2>&1") !=NULL);
1984 
1985   // Create windows pipes
1986   if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) )
1987 	return freeHandles(); // error
1988 
1989   // Initialize Startup Info
1990   ZeroMemory(&si, sizeof(STARTUPINFO));
1991   si.cb           = sizeof(STARTUPINFO);
1992   si.dwFlags    = STARTF_USESTDHANDLES;
1993   si.hStdInput    = pin[0];
1994   si.hStdOutput   = pout[1];
1995   si.hStdError  = fusion ? pout[1] : perr [1];
1996 
1997   if ( CreateProcess(NULL, (LPTSTR) cmd,NULL,NULL,TRUE,
1998 		     DETACHED_PROCESS,NULL,NULL, &si, &pi)) {
1999     // don't need theses handles inherited by child process:
2000     clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]);
2001     HANDLE & h = *mode == 'r' ? pout[0] : pin[1];
2002     _fpt = _fdopen(_open_osfhandle((fl_intptr_t) h,_O_BINARY),mode);
2003     h= INVALID_HANDLE_VALUE;  // reset the handle pointer that is shared
2004     // with _fpt so we don't free it twice
2005   }
2006 
2007   if (!_fpt)  freeHandles();
2008   return _fpt;
2009 #else
2010   _fpt=::popen(cmd,mode);
2011   return _fpt;
2012 #endif
2013 }
2014 
close()2015 int Fl_Process::close() {
2016 #if defined(WIN32)  && !defined(__CYGWIN__)
2017   if (_fpt) {
2018     fclose(_fpt);
2019     clean_close(perr[0]);
2020     clean_close(pin[1]);
2021     clean_close(pout[0]);
2022     _fpt = NULL;
2023     return 0;
2024   }
2025   return -1;
2026 #else
2027   int ret = ::pclose(_fpt);
2028   _fpt=NULL;
2029   return ret;
2030 #endif
2031 }
2032 
2033 #if defined(WIN32)  && !defined(__CYGWIN__)
clean_close(HANDLE & h)2034 void Fl_Process::clean_close(HANDLE& h) {
2035   if (h!= INVALID_HANDLE_VALUE) CloseHandle(h);
2036   h = INVALID_HANDLE_VALUE;
2037 }
2038 #endif
2039 // ********** Fl_Process class end **********
2040 
2041 static Fl_Process s_proc;
2042 
2043 // Shell command support...
2044 
prepare_shell_command(const char * & command)2045 static bool prepare_shell_command(const char * &command)  { // common pre-shell command code all platforms
2046   shell_window->hide();
2047   if (s_proc.desc()) {
2048     fl_alert("Previous shell command still running!");
2049     return false;
2050   }
2051   if ((command = shell_command_input->value()) == NULL || !*command) {
2052     fl_alert("No shell command entered!");
2053     return false;
2054   }
2055   if (shell_savefl_button->value()) {
2056     save_cb(0, 0);
2057   }
2058   if (shell_writecode_button->value()) {
2059     compile_only = 1;
2060     write_cb(0, 0);
2061     compile_only = 0;
2062   }
2063   if (shell_writemsgs_button->value()) {
2064     compile_only = 1;
2065     write_strings_cb(0, 0);
2066     compile_only = 0;
2067   }
2068   return true;
2069 }
2070 
2071 #if !defined(__MWERKS__)
2072 // Support the full piped shell command...
2073 void
shell_pipe_cb(int,void *)2074 shell_pipe_cb(int, void*) {
2075   char	line[1024]="";		// Line from command output...
2076 
2077   if (s_proc.get_line(line, sizeof(line)) != NULL) {
2078     // Add the line to the output list...
2079     shell_run_buffer->append(line);
2080   } else {
2081     // End of file; tell the parent...
2082     Fl::remove_fd(fileno(s_proc.desc()));
2083     s_proc.close();
2084     shell_run_buffer->append("... END SHELL COMMAND ...\n");
2085   }
2086 
2087   shell_run_display->scroll(shell_run_display->count_lines(0,
2088                             shell_run_buffer->length(), 1), 0);
2089 }
2090 
2091 void
do_shell_command(Fl_Return_Button *,void *)2092 do_shell_command(Fl_Return_Button*, void*) {
2093   const char	*command=NULL;	// Command to run
2094 
2095   if (!prepare_shell_command(command)) return;
2096 
2097   // Show the output window and clear things...
2098   shell_run_buffer->text("");
2099   shell_run_buffer->append(command);
2100   shell_run_buffer->append("\n");
2101   shell_run_window->label("Shell Command Running...");
2102 
2103   if (s_proc.popen((char *)command) == NULL) {
2104     fl_alert("Unable to run shell command: %s", strerror(errno));
2105     return;
2106   }
2107 
2108   shell_run_button->deactivate();
2109   shell_run_window->hotspot(shell_run_display);
2110   shell_run_window->show();
2111 
2112   Fl::add_fd(fileno(s_proc.desc()), shell_pipe_cb);
2113 
2114   while (s_proc.desc()) Fl::wait();
2115 
2116   shell_run_button->activate();
2117   shell_run_window->label("Shell Command Complete");
2118   fl_beep();
2119 
2120   while (shell_run_window->shown()) Fl::wait();
2121 }
2122 #else
2123 // Just do basic shell command stuff, no status window...
2124 void
do_shell_command(Fl_Return_Button *,void *)2125 do_shell_command(Fl_Return_Button*, void*) {
2126   const char	*command;	// Command to run
2127   int		status;		// Status from command...
2128 
2129   if (!prepare_shell_command(command)) return;
2130 
2131   if ((status = system(command)) != 0) {
2132     fl_alert("Shell command returned status %d!", status);
2133   } else if (completion_button->value()) {
2134     fl_message("Shell command completed successfully!");
2135   }
2136 }
2137 #endif // !__MWERKS__
2138 
2139 void
show_shell_window()2140 show_shell_window() {
2141   shell_window->hotspot(shell_command_input);
2142   shell_window->show();
2143 }
2144 
set_filename(const char * c)2145 void set_filename(const char *c) {
2146   if (filename) free((void *)filename);
2147   filename = c ? strdup(c) : NULL;
2148 
2149   if (filename) update_history(filename);
2150 
2151   set_modflag(modflag);
2152 }
2153 
2154 //
2155 // The Source View system offers an immediate preview of the code
2156 // files that will be generated by FLUID. It also marks the code
2157 // generated for the last selected item in the header and the source
2158 // file.
2159 //
2160 // Can we patent this?  ;-)  - Matt, mm@matthiasm.com
2161 //
2162 
2163 //
2164 // Update the header and source code highlighting depending on the
2165 // currently selected object
2166 //
update_sourceview_position()2167 void update_sourceview_position()
2168 {
2169   if (!sourceview_panel || !sourceview_panel->visible())
2170     return;
2171   if (sv_autoposition->value()==0)
2172     return;
2173   if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) {
2174     int pos0, pos1;
2175     if (sv_source->visible_r()) {
2176       pos0 = Fl_Type::current->code_position;
2177       pos1 = Fl_Type::current->code_position_end;
2178       if (pos0>=0) {
2179         if (pos1<pos0)
2180           pos1 = pos0;
2181         sv_source->buffer()->highlight(pos0, pos1);
2182         int line = sv_source->buffer()->count_lines(0, pos0);
2183         sv_source->scroll(line, 0);
2184       }
2185     }
2186     if (sv_header->visible_r()) {
2187       pos0 = Fl_Type::current->header_position;
2188       pos1 = Fl_Type::current->header_position_end;
2189       if (pos0>=0) {
2190         if (pos1<pos0)
2191           pos1 = pos0;
2192         sv_header->buffer()->highlight(pos0, pos1);
2193         int line = sv_header->buffer()->count_lines(0, pos0);
2194         sv_header->scroll(line, 0);
2195       }
2196     }
2197   }
2198 }
2199 
update_sourceview_position_cb(Fl_Tabs *,void *)2200 void update_sourceview_position_cb(Fl_Tabs*, void*)
2201 {
2202   update_sourceview_position();
2203 }
2204 
2205 static char *sv_source_filename = 0;
2206 static char *sv_header_filename = 0;
2207 
2208 //
2209 // Generate a header and source file in a temporary directory and
2210 // load those into the Code Viewer widgets.
2211 //
update_sourceview_cb(Fl_Button *,void *)2212 void update_sourceview_cb(Fl_Button*, void*)
2213 {
2214   if (!sourceview_panel || !sourceview_panel->visible())
2215     return;
2216   // generate space for the source and header file filenames
2217   if (!sv_source_filename) {
2218     sv_source_filename = (char*)malloc(FL_PATH_MAX);
2219     fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX);
2220     strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX);
2221   }
2222   if (!sv_header_filename) {
2223     sv_header_filename = (char*)malloc(FL_PATH_MAX);
2224     fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX);
2225     strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX);
2226   }
2227 
2228   strlcpy(i18n_program, fl_filename_name(sv_source_filename), sizeof(i18n_program));
2229   fl_filename_setext(i18n_program, sizeof(i18n_program), "");
2230   const char *code_file_name_bak = code_file_name;
2231   code_file_name = sv_source_filename;
2232   const char *header_file_name_bak = header_file_name;
2233   header_file_name = sv_header_filename;
2234 
2235   // generate the code and load the files
2236   write_sourceview = 1;
2237   // generate files
2238   if (write_code(sv_source_filename, sv_header_filename))
2239   {
2240     // load file into source editor
2241     int pos = sv_source->top_line();
2242     sv_source->buffer()->loadfile(sv_source_filename);
2243     sv_source->scroll(pos, 0);
2244     // load file into header editor
2245     pos = sv_header->top_line();
2246     sv_header->buffer()->loadfile(sv_header_filename);
2247     sv_header->scroll(pos, 0);
2248     // update the source code highlighting
2249     update_sourceview_position();
2250   }
2251   write_sourceview = 0;
2252 
2253   code_file_name = code_file_name_bak;
2254   header_file_name = header_file_name_bak;
2255 }
2256 
update_sourceview_timer(void *)2257 void update_sourceview_timer(void*)
2258 {
2259   update_sourceview_cb(0,0);
2260 }
2261 
2262 // Set the "modified" flag and update the title of the main window...
set_modflag(int mf)2263 void set_modflag(int mf) {
2264   const char	*basename;
2265   static char	title[FL_PATH_MAX];
2266 
2267   modflag = mf;
2268 
2269   if (main_window) {
2270     if (!filename) basename = "Untitled.fl";
2271     else if ((basename = strrchr(filename, '/')) != NULL) basename ++;
2272 #if defined(WIN32) || defined(__EMX__)
2273     else if ((basename = strrchr(filename, '\\')) != NULL) basename ++;
2274 #endif // WIN32 || __EMX__
2275     else basename = filename;
2276 
2277     if (modflag) {
2278       snprintf(title, sizeof(title), "%s (modified)", basename);
2279       main_window->label(title);
2280     } else main_window->label(basename);
2281   }
2282   // if the UI was modified in any way, update the Source View panel
2283   if (sourceview_panel && sourceview_panel->visible() && sv_autorefresh->value())
2284   {
2285     // we will only update ealiest 0.5 seconds after the last change, and only
2286     // if no other change was made, so dragging a widget will not generate any
2287     // CPU load
2288     Fl::remove_timeout(update_sourceview_timer, 0);
2289     Fl::add_timeout(0.5, update_sourceview_timer, 0);
2290   }
2291 
2292   // Enable/disable the Save menu item...
2293   if (modflag) save_item->activate();
2294   else save_item->deactivate();
2295 }
2296 
2297 ////////////////////////////////////////////////////////////////
2298 
arg(int argc,char ** argv,int & i)2299 static int arg(int argc, char** argv, int& i) {
2300   if (argv[i][1] == 'c' && !argv[i][2]) {compile_only = 1; i++; return 1;}
2301   if (argv[i][1] == 'c' && argv[i][2] == 's' && !argv[i][3]) {compile_only = 1; compile_strings = 1; i++; return 1;}
2302   if (argv[i][1] == 'o' && !argv[i][2] && i+1 < argc) {
2303     code_file_name = argv[i+1];
2304     code_file_set  = 1;
2305     i += 2;
2306     return 2;
2307   }
2308   if (argv[i][1] == 'h' && !argv[i][2]) {
2309     header_file_name = argv[i+1];
2310     header_file_set  = 1;
2311     i += 2;
2312     return 2;
2313   }
2314   Fl_Plugin_Manager pm("commandline");
2315   int j, n = pm.plugins();
2316   for (j=0; j<n; j++) {
2317     Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(j);
2318     int r = pi->arg(argc, argv, i);
2319     if (r) return r;
2320   }
2321   return 0;
2322 }
2323 
2324 #if ! (defined(WIN32) && !defined (__CYGWIN__))
2325 
2326 int quit_flag = 0;
2327 #include <signal.h>
2328 #ifdef _sigargs
2329 #define SIGARG _sigargs
2330 #else
2331 #ifdef __sigargs
2332 #define SIGARG __sigargs
2333 #else
2334 #define SIGARG int // you may need to fix this for older systems
2335 #endif
2336 #endif
2337 
2338 extern "C" {
sigint(SIGARG)2339 static void sigint(SIGARG) {
2340   signal(SIGINT,sigint);
2341   quit_flag = 1;
2342 }
2343 }
2344 #endif
2345 
2346 
main(int argc,char ** argv)2347 int main(int argc,char **argv) {
2348   int i = 1;
2349 
2350   if (!Fl::args(argc,argv,i,arg) || i < argc-1) {
2351     static const char *msg =
2352       "usage: %s <switches> name.fl\n"
2353       " -c : write .cxx and .h and exit\n"
2354       " -cs : write .cxx and .h and strings and exit\n"
2355       " -o <name> : .cxx output filename, or extension if <name> starts with '.'\n"
2356       " -h <name> : .h output filename, or extension if <name> starts with '.'\n";
2357     int len = strlen(msg) + strlen(argv[0]) + strlen(Fl::help);
2358     Fl_Plugin_Manager pm("commandline");
2359     int i, n = pm.plugins();
2360     for (i=0; i<n; i++) {
2361       Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(i);
2362       if (pi) len += strlen(pi->help());
2363     }
2364     char *buf = (char*)malloc(len+1);
2365     sprintf(buf, msg, argv[0]);
2366     for (i=0; i<n; i++) {
2367       Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(i);
2368       if (pi) strcat(buf, pi->help());
2369     }
2370     strcat(buf, Fl::help);
2371 #ifdef _MSC_VER
2372     fl_message("%s\n", buf);
2373 #else
2374     fprintf(stderr, "%s\n", buf);
2375 #endif
2376     free(buf);
2377     return 1;
2378   }
2379   if (exit_early)
2380     exit(0);
2381 
2382   const char *c = argv[i];
2383 
2384   fl_register_images();
2385 
2386   make_main_window();
2387 
2388 
2389   if (c) set_filename(c);
2390   if (!compile_only) {
2391 #ifdef __APPLE__
2392     fl_open_callback(apple_open_cb);
2393 #endif // __APPLE__
2394     Fl::visual((Fl_Mode)(FL_DOUBLE|FL_INDEX));
2395     Fl_File_Icon::load_system_icons();
2396     main_window->callback(exit_cb);
2397     position_window(main_window,"main_window_pos", 1, 10, 30, WINWIDTH, WINHEIGHT );
2398     main_window->show(argc,argv);
2399     toggle_widgetbin_cb(0,0);
2400     toggle_sourceview_cb(0,0);
2401     if (!c && openlast_button->value() && absolute_history[0][0]) {
2402       // Open previous file when no file specified...
2403       open_history_cb(0, absolute_history[0]);
2404     }
2405   }
2406   undo_suspend();
2407   if (c && !read_file(c,0)) {
2408     if (compile_only) {
2409       fprintf(stderr,"%s : %s\n", c, strerror(errno));
2410       exit(1);
2411     }
2412     fl_message("Can't read %s: %s", c, strerror(errno));
2413   }
2414   undo_resume();
2415   if (compile_only) {
2416     if (compile_strings) write_strings_cb(0,0);
2417     write_cb(0,0);
2418     exit(0);
2419   }
2420   set_modflag(0);
2421   undo_clear();
2422 #ifndef WIN32
2423   signal(SIGINT,sigint);
2424 #endif
2425 
2426   grid_cb(horizontal_input, 0); // Makes sure that windows get snap params...
2427 
2428 #ifdef WIN32
2429   Fl::run();
2430 #else
2431   while (!quit_flag) Fl::wait();
2432 
2433   if (quit_flag) exit_cb(0,0);
2434 #endif // WIN32
2435 
2436   undo_clear();
2437 
2438   return (0);
2439 }
2440 
2441 //
2442 // End of "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $".
2443 //
2444