2 // "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $"
4 // FLUID main entry for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
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.
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.
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
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
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>
48 #include <time.h> // time(), localtime(), etc.
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__
58 #if defined(WIN32) && !defined(__CYGWIN__)
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
70 # define getcwd _getcwd
71 # endif // !__WATCOMC__
76 # include <X11/Xlibint.h>
79 #include "about_panel.h"
86 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
91 # include <libpng/png.h>
93 #endif // HAVE_LIBPNG && HAVE_LIBZ
96 static Fl_Help_Dialog
*help_dialog
= 0;
98 Fl_Preferences
fluid_prefs(Fl_Preferences::USER
, "fltk.org", "fluid");
103 int show_comments
= 1;
104 int show_coredevmenus
= 1;
106 // File history info...
107 char absolute_history
[10][FL_PATH_MAX
];
108 char relative_history
[10][FL_PATH_MAX
];
111 void update_history(const char *);
113 // Shell command support...
114 void show_shell_window();
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;
121 ////////////////////////////////////////////////////////////////
123 static const char *filename
;
124 void set_filename(const char *c
);
125 void set_modflag(int mf
);
129 static char in_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;
139 pwd
= getcwd(0,FL_PATH_MAX
);
140 if (!pwd
) {fprintf(stderr
,"getwd : %s\n",strerror(errno
)); return;}
142 if (chdir(buffer
)<0) {fprintf(stderr
, "Can't chdir to %s : %s\n",
143 buffer
, strerror(errno
)); return;}
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
));}
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()) {
162 w
->resize( X
, Y
, W
, H
);
167 pos
.get("visible", Visible
, Visible
);
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()));
180 Fl_Window
*main_window
;
181 Fl_Menu_Bar
*main_menubar
;
183 static char* cutfname(int which
= 0) {
184 static char name
[2][FL_PATH_MAX
];
185 static char beenhere
= 0;
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]));
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
);
207 const char *basename
;
208 if ((basename
= strrchr(c
, '/')) != NULL
)
210 #if defined(WIN32) || defined(__EMX__)
211 if ((basename
= strrchr(c
, '\\')) != NULL
)
213 #endif // WIN32 || __EMX__
217 if (fl_choice("The file \"%s\" already exists.\n"
218 "Do you want to replace it?", "Cancel",
219 "Replace", NULL
, basename
) == 0) return;
222 if (v
!= (void *)2) set_filename(c
);
224 if (!write_file(c
)) {
225 fl_alert("Error writing %s: %s", c
, strerror(errno
));
229 if (v
!= (void *)2) {
231 undo_save
= undo_current
;
235 void save_template_cb(Fl_Widget
*, void *) {
236 // Setup the template panel...
237 if (!template_panel
) make_template_panel();
240 template_browser
->add("New Template");
243 template_name
->show();
244 template_name
->value("");
246 template_instance
->hide();
248 template_delete
->show();
249 template_delete
->deactivate();
251 template_submit
->label("Save");
252 template_submit
->deactivate();
254 template_panel
->label("Save Template");
256 // Show the panel and wait for the user to do something...
257 template_panel
->show();
258 while (template_panel
->shown()) Fl::wait();
260 // Get the template name, return if it is empty...
261 const char *c
= template_name
->value();
262 if (!c
|| !*c
) return;
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
= '_';
271 // Find the templates directory...
272 char filename
[FL_PATH_MAX
];
273 fluid_prefs
.getUserdataPath(filename
, sizeof(filename
));
275 strlcat(filename
, "templates", sizeof(filename
));
276 #if defined(WIN32) && !defined(__CYGWIN__)
277 if (access(filename
, 0)) mkdir(filename
);
279 if (access(filename
, 0)) mkdir(filename
, 0777);
280 #endif // WIN32 && !__CYGWIN__
282 strlcat(filename
, "/", sizeof(filename
));
283 strlcat(filename
, safename
, sizeof(filename
));
285 char *ext
= filename
+ strlen(filename
);
286 if (ext
>= (filename
+ sizeof(filename
) - 5)) {
287 fl_alert("The template name \"%s\" is too long!", c
);
291 // Save the .fl file...
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;
300 if (!write_file(filename
)) {
301 fl_alert("Error writing %s: %s", filename
, strerror(errno
));
305 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
306 // Get the screenshot, if any...
309 for (t
= Fl_Type::first
; t
; t
= t
->next
) {
310 // Find the first window...
311 if (t
->is_window()) break;
316 // Grab a screenshot...
317 Fl_Window_Type
*wt
= (Fl_Window_Type
*)t
;
321 if ((pixels
= wt
->read_image(w
, h
)) == NULL
) return;
323 // Save to a PNG file...
328 if ((fp
= fl_fopen(filename
, "wb")) == NULL
) {
330 fl_alert("Error writing %s: %s", filename
, strerror(errno
));
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
;
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
);
343 png_write_info(pptr
, iptr
);
345 for (int i
= h
; i
> 0; i
--, ptr
+= w
* 3) {
346 png_write_row(pptr
, ptr
);
349 png_write_end(pptr
, iptr
);
350 png_destroy_write_struct(&pptr
, &iptr
);
354 # if 0 // The original PPM output code...
356 fp
= fl_fopen(filename
, "wb");
357 fprintf(fp
, "P6\n%d %d 255\n", w
, h
);
358 fwrite(pixels
, w
* h
, 3, fp
);
363 #endif // HAVE_LIBPNG && HAVE_LIBZ
366 void revert_cb(Fl_Widget
*,void *) {
368 if (!fl_choice("This user interface has been changed. Really revert?",
369 "Cancel", "Revert", NULL
)) return;
372 if (!read_file(filename
, 0)) {
374 fl_message("Can't read %s: %s", filename
, strerror(errno
));
382 void exit_cb(Fl_Widget
*,void *) {
384 switch (fl_choice("Do you want to save changes to this user\n"
385 "interface before exiting?", "Cancel",
386 "Save", "Don't Save"))
388 case 0 : /* Cancel */
392 if (modflag
) return; // Didn't save!
395 save_position(main_window
,"main_window_pos");
397 if (widgetbin_panel
) {
398 save_position(widgetbin_panel
,"widgetbin_pos");
399 delete widgetbin_panel
;
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
;
423 apple_open_cb(const char *c
) {
425 switch (fl_choice("Do you want to save changes to this user\n"
426 "interface before opening another one?", "Don't Save",
429 case 0 : /* Cancel */
433 if (modflag
) return; // Didn't save!
436 const char *oldfilename
;
437 oldfilename
= filename
;
441 if (!read_file(c
, 0)) {
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
);
450 // Loaded a file; free the old filename...
454 if (oldfilename
) free((void *)oldfilename
);
458 void open_cb(Fl_Widget
*, void *v
) {
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"))
464 case 0 : /* Cancel */
468 if (modflag
) return; // Didn't save!
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
);
477 oldfilename
= filename
;
480 if (v
!= 0) undo_checkpoint();
482 if (!read_file(c
, v
!=0)) {
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
);
492 // Inserting a file; restore the original filename...
493 free((void *)filename
);
494 filename
= oldfilename
;
497 // Loaded a file; free the old filename...
500 if (oldfilename
) free((void *)oldfilename
);
504 void open_history_cb(Fl_Widget
*, void *v
) {
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"))
510 case 0 : /* Cancel */
514 if (modflag
) return; // Didn't save!
517 const char *oldfilename
= filename
;
519 set_filename((char *)v
);
521 if (!read_file(filename
, 0)) {
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
);
533 if (oldfilename
) free((void *)oldfilename
);
536 void new_cb(Fl_Widget
*, void *v
) {
537 // Check if the current file has been modified...
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"))
544 case 0 : /* Cancel */
548 if (modflag
) return; // Didn't save!
552 // Setup the template panel...
553 if (!template_panel
) make_template_panel();
556 template_browser
->add("Blank");
559 template_name
->hide();
560 template_name
->value("");
562 template_instance
->show();
563 template_instance
->deactivate();
564 template_instance
->value("");
566 template_delete
->hide();
568 template_submit
->label("New");
569 template_submit
->deactivate();
571 template_panel
->label("New");
573 // Show the panel and wait for the user to do something...
574 template_panel
->show();
575 while (template_panel
->shown()) Fl::wait();
577 // See if the user chose anything...
578 int item
= template_browser
->value();
579 if (item
< 1) return;
581 // Clear the current data...
585 // Load the template, if any...
586 const char *tname
= (const char *)template_browser
->data(item
);
589 // Grab the instance name...
590 const char *iname
= template_instance
->value();
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
;
597 if ((infile
= fl_fopen(tname
, "r")) == NULL
) {
598 fl_alert("Error reading template file \"%s\":\n%s", tname
,
605 if ((outfile
= fl_fopen(cutfname(1), "w")) == NULL
) {
606 fl_alert("Error writing buffer file \"%s\":\n%s", cutfname(1),
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
);
628 read_file(cutfname(1), 0);
632 // No instance name, so read the template without replacements...
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";
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
] = "";
657 void write_cb(Fl_Widget
*, void *) {
660 if (!filename
) return;
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
);
670 strlcpy(cname
, code_file_name
, sizeof(hname
));
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
);
676 strlcpy(hname
, header_file_name
, sizeof(hname
));
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
));
684 if (!x
) {fprintf(stderr
,"%s : %s\n",cname
,strerror(errno
)); exit(1);}
687 fl_message("Can't write %s: %s", cname
, strerror(errno
));
688 } else if (completion_button
->value()) {
689 fl_message("Wrote %s", cname
);
694 void write_strings_cb(Fl_Widget
*, void *) {
695 static const char *exts
[] = { ".txt", ".po", ".msg" };
698 if (!filename
) return;
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();
707 if (x
) {fprintf(stderr
,"%s : %s\n",sname
,strerror(errno
)); exit(1);}
710 fl_message("Can't write %s: %s", sname
, strerror(errno
));
711 } else if (completion_button
->value()) {
712 fl_message("Wrote %s", sname
);
717 void openwidget_cb(Fl_Widget
*, void *) {
718 if (!Fl_Type::current
) {
719 fl_message("Please select a widget");
722 Fl_Type::current
->open();
725 void toggle_overlays(Fl_Widget
*,void *);
727 void select_all_cb(Fl_Widget
*,void *);
728 void select_none_cb(Fl_Widget
*,void *);
730 void group_cb(Fl_Widget
*, void *);
732 void ungroup_cb(Fl_Widget
*, void *);
734 extern int pasteoffset
;
735 static int ipasteoffset
;
737 void copy_cb(Fl_Widget
*, void*) {
738 if (!Fl_Type::current
) {
743 if (!write_file(cutfname(),1)) {
744 fl_message("Can't write %s: %s", cutfname(), strerror(errno
));
749 extern void select_only(Fl_Type
*);
750 void cut_cb(Fl_Widget
*, void *) {
751 if (!Fl_Type::current
) {
755 if (!write_file(cutfname(),1)) {
756 fl_message("Can't write %s: %s", cutfname(), strerror(errno
));
762 Fl_Type
*p
= Fl_Type::current
->parent
;
763 while (p
&& p
->selected
) p
= p
->parent
;
765 if (p
) select_only(p
);
768 void delete_cb(Fl_Widget
*, void *) {
769 if (!Fl_Type::current
) {
776 Fl_Type
*p
= Fl_Type::current
->parent
;
777 while (p
&& p
->selected
) p
= p
->parent
;
779 if (p
) select_only(p
);
782 extern int force_parent
;
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
;
791 if (!read_file(cutfname(), 1)) {
792 fl_message("Can't read %s: %s", cutfname(), strerror(errno
));
800 // Duplicate the selected widgets...
801 void duplicate_cb(Fl_Widget
*, void*) {
802 if (!Fl_Type::current
) {
807 if (!write_file(cutfname(1),1)) {
808 fl_message("Can't write %s: %s", cutfname(1), strerror(errno
));
817 if (!read_file(cutfname(1), 1)) {
818 fl_message("Can't read %s: %s", cutfname(1), strerror(errno
));
826 void earlier_cb(Fl_Widget
*,void*);
828 void later_cb(Fl_Widget
*,void*);
830 Fl_Type
*sort(Fl_Type
*parent
);
832 static void sort_cb(Fl_Widget
*,void *) {
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 *);
841 void align_widget_cb(Fl_Widget
*, long);
842 void widget_size_cb(Fl_Widget
*, long);
844 void about_cb(Fl_Widget
*, void *) {
845 if (!about_panel
) make_about_panel();
849 void show_help(const char *name
) {
851 char helpname
[FL_PATH_MAX
];
853 if (!help_dialog
) help_dialog
= new Fl_Help_Dialog();
855 if ((docdir
= getenv("FLTK_DOCDIR")) == NULL
) {
857 // Doesn't make sense to have a hardcoded fallback
858 static char fltk_docdir
[FL_PATH_MAX
];
860 strlcpy(fltk_docdir
, __XOS2RedirRoot("/XFree86/lib/X11/fltk/doc"),
861 sizeof(fltk_docdir
));
863 docdir
= fltk_docdir
;
865 docdir
= FLTK_DOCDIR
;
868 snprintf(helpname
, sizeof(helpname
), "%s/%s", docdir
, name
);
870 // make sure that we can read the file
871 FILE *f
= fopen(helpname
, "rb");
874 help_dialog
->load(helpname
);
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
));
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>"
908 } else if (strcmp(name
, "license.html")==0) {
909 fl_open_uri("http://www.fltk.org/doc-1.3/license.html");
911 } else if (strcmp(name
, "index.html")==0) {
912 fl_open_uri("http://www.fltk.org/doc-1.3/index.html");
915 snprintf(helpname
, sizeof(helpname
), "http://www.fltk.org/%s", name
);
916 fl_open_uri(helpname
);
923 void help_cb(Fl_Widget
*, void *) {
924 show_help("fluid.html");
927 void manual_cb(Fl_Widget
*, void *) {
928 show_help("index.html");
932 ////////////////////////////////////////////////////////////////
934 #if defined(WIN32) && !defined(__CYGWIN__)
935 // Draw a shaded box...
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
);
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);
949 // Load and show the print dialog...
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
962 // Show print dialog...
963 for (t
= Fl_Type::first
, num_pages
= 0; t
; t
= t
->next
) {
964 if (t
->is_window()) num_pages
++;
967 memset(&dialog
, 0, sizeof(dialog
));
968 dialog
.lStructSize
= sizeof(dialog
);
969 dialog
.hwndOwner
= fl_xid(main_window
);
970 dialog
.Flags
= PD_ALLPAGES
|
972 dialog
.nFromPage
= 1;
973 dialog
.nToPage
= num_pages
;
975 dialog
.nMaxPage
= num_pages
;
978 if (!PrintDlg(&dialog
)) return;
980 // Get the base filename...
981 const char *basename
= strrchr(filename
, '/');
982 if (basename
) basename
++;
983 else basename
= filename
;
985 // Do the print job...
986 memset(&docinfo
, 0, sizeof(docinfo
));
987 docinfo
.cbSize
= sizeof(docinfo
);
988 docinfo
.lpszDocName
= basename
;
990 StartDoc(dialog
.hDC
, &docinfo
);
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
;
999 // Swap first/last page
1005 // Print everything...
1007 last
= dialog
.nMaxPage
;
1010 for (t
= Fl_Type::first
, num_windows
= 0, winpage
= 0; t
; t
= t
->next
) {
1011 if (t
->is_window()) {
1013 windows
[num_windows
] = (Fl_Window_Type
*)t
;
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
++;
1024 num_pages
= num_windows
;
1026 // Figure out the page size and margins...
1027 int width
, length
; // Size of page
1028 int xdpi
, ydpi
; // Output resolution
1031 width
= GetDeviceCaps(dialog
.hDC
, HORZRES
);
1032 length
= GetDeviceCaps(dialog
.hDC
, VERTRES
);
1033 xdpi
= GetDeviceCaps(dialog
.hDC
, LOGPIXELSX
);
1034 ydpi
= GetDeviceCaps(dialog
.hDC
, LOGPIXELSY
);
1036 // fl_message("width=%d, length=%d, xdpi=%d, ydpi=%d, num_windows=%d\n",
1037 // width, length, xdpi, ydpi, num_windows);
1039 HDC save_dc
= fl_gc
;
1040 HWND save_win
= fl_window
;
1041 int fontsize
= 14 * ydpi
/ 72;
1044 fl_window
= (HWND
)dialog
.hDC
;
1047 // Get the time and date...
1048 time_t curtime
= time(NULL
);
1049 struct tm
*curdate
= localtime(&curtime
);
1052 strftime(date
, sizeof(date
), "%c", curdate
);
1054 // Print each of the windows...
1055 for (winpage
= 0; winpage
< num_windows
; winpage
++) {
1057 StartPage(dialog
.hDC
);
1059 fl_font(FL_HELVETICA_BOLD
, fontsize
);
1062 fl_draw(basename
, 0, fontsize
);
1064 fl_draw(date
, (width
- (int)fl_width(date
)) / 2, fontsize
);
1066 sprintf(buffer
, "%d/%d", winpage
+ 1, num_windows
);
1067 fl_draw(buffer
, width
- (int)fl_width(buffer
), fontsize
);
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
1077 win
= (Fl_Window
*)(windows
[winpage
]->o
);
1078 pixels
= windows
[winpage
]->read_image(w
, h
);
1080 // Swap colors: FLTK uses R-G-B --> Windows GDI uses B-G-R
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
;
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;
1095 hh
= h
* ww
* ydpi
/ xdpi
/ w
;
1098 if (hh
> (length
- ydpi
/ 2)) {
1099 hh
= length
- ydpi
/ 2;
1103 // Position the window in the center...
1104 ulx
= (width
- ww
) / 2;
1105 uly
= (length
- hh
) / 2;
1107 // fl_message("winpage=%d, ulx=%d, uly=%d, ww=%d, hh=%d",
1108 // winpage, ulx, uly, ww, hh);
1110 // Draw a simulated window border...
1111 int xborder
= 4 * ww
/ w
;
1112 int yborder
= 4 * hh
/ h
;
1114 win_box(ulx
- xborder
, uly
- 5 * yborder
,
1115 ww
+ 2 * xborder
, hh
+ 6 * yborder
);
1117 fl_color(0, 0, 255);
1118 fl_rectf(ulx
, uly
- 4 * yborder
, ww
, 4 * yborder
);
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
);
1125 int x
= ulx
+ ww
- 4 * xborder
;
1127 win_box(x
, uly
- 4 * yborder
, 4 * xborder
, 4 * yborder
);
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
);
1135 if (win
->resizable()) {
1136 win_box(x
, uly
- 4 * yborder
, 4 * xborder
, 4 * yborder
);
1138 fl_rect(x
+ xborder
, uly
- 3 * yborder
, 2 * xborder
, 2 * yborder
);
1142 if (!win
->modal()) {
1143 win_box(x
, uly
- 4 * yborder
, 4 * xborder
, 4 * yborder
);
1145 fl_line(x
+ xborder
, uly
- yborder
, x
+ 3 * xborder
, uly
- yborder
);
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
;
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
);
1166 EndPage(dialog
.hDC
);
1173 fl_window
= save_win
;
1176 // Free the print DC and return...
1177 DeleteDC(dialog
.hDC
);
1180 // Load and show the print dialog...
1181 void print_menu_cb(Fl_Widget
*, void *) {
1182 if (!print_panel
) make_print_panel();
1186 print_selection
->deactivate();
1188 for (Fl_Type
*t
= Fl_Type::first
; t
; t
= t
->next
) {
1189 if (t
->selected
&& t
->is_window()) {
1190 print_selection
->activate();
1195 print_all
->setonly();
1196 print_all
->do_callback();
1198 print_panel
->show();
1201 // Quote a string for PostScript printing
1202 static const char *ps_string(const char *s
) {
1204 static char buffer
[FL_PATH_MAX
];
1210 for (bufptr
= buffer
; bufptr
< (buffer
+ sizeof(buffer
) - 3) && *s
;) {
1211 if (*s
== '(' || *s
== ')' || *s
== '\\') *bufptr
++ = '\\';
1221 // Actually print...
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
1234 // Show progress, deactivate controls...
1235 print_panel_controls
->deactivate();
1236 print_progress
->show();
1238 // Figure out how many pages we'll have to print...
1239 if (print_collate_button
->value()) copies
= (int)print_copies
->value();
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;
1248 // Swap first/last page
1254 // Print everything...
1259 for (t
= Fl_Type::first
, num_windows
= 0, winpage
= 0; t
; t
= t
->next
) {
1260 if (t
->is_window()) {
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
++;
1271 num_pages
= num_windows
* copies
;
1273 print_progress
->minimum(0);
1274 print_progress
->maximum(num_pages
);
1275 print_progress
->value(0);
1278 // Get the base filename...
1279 const char *basename
= strrchr(filename
, '/');
1280 if (basename
) basename
++;
1281 else basename
= filename
;
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();
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");
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
);
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
;
1304 if (outname
) outfile
= fl_fopen(outname
, "w");
1305 else outfile
= NULL
;
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
1314 if (print_page_size
->value()) {
1325 for (output_mode
= 0; output_mode
< 4; output_mode
++) {
1326 if (print_output_mode
[output_mode
]->value()) break;
1329 if (output_mode
& 1) {
1333 right
= length
- 36;
1343 // Get the time and date...
1344 time_t curtime
= time(NULL
);
1345 struct tm
*curdate
= localtime(&curtime
);
1348 strftime(date
, sizeof(date
), "%c", curdate
);
1350 // Write the prolog...
1353 "%%%%BoundingBox: 18 36 %d %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"
1363 "%%languagelevel 1 eq {\n"
1365 " newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
1366 " neg 0 exch rlineto closepath fill\n"
1369 " newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
1370 " neg 0 exch rlineto closepath stroke\n"
1375 "%%%%BeginFeature: *PageSize %s\n"
1376 "languagelevel 1 ne {\n"
1377 " <</PageSize[%d %d]/ImagingBBox null>>setpagedevice\n"
1383 width
- 18, length
- 36,
1388 print_page_size
->text(print_page_size
->value()),
1390 print_page_size
->value() ? "a4tray" : "lettertray");
1392 // Print each of the windows...
1393 char progress
[255]; // Progress text
1394 int copy
; // Current copy
1396 for (copy
= 0, page
= 0; copy
< copies
; copy
++) {
1397 for (winpage
= 0; winpage
< num_pages
; winpage
++) {
1398 // Start next page...
1400 sprintf(progress
, "Printing page %d/%d...", page
, num_pages
);
1401 print_progress
->value(page
);
1402 print_progress
->label(progress
);
1405 // Add common page stuff...
1411 if (output_mode
& 1) {
1413 fprintf(outfile
, "%d 0 translate 90 rotate\n", width
);
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
);
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
1436 win
= (Fl_Window
*)(windows
[winpage
]->o
);
1437 pixels
= windows
[winpage
]->read_image(w
, h
);
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;
1444 if (ww
> (right
- left
)) {
1449 if (hh
> (top
- bottom
- 36)) {
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
);
1462 // Draw a simulated window border...
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
);
1477 if (output_mode
& 2) {
1478 fputs("0.25 setgray\n", outfile
);
1480 fputs("0.1 0.2 0.6 setrgbcolor\n", outfile
);
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
,
1489 if (win
->resizable()) {
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
);
1501 // Inside outline and button shading...
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",
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
);
1512 if (!win
->modal() || win
->resizable()) {
1513 fprintf(outfile
, "%.2f %.2f moveto 0 %.2f rlineto\n",
1514 urx
- 28 * border
, ury
, 16 * border
);
1517 if (!win
->modal() && win
->resizable()) {
1518 fprintf(outfile
, "%.2f %.2f moveto 0 %.2f rlineto\n",
1519 urx
- 44 * border
, ury
, 16 * border
);
1522 fprintf(outfile
, "%.2f %.2f moveto %.2f 0 rlineto stroke\n",
1523 llx
- 3.5 * border
, ury
+ 0.5 * border
, ww
+ 7 * border
);
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",
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
);
1534 float x
= urx
- 16 * border
;
1536 if (win
->resizable()) {
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
);
1547 if (!win
->modal()) {
1550 "%.2f %.2f moveto -%.2f 0 rlineto\n",
1551 x
, ury
+ 4 * border
, 8 * border
);
1554 fputs("stroke\n", outfile
);
1557 // Add window title...
1560 "/Helvetica-Bold findfont %.2f scalefont setfont\n"
1561 "(%s) %.2f %.2f moveto show\n",
1563 ps_string(win
->label()), llx
+ 16 * border
, ury
+ 4 * border
);
1568 "%.2f %.2f translate %.2f %.2f scale\n",
1569 llx
, ury
- border
, border
, border
);
1571 if (output_mode
& 2) {
1572 // Grayscale image...
1574 "/imgdata %d string def\n"
1575 "%d %d 8[1 0 0 -1 0 1] "
1576 "{currentfile imgdata readhexstring pop} image\n",
1580 uchar
*ptr
= pixels
;
1581 int i
, count
= w
* h
;
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
);
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",
1597 uchar
*ptr
= pixels
;
1598 int i
, count
= w
* h
;
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
);
1606 fputs("\ngrestore\n", outfile
);
1611 fputs("grestore showpage\n", outfile
);
1616 fputs("%%EOF\n", outfile
);
1618 if (print_choice
->value()) pclose(outfile
);
1619 else fclose(outfile
);
1621 // Unable to print...
1622 fl_alert("Error printing: %s", strerror(errno
));
1625 // Hide progress, activate controls, hide print panel...
1626 print_panel_controls
->activate();
1627 print_progress
->hide();
1628 print_panel
->hide();
1630 #endif // WIN32 && !__CYGWIN__
1632 ////////////////////////////////////////////////////////////////
1634 extern Fl_Menu_Item New_Menu
[];
1636 void toggle_widgetbin_cb(Fl_Widget
*, void *);
1637 void toggle_sourceview_cb(Fl_Double_Window
*, void *);
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
},
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
},
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},
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},
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},
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},
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},
1718 {"&Grid and Size Settings...",FL_COMMAND
+'g',show_grid_cb
},
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
},
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
},
1731 #define BROWSERWIDTH 300
1732 #define BROWSERHEIGHT 500
1733 #define WINWIDTH 300
1734 #define MENUHEIGHT 25
1735 #define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT)
1737 extern void fill_in_New_Menu();
1739 void scheme_cb(Fl_Choice
*, void *) {
1744 void toggle_widgetbin_cb(Fl_Widget
*, void *) {
1745 if (!widgetbin_panel
) {
1747 if (!position_window(widgetbin_panel
,"widgetbin_pos", 1, 320, 30)) return;
1750 if (widgetbin_panel
->visible()) {
1751 widgetbin_panel
->hide();
1752 widgetbin_item
->label("Show Widget &Bin...");
1754 widgetbin_panel
->show();
1755 widgetbin_item
->label("Hide Widget &Bin");
1760 void toggle_sourceview_cb(Fl_Double_Window
*, void *) {
1761 if (!sourceview_panel
) {
1763 sourceview_panel
->callback((Fl_Callback
*)toggle_sourceview_cb
);
1764 Fl_Preferences
svp(fluid_prefs
, "sourceview");
1766 svp
.get("autorefresh", autorefresh
, 1);
1767 sv_autorefresh
->value(autorefresh
);
1769 svp
.get("autoposition", autoposition
, 1);
1770 sv_autoposition
->value(autoposition
);
1772 svp
.get("tab", tab
, 0);
1773 if (tab
>=0 && tab
<sv_tab
->children()) sv_tab
->value(sv_tab
->child(tab
));
1774 if (!position_window(sourceview_panel
,"sourceview_pos", 0, 320, 120, 550, 500)) return;
1777 if (sourceview_panel
->visible()) {
1778 sourceview_panel
->hide();
1779 sourceview_item
->label("Show Source Code...");
1781 sourceview_panel
->show();
1782 sourceview_item
->label("Hide Source Code...");
1783 update_sourceview_cb(0,0);
1787 void toggle_sourceview_b_cb(Fl_Button
*, void *) {
1788 toggle_sourceview_cb(0,0);
1791 void make_main_window() {
1792 if (!compile_only
) {
1793 fluid_prefs
.get("snap", snap
, 1);
1794 fluid_prefs
.get("gridx", gridx
, 5);
1795 fluid_prefs
.get("gridy", gridy
, 5);
1796 fluid_prefs
.get("show_guides", show_guides
, 0);
1797 fluid_prefs
.get("widget_size", Fl_Widget_Type::default_size
, 14);
1798 fluid_prefs
.get("show_comments", show_comments
, 1);
1799 make_layout_window();
1800 make_shell_window();
1805 main_window
= new Fl_Double_Window(WINWIDTH
,WINHEIGHT
,"fluid");
1806 main_window
->box(FL_NO_BOX
);
1807 o
= make_widget_browser(0,MENUHEIGHT
,BROWSERWIDTH
,BROWSERHEIGHT
);
1808 o
->box(FL_FLAT_BOX
);
1809 o
->tooltip("Double-click to view or change an item.");
1810 main_window
->resizable(o
);
1811 main_menubar
= new Fl_Menu_Bar(0,0,BROWSERWIDTH
,MENUHEIGHT
);
1812 main_menubar
->menu(Main_Menu
);
1813 // quick access to all dynamic menu items
1814 save_item
= (Fl_Menu_Item
*)main_menubar
->find_item(save_cb
);
1815 history_item
= (Fl_Menu_Item
*)main_menubar
->find_item(open_history_cb
);
1816 widgetbin_item
= (Fl_Menu_Item
*)main_menubar
->find_item(toggle_widgetbin_cb
);
1817 sourceview_item
= (Fl_Menu_Item
*)main_menubar
->find_item((Fl_Callback
*)toggle_sourceview_cb
);
1818 main_menubar
->global();
1823 if (!compile_only
) {
1825 make_settings_window();
1826 make_global_settings_window();
1830 // Load file history from preferences...
1831 void load_history() {
1832 int i
; // Looping var
1836 fluid_prefs
.get("recent_files", max_files
, 5);
1837 if (max_files
> 10) max_files
= 10;
1839 for (i
= 0; i
< max_files
; i
++) {
1840 fluid_prefs
.get( Fl_Preferences::Name("file%d", i
), absolute_history
[i
], "", sizeof(absolute_history
[i
]));
1841 if (absolute_history
[i
][0]) {
1842 // Make a relative version of the filename for the menu...
1843 fl_filename_relative(relative_history
[i
], sizeof(relative_history
[i
]),
1844 absolute_history
[i
]);
1846 if (i
== 9) history_item
[i
].flags
= FL_MENU_DIVIDER
;
1847 else history_item
[i
].flags
= 0;
1851 for (; i
< 10; i
++) {
1852 if (i
) history_item
[i
-1].flags
|= FL_MENU_DIVIDER
;
1853 history_item
[i
].hide();
1857 // Update file history from preferences...
1858 void update_history(const char *flname
) {
1859 int i
; // Looping var
1860 char absolute
[FL_PATH_MAX
];
1864 fluid_prefs
.get("recent_files", max_files
, 5);
1865 if (max_files
> 10) max_files
= 10;
1867 fl_filename_absolute(absolute
, sizeof(absolute
), flname
);
1869 for (i
= 0; i
< max_files
; i
++)
1870 #if defined(WIN32) || defined(__APPLE__)
1871 if (!strcasecmp(absolute
, absolute_history
[i
])) break;
1873 if (!strcmp(absolute
, absolute_history
[i
])) break;
1874 #endif // WIN32 || __APPLE__
1878 if (i
>= max_files
) i
= max_files
- 1;
1880 // Move the other flnames down in the list...
1881 memmove(absolute_history
+ 1, absolute_history
,
1882 i
* sizeof(absolute_history
[0]));
1883 memmove(relative_history
+ 1, relative_history
,
1884 i
* sizeof(relative_history
[0]));
1886 // Put the new file at the top...
1887 strlcpy(absolute_history
[0], absolute
, sizeof(absolute_history
[0]));
1889 fl_filename_relative(relative_history
[0], sizeof(relative_history
[0]),
1890 absolute_history
[0]);
1892 // Update the menu items as needed...
1893 for (i
= 0; i
< max_files
; i
++) {
1894 fluid_prefs
.set( Fl_Preferences::Name("file%d", i
), absolute_history
[i
]);
1895 if (absolute_history
[i
][0]) {
1896 if (i
== 9) history_item
[i
].flags
= FL_MENU_DIVIDER
;
1897 else history_item
[i
].flags
= 0;
1901 for (; i
< 10; i
++) {
1902 fluid_prefs
.set( Fl_Preferences::Name("file%d", i
), "");
1903 if (i
) history_item
[i
-1].flags
|= FL_MENU_DIVIDER
;
1904 history_item
[i
].hide();
1908 // ********** portable process class definition **********
1912 // construction / destruction
1913 Fl_Process() {_fpt
= NULL
;}
1914 ~Fl_Process() {if (_fpt
) close();}
1916 // FIXME: popen needs the utf8 equivalen fl_popen
1917 FILE * popen (const char *cmd
, const char *mode
="r");
1918 //not necessary here: FILE * fl_fopen (const char *file, const char *mode="r");
1921 FILE * desc() const { return _fpt
;} // non null if file is open
1922 char * get_line(char * line
, size_t s
) const {return _fpt
? fgets(line
, s
, _fpt
) : NULL
;}
1924 #if defined(WIN32) && !defined(__CYGWIN__)
1926 HANDLE pin
[2], pout
[2], perr
[2];
1928 PROCESS_INFORMATION pi
;
1931 static bool createPipe(HANDLE
* h
, BOOL bInheritHnd
=TRUE
);
1934 FILE * freeHandles() {
1935 clean_close(pin
[0]); clean_close(pin
[1]);
1936 clean_close(pout
[0]); clean_close(pout
[1]);
1937 clean_close(perr
[0]); clean_close(perr
[1]);
1938 return NULL
; // convenient for error management
1940 static void clean_close(HANDLE
& h
);
1947 #if defined(WIN32) && !defined(__CYGWIN__)
1948 bool Fl_Process::createPipe(HANDLE
* h
, BOOL bInheritHnd
) {
1949 SECURITY_ATTRIBUTES sa
;
1950 sa
.nLength
= sizeof(sa
);
1951 sa
.lpSecurityDescriptor
= NULL
;
1952 sa
.bInheritHandle
= bInheritHnd
;
1953 return CreatePipe (&h
[0],&h
[1],&sa
,0) ? true : false;
1956 // portable open process:
1957 FILE * Fl_Process::popen(const char *cmd
, const char *mode
) {
1958 #if defined(WIN32) && !defined(__CYGWIN__)
1960 if (!mode
|| !*mode
|| (*mode
!='r' && *mode
!='w') ) return NULL
;
1961 if (_fpt
) close(); // close first before reuse
1964 pin
[0] = pin
[1] = pout
[0] = pout
[1] = perr
[0] = perr
[1] = INVALID_HANDLE_VALUE
;
1965 // stderr to stdout wanted ?
1966 int fusion
= (strstr(cmd
,"2>&1") !=NULL
);
1968 // Create windows pipes
1969 if (!createPipe(pin
) || !createPipe(pout
) || (!fusion
&& !createPipe(perr
) ) )
1970 return freeHandles(); // error
1972 // Initialize Startup Info
1973 ZeroMemory(&si
, sizeof(STARTUPINFO
));
1974 si
.cb
= sizeof(STARTUPINFO
);
1975 si
.dwFlags
= STARTF_USESTDHANDLES
;
1976 si
.hStdInput
= pin
[0];
1977 si
.hStdOutput
= pout
[1];
1978 si
.hStdError
= fusion
? pout
[1] : perr
[1];
1980 if ( CreateProcess(NULL
, (LPTSTR
) cmd
,NULL
,NULL
,TRUE
,
1981 DETACHED_PROCESS
,NULL
,NULL
, &si
, &pi
)) {
1982 // don't need theses handles inherited by child process:
1983 clean_close(pin
[0]); clean_close(pout
[1]); clean_close(perr
[1]);
1984 HANDLE
& h
= *mode
== 'r' ? pout
[0] : pin
[1];
1985 _fpt
= _fdopen(_open_osfhandle((fl_intptr_t
) h
,_O_BINARY
),mode
);
1986 h
= INVALID_HANDLE_VALUE
; // reset the handle pointer that is shared
1987 // with _fpt so we don't free it twice
1990 if (!_fpt
) freeHandles();
1993 _fpt
=::popen(cmd
,mode
);
1998 int Fl_Process::close() {
1999 #if defined(WIN32) && !defined(__CYGWIN__)
2002 clean_close(perr
[0]);
2003 clean_close(pin
[1]);
2004 clean_close(pout
[0]);
2010 int ret
= ::pclose(_fpt
);
2016 #if defined(WIN32) && !defined(__CYGWIN__)
2017 void Fl_Process::clean_close(HANDLE
& h
) {
2018 if (h
!= INVALID_HANDLE_VALUE
) CloseHandle(h
);
2019 h
= INVALID_HANDLE_VALUE
;
2022 // ********** Fl_Process class end **********
2024 static Fl_Process s_proc
;
2026 // Shell command support...
2028 static bool prepare_shell_command(const char * &command
) { // common pre-shell command code all platforms
2029 shell_window
->hide();
2030 if (s_proc
.desc()) {
2031 fl_alert("Previous shell command still running!");
2034 if ((command
= shell_command_input
->value()) == NULL
|| !*command
) {
2035 fl_alert("No shell command entered!");
2038 if (shell_savefl_button
->value()) {
2041 if (shell_writecode_button
->value()) {
2046 if (shell_writemsgs_button
->value()) {
2048 write_strings_cb(0, 0);
2054 #if !defined(__MWERKS__)
2055 // Support the full piped shell command...
2057 shell_pipe_cb(int, void*) {
2058 char line
[1024]=""; // Line from command output...
2060 if (s_proc
.get_line(line
, sizeof(line
)) != NULL
) {
2061 // Add the line to the output list...
2062 shell_run_buffer
->append(line
);
2064 // End of file; tell the parent...
2065 Fl::remove_fd(fileno(s_proc
.desc()));
2067 shell_run_buffer
->append("... END SHELL COMMAND ...\n");
2070 shell_run_display
->scroll(shell_run_display
->count_lines(0,
2071 shell_run_buffer
->length(), 1), 0);
2075 do_shell_command(Fl_Return_Button
*, void*) {
2076 const char *command
=NULL
; // Command to run
2078 if (!prepare_shell_command(command
)) return;
2080 // Show the output window and clear things...
2081 shell_run_buffer
->text("");
2082 shell_run_buffer
->append(command
);
2083 shell_run_buffer
->append("\n");
2084 shell_run_window
->label("Shell Command Running...");
2086 if (s_proc
.popen((char *)command
) == NULL
) {
2087 fl_alert("Unable to run shell command: %s", strerror(errno
));
2091 shell_run_button
->deactivate();
2092 shell_run_window
->hotspot(shell_run_display
);
2093 shell_run_window
->show();
2095 Fl::add_fd(fileno(s_proc
.desc()), shell_pipe_cb
);
2097 while (s_proc
.desc()) Fl::wait();
2099 shell_run_button
->activate();
2100 shell_run_window
->label("Shell Command Complete");
2103 while (shell_run_window
->shown()) Fl::wait();
2106 // Just do basic shell command stuff, no status window...
2108 do_shell_command(Fl_Return_Button
*, void*) {
2109 const char *command
; // Command to run
2110 int status
; // Status from command...
2112 if (!prepare_shell_command(command
)) return;
2114 if ((status
= system(command
)) != 0) {
2115 fl_alert("Shell command returned status %d!", status
);
2116 } else if (completion_button
->value()) {
2117 fl_message("Shell command completed successfully!");
2120 #endif // !__MWERKS__
2123 show_shell_window() {
2124 shell_window
->hotspot(shell_command_input
);
2125 shell_window
->show();
2128 void set_filename(const char *c
) {
2129 if (filename
) free((void *)filename
);
2130 filename
= c
? strdup(c
) : NULL
;
2132 if (filename
) update_history(filename
);
2134 set_modflag(modflag
);
2138 // The Source View system offers an immediate preview of the code
2139 // files that will be generated by FLUID. It also marks the code
2140 // generated for the last selected item in the header and the source
2143 // Can we patent this? ;-) - Matt, mm@matthiasm.com
2147 // Update the header and source code highlighting depending on the
2148 // currently selected object
2150 void update_sourceview_position()
2152 if (!sourceview_panel
|| !sourceview_panel
->visible())
2154 if (sv_autoposition
->value()==0)
2156 if (sourceview_panel
&& sourceview_panel
->visible() && Fl_Type::current
) {
2158 if (sv_source
->visible_r()) {
2159 pos0
= Fl_Type::current
->code_position
;
2160 pos1
= Fl_Type::current
->code_position_end
;
2164 sv_source
->buffer()->highlight(pos0
, pos1
);
2165 int line
= sv_source
->buffer()->count_lines(0, pos0
);
2166 sv_source
->scroll(line
, 0);
2169 if (sv_header
->visible_r()) {
2170 pos0
= Fl_Type::current
->header_position
;
2171 pos1
= Fl_Type::current
->header_position_end
;
2175 sv_header
->buffer()->highlight(pos0
, pos1
);
2176 int line
= sv_header
->buffer()->count_lines(0, pos0
);
2177 sv_header
->scroll(line
, 0);
2183 void update_sourceview_position_cb(Fl_Tabs
*, void*)
2185 update_sourceview_position();
2188 static char *sv_source_filename
= 0;
2189 static char *sv_header_filename
= 0;
2192 // Generate a header and source file in a temporary directory and
2193 // load those into the Code Viewer widgets.
2195 void update_sourceview_cb(Fl_Button
*, void*)
2197 if (!sourceview_panel
|| !sourceview_panel
->visible())
2199 // generate space for the source and header file filenames
2200 if (!sv_source_filename
) {
2201 sv_source_filename
= (char*)malloc(FL_PATH_MAX
);
2202 fluid_prefs
.getUserdataPath(sv_source_filename
, FL_PATH_MAX
);
2203 strlcat(sv_source_filename
, "source_view_tmp.cxx", FL_PATH_MAX
);
2205 if (!sv_header_filename
) {
2206 sv_header_filename
= (char*)malloc(FL_PATH_MAX
);
2207 fluid_prefs
.getUserdataPath(sv_header_filename
, FL_PATH_MAX
);
2208 strlcat(sv_header_filename
, "source_view_tmp.h", FL_PATH_MAX
);
2211 strlcpy(i18n_program
, fl_filename_name(sv_source_filename
), sizeof(i18n_program
));
2212 fl_filename_setext(i18n_program
, sizeof(i18n_program
), "");
2213 const char *code_file_name_bak
= code_file_name
;
2214 code_file_name
= sv_source_filename
;
2215 const char *header_file_name_bak
= header_file_name
;
2216 header_file_name
= sv_header_filename
;
2218 // generate the code and load the files
2219 write_sourceview
= 1;
2221 if (write_code(sv_source_filename
, sv_header_filename
))
2223 // load file into source editor
2224 int pos
= sv_source
->top_line();
2225 sv_source
->buffer()->loadfile(sv_source_filename
);
2226 sv_source
->scroll(pos
, 0);
2227 // load file into header editor
2228 pos
= sv_header
->top_line();
2229 sv_header
->buffer()->loadfile(sv_header_filename
);
2230 sv_header
->scroll(pos
, 0);
2231 // update the source code highlighting
2232 update_sourceview_position();
2234 write_sourceview
= 0;
2236 code_file_name
= code_file_name_bak
;
2237 header_file_name
= header_file_name_bak
;
2240 void update_sourceview_timer(void*)
2242 update_sourceview_cb(0,0);
2245 // Set the "modified" flag and update the title of the main window...
2246 void set_modflag(int mf
) {
2247 const char *basename
;
2248 static char title
[FL_PATH_MAX
];
2253 if (!filename
) basename
= "Untitled.fl";
2254 else if ((basename
= strrchr(filename
, '/')) != NULL
) basename
++;
2255 #if defined(WIN32) || defined(__EMX__)
2256 else if ((basename
= strrchr(filename
, '\\')) != NULL
) basename
++;
2257 #endif // WIN32 || __EMX__
2258 else basename
= filename
;
2261 snprintf(title
, sizeof(title
), "%s (modified)", basename
);
2262 main_window
->label(title
);
2263 } else main_window
->label(basename
);
2265 // if the UI was modified in any way, update the Source View panel
2266 if (sourceview_panel
&& sourceview_panel
->visible() && sv_autorefresh
->value())
2268 // we will only update ealiest 0.5 seconds after the last change, and only
2269 // if no other change was made, so dragging a widget will not generate any
2271 Fl::remove_timeout(update_sourceview_timer
, 0);
2272 Fl::add_timeout(0.5, update_sourceview_timer
, 0);
2275 // Enable/disable the Save menu item...
2276 if (modflag
) save_item
->activate();
2277 else save_item
->deactivate();
2280 ////////////////////////////////////////////////////////////////
2282 static int arg(int argc
, char** argv
, int& i
) {
2283 if (argv
[i
][1] == 'c' && !argv
[i
][2]) {compile_only
= 1; i
++; return 1;}
2284 if (argv
[i
][1] == 'c' && argv
[i
][2] == 's' && !argv
[i
][3]) {compile_only
= 1; compile_strings
= 1; i
++; return 1;}
2285 if (argv
[i
][1] == 'o' && !argv
[i
][2] && i
+1 < argc
) {
2286 code_file_name
= argv
[i
+1];
2291 if (argv
[i
][1] == 'h' && !argv
[i
][2]) {
2292 header_file_name
= argv
[i
+1];
2293 header_file_set
= 1;
2297 Fl_Plugin_Manager
pm("commandline");
2298 int j
, n
= pm
.plugins();
2299 for (j
=0; j
<n
; j
++) {
2300 Fl_Commandline_Plugin
*pi
= (Fl_Commandline_Plugin
*)pm
.plugin(j
);
2301 int r
= pi
->arg(argc
, argv
, i
);
2307 #if ! (defined(WIN32) && !defined (__CYGWIN__))
2312 #define SIGARG _sigargs
2315 #define SIGARG __sigargs
2317 #define SIGARG int // you may need to fix this for older systems
2322 static void sigint(SIGARG
) {
2323 signal(SIGINT
,sigint
);
2330 int main(int argc
,char **argv
) {
2333 if (!Fl::args(argc
,argv
,i
,arg
) || i
< argc
-1) {
2334 static const char *msg
=
2335 "usage: %s <switches> name.fl\n"
2336 " -c : write .cxx and .h and exit\n"
2337 " -cs : write .cxx and .h and strings and exit\n"
2338 " -o <name> : .cxx output filename, or extension if <name> starts with '.'\n"
2339 " -h <name> : .h output filename, or extension if <name> starts with '.'\n";
2340 int len
= strlen(msg
) + strlen(argv
[0]) + strlen(Fl::help
);
2341 Fl_Plugin_Manager
pm("commandline");
2342 int i
, n
= pm
.plugins();
2343 for (i
=0; i
<n
; i
++) {
2344 Fl_Commandline_Plugin
*pi
= (Fl_Commandline_Plugin
*)pm
.plugin(i
);
2345 if (pi
) len
+= strlen(pi
->help());
2347 char *buf
= (char*)malloc(len
+1);
2348 sprintf(buf
, msg
, argv
[0]);
2349 for (i
=0; i
<n
; i
++) {
2350 Fl_Commandline_Plugin
*pi
= (Fl_Commandline_Plugin
*)pm
.plugin(i
);
2351 if (pi
) strcat(buf
, pi
->help());
2353 strcat(buf
, Fl::help
);
2355 fl_message("%s\n", buf
);
2357 fprintf(stderr
, "%s\n", buf
);
2365 const char *c
= argv
[i
];
2367 fl_register_images();
2372 if (c
) set_filename(c
);
2373 if (!compile_only
) {
2375 fl_open_callback(apple_open_cb
);
2377 Fl::visual((Fl_Mode
)(FL_DOUBLE
|FL_INDEX
));
2378 Fl_File_Icon::load_system_icons();
2379 main_window
->callback(exit_cb
);
2380 position_window(main_window
,"main_window_pos", 1, 10, 30, WINWIDTH
, WINHEIGHT
);
2381 main_window
->show(argc
,argv
);
2382 toggle_widgetbin_cb(0,0);
2383 toggle_sourceview_cb(0,0);
2384 if (!c
&& openlast_button
->value() && absolute_history
[0][0]) {
2385 // Open previous file when no file specified...
2386 open_history_cb(0, absolute_history
[0]);
2390 if (c
&& !read_file(c
,0)) {
2392 fprintf(stderr
,"%s : %s\n", c
, strerror(errno
));
2395 fl_message("Can't read %s: %s", c
, strerror(errno
));
2399 if (compile_strings
) write_strings_cb(0,0);
2406 signal(SIGINT
,sigint
);
2409 grid_cb(horizontal_input
, 0); // Makes sure that windows get snap params...
2414 while (!quit_flag
) Fl::wait();
2416 if (quit_flag
) exit_cb(0,0);
2425 // End of "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $".