value()) {
fl_message("Wrote %s", g_project.stringsfile_name().c_str());
}
}
}
/**
Show the editor for the \c current Fl_Type.
*/
void openwidget_cb(Fl_Widget *, void *) {
if (!Fl_Type::current) {
fl_message("Please select a widget");
return;
}
Fl_Type::current->open();
}
/**
User chose to copy the currently selected widgets.
*/
void copy_cb(Fl_Widget*, void*) {
flush_text_widgets();
if (!Fl_Type::current) {
fl_beep();
return;
}
flush_text_widgets();
ipasteoffset = 10;
if (!write_file(cutfname(),1)) {
fl_message("Can't write %s: %s", cutfname(), strerror(errno));
return;
}
}
/**
User chose to cut the currently selected widgets.
*/
void cut_cb(Fl_Widget *, void *) {
if (!Fl_Type::current) {
fl_beep();
return;
}
flush_text_widgets();
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);
widget_browser->rebuild();
}
/**
User chose to delete the currently selected widgets.
*/
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);
widget_browser->rebuild();
}
/**
User chose to paste the widgets from the cut buffer.
This function will paste the widgets in the cut buffer after the currently
selected widget. If the currently selected widget is a group widget and
it is not folded, the new widgets will be added inside the group.
*/
void paste_cb(Fl_Widget*, void*) {
pasteoffset = ipasteoffset;
undo_checkpoint();
undo_suspend();
Strategy strategy = Strategy::FROM_FILE_AFTER_CURRENT;
if (Fl_Type::current && Fl_Type::current->can_have_children()) {
if (Fl_Type::current->folded_ == 0) {
// If the current widget is a group widget and it is not folded,
// add the new widgets inside the group.
strategy = Strategy::FROM_FILE_AS_LAST_CHILD;
// The following alternative also works quite nicely
//strategy = Strategy::FROM_FILE_AS_FIRST_CHILD;
}
}
if (!read_file(cutfname(), 1, strategy)) {
widget_browser->rebuild();
fl_message("Can't read %s: %s", cutfname(), strerror(errno));
}
undo_resume();
widget_browser->display(Fl_Type::current);
widget_browser->rebuild();
pasteoffset = 0;
ipasteoffset += 10;
}
/**
Duplicate the selected widgets.
This code is a bit complex because it needs to find the last selected
widget with the lowest level, so that the new widgets are inserted after
this one.
*/
void duplicate_cb(Fl_Widget*, void*) {
if (!Fl_Type::current) {
fl_beep();
return;
}
// flush the text widgets to make sure the user's changes are saved:
flush_text_widgets();
// find the last selected node with the lowest level:
int lowest_level = 9999;
Fl_Type *new_insert = NULL;
if (Fl_Type::current->selected) {
for (Fl_Type *t = Fl_Type::first; t; t = t->next) {
if (t->selected && (t->level <= lowest_level)) {
lowest_level = t->level;
new_insert = t;
}
}
}
if (new_insert)
Fl_Type::current = new_insert;
// write the selected widgets to a file:
if (!write_file(cutfname(1),1)) {
fl_message("Can't write %s: %s", cutfname(1), strerror(errno));
return;
}
// read the file and add the widgets after the current one:
pasteoffset = 0;
undo_checkpoint();
undo_suspend();
if (!read_file(cutfname(1), 1, Strategy::FROM_FILE_AFTER_CURRENT)) {
fl_message("Can't read %s: %s", cutfname(1), strerror(errno));
}
fl_unlink(cutfname(1));
widget_browser->display(Fl_Type::current);
widget_browser->rebuild();
undo_resume();
}
/**
User wants to sort selected widgets by y coordinate.
*/
static void sort_cb(Fl_Widget *,void *) {
undo_checkpoint();
sort((Fl_Type*)NULL);
widget_browser->rebuild();
set_modflag(1);
}
/**
Open the "About" dialog.
*/
void about_cb(Fl_Widget *, void *) {
if (!about_panel) make_about_panel();
about_panel->show();
}
/**
Open a dialog to show the HTML help page form the FLTK documentation folder.
\param[in] name name of the HTML help file.
*/
void show_help(const char *name) {
const char *docdir;
char helpname[FL_PATH_MAX];
if (!help_dialog) help_dialog = new Fl_Help_Dialog();
if ((docdir = fl_getenv("FLTK_DOCDIR")) == NULL) {
docdir = FLTK_DOCDIR;
}
snprintf(helpname, sizeof(helpname), "%s/%s", docdir, name);
// make sure that we can read the file
FILE *f = fopen(helpname, "rb");
if (f) {
fclose(f);
help_dialog->load(helpname);
} else {
// if we can not read the file, we display the canned version instead
// or ask the native browser to open the page on www.fltk.org
if (strcmp(name, "fluid.html")==0) {
if (!Fl_Shared_Image::find("embedded:/fluid_flow_chart_800.png"))
new Fl_PNG_Image("embedded:/fluid_flow_chart_800.png", fluid_flow_chart_800_png, sizeof(fluid_flow_chart_800_png));
help_dialog->value
(
"\n"
"FLTK: Programming with FLUID\n"
"What is FLUID?
\n"
"The Fast Light User Interface Designer, or FLUID, is a graphical editor "
"that is used to produce FLTK source code. FLUID edits and saves its state "
"in .fl
files. These files are text, and you can (with care) "
"edit them in a text editor, perhaps to get some special effects.\n"
"FLUID can \"compile\" the .fl
file into a .cxx
"
"and a .h
file. The .cxx
file defines all the "
"objects from the .fl
file and the .h
file "
"declares all the global ones. FLUID also supports localization "
"(Internationalization) of label strings using message files and the GNU "
"gettext or POSIX catgets interfaces.
\n"
"A simple program can be made by putting all your code (including a "
"main()
function) into the .fl
file and thus making the "
".cxx
file a single source file to compile. Most programs are "
"more complex than this, so you write other .cxx
files that "
"call the FLUID functions. These .cxx
files must "
"#include
the .h
file or they can #include
"
"the .cxx
file so it still appears to be a single source file.
"
"
"
"More information is available online at https://www.fltk.org/"
""
);
} else if (strcmp(name, "license.html")==0) {
fl_open_uri("https://www.fltk.org/doc-1.4/license.html");
return;
} else if (strcmp(name, "index.html")==0) {
fl_open_uri("https://www.fltk.org/doc-1.4/index.html");
return;
} else {
snprintf(helpname, sizeof(helpname), "https://www.fltk.org/%s", name);
fl_open_uri(helpname);
return;
}
}
help_dialog->show();
}
/**
User wants help on Fluid.
*/
void help_cb(Fl_Widget *, void *) {
show_help("fluid.html");
}
/**
User wants to see the Fluid manual.
*/
void manual_cb(Fl_Widget *, void *) {
show_help("index.html");
}
// ---- Printing
/**
Open the dialog to allow the user to print the current window.
*/
void print_menu_cb(Fl_Widget *, void *) {
int w, h, ww, hh;
int frompage, topage;
Fl_Type *t; // Current widget
int num_windows; // Number of windows
Fl_Window_Type *windows[1000]; // Windows to print
int winpage; // Current window page
Fl_Window *win;
for (t = Fl_Type::first, num_windows = 0; t; t = t->next) {
if (t->is_a(ID_Window)) {
windows[num_windows] = (Fl_Window_Type *)t;
if (!((Fl_Window*)(windows[num_windows]->o))->shown()) continue;
num_windows ++;
}
}
Fl_Printer printjob;
if ( printjob.start_job(num_windows, &frompage, &topage) ) return;
int pagecount = 0;
for (winpage = 0; winpage < num_windows; winpage++) {
float scale = 1, scale_x = 1, scale_y = 1;
if (winpage+1 < frompage || winpage+1 > topage) continue;
printjob.start_page();
printjob.printable_rect(&w, &h);
// Get the time and date...
time_t curtime = time(NULL);
struct tm *curdate = localtime(&curtime);
char date[1024];
strftime(date, sizeof(date), "%c", curdate);
fl_font(FL_HELVETICA, 12);
fl_color(FL_BLACK);
fl_draw(date, (w - (int)fl_width(date))/2, fl_height());
sprintf(date, "%d/%d", ++pagecount, topage-frompage+1);
fl_draw(date, w - (int)fl_width(date), fl_height());
// Get the base filename...
Fl_String basename = fl_filename_name(Fl_String(filename));
fl_draw(basename.c_str(), 0, fl_height());
// print centered and scaled to fit in the page
win = (Fl_Window*)windows[winpage]->o;
ww = win->decorated_w();
if(ww > w) scale_x = float(w)/ww;
hh = win->decorated_h();
if(hh > h) scale_y = float(h)/hh;
if (scale_x < scale) scale = scale_x;
if (scale_y < scale) scale = scale_y;
if (scale < 1) {
printjob.scale(scale);
printjob.printable_rect(&w, &h);
}
printjob.origin(w/2, h/2);
printjob.print_window(win, -ww/2, -hh/2);
printjob.end_page();
}
printjob.end_job();
}
// ---- Main menu bar
extern void select_layout_preset_cb(Fl_Widget *, void *user_data);
extern void layout_suite_marker(Fl_Widget *, void *user_data);
static void menu_file_new_cb(Fl_Widget *, void *) { new_project(); }
static void menu_file_new_from_template_cb(Fl_Widget *, void *) { new_project_from_template(); }
static void menu_file_open_cb(Fl_Widget *, void *) { open_project_file(""); }
static void menu_file_insert_cb(Fl_Widget *, void *) { merge_project_file(""); }
static void menu_file_open_history_cb(Fl_Widget *, void *v) { open_project_file(Fl_String((const char*)v)); }
static void menu_layout_sync_resize_cb(Fl_Menu_ *m, void*) {
if (m->mvalue()->value()) Fl_Type::allow_layout = 1; else Fl_Type::allow_layout = 0; }
/**
This is the main Fluid menu.
Design history is manipulated right inside this menu structure.
Some menu items change or deactivate correctly, but most items just trigger
various callbacks.
\c New_Menu creates new widgets and is explained in detail in another location.
\see New_Menu
\todo This menu needs some major modernization. Menus are too long and their
sorting is not always obvious.
\todo Shortcuts are all over the place (Alt, Ctrl, Command, Shift-Ctrl,
function keys), and there should be a help page listing all shortcuts.
*/
Fl_Menu_Item Main_Menu[] = {
{"&File",0,0,0,FL_SUBMENU},
{"&New", FL_COMMAND+'n', menu_file_new_cb},
{"&Open...", FL_COMMAND+'o', menu_file_open_cb},
{"&Insert...", FL_COMMAND+'i', menu_file_insert_cb, 0, FL_MENU_DIVIDER},
{"&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},
{"&Revert...", 0, revert_cb, 0, FL_MENU_DIVIDER},
{"New &From Template...", FL_COMMAND+'N', menu_file_new_from_template_cb, 0},
{"Save As &Template...", 0, save_template_cb, 0, FL_MENU_DIVIDER},
{"&Print...", FL_COMMAND+'p', print_menu_cb},
{"Write &Code", FL_COMMAND+FL_SHIFT+'c', write_cb, 0},
// Matt: disabled {"MergeBack Code", FL_COMMAND+FL_SHIFT+'m', mergeback_cb, 0},
{"&Write Strings", FL_COMMAND+FL_SHIFT+'w', write_strings_cb, 0, FL_MENU_DIVIDER},
{relative_history[0], FL_COMMAND+'1', menu_file_open_history_cb, absolute_history[0]},
{relative_history[1], FL_COMMAND+'2', menu_file_open_history_cb, absolute_history[1]},
{relative_history[2], FL_COMMAND+'3', menu_file_open_history_cb, absolute_history[2]},
{relative_history[3], FL_COMMAND+'4', menu_file_open_history_cb, absolute_history[3]},
{relative_history[4], FL_COMMAND+'5', menu_file_open_history_cb, absolute_history[4]},
{relative_history[5], FL_COMMAND+'6', menu_file_open_history_cb, absolute_history[5]},
{relative_history[6], FL_COMMAND+'7', menu_file_open_history_cb, absolute_history[6]},
{relative_history[7], FL_COMMAND+'8', menu_file_open_history_cb, absolute_history[7]},
{relative_history[8], FL_COMMAND+'9', menu_file_open_history_cb, absolute_history[8]},
{relative_history[9], 0, menu_file_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},
{"Hide Guides",FL_COMMAND+FL_SHIFT+'g',toggle_guides},
{"Hide Restricted",FL_COMMAND+FL_SHIFT+'r',toggle_restricted},
{"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb},
{"Show Code View",FL_ALT+'c', (Fl_Callback*)toggle_codeview_cb, 0, FL_MENU_DIVIDER},
{"Settings...",FL_ALT+'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},
{"Synchronized Resize", 0, (Fl_Callback*)menu_layout_sync_resize_cb, NULL, FL_MENU_TOGGLE|FL_MENU_DIVIDER },
{"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb, NULL, FL_MENU_DIVIDER},
{"Presets", 0, layout_suite_marker, (void*)main_layout_submenu_, FL_SUBMENU_POINTER },
{"Application", 0, select_layout_preset_cb, (void*)0, FL_MENU_RADIO|FL_MENU_VALUE },
{"Dialog", 0, select_layout_preset_cb, (void*)1, FL_MENU_RADIO },
{"Toolbox", 0, select_layout_preset_cb, (void*)2, FL_MENU_RADIO },
{0},
{"&Shell", 0, Fd_Shell_Command_List::menu_marker, (void*)Fd_Shell_Command_List::default_menu, FL_SUBMENU_POINTER},
{"&Help",0,0,0,FL_SUBMENU},
{"&Rapid development with FLUID...",0,help_cb},
{"&FLTK Programmers Manual...",0,manual_cb, 0, FL_MENU_DIVIDER},
{"&About FLUID...",0,about_cb},
{0},
{0}};
/**
Change the app's and hence preview the design's scheme.
The scheme setting is stored in the app preferences
- in key \p 'scheme_name' since 1.4.0
- in key \p 'scheme' (index: 0 - 4) in 1.3.x
This callback is triggered by changing the scheme in the
Fl_Scheme_Choice widget (\p Edit/GUI Settings).
\param[in] choice the calling widget
\see init_scheme() for choice values and backwards compatibility
*/
void scheme_cb(Fl_Scheme_Choice *choice, void *) {
if (batch_mode)
return;
// set the new scheme only if the scheme was changed
const char *new_scheme = choice->text(choice->value());
if (Fl::is_scheme(new_scheme))
return;
Fl::scheme(new_scheme);
fluid_prefs.set("scheme_name", new_scheme);
// Backwards compatibility: store 1.3 scheme index (1-4).
// We assume that index 0-3 (base, plastic, gtk+, gleam) are in the
// same order as in 1.3.x (index 1-4), higher values are ignored
int scheme_index = scheme_choice->value();
if (scheme_index <= 3) // max. index for 1.3.x (Gleam)
fluid_prefs.set("scheme", scheme_index + 1); // compensate for different indexing
}
/**
Read Fluid's scheme preferences and set the app's scheme.
Since FLTK 1.4.0 the scheme \b name is stored as a character string
with key "scheme_name" in the preference database.
In FLTK 1.3.x the scheme preference was stored as an integer index
with key "scheme" in the database. The known schemes were hardcoded in
Fluid's sources (here for reference):
| Index | 1.3 Scheme Name | Choice | 1.4 Scheme Name |
|-------|-----------------|-------|-----------------|
| 0 | Default (same as None) | n/a | n/a |
| 1 | None (same as Default) | 0 | base |
| 2 | Plastic | 1 | plastic |
| 3 | GTK+ | 2 | gtk+ |
| 4 | Gleam | 3 | gleam |
| n/a | n/a | 4 | oxy |
The new Fluid tries to keep backwards compatibility and reads both
keys (\p scheme and \p scheme_name). If the latter is defined, it is used.
If not the old \p scheme (index) is used - but we need to subtract one to
get the new Fl_Scheme_Choice index (column "Choice" above).
*/
void init_scheme() {
int scheme_index = 0; // scheme index for backwards compatibility (1.3.x)
char *scheme_name = 0; // scheme name since 1.4.0
fluid_prefs.get("scheme_name", scheme_name, "XXX"); // XXX means: not set => fallback 1.3.x
if (!strcmp(scheme_name, "XXX")) {
fluid_prefs.get("scheme", scheme_index, 0);
if (scheme_index > 0) {
scheme_index--;
scheme_choice->value(scheme_index); // set the choice value
}
if (scheme_index < 0)
scheme_index = 0;
else if (scheme_index > scheme_choice->size() - 1)
scheme_index = 0;
scheme_name = const_cast(scheme_choice->text(scheme_index));
fluid_prefs.set("scheme_name", scheme_name);
}
// Set the new scheme only if it was not overridden by the -scheme
// command line option
if (Fl::scheme() == NULL) {
Fl::scheme(scheme_name);
}
free(scheme_name);
}
/**
Show or hide the widget bin.
The state is stored in the app preferences.
*/
void toggle_widgetbin_cb(Fl_Widget *, void *) {
if (!widgetbin_panel) {
make_widgetbin();
if (!position_window(widgetbin_panel,"widgetbin_pos", 1, 320, 30)) return;
}
if (widgetbin_panel->visible()) {
widgetbin_panel->hide();
widgetbin_item->label("Show Widget &Bin...");
} else {
widgetbin_panel->show();
widgetbin_item->label("Hide Widget &Bin");
}
}
/**
Show or hide the code preview window.
*/
void toggle_codeview_cb(Fl_Double_Window *, void *) {
codeview_toggle_visibility();
}
/**
Show or hide the code preview window, button callback.
*/
void toggle_codeview_b_cb(Fl_Button*, void *) {
codeview_toggle_visibility();
}
/**
Build the main app window and create a few other dialogs.
*/
void make_main_window() {
if (!batch_mode) {
fluid_prefs.get("show_guides", show_guides, 1);
fluid_prefs.get("show_restricted", show_restricted, 1);
fluid_prefs.get("show_ghosted_outline", show_ghosted_outline, 0);
fluid_prefs.get("show_comments", show_comments, 1);
make_shell_window();
}
if (!main_window) {
Fl_Widget *o;
loadPixmaps();
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);
// quick access to all dynamic menu items
save_item = (Fl_Menu_Item*)main_menubar->find_item(save_cb);
history_item = (Fl_Menu_Item*)main_menubar->find_item(menu_file_open_history_cb);
widgetbin_item = (Fl_Menu_Item*)main_menubar->find_item(toggle_widgetbin_cb);
codeview_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_codeview_cb);
overlay_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_overlays);
guides_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_guides);
restricted_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_restricted);
main_menubar->global();
fill_in_New_Menu();
main_window->end();
}
if (!batch_mode) {
load_history();
g_shell_config = new Fd_Shell_Command_List;
widget_browser->load_prefs();
make_settings_window();
}
}
/**
Load file history from preferences.
This loads the absolute filepaths of the last 10 used design files.
It also computes and stores the relative filepaths for display in
the main menu.
*/
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 shortened version of the filename for the menu...
Fl_String fn = fl_filename_shortened(absolute_history[i], 48);
strncpy(relative_history[i], fn.c_str(), sizeof(relative_history[i]) - 1);
if (i == 9) history_item[i].flags = FL_MENU_DIVIDER;
else history_item[i].flags = 0;
} else break;
}
for (; i < 10; i ++) {
if (i) history_item[i-1].flags |= FL_MENU_DIVIDER;
history_item[i].hide();
}
}
/**
Update file history from preferences.
Add this new filepath to the history and update the main menu.
Writes the new file history to the app preferences.
\param[in] flname path or filename of .fl file, will be converted into an
absolute file path based on the current working directory.
*/
void update_history(const char *flname) {
int i; // Looping var
char absolute[FL_PATH_MAX];
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);
#ifdef _WIN32
// Make path canonical.
for (char *s = absolute; *s; s++) {
if (*s == '\\')
*s = '/';
}
#endif
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_String fn = fl_filename_shortened(absolute_history[0], 48);
strncpy(relative_history[0], fn.c_str(), sizeof(relative_history[0]) - 1);
// 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) history_item[i].flags = FL_MENU_DIVIDER;
else history_item[i].flags = 0;
} else break;
}
for (; i < 10; i ++) {
fluid_prefs.set( Fl_Preferences::Name("file%d", i), "");
if (i) history_item[i-1].flags |= FL_MENU_DIVIDER;
history_item[i].hide();
}
fluid_prefs.flush();
}
/**
Set the filename of the current .fl design.
\param[in] c the new absolute filename and path
*/
void set_filename(const char *c) {
if (filename) free((void *)filename);
filename = c ? fl_strdup(c) : NULL;
if (filename && !batch_mode)
update_history(filename);
set_modflag(modflag);
}
/**
Set the "modified" flag and update the title of the main window.
The first argument sets the modification state of the current design against
the corresponding .fl design file. Any change to the widget tree will mark
the design 'modified'. Saving the design will mark it clean.
The second argument is optional and set the modification state of the current
design against the source code and header file. Any change to the tree,
including saving the tree, will mark the code 'outdated'. Generating source
code and header files will clear this flag until the next modification.
\param[in] mf 0 to clear the modflag, 1 to mark the design "modified", -1 to
ignore this parameter
\param[in] mfc default -1 to let \c mf control \c modflag_c, 0 to mark the
code files current, 1 to mark it out of date. -2 to ignore changes to mf.
*/
void set_modflag(int mf, int mfc) {
const char *code_ext = NULL;
char new_title[FL_PATH_MAX];
// Update the modflag_c to the worst possible condition. We could be a bit
// more graceful and compare modification times of the files, but C++ has
// no API for that until C++17.
if (mf!=-1) {
modflag = mf;
if (mfc==-1 && mf==1)
mfc = mf;
}
if (mfc>=0) {
modflag_c = mfc;
}
if (main_window) {
Fl_String basename;
if (!filename) basename = "Untitled.fl";
else basename = fl_filename_name(Fl_String(filename));
code_ext = fl_filename_ext(g_project.code_file_name.c_str());
char mod_star = modflag ? '*' : ' ';
char mod_c_star = modflag_c ? '*' : ' ';
snprintf(new_title, sizeof(new_title), "%s%c %s%c",
basename.c_str(), mod_star, code_ext, mod_c_star);
const char *old_title = main_window->label();
// only update the title if it actually changed
if (!old_title || strcmp(old_title, new_title))
main_window->copy_label(new_title);
}
// if the UI was modified in any way, update the Code View panel
if (codeview_panel && codeview_panel->visible() && cv_autorefresh->value())
codeview_defer_update();
}
// ---- Main program entry point
/**
Handle command line arguments.
\param[in] argc number of arguments in the list
\param[in] argv pointer to an array of arguments
\param[inout] i current argument index
\return number of arguments used; if 0, the argument is not supported
*/
static int arg(int argc, char** argv, int& i) {
if (argv[i][0] != '-')
return 0;
if (argv[i][1] == 'd' && !argv[i][2]) {
G_debug=1;
i++; return 1;
}
if (argv[i][1] == 'u' && !argv[i][2]) {
update_file++;
batch_mode++;
i++; return 1;
}
if (argv[i][1] == 'c' && !argv[i][2]) {
compile_file++;
batch_mode++;
i++; return 1;
}
if ((strcmp(argv[i], "-v")==0) || (strcmp(argv[i], "--version")==0)) {
show_version = 1;
i++; return 1;
}
if (argv[i][1] == 'c' && argv[i][2] == 's' && !argv[i][3]) {
compile_file++;
compile_strings++;
batch_mode++;
i++; return 1;
}
if (argv[i][1] == 'o' && !argv[i][2] && i+1 < argc) {
g_code_filename_arg = argv[i+1];
batch_mode++;
i += 2; return 2;
}
#ifndef NDEBUG
if ((i+1 < argc) && (strcmp(argv[i], "--autodoc") == 0)) {
g_autodoc_path = argv[i+1];
i += 2; return 2;
}
#endif
if (strcmp(argv[i], "--help")==0) {
return 0;
}
if (argv[i][1] == 'h' && !argv[i][2]) {
if ( (i+1 < argc) && (argv[i+1][0] != '-') ) {
g_header_filename_arg = argv[i+1];
batch_mode++;
i += 2;
return 2;
} else {
// a lone "-h" without a filename will output the help string
return 0;
}
}
return 0;
}
#if ! (defined(_WIN32) && !defined (__CYGWIN__))
int quit_flag = 0;
#include
#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
/**
Start Fluid.
Fluid can run in interactive mode with a full user interface to design new
user interfaces and write the C++ files to manage them,
Fluid can run form the command line in batch mode to convert .fl design files
into C++ source and header files. In batch mode, no display is needed,
particularly no X11 connection will be attempted on Linux/Unix.
\param[in] argc number of arguments in the list
\param[in] argv pointer to an array of arguments
\return in batch mode, an error code will be returned via \c exit() . This
function return 1, if there was an error in the parameters list.
\todo On Windows, Fluid can under certain conditions open a dialog box, even
in batch mode. Is that intentional? Does it circumvent issues with Windows'
stderr and stdout?
*/
int main(int argc,char **argv) {
int i = 1;
setlocale(LC_ALL, ""); // enable multi-language errors in file chooser
setlocale(LC_NUMERIC, "C"); // make sure numeric values are written correctly
g_launch_path = end_with_slash(fl_getcwd()); // store the current path at launch
Fl::args_to_utf8(argc, argv); // for MSYS2/MinGW
if ( (Fl::args(argc,argv,i,arg) == 0) // unsupported argument found
|| (batch_mode && (i != argc-1)) // .fl filename missing
|| (!batch_mode && (i < argc-1)) // more than one filename found
|| (argv[i] && (argv[i][0] == '-'))) { // unknown option
static const char *msg =
"usage: %s name.fl\n"
" -u : update .fl file and exit (may be combined with '-c' or '-cs')\n"
" -c : write .cxx and .h and exit\n"
" -cs : write .cxx and .h and strings and exit\n"
" -o : .cxx output filename, or extension if starts with '.'\n"
" -h : .h output filename, or extension if starts with '.'\n"
" --help : brief usage information\n"
" --version, -v : print fluid version number\n"
" -d : enable internal debugging\n";
const char *app_name = NULL;
if ( (argc > 0) && argv[0] && argv[0][0] )
app_name = fl_filename_name(argv[0]);
if ( !app_name || !app_name[0])
app_name = "fluid";
#ifdef _MSC_VER
// TODO: if this is fluid-cmd, use stderr and not fl_message
fl_message(msg, app_name);
#else
fprintf(stderr, msg, app_name);
#endif
return 1;
}
if (show_version) {
printf("fluid v%d.%d.%d\n", FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION);
::exit(0);
}
const char *c = NULL;
if (g_autodoc_path.empty())
c = argv[i];
fl_register_images();
make_main_window();
if (c) set_filename(c);
if (!batch_mode) {
#ifdef __APPLE__
fl_open_callback(apple_open_cb);
#endif // __APPLE__
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 );
if (g_shell_config) {
g_shell_config->read(fluid_prefs, FD_STORE_USER);
g_shell_config->update_settings_dialog();
g_shell_config->rebuild_shell_menu();
}
g_layout_list.read(fluid_prefs, FD_STORE_USER);
main_window->show(argc,argv);
toggle_widgetbin_cb(0,0);
toggle_codeview_cb(0,0);
if (!c && openlast_button->value() && absolute_history[0][0] && g_autodoc_path.empty()) {
// Open previous file when no file specified...
open_project_file(absolute_history[0]);
}
}
undo_suspend();
if (c && !read_file(c,0)) {
if (batch_mode) {
fprintf(stderr,"%s : %s\n", c, strerror(errno));
exit(1);
}
fl_message("Can't read %s: %s", c, strerror(errno));
}
undo_resume();
// command line args override code and header filenames from the project file
// in batch mode only
if (batch_mode) {
if (!g_code_filename_arg.empty()) {
g_project.code_file_set = 1;
g_project.code_file_name = g_code_filename_arg;
}
if (!g_header_filename_arg.empty()) {
g_project.header_file_set = 1;
g_project.header_file_name = g_header_filename_arg;
}
}
if (update_file) { // fluid -u
write_file(c,0);
if (!compile_file)
exit(0);
}
if (compile_file) { // fluid -c[s]
if (compile_strings)
write_strings_cb(0,0);
write_cb(0,0);
exit(0);
}
// don't lock up if inconsistent command line arguments were given
if (batch_mode)
exit(0);
set_modflag(0);
undo_clear();
#ifndef _WIN32
signal(SIGINT,sigint);
#endif
// Set (but do not start) timer callback for external editor updates
ExternalCodeEditor::set_update_timer_callback(external_editor_timer);
#ifndef NDEBUG
// check if the user wants FLUID to generate image for the user documentation
if (!g_autodoc_path.empty()) {
run_autodoc(g_autodoc_path);
set_modflag(0, 0);
exit_cb(0,0);
return 0;
}
#endif
#ifdef _WIN32
Fl::run();
#else
while (!quit_flag) Fl::wait();
if (quit_flag) exit_cb(0,0);
#endif // _WIN32
undo_clear();
return (0);
}
/// \}
fltk-1.4.3/fluid/icons/ 0000755 0001750 0001750 00000000000 15004135251 015023 5 ustar albrecht albrecht fltk-1.4.3/fluid/icons/language_64.png 0000644 0001750 0001750 00000002652 15004135251 017632 0 ustar albrecht albrecht PNG
IHDR ` @ O= qIDAThkLU
,tKKAj[(b5hbBC&6~0~0&ƄVb b[ZZ
X`,f.̚xÞ{g{ uY+@Y`/H4f]N?KH4`4$KRQJ:p*1J "'`Zŵ挀,\Ht |f3$q9ZXծPXW`rEG4 8rM+Ie8ͼEVSUN "T!-~%.96>ǝ&er\̦0rzI;0(0̉5Ќ?i i`eJsMA*t*+ؽ5.YY(JP# st\vx@1ۼɼnq f/j4Mcj4P`?9]A/8oqA
=CC1jI'@x,gD)ICv] & Y8]%ۻy !R X~q?h'+\!Es>
b2ĘBR 8V6ke N "%EkD5xE1\.TTv mBoqls[̄1 Ȟ%udB y N,~=AG9 U2~ B[ JJ^ݣ&ޡI?~2nήD/_r-Jxڞ d*TVw #jatqO.$@3y=9(<+ʝ|#]Q~G 9ce(ò6r|5 }5Q