You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2427 lines
68KB

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