source: rtems-graphics-toolkit/fltk-1.1.10/fluid/fluid.cxx @ 513eea1

Last change on this file since 513eea1 was 513eea1, checked in by Joel Sherrill <joel.sherrill@…>, on 01/09/10 at 22:43:24

2010-01-08 Joel Sherrill <joel.sherrill@…>

fltk 1.1.10. imported

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