Clean up some inconsistencies in themes.
[ntk.git] / fluid / fluid.cxx
blobe1832f0049f43870b5b2ed9d3c2879ed7dcbda25
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.
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
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
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.
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__)
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
79 #include "about_panel.h"
80 #include "undo.h"
82 #include "Fl_Type.h"
84 extern "C"
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
96 static Fl_Help_Dialog *help_dialog = 0;
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;
106 // File history info...
107 char absolute_history[10][FL_PATH_MAX];
108 char relative_history[10][FL_PATH_MAX];
110 void load_history();
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);
126 int modflag;
128 static char* pwd;
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;
138 if (!pwd) {
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;}
144 in_source_dir = 1;
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;
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 );
164 else
165 w->position( X, Y );
167 pos.get("visible", Visible, Visible);
168 return 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;
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]));
195 return name[which];
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;
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;
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));
226 return;
229 if (v != (void *)2) {
230 set_modflag(0);
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();
239 template_clear();
240 template_browser->add("New Template");
241 template_load();
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);
278 #else
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);
288 return;
291 // Save the .fl file...
292 strcpy(ext, ".fl");
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));
302 return;
305 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
306 // Get the screenshot, if any...
307 Fl_Type *t;
309 for (t = Fl_Type::first; t; t = t->next) {
310 // Find the first window...
311 if (t->is_window()) break;
314 if (!t) return;
316 // Grab a screenshot...
317 Fl_Window_Type *wt = (Fl_Window_Type *)t;
318 uchar *pixels;
319 int w, h;
321 if ((pixels = wt->read_image(w, h)) == NULL) return;
323 // Save to a PNG file...
324 strcpy(ext, ".png");
326 FILE *fp;
328 if ((fp = fl_fopen(filename, "wb")) == NULL) {
329 delete[] pixels;
330 fl_alert("Error writing %s: %s", filename, strerror(errno));
331 return;
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);
352 fclose(fp);
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
362 delete[] pixels;
363 #endif // HAVE_LIBPNG && HAVE_LIBZ
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;
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;
377 undo_resume();
378 set_modflag(0);
379 undo_clear();
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"))
388 case 0 : /* Cancel */
389 return;
390 case 1 : /* Save */
391 save_cb(NULL, NULL);
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;
409 if (about_panel)
410 delete about_panel;
411 if (help_dialog)
412 delete help_dialog;
414 undo_clear();
416 exit(0);
419 #ifdef __APPLE__
420 # include <FL/x.H>
422 void
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"))
429 case 0 : /* Cancel */
430 return;
431 case 1 : /* Save */
432 save_cb(NULL, NULL);
433 if (modflag) return; // Didn't save!
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;
450 // Loaded a file; free the old filename...
451 set_modflag(0);
452 undo_resume();
453 undo_clear();
454 if (oldfilename) free((void *)oldfilename);
456 #endif // __APPLE__
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"))
464 case 0 : /* Cancel */
465 return;
466 case 1 : /* Save */
467 save_cb(NULL, NULL);
468 if (modflag) return; // Didn't save!
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;
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);
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"))
510 case 0 : /* Cancel */
511 return;
512 case 1 : /* Save */
513 save_cb(NULL, NULL);
514 if (modflag) return; // Didn't save!
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;
530 set_modflag(0);
531 undo_resume();
532 undo_clear();
533 if (oldfilename) free((void *)oldfilename);
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"))
544 case 0 : /* Cancel */
545 return;
546 case 1 : /* Save */
547 save_cb(NULL, NULL);
548 if (modflag) return; // Didn't save!
552 // Setup the template panel...
553 if (!template_panel) make_template_panel();
555 template_clear();
556 template_browser->add("Blank");
557 template_load();
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...
582 delete_all();
583 set_filename(NULL);
585 // Load the template, if any...
586 const char *tname = (const char *)template_browser->data(item);
588 if (tname) {
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,
599 strerror(errno));
600 set_modflag(0);
601 undo_clear();
602 return;
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;
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);
621 fputs(ptr, outfile);
624 fclose(infile);
625 fclose(outfile);
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();
639 set_modflag(0);
640 undo_clear();
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] = "";
657 void write_cb(Fl_Widget *, void *) {
658 if (!filename) {
659 save_cb(0,0);
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);
669 } else {
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);
675 } else {
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));
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);
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;
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);
717 void openwidget_cb(Fl_Widget *, void *) {
718 if (!Fl_Type::current) {
719 fl_message("Please select a widget");
720 return;
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) {
739 fl_beep();
740 return;
742 ipasteoffset = 10;
743 if (!write_file(cutfname(),1)) {
744 fl_message("Can't write %s: %s", cutfname(), strerror(errno));
745 return;
749 extern void select_only(Fl_Type *);
750 void cut_cb(Fl_Widget *, void *) {
751 if (!Fl_Type::current) {
752 fl_beep();
753 return;
755 if (!write_file(cutfname(),1)) {
756 fl_message("Can't write %s: %s", cutfname(), strerror(errno));
757 return;
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);
768 void delete_cb(Fl_Widget *, void *) {
769 if (!Fl_Type::current) {
770 fl_beep();
771 return;
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);
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;
789 undo_checkpoint();
790 undo_suspend();
791 if (!read_file(cutfname(), 1)) {
792 fl_message("Can't read %s: %s", cutfname(), strerror(errno));
794 undo_resume();
795 pasteoffset = 0;
796 ipasteoffset += 10;
797 force_parent = 0;
800 // Duplicate the selected widgets...
801 void duplicate_cb(Fl_Widget*, void*) {
802 if (!Fl_Type::current) {
803 fl_beep();
804 return;
807 if (!write_file(cutfname(1),1)) {
808 fl_message("Can't write %s: %s", cutfname(1), strerror(errno));
809 return;
812 pasteoffset = 0;
813 force_parent = 1;
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));
820 unlink(cutfname(1));
821 undo_resume();
823 force_parent = 0;
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 *) {
833 sort((Fl_Type*)0);
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();
846 about_panel->show();
849 void show_help(const char *name) {
850 const char *docdir;
851 char helpname[FL_PATH_MAX];
853 if (!help_dialog) help_dialog = new Fl_Help_Dialog();
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];
860 strlcpy(fltk_docdir, __XOS2RedirRoot("/XFree86/lib/X11/fltk/doc"),
861 sizeof(fltk_docdir));
863 docdir = fltk_docdir;
864 #else
865 docdir = FLTK_DOCDIR;
866 #endif // __EMX__
868 snprintf(helpname, sizeof(helpname), "%s/%s", docdir, name);
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
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>"
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;
920 help_dialog->show();
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);
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);
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 |
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;
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;
998 if (first > last) {
999 // Swap first/last page
1000 page = first;
1001 first = last;
1002 last = page;
1004 } else {
1005 // Print everything...
1006 first = 1;
1007 last = dialog.nMaxPage;
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
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
1029 char buffer[1024];
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;
1043 fl_gc = dialog.hDC;
1044 fl_window = (HWND)dialog.hDC;
1045 fl_push_no_clip();
1047 // Get the time and date...
1048 time_t curtime = time(NULL);
1049 struct tm *curdate = localtime(&curtime);
1050 char date[1024];
1052 strftime(date, sizeof(date), "%c", curdate);
1054 // Print each of the windows...
1055 for (winpage = 0; winpage < num_windows; winpage ++) {
1056 // Draw header...
1057 StartPage(dialog.hDC);
1059 fl_font(FL_HELVETICA_BOLD, fontsize);
1060 fl_color(0, 0, 0);
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;
1093 if (ww > width) {
1094 ww = width;
1095 hh = h * ww * ydpi / xdpi / w;
1098 if (hh > (length - ydpi / 2)) {
1099 hh = length - ydpi / 2;
1100 ww = w * hh / h;
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);
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;
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;
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;
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;
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);
1163 delete[] pixels;
1165 // Show the page...
1166 EndPage(dialog.hDC);
1169 // Finish up...
1170 EndDoc(dialog.hDC);
1172 fl_gc = save_dc;
1173 fl_window = save_win;
1174 fl_pop_clip();
1176 // Free the print DC and return...
1177 DeleteDC(dialog.hDC);
1179 #else
1180 // Load and show the print dialog...
1181 void print_menu_cb(Fl_Widget *, void *) {
1182 if (!print_panel) make_print_panel();
1184 print_load();
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();
1191 break;
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) {
1203 char *bufptr;
1204 static char buffer[FL_PATH_MAX];
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++;
1215 *bufptr = '\0';
1218 return (buffer);
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();
1240 else copies = 1;
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;
1247 if (first > last) {
1248 // Swap first/last page
1249 page = first;
1250 first = last;
1251 last = page;
1253 } else {
1254 // Print everything...
1255 first = 1;
1256 last = 1000;
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 ++;
1271 num_pages = num_windows * copies;
1273 print_progress->minimum(0);
1274 print_progress->maximum(num_pages);
1275 print_progress->value(0);
1276 Fl::check();
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");
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);
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;
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
1314 if (print_page_size->value()) {
1315 // A4
1316 width = 595;
1317 length = 842;
1318 } else {
1319 // Letter
1320 width = 612;
1321 length = 792;
1324 int output_mode;
1325 for (output_mode = 0; output_mode < 4; output_mode ++) {
1326 if (print_output_mode[output_mode]->value()) break;
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;
1343 // Get the time and date...
1344 time_t curtime = time(NULL);
1345 struct tm *curdate = localtime(&curtime);
1346 char date[1024];
1348 strftime(date, sizeof(date), "%c", curdate);
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");
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...
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();
1405 // Add common page stuff...
1406 fprintf(outfile,
1407 "%%%%Page: %d %d\n"
1408 "gsave\n",
1409 page, page);
1411 if (output_mode & 1) {
1412 // Landscape...
1413 fprintf(outfile, "%d 0 translate 90 rotate\n", width);
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);
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)) {
1445 ww = right - left;
1446 hh = h * ww / w;
1449 if (hh > (top - bottom - 36)) {
1450 hh = top - bottom;
1451 ww = w * hh / h;
1454 border = ww / w;
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...
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);
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);
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);
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);
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);
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);
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);
1534 float x = urx - 16 * border;
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);
1544 x -= 16 * border;
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);
1554 fputs("stroke\n", outfile);
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);
1566 fprintf(outfile,
1567 "gsave\n"
1568 "%.2f %.2f translate %.2f %.2f scale\n",
1569 llx, ury - border, border, border);
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",
1578 w, h);
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);
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);
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);
1608 delete[] pixels;
1610 // Show the page...
1611 fputs("grestore showpage\n", outfile);
1615 // Finish up...
1616 fputs("%%EOF\n", outfile);
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));
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},
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}};
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 *) {
1740 if (compile_only)
1741 return;
1744 void toggle_widgetbin_cb(Fl_Widget *, void *) {
1745 if (!widgetbin_panel) {
1746 make_widgetbin();
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...");
1753 } else {
1754 widgetbin_panel->show();
1755 widgetbin_item->label("Hide Widget &Bin");
1760 void toggle_sourceview_cb(Fl_Double_Window *, void *) {
1761 if (!sourceview_panel) {
1762 make_sourceview();
1763 sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb);
1764 Fl_Preferences svp(fluid_prefs, "sourceview");
1765 int autorefresh;
1766 svp.get("autorefresh", autorefresh, 1);
1767 sv_autorefresh->value(autorefresh);
1768 int autoposition;
1769 svp.get("autoposition", autoposition, 1);
1770 sv_autoposition->value(autoposition);
1771 int tab;
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...");
1780 } else {
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();
1803 if (!main_window) {
1804 Fl_Widget *o;
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();
1819 fill_in_New_Menu();
1820 main_window->end();
1823 if (!compile_only) {
1824 load_history();
1825 make_settings_window();
1826 make_global_settings_window();
1830 // Load file history from preferences...
1831 void load_history() {
1832 int i; // Looping var
1833 int max_files;
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;
1848 } else break;
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];
1861 int max_files;
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;
1872 #else
1873 if (!strcmp(absolute, absolute_history[i])) break;
1874 #endif // WIN32 || __APPLE__
1876 if (i == 0) return;
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;
1898 } else break;
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 **********
1910 class Fl_Process {
1911 public:
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");
1919 int close();
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__)
1925 protected:
1926 HANDLE pin[2], pout[2], perr[2];
1927 char ptmode;
1928 PROCESS_INFORMATION pi;
1929 STARTUPINFO si;
1931 static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE);
1933 private:
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);
1941 #endif
1943 protected:
1944 FILE * _fpt;
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;
1955 #endif
1956 // portable open process:
1957 FILE * Fl_Process::popen(const char *cmd, const char *mode) {
1958 #if defined(WIN32) && !defined(__CYGWIN__)
1959 // PRECONDITIONS
1960 if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL;
1961 if (_fpt) close(); // close first before reuse
1963 ptmode = *mode;
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();
1991 return _fpt;
1992 #else
1993 _fpt=::popen(cmd,mode);
1994 return _fpt;
1995 #endif
1998 int Fl_Process::close() {
1999 #if defined(WIN32) && !defined(__CYGWIN__)
2000 if (_fpt) {
2001 fclose(_fpt);
2002 clean_close(perr[0]);
2003 clean_close(pin[1]);
2004 clean_close(pout[0]);
2005 _fpt = NULL;
2006 return 0;
2008 return -1;
2009 #else
2010 int ret = ::pclose(_fpt);
2011 _fpt=NULL;
2012 return ret;
2013 #endif
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;
2021 #endif
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!");
2032 return false;
2034 if ((command = shell_command_input->value()) == NULL || !*command) {
2035 fl_alert("No shell command entered!");
2036 return false;
2038 if (shell_savefl_button->value()) {
2039 save_cb(0, 0);
2041 if (shell_writecode_button->value()) {
2042 compile_only = 1;
2043 write_cb(0, 0);
2044 compile_only = 0;
2046 if (shell_writemsgs_button->value()) {
2047 compile_only = 1;
2048 write_strings_cb(0, 0);
2049 compile_only = 0;
2051 return true;
2054 #if !defined(__MWERKS__)
2055 // Support the full piped shell command...
2056 void
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);
2063 } else {
2064 // End of file; tell the parent...
2065 Fl::remove_fd(fileno(s_proc.desc()));
2066 s_proc.close();
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);
2074 void
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));
2088 return;
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");
2101 fl_beep();
2103 while (shell_run_window->shown()) Fl::wait();
2105 #else
2106 // Just do basic shell command stuff, no status window...
2107 void
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__
2122 void
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
2141 // file.
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())
2153 return;
2154 if (sv_autoposition->value()==0)
2155 return;
2156 if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) {
2157 int pos0, pos1;
2158 if (sv_source->visible_r()) {
2159 pos0 = Fl_Type::current->code_position;
2160 pos1 = Fl_Type::current->code_position_end;
2161 if (pos0>=0) {
2162 if (pos1<pos0)
2163 pos1 = pos0;
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;
2172 if (pos0>=0) {
2173 if (pos1<pos0)
2174 pos1 = pos0;
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())
2198 return;
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;
2220 // generate files
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];
2250 modflag = mf;
2252 if (main_window) {
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;
2260 if (modflag) {
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
2270 // CPU load
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];
2287 code_file_set = 1;
2288 i += 2;
2289 return 2;
2291 if (argv[i][1] == 'h' && !argv[i][2]) {
2292 header_file_name = argv[i+1];
2293 header_file_set = 1;
2294 i += 2;
2295 return 2;
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);
2302 if (r) return r;
2304 return 0;
2307 #if ! (defined(WIN32) && !defined (__CYGWIN__))
2309 int quit_flag = 0;
2310 #include <signal.h>
2311 #ifdef _sigargs
2312 #define SIGARG _sigargs
2313 #else
2314 #ifdef __sigargs
2315 #define SIGARG __sigargs
2316 #else
2317 #define SIGARG int // you may need to fix this for older systems
2318 #endif
2319 #endif
2321 extern "C" {
2322 static void sigint(SIGARG) {
2323 signal(SIGINT,sigint);
2324 quit_flag = 1;
2327 #endif
2330 int main(int argc,char **argv) {
2331 int i = 1;
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);
2354 #ifdef _MSC_VER
2355 fl_message("%s\n", buf);
2356 #else
2357 fprintf(stderr, "%s\n", buf);
2358 #endif
2359 free(buf);
2360 return 1;
2362 if (exit_early)
2363 exit(0);
2365 const char *c = argv[i];
2367 fl_register_images();
2369 make_main_window();
2372 if (c) set_filename(c);
2373 if (!compile_only) {
2374 #ifdef __APPLE__
2375 fl_open_callback(apple_open_cb);
2376 #endif // __APPLE__
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]);
2389 undo_suspend();
2390 if (c && !read_file(c,0)) {
2391 if (compile_only) {
2392 fprintf(stderr,"%s : %s\n", c, strerror(errno));
2393 exit(1);
2395 fl_message("Can't read %s: %s", c, strerror(errno));
2397 undo_resume();
2398 if (compile_only) {
2399 if (compile_strings) write_strings_cb(0,0);
2400 write_cb(0,0);
2401 exit(0);
2403 set_modflag(0);
2404 undo_clear();
2405 #ifndef WIN32
2406 signal(SIGINT,sigint);
2407 #endif
2409 grid_cb(horizontal_input, 0); // Makes sure that windows get snap params...
2411 #ifdef WIN32
2412 Fl::run();
2413 #else
2414 while (!quit_flag) Fl::wait();
2416 if (quit_flag) exit_cb(0,0);
2417 #endif // WIN32
2419 undo_clear();
2421 return (0);
2425 // End of "$Id: fluid.cxx 8801 2011-06-10 13:37:07Z manolo $".