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