Fl_win32.cxx and Fl_x.cxx modified for: ====================================== - STR# 2029 fix: async select using USE_ASYNC_SELECT def. would not work. Obsoleted and commented as discussed - STR# 2032 fix: fl_ready would load wsock dll unnecessarily. Bad indents corrected fluid.cxx modifed for: ====================== Added a local portable Fl_Process class to fluid enabling popen encapsulated win32 impl. based on CreateProcess() to work as expected in non console apps, so that exec command output window is now also implemented in win32, also permitting testing add_fd()/remove_fd() API relying on winsock on win32. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6188 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
2337 lines
64 KiB
C++
2337 lines
64 KiB
C++
//
|
|
// "$Id$"
|
|
//
|
|
// FLUID main entry for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 1998-2007 by Bill Spitzak and others.
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Library General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Library General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
// USA.
|
|
//
|
|
// Please report all bugs and problems on the following page:
|
|
//
|
|
// http://www.fltk.org/str.php
|
|
//
|
|
|
|
#include <FL/Fl.H>
|
|
#include <FL/Fl_Double_Window.H>
|
|
#include <FL/Fl_Box.H>
|
|
#include <FL/Fl_Button.H>
|
|
#include <FL/Fl_File_Icon.H>
|
|
#include <FL/Fl_Help_Dialog.H>
|
|
#include <FL/Fl_Hold_Browser.H>
|
|
#include <FL/Fl_Menu_Bar.H>
|
|
#include <FL/Fl_Input.H>
|
|
#include <FL/fl_ask.H>
|
|
#include <FL/fl_draw.H>
|
|
#include <FL/Fl_File_Chooser.H>
|
|
#include <FL/fl_message.H>
|
|
#include <FL/filename.H>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h> // time(), localtime(), etc.
|
|
|
|
#include "../src/flstring.h"
|
|
#include "alignment_panel.h"
|
|
#include "function_panel.h"
|
|
#include "template_panel.h"
|
|
#if !defined(WIN32) || defined(__CYGWIN__)
|
|
# include "print_panel.cxx"
|
|
#endif // !WIN32 || __CYGWIN__
|
|
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
# include <direct.h>
|
|
# include <windows.h>
|
|
# include <io.h>
|
|
# include <FCNTL.H>
|
|
# include <commdlg.h>
|
|
# include <FL/x.H>
|
|
# ifndef __WATCOMC__
|
|
// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
|
|
// on Windows, which is supposed to be POSIX compliant...
|
|
# define access _access
|
|
# define chdir _chdir
|
|
# define getcwd _getcwd
|
|
# endif // !__WATCOMC__
|
|
#else
|
|
# include <unistd.h>
|
|
#endif
|
|
#ifdef __EMX__
|
|
# include <X11/Xlibint.h>
|
|
#endif
|
|
|
|
#include "about_panel.h"
|
|
#include "undo.h"
|
|
|
|
#include "Fl_Type.h"
|
|
|
|
extern "C"
|
|
{
|
|
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
|
|
# include <zlib.h>
|
|
# ifdef HAVE_PNG_H
|
|
# include <png.h>
|
|
# else
|
|
# include <libpng/png.h>
|
|
# endif // HAVE_PNG_H
|
|
#endif // HAVE_LIBPNG && HAVE_LIBZ
|
|
}
|
|
|
|
static Fl_Help_Dialog *help_dialog = 0;
|
|
|
|
Fl_Preferences fluid_prefs(Fl_Preferences::USER, "fltk.org", "fluid");
|
|
int gridx = 5;
|
|
int gridy = 5;
|
|
int snap = 1;
|
|
int show_guides = 1;
|
|
|
|
// File history info...
|
|
char absolute_history[10][1024];
|
|
char relative_history[10][1024];
|
|
|
|
void load_history();
|
|
void update_history(const char *);
|
|
|
|
// Shell command support...
|
|
void show_shell_window();
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static const char *filename;
|
|
void set_filename(const char *c);
|
|
void set_modflag(int mf);
|
|
int modflag;
|
|
|
|
static char* pwd;
|
|
static char in_source_dir;
|
|
void goto_source_dir() {
|
|
if (in_source_dir) return;
|
|
if (!filename || !*filename) return;
|
|
const char *p = fl_filename_name(filename);
|
|
if (p <= filename) return; // it is in the current directory
|
|
char buffer[1024];
|
|
strlcpy(buffer, filename, sizeof(buffer));
|
|
int n = p-filename; if (n>1) n--; buffer[n] = 0;
|
|
if (!pwd) {
|
|
pwd = getcwd(0,1024);
|
|
if (!pwd) {fprintf(stderr,"getwd : %s\n",strerror(errno)); return;}
|
|
}
|
|
if (chdir(buffer)<0) {fprintf(stderr, "Can't chdir to %s : %s\n",
|
|
buffer, strerror(errno)); return;}
|
|
in_source_dir = 1;
|
|
}
|
|
|
|
void leave_source_dir() {
|
|
if (!in_source_dir) return;
|
|
if (chdir(pwd)<0) {fprintf(stderr, "Can't chdir to %s : %s\n",
|
|
pwd, strerror(errno));}
|
|
in_source_dir = 0;
|
|
}
|
|
|
|
char position_window(Fl_Window *w, const char *prefsName, int Visible, int X, int Y, int W=0, int H=0 ) {
|
|
Fl_Preferences pos(fluid_prefs, prefsName);
|
|
if (prevpos_button->value()) {
|
|
pos.get("x", X, X);
|
|
pos.get("y", Y, Y);
|
|
if ( W!=0 ) {
|
|
pos.get("w", W, W);
|
|
pos.get("h", H, H);
|
|
w->resize( X, Y, W, H );
|
|
}
|
|
else
|
|
w->position( X, Y );
|
|
}
|
|
pos.get("visible", Visible, Visible);
|
|
return Visible;
|
|
}
|
|
|
|
void save_position(Fl_Window *w, const char *prefsName) {
|
|
Fl_Preferences pos(fluid_prefs, prefsName);
|
|
pos.set("x", w->x());
|
|
pos.set("y", w->y());
|
|
pos.set("w", w->w());
|
|
pos.set("h", w->h());
|
|
pos.set("visible", (int)(w->shown() && w->visible()));
|
|
}
|
|
|
|
Fl_Window *main_window;
|
|
Fl_Menu_Bar *main_menubar;
|
|
|
|
static char* cutfname(int which = 0) {
|
|
static char name[2][1024];
|
|
static char beenhere = 0;
|
|
|
|
if (!beenhere) {
|
|
beenhere = 1;
|
|
fluid_prefs.getUserdataPath(name[0], sizeof(name[0]));
|
|
strlcat(name[0], "cut_buffer", sizeof(name[0]));
|
|
fluid_prefs.getUserdataPath(name[1], sizeof(name[1]));
|
|
strlcat(name[1], "dup_buffer", sizeof(name[1]));
|
|
}
|
|
|
|
return name[which];
|
|
}
|
|
|
|
void save_cb(Fl_Widget *, void *v) {
|
|
const char *c = filename;
|
|
if (v || !c || !*c) {
|
|
fl_file_chooser_ok_label("Save");
|
|
c=fl_file_chooser("Save To:", "FLUID Files (*.f[ld])", c);
|
|
fl_file_chooser_ok_label(NULL);
|
|
if (!c) return;
|
|
|
|
if (!access(c, 0)) {
|
|
const char *basename;
|
|
if ((basename = strrchr(c, '/')) != NULL)
|
|
basename ++;
|
|
#if defined(WIN32) || defined(__EMX__)
|
|
if ((basename = strrchr(c, '\\')) != NULL)
|
|
basename ++;
|
|
#endif // WIN32 || __EMX__
|
|
else
|
|
basename = c;
|
|
|
|
if (fl_choice("The file \"%s\" already exists.\n"
|
|
"Do you want to replace it?", "Cancel",
|
|
"Replace", NULL, basename) == 0) return;
|
|
}
|
|
|
|
if (v != (void *)2) set_filename(c);
|
|
}
|
|
if (!write_file(c)) {
|
|
fl_alert("Error writing %s: %s", c, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
if (v != (void *)2) {
|
|
set_modflag(0);
|
|
undo_save = undo_current;
|
|
}
|
|
}
|
|
|
|
void save_template_cb(Fl_Widget *, void *) {
|
|
// Setup the template panel...
|
|
if (!template_panel) make_template_panel();
|
|
|
|
template_clear();
|
|
template_browser->add("New Template");
|
|
template_load();
|
|
|
|
template_name->show();
|
|
template_name->value("");
|
|
|
|
template_instance->hide();
|
|
|
|
template_delete->show();
|
|
template_delete->deactivate();
|
|
|
|
template_submit->label("Save");
|
|
template_submit->deactivate();
|
|
|
|
template_panel->label("Save Template");
|
|
|
|
// Show the panel and wait for the user to do something...
|
|
template_panel->show();
|
|
while (template_panel->shown()) Fl::wait();
|
|
|
|
// Get the template name, return if it is empty...
|
|
const char *c = template_name->value();
|
|
if (!c || !*c) return;
|
|
|
|
// Convert template name to filename_with_underscores
|
|
char safename[1024], *safeptr;
|
|
strlcpy(safename, c, sizeof(safename));
|
|
for (safeptr = safename; *safeptr; safeptr ++) {
|
|
if (isspace(*safeptr)) *safeptr = '_';
|
|
}
|
|
|
|
// Find the templates directory...
|
|
char filename[1024];
|
|
fluid_prefs.getUserdataPath(filename, sizeof(filename));
|
|
|
|
strlcat(filename, "templates", sizeof(filename));
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
if (access(filename, 0)) mkdir(filename);
|
|
#else
|
|
if (access(filename, 0)) mkdir(filename, 0777);
|
|
#endif // WIN32 && !__CYGWIN__
|
|
|
|
strlcat(filename, "/", sizeof(filename));
|
|
strlcat(filename, safename, sizeof(filename));
|
|
|
|
char *ext = filename + strlen(filename);
|
|
if (ext >= (filename + sizeof(filename) - 5)) {
|
|
fl_alert("The template name \"%s\" is too long!", c);
|
|
return;
|
|
}
|
|
|
|
// Save the .fl file...
|
|
strcpy(ext, ".fl");
|
|
|
|
if (!access(filename, 0)) {
|
|
if (fl_choice("The template \"%s\" already exists.\n"
|
|
"Do you want to replace it?", "Cancel",
|
|
"Replace", NULL, c) == 0) return;
|
|
}
|
|
|
|
if (!write_file(filename)) {
|
|
fl_alert("Error writing %s: %s", filename, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
|
|
// Get the screenshot, if any...
|
|
Fl_Type *t;
|
|
|
|
for (t = Fl_Type::first; t; t = t->next) {
|
|
// Find the first window...
|
|
if (t->is_window()) break;
|
|
}
|
|
|
|
if (!t) return;
|
|
|
|
// Grab a screenshot...
|
|
Fl_Window_Type *wt = (Fl_Window_Type *)t;
|
|
uchar *pixels;
|
|
int w, h;
|
|
|
|
if ((pixels = wt->read_image(w, h)) == NULL) return;
|
|
|
|
// Save to a PNG file...
|
|
strcpy(ext, ".png");
|
|
|
|
FILE *fp;
|
|
|
|
if ((fp = fopen(filename, "wb")) == NULL) {
|
|
delete[] pixels;
|
|
fl_alert("Error writing %s: %s", filename, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
png_structp pptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
|
png_infop iptr = png_create_info_struct(pptr);
|
|
png_bytep ptr = (png_bytep)pixels;
|
|
|
|
png_init_io(pptr, fp);
|
|
png_set_IHDR(pptr, iptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
|
png_set_sRGB(pptr, iptr, PNG_sRGB_INTENT_PERCEPTUAL);
|
|
|
|
png_write_info(pptr, iptr);
|
|
|
|
for (int i = h; i > 0; i --, ptr += w * 3) {
|
|
png_write_row(pptr, ptr);
|
|
}
|
|
|
|
png_write_end(pptr, iptr);
|
|
png_destroy_write_struct(&pptr, &iptr);
|
|
|
|
fclose(fp);
|
|
|
|
# if 0 // The original PPM output code...
|
|
strcpy(ext, ".ppm");
|
|
fp = fopen(filename, "wb");
|
|
fprintf(fp, "P6\n%d %d 255\n", w, h);
|
|
fwrite(pixels, w * h, 3, fp);
|
|
fclose(fp);
|
|
# endif // 0
|
|
|
|
delete[] pixels;
|
|
#endif // HAVE_LIBPNG && HAVE_LIBZ
|
|
}
|
|
|
|
void revert_cb(Fl_Widget *,void *) {
|
|
if (modflag) {
|
|
if (!fl_choice("This user interface has been changed. Really revert?",
|
|
"Cancel", "Revert", NULL)) return;
|
|
}
|
|
undo_suspend();
|
|
if (!read_file(filename, 0)) {
|
|
undo_resume();
|
|
fl_message("Can't read %s: %s", filename, strerror(errno));
|
|
return;
|
|
}
|
|
undo_resume();
|
|
set_modflag(0);
|
|
undo_clear();
|
|
}
|
|
|
|
void exit_cb(Fl_Widget *,void *) {
|
|
if (modflag)
|
|
switch (fl_choice("Do you want to save changes to this user\n"
|
|
"interface before exiting?", "Cancel",
|
|
"Save", "Don't Save"))
|
|
{
|
|
case 0 : /* Cancel */
|
|
return;
|
|
case 1 : /* Save */
|
|
save_cb(NULL, NULL);
|
|
if (modflag) return; // Didn't save!
|
|
}
|
|
|
|
save_position(main_window,"main_window_pos");
|
|
|
|
if (widgetbin_panel) {
|
|
save_position(widgetbin_panel,"widgetbin_pos");
|
|
delete widgetbin_panel;
|
|
}
|
|
if (sourceview_panel) {
|
|
Fl_Preferences svp(fluid_prefs, "sourceview");
|
|
svp.set("autorefresh", sv_autorefresh->value());
|
|
svp.set("autoposition", sv_autoposition->value());
|
|
svp.set("tab", sv_tab->find(sv_tab->value()));
|
|
save_position(sourceview_panel,"sourceview_pos");
|
|
delete sourceview_panel;
|
|
}
|
|
if (about_panel)
|
|
delete about_panel;
|
|
if (help_dialog)
|
|
delete help_dialog;
|
|
|
|
undo_clear();
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
# include <FL/x.H>
|
|
|
|
void
|
|
apple_open_cb(const char *c) {
|
|
if (modflag) {
|
|
switch (fl_choice("Do you want to save changes to this user\n"
|
|
"interface before opening another one?", "Don't Save",
|
|
"Save", "Cancel"))
|
|
{
|
|
case 0 : /* Cancel */
|
|
return;
|
|
case 1 : /* Save */
|
|
save_cb(NULL, NULL);
|
|
if (modflag) return; // Didn't save!
|
|
}
|
|
}
|
|
const char *oldfilename;
|
|
oldfilename = filename;
|
|
filename = NULL;
|
|
set_filename(c);
|
|
undo_suspend();
|
|
if (!read_file(c, 0)) {
|
|
undo_resume();
|
|
fl_message("Can't read %s: %s", c, strerror(errno));
|
|
free((void *)filename);
|
|
filename = oldfilename;
|
|
if (main_window) main_window->label(filename);
|
|
return;
|
|
}
|
|
|
|
// Loaded a file; free the old filename...
|
|
set_modflag(0);
|
|
undo_resume();
|
|
undo_clear();
|
|
if (oldfilename) free((void *)oldfilename);
|
|
}
|
|
#endif // __APPLE__
|
|
|
|
void open_cb(Fl_Widget *, void *v) {
|
|
if (!v && modflag) {
|
|
switch (fl_choice("Do you want to save changes to this user\n"
|
|
"interface before opening another one?", "Cancel",
|
|
"Save", "Don't Save"))
|
|
{
|
|
case 0 : /* Cancel */
|
|
return;
|
|
case 1 : /* Save */
|
|
save_cb(NULL, NULL);
|
|
if (modflag) return; // Didn't save!
|
|
}
|
|
}
|
|
const char *c;
|
|
const char *oldfilename;
|
|
fl_file_chooser_ok_label("Open");
|
|
c = fl_file_chooser("Open:", "FLUID Files (*.f[ld])", filename);
|
|
fl_file_chooser_ok_label(NULL);
|
|
if (!c) return;
|
|
oldfilename = filename;
|
|
filename = NULL;
|
|
set_filename(c);
|
|
if (v != 0) undo_checkpoint();
|
|
undo_suspend();
|
|
if (!read_file(c, v!=0)) {
|
|
undo_resume();
|
|
fl_message("Can't read %s: %s", c, strerror(errno));
|
|
free((void *)filename);
|
|
filename = oldfilename;
|
|
if (main_window) set_modflag(modflag);
|
|
return;
|
|
}
|
|
undo_resume();
|
|
if (v) {
|
|
// Inserting a file; restore the original filename...
|
|
free((void *)filename);
|
|
filename = oldfilename;
|
|
set_modflag(1);
|
|
} else {
|
|
// Loaded a file; free the old filename...
|
|
set_modflag(0);
|
|
undo_clear();
|
|
if (oldfilename) free((void *)oldfilename);
|
|
}
|
|
}
|
|
|
|
void open_history_cb(Fl_Widget *, void *v) {
|
|
if (modflag) {
|
|
switch (fl_choice("Do you want to save changes to this user\n"
|
|
"interface before opening another one?", "Cancel",
|
|
"Save", "Don't Save"))
|
|
{
|
|
case 0 : /* Cancel */
|
|
return;
|
|
case 1 : /* Save */
|
|
save_cb(NULL, NULL);
|
|
if (modflag) return; // Didn't save!
|
|
}
|
|
}
|
|
const char *oldfilename = filename;
|
|
filename = NULL;
|
|
set_filename((char *)v);
|
|
undo_suspend();
|
|
if (!read_file(filename, 0)) {
|
|
undo_resume();
|
|
undo_clear();
|
|
fl_message("Can't read %s: %s", filename, strerror(errno));
|
|
free((void *)filename);
|
|
filename = oldfilename;
|
|
if (main_window) main_window->label(filename);
|
|
return;
|
|
}
|
|
set_modflag(0);
|
|
undo_resume();
|
|
undo_clear();
|
|
if (oldfilename) free((void *)oldfilename);
|
|
}
|
|
|
|
void new_cb(Fl_Widget *, void *v) {
|
|
// Check if the current file has been modified...
|
|
if (!v && modflag) {
|
|
// Yes, ask the user what to do...
|
|
switch (fl_choice("Do you want to save changes to this user\n"
|
|
"interface before creating a new one?", "Cancel",
|
|
"Save", "Don't Save"))
|
|
{
|
|
case 0 : /* Cancel */
|
|
return;
|
|
case 1 : /* Save */
|
|
save_cb(NULL, NULL);
|
|
if (modflag) return; // Didn't save!
|
|
}
|
|
}
|
|
|
|
// Setup the template panel...
|
|
if (!template_panel) make_template_panel();
|
|
|
|
template_clear();
|
|
template_browser->add("Blank");
|
|
template_load();
|
|
|
|
template_name->hide();
|
|
template_name->value("");
|
|
|
|
template_instance->show();
|
|
template_instance->deactivate();
|
|
template_instance->value("");
|
|
|
|
template_delete->hide();
|
|
|
|
template_submit->label("New");
|
|
template_submit->deactivate();
|
|
|
|
template_panel->label("New");
|
|
|
|
// Show the panel and wait for the user to do something...
|
|
template_panel->show();
|
|
while (template_panel->shown()) Fl::wait();
|
|
|
|
// See if the user chose anything...
|
|
int item = template_browser->value();
|
|
if (item < 1) return;
|
|
|
|
// Clear the current data...
|
|
delete_all();
|
|
set_filename(NULL);
|
|
|
|
// Load the template, if any...
|
|
const char *tname = (const char *)template_browser->data(item);
|
|
|
|
if (tname) {
|
|
// Grab the instance name...
|
|
const char *iname = template_instance->value();
|
|
|
|
if (iname && *iname) {
|
|
// Copy the template to a temp file, then read it in...
|
|
char line[1024], *ptr, *next;
|
|
FILE *infile, *outfile;
|
|
|
|
if ((infile = fopen(tname, "r")) == NULL) {
|
|
fl_alert("Error reading template file \"%s\":\n%s", tname,
|
|
strerror(errno));
|
|
set_modflag(0);
|
|
undo_clear();
|
|
return;
|
|
}
|
|
|
|
if ((outfile = fopen(cutfname(1), "w")) == NULL) {
|
|
fl_alert("Error writing buffer file \"%s\":\n%s", cutfname(1),
|
|
strerror(errno));
|
|
fclose(infile);
|
|
set_modflag(0);
|
|
undo_clear();
|
|
return;
|
|
}
|
|
|
|
while (fgets(line, sizeof(line), infile)) {
|
|
// Replace @INSTANCE@ with the instance name...
|
|
for (ptr = line; (next = strstr(ptr, "@INSTANCE@")) != NULL; ptr = next + 10) {
|
|
fwrite(ptr, next - ptr, 1, outfile);
|
|
fputs(iname, outfile);
|
|
}
|
|
|
|
fputs(ptr, outfile);
|
|
}
|
|
|
|
fclose(infile);
|
|
fclose(outfile);
|
|
|
|
undo_suspend();
|
|
read_file(cutfname(1), 0);
|
|
unlink(cutfname(1));
|
|
undo_resume();
|
|
} else {
|
|
// No instance name, so read the template without replacements...
|
|
undo_suspend();
|
|
read_file(tname, 0);
|
|
undo_resume();
|
|
}
|
|
}
|
|
|
|
set_modflag(0);
|
|
undo_clear();
|
|
}
|
|
|
|
int compile_only = 0;
|
|
int compile_strings = 0;
|
|
int header_file_set = 0;
|
|
int code_file_set = 0;
|
|
const char* header_file_name = ".h";
|
|
const char* code_file_name = ".cxx";
|
|
int i18n_type = 0;
|
|
const char* i18n_include = "";
|
|
const char* i18n_function = "";
|
|
const char* i18n_file = "";
|
|
const char* i18n_set = "";
|
|
char i18n_program[1024] = "";
|
|
|
|
void write_cb(Fl_Widget *, void *) {
|
|
if (!filename) {
|
|
save_cb(0,0);
|
|
if (!filename) return;
|
|
}
|
|
char cname[1024];
|
|
char hname[1024];
|
|
strlcpy(i18n_program, fl_filename_name(filename), sizeof(i18n_program));
|
|
fl_filename_setext(i18n_program, sizeof(i18n_program), "");
|
|
if (*code_file_name == '.' && strchr(code_file_name, '/') == NULL) {
|
|
strlcpy(cname, fl_filename_name(filename), sizeof(cname));
|
|
fl_filename_setext(cname, sizeof(cname), code_file_name);
|
|
} else {
|
|
strlcpy(cname, code_file_name, sizeof(hname));
|
|
}
|
|
if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) {
|
|
strlcpy(hname, fl_filename_name(filename), sizeof(hname));
|
|
fl_filename_setext(hname, sizeof(hname), header_file_name);
|
|
} else {
|
|
strlcpy(hname, header_file_name, sizeof(hname));
|
|
}
|
|
if (!compile_only) goto_source_dir();
|
|
int x = write_code(cname,hname);
|
|
if (!compile_only) leave_source_dir();
|
|
strlcat(cname, " and ", sizeof(cname));
|
|
strlcat(cname, hname, sizeof(cname));
|
|
if (compile_only) {
|
|
if (!x) {fprintf(stderr,"%s : %s\n",cname,strerror(errno)); exit(1);}
|
|
} else {
|
|
if (!x) {
|
|
fl_message("Can't write %s: %s", cname, strerror(errno));
|
|
} else if (completion_button->value()) {
|
|
fl_message("Wrote %s", cname);
|
|
}
|
|
}
|
|
}
|
|
|
|
void write_strings_cb(Fl_Widget *, void *) {
|
|
static const char *exts[] = { ".txt", ".po", ".msg" };
|
|
if (!filename) {
|
|
save_cb(0,0);
|
|
if (!filename) return;
|
|
}
|
|
char sname[1024];
|
|
strlcpy(sname, fl_filename_name(filename), sizeof(sname));
|
|
fl_filename_setext(sname, sizeof(sname), exts[i18n_type]);
|
|
if (!compile_only) goto_source_dir();
|
|
int x = write_strings(sname);
|
|
if (!compile_only) leave_source_dir();
|
|
if (compile_only) {
|
|
if (x) {fprintf(stderr,"%s : %s\n",sname,strerror(errno)); exit(1);}
|
|
} else {
|
|
if (x) {
|
|
fl_message("Can't write %s: %s", sname, strerror(errno));
|
|
} else if (completion_button->value()) {
|
|
fl_message("Wrote %s", sname);
|
|
}
|
|
}
|
|
}
|
|
|
|
void openwidget_cb(Fl_Widget *, void *) {
|
|
if (!Fl_Type::current) {
|
|
fl_message("Please select a widget");
|
|
return;
|
|
}
|
|
Fl_Type::current->open();
|
|
}
|
|
|
|
void toggle_overlays(Fl_Widget *,void *);
|
|
|
|
void select_all_cb(Fl_Widget *,void *);
|
|
void select_none_cb(Fl_Widget *,void *);
|
|
|
|
void group_cb(Fl_Widget *, void *);
|
|
|
|
void ungroup_cb(Fl_Widget *, void *);
|
|
|
|
extern int pasteoffset;
|
|
static int ipasteoffset;
|
|
|
|
void copy_cb(Fl_Widget*, void*) {
|
|
if (!Fl_Type::current) {
|
|
fl_beep();
|
|
return;
|
|
}
|
|
ipasteoffset = 10;
|
|
if (!write_file(cutfname(),1)) {
|
|
fl_message("Can't write %s: %s", cutfname(), strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
|
|
extern void select_only(Fl_Type *);
|
|
void cut_cb(Fl_Widget *, void *) {
|
|
if (!Fl_Type::current) {
|
|
fl_beep();
|
|
return;
|
|
}
|
|
if (!write_file(cutfname(),1)) {
|
|
fl_message("Can't write %s: %s", cutfname(), strerror(errno));
|
|
return;
|
|
}
|
|
undo_checkpoint();
|
|
set_modflag(1);
|
|
ipasteoffset = 0;
|
|
Fl_Type *p = Fl_Type::current->parent;
|
|
while (p && p->selected) p = p->parent;
|
|
delete_all(1);
|
|
if (p) select_only(p);
|
|
}
|
|
|
|
void delete_cb(Fl_Widget *, void *) {
|
|
if (!Fl_Type::current) {
|
|
fl_beep();
|
|
return;
|
|
}
|
|
undo_checkpoint();
|
|
set_modflag(1);
|
|
ipasteoffset = 0;
|
|
Fl_Type *p = Fl_Type::current->parent;
|
|
while (p && p->selected) p = p->parent;
|
|
delete_all(1);
|
|
if (p) select_only(p);
|
|
}
|
|
|
|
extern int force_parent;
|
|
|
|
void paste_cb(Fl_Widget*, void*) {
|
|
//if (ipasteoffset) force_parent = 1;
|
|
pasteoffset = ipasteoffset;
|
|
if (gridx>1) pasteoffset = ((pasteoffset-1)/gridx+1)*gridx;
|
|
if (gridy>1) pasteoffset = ((pasteoffset-1)/gridy+1)*gridy;
|
|
undo_checkpoint();
|
|
undo_suspend();
|
|
if (!read_file(cutfname(), 1)) {
|
|
fl_message("Can't read %s: %s", cutfname(), strerror(errno));
|
|
}
|
|
undo_resume();
|
|
pasteoffset = 0;
|
|
ipasteoffset += 10;
|
|
force_parent = 0;
|
|
}
|
|
|
|
// Duplicate the selected widgets...
|
|
void duplicate_cb(Fl_Widget*, void*) {
|
|
if (!Fl_Type::current) {
|
|
fl_beep();
|
|
return;
|
|
}
|
|
|
|
if (!write_file(cutfname(1),1)) {
|
|
fl_message("Can't write %s: %s", cutfname(1), strerror(errno));
|
|
return;
|
|
}
|
|
|
|
pasteoffset = 0;
|
|
force_parent = 1;
|
|
|
|
undo_checkpoint();
|
|
undo_suspend();
|
|
if (!read_file(cutfname(1), 1)) {
|
|
fl_message("Can't read %s: %s", cutfname(1), strerror(errno));
|
|
}
|
|
unlink(cutfname(1));
|
|
undo_resume();
|
|
|
|
force_parent = 0;
|
|
}
|
|
|
|
void earlier_cb(Fl_Widget*,void*);
|
|
|
|
void later_cb(Fl_Widget*,void*);
|
|
|
|
Fl_Type *sort(Fl_Type *parent);
|
|
|
|
static void sort_cb(Fl_Widget *,void *) {
|
|
sort((Fl_Type*)0);
|
|
}
|
|
|
|
void show_project_cb(Fl_Widget *, void *);
|
|
void show_grid_cb(Fl_Widget *, void *);
|
|
void show_settings_cb(Fl_Widget *, void *);
|
|
|
|
void align_widget_cb(Fl_Widget *, long);
|
|
void widget_size_cb(Fl_Widget *, long);
|
|
|
|
void about_cb(Fl_Widget *, void *) {
|
|
if (!about_panel) make_about_panel();
|
|
about_panel->show();
|
|
}
|
|
|
|
void show_help(const char *name) {
|
|
const char *docdir;
|
|
char helpname[1024];
|
|
|
|
if (!help_dialog) help_dialog = new Fl_Help_Dialog();
|
|
|
|
if ((docdir = getenv("FLTK_DOCDIR")) == NULL) {
|
|
#ifdef __EMX__
|
|
// Doesn't make sense to have a hardcoded fallback
|
|
static char fltk_docdir[1024];
|
|
|
|
strlcpy(fltk_docdir, __XOS2RedirRoot("/XFree86/lib/X11/fltk/doc"),
|
|
sizeof(fltk_docdir));
|
|
|
|
docdir = fltk_docdir;
|
|
#else
|
|
docdir = FLTK_DOCDIR;
|
|
#endif // __EMX__
|
|
}
|
|
snprintf(helpname, sizeof(helpname), "%s/%s", docdir, name);
|
|
|
|
help_dialog->load(helpname);
|
|
help_dialog->show();
|
|
}
|
|
|
|
void help_cb(Fl_Widget *, void *) {
|
|
show_help("fluid.html");
|
|
}
|
|
|
|
void manual_cb(Fl_Widget *, void *) {
|
|
show_help("index.html");
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
// Draw a shaded box...
|
|
static void win_box(int x, int y, int w, int h) {
|
|
fl_color(0xc0, 0xc0, 0xc0);
|
|
fl_rectf(x, y, w, h);
|
|
fl_color(0, 0, 0);
|
|
fl_rect(x, y, w, h);
|
|
fl_color(0xf0, 0xf0, 0xf0);
|
|
fl_rectf(x + 1, y + 1, 4, h - 2);
|
|
fl_rectf(x + 1, y + 1, w - 2, 4);
|
|
fl_color(0x90, 0x90, 0x90);
|
|
fl_rectf(x + w - 5, y + 1, 4, h - 2);
|
|
fl_rectf(x + 1, y + h - 5, w - 2, 4);
|
|
}
|
|
|
|
// Load and show the print dialog...
|
|
void print_menu_cb(Fl_Widget *, void *) {
|
|
PRINTDLG dialog; // Print dialog
|
|
DOCINFO docinfo; // Document info
|
|
int first, last; // First and last page
|
|
int page; // Current page
|
|
int winpage; // Current window page
|
|
int num_pages; // Number of pages
|
|
Fl_Type *t; // Current widget
|
|
int num_windows; // Number of windows
|
|
Fl_Window_Type *windows[1000]; // Windows to print
|
|
|
|
|
|
// Show print dialog...
|
|
for (t = Fl_Type::first, num_pages = 0; t; t = t->next) {
|
|
if (t->is_window()) num_pages ++;
|
|
}
|
|
|
|
memset(&dialog, 0, sizeof(dialog));
|
|
dialog.lStructSize = sizeof(dialog);
|
|
dialog.hwndOwner = fl_xid(main_window);
|
|
dialog.Flags = PD_ALLPAGES |
|
|
PD_RETURNDC;
|
|
dialog.nFromPage = 1;
|
|
dialog.nToPage = num_pages;
|
|
dialog.nMinPage = 1;
|
|
dialog.nMaxPage = num_pages;
|
|
dialog.nCopies = 1;
|
|
|
|
if (!PrintDlg(&dialog)) return;
|
|
|
|
// Get the base filename...
|
|
const char *basename = strrchr(filename, '/');
|
|
if (basename) basename ++;
|
|
else basename = filename;
|
|
|
|
// Do the print job...
|
|
memset(&docinfo, 0, sizeof(docinfo));
|
|
docinfo.cbSize = sizeof(docinfo);
|
|
docinfo.lpszDocName = basename;
|
|
|
|
StartDoc(dialog.hDC, &docinfo);
|
|
|
|
// Figure out how many pages we'll have to print...
|
|
if (dialog.Flags & PD_PAGENUMS) {
|
|
// Get from and to page numbers...
|
|
first = dialog.nFromPage;
|
|
last = dialog.nToPage;
|
|
|
|
if (first > last) {
|
|
// Swap first/last page
|
|
page = first;
|
|
first = last;
|
|
last = page;
|
|
}
|
|
} else {
|
|
// Print everything...
|
|
first = 1;
|
|
last = dialog.nMaxPage;
|
|
}
|
|
|
|
for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) {
|
|
if (t->is_window()) {
|
|
winpage ++;
|
|
windows[num_windows] = (Fl_Window_Type *)t;
|
|
num_windows ++;
|
|
#if 0
|
|
if (dialog.Flags & PD_ALLPAGES) num_windows ++;
|
|
else if ((dialog.Flags & PD_PAGENUMS) && winpage >= first &&
|
|
winpage <= last) num_windows ++;
|
|
else if ((dialog.Flags & PD_SELECTION) && t->selected) num_windows ++;
|
|
#endif // 0
|
|
}
|
|
}
|
|
|
|
num_pages = num_windows;
|
|
|
|
// Figure out the page size and margins...
|
|
int width, length; // Size of page
|
|
int xdpi, ydpi; // Output resolution
|
|
char buffer[1024];
|
|
|
|
width = GetDeviceCaps(dialog.hDC, HORZRES);
|
|
length = GetDeviceCaps(dialog.hDC, VERTRES);
|
|
xdpi = GetDeviceCaps(dialog.hDC, LOGPIXELSX);
|
|
ydpi = GetDeviceCaps(dialog.hDC, LOGPIXELSY);
|
|
|
|
// fl_message("width=%d, length=%d, xdpi=%d, ydpi=%d, num_windows=%d\n",
|
|
// width, length, xdpi, ydpi, num_windows);
|
|
|
|
HDC save_dc = fl_gc;
|
|
HWND save_win = fl_window;
|
|
int fontsize = 14 * ydpi / 72;
|
|
|
|
fl_gc = dialog.hDC;
|
|
fl_window = (HWND)dialog.hDC;
|
|
fl_push_no_clip();
|
|
|
|
// Get the time and date...
|
|
time_t curtime = time(NULL);
|
|
struct tm *curdate = localtime(&curtime);
|
|
char date[1024];
|
|
|
|
strftime(date, sizeof(date), "%c", curdate);
|
|
|
|
// Print each of the windows...
|
|
for (winpage = 0; winpage < num_windows; winpage ++) {
|
|
// Draw header...
|
|
StartPage(dialog.hDC);
|
|
|
|
fl_font(FL_HELVETICA_BOLD, fontsize);
|
|
fl_color(0, 0, 0);
|
|
|
|
fl_draw(basename, 0, fontsize);
|
|
|
|
fl_draw(date, (width - (int)fl_width(date)) / 2, fontsize);
|
|
|
|
sprintf(buffer, "%d/%d", winpage + 1, num_windows);
|
|
fl_draw(buffer, width - (int)fl_width(buffer), fontsize);
|
|
|
|
// Get window image...
|
|
uchar *pixels; // Window image data
|
|
int w, h; // Window image dimensions
|
|
int ww, hh; // Scaled size
|
|
int ulx, uly; // Upper-lefthand corner
|
|
Fl_Window *win; // Window widget
|
|
BITMAPINFO info; // Bitmap information
|
|
|
|
win = (Fl_Window *)(windows[winpage]->o);
|
|
pixels = windows[winpage]->read_image(w, h);
|
|
|
|
// Figure out the window size, first at 100 PPI and then scaled
|
|
// down if that is too big...
|
|
ww = w * xdpi / 100;
|
|
hh = h * ydpi / 100;
|
|
|
|
if (ww > width) {
|
|
ww = width;
|
|
hh = h * ww * ydpi / xdpi / w;
|
|
}
|
|
|
|
if (hh > (length - ydpi / 2)) {
|
|
hh = length - ydpi / 2;
|
|
ww = w * hh / h;
|
|
}
|
|
|
|
// Position the window in the center...
|
|
ulx = (width - ww) / 2;
|
|
uly = (length - hh) / 2;
|
|
|
|
// fl_message("winpage=%d, ulx=%d, uly=%d, ww=%d, hh=%d",
|
|
// winpage, ulx, uly, ww, hh);
|
|
|
|
// Draw a simulated window border...
|
|
int xborder = 4 * ww / w;
|
|
int yborder = 4 * hh / h;
|
|
|
|
win_box(ulx - xborder, uly - 5 * yborder,
|
|
ww + 2 * xborder, hh + 6 * yborder);
|
|
|
|
fl_color(0, 0, 255);
|
|
fl_rectf(ulx, uly - 4 * yborder, ww, 4 * yborder);
|
|
|
|
fl_font(FL_HELVETICA_BOLD, 2 * yborder);
|
|
fl_color(255, 255, 255);
|
|
fl_draw(win->label() ? win->label() : "Window",
|
|
ulx + xborder, uly - 3 * yborder);
|
|
|
|
int x = ulx + ww - 4 * xborder;
|
|
|
|
win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
|
|
fl_color(0, 0, 0);
|
|
fl_line(x + xborder, uly - yborder,
|
|
x + 3 * xborder, uly - 3 * yborder);
|
|
fl_line(x + xborder, uly - 3 * yborder,
|
|
x + 3 * xborder, uly - yborder);
|
|
x -= 4 * xborder;
|
|
|
|
if (win->resizable()) {
|
|
win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
|
|
fl_color(0, 0, 0);
|
|
fl_rect(x + xborder, uly - 3 * yborder, 2 * xborder, 2 * yborder);
|
|
x -= 4 * xborder;
|
|
}
|
|
|
|
if (!win->modal()) {
|
|
win_box(x, uly - 4 * yborder, 4 * xborder, 4 * yborder);
|
|
fl_color(0, 0, 0);
|
|
fl_line(x + xborder, uly - yborder, x + 3 * xborder, uly - yborder);
|
|
x -= 4 * xborder;
|
|
}
|
|
|
|
// Color image...
|
|
memset(&info, 0, sizeof(info));
|
|
info.bmiHeader.biSize = sizeof(info);
|
|
info.bmiHeader.biWidth = w;
|
|
info.bmiHeader.biHeight = 1;
|
|
info.bmiHeader.biPlanes = 1;
|
|
info.bmiHeader.biBitCount = 24;
|
|
info.bmiHeader.biCompression = BI_RGB;
|
|
|
|
for (int y = 0; y < h; y ++) {
|
|
StretchDIBits(dialog.hDC, ulx, uly + y * hh / h, ww, (hh + h - 1) / h, 0, 0, w, 1,
|
|
pixels + y * w * 3, &info, DIB_RGB_COLORS, SRCCOPY);
|
|
}
|
|
|
|
delete[] pixels;
|
|
|
|
// Show the page...
|
|
EndPage(dialog.hDC);
|
|
}
|
|
|
|
// Finish up...
|
|
EndDoc(dialog.hDC);
|
|
|
|
fl_gc = save_dc;
|
|
fl_window = save_win;
|
|
fl_pop_clip();
|
|
|
|
// Free the print DC and return...
|
|
DeleteDC(dialog.hDC);
|
|
}
|
|
#else
|
|
// Load and show the print dialog...
|
|
void print_menu_cb(Fl_Widget *, void *) {
|
|
if (!print_panel) make_print_panel();
|
|
|
|
print_load();
|
|
|
|
print_selection->deactivate();
|
|
|
|
for (Fl_Type *t = Fl_Type::first; t; t = t->next) {
|
|
if (t->selected && t->is_window()) {
|
|
print_selection->activate();
|
|
break;
|
|
}
|
|
}
|
|
|
|
print_all->setonly();
|
|
print_all->do_callback();
|
|
|
|
print_panel->show();
|
|
}
|
|
|
|
// Quote a string for PostScript printing
|
|
static const char *ps_string(const char *s) {
|
|
char *bufptr;
|
|
static char buffer[2048];
|
|
|
|
|
|
if (!s) {
|
|
buffer[0] = '\0';
|
|
} else {
|
|
for (bufptr = buffer; bufptr < (buffer + sizeof(buffer) - 3) && *s;) {
|
|
if (*s == '(' || *s == ')' || *s == '\\') *bufptr++ = '\\';
|
|
*bufptr++ = *s++;
|
|
}
|
|
|
|
*bufptr = '\0';
|
|
}
|
|
|
|
return (buffer);
|
|
}
|
|
|
|
// Actually print...
|
|
void print_cb(Fl_Return_Button *, void *) {
|
|
FILE *outfile; // Output file or pipe to print command
|
|
char command[1024]; // Print command
|
|
int copies; // Collated copies
|
|
int first, last; // First and last page
|
|
int page; // Current page
|
|
int winpage; // Current window page
|
|
int num_pages; // Number of pages
|
|
Fl_Type *t; // Current widget
|
|
int num_windows; // Number of windows
|
|
Fl_Window_Type *windows[1000]; // Windows to print
|
|
|
|
// Show progress, deactivate controls...
|
|
print_panel_controls->deactivate();
|
|
print_progress->show();
|
|
|
|
// Figure out how many pages we'll have to print...
|
|
if (print_collate_button->value()) copies = (int)print_copies->value();
|
|
else copies = 1;
|
|
|
|
if (print_pages->value()) {
|
|
// Get from and to page numbers...
|
|
if ((first = atoi(print_from->value())) < 1) first = 1;
|
|
if ((last = atoi(print_to->value())) < 1) last = 1000;
|
|
|
|
if (first > last) {
|
|
// Swap first/last page
|
|
page = first;
|
|
first = last;
|
|
last = page;
|
|
}
|
|
} else {
|
|
// Print everything...
|
|
first = 1;
|
|
last = 1000;
|
|
}
|
|
|
|
for (t = Fl_Type::first, num_windows = 0, winpage = 0; t; t = t->next) {
|
|
if (t->is_window()) {
|
|
winpage ++;
|
|
windows[num_windows] = (Fl_Window_Type *)t;
|
|
|
|
if (print_all->value()) num_windows ++;
|
|
else if (print_pages->value() && winpage >= first &&
|
|
winpage <= last) num_windows ++;
|
|
else if (print_selection->value() && t->selected) num_windows ++;
|
|
}
|
|
}
|
|
|
|
num_pages = num_windows * copies;
|
|
|
|
print_progress->minimum(0);
|
|
print_progress->maximum(num_pages);
|
|
print_progress->value(0);
|
|
Fl::check();
|
|
|
|
// Get the base filename...
|
|
const char *basename = strrchr(filename, '/');
|
|
if (basename) basename ++;
|
|
else basename = filename;
|
|
|
|
// Open the print stream...
|
|
if (print_choice->value()) {
|
|
// Pipe the output into the lp command...
|
|
const char *printer = (const char *)print_choice->menu()[print_choice->value()].user_data();
|
|
|
|
snprintf(command, sizeof(command), "lp -s -d %s -n %.0f -t '%s' -o media=%s",
|
|
printer, print_collate_button->value() ? 1.0 : print_copies->value(),
|
|
basename, print_page_size->text(print_page_size->value()));
|
|
outfile = popen(command, "w");
|
|
} else {
|
|
// Print to file...
|
|
fl_file_chooser_ok_label("Print");
|
|
const char *outname = fl_file_chooser("Print To", "PostScript (*.ps)", NULL, 1);
|
|
fl_file_chooser_ok_label(NULL);
|
|
|
|
if (outname && !access(outname, 0)) {
|
|
if (fl_choice("The file \"%s\" already exists.\n"
|
|
"Do you want to replace it?", "Cancel",
|
|
"Replace", NULL, outname) == 0) outname = NULL;
|
|
}
|
|
|
|
if (outname) outfile = fopen(outname, "w");
|
|
else outfile = NULL;
|
|
}
|
|
|
|
if (outfile) {
|
|
// Figure out the page size and margins...
|
|
int width, length; // Size of page
|
|
int left, bottom, // Bottom lefthand corner
|
|
right, top; // Top righthand corner
|
|
|
|
if (print_page_size->value()) {
|
|
// A4
|
|
width = 595;
|
|
length = 842;
|
|
} else {
|
|
// Letter
|
|
width = 612;
|
|
length = 792;
|
|
}
|
|
|
|
int output_mode;
|
|
for (output_mode = 0; output_mode < 4; output_mode ++) {
|
|
if (print_output_mode[output_mode]->value()) break;
|
|
}
|
|
|
|
if (output_mode & 1) {
|
|
// Landscape
|
|
left = 36;
|
|
bottom = 18;
|
|
right = length - 36;
|
|
top = width - 18;
|
|
} else {
|
|
// Portrait
|
|
left = 18;
|
|
bottom = 36;
|
|
right = width - 18;
|
|
top = length - 36;
|
|
}
|
|
|
|
// Get the time and date...
|
|
time_t curtime = time(NULL);
|
|
struct tm *curdate = localtime(&curtime);
|
|
char date[1024];
|
|
|
|
strftime(date, sizeof(date), "%c", curdate);
|
|
|
|
// Write the prolog...
|
|
fprintf(outfile,
|
|
"%%!PS-Adobe-3.0\n"
|
|
"%%%%BoundingBox: 18 36 %d %d\n"
|
|
"%%%%Pages: %d\n"
|
|
"%%%%LanguageLevel: 1\n"
|
|
"%%%%DocumentData: Clean7Bit\n"
|
|
"%%%%DocumentNeededResources: font Helvetica-Bold\n"
|
|
"%%%%Creator: FLUID %.4f\n"
|
|
"%%%%CreationDate: %s\n"
|
|
"%%%%Title: (%s)\n"
|
|
"%%%%EndComments\n"
|
|
"%%%%BeginProlog\n"
|
|
"%%languagelevel 1 eq {\n"
|
|
" /rectfill {\n"
|
|
" newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
|
|
" neg 0 exch rlineto closepath fill\n"
|
|
" } bind def\n"
|
|
" /rectstroke {\n"
|
|
" newpath 4 2 roll moveto dup 0 exch rlineto exch 0 rlineto\n"
|
|
" neg 0 exch rlineto closepath stroke\n"
|
|
" } bind def\n"
|
|
"%%} if\n"
|
|
"%%%%EndProlog\n"
|
|
"%%%%BeginSetup\n"
|
|
"%%%%BeginFeature: *PageSize %s\n"
|
|
"languagelevel 1 ne {\n"
|
|
" <</PageSize[%d %d]/ImagingBBox null>>setpagedevice\n"
|
|
"} {\n"
|
|
" %s\n"
|
|
"} ifelse\n"
|
|
"%%%%EndFeature\n"
|
|
"%%%%EndSetup\n",
|
|
width - 18, length - 36,
|
|
num_pages,
|
|
FL_VERSION,
|
|
date,
|
|
basename,
|
|
print_page_size->text(print_page_size->value()),
|
|
width, length,
|
|
print_page_size->value() ? "a4tray" : "lettertray");
|
|
|
|
// Print each of the windows...
|
|
char progress[255]; // Progress text
|
|
int copy; // Current copy
|
|
|
|
for (copy = 0, page = 0; copy < copies; copy ++) {
|
|
for (winpage = 0; winpage < num_pages; winpage ++) {
|
|
// Start next page...
|
|
page ++;
|
|
sprintf(progress, "Printing page %d/%d...", page, num_pages);
|
|
print_progress->value(page);
|
|
print_progress->label(progress);
|
|
Fl::check();
|
|
|
|
// Add common page stuff...
|
|
fprintf(outfile,
|
|
"%%%%Page: %d %d\n"
|
|
"gsave\n",
|
|
page, page);
|
|
|
|
if (output_mode & 1) {
|
|
// Landscape...
|
|
fprintf(outfile, "%d 0 translate 90 rotate\n", width);
|
|
}
|
|
|
|
// Draw header...
|
|
fprintf(outfile,
|
|
"0 setgray\n"
|
|
"/Helvetica-Bold findfont 14 scalefont setfont\n"
|
|
"%d %d moveto (%s) show\n"
|
|
"%.1f %d moveto (%s) dup stringwidth pop -0.5 mul 0 rmoveto show\n"
|
|
"%d %d moveto (%d/%d) dup stringwidth pop neg 0 rmoveto show\n",
|
|
left, top - 15, ps_string(basename),
|
|
0.5 * (left + right), top - 15, date,
|
|
right, top - 15, winpage + 1, num_windows);
|
|
|
|
// Get window image...
|
|
uchar *pixels; // Window image data
|
|
int w, h; // Window image dimensions
|
|
float ww, hh; // Scaled size
|
|
float border; // Width of 1 pixel
|
|
float llx, lly, // Lower-lefthand corner
|
|
urx, ury; // Upper-righthand corner
|
|
Fl_Window *win; // Window widget
|
|
|
|
win = (Fl_Window *)(windows[winpage]->o);
|
|
pixels = windows[winpage]->read_image(w, h);
|
|
|
|
// Figure out the window size, first at 100 PPI and then scaled
|
|
// down if that is too big...
|
|
ww = w * 72.0 / 100.0;
|
|
hh = h * 72.0 / 100.0;
|
|
|
|
if (ww > (right - left)) {
|
|
ww = right - left;
|
|
hh = h * ww / w;
|
|
}
|
|
|
|
if (hh > (top - bottom - 36)) {
|
|
hh = top - bottom;
|
|
ww = w * hh / h;
|
|
}
|
|
|
|
border = ww / w;
|
|
|
|
// Position the window in the center...
|
|
llx = 0.5 * (right - left - ww);
|
|
lly = 0.5 * (top - bottom - hh);
|
|
urx = 0.5 * (right - left + ww);
|
|
ury = 0.5 * (top - bottom + hh);
|
|
|
|
// Draw a simulated window border...
|
|
fprintf(outfile,
|
|
"0.75 setgray\n" // Gray background
|
|
"newpath %.2f %.2f %.2f 180 90 arcn\n" // Top left
|
|
"%.2f %.2f %.2f 90 0 arcn\n" // Top right
|
|
"%.2f %.2f %.2f 0 -90 arcn\n" // Bottom right
|
|
"%.2f %.2f %.2f -90 -180 arcn\n" // Bottom left
|
|
"closepath gsave fill grestore\n" // Fill
|
|
"0 setlinewidth 0 setgray stroke\n", // Outline
|
|
llx, ury + 12 * border, 4 * border,
|
|
urx, ury + 12 * border, 4 * border,
|
|
urx, lly, 4 * border,
|
|
llx, lly, 4 * border);
|
|
|
|
// Title bar...
|
|
if (output_mode & 2) {
|
|
fputs("0.25 setgray\n", outfile);
|
|
} else {
|
|
fputs("0.1 0.2 0.6 setrgbcolor\n", outfile);
|
|
}
|
|
|
|
fprintf(outfile, "%.2f %.2f %.2f %.2f rectfill\n",
|
|
llx + 12 * border, ury,
|
|
ww - (24 + 16 * (!win->modal() || win->resizable()) +
|
|
16 * (!win->modal() && win->resizable())) * border,
|
|
16 * border);
|
|
|
|
if (win->resizable()) {
|
|
fprintf(outfile,
|
|
"%.2f %.2f %.2f -90 -180 arcn\n" // Bottom left
|
|
"0 %.2f rlineto %.2f 0 rlineto 0 -%.2f rlineto closepath fill\n"
|
|
"%.2f %.2f %.2f 0 -90 arcn\n" // Bottom right
|
|
"-%.2f 0 rlineto 0 %.2f rlineto %.2f 0 rlineto closepath fill\n",
|
|
llx, lly, 4 * border,
|
|
12 * border, 16 * border, 16 * border,
|
|
urx, lly, 4 * border,
|
|
12 * border, 16 * border, 16 * border);
|
|
}
|
|
|
|
// Inside outline and button shading...
|
|
fprintf(outfile,
|
|
"%.2f setlinewidth 0.5 setgray\n"
|
|
"%.2f %.2f %.2f %.2f rectstroke\n"
|
|
"%.2f %.2f moveto 0 %.2f rlineto\n"
|
|
"%.2f %.2f moveto 0 %.2f rlineto\n",
|
|
border,
|
|
llx - 0.5 * border, lly - 0.5 * border, ww + border, hh + border,
|
|
llx + 12 * border, ury, 16 * border,
|
|
urx - 12 * border, ury, 16 * border);
|
|
|
|
if (!win->modal() || win->resizable()) {
|
|
fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n",
|
|
urx - 28 * border, ury, 16 * border);
|
|
}
|
|
|
|
if (!win->modal() && win->resizable()) {
|
|
fprintf(outfile, "%.2f %.2f moveto 0 %.2f rlineto\n",
|
|
urx - 44 * border, ury, 16 * border);
|
|
}
|
|
|
|
fprintf(outfile, "%.2f %.2f moveto %.2f 0 rlineto stroke\n",
|
|
llx - 3.5 * border, ury + 0.5 * border, ww + 7 * border);
|
|
|
|
// Button icons...
|
|
fprintf(outfile,
|
|
"%.2f setlinewidth 0 setgray\n"
|
|
"%.2f %.2f moveto %.2f -%.2f rlineto %.2f %.2f rlineto\n"
|
|
"%.2f %.2f moveto -%.2f -%.2f rlineto 0 %.2f rmoveto %.2f -%.2f rlineto\n",
|
|
2 * border,
|
|
llx, ury + 10 * border, 4 * border, 4 * border, 4 * border, 4 * border,
|
|
urx, ury + 12 * border, 8 * border, 8 * border, 8 * border, 8 * border, 8 * border);
|
|
|
|
float x = urx - 16 * border;
|
|
|
|
if (win->resizable()) {
|
|
// Maximize button
|
|
fprintf(outfile,
|
|
"%.2f %.2f moveto -%.2f 0 rlineto 0 -%.2f rlineto "
|
|
"%.2f 0 rlineto 0 %.2f rlineto\n",
|
|
x, ury + 12 * border, 8 * border, 8 * border,
|
|
8 * border, 8 * border);
|
|
|
|
x -= 16 * border;
|
|
}
|
|
|
|
if (!win->modal()) {
|
|
// Minimize button
|
|
fprintf(outfile,
|
|
"%.2f %.2f moveto -%.2f 0 rlineto\n",
|
|
x, ury + 4 * border, 8 * border);
|
|
}
|
|
|
|
fputs("stroke\n", outfile);
|
|
|
|
if (win->label()) {
|
|
// Add window title...
|
|
fprintf(outfile,
|
|
"1 setgray\n"
|
|
"/Helvetica-Bold findfont %.2f scalefont setfont\n"
|
|
"(%s) %.2f %.2f moveto show\n",
|
|
12 * border,
|
|
ps_string(win->label()), llx + 16 * border, ury + 4 * border);
|
|
}
|
|
|
|
fprintf(outfile,
|
|
"gsave\n"
|
|
"%.2f %.2f translate %.2f %.2f scale\n",
|
|
llx, ury - border, border, border);
|
|
|
|
if (output_mode & 2) {
|
|
// Grayscale image...
|
|
fprintf(outfile,
|
|
"/imgdata %d string def\n"
|
|
"%d %d 8[1 0 0 -1 0 1] "
|
|
"{currentfile imgdata readhexstring pop} image\n",
|
|
w,
|
|
w, h);
|
|
|
|
uchar *ptr = pixels;
|
|
int i, count = w * h;
|
|
|
|
for (i = 0; i < count; i ++, ptr += 3) {
|
|
fprintf(outfile, "%02X",
|
|
(31 * ptr[0] + 61 * ptr[1] + 8 * ptr[2]) / 100);
|
|
if (!(i % 40)) putc('\n', outfile);
|
|
}
|
|
} else {
|
|
// Color image...
|
|
fprintf(outfile,
|
|
"/imgdata %d string def\n"
|
|
"%d %d 8[1 0 0 -1 0 1] "
|
|
"{currentfile imgdata readhexstring pop} false 3 colorimage\n",
|
|
w * 3,
|
|
w, h);
|
|
|
|
uchar *ptr = pixels;
|
|
int i, count = w * h;
|
|
|
|
for (i = 0; i < count; i ++, ptr += 3) {
|
|
fprintf(outfile, "%02X%02X%02X", ptr[0], ptr[1], ptr[2]);
|
|
if (!(i % 13)) putc('\n', outfile);
|
|
}
|
|
}
|
|
|
|
fputs("\ngrestore\n", outfile);
|
|
|
|
delete[] pixels;
|
|
|
|
// Show the page...
|
|
fputs("grestore showpage\n", outfile);
|
|
}
|
|
}
|
|
|
|
// Finish up...
|
|
fputs("%%EOF\n", outfile);
|
|
|
|
if (print_choice->value()) pclose(outfile);
|
|
else fclose(outfile);
|
|
} else {
|
|
// Unable to print...
|
|
fl_alert("Error printing: %s", strerror(errno));
|
|
}
|
|
|
|
// Hide progress, activate controls, hide print panel...
|
|
print_panel_controls->activate();
|
|
print_progress->hide();
|
|
print_panel->hide();
|
|
}
|
|
#endif // WIN32 && !__CYGWIN__
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
extern Fl_Menu_Item New_Menu[];
|
|
|
|
void toggle_widgetbin_cb(Fl_Widget *, void *);
|
|
void toggle_sourceview_cb(Fl_Double_Window *, void *);
|
|
|
|
Fl_Menu_Item Main_Menu[] = {
|
|
{"&File",0,0,0,FL_SUBMENU},
|
|
{"&New...", FL_COMMAND+'n', new_cb, 0},
|
|
{"&Open...", FL_COMMAND+'o', open_cb, 0},
|
|
{"&Insert...", FL_COMMAND+'i', open_cb, (void*)1, FL_MENU_DIVIDER},
|
|
#define SAVE_ITEM 4
|
|
{"&Save", FL_COMMAND+'s', save_cb, 0},
|
|
{"Save &As...", FL_COMMAND+FL_SHIFT+'s', save_cb, (void*)1},
|
|
{"Sa&ve A Copy...", 0, save_cb, (void*)2},
|
|
{"Save &Template...", 0, save_template_cb},
|
|
{"&Revert...", 0, revert_cb, 0, FL_MENU_DIVIDER},
|
|
{"&Print...", FL_COMMAND+'p', print_menu_cb},
|
|
{"Write &Code...", FL_COMMAND+FL_SHIFT+'c', write_cb, 0},
|
|
{"&Write Strings...", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, 0, FL_MENU_DIVIDER},
|
|
#define HISTORY_ITEM 12
|
|
{relative_history[0], FL_COMMAND+'0', open_history_cb, absolute_history[0]},
|
|
{relative_history[1], FL_COMMAND+'1', open_history_cb, absolute_history[1]},
|
|
{relative_history[2], FL_COMMAND+'2', open_history_cb, absolute_history[2]},
|
|
{relative_history[3], FL_COMMAND+'3', open_history_cb, absolute_history[3]},
|
|
{relative_history[4], FL_COMMAND+'4', open_history_cb, absolute_history[4]},
|
|
{relative_history[5], FL_COMMAND+'5', open_history_cb, absolute_history[5]},
|
|
{relative_history[6], FL_COMMAND+'6', open_history_cb, absolute_history[6]},
|
|
{relative_history[7], FL_COMMAND+'7', open_history_cb, absolute_history[7]},
|
|
{relative_history[8], FL_COMMAND+'8', open_history_cb, absolute_history[8]},
|
|
{relative_history[9], FL_COMMAND+'9', open_history_cb, absolute_history[9], FL_MENU_DIVIDER},
|
|
{"&Quit", FL_COMMAND+'q', exit_cb},
|
|
{0},
|
|
{"&Edit",0,0,0,FL_SUBMENU},
|
|
{"&Undo", FL_COMMAND+'z', undo_cb},
|
|
{"&Redo", FL_COMMAND+FL_SHIFT+'z', redo_cb, 0, FL_MENU_DIVIDER},
|
|
{"C&ut", FL_COMMAND+'x', cut_cb},
|
|
{"&Copy", FL_COMMAND+'c', copy_cb},
|
|
{"&Paste", FL_COMMAND+'v', paste_cb},
|
|
{"Dup&licate", FL_COMMAND+'u', duplicate_cb},
|
|
{"&Delete", FL_Delete, delete_cb, 0, FL_MENU_DIVIDER},
|
|
{"Select &All", FL_COMMAND+'a', select_all_cb},
|
|
{"Select &None", FL_COMMAND+FL_SHIFT+'a', select_none_cb, 0, FL_MENU_DIVIDER},
|
|
{"Pr&operties...", FL_F+1, openwidget_cb},
|
|
{"&Sort",0,sort_cb},
|
|
{"&Earlier", FL_F+2, earlier_cb},
|
|
{"&Later", FL_F+3, later_cb},
|
|
{"&Group", FL_F+7, group_cb},
|
|
{"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER},
|
|
{"Hide O&verlays",FL_COMMAND+FL_SHIFT+'o',toggle_overlays},
|
|
#define WIDGETBIN_ITEM 41
|
|
{"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb},
|
|
#define SOURCEVIEW_ITEM 42
|
|
{"Show Source Code...",FL_ALT+FL_SHIFT+'s', (Fl_Callback*)toggle_sourceview_cb, 0, FL_MENU_DIVIDER},
|
|
{"Pro&ject Settings...",FL_ALT+'p',show_project_cb},
|
|
{"GU&I Settings...",FL_ALT+FL_SHIFT+'p',show_settings_cb},
|
|
{0},
|
|
{"&New", 0, 0, (void *)New_Menu, FL_SUBMENU_POINTER},
|
|
{"&Layout",0,0,0,FL_SUBMENU},
|
|
{"&Align",0,0,0,FL_SUBMENU},
|
|
{"&Left",0,(Fl_Callback *)align_widget_cb,(void*)10},
|
|
{"&Center",0,(Fl_Callback *)align_widget_cb,(void*)11},
|
|
{"&Right",0,(Fl_Callback *)align_widget_cb,(void*)12},
|
|
{"&Top",0,(Fl_Callback *)align_widget_cb,(void*)13},
|
|
{"&Middle",0,(Fl_Callback *)align_widget_cb,(void*)14},
|
|
{"&Bottom",0,(Fl_Callback *)align_widget_cb,(void*)15},
|
|
{0},
|
|
{"&Space Evenly",0,0,0,FL_SUBMENU},
|
|
{"&Across",0,(Fl_Callback *)align_widget_cb,(void*)20},
|
|
{"&Down",0,(Fl_Callback *)align_widget_cb,(void*)21},
|
|
{0},
|
|
{"&Make Same Size",0,0,0,FL_SUBMENU},
|
|
{"&Width",0,(Fl_Callback *)align_widget_cb,(void*)30},
|
|
{"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31},
|
|
{"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32},
|
|
{0},
|
|
{"&Center In Group",0,0,0,FL_SUBMENU},
|
|
{"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40},
|
|
{"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41},
|
|
{0},
|
|
{"Set &Widget Size",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER},
|
|
{"&Tiny",FL_ALT+'1',(Fl_Callback *)widget_size_cb,(void*)8,0,FL_NORMAL_LABEL,FL_HELVETICA,8},
|
|
{"&Small",FL_ALT+'2',(Fl_Callback *)widget_size_cb,(void*)11,0,FL_NORMAL_LABEL,FL_HELVETICA,11},
|
|
{"&Normal",FL_ALT+'3',(Fl_Callback *)widget_size_cb,(void*)14,0,FL_NORMAL_LABEL,FL_HELVETICA,14},
|
|
{"&Medium",FL_ALT+'4',(Fl_Callback *)widget_size_cb,(void*)18,0,FL_NORMAL_LABEL,FL_HELVETICA,18},
|
|
{"&Large",FL_ALT+'5',(Fl_Callback *)widget_size_cb,(void*)24,0,FL_NORMAL_LABEL,FL_HELVETICA,24},
|
|
{"&Huge",FL_ALT+'6',(Fl_Callback *)widget_size_cb,(void*)32,0,FL_NORMAL_LABEL,FL_HELVETICA,32},
|
|
{0},
|
|
{"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb},
|
|
{0},
|
|
{"&Shell",0,0,0,FL_SUBMENU},
|
|
{"Execute &Command...",FL_ALT+'x',(Fl_Callback *)show_shell_window},
|
|
{"Execute &Again...",FL_ALT+'g',(Fl_Callback *)do_shell_command},
|
|
{0},
|
|
{"&Help",0,0,0,FL_SUBMENU},
|
|
{"&About FLUID...",0,about_cb},
|
|
{"&On FLUID...",0,help_cb},
|
|
{"&Manual...",0,manual_cb},
|
|
{0},
|
|
{0}};
|
|
|
|
#define BROWSERWIDTH 300
|
|
#define BROWSERHEIGHT 500
|
|
#define WINWIDTH 300
|
|
#define MENUHEIGHT 25
|
|
#define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT)
|
|
|
|
extern void fill_in_New_Menu();
|
|
|
|
void scheme_cb(Fl_Choice *, void *) {
|
|
if (compile_only)
|
|
return;
|
|
|
|
switch (scheme_choice->value()) {
|
|
case 0 : // Default
|
|
Fl::scheme(NULL);
|
|
break;
|
|
case 1 : // None
|
|
Fl::scheme("none");
|
|
break;
|
|
case 2 : // Plastic
|
|
Fl::scheme("plastic");
|
|
break;
|
|
case 3 : // GTK+
|
|
Fl::scheme("gtk+");
|
|
break;
|
|
}
|
|
|
|
fluid_prefs.set("scheme", scheme_choice->value());
|
|
}
|
|
|
|
void toggle_widgetbin_cb(Fl_Widget *, void *) {
|
|
if (!widgetbin_panel) {
|
|
make_widgetbin();
|
|
widgetbin_panel->callback(toggle_widgetbin_cb);
|
|
if (!position_window(widgetbin_panel,"widgetbin_pos", 1, 320, 30)) return;
|
|
}
|
|
|
|
if (widgetbin_panel->visible()) {
|
|
widgetbin_panel->hide();
|
|
Main_Menu[WIDGETBIN_ITEM].label("Show Widget &Bin...");
|
|
} else {
|
|
widgetbin_panel->show();
|
|
Main_Menu[WIDGETBIN_ITEM].label("Hide Widget &Bin");
|
|
}
|
|
}
|
|
|
|
|
|
void toggle_sourceview_cb(Fl_Double_Window *, void *) {
|
|
if (!sourceview_panel) {
|
|
make_sourceview();
|
|
sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb);
|
|
Fl_Preferences svp(fluid_prefs, "sourceview");
|
|
int autorefresh;
|
|
svp.get("autorefresh", autorefresh, 1);
|
|
sv_autorefresh->value(autorefresh);
|
|
int autoposition;
|
|
svp.get("autoposition", autoposition, 1);
|
|
sv_autoposition->value(autoposition);
|
|
int tab;
|
|
svp.get("tab", tab, 0);
|
|
if (tab>=0 && tab<sv_tab->children()) sv_tab->value(sv_tab->child(tab));
|
|
if (!position_window(sourceview_panel,"sourceview_pos", 0, 320, 120, 550, 500)) return;
|
|
}
|
|
|
|
if (sourceview_panel->visible()) {
|
|
sourceview_panel->hide();
|
|
Main_Menu[SOURCEVIEW_ITEM].label("Show Source Code...");
|
|
} else {
|
|
sourceview_panel->show();
|
|
Main_Menu[SOURCEVIEW_ITEM].label("Hide Source Code...");
|
|
update_sourceview_cb(0,0);
|
|
}
|
|
}
|
|
|
|
void toggle_sourceview_b_cb(Fl_Button*, void *) {
|
|
toggle_sourceview_cb(0,0);
|
|
}
|
|
|
|
void make_main_window() {
|
|
fluid_prefs.get("snap", snap, 1);
|
|
fluid_prefs.get("gridx", gridx, 5);
|
|
fluid_prefs.get("gridy", gridy, 5);
|
|
fluid_prefs.get("show_guides", show_guides, 0);
|
|
fluid_prefs.get("widget_size", Fl_Widget_Type::default_size, 14);
|
|
|
|
load_history();
|
|
|
|
make_layout_window();
|
|
make_settings_window();
|
|
make_shell_window();
|
|
|
|
if (!main_window) {
|
|
Fl_Widget *o;
|
|
main_window = new Fl_Double_Window(WINWIDTH,WINHEIGHT,"fluid");
|
|
main_window->box(FL_NO_BOX);
|
|
o = make_widget_browser(0,MENUHEIGHT,BROWSERWIDTH,BROWSERHEIGHT);
|
|
o->box(FL_FLAT_BOX);
|
|
o->tooltip("Double-click to view or change an item.");
|
|
main_window->resizable(o);
|
|
main_menubar = new Fl_Menu_Bar(0,0,BROWSERWIDTH,MENUHEIGHT);
|
|
main_menubar->menu(Main_Menu);
|
|
main_menubar->global();
|
|
fill_in_New_Menu();
|
|
main_window->end();
|
|
}
|
|
}
|
|
|
|
// Load file history from preferences...
|
|
void load_history() {
|
|
int i; // Looping var
|
|
int max_files;
|
|
|
|
|
|
fluid_prefs.get("recent_files", max_files, 5);
|
|
if (max_files > 10) max_files = 10;
|
|
|
|
for (i = 0; i < max_files; i ++) {
|
|
fluid_prefs.get( Fl_Preferences::Name("file%d", i), absolute_history[i], "", sizeof(absolute_history[i]));
|
|
if (absolute_history[i][0]) {
|
|
// Make a relative version of the filename for the menu...
|
|
fl_filename_relative(relative_history[i], sizeof(relative_history[i]),
|
|
absolute_history[i]);
|
|
|
|
if (i == 9) Main_Menu[i + HISTORY_ITEM].flags = FL_MENU_DIVIDER;
|
|
else Main_Menu[i + HISTORY_ITEM].flags = 0;
|
|
} else break;
|
|
}
|
|
|
|
for (; i < 10; i ++) {
|
|
if (i) Main_Menu[i + HISTORY_ITEM - 1].flags |= FL_MENU_DIVIDER;
|
|
Main_Menu[i + HISTORY_ITEM].hide();
|
|
}
|
|
}
|
|
|
|
// Update file history from preferences...
|
|
void update_history(const char *flname) {
|
|
int i; // Looping var
|
|
char absolute[1024];
|
|
int max_files;
|
|
|
|
|
|
fluid_prefs.get("recent_files", max_files, 5);
|
|
if (max_files > 10) max_files = 10;
|
|
|
|
fl_filename_absolute(absolute, sizeof(absolute), flname);
|
|
|
|
for (i = 0; i < max_files; i ++)
|
|
#if defined(WIN32) || defined(__APPLE__)
|
|
if (!strcasecmp(absolute, absolute_history[i])) break;
|
|
#else
|
|
if (!strcmp(absolute, absolute_history[i])) break;
|
|
#endif // WIN32 || __APPLE__
|
|
|
|
if (i == 0) return;
|
|
|
|
if (i >= max_files) i = max_files - 1;
|
|
|
|
// Move the other flnames down in the list...
|
|
memmove(absolute_history + 1, absolute_history,
|
|
i * sizeof(absolute_history[0]));
|
|
memmove(relative_history + 1, relative_history,
|
|
i * sizeof(relative_history[0]));
|
|
|
|
// Put the new file at the top...
|
|
strlcpy(absolute_history[0], absolute, sizeof(absolute_history[0]));
|
|
|
|
fl_filename_relative(relative_history[0], sizeof(relative_history[0]),
|
|
absolute_history[0]);
|
|
|
|
// Update the menu items as needed...
|
|
for (i = 0; i < max_files; i ++) {
|
|
fluid_prefs.set( Fl_Preferences::Name("file%d", i), absolute_history[i]);
|
|
if (absolute_history[i][0]) {
|
|
if (i == 9) Main_Menu[i + HISTORY_ITEM].flags = FL_MENU_DIVIDER;
|
|
else Main_Menu[i + HISTORY_ITEM].flags = 0;
|
|
} else break;
|
|
}
|
|
|
|
for (; i < 10; i ++) {
|
|
fluid_prefs.set( Fl_Preferences::Name("file%d", i), "");
|
|
if (i) Main_Menu[i + HISTORY_ITEM - 1].flags |= FL_MENU_DIVIDER;
|
|
Main_Menu[i + HISTORY_ITEM].hide();
|
|
}
|
|
}
|
|
|
|
// ********** portable process class definition **********
|
|
|
|
class Fl_Process {
|
|
public:
|
|
// construction / destruction
|
|
Fl_Process() {_fpt= NULL;}
|
|
~Fl_Process() {if (_fpt) close();}
|
|
|
|
FILE * popen (const char *cmd, const char *mode="r");
|
|
//not necessary here: FILE * fopen (const char *file, const char *mode="r");
|
|
int close();
|
|
|
|
FILE * desc() const { return _fpt;} // non null if file is open
|
|
char * get_line(char * line, size_t s) const {return _fpt ? fgets(line, s, _fpt) : NULL;}
|
|
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
protected:
|
|
HANDLE pin[2], pout[2], perr[2];
|
|
char ptmode;
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
|
|
static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE);
|
|
|
|
private:
|
|
FILE * freeHandles() {
|
|
clean_close(pin[0]); clean_close(pin[1]);
|
|
clean_close(pout[0]); clean_close(pout[1]);
|
|
clean_close(perr[0]); clean_close(perr[1]);
|
|
return NULL; // convenient for error management
|
|
}
|
|
static void clean_close(HANDLE& h);
|
|
#endif
|
|
|
|
protected:
|
|
FILE * _fpt;
|
|
};
|
|
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) {
|
|
SECURITY_ATTRIBUTES sa;
|
|
sa.nLength = sizeof(sa);
|
|
sa.lpSecurityDescriptor = NULL;
|
|
sa.bInheritHandle = bInheritHnd;
|
|
return CreatePipe (&h[0],&h[1],&sa,0) ? true : false;
|
|
}
|
|
#endif
|
|
// portable open process:
|
|
FILE * Fl_Process::popen(const char *cmd, const char *mode) {
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
// PRECONDITIONS
|
|
if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL;
|
|
if (_fpt) close(); // close first before reuse
|
|
|
|
ptmode = *mode;
|
|
pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE;
|
|
// stderr to stdout wanted ?
|
|
int fusion = (strstr(cmd,"2>&1") !=NULL);
|
|
|
|
// Create windows pipes
|
|
if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) )
|
|
return freeHandles(); // error
|
|
|
|
// Initialize Startup Info
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.dwFlags = STARTF_USESTDHANDLES;
|
|
si.hStdInput = pin[0];
|
|
si.hStdOutput = pout[1];
|
|
si.hStdError = fusion ? pout[1] : perr [1];
|
|
|
|
if ( CreateProcess(NULL, (LPTSTR) cmd,NULL,NULL,TRUE,
|
|
DETACHED_PROCESS,NULL,NULL, &si, &pi)) {
|
|
// don't need theses handles inherited by child process:
|
|
clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]);
|
|
HANDLE & h = *mode == 'r' ? pout[0] : pin[1];
|
|
_fpt = _fdopen(_open_osfhandle((long) h,_O_BINARY),mode);
|
|
h= INVALID_HANDLE_VALUE; // reset the handle pointer that is shared
|
|
// with _fpt so we don't free it twice
|
|
}
|
|
|
|
if (!_fpt) freeHandles();
|
|
return _fpt;
|
|
#else
|
|
_fpt=::popen(cmd,mode);
|
|
return _fpt;
|
|
#endif
|
|
}
|
|
|
|
int Fl_Process::close() {
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
if (_fpt) {
|
|
fclose(_fpt);
|
|
clean_close(perr[0]);
|
|
clean_close(pin[1]);
|
|
clean_close(pout[0]);
|
|
_fpt = NULL;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
#else
|
|
int ret = ::pclose(_fpt);
|
|
_fpt=NULL;
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
void Fl_Process::clean_close(HANDLE& h) {
|
|
if (h!= INVALID_HANDLE_VALUE) CloseHandle(h);
|
|
h = INVALID_HANDLE_VALUE;
|
|
}
|
|
#endif
|
|
// ********** Fl_Process class end **********
|
|
|
|
static Fl_Process s_proc;
|
|
|
|
// Shell command support...
|
|
|
|
static bool prepare_shell_command(const char * &command) { // common pre-shell command code all platforms
|
|
shell_window->hide();
|
|
if (s_proc.desc()) {
|
|
fl_alert("Previous shell command still running!");
|
|
return false;
|
|
}
|
|
if ((command = shell_command_input->value()) == NULL || !*command) {
|
|
fl_alert("No shell command entered!");
|
|
return false;
|
|
}
|
|
if (shell_savefl_button->value()) {
|
|
save_cb(0, 0);
|
|
}
|
|
if (shell_writecode_button->value()) {
|
|
compile_only = 1;
|
|
write_cb(0, 0);
|
|
compile_only = 0;
|
|
}
|
|
if (shell_writemsgs_button->value()) {
|
|
compile_only = 1;
|
|
write_strings_cb(0, 0);
|
|
compile_only = 0;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#if !defined(__MWERKS__)
|
|
// Support the full piped shell command...
|
|
void
|
|
shell_pipe_cb(int, void*) {
|
|
char line[1024]=""; // Line from command output...
|
|
|
|
if (s_proc.get_line(line, sizeof(line)) != NULL) {
|
|
// Add the line to the output list...
|
|
shell_run_buffer->append(line);
|
|
} else {
|
|
// End of file; tell the parent...
|
|
Fl::remove_fd(fileno(s_proc.desc()));
|
|
s_proc.close();
|
|
shell_run_buffer->append("... END SHELL COMMAND ...\n");
|
|
}
|
|
|
|
shell_run_display->scroll(shell_run_display->count_lines(0,
|
|
shell_run_buffer->length(), 1), 0);
|
|
}
|
|
|
|
void
|
|
do_shell_command(Fl_Return_Button*, void*) {
|
|
const char *command=NULL; // Command to run
|
|
|
|
if (!prepare_shell_command(command)) return;
|
|
|
|
// Show the output window and clear things...
|
|
shell_run_buffer->text("");
|
|
shell_run_buffer->append(command);
|
|
shell_run_buffer->append("\n");
|
|
shell_run_window->label("Shell Command Running...");
|
|
|
|
if (s_proc.popen((char *)command) == NULL) {
|
|
fl_alert("Unable to run shell command: %s", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
shell_run_button->deactivate();
|
|
shell_run_window->hotspot(shell_run_display);
|
|
shell_run_window->show();
|
|
|
|
Fl::add_fd(fileno(s_proc.desc()), shell_pipe_cb);
|
|
|
|
while (s_proc.desc()) Fl::wait();
|
|
|
|
shell_run_button->activate();
|
|
shell_run_window->label("Shell Command Complete");
|
|
fl_beep();
|
|
|
|
while (shell_run_window->shown()) Fl::wait();
|
|
}
|
|
#else
|
|
// Just do basic shell command stuff, no status window...
|
|
void
|
|
do_shell_command(Fl_Return_Button*, void*) {
|
|
const char *command; // Command to run
|
|
int status; // Status from command...
|
|
|
|
if (!prepare_shell_command(command)) return;
|
|
|
|
if ((status = system(command)) != 0) {
|
|
fl_alert("Shell command returned status %d!", status);
|
|
} else if (completion_button->value()) {
|
|
fl_message("Shell command completed successfully!");
|
|
}
|
|
}
|
|
#endif // !__MWERKS__
|
|
|
|
void
|
|
show_shell_window() {
|
|
shell_window->hotspot(shell_command_input);
|
|
shell_window->show();
|
|
}
|
|
|
|
void set_filename(const char *c) {
|
|
if (filename) free((void *)filename);
|
|
filename = c ? strdup(c) : NULL;
|
|
|
|
if (filename) update_history(filename);
|
|
|
|
set_modflag(modflag);
|
|
}
|
|
|
|
//
|
|
// The Source View system offers an immediate preview of the code
|
|
// files that will be generated by FLUID. It also marks the code
|
|
// generated for the last selected item in the header and the source
|
|
// file.
|
|
//
|
|
// Can we patent this? ;-) - Matt, mm@matthiasm.com
|
|
//
|
|
|
|
//
|
|
// Update the header and source code highlighting depending on the
|
|
// currently selected object
|
|
//
|
|
void update_sourceview_position()
|
|
{
|
|
if (!sourceview_panel || !sourceview_panel->visible())
|
|
return;
|
|
if (sv_autoposition->value()==0)
|
|
return;
|
|
if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) {
|
|
int pos0, pos1;
|
|
if (sv_source->visible_r()) {
|
|
pos0 = Fl_Type::current->code_line;
|
|
pos1 = Fl_Type::current->code_line_end;
|
|
if (pos0>=0) {
|
|
if (pos1<pos0)
|
|
pos1 = pos0;
|
|
sv_source->buffer()->highlight(pos0, pos1);
|
|
int line = sv_source->buffer()->count_lines(0, pos0);
|
|
sv_source->scroll(line, 0);
|
|
}
|
|
}
|
|
if (sv_header->visible_r()) {
|
|
pos0 = Fl_Type::current->header_line;
|
|
pos1 = Fl_Type::current->header_line_end;
|
|
if (pos0>=0) {
|
|
if (pos1<pos0)
|
|
pos1 = pos0;
|
|
sv_header->buffer()->highlight(pos0, pos1);
|
|
int line = sv_header->buffer()->count_lines(0, pos0);
|
|
sv_header->scroll(line, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void update_sourceview_position_cb(Fl_Tabs*, void*)
|
|
{
|
|
update_sourceview_position();
|
|
}
|
|
|
|
static char *sv_source_filename = 0;
|
|
static char *sv_header_filename = 0;
|
|
|
|
//
|
|
// Generate a header and source file in a temporary directory and
|
|
// load those into the Code Viewer widgets.
|
|
//
|
|
void update_sourceview_cb(Fl_Button*, void*)
|
|
{
|
|
if (!sourceview_panel || !sourceview_panel->visible())
|
|
return;
|
|
// generate space for the source and header file filenames
|
|
if (!sv_source_filename) {
|
|
sv_source_filename = (char*)malloc(FL_PATH_MAX);
|
|
fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX);
|
|
strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX);
|
|
}
|
|
if (!sv_header_filename) {
|
|
sv_header_filename = (char*)malloc(FL_PATH_MAX);
|
|
fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX);
|
|
strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX);
|
|
}
|
|
|
|
strlcpy(i18n_program, fl_filename_name(sv_source_filename), sizeof(i18n_program));
|
|
fl_filename_setext(i18n_program, sizeof(i18n_program), "");
|
|
const char *code_file_name_bak = code_file_name;
|
|
code_file_name = sv_source_filename;
|
|
const char *header_file_name_bak = header_file_name;
|
|
header_file_name = sv_header_filename;
|
|
|
|
// generate the code and load the files
|
|
write_sourceview = 1;
|
|
// generate files
|
|
if (write_code(sv_source_filename, sv_header_filename))
|
|
{
|
|
// load file into source editor
|
|
int pos = sv_source->top_line();
|
|
sv_source->buffer()->loadfile(sv_source_filename);
|
|
sv_source->scroll(pos, 0);
|
|
// load file into header editor
|
|
pos = sv_header->top_line();
|
|
sv_header->buffer()->loadfile(sv_header_filename);
|
|
sv_header->scroll(pos, 0);
|
|
// update the source code highlighting
|
|
update_sourceview_position();
|
|
}
|
|
write_sourceview = 0;
|
|
|
|
code_file_name = code_file_name_bak;
|
|
header_file_name = header_file_name_bak;
|
|
}
|
|
|
|
void update_sourceview_timer(void*)
|
|
{
|
|
update_sourceview_cb(0,0);
|
|
}
|
|
|
|
// Set the "modified" flag and update the title of the main window...
|
|
void set_modflag(int mf) {
|
|
const char *basename;
|
|
static char title[1024];
|
|
|
|
modflag = mf;
|
|
|
|
if (main_window) {
|
|
if (!filename) basename = "Untitled.fl";
|
|
else if ((basename = strrchr(filename, '/')) != NULL) basename ++;
|
|
#if defined(WIN32) || defined(__EMX__)
|
|
else if ((basename = strrchr(filename, '\\')) != NULL) basename ++;
|
|
#endif // WIN32 || __EMX__
|
|
else basename = filename;
|
|
|
|
if (modflag) {
|
|
snprintf(title, sizeof(title), "%s (modified)", basename);
|
|
main_window->label(title);
|
|
} else main_window->label(basename);
|
|
}
|
|
// if the UI was modified in any way, update the Source View panel
|
|
if (sourceview_panel && sourceview_panel->visible() && sv_autorefresh->value())
|
|
{
|
|
// we will only update ealiest 0.5 seconds after the last change, and only
|
|
// if no other change was made, so dragging a widget will not generate any
|
|
// CPU load
|
|
Fl::remove_timeout(update_sourceview_timer, 0);
|
|
Fl::add_timeout(0.5, update_sourceview_timer, 0);
|
|
}
|
|
|
|
// Enable/disable the Save menu item...
|
|
if (modflag) Main_Menu[SAVE_ITEM].activate();
|
|
else Main_Menu[SAVE_ITEM].deactivate();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static int arg(int argc, char** argv, int& i) {
|
|
if (argv[i][1] == 'c' && !argv[i][2]) {compile_only = 1; i++; return 1;}
|
|
if (argv[i][1] == 'c' && argv[i][2] == 's' && !argv[i][3]) {compile_only = 1; compile_strings = 1; i++; return 1;}
|
|
if (argv[i][1] == 'o' && !argv[i][2] && i+1 < argc) {
|
|
code_file_name = argv[i+1];
|
|
code_file_set = 1;
|
|
i += 2;
|
|
return 2;
|
|
}
|
|
if (argv[i][1] == 'h' && !argv[i][2]) {
|
|
header_file_name = argv[i+1];
|
|
header_file_set = 1;
|
|
i += 2;
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if ! (defined(WIN32) && !defined (__CYGWIN__))
|
|
|
|
int quit_flag = 0;
|
|
#include <signal.h>
|
|
#ifdef _sigargs
|
|
#define SIGARG _sigargs
|
|
#else
|
|
#ifdef __sigargs
|
|
#define SIGARG __sigargs
|
|
#else
|
|
#define SIGARG int // you may need to fix this for older systems
|
|
#endif
|
|
#endif
|
|
|
|
extern "C" {
|
|
static void sigint(SIGARG) {
|
|
signal(SIGINT,sigint);
|
|
quit_flag = 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int main(int argc,char **argv) {
|
|
int i = 1;
|
|
if (!Fl::args(argc,argv,i,arg) || i < argc-1) {
|
|
fprintf(stderr,"usage: %s <switches> name.fl\n"
|
|
" -c : write .cxx and .h and exit\n"
|
|
" -cs : write .cxx and .h and strings and exit\n"
|
|
" -o <name> : .cxx output filename, or extension if <name> starts with '.'\n"
|
|
" -h <name> : .h output filename, or extension if <name> starts with '.'\n"
|
|
"%s\n", argv[0], Fl::help);
|
|
return 1;
|
|
}
|
|
const char *c = argv[i];
|
|
|
|
fl_register_images();
|
|
|
|
make_main_window();
|
|
|
|
#ifdef __APPLE__
|
|
fl_open_callback(apple_open_cb);
|
|
#endif // __APPLE__
|
|
|
|
if (c) set_filename(c);
|
|
if (!compile_only) {
|
|
Fl::visual((Fl_Mode)(FL_DOUBLE|FL_INDEX));
|
|
Fl_File_Icon::load_system_icons();
|
|
main_window->callback(exit_cb);
|
|
position_window(main_window,"main_window_pos", 1, 10, 30, WINWIDTH, WINHEIGHT );
|
|
main_window->show(argc,argv);
|
|
toggle_widgetbin_cb(0,0);
|
|
toggle_sourceview_cb(0,0);
|
|
if (!c && openlast_button->value() && absolute_history[0][0]) {
|
|
// Open previous file when no file specified...
|
|
open_history_cb(0, absolute_history[0]);
|
|
}
|
|
}
|
|
undo_suspend();
|
|
if (c && !read_file(c,0)) {
|
|
if (compile_only) {
|
|
fprintf(stderr,"%s : %s\n", c, strerror(errno));
|
|
exit(1);
|
|
}
|
|
fl_message("Can't read %s: %s", c, strerror(errno));
|
|
}
|
|
undo_resume();
|
|
if (compile_only) {
|
|
if (compile_strings) write_strings_cb(0,0);
|
|
write_cb(0,0);
|
|
exit(0);
|
|
}
|
|
set_modflag(0);
|
|
undo_clear();
|
|
#ifndef WIN32
|
|
signal(SIGINT,sigint);
|
|
#endif
|
|
|
|
grid_cb(horizontal_input, 0); // Makes sure that windows get snap params...
|
|
|
|
#ifdef WIN32
|
|
Fl::run();
|
|
#else
|
|
while (!quit_flag) Fl::wait();
|
|
|
|
if (quit_flag) exit_cb(0,0);
|
|
#endif // WIN32
|
|
|
|
undo_clear();
|
|
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// End of "$Id$".
|
|
//
|