diff options
Diffstat (limited to 'fluid')
51 files changed, 3800 insertions, 2425 deletions
diff --git a/fluid/CMakeLists.txt b/fluid/CMakeLists.txt index ffcb4c4c1..d45b7b1b7 100644 --- a/fluid/CMakeLists.txt +++ b/fluid/CMakeLists.txt @@ -33,8 +33,10 @@ set (CPPFILES fluid.cxx function_panel.cxx pixmaps.cxx + shell_command.cxx template_panel.cxx undo.cxx + widget_browser.cxx widget_panel.cxx ) @@ -42,19 +44,30 @@ set (CPPFILES set (HEADERFILES CodeEditor.h + Fl_Function_Type.h + Fl_Group_Type.h + Fl_Menu_Type.h Fl_Type.h Fl_Widget_Type.h + Fl_Window_Type.h Fluid_Image.h Shortcut_Button.h StyleParse.h about_panel.h + align_widget.h alignment_panel.h + code.h comments.h + factory.h + file.h + fluid.h function_panel.h print_panel.h pixmaps.h + shell_command.h template_panel.h undo.h + widget_browser.h widget_panel.h ) diff --git a/fluid/CodeEditor.cxx b/fluid/CodeEditor.cxx index a6bfecc48..773a19000 100644 --- a/fluid/CodeEditor.cxx +++ b/fluid/CodeEditor.cxx @@ -19,12 +19,26 @@ // Include necessary headers... // +#include "CodeEditor.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> -#include "CodeEditor.h" +// ---- CodeEditor implementation + +/** \class CodeEditor + A widget derived from Fl_Text_Editor that implements C++ code highlighting. + + CodeEditor is used in Fluid whenever the user can edit C++ source + code or header text. + */ + +/** + Lookup table for all supported styles. + Every table entry describes a rendering style for the corresponding text. + */ Fl_Text_Display::Style_Table_Entry CodeEditor:: styletable[] = { // Style table { FL_FOREGROUND_COLOR, FL_COURIER, 11 }, // A - Plain @@ -37,18 +51,13 @@ Fl_Text_Display::Style_Table_Entry CodeEditor:: { 220, /* med cyan */ FL_COURIER, 11 } // H - Single quote chars }; -// attempt to make the fluid code editor widget honour textsize setting -void CodeEditor::textsize(Fl_Fontsize s) { - Fl_Text_Editor::textsize(s); // call base class method - // now attempt to update our styletable to honour the new size... - int entries = sizeof(styletable) / sizeof(styletable[0]); - for(int iter = 0; iter < entries; iter++) { - styletable[iter].size = s; - } -} // textsize - - -// 'style_parse()' - Parse text and produce style data. +/** + Parse text and produce style data. + \param[in] in_tbuff text buffer to parse + \param[inout] in_sbuf style buffer we modify + \param[in] in_len byte length to parse + \param[in] in_style starting style letter + */ void CodeEditor::style_parse(const char *in_tbuff, // text buffer to parse char *in_sbuff, // style buffer we modify int in_len, // byte length to parse @@ -99,10 +108,19 @@ void CodeEditor::style_parse(const char *in_tbuff, // text buffer to par } } -// 'style_unfinished_cb()' - Update unfinished styles. -void CodeEditor::style_unfinished_cb(int, void*) { } +/** + Update unfinished styles. + */ +void CodeEditor::style_unfinished_cb(int, void*) { +} -// 'style_update()' - Update the style buffer... +/** + Update the style buffer. + \param[in] pos insert position in text + \param[in] nInserted number of bytes inserted + \param[in] nDeleted number of bytes deleted + \param[in] cbArg pointer back to the code editr + */ void CodeEditor::style_update(int pos, int nInserted, int nDeleted, int /*nRestyled*/, const char * /*deletedText*/, void *cbArg) { @@ -150,6 +168,10 @@ void CodeEditor::style_update(int pos, int nInserted, int nDeleted, free(style); } +/** + Find the right indentation depth after pressing the Enter key. + \param[in] e pointer back to the code editor + */ int CodeEditor::auto_indent(int, CodeEditor* e) { if (e->buffer()->selected()) { e->insert_position(e->buffer()->primary_selection()->start()); @@ -183,7 +205,11 @@ int CodeEditor::auto_indent(int, CodeEditor* e) { return 1; } -// Create a CodeEditor widget... +/** + Create a CodeEditor widget. + \param[in] X, Y, W, H position and size of the widget + \param[in] L optional label + */ CodeEditor::CodeEditor(int X, int Y, int W, int H, const char *L) : Fl_Text_Editor(X, Y, W, H, L) { buffer(new Fl_Text_Buffer); @@ -209,7 +235,9 @@ CodeEditor::CodeEditor(int X, int Y, int W, int H, const char *L) : (Fl_Text_Editor::Key_Func)auto_indent); } -// Destroy a CodeEditor widget... +/** + Destroy a CodeEditor widget. + */ CodeEditor::~CodeEditor() { Fl_Text_Buffer *buf = mStyleBuffer; mStyleBuffer = 0; @@ -220,7 +248,35 @@ CodeEditor::~CodeEditor() { delete buf; } +/** + Attempt to make the fluid code editor widget honour textsize setting. + This works by updating the fontsizes in the style table. + \param[in] s the new general height of the text font + */ +void CodeEditor::textsize(Fl_Fontsize s) { + Fl_Text_Editor::textsize(s); // call base class method + // now attempt to update our styletable to honour the new size... + int entries = sizeof(styletable) / sizeof(styletable[0]); + for(int iter = 0; iter < entries; iter++) { + styletable[iter].size = s; + } +} // textsize + +// ---- CodeViewer implementation +/** \class CodeViewer + A widget derived from CodeEditor with highlighting for code blocks. + + This widget is used by the SourceView system to show the design's + source an header code. The secondary highlighting show the text + part that corresponds to the selected widget(s). + */ + +/** + Create a CodeViewer widget. + \param[in] X, Y, W, H position and size of the widget + \param[in] L optional label + */ CodeViewer::CodeViewer(int X, int Y, int W, int H, const char *L) : CodeEditor(X, Y, W, H, L) { @@ -229,10 +285,11 @@ CodeViewer::CodeViewer(int X, int Y, int W, int H, const char *L) cursor_style(CARET_CURSOR); } - +/** + Tricking Fl_Text_Display into using bearable colors for this specific task. + */ void CodeViewer::draw() { - // Tricking Fl_Text_Display into using bearable colors for this specific task Fl_Color c = Fl::get_color(FL_SELECTION_COLOR); Fl::set_color(FL_SELECTION_COLOR, fl_color_average(FL_BACKGROUND_COLOR, FL_FOREGROUND_COLOR, 0.9f)); CodeEditor::draw(); diff --git a/fluid/CodeEditor.h b/fluid/CodeEditor.h index bf4b7b499..d30f1b680 100644 --- a/fluid/CodeEditor.h +++ b/fluid/CodeEditor.h @@ -1,7 +1,8 @@ // // Code editor widget for the Fast Light Tool Kit (FLTK). +// Syntax highlighting rewritten by erco@seriss.com 09/15/20. // -// Copyright 1998-2020 by Bill Spitzak and others. +// Copyright 1998-2021 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -21,51 +22,44 @@ // Include necessary headers... // +#include "StyleParse.h" + +#include <FL/Fl.H> +#include <FL/Fl_Text_Buffer.H> +#include <FL/Fl_Text_Editor.H> + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> -#include <FL/Fl.H> -#include <FL/Fl_Text_Buffer.H> -#include <FL/Fl_Text_Editor.H> -#include "StyleParse.h" + +// ---- CodeEditor declaration class CodeEditor : public Fl_Text_Editor { friend class StyleParse; static Fl_Text_Display::Style_Table_Entry styletable[]; - - // 'style_parse()' - Parse text and produce style data. static void style_parse(const char *tbuff, char *sbuff, int len, char style); - - // 'style_unfinished_cb()' - Update unfinished styles. static void style_unfinished_cb(int, void*); - - // 'style_update()' - Update the style buffer... static void style_update(int pos, int nInserted, int nDeleted, int /*nRestyled*/, const char * /*deletedText*/, void *cbArg); - static int auto_indent(int, CodeEditor* e); - public: - +public: CodeEditor(int X, int Y, int W, int H, const char *L=0); ~CodeEditor(); int top_line() { return get_absolute_top_line_number(); } - - // attempt to make the fluid code editor widget honour textsize setting void textsize(Fl_Fontsize s); }; -class CodeViewer : public CodeEditor { - - public: +// ---- CodeViewer declaration +class CodeViewer : public CodeEditor { +public: CodeViewer(int X, int Y, int W, int H, const char *L=0); - protected: - +protected: int handle(int ev) { return Fl_Text_Display::handle(ev); } void draw(); }; diff --git a/fluid/ExternalCodeEditor_UNIX.cxx b/fluid/ExternalCodeEditor_UNIX.cxx index c0f753550..8ff27d036 100644 --- a/fluid/ExternalCodeEditor_UNIX.cxx +++ b/fluid/ExternalCodeEditor_UNIX.cxx @@ -3,6 +3,14 @@ // // Note: This entire file Unix only +#include "ExternalCodeEditor_UNIX.h" + +#include "fluid.h" + +#include <FL/Fl.H> /* Fl_Timeout_Handler.. */ +#include <FL/fl_ask.H> /* fl_alert() */ +#include <FL/fl_string.h> /* fl_strdup() */ + #include <errno.h> /* errno */ #include <string.h> /* strerror() */ #include <sys/types.h> /* stat().. */ @@ -14,14 +22,6 @@ #include <stdlib.h> /* free().. */ #include <stdio.h> /* snprintf().. */ -#include <FL/Fl.H> /* Fl_Timeout_Handler.. */ -#include <FL/fl_ask.H> /* fl_alert() */ -#include <FL/fl_string.h> /* fl_strdup() */ - -#include "ExternalCodeEditor_UNIX.h" - -extern int G_debug; // defined in fluid.cxx - // Static local data static int L_editors_open = 0; // keep track of #editors open static Fl_Timeout_Handler L_update_timer_cb = 0; // app's update timer callback @@ -40,7 +40,20 @@ static int is_dir(const char *dirname) { return(S_ISDIR(buf.st_mode) ? 1 : 0); // a dir? } -// CTOR +// ---- ExternalCodeEditor implementation + +/** \class ExternalCodeEditor + Support for an external C++ code editor for Fluid Code block. + + This class can launch and quit a user defined program for editiing + code outside of Fluid. + It observes changes in the external file and updates the Fluid + widget to stay synchronized. + */ + +/** + Create the manager for external code editors. + */ ExternalCodeEditor::ExternalCodeEditor() { pid_ = -1; filename_ = 0; @@ -48,7 +61,10 @@ ExternalCodeEditor::ExternalCodeEditor() { file_size_ = 0; } -// DTOR +/** + Destroy the manager. + This also closes the external editor. + */ ExternalCodeEditor::~ExternalCodeEditor() { if ( G_debug ) printf("ExternalCodeEditor() DTOR CALLED (this=%p, pid=%ld)\n", @@ -57,20 +73,28 @@ ExternalCodeEditor::~ExternalCodeEditor() { set_filename(0); // free()s filename } -// [Protected] Set the filename. Handles memory allocation/free -// If set to NULL, frees memory. -// +/** + Set the filename for the file we wish to edit. + Handles memory allocation/free. + If set to NULL, frees memory. + \param[in] val new filename + */ void ExternalCodeEditor::set_filename(const char *val) { if ( filename_ ) free((void*)filename_); filename_ = val ? fl_strdup(val) : 0; } -// [Public] Is editor running? +/** + Is editor running? + \return 1 if we are currently editing a file. + */ int ExternalCodeEditor::is_editing() { return( (pid_ != -1) ? 1 : 0 ); } -// [Protected] Wait for editor to close +/** + Wait for editor to close + */ void ExternalCodeEditor::close_editor() { if ( G_debug ) printf("close_editor() called: pid=%ld\n", long(pid_)); // Wait until editor is closed + reaped @@ -101,10 +125,12 @@ void ExternalCodeEditor::close_editor() { } } -// [Protected] Kill the running editor (if any) -// Kills the editor, reaps the process, and removes the tmp file. -// The dtor calls this to ensure no editors remain running when fluid exits. -// +/** + Kill the running editor (if any). + + Kills the editor, reaps the process, and removes the tmp file. + The dtor calls this to ensure no editors remain running when fluid exits. + */ void ExternalCodeEditor::kill_editor() { if ( G_debug ) printf("kill_editor() called: pid=%ld\n", (long)pid_); if ( !is_editing() ) return; // editor not running? return.. @@ -137,15 +163,18 @@ void ExternalCodeEditor::kill_editor() { return; } -// [Public] Handle if file changed since last check, and update records if so. -// Load new data into 'code', which caller must free(). -// If 'force' set, forces reload even if file size/time didn't change. -// -// Returns: -// 0 -- file unchanged or not editing -// 1 -- file changed, internal records updated, 'code' has new content -// -1 -- error getting file info (strerror() has reason) -// +/** + Handle if file changed since last check, and update records if so. + + Load new data into 'code', which caller must free(). + If 'force' set, forces reload even if file size/time didn't change. + + \param[in] code + \param[in] force + \return 0 if file unchanged or not editing + \return 1 if file changed, internal records updated, 'code' has new content + \return -1 error getting file info (strerror() has reason) +*/ int ExternalCodeEditor::handle_changes(const char **code, int force) { code[0] = 0; if ( !is_editing() ) return 0; @@ -190,12 +219,12 @@ int ExternalCodeEditor::handle_changes(const char **code, int force) { return ret; } -// [Public] Remove the tmp file (if it exists), and zero out filename/mtime/size -// Returns: -// -1 -- on error (dialog is posted as to why) -// 0 -- no file to remove -// 1 -- file was removed -// +/** + Remove the tmp file (if it exists), and zero out filename/mtime/size. + \return -1 on error (dialog is posted as to why) + \return 0 no file to remove + \return 1 -- file was removed + */ int ExternalCodeEditor::remove_tmpfile() { const char *tmpfile = filename(); if ( !tmpfile ) return 0; @@ -213,18 +242,20 @@ int ExternalCodeEditor::remove_tmpfile() { return 1; } -// [Static/Public] Return tmpdir name for this fluid instance. -// Returns pointer to static memory. -// +/** + Return tmpdir name for this fluid instance. + \return pointer to static memory. + */ const char* ExternalCodeEditor::tmpdir_name() { static char dirname[100]; snprintf(dirname, sizeof(dirname), "/tmp/.fluid-%ld", (long)getpid()); return dirname; } -// [Static/Public] Clear the external editor's tempdir -// Static so that the main program can call it on exit to clean up. -// +/** + Clear the external editor's tempdir. + Static so that the main program can call it on exit to clean up. + */ void ExternalCodeEditor::tmpdir_clear() { const char *tmpdir = tmpdir_name(); if ( is_dir(tmpdir) ) { @@ -235,9 +266,11 @@ void ExternalCodeEditor::tmpdir_clear() { } } -// [Protected] Creates temp dir (if doesn't exist) and returns the dirname -// as a static string. Returns NULL on error, dialog shows reason. -// +/** + Creates temp dir (if doesn't exist) and returns the dirname + as a static string. + \return NULL on error, dialog shows reason. + */ const char* ExternalCodeEditor::create_tmpdir() { const char *dirname = tmpdir_name(); if ( ! is_dir(dirname) ) { @@ -250,26 +283,26 @@ const char* ExternalCodeEditor::create_tmpdir() { return dirname; } -// [Protected] Returns temp filename in static buffer. -// Returns NULL if can't, posts dialog explaining why. -// +/** + Returns temp filename in static buffer. + \return NULL if can't, posts dialog explaining why. + */ const char* ExternalCodeEditor::tmp_filename() { static char path[512]; const char *tmpdir = create_tmpdir(); if ( !tmpdir ) return 0; - extern const char *code_file_name; // fluid's global const char *ext = code_file_name; // e.g. ".cxx" snprintf(path, sizeof(path), "%s/%p%s", tmpdir, (void*)this, ext); path[sizeof(path)-1] = 0; return path; } -// [Static/Local] Save string 'code' to 'filename', returning file's mtime/size -// 'code' can be NULL -- writes an empty file if so. -// Returns: -// 0 on success -// -1 on error (posts dialog with reason) -// +/** + Save string 'code' to 'filename', returning file's mtime/size. + 'code' can be NULL -- writes an empty file if so. + \return 0 on success + \return -1 on error (posts dialog with reason) + */ static int save_file(const char *filename, const char *code) { int fd = open(filename, O_WRONLY|O_CREAT, 0666); if ( fd == -1 ) { @@ -291,14 +324,14 @@ static int save_file(const char *filename, const char *code) { return(ret); } -// [Static/Local] Convert string 's' to array of argv[], useful for execve() -// o 's' will be modified (words will be NULL separated) -// o argv[] will end up pointing to the words of 's' -// o Caller must free argv with: free(argv); -// Returns: -// o -1 in case of memory allocation error -// o number of arguments in argv (same value as in argc) -// +/** + Convert string 's' to array of argv[], useful for execve(). + - 's' will be modified (words will be NULL separated) + - argv[] will end up pointing to the words of 's' + - Caller must free argv with: free(argv); + \return -1 in case of memory allocation error + \return number of arguments in argv (same value as in argc) + */ static int make_args(char *s, // string containing words (gets trashed!) int *aargc, // pointer to argc char ***aargv) { // pointer to argv @@ -316,11 +349,11 @@ static int make_args(char *s, // string containing words (gets trashed!) return(t); } -// [Protected] Start editor in background (fork/exec) -// Returns: -// > 0 on success, leaves editor child process running as 'pid_' -// > -1 on error, posts dialog with reason (child exits) -// +/** + Start editor in background (fork/exec) + \return 0 on success, leaves editor child process running as 'pid_' + \return -1 on error, posts dialog with reason (child exits) + */ int ExternalCodeEditor::start_editor(const char *editor_cmd, const char *filename) { if ( G_debug ) printf("start_editor() cmd='%s', filename='%s'\n", @@ -354,17 +387,18 @@ int ExternalCodeEditor::start_editor(const char *editor_cmd, return 0; } -// [Public] Try to reap external editor process -// If 'pid_reaped' not NULL, returns PID of reaped editor. -// Returns: -// -2 -- editor not open -// -1 -- waitpid() failed (errno has reason) -// 0 -- process still running -// 1 -- process finished + reaped ('pid_reaped' has pid), pid_ set to -1. -// Handles removing tmpfile/zeroing file_mtime/file_size/filename -// -// If return value <=0, 'pid_reaped' is set to zero. -// +/** + Try to reap external editor process. + + If 'pid_reaped' not NULL, returns PID of reaped editor. + + \return -2: editor not open + \return -1: waitpid() failed (errno has reason) + \return 0: process still running + \return 1: process finished + reaped ('pid_reaped' has pid), pid_ set to -1. + Handles removing tmpfile/zeroing file_mtime/file_size/filename + \return If return value <=0, 'pid_reaped' is set to zero. + */ int ExternalCodeEditor::reap_editor(pid_t *pid_reaped) { if ( pid_reaped ) *pid_reaped = 0; if ( !is_editing() ) return -2; @@ -388,14 +422,15 @@ int ExternalCodeEditor::reap_editor(pid_t *pid_reaped) { return 1; } -// [Public] Open external editor using 'editor_cmd' to edit 'code' -// 'code' contains multiline code to be edited as a temp file. -// -// Returns: -// 0 if succeeds -// -1 if can't open editor (already open, etc), -// errors were shown to user in a dialog -// +/** + Open external editor using 'editor_cmd' to edit 'code'. + + 'code' contains multiline code to be edited as a temp file. + + \return 0 if succeeds + \return -1 if can't open editor (already open, etc), + errors were shown to user in a dialog + */ int ExternalCodeEditor::open_editor(const char *editor_cmd, const char *code) { // Make sure a temp filename exists @@ -446,31 +481,38 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, return 0; } -// [Public/Static] Start update timer +/** + Start update timer. + */ void ExternalCodeEditor::start_update_timer() { if ( !L_update_timer_cb ) return; if ( G_debug ) printf("--- TIMER: STARTING UPDATES\n"); Fl::add_timeout(2.0, L_update_timer_cb); } -// [Public/Static] Stop update timer +/** + Stop update timer. + */ void ExternalCodeEditor::stop_update_timer() { if ( !L_update_timer_cb ) return; if ( G_debug ) printf("--- TIMER: STOPPING UPDATES\n"); Fl::remove_timeout(L_update_timer_cb); } -// [Public/Static] Set app's external editor update timer callback -// This is the app's callback callback we start while editors are open, -// and stop when all editors are closed. -// +/** + Set app's external editor update timer callback. + + This is the app's callback callback we start while editors are open, + and stop when all editors are closed. + */ void ExternalCodeEditor::set_update_timer_callback(Fl_Timeout_Handler cb) { L_update_timer_cb = cb; } -// [Static/Public] See if any external editors are open. -// App's timer cb can see if any editors need checking.. -// +/** + See if any external editors are open. + App's timer cb can see if any editors need checking.. + */ int ExternalCodeEditor::editors_open() { return L_editors_open; } diff --git a/fluid/ExternalCodeEditor_UNIX.h b/fluid/ExternalCodeEditor_UNIX.h index d366a95c1..186a5b5ec 100644 --- a/fluid/ExternalCodeEditor_UNIX.h +++ b/fluid/ExternalCodeEditor_UNIX.h @@ -7,24 +7,29 @@ #ifndef _EXTCODEEDITOR_H #define _EXTCODEEDITOR_H +#include <FL/Fl.H> + #include <errno.h> /* errno */ #include <string.h> /* strerror() */ - #include <sys/types.h> /* stat().. */ #include <sys/stat.h> #include <unistd.h> +// ---- ExternalCodeEditor declaration + class ExternalCodeEditor { int pid_; time_t file_mtime_; // last modify time of the file (used to determine if file changed) size_t file_size_; // last file size (used to determine if changed) const char *filename_; + protected: void kill_editor(); const char *create_tmpdir(); const char *tmp_filename(); int start_editor(const char *cmd, const char *filename); void set_filename(const char *val); + public: ExternalCodeEditor(); ~ExternalCodeEditor(); diff --git a/fluid/Fl_Function_Type.cxx b/fluid/Fl_Function_Type.cxx index 2ece47e38..f8b9cd276 100644 --- a/fluid/Fl_Function_Type.cxx +++ b/fluid/Fl_Function_Type.cxx @@ -13,46 +13,58 @@ // // https://www.fltk.org/bugs.php // -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Preferences.H> -#include <FL/Fl_File_Chooser.H> + +#include "Fl_Function_Type.h" + +#include "fluid.h" +#include "Fl_Window_Type.h" +#include "Fl_Group_Type.h" +#include "widget_browser.h" +#include "file.h" +#include "code.h" +#include "function_panel.h" +#include "comments.h" + #include <FL/fl_string.h> -#include "Fl_Type.h" -#include <FL/fl_show_input.H> #include <FL/Fl_File_Chooser.H> -#include "alignment_panel.h" +#include <FL/fl_ask.H> #include "../src/flstring.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef _WIN32 - #include "ExternalCodeEditor_WIN32.h" -#else - #include "ExternalCodeEditor_UNIX.h" -#endif - -extern int i18n_type; -extern const char* i18n_include; -extern const char* i18n_function; -extern const char* i18n_file; -extern const char* i18n_set; -extern char i18n_program[]; - -extern int batch_mode; - -extern void redraw_browser(); -extern void goto_source_dir(); -extern void leave_source_dir(); -extern Fl_Window *main_window; + +/// Set a current class, so that the code of the children is generated correctly. +Fl_Class_Type *current_class = NULL; + +/** + Return 1 if the list contains a function with the given signature at the top level. + \param[in] rtype return type + \param[in] sig function signature + \return 1 if found. + */ +int has_toplevel_function(const char *rtype, const char *sig) { + Fl_Type *child; + for (child = Fl_Type::first; child; child = child->next) { + if (!child->is_in_class() && strcmp(child->type_name(), "Function")==0) { + const Fl_Function_Type *fn = (const Fl_Function_Type*)child; + if (fn->has_signature(rtype, sig)) + return 1; + } + } + return 0; +} + //////////////////////////////////////////////////////////////// // quick check of any C code for legality, returns an error message static char buffer[128]; // for error messages -// check a quoted string ending in either " or ' or >: +/** + Check a quoted string contains a character. + This is used to find a matchin " or ' in a string. + \param[inout] c start searching here, return where we found \c type + \param[in] type find this character + \return NULL if the character was found, else a pointer to a static string + with an error message + */ const char *_q_check(const char * & c, int type) { for (;;) switch (*c++) { case '\0': @@ -66,7 +78,15 @@ const char *_q_check(const char * & c, int type) { } } -// check normal code, match braces and parenthesis: +/** + Check normal code, match brackets and parenthesis. + Recursively run a line of code and make sure that + {, ", ', and ( are matched. + \param[inout] c start searching here, return the end of the search + \param[in] type find this character match + \return NULL if the character was found, else a pointer to a static string + with an error message + */ const char *_c_check(const char * & c, int type) { const char *d; for (;;) switch (*c++) { @@ -117,14 +137,58 @@ const char *_c_check(const char * & c, int type) { } } +/** + Check legality of c code (sort of) and return error: + Make sure that {, ", ', and ( are matched. + \param[in] c start searching here + \param[in] type find this character match + \return NULL if the character was found, else a pointer to a static string + with an error message + \note This function checks every conceivable line of code, which is not + always wanted. It can't differentiate characters in comments, and the + user may well intend to leave a curly bracket open + (i.e. namesapece { ... } ). We should make this option user selectable. + */ const char *c_check(const char *c, int type) { return _c_check(c,type); } -//////////////////////////////////////////////////////////////// +// ---- Fl_Function_Type implemntation + +/** \class Fl_Function_Type + Manage a C++ function node in the Fluid design. + + A function can have a signature (name followed by arguments), a return type + and a comment section. If can be local or global, and it can be declared a C + or C++ function. + */ + +/// Prototype for a function to be used by the factory. +Fl_Function_Type Fl_Function_type; + +/** + Create a new function. + */ +Fl_Function_Type::Fl_Function_Type() : + Fl_Type(), + return_type(0L), + public_(0), + cdecl_(0), + constructor(0), + havewidgets(0) +{ } -int Fl_Function_Type::is_public() const {return public_;} +/** + Destructor. + */ +Fl_Function_Type::~Fl_Function_Type() { + if (return_type) free((void*)return_type); +} +/** + Create a new function for the widget tree. + \return the new node + */ Fl_Type *Fl_Function_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_decl_block()) p = p->parent; @@ -138,6 +202,12 @@ Fl_Type *Fl_Function_Type::make() { return o; } +/** + Write function specific properties to an .fl file. + - "private"/"public" indicates the state of the function + - "C" is written if we want a C signature instead of C++ + - "return_type" is followed by the return type of the function + */ void Fl_Function_Type::write_properties() { Fl_Type::write_properties(); switch (public_) { @@ -151,6 +221,10 @@ void Fl_Function_Type::write_properties() { } } +/** + Read function specific properties fron an .fl file. + \param[in] c read from this string + */ void Fl_Function_Type::read_property(const char *c) { if (!strcmp(c,"private")) { public_ = 0; @@ -165,9 +239,9 @@ void Fl_Function_Type::read_property(const char *c) { } } -#include "function_panel.h" -#include <FL/fl_ask.H> - +/** + Open the function_panel dialog box to edit this function. + */ void Fl_Function_Type::open() { if (!function_panel) make_function_panel(); f_return_type_input->static_value(return_type); @@ -240,10 +314,19 @@ BREAK2: function_panel->hide(); } -Fl_Function_Type Fl_Function_type; - -extern const char* subclassname(Fl_Type*); +/** + Return 1 if the function is global. + \return 1 if public, 0 if local. + */ +int Fl_Function_Type::is_public() const { + return public_; +} +/** + Write the code for the source and the header file. + This writes the code that goes \b before all children of this class. + \see write_code2() + */ void Fl_Function_Type::write_code1() { constructor=0; havewidgets = 0; @@ -397,6 +480,11 @@ void Fl_Function_Type::write_code1() { indentation += 2; } +/** + Write the code for the source and the header file. + This writes the code that goes \b after all children of this class. + \see write_code1() + */ void Fl_Function_Type::write_code2() { Fl_Type *child; const char *var = "w"; @@ -417,6 +505,12 @@ void Fl_Function_Type::write_code2() { indentation = 0; } +/** + Check if the return type and signature s match. + \param[in] rtype function return type + \param[in] sig function name followed by arguments + \return 1 if they match, 0 if not + */ int Fl_Function_Type::has_signature(const char *rtype, const char *sig) const { if (rtype && !return_type) return 0; if (!name()) return 0; @@ -427,8 +521,35 @@ int Fl_Function_Type::has_signature(const char *rtype, const char *sig) const { return 0; } -//////////////////////////////////////////////////////////////// +// ---- Fl_Code_Type declaration + +/** \class Fl_Code_Type + Manage a block of C++ code in the Fluid design. + + This node manages an arbitrary block of code inside a function that will + be written into the source code file. Fl_Code_Block has no comment field. + However, the first line of code will be shown in the widget browser. + + \todo Fl_Code_Block stores the cursor position in text editor, but it does not + store the view position (scrollbars). Make sure that we can always see + the cursor when opening the dialog. (it's not stored in the .fl file) + */ + +/// Prototype for code to be used by the factory. +Fl_Code_Type Fl_Code_type; + +/** + Constructor. + */ +Fl_Code_Type::Fl_Code_Type() { + cursor_position_ = 0; +} +/** + Make a new code node. + If the parent node is not a function, a message box will pop up and + the request will be ignored. + */ Fl_Type *Fl_Code_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_code_block()) p = p->parent; @@ -443,6 +564,9 @@ Fl_Type *Fl_Code_Type::make() { return o; } +/** + Open the code_panel or an external editor to edit this code section. + */ void Fl_Code_Type::open() { // Using an external code editor? Open it.. if ( G_use_external_editor && G_external_editor_command[0] ) { @@ -477,8 +601,9 @@ BREAK2: code_panel->hide(); } -Fl_Code_Type Fl_Code_type; - +/** + Grab changes from an external editor and write this node. + */ void Fl_Code_Type::write() { // External editor changes? If so, load changes into ram, update mtime/size if ( handle_editor_changes() == 1 ) { @@ -487,6 +612,9 @@ void Fl_Code_Type::write() { Fl_Type::write(); } +/** + Write the code block with the correct indentation. + */ void Fl_Code_Type::write_code1() { // External editor changes? If so, load changes into ram, update mtime/size if ( handle_editor_changes() == 1 ) { @@ -513,10 +641,82 @@ void Fl_Code_Type::write_code1() { write_c("\n"); } -void Fl_Code_Type::write_code2() {} +/** + See if external editor is open. + */ +int Fl_Code_Type::is_editing() { + return editor_.is_editing(); +} -//////////////////////////////////////////////////////////////// +/** + Reap the editor's pid + \return -2: editor not open + \return -1: wait failed + \return 0: process still running + \return \>0: process finished + reaped (returns pid) + */ +int Fl_Code_Type::reap_editor() { + return editor_.reap_editor(); +} + +/** + Handle external editor file modifications. + If changed, record keeping is updated and file's contents is loaded into ram + \return 0: file unchanged or not editing + \return 1: file changed, internal records updated, 'code' has new content + \return -1: error getting file info (get_ms_errmsg() has reason) + \todo Figure out how saving a fluid file can be intercepted to grab + current contents of editor file.. + */ +int Fl_Code_Type::handle_editor_changes() { + const char *newcode = 0; + switch ( editor_.handle_changes(&newcode) ) { + case 1: { // (1)=changed + name(newcode); // update value in ram + free((void*)newcode); + return 1; + } + case -1: return -1; // (-1)=error -- couldn't read file (dialog showed reason) + default: break; // (0)=no change + } + return 0; +} + +// ---- Fl_CodeBlock_Type implemntation + +/** \class Fl_CodeBlock_Type + Manage two blocks of C++ code enclosing its children. + + This node manages two lines of code that enclose all children + of this node. This is usually an if..then clause. + + \todo this node could support multiple lines of code for each block. + */ + +/// Prototype for a block of code to be used by the factory. +Fl_CodeBlock_Type Fl_CodeBlock_type; +/** + Constructor. + */ +Fl_CodeBlock_Type::Fl_CodeBlock_Type() : + Fl_Type(), + after(NULL) +{ } + +/** + Destructor. + */ +Fl_CodeBlock_Type::~Fl_CodeBlock_Type() { + if (after) + free((void*)after); +} + +/** + Make a new code block. + If the parent node is not a function or another codeblock, a message box will + pop up and the request will be ignored. + */ Fl_Type *Fl_CodeBlock_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_code_block()) p = p->parent; @@ -532,6 +732,11 @@ Fl_Type *Fl_CodeBlock_Type::make() { return o; } +/** + Write the specific properties for this node. + - "after" is followed by the code that comes after the children + The "before" code is stored in the name() field. + */ void Fl_CodeBlock_Type::write_properties() { Fl_Type::write_properties(); if (after) { @@ -540,6 +745,9 @@ void Fl_CodeBlock_Type::write_properties() { } } +/** + Read the node specifc properties. + */ void Fl_CodeBlock_Type::read_property(const char *c) { if (!strcmp(c,"after")) { storestring(read_word(),after); @@ -548,6 +756,9 @@ void Fl_CodeBlock_Type::read_property(const char *c) { } } +/** + Open the codeblock_panel. + */ void Fl_CodeBlock_Type::open() { if (!codeblock_panel) make_codeblock_panel(); code_before_input->static_value(name()); @@ -574,22 +785,49 @@ BREAK2: codeblock_panel->hide(); } -Fl_CodeBlock_Type Fl_CodeBlock_type; - +/** + Write the "before" code. + */ void Fl_CodeBlock_Type::write_code1() { const char* c = name(); write_c("%s%s {\n", indent(), c ? c : ""); indentation += 2; } +/** + Write the "after" code. + */ void Fl_CodeBlock_Type::write_code2() { indentation -= 2; if (after) write_c("%s} %s\n", indent(), after); else write_c("%s}\n", indent()); } -//////////////////////////////////////////////////////////////// +// ---- Fl_Decl_Type declaration +/** \class Fl_Decl_Type + Manage the C/C++ declaration of a variable. + + This node manages a single line of code that can be in the header or the source + code, and can be made static. + + \todo this node could support multiple lines. + */ + +/// Prototype for a declaration to be used by the factory. +Fl_Decl_Type Fl_Decl_type; + +/** + Constructor. + */ +Fl_Decl_Type::Fl_Decl_Type() : + public_(0), + static_(1) +{ } + +/** + Return 1 if this declaration and its parents are public. + */ int Fl_Decl_Type::is_public() const { Fl_Type *p = parent; @@ -601,6 +839,9 @@ int Fl_Decl_Type::is_public() const return 0; } +/** + Make a new declaration. + */ Fl_Type *Fl_Decl_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_decl_block()) p = p->parent; @@ -613,6 +854,11 @@ Fl_Type *Fl_Decl_Type::make() { return o; } +/** + Write the specific properties. + - "private"/"public"/"protected" + - "local"/"global" if this is static or not + */ void Fl_Decl_Type::write_properties() { Fl_Type::write_properties(); switch (public_) { @@ -626,6 +872,9 @@ void Fl_Decl_Type::write_properties() { write_string("global"); } +/** + Read the specific properties. + */ void Fl_Decl_Type::read_property(const char *c) { if (!strcmp(c,"public")) { public_ = 1; @@ -642,6 +891,9 @@ void Fl_Decl_Type::read_property(const char *c) { } } +/** + Open the decl_panel to edit this node. + */ void Fl_Decl_Type::open() { if (!decl_panel) make_decl_panel(); decl_input->static_value(name()); @@ -701,8 +953,11 @@ BREAK2: decl_panel->hide(); } -Fl_Decl_Type Fl_Decl_type; - +/** + Write the code to the source and header files. + \todo There are a lot of side effect in this node depending on the given text + and the parent node which should really be documented. + */ void Fl_Decl_Type::write_code1() { const char* c = name(); if (!c) return; @@ -767,10 +1022,38 @@ void Fl_Decl_Type::write_code1() { } } -void Fl_Decl_Type::write_code2() {} +// ---- Fl_Data_Type declaration -//////////////////////////////////////////////////////////////// +/** \class Fl_Data_Type + Manage data from an external arbitrary file. + The content of the file will be stored in binary inside the generated + code. This can be used to store images inline in the source code, + */ + +/// Prototype for a data node to be used by the factory. +Fl_Data_Type Fl_Data_type; + +/** + Constructor. + */ +Fl_Data_Type::Fl_Data_Type() : + Fl_Decl_Type(), + filename_(NULL), + text_mode_(0) +{ } + +/** + Destructor. + */ +Fl_Data_Type::~Fl_Data_Type() { + if (filename_) + free((void*)filename_); +} + +/** + Create an empty inline data node. + */ Fl_Type *Fl_Data_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_decl_block()) p = p->parent; @@ -785,6 +1068,11 @@ Fl_Type *Fl_Data_Type::make() { return o; } +/** + Write additional properties. + - "filename" followed by the filename of the file to inline + - "textmode" if data is written in ASCII vs. binary + */ void Fl_Data_Type::write_properties() { Fl_Decl_Type::write_properties(); if (filename_) { @@ -796,6 +1084,9 @@ void Fl_Data_Type::write_properties() { } } +/** + Read specific properties. + */ void Fl_Data_Type::read_property(const char *c) { if (!strcmp(c,"filename")) { storestring(read_word(), filename_, 1); @@ -806,6 +1097,9 @@ void Fl_Data_Type::read_property(const char *c) { } } +/** + Open the data_panel to edit this node. + */ void Fl_Data_Type::open() { if (!data_panel) make_data_panel(); data_input->static_value(name()); @@ -908,8 +1202,9 @@ BREAK2: data_panel->hide(); } -Fl_Data_Type Fl_Data_type; - +/** + Write the content of the external file inline into the source code. + */ void Fl_Data_Type::write_code1() { const char *message = 0; const char *c = name(); @@ -1005,12 +1300,43 @@ void Fl_Data_Type::write_code1() { if (data) free(data); } -void Fl_Data_Type::write_code2() {} +// ---- Fl_DeclBlock_Type declaration -//////////////////////////////////////////////////////////////// +/** \class Fl_DeclBlock_Type + Manage a declaration block. + + Declaration blocks have two text field that are written before and after + the children of this block. This block is located at the top level and + is written to the source file, and to the header file, if declared public. + */ +/// Prototype for a declaration block to be used by the factory. +Fl_DeclBlock_Type Fl_DeclBlock_type; + +/** + Constructor. + */ +Fl_DeclBlock_Type::Fl_DeclBlock_Type() : + Fl_Type(), + after(NULL) +{ } + +/** + Destructor. + */ +Fl_DeclBlock_Type::~Fl_DeclBlock_Type() { + if (after) + free((void*)after); +} + +/** + Return 1 if this block is public. + */ int Fl_DeclBlock_Type::is_public() const {return public_;} +/** + Create a new declaration block. + */ Fl_Type *Fl_DeclBlock_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_decl_block()) p = p->parent; @@ -1023,6 +1349,11 @@ Fl_Type *Fl_DeclBlock_Type::make() { return o; } +/** + Write the specific properties. + - "public"/"protected" + - "after" followed by the second code block. + */ void Fl_DeclBlock_Type::write_properties() { Fl_Type::write_properties(); switch (public_) { @@ -1033,6 +1364,9 @@ void Fl_DeclBlock_Type::write_properties() { write_word(after); } +/** + Read the specific properties. + */ void Fl_DeclBlock_Type::read_property(const char *c) { if(!strcmp(c,"public")) { public_ = 1; @@ -1045,6 +1379,9 @@ void Fl_DeclBlock_Type::read_property(const char *c) { } } +/** + Open the declblock_panel to edit this node. + */ void Fl_DeclBlock_Type::open() { if (!declblock_panel) make_declblock_panel(); decl_before_input->static_value(name()); @@ -1081,8 +1418,10 @@ BREAK2: declblock_panel->hide(); } -Fl_DeclBlock_Type Fl_DeclBlock_type; - +/** + Write the \b before code to the source file, and to the header file if declared public. + The before code is stored in the name() field. + */ void Fl_DeclBlock_Type::write_code1() { const char* c = name(); if (public_) @@ -1090,6 +1429,9 @@ void Fl_DeclBlock_Type::write_code1() { write_c("%s\n", c); } +/** + Write the \b after code to the source file, and to the header file if declared public. + */ void Fl_DeclBlock_Type::write_code2() { const char* c = after; if (public_) @@ -1097,8 +1439,31 @@ void Fl_DeclBlock_Type::write_code2() { write_c("%s\n", c); } -//////////////////////////////////////////////////////////////// +// ---- Fl_Comment_Type declaration + +/** \class Fl_Comment_Type + Manage a comment node. + + The comment field takes one or more lines of ASCII text. If the text starts + with a '/' and a '*', Fluid assumes that the text is already formatted. If not, + every line will be preceded with "// ". + */ +/// Prototype for a comment node to be used by the factory. +Fl_Comment_Type Fl_Comment_type; + +/** + Constructor. + */ +Fl_Comment_Type::Fl_Comment_Type() : + in_c_(1), + in_h_(1), + style_(0) +{ } + +/** + Make a new comment node. + */ Fl_Type *Fl_Comment_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_code_block()) p = p->parent; @@ -1113,12 +1478,20 @@ Fl_Type *Fl_Comment_Type::make() { return o; } +/** + Write respective properties. + - "in_source"/"not_in_source" if the comment will be written to the source code + - "in_header"/"not_in_header" if the comment will be written to the header file + */ void Fl_Comment_Type::write_properties() { Fl_Type::write_properties(); if (in_c_) write_string("in_source"); else write_string("not_in_source"); if (in_h_) write_string("in_header"); else write_string("not_in_header"); } +/** + Read extra properties. + */ void Fl_Comment_Type::read_property(const char *c) { if (!strcmp(c,"in_source")) { in_c_ = 1; @@ -1133,8 +1506,12 @@ void Fl_Comment_Type::read_property(const char *c) { } } -#include "comments.h" - +/** + Load available preset comments. + Fluid comes with GPL and LGPL preset for comments. Users can + add their own presets which are stored per user in a seperate + preferences database. + */ static void load_comments_preset(Fl_Preferences &menu) { static const char * const predefined_comment[] = { "GNU Public License/GPL Header", "GNU Public License/GPL Footer", @@ -1149,6 +1526,9 @@ static void load_comments_preset(Fl_Preferences &menu) { } } +/** + Open the comment_panel to edit this node. + */ void Fl_Comment_Type::open() { if (!comment_panel) make_comment_panel(); const char *text = name(); @@ -1268,6 +1648,9 @@ BREAK2: comment_panel->hide(); } +/** + Create a title for the Widget Browser by extracting the first 50 characters of the comment. + */ const char *Fl_Comment_Type::title() { const char* n = name(); if (!n || !*n) return type_name(); @@ -1289,8 +1672,9 @@ const char *Fl_Comment_Type::title() { return title_buf; } -Fl_Comment_Type Fl_Comment_type; - +/** + Write the comment to the files. + */ void Fl_Comment_Type::write_code1() { const char* c = name(); if (!c) return; @@ -1331,66 +1715,74 @@ void Fl_Comment_Type::write_code1() { free(txt); } -void Fl_Comment_Type::write_code2() {} +// ---- Fl_Class_Type declaration -//////////////////////////////////////////////////////////////// +/** \class Fl_Class_Type + Manage a class declaration and implementation. -const char* Fl_Type::class_name(const int need_nest) const { - Fl_Type* p = parent; - while (p) { - if (p->is_class()) { - // see if we are nested in another class, we must fully-qualify name: - // this is lame but works... - const char* q = 0; - if(need_nest) q=p->class_name(need_nest); - if (q) { - static char s[256]; - if (q != s) strlcpy(s, q, sizeof(s)); - strlcat(s, "::", sizeof(s)); - strlcat(s, p->name(), sizeof(s)); - return s; - } - return p->name(); - } - p = p->parent; - } - return 0; -} + \todo This is pretty complex and needs to be revisited to give + a good description. + */ + +/// Prototype for a class node to be used by the factory. +Fl_Class_Type Fl_Class_type; /** - If this Type resides inside a class, this function returns the class type, or null. + Constructor. */ -const Fl_Class_Type *Fl_Type::is_in_class() const { - Fl_Type* p = parent; - while (p) { - if (p->is_class()) { - return (Fl_Class_Type*)p; - } - p = p->parent; - } - return 0; +Fl_Class_Type::Fl_Class_Type() : + Fl_Type(), + subclass_of(NULL), + public_(1), + class_prefix(NULL) +{ } + +/** + Destructor. + */ +Fl_Class_Type::~Fl_Class_Type() { + if (subclass_of) + free((void*)subclass_of); + if (class_prefix) + free((void*)class_prefix); } -int Fl_Class_Type::is_public() const {return public_;} +/** + Return 1 if this class is marked public. + */ +int Fl_Class_Type::is_public() const { + return public_; +} +/** + Set the prefixx string. + */ void Fl_Class_Type::prefix(const char*p) { free((void*) class_prefix); class_prefix=fl_strdup(p ? p : "" ); } +/** + Make a new class node. + */ Fl_Type *Fl_Class_Type::make() { Fl_Type *p = Fl_Type::current; while (p && !p->is_decl_block()) p = p->parent; Fl_Class_Type *o = new Fl_Class_Type(); o->name("UserInterface"); - o->class_prefix=0; - o->subclass_of = 0; + o->class_prefix = NULL; + o->subclass_of = NULL; o->public_ = 1; o->add(p); o->factory = this; return o; } +/** + Write the respective properties. + - ":" followed by the super class + - "private"/"protected" + */ void Fl_Class_Type::write_properties() { Fl_Type::write_properties(); if (subclass_of) { @@ -1403,6 +1795,9 @@ void Fl_Class_Type::write_properties() { } } +/** + Read additional properties. + */ void Fl_Class_Type::read_property(const char *c) { if (!strcmp(c,"private")) { public_ = 0; @@ -1415,6 +1810,9 @@ void Fl_Class_Type::read_property(const char *c) { } } +/** + Open the class_panel to edit the class name and superclass name. + */ void Fl_Class_Type::open() { if (!class_panel) make_class_panel(); char fullname[FL_PATH_MAX]=""; @@ -1485,23 +1883,9 @@ BREAK2: class_panel->hide(); } -Fl_Class_Type Fl_Class_type; - -Fl_Class_Type *current_class; -extern Fl_Widget_Class_Type *current_widget_class; -void write_public(int state) { - if (!current_class && !current_widget_class) return; - if (current_class && current_class->write_public_state == state) return; - if (current_widget_class && current_widget_class->write_public_state == state) return; - if (current_class) current_class->write_public_state = state; - if (current_widget_class) current_widget_class->write_public_state = state; - switch (state) { - case 0: write_h("private:\n"); break; - case 1: write_h("public:\n"); break; - case 2: write_h("protected:\n"); break; - } -} - +/** + Write the header code that declares this class. + */ void Fl_Class_Type::write_code1() { parent_class = current_class; current_class = this; @@ -1516,6 +1900,9 @@ void Fl_Class_Type::write_code1() { write_h("{\n"); } +/** + Write the header code that ends the declaration of this class. + */ void Fl_Class_Type::write_code2() { write_h("};\n"); current_class = parent_class; diff --git a/fluid/Fl_Function_Type.h b/fluid/Fl_Function_Type.h new file mode 100644 index 000000000..d5b0087c0 --- /dev/null +++ b/fluid/Fl_Function_Type.h @@ -0,0 +1,230 @@ +// +// C function type header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FL_FUNCTION_TYPE_H +#define _FLUID_FL_FUNCTION_TYPE_H + +#include "Fl_Type.h" + +#include "Fluid_Image.h" +#ifdef _WIN32 +#include "ExternalCodeEditor_WIN32.h" +#else +#include "ExternalCodeEditor_UNIX.h" +#endif + +#include <FL/Fl_Widget.H> +#include <FL/Fl_Menu.H> +#include <FL/fl_draw.H> +#include <FL/fl_attr.h> + +#include <stdarg.h> +#include <stdlib.h> + +extern Fl_Class_Type *current_class; + +int has_toplevel_function(const char *rtype, const char *sig); + +const char *c_check(const char *c, int type = 0); + +// ---- Fl_Function_Type declaration + +class Fl_Function_Type : public Fl_Type { + const char* return_type; + char public_, cdecl_, constructor, havewidgets; + +public: + Fl_Function_Type(); + ~Fl_Function_Type(); + Fl_Type *make(); + void write_code1(); + void write_code2(); + void open(); + int ismain() {return name_ == 0;} + virtual const char *type_name() {return "Function";} + virtual const char *title() { + return name() ? name() : "main()"; + } + int is_parent() const {return 1;} + int is_code_block() const {return 1;} + virtual int is_public() const; + int pixmapID() { return 7; } + void write_properties(); + void read_property(const char *); + int has_signature(const char *, const char*) const; +}; + +// ---- Fl_Code_Type declaration + +class Fl_Code_Type : public Fl_Type { + ExternalCodeEditor editor_; + int cursor_position_; + +public: + Fl_Code_Type(); + Fl_Type *make(); + void write(); + void write_code1(); + void write_code2() { } + void open(); + virtual const char *type_name() {return "code";} + int is_code_block() const {return 0;} + int is_code() const {return 1;} + int pixmapID() { return 8; } + virtual int is_public() const { return -1; } + int is_editing(); + int reap_editor(); + int handle_editor_changes(); +}; + +// ---- Fl_CodeBlock_Type declaration + +class Fl_CodeBlock_Type : public Fl_Type { + const char* after; + +public: + Fl_CodeBlock_Type(); + ~Fl_CodeBlock_Type(); + Fl_Type *make(); + void write_code1(); + void write_code2(); + void open(); + virtual const char *type_name() {return "codeblock";} + int is_code_block() const {return 1;} + int is_parent() const {return 1;} + virtual int is_public() const { return -1; } + int pixmapID() { return 9; } + void write_properties(); + void read_property(const char *); +}; + +// ---- Fl_Decl_Type declaration + +class Fl_Decl_Type : public Fl_Type { + +protected: + char public_; + char static_; + +public: + Fl_Decl_Type(); + Fl_Type *make(); + void write_code1(); + void write_code2() { } + void open(); + virtual const char *type_name() {return "decl";} + void write_properties(); + void read_property(const char *); + virtual int is_public() const; + int pixmapID() { return 10; } +}; + +// ---- Fl_Data_Type declaration + +class Fl_Data_Type : public Fl_Decl_Type { + const char *filename_; + int text_mode_; + +public: + Fl_Data_Type(); + ~Fl_Data_Type(); + Fl_Type *make(); + void write_code1(); + void write_code2() {} + void open(); + virtual const char *type_name() {return "data";} + void write_properties(); + void read_property(const char *); + int pixmapID() { return 49; } +}; + +// ---- Fl_DeclBlock_Type declaration + +class Fl_DeclBlock_Type : public Fl_Type { + const char* after; + char public_; + +public: + Fl_DeclBlock_Type(); + ~Fl_DeclBlock_Type(); + Fl_Type *make(); + void write_code1(); + void write_code2(); + void open(); + virtual const char *type_name() {return "declblock";} + void write_properties(); + void read_property(const char *); + int is_parent() const {return 1;} + int is_decl_block() const {return 1;} + virtual int is_public() const; + int pixmapID() { return 11; } +}; + +// ---- Fl_Comment_Type declaration + +class Fl_Comment_Type : public Fl_Type { + char in_c_, in_h_, style_; + char title_buf[64]; + +public: + Fl_Comment_Type(); + Fl_Type *make(); + void write_code1(); + void write_code2() { } + void open(); + virtual const char *type_name() {return "comment";} + virtual const char *title(); // string for browser + void write_properties(); + void read_property(const char *); + virtual int is_public() const { return 1; } + virtual int is_comment() const { return 1; } + int pixmapID() { return 46; } +}; + +// ---- Fl_Class_Type declaration + +class Fl_Class_Type : public Fl_Type { + const char* subclass_of; + char public_; + const char* class_prefix; + +public: + Fl_Class_Type(); + ~Fl_Class_Type(); + // state variables for output: + char write_public_state; // true when public: has been printed + Fl_Class_Type* parent_class; // save class if nested +// + Fl_Type *make(); + void write_code1(); + void write_code2(); + void open(); + virtual const char *type_name() {return "class";} + int is_parent() const {return 1;} + int is_decl_block() const {return 1;} + int is_class() const {return 1;} + virtual int is_public() const; + int pixmapID() { return 12; } + void write_properties(); + void read_property(const char *); + + // class prefix attribute access + void prefix(const char* p); + const char* prefix() const {return class_prefix;} + int has_function(const char*, const char*) const; +}; + +#endif // _FLUID_FL_FUNCTION_TYPE_H diff --git a/fluid/Fl_Group_Type.cxx b/fluid/Fl_Group_Type.cxx index cc6fb59a6..a2a45a541 100644 --- a/fluid/Fl_Group_Type.cxx +++ b/fluid/Fl_Group_Type.cxx @@ -18,13 +18,22 @@ // https://www.fltk.org/bugs.php // +#include "Fl_Group_Type.h" + +#include "fluid.h" +#include "file.h" +#include "code.h" + #include <FL/Fl.H> #include <FL/Fl_Group.H> #include <FL/Fl_Table.H> +#include <FL/Fl_Menu_Item.H> #include <FL/fl_message.H> -#include "Fl_Widget_Type.h" +#include <FL/Fl_Scroll.H> #include "../src/flstring.h" +#include <stdio.h> + // Override group's resize behavior to do nothing to children: void igroup::resize(int X, int Y, int W, int H) { Fl_Widget::resize(X,Y,W,H); @@ -55,8 +64,6 @@ void fix_group_size(Fl_Type *tt) { t->o->resize(X,Y,R-X,B-Y); } -extern int force_parent; - void group_cb(Fl_Widget *, void *) { // Find the current widget: Fl_Type *qq = Fl_Type::current; @@ -106,8 +113,6 @@ void ungroup_cb(Fl_Widget *, void *) { //////////////////////////////////////////////////////////////// -#include <stdio.h> - void Fl_Group_Type::write_code1() { Fl_Widget_Type::write_code1(); } @@ -380,8 +385,6 @@ void Fl_Group_Type::copy_properties() { //////////////////////////////////////////////////////////////// // some other group subclasses that fluid does not treat specially: -#include <FL/Fl_Scroll.H> - const char scroll_type_name[] = "Fl_Scroll"; Fl_Widget *Fl_Scroll_Type::enter_live_mode(int) { diff --git a/fluid/Fl_Group_Type.h b/fluid/Fl_Group_Type.h new file mode 100644 index 000000000..a55e0dfd2 --- /dev/null +++ b/fluid/Fl_Group_Type.h @@ -0,0 +1,158 @@ +// +// Widget type header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FL_GROUP_TYPE_H +#define _FLUID_FL_GROUP_TYPE_H + +#include "Fl_Widget_Type.h" + +#include <FL/Fl_Tabs.H> +#include <FL/Fl_Pack.H> +#include <FL/Fl_Wizard.H> + +void group_cb(Fl_Widget *, void *); +void ungroup_cb(Fl_Widget *, void *); + +class igroup : public Fl_Group { +public: + void resize(int,int,int,int); + void full_resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } + igroup(int X,int Y,int W,int H) : Fl_Group(X,Y,W,H) {Fl_Group::current(0);} +}; + +class itabs : public Fl_Tabs { +public: + void resize(int,int,int,int); + void full_resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } + itabs(int X,int Y,int W,int H) : Fl_Tabs(X,Y,W,H) {} +}; + +class iwizard : public Fl_Wizard { +public: + void resize(int,int,int,int); + void full_resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } + iwizard(int X,int Y,int W,int H) : Fl_Wizard(X,Y,W,H) {} +}; + +class Fl_Group_Type : public Fl_Widget_Type { +public: + virtual const char *type_name() {return "Fl_Group";} + virtual const char *alt_type_name() {return "fltk::Group";} + Fl_Widget *widget(int X,int Y,int W,int H) { + igroup *g = new igroup(X,Y,W,H); Fl_Group::current(0); return g;} + Fl_Widget_Type *_make() {return new Fl_Group_Type();} + Fl_Type *make(); + void write_code1(); + void write_code2(); + void add_child(Fl_Type*, Fl_Type*); + void move_child(Fl_Type*, Fl_Type*); + void remove_child(Fl_Type*); + int is_parent() const {return 1;} + int is_group() const {return 1;} + int pixmapID() { return 6; } + + virtual Fl_Widget *enter_live_mode(int top=0); + virtual void leave_live_mode(); + virtual void copy_properties(); +}; + +extern const char pack_type_name[]; +extern Fl_Menu_Item pack_type_menu[]; + +class Fl_Pack_Type : public Fl_Group_Type { + Fl_Menu_Item *subtypes() {return pack_type_menu;} +public: + virtual const char *type_name() {return pack_type_name;} + virtual const char *alt_type_name() {return "fltk::PackedGroup";} + Fl_Widget_Type *_make() {return new Fl_Pack_Type();} + int pixmapID() { return 22; } + void copy_properties(); +}; + +extern const char table_type_name[]; + +class Fl_Table_Type : public Fl_Group_Type { +public: + virtual const char *type_name() {return table_type_name;} + virtual const char *alt_type_name() {return "fltk::TableGroup";} + Fl_Widget_Type *_make() {return new Fl_Table_Type();} + Fl_Widget *widget(int X,int Y,int W,int H); + int pixmapID() { return 51; } + virtual Fl_Widget *enter_live_mode(int top=0); + void add_child(Fl_Type*, Fl_Type*); + void move_child(Fl_Type*, Fl_Type*); + void remove_child(Fl_Type*); +}; + +extern const char tabs_type_name[]; + +class Fl_Tabs_Type : public Fl_Group_Type { +public: + virtual void ideal_spacing(int &x, int &y) { + x = 10; + fl_font(o->labelfont(), o->labelsize()); + y = fl_height() + o->labelsize() - 6; + } + virtual const char *type_name() {return tabs_type_name;} + virtual const char *alt_type_name() {return "fltk::TabGroup";} + Fl_Widget *widget(int X,int Y,int W,int H) { + itabs *g = new itabs(X,Y,W,H); Fl_Group::current(0); return g;} + Fl_Widget_Type *_make() {return new Fl_Tabs_Type();} + Fl_Type* click_test(int,int); + void add_child(Fl_Type*, Fl_Type*); + void remove_child(Fl_Type*); + int pixmapID() { return 13; } + Fl_Widget *enter_live_mode(int top=0); +}; + +extern const char scroll_type_name[]; +extern Fl_Menu_Item scroll_type_menu[]; + +class Fl_Scroll_Type : public Fl_Group_Type { + Fl_Menu_Item *subtypes() {return scroll_type_menu;} +public: + virtual const char *type_name() {return scroll_type_name;} + virtual const char *alt_type_name() {return "fltk::ScrollGroup";} + Fl_Widget_Type *_make() {return new Fl_Scroll_Type();} + int pixmapID() { return 19; } + Fl_Widget *enter_live_mode(int top=0); + void copy_properties(); +}; + +extern const char tile_type_name[]; + +class Fl_Tile_Type : public Fl_Group_Type { +public: + virtual const char *type_name() {return tile_type_name;} + virtual const char *alt_type_name() {return "fltk::TileGroup";} + Fl_Widget_Type *_make() {return new Fl_Tile_Type();} + int pixmapID() { return 20; } + void copy_properties(); +}; + +extern const char wizard_type_name[]; + +class Fl_Wizard_Type : public Fl_Group_Type { +public: + virtual const char *type_name() {return wizard_type_name;} + virtual const char *alt_type_name() {return "fltk::WizardGroup";} + Fl_Widget *widget(int X,int Y,int W,int H) { + iwizard *g = new iwizard(X,Y,W,H); Fl_Group::current(0); return g;} + Fl_Widget_Type *_make() {return new Fl_Wizard_Type();} + int pixmapID() { return 21; } +}; + +#endif // _FLUID_FL_GROUP_TYPE_H diff --git a/fluid/Fl_Menu_Type.cxx b/fluid/Fl_Menu_Type.cxx index 5c1a56f30..a93538de6 100644 --- a/fluid/Fl_Menu_Type.cxx +++ b/fluid/Fl_Menu_Type.cxx @@ -20,15 +20,27 @@ // https://www.fltk.org/bugs.php // -#include <FL/Fl.H> -#include "Fl_Widget_Type.h" +#include "Fl_Menu_Type.h" + +#include "fluid.h" +#include "Fl_Window_Type.h" #include "alignment_panel.h" +#include "file.h" +#include "code.h" +#include "Fluid_Image.h" +#include "Shortcut_Button.h" + +#include <FL/Fl.H> #include <FL/fl_message.H> #include <FL/Fl_Menu_.H> #include <FL/Fl_Button.H> #include <FL/Fl_Value_Input.H> #include <FL/Fl_Text_Display.H> +#include <FL/Fl_Menu_Button.H> +#include <FL/Fl_Output.H> +#include <FL/fl_draw.H> #include "../src/flstring.h" + #include <stdio.h> #include <stdlib.h> @@ -38,14 +50,6 @@ Fl_Menu_Item menu_item_type_menu[] = { {"Radio",0,0,(void*)FL_MENU_RADIO}, {0}}; -extern int reading_file; -extern int force_parent; -extern int i18n_type; -extern const char* i18n_include; -extern const char* i18n_function; -extern const char* i18n_file; -extern const char* i18n_set; - static char submenuflag; static uchar menuitemtype = 0; @@ -174,8 +178,6 @@ const char* Fl_Menu_Item_Type::menu_name(int& i) { return unique_id(t, "menu", t->name(), t->label()); } -#include "Fluid_Image.h" - void Fl_Menu_Item_Type::write_static() { if (callback() && is_name(callback()) && !user_defined(callback())) write_declare("extern void %s(Fl_Menu_*, %s);", callback(), @@ -525,7 +527,6 @@ void Fl_Menu_Type::copy_properties() { //////////////////////////////////////////////////////////////// -#include <FL/Fl_Menu_Button.H> Fl_Menu_Item button_type_menu[] = { {"normal",0,0,(void*)0}, {"popup1",0,0,(void*)Fl_Menu_Button::POPUP1}, @@ -582,10 +583,6 @@ Fl_Menu_Bar_Type Fl_Menu_Bar_type; //////////////////////////////////////////////////////////////// // Shortcut entry item in panel: -#include <FL/Fl_Output.H> -#include "Shortcut_Button.h" -#include <FL/fl_draw.H> - void Shortcut_Button::draw() { if (value()) draw_box(FL_DOWN_BOX, (Fl_Color)9); else draw_box(FL_UP_BOX, FL_WHITE); diff --git a/fluid/Fl_Menu_Type.h b/fluid/Fl_Menu_Type.h new file mode 100644 index 000000000..b42798d61 --- /dev/null +++ b/fluid/Fl_Menu_Type.h @@ -0,0 +1,212 @@ +// +// Widget type header file for the Fast Light Tool Kit (FLTK). +// +// Type for creating all subclasses of Fl_Widget +// This should have the widget pointer in it, but it is still in the +// Fl_Type base class. +// +// Copyright 1998-2010 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FL_MENU_TYPE_H +#define _FLUID_FL_MENU_TYPE_H + +#include "Fl_Widget_Type.h" + +#include <FL/Fl_Menu_.H> +#include <FL/Fl_Menu_Button.H> +#include <FL/Fl_Input_Choice.H> +#include <FL/Fl_Window.H> +#include <FL/Fl_Menu_Bar.H> + +extern Fl_Menu_Item menu_item_type_menu[]; + +class Fl_Menu_Item_Type : public Fl_Widget_Type { +public: + Fl_Menu_Item* subtypes() {return menu_item_type_menu;} + const char* type_name() {return "MenuItem";} + const char* alt_type_name() {return "fltk::Item";} + Fl_Type* make(); + int is_menu_item() const {return 1;} + int is_button() const {return 1;} // this gets shortcut to work + Fl_Widget* widget(int,int,int,int) {return 0;} + Fl_Widget_Type* _make() {return 0;} + const char* menu_name(int& i); + int flags(); + void write_static(); + void write_item(); + void write_code1(); + void write_code2(); + int pixmapID() { return 16; } +}; + +class Fl_Radio_Menu_Item_Type : public Fl_Menu_Item_Type { +public: + const char* type_name() {return "RadioMenuItem";} + Fl_Type* make(); + int pixmapID() { return 55; } +}; + +class Fl_Checkbox_Menu_Item_Type : public Fl_Menu_Item_Type { +public: + const char* type_name() {return "CheckMenuItem";} + Fl_Type* make(); + int pixmapID() { return 54; } +}; + +class Fl_Submenu_Type : public Fl_Menu_Item_Type { +public: + Fl_Menu_Item* subtypes() {return 0;} + const char* type_name() {return "Submenu";} + const char* alt_type_name() {return "fltk::ItemGroup";} + int is_parent() const {return 1;} + int is_button() const {return 0;} // disable shortcut + Fl_Type* make(); + // changes to submenu must propagate up so build_menu is called + // on the parent Fl_Menu_Type: + void add_child(Fl_Type*a, Fl_Type*b) {parent->add_child(a,b);} + void move_child(Fl_Type*a, Fl_Type*b) {parent->move_child(a,b);} + void remove_child(Fl_Type*a) {parent->remove_child(a);} + int pixmapID() { return 18; } +}; + +class Fl_Menu_Type : public Fl_Widget_Type { + int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { + Fl_Menu_ *myo = (Fl_Menu_*)(w==4 ? ((Fl_Widget_Type*)this->factory)->o : this->o); + switch (w) { + case 4: + case 0: f = myo->textfont(); s = myo->textsize(); c = myo->textcolor(); break; + case 1: myo->textfont(f); break; + case 2: myo->textsize(s); break; + case 3: myo->textcolor(c); break; + } + return 1; + } +public: + int is_menu_button() const {return 1;} + int is_parent() const {return 1;} + int menusize; + virtual void build_menu(); + Fl_Menu_Type() : Fl_Widget_Type() {menusize = 0;} + ~Fl_Menu_Type() { + if (menusize) delete[] (Fl_Menu_Item*)(((Fl_Menu_*)o)->menu()); + } + void add_child(Fl_Type*, Fl_Type*) {build_menu();} + void move_child(Fl_Type*, Fl_Type*) {build_menu();} + void remove_child(Fl_Type*) {build_menu();} + Fl_Type* click_test(int x, int y); + void write_code2(); + void copy_properties(); +}; + +extern Fl_Menu_Item button_type_menu[]; + +class Fl_Menu_Button_Type : public Fl_Menu_Type { + Fl_Menu_Item *subtypes() {return button_type_menu;} +public: + virtual void ideal_size(int &w, int &h) { + Fl_Widget_Type::ideal_size(w, h); + w += 2 * ((o->labelsize() - 3) & ~1) + o->labelsize() - 4; + h = (h / 5) * 5; + if (h < 15) h = 15; + if (w < (15 + h)) w = 15 + h; + } + virtual const char *type_name() {return "Fl_Menu_Button";} + virtual const char *alt_type_name() {return "fltk::MenuButton";} + Fl_Widget *widget(int X,int Y,int W,int H) { + return new Fl_Menu_Button(X,Y,W,H,"menu");} + Fl_Widget_Type *_make() {return new Fl_Menu_Button_Type();} + int pixmapID() { return 26; } +}; + +extern Fl_Menu_Item dummymenu[]; + +#include <FL/Fl_Choice.H> +class Fl_Choice_Type : public Fl_Menu_Type { +public: + virtual void ideal_size(int &w, int &h) { + Fl_Widget_Type::ideal_size(w, h); + int w1 = o->h() - Fl::box_dh(o->box()); + if (w1 > 20) w1 = 20; + w1 = (w1 - 4) / 3; + if (w1 < 1) w1 = 1; + w += 2 * w1 + o->labelsize() - 4; + h = (h / 5) * 5; + if (h < 15) h = 15; + if (w < (15 + h)) w = 15 + h; + } + virtual const char *type_name() {return "Fl_Choice";} + virtual const char *alt_type_name() {return "fltk::Choice";} + Fl_Widget *widget(int X,int Y,int W,int H) { + Fl_Choice *myo = new Fl_Choice(X,Y,W,H,"choice:"); + myo->menu(dummymenu); + return myo; + } + Fl_Widget_Type *_make() {return new Fl_Choice_Type();} + int pixmapID() { return 15; } +}; + +class Fl_Input_Choice_Type : public Fl_Menu_Type { + int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { + Fl_Input_Choice *myo = (Fl_Input_Choice*)(w==4 ? ((Fl_Widget_Type*)this->factory)->o : this->o); + switch (w) { + case 4: + case 0: f = (Fl_Font)myo->textfont(); s = myo->textsize(); c = myo->textcolor(); break; + case 1: myo->textfont(f); break; + case 2: myo->textsize(s); break; + case 3: myo->textcolor(c); break; + } + return 1; + } +public: + virtual void ideal_size(int &w, int &h) { + Fl_Input_Choice *myo = (Fl_Input_Choice *)o; + fl_font(myo->textfont(), myo->textsize()); + h = fl_height() + myo->textsize() - 6; + w = o->w() - 20 - Fl::box_dw(o->box()); + int ww = (int)fl_width('m'); + w = ((w + ww - 1) / ww) * ww + 20 + Fl::box_dw(o->box()); + if (h < 15) h = 15; + if (w < (15 + h)) w = 15 + h; + } + virtual const char *type_name() {return "Fl_Input_Choice";} + virtual const char *alt_type_name() {return "fltk::ComboBox";} + virtual Fl_Type* click_test(int,int); + Fl_Widget *widget(int X,int Y,int W,int H) { + Fl_Input_Choice *myo = new Fl_Input_Choice(X,Y,W,H,"input choice:"); + myo->menu(dummymenu); + myo->value("input"); + return myo; + } + Fl_Widget_Type *_make() {return new Fl_Input_Choice_Type();} + virtual void build_menu(); + int pixmapID() { return 53; } + void copy_properties(); +}; + +class Fl_Menu_Bar_Type : public Fl_Menu_Type { +public: + virtual void ideal_size(int &w, int &h) { + w = o->window()->w(); + h = ((o->labelsize() + Fl::box_dh(o->box()) + 4) / 5) * 5; + if (h < 15) h = 15; + } + virtual const char *type_name() {return "Fl_Menu_Bar";} + virtual const char *alt_type_name() {return "fltk::MenuBar";} + Fl_Widget *widget(int X,int Y,int W,int H) {return new Fl_Menu_Bar(X,Y,W,H);} + Fl_Widget_Type *_make() {return new Fl_Menu_Bar_Type();} + int pixmapID() { return 17; } +}; + + +#endif // _FLUID_FL_MENU_TYPE_H diff --git a/fluid/Fl_Type.cxx b/fluid/Fl_Type.cxx index 04b469b8d..68094850f 100644 --- a/fluid/Fl_Type.cxx +++ b/fluid/Fl_Type.cxx @@ -14,415 +14,201 @@ // https://www.fltk.org/bugs.php // -// Each object described by Fluid is one of these objects. They -// are all stored in a double-linked list. -// -// The "type" of the object is covered by the virtual functions. -// There will probably be a lot of these virtual functions. -// -// The type browser is also a list of these objects, but they -// are "factory" instances, not "real" ones. These objects exist -// only so the "make" method can be called on them. They are -// not in the linked list and are not written to files or -// copied or otherwise examined. - -#include <FL/Fl.H> -#include <FL/Fl_Browser_.H> -#include <FL/fl_draw.H> -#include <stdlib.h> -#include "../src/flstring.h" -#include <stdio.h> +/** \class Fl_Type +Each object described by Fluid is one of these objects. They +are all stored in a double-linked list. + +The "type" of the object is covered by the virtual functions. +There will probably be a lot of these virtual functions. + +The type browser is also a list of these objects, but they +are "factory" instances, not "real" ones. These objects exist +only so the "make" method can be called on them. They are +not in the linked list and are not written to files or +copied or otherwise examined. +*/ #include "Fl_Type.h" -#include "undo.h" +#include "fluid.h" +#include "Fl_Function_Type.h" +#include "Fl_Widget_Type.h" +#include "Fl_Window_Type.h" +#include "widget_browser.h" +#include "file.h" +#include "code.h" +#include "undo.h" #include "pixmaps.h" -extern int show_comments; - -//////////////////////////////////////////////////////////////// - -// Copy the given string str to buffer p with no more than maxl characters. -// Add "..." if string was truncated. -// If parameter quote is true (not 0) the string is quoted with "". -// Quote characters are NOT counted. -// The returned buffer (string) is terminated with a null byte. -// Returns pointer to end of string (before terminating null byte). -// Note: the buffer p must be large enough to hold (4 * (maxl+1) + 1) bytes -// or (4 * (maxl+1) + 3) bytes if quoted, e.g. "123..." because each UTF-8 -// character can consist of 4 bytes, "..." adds 3 bytes, quotes '""' add two -// bytes, and the terminating null byte adds another byte. -// This supports Unicode code points up to U+10FFFF (standard as of 10/2016). -// Sanity checks for illegal UTF-8 sequences are included. - -static char *copy_trunc(char *p, const char *str, int maxl, int quote) { - - int size = 0; // truncated string size in characters - int bs; // size of UTF-8 character in bytes - const char *end = str + strlen(str); // end of input string - if (quote) *p++ = '"'; // opening quote - while (size < maxl) { // maximum <maxl> characters - if (!(*str & (-32))) break; // end of string (0 or control char) - bs = fl_utf8len(*str); // size of next character - if (bs <= 0) break; // some error - leave - if (str + bs > end) break; // UTF-8 sequence beyond end of string - while (bs--) *p++ = *str++; // copy that character into the buffer - size++; // count copied characters - } - if (*str) { // string was truncated - strcpy(p,"..."); p += 3; - } - if (quote) *p++ = '"'; // closing quote - *p = 0; // terminating null byte - return p; -} - -//////////////////////////////////////////////////////////////// +#include <FL/Fl.H> +#include <FL/Fl_Browser_.H> +#include <FL/fl_draw.H> +#include "../src/flstring.h" -class Widget_Browser : public Fl_Browser_ { - friend class Fl_Type; +#include <stdlib.h> +#include <stdio.h> - // required routines for Fl_Browser_ subclass: - void *item_first() const ; - void *item_next(void *) const ; - void *item_prev(void *) const ; - int item_selected(void *) const ; - void item_select(void *,int); - int item_width(void *) const ; - int item_height(void *) const ; - void item_draw(void *,int,int,int,int) const ; - int incr_height() const ; +// ---- global variables -public: +Fl_Type *Fl_Type::first = NULL; +Fl_Type *Fl_Type::last = NULL; - int handle(int); - void callback(); - Widget_Browser(int,int,int,int,const char * =0); -}; +Fl_Type *in_this_only; // set if menu popped-up in window -static Widget_Browser *widget_browser; -Fl_Widget *make_widget_browser(int x,int y,int w,int h) { - return (widget_browser = new Widget_Browser(x,y,w,h)); -} +// ---- various functions -void redraw_widget_browser(Fl_Type *caller) -{ - if (caller) { - widget_browser->display(caller); +void select_all_cb(Fl_Widget *,void *) { + Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0; + if (in_this_only) { + Fl_Type *t = p; + for (; t && t != in_this_only; t = t->parent) {/*empty*/} + if (t != in_this_only) p = in_this_only; } - widget_browser->redraw(); -} - -void select(Fl_Type *o, int v) { - widget_browser->select(o,v,1); - // Fl_Type::current = o; -} - -void select_only(Fl_Type *o) { - widget_browser->select_only(o,1); -} - -void deselect() { - widget_browser->deselect(); - //Fl_Type::current = 0; // this breaks the paste & merge functions -} - -Fl_Type *Fl_Type::first; -Fl_Type *Fl_Type::last; - -static void Widget_Browser_callback(Fl_Widget *o,void *) { - ((Widget_Browser *)o)->callback(); -} - -Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l) -: Fl_Browser_(X,Y,W,H,l) { - type(FL_MULTI_BROWSER); - Fl_Widget::callback(Widget_Browser_callback); - when(FL_WHEN_RELEASE); -} - -void *Widget_Browser::item_first() const {return Fl_Type::first;} - -void *Widget_Browser::item_next(void *l) const {return ((Fl_Type*)l)->next;} - -void *Widget_Browser::item_prev(void *l) const {return ((Fl_Type*)l)->prev;} - -int Widget_Browser::item_selected(void *l) const {return ((Fl_Type*)l)->new_selected;} - -void Widget_Browser::item_select(void *l,int v) {((Fl_Type*)l)->new_selected = v;} - -int Widget_Browser::item_height(void *l) const { - Fl_Type *t = (Fl_Type*)l; - if (t->visible) { - if (show_comments && t->comment()) - return textsize()*2+4; - else - return textsize()+5; + for (;;) { + if (p) { + int foundany = 0; + for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) { + if (!t->new_selected) {widget_browser->select(t,1,0); foundany = 1;} + } + if (foundany) break; + p = p->parent; + } else { + for (Fl_Type *t = Fl_Type::first; t; t = t->next) + widget_browser->select(t,1,0); + break; + } } - return 0; -} - -int Widget_Browser::incr_height() const {return textsize()+2;} - -static Fl_Type* pushedtitle; - -// Generate a descriptive text for this item, to put in browser & window titles -const char* Fl_Type::title() { - const char* c = name(); if (c) return c; - return type_name(); + selection_changed(p); } -extern const char* subclassname(Fl_Type*); - - -/** - Draw an item in the widget browser. - - A browser line starts with a variable size space. This space directly - relates to the level of the type entry. - - If this type has the ability to store children, a triangle follows, - pointing right (closed) or pointing down (open, children shown). - - Next follows an icon that is specific to the type. This makes it easy to - spot certain types. - - Now follows some text. For classes and widgets, this is the type itself, - followed by the name of the object. Other objects show their content as - text, possibly abbreviated with an ellipsis. - - \param v v is a pointer to the actual widget type and can be cast safely - to Fl_Type - \param X,Y these give the position in window coordinates of the top left - corner of this line -*/ -void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const { - // cast to a more general type - Fl_Type *l = (Fl_Type *)v; - - char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul - - // calculate the horizontal start position of this item - // 3 is the edge of the browser - // 13 is the width of the arrow that indicates children for the item - // 18 is the width of the icon - // 12 is the indent per level - X += 3 + 13 + 18 + l->level * 12; - - // calculate the horizontal start position and width of the separator line - int x1 = X; - int w1 = w() - x1; - - // items can contain a comment. If they do, the comment gets a second text - // line inside this browser line - int comment_incr = 0; - if (show_comments && l->comment()) { - copy_trunc(buf, l->comment(), 80, 0); - comment_incr = textsize()-1; - if (l->new_selected) fl_color(fl_contrast(FL_DARK_GREEN,FL_SELECTION_COLOR)); - else fl_color(fl_contrast(FL_DARK_GREEN,color())); - fl_font(textfont()+FL_ITALIC, textsize()-2); - fl_draw(buf, X, Y+12); - Y += comment_incr/2; - comment_incr -= comment_incr/2; +void select_none_cb(Fl_Widget *,void *) { + Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0; + if (in_this_only) { + Fl_Type *t = p; + for (; t && t != in_this_only; t = t->parent) {/*empty*/} + if (t != in_this_only) p = in_this_only; } - - if (l->new_selected) fl_color(fl_contrast(FL_FOREGROUND_COLOR,FL_SELECTION_COLOR)); - else fl_color(FL_FOREGROUND_COLOR); - - // Width=10: Draw the triangle that indicates possible children - if (l->is_parent()) { - X = X - 18 - 13; - if (!l->next || l->next->level <= l->level) { - if (l->open_!=(l==pushedtitle)) { - // an outlined triangle to the right indicates closed item, no children - fl_loop(X,Y+7,X+5,Y+12,X+10,Y+7); - } else { - // an outlined triangle to the bottom indicates open item, no children - fl_loop(X+2,Y+2,X+7,Y+7,X+2,Y+12); + for (;;) { + if (p) { + int foundany = 0; + for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) { + if (t->new_selected) {widget_browser->select(t,0,0); foundany = 1;} } + if (foundany) break; + p = p->parent; } else { - if (l->open_!=(l==pushedtitle)) { - // a filled triangle to the right indicates closed item, with children - fl_polygon(X,Y+7,X+5,Y+12,X+10,Y+7); - } else { - // a filled triangle to the bottom indicates open item, with children - fl_polygon(X+2,Y+2,X+7,Y+7,X+2,Y+12); - } + for (Fl_Type *t = Fl_Type::first; t; t = t->next) + widget_browser->select(t,0,0); + break; } - X = X + 13 + 18; - } - - // Width=18: Draw the icon associated with the type. - Fl_Pixmap *pm = pixmap[l->pixmapID()]; - if (pm) pm->draw(X-18, Y); - - // Add tags on top of the icon for locked and protected types. - switch (l->is_public()) { - case 0: lock_pixmap->draw(X - 17, Y); break; - case 2: protected_pixmap->draw(X - 17, Y); break; } + selection_changed(p); +} - if ( l->is_widget() - && !l->is_window() - && ((Fl_Widget_Type*)l)->o - && !((Fl_Widget_Type*)l)->o->visible() - && (!l->parent || ( strcmp(l->parent->type_name(),"Fl_Tabs") - && strcmp(l->parent->type_name(),"Fl_Wizard")) ) - ) - { - invisible_pixmap->draw(X - 17, Y); +// move selected widgets in their parent's list: +void earlier_cb(Fl_Widget*,void*) { + Fl_Type *f; + int mod = 0; + for (f = Fl_Type::first; f; ) { + Fl_Type* nxt = f->next; + if (f->selected) { + Fl_Type* g; + for (g = f->prev; g && g->level > f->level; g = g->prev) {/*empty*/} + if (g && g->level == f->level && !g->selected) { + f->move_before(g); + mod = 1; + } + } + f = nxt; } + if (mod) set_modflag(1); +} - // Indent=12 per level: Now write the text that comes after the graphics representation - Y += comment_incr; - if (l->is_widget() || l->is_class()) { - const char* c = subclassname(l); - if (!strncmp(c,"Fl_",3)) c += 3; - fl_font(textfont(), textsize()); - fl_draw(c, X, Y+13); - X += int(fl_width(c)+fl_width('n')); - c = l->name(); - if (c) { - fl_font(textfont()|FL_BOLD, textsize()); - fl_draw(c, X, Y+13); - } else if ((c = l->label())) { - copy_trunc(buf, c, 20, 1); // quoted string - fl_draw(buf, X, Y+13); +void later_cb(Fl_Widget*,void*) { + Fl_Type *f; + int mod = 0; + for (f = Fl_Type::last; f; ) { + Fl_Type* prv = f->prev; + if (f->selected) { + Fl_Type* g; + for (g = f->next; g && g->level > f->level; g = g->next) {/*empty*/} + if (g && g->level == f->level && !g->selected) { + g->move_before(f); + mod = 1; + } } - } else { - copy_trunc(buf, l->title(), 55, 0); - fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize()); - fl_draw(buf, X, Y+13); + f = prv; } + if (mod) set_modflag(1); +} - // draw a thin line below the item if this item is not selected - // (if it is selected this additional line would look bad) - if (!l->new_selected) { - fl_color(fl_lighter(FL_GRAY)); - fl_line(x1,Y+16,x1+w1,Y+16); +static void delete_children(Fl_Type *p) { + Fl_Type *f; + for (f = p; f && f->next && f->next->level > p->level; f = f->next) {/*empty*/} + for (; f != p; ) { + Fl_Type *g = f->prev; + delete f; + f = g; } } -int Widget_Browser::item_width(void *v) const { - - char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul - - Fl_Type *l = (Fl_Type *)v; - - if (!l->visible) return 0; - - int W = 3 + 13 + 18 + l->level * 12; - - if (l->is_widget() || l->is_class()) { - const char* c = l->type_name(); - if (!strncmp(c,"Fl_",3)) c += 3; - fl_font(textfont(), textsize()); - W += int(fl_width(c) + fl_width('n')); - c = l->name(); - if (c) { - fl_font(textfont()|FL_BOLD, textsize()); - W += int(fl_width(c)); - } else if (l->label()) { - copy_trunc(buf, l->label(), 20, 1); // quoted string - W += int(fl_width(buf)); - } - } else { - copy_trunc(buf, l->title(), 55, 0); - fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize()); - W += int(fl_width(buf)); +// object list operations: +void delete_all(int selected_only) { + for (Fl_Type *f = Fl_Type::first; f;) { + if (f->selected || !selected_only) { + delete_children(f); + Fl_Type *g = f->next; + delete f; + f = g; + } else f = f->next; + } + if(!selected_only) { + include_H_from_C=1; + use_FL_COMMAND=0; } - return W; -} - -void redraw_browser() { - widget_browser->redraw(); + selection_changed(0); } -void Widget_Browser::callback() { - selection_changed((Fl_Type*)selection()); +// update a string member: +// replace a string pointer with new value, strips leading/trailing blanks: +int storestring(const char *n, const char * & p, int nostrip) { + if (n == p) return 0; + undo_checkpoint(); + int length = 0; + if (n) { // see if blank, strip leading & trailing blanks + if (!nostrip) while (isspace((int)(unsigned char)*n)) n++; + const char *e = n + strlen(n); + if (!nostrip) while (e > n && isspace((int)(unsigned char)*(e-1))) e--; + length = int(e-n); + if (!length) n = 0; + } + if (n == p) return 0; + if (n && p && !strncmp(n,p,length) && !p[length]) return 0; + if (p) free((void *)p); + if (!n || !*n) { + p = 0; + } else { + char *q = (char *)malloc(length+1); + strlcpy(q,n,length+1); + p = q; + } + set_modflag(1); + return 1; } - -/** - Override the event handling for this browser. - - The vertical mouse position corresponds to an entry in the type tree. - The horizontal position has the following hot zones: - - 0-3 is the widget frame and ignored - - the next hot zone starts 12*indent pixels further to the right - - the next 13 pixels refer to the arrow that indicates children for the item - - 18 pixels follow for the icon - - the remaining part is filled with text - - \param[in] e the incoming event type - \return 0 if the event is not supported, and 1 if the event was "used up" -*/ -int Widget_Browser::handle(int e) { - static Fl_Type *title; - Fl_Type *l; - int X,Y,W,H; bbox(X,Y,W,H); - switch (e) { - case FL_PUSH: - if (!Fl::event_inside(X,Y,W,H)) break; - l = (Fl_Type*)find_item(Fl::event_y()); - if (l) { - X += 3 + 12*l->level - hposition(); - if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) { - title = pushedtitle = l; - redraw_line(l); - return 1; - } - } - break; - case FL_DRAG: - if (!title) break; - l = (Fl_Type*)find_item(Fl::event_y()); - if (l) { - X += 3 + 12*l->level - hposition(); - if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) ; - else l = 0; - } - if (l != pushedtitle) { - if (pushedtitle) redraw_line(pushedtitle); - if (l) redraw_line(l); - pushedtitle = l; - } - return 1; - case FL_RELEASE: - if (!title) { - l = (Fl_Type*)find_item(Fl::event_y()); - if (l && l->new_selected && (Fl::event_clicks() || Fl::event_state(FL_CTRL))) - l->open(); - break; - } - l = pushedtitle; - title = pushedtitle = 0; - if (l) { - if (l->open_) { - l->open_ = 0; - for (Fl_Type*k = l->next; k&&k->level>l->level; k = k->next) - k->visible = 0; - } else { - l->open_ = 1; - for (Fl_Type*k=l->next; k&&k->level>l->level;) { - k->visible = 1; - if (k->is_parent() && !k->open_) { - Fl_Type *j; - for (j = k->next; j && j->level>k->level; j = j->next) {/*empty*/} - k = j; - } else - k = k->next; - } - } - redraw(); - } - return 1; +void fixvisible(Fl_Type *p) { + Fl_Type *t = p; + for (;;) { + if (t->parent) t->visible = t->parent->visible && t->parent->open_; + else t->visible = 1; + t = t->next; + if (!t || t->level <= p->level) break; } - return Fl_Browser_::handle(e); } +// ---- implemenation of Fl_Type + Fl_Type::Fl_Type() { factory = 0; parent = 0; @@ -441,21 +227,28 @@ Fl_Type::Fl_Type() { code_position_end = header_position_end = -1; } -static void fixvisible(Fl_Type *p) { - Fl_Type *t = p; - for (;;) { - if (t->parent) t->visible = t->parent->visible && t->parent->open_; - else t->visible = 1; - t = t->next; - if (!t || t->level <= p->level) break; - } +Fl_Type::~Fl_Type() { + // warning: destructor only works for widgets that have been add()ed. + if (widget_browser) widget_browser->deleting(this); + if (prev) prev->next = next; else first = next; + if (next) next->prev = prev; else last = prev; + if (current == this) current = 0; + if (parent) parent->remove_child(this); + if (name_) free((void*)name_); + if (label_) free((void*)label_); + if (callback_) free((void*)callback_); + if (user_data_) free((void*)user_data_); + if (user_data_type_) free((void*)user_data_type_); + if (comment_) free((void*)comment_); } -// turn a click at x,y on this into the actual picked object: -Fl_Type* Fl_Type::click_test(int,int) {return 0;} -void Fl_Type::add_child(Fl_Type*, Fl_Type*) {} -void Fl_Type::move_child(Fl_Type*, Fl_Type*) {} -void Fl_Type::remove_child(Fl_Type*) {} +// Generate a descriptive text for this item, to put in browser & window titles +const char* Fl_Type::title() { + const char* c = name(); + if (c) + return c; + return type_name(); +} // add a list of widgets as a new child of p: void Fl_Type::add(Fl_Type *p) { @@ -516,8 +309,7 @@ void Fl_Type::insert(Fl_Type *g) { } // Return message number for I18N... -int -Fl_Type::msgnum() { +int Fl_Type::msgnum() { int count; Fl_Type *p; @@ -532,53 +324,34 @@ Fl_Type::msgnum() { return count; } - -// delete from parent: +/** + Remove this node and all its children from the parent node. + \return the node that follows this node after the operation; can be NULL + */ Fl_Type *Fl_Type::remove() { + // -- find the last child of this node Fl_Type *end = this; for (;;) { if (!end->next || end->next->level <= level) break; end = end->next; } + // -- unlink this node from the previous one if (prev) prev->next = end->next; else first = end->next; + // -- unlink the last child from their next node if (end->next) end->next->prev = prev; else last = prev; Fl_Type *r = end->next; prev = end->next = 0; + // -- allow the parent to update changes in the UI if (parent) parent->remove_child(this); parent = 0; + widget_browser->redraw_lines(); widget_browser->redraw(); selection_changed(0); return r; } -// update a string member: -int storestring(const char *n, const char * & p, int nostrip) { - if (n == p) return 0; - undo_checkpoint(); - int length = 0; - if (n) { // see if blank, strip leading & trailing blanks - if (!nostrip) while (isspace((int)(unsigned char)*n)) n++; - const char *e = n + strlen(n); - if (!nostrip) while (e > n && isspace((int)(unsigned char)*(e-1))) e--; - length = int(e-n); - if (!length) n = 0; - } - if (n == p) return 0; - if (n && p && !strncmp(n,p,length) && !p[length]) return 0; - if (p) free((void *)p); - if (!n || !*n) { - p = 0; - } else { - char *q = (char *)malloc(length+1); - strlcpy(q,n,length+1); - p = q; - } - set_modflag(1); - return 1; -} - void Fl_Type::name(const char *n) { int nostrip = is_comment(); if (storestring(n,name_,nostrip)) { @@ -615,125 +388,6 @@ void Fl_Type::open() { printf("Open of '%s' is not yet implemented\n",type_name()); } -void Fl_Type::setlabel(const char *) {} - -Fl_Type::~Fl_Type() { - // warning: destructor only works for widgets that have been add()ed. - if (widget_browser) widget_browser->deleting(this); - if (prev) prev->next = next; else first = next; - if (next) next->prev = prev; else last = prev; - if (current == this) current = 0; - if (parent) parent->remove_child(this); - if (name_) free((void*)name_); - if (label_) free((void*)label_); - if (callback_) free((void*)callback_); - if (user_data_) free((void*)user_data_); - if (user_data_type_) free((void*)user_data_type_); - if (comment_) free((void*)comment_); -} - -int Fl_Type::is_parent() const {return 0;} -int Fl_Type::is_widget() const {return 0;} -int Fl_Type::is_valuator() const {return 0;} -int Fl_Type::is_spinner() const {return 0;} -int Fl_Type::is_button() const {return 0;} -int Fl_Type::is_input() const {return 0;} -int Fl_Type::is_value_input() const {return 0;} -int Fl_Type::is_text_display() const {return 0;} -int Fl_Type::is_menu_item() const {return 0;} -int Fl_Type::is_menu_button() const {return 0;} -int Fl_Type::is_group() const {return 0;} -int Fl_Type::is_window() const {return 0;} -int Fl_Type::is_code() const {return 0;} -int Fl_Type::is_code_block() const {return 0;} -int Fl_Type::is_decl_block() const {return 0;} -int Fl_Type::is_comment() const {return 0;} -int Fl_Type::is_class() const {return 0;} -int Fl_Type::is_public() const {return 1;} - -int Fl_Code_Type::is_public()const { return -1; } -int Fl_CodeBlock_Type::is_public()const { return -1; } - - -//////////////////////////////////////////////////////////////// - -Fl_Type *in_this_only; // set if menu popped-up in window - -void select_all_cb(Fl_Widget *,void *) { - Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0; - if (in_this_only) { - Fl_Type *t = p; - for (; t && t != in_this_only; t = t->parent) {/*empty*/} - if (t != in_this_only) p = in_this_only; - } - for (;;) { - if (p) { - int foundany = 0; - for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) { - if (!t->new_selected) {widget_browser->select(t,1,0); foundany = 1;} - } - if (foundany) break; - p = p->parent; - } else { - for (Fl_Type *t = Fl_Type::first; t; t = t->next) - widget_browser->select(t,1,0); - break; - } - } - selection_changed(p); -} - -void select_none_cb(Fl_Widget *,void *) { - Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0; - if (in_this_only) { - Fl_Type *t = p; - for (; t && t != in_this_only; t = t->parent) {/*empty*/} - if (t != in_this_only) p = in_this_only; - } - for (;;) { - if (p) { - int foundany = 0; - for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) { - if (t->new_selected) {widget_browser->select(t,0,0); foundany = 1;} - } - if (foundany) break; - p = p->parent; - } else { - for (Fl_Type *t = Fl_Type::first; t; t = t->next) - widget_browser->select(t,0,0); - break; - } - } - selection_changed(p); -} - -static void delete_children(Fl_Type *p) { - Fl_Type *f; - for (f = p; f && f->next && f->next->level > p->level; f = f->next) {/*empty*/} - for (; f != p; ) { - Fl_Type *g = f->prev; - delete f; - f = g; - } -} - -void delete_all(int selected_only) { - for (Fl_Type *f = Fl_Type::first; f;) { - if (f->selected || !selected_only) { - delete_children(f); - Fl_Type *g = f->next; - delete f; - f = g; - } else f = f->next; - } - if(!selected_only) { - include_H_from_C=1; - use_FL_COMMAND=0; - } - - selection_changed(0); -} - // move f (and its children) into list before g: // returns pointer to whatever is after f & children void Fl_Type::move_before(Fl_Type* g) { @@ -756,45 +410,6 @@ void Fl_Type::move_before(Fl_Type* g) { } -// move selected widgets in their parent's list: -void earlier_cb(Fl_Widget*,void*) { - Fl_Type *f; - int mod = 0; - for (f = Fl_Type::first; f; ) { - Fl_Type* nxt = f->next; - if (f->selected) { - Fl_Type* g; - for (g = f->prev; g && g->level > f->level; g = g->prev) {/*empty*/} - if (g && g->level == f->level && !g->selected) { - f->move_before(g); - mod = 1; - } - } - f = nxt; - } - if (mod) set_modflag(1); -} - -void later_cb(Fl_Widget*,void*) { - Fl_Type *f; - int mod = 0; - for (f = Fl_Type::last; f; ) { - Fl_Type* prv = f->prev; - if (f->selected) { - Fl_Type* g; - for (g = f->next; g && g->level > f->level; g = g->next) {/*empty*/} - if (g && g->level == f->level && !g->selected) { - g->move_before(f); - mod = 1; - } - } - f = prv; - } - if (mod) set_modflag(1); -} - -//////////////////////////////////////////////////////////////// - // write a widget and all its children: void Fl_Type::write() { write_indent(level); @@ -871,21 +486,6 @@ void Fl_Type::read_property(const char *c) { int Fl_Type::read_fdesign(const char*, const char*) {return 0;} /** - Return 1 if the list contains a function with the given signature at the top level. - */ -int has_toplevel_function(const char *rtype, const char *sig) { - Fl_Type *child; - for (child = Fl_Type::first; child; child = child->next) { - if (!child->is_in_class() && strcmp(child->type_name(), "Function")==0) { - const Fl_Function_Type *fn = (const Fl_Function_Type*)child; - if (fn->has_signature(rtype, sig)) - return 1; - } - } - return 0; -} - -/** Write a comment into the header file. */ void Fl_Type::write_comment_h(const char *pre) @@ -963,25 +563,6 @@ void Fl_Type::write_comment_inline_c(const char *pre) } /** - Make sure that the given item is visible in the browser by opening - all parent groups and moving the item into the visible space. -*/ -void reveal_in_browser(Fl_Type *t) { - Fl_Type *p = t->parent; - if (p) { - for (;;) { - if (!p->open_) - p->open_ = 1; - if (!p->parent) break; - p = p->parent; - } - fixvisible(p); - } - widget_browser->display(t); - redraw_browser(); -} - -/** Build widgets and dataset needed in live mode. \return a widget pointer that the live mode initiator can 'show()' \see leave_live_mode() @@ -1019,3 +600,56 @@ int Fl_Type::user_defined(const char* cbname) const { return 1; return 0; } + +const char *Fl_Type::callback_name() { + if (is_name(callback())) return callback(); + return unique_id(this, "cb", name(), label()); +} + +const char* Fl_Type::class_name(const int need_nest) const { + Fl_Type* p = parent; + while (p) { + if (p->is_class()) { + // see if we are nested in another class, we must fully-qualify name: + // this is lame but works... + const char* q = 0; + if(need_nest) q=p->class_name(need_nest); + if (q) { + static char s[256]; + if (q != s) strlcpy(s, q, sizeof(s)); + strlcat(s, "::", sizeof(s)); + strlcat(s, p->name(), sizeof(s)); + return s; + } + return p->name(); + } + p = p->parent; + } + return 0; +} + +/** + If this Type resides inside a class, this function returns the class type, or null. + */ +const Fl_Class_Type *Fl_Type::is_in_class() const { + Fl_Type* p = parent; + while (p) { + if (p->is_class()) { + return (Fl_Class_Type*)p; + } + p = p->parent; + } + return 0; +} + +void Fl_Type::write_static() { +} + +void Fl_Type::write_code1() { + write_h("// Header for %s\n", title()); + write_c("// Code for %s\n", title()); +} + +void Fl_Type::write_code2() { +} + diff --git a/fluid/Fl_Type.h b/fluid/Fl_Type.h index 3f7c9bde1..9027b4fc5 100644 --- a/fluid/Fl_Type.h +++ b/fluid/Fl_Type.h @@ -14,39 +14,30 @@ // https://www.fltk.org/bugs.php // -// Each object described by Fluid is one of these objects. They -// are all stored in a double-linked list. -// -// There is also a single "factory" instance of each type of this. -// The method "make()" is called on this factory to create a new -// instance of this object. It could also have a "copy()" function, -// but it was easier to implement this by using the file read/write -// that is needed to save the setup anyways. +#ifndef _FLUID_FL_TYPE_H +#define _FLUID_FL_TYPE_H #include <FL/Fl_Widget.H> -#include <FL/Fl_Menu.H> -#include <FL/Fl_Plugin.H> -#include "Fluid_Image.h" #include <FL/fl_draw.H> -#include <FL/fl_attr.h> -#include <stdarg.h> -#include <stdlib.h> +class Fl_Type; -#ifdef _WIN32 - #include "ExternalCodeEditor_WIN32.h" -#else - #include "ExternalCodeEditor_UNIX.h" -#endif +void fixvisible(Fl_Type *p); +void delete_all(int selected_only=0); +int storestring(const char *n, const char * & p, int nostrip=0); -void set_modflag(int mf); +void select_all_cb(Fl_Widget *,void *); +void select_none_cb(Fl_Widget *,void *); +void earlier_cb(Fl_Widget*,void*); +void later_cb(Fl_Widget*,void*); class Fl_Type { friend class Widget_Browser; friend Fl_Widget *make_type_browser(int,int,int,int,const char *); friend class Fl_Window_Type; - virtual void setlabel(const char *); // virtual part of label(char*) + + virtual void setlabel(const char *) { } // virtual part of label(char*) protected: @@ -107,10 +98,10 @@ public: const char *comment() { return comment_; } void comment(const char *); - virtual Fl_Type* click_test(int,int); - virtual void add_child(Fl_Type*, Fl_Type* beforethis); - virtual void move_child(Fl_Type*, Fl_Type* beforethis); - virtual void remove_child(Fl_Type*); + virtual Fl_Type* click_test(int,int) { return NULL; } + virtual void add_child(Fl_Type*, Fl_Type* beforethis) { } + virtual void move_child(Fl_Type*, Fl_Type* beforethis) { } + virtual void remove_child(Fl_Type*) { } static Fl_Type *current; // most recently picked object virtual void open(); // what happens when you double-click @@ -138,24 +129,24 @@ public: int msgnum(); // fake rtti: - virtual int is_parent() const; - virtual int is_widget() const; - virtual int is_button() const; - virtual int is_input() const; - virtual int is_value_input() const; - virtual int is_text_display() const; - virtual int is_valuator() const; - virtual int is_spinner() const; - virtual int is_menu_item() const; - virtual int is_menu_button() const; - virtual int is_group() const; - virtual int is_window() const; - virtual int is_code() const; - virtual int is_code_block() const; - virtual int is_decl_block() const; - virtual int is_comment() const; - virtual int is_class() const; - virtual int is_public() const; + virtual int is_parent() const {return 0;} + virtual int is_widget() const {return 0;} + virtual int is_button() const {return 0;} + virtual int is_input() const {return 0;} + virtual int is_value_input() const {return 0;} + virtual int is_text_display() const {return 0;} + virtual int is_valuator() const {return 0;} + virtual int is_spinner() const {return 0;} + virtual int is_menu_item() const {return 0;} + virtual int is_menu_button() const {return 0;} + virtual int is_group() const {return 0;} + virtual int is_window() const {return 0;} + virtual int is_code() const {return 0;} + virtual int is_code_block() const {return 0;} + virtual int is_decl_block() const {return 0;} + virtual int is_comment() const {return 0;} + virtual int is_class() const {return 0;} + virtual int is_public() const {return 1;} virtual int pixmapID() { return 0; } @@ -163,767 +154,4 @@ public: const class Fl_Class_Type* is_in_class() const; }; -class Fl_Function_Type : public Fl_Type { - const char* return_type; - char public_, cdecl_, constructor, havewidgets; -public: - Fl_Function_Type() : - Fl_Type(), - return_type(0L), public_(0), cdecl_(0), constructor(0), havewidgets(0) - { } - ~Fl_Function_Type() { - if (return_type) free((void*)return_type); - } - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - int ismain() {return name_ == 0;} - virtual const char *type_name() {return "Function";} - virtual const char *title() { - return name() ? name() : "main()"; - } - int is_parent() const {return 1;} - int is_code_block() const {return 1;} - virtual int is_public() const; - int pixmapID() { return 7; } - void write_properties(); - void read_property(const char *); - int has_signature(const char *, const char*) const; -}; - -class Fl_Code_Type : public Fl_Type { - ExternalCodeEditor editor_; - int cursor_position_; -public: - Fl_Code_Type() { cursor_position_ = 0; } - Fl_Type *make(); - void write(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "code";} - int is_code_block() const {return 0;} - int is_code() const {return 1;} - int pixmapID() { return 8; } - virtual int is_public() const; - // See if external editor is open - int is_editing() { - return editor_.is_editing(); - } - // Reap the editor's pid - // Returns: - // -2 -- editor not open - // -1 -- wait failed - // 0 -- process still running - // >0 -- process finished + reaped (returns pid) - // - int reap_editor() { - return editor_.reap_editor(); - } - // Handle external editor file modifications - // If changed, record keeping is updated and file's contents is loaded into ram - // - // Returns: - // 0 -- file unchanged or not editing - // 1 -- file changed, internal records updated, 'code' has new content - // -1 -- error getting file info (get_ms_errmsg() has reason) - // - // TODO: Figure out how saving a fluid file can be intercepted to grab - // current contents of editor file.. - // - int handle_editor_changes() { - const char *newcode = 0; - switch ( editor_.handle_changes(&newcode) ) { - case 1: { // (1)=changed - name(newcode); // update value in ram - free((void*)newcode); - return 1; - } - case -1: return -1; // (-1)=error -- couldn't read file (dialog showed reason) - default: break; // (0)=no change - } - return 0; - } -}; - -class Fl_CodeBlock_Type : public Fl_Type { - const char* after; -public: - Fl_CodeBlock_Type() : Fl_Type(), after(0L) { } - ~Fl_CodeBlock_Type() { - if (after) free((void*)after); - } - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "codeblock";} - int is_code_block() const {return 1;} - int is_parent() const {return 1;} - virtual int is_public() const; - int pixmapID() { return 9; } - void write_properties(); - void read_property(const char *); -}; - -class Fl_Decl_Type : public Fl_Type { -protected: - char public_; - char static_; -public: - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "decl";} - void write_properties(); - void read_property(const char *); - virtual int is_public() const; - int pixmapID() { return 10; } -}; - -class Fl_Data_Type : public Fl_Decl_Type { - const char *filename_; - int text_mode_; -public: - Fl_Data_Type() : Fl_Decl_Type(), filename_(0L), text_mode_(0) { } - ~Fl_Data_Type() { - if (filename_) free((void*)filename_); - } - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "data";} - void write_properties(); - void read_property(const char *); - int pixmapID() { return 49; } -}; - -class Fl_DeclBlock_Type : public Fl_Type { - const char* after; - char public_; -public: - Fl_DeclBlock_Type() : Fl_Type(), after(0L) { } - ~Fl_DeclBlock_Type() { - if (after) free((void*)after); - } - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "declblock";} - void write_properties(); - void read_property(const char *); - int is_parent() const {return 1;} - int is_decl_block() const {return 1;} - virtual int is_public() const; - int pixmapID() { return 11; } -}; - -class Fl_Comment_Type : public Fl_Type { - char in_c_, in_h_, style_; - char title_buf[64]; -public: - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "comment";} - virtual const char *title(); // string for browser - void write_properties(); - void read_property(const char *); - virtual int is_public() const { return 1; } - virtual int is_comment() const { return 1; } - int pixmapID() { return 46; } -}; - -class Fl_Class_Type : public Fl_Type { - const char* subclass_of; - char public_; -public: - Fl_Class_Type() : Fl_Type(), subclass_of(0L) { } - ~Fl_Class_Type() { - if (subclass_of) free((void*)subclass_of); - } - - // state variables for output: - char write_public_state; // true when public: has been printed - Fl_Class_Type* parent_class; // save class if nested -// - Fl_Type *make(); - void write_code1(); - void write_code2(); - void open(); - virtual const char *type_name() {return "class";} - int is_parent() const {return 1;} - int is_decl_block() const {return 1;} - int is_class() const {return 1;} - virtual int is_public() const; - int pixmapID() { return 12; } - void write_properties(); - void read_property(const char *); - - // class prefix attribute access - void prefix(const char* p); - const char* prefix() const {return class_prefix;} - int has_function(const char*, const char*) const; -private: - const char* class_prefix; -}; - -#define NUM_EXTRA_CODE 4 - -class Fl_Widget_Type : public Fl_Type { - virtual Fl_Widget *widget(int,int,int,int) = 0; - virtual Fl_Widget_Type *_make() = 0; // virtual constructor - virtual void setlabel(const char *); - - const char *extra_code_[NUM_EXTRA_CODE]; - const char *subclass_; - const char *tooltip_; - const char *image_name_; - const char *inactive_name_; - uchar hotspot_; - -protected: - - void write_static(); - void write_code1(); - void write_widget_code(); - void write_extra_code(); - void write_block_close(); - void write_code2(); - void write_color(const char*, Fl_Color); - Fl_Widget *live_widget; - -public: - static int default_size; - - const char *xclass; // junk string, used for shortcut - Fl_Widget *o; - int public_; - - Fluid_Image *image; - void setimage(Fluid_Image *); - Fluid_Image *inactive; - void setinactive(Fluid_Image *); - - Fl_Widget_Type(); - Fl_Type *make(); - void open(); - - const char *extra_code(int n) const {return extra_code_[n];} - void extra_code(int n,const char *); - const char *subclass() const {return subclass_;} - void subclass(const char *); - const char *tooltip() const {return tooltip_;} - void tooltip(const char *); - const char *image_name() const {return image_name_;} - void image_name(const char *); - const char *inactive_name() const {return inactive_name_;} - void inactive_name(const char *); - uchar hotspot() const {return hotspot_;} - void hotspot(uchar v) {hotspot_ = v;} - uchar resizable() const; - void resizable(uchar v); - - virtual int textstuff(int what, Fl_Font &, int &, Fl_Color &); - virtual Fl_Menu_Item *subtypes(); - - virtual int is_widget() const; - virtual int is_public() const; - - virtual void write_properties(); - virtual void read_property(const char *); - virtual int read_fdesign(const char*, const char*); - - virtual Fl_Widget *enter_live_mode(int top=0); - virtual void leave_live_mode(); - virtual void copy_properties(); - - virtual void ideal_size(int &w, int &h); - virtual void ideal_spacing(int &x, int &y); - - ~Fl_Widget_Type(); - void redraw(); -}; - -#include <FL/Fl_Tabs.H> -#include <FL/Fl_Pack.H> -#include <FL/Fl_Wizard.H> - -class igroup : public Fl_Group { -public: - void resize(int,int,int,int); - void full_resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } - igroup(int X,int Y,int W,int H) : Fl_Group(X,Y,W,H) {Fl_Group::current(0);} -}; - -class itabs : public Fl_Tabs { -public: - void resize(int,int,int,int); - void full_resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } - itabs(int X,int Y,int W,int H) : Fl_Tabs(X,Y,W,H) {} -}; - -class iwizard : public Fl_Wizard { -public: - void resize(int,int,int,int); - void full_resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } - iwizard(int X,int Y,int W,int H) : Fl_Wizard(X,Y,W,H) {} -}; - -class Fl_Group_Type : public Fl_Widget_Type { -public: - virtual const char *type_name() {return "Fl_Group";} - virtual const char *alt_type_name() {return "fltk::Group";} - Fl_Widget *widget(int X,int Y,int W,int H) { - igroup *g = new igroup(X,Y,W,H); Fl_Group::current(0); return g;} - Fl_Widget_Type *_make() {return new Fl_Group_Type();} - Fl_Type *make(); - void write_code1(); - void write_code2(); - void add_child(Fl_Type*, Fl_Type*); - void move_child(Fl_Type*, Fl_Type*); - void remove_child(Fl_Type*); - int is_parent() const {return 1;} - int is_group() const {return 1;} - int pixmapID() { return 6; } - - virtual Fl_Widget *enter_live_mode(int top=0); - virtual void leave_live_mode(); - virtual void copy_properties(); -}; - -extern const char pack_type_name[]; -extern Fl_Menu_Item pack_type_menu[]; - -class Fl_Pack_Type : public Fl_Group_Type { - Fl_Menu_Item *subtypes() {return pack_type_menu;} -public: - virtual const char *type_name() {return pack_type_name;} - virtual const char *alt_type_name() {return "fltk::PackedGroup";} - Fl_Widget_Type *_make() {return new Fl_Pack_Type();} - int pixmapID() { return 22; } - void copy_properties(); -}; - -extern const char table_type_name[]; - -class Fl_Table_Type : public Fl_Group_Type { -public: - virtual const char *type_name() {return table_type_name;} - virtual const char *alt_type_name() {return "fltk::TableGroup";} - Fl_Widget_Type *_make() {return new Fl_Table_Type();} - Fl_Widget *widget(int X,int Y,int W,int H); - int pixmapID() { return 51; } - virtual Fl_Widget *enter_live_mode(int top=0); - void add_child(Fl_Type*, Fl_Type*); - void move_child(Fl_Type*, Fl_Type*); - void remove_child(Fl_Type*); -}; - -extern const char tabs_type_name[]; - -class Fl_Tabs_Type : public Fl_Group_Type { -public: - virtual void ideal_spacing(int &x, int &y) { - x = 10; - fl_font(o->labelfont(), o->labelsize()); - y = fl_height() + o->labelsize() - 6; - } - virtual const char *type_name() {return tabs_type_name;} - virtual const char *alt_type_name() {return "fltk::TabGroup";} - Fl_Widget *widget(int X,int Y,int W,int H) { - itabs *g = new itabs(X,Y,W,H); Fl_Group::current(0); return g;} - Fl_Widget_Type *_make() {return new Fl_Tabs_Type();} - Fl_Type* click_test(int,int); - void add_child(Fl_Type*, Fl_Type*); - void remove_child(Fl_Type*); - int pixmapID() { return 13; } - Fl_Widget *enter_live_mode(int top=0); -}; - -extern const char scroll_type_name[]; -extern Fl_Menu_Item scroll_type_menu[]; - -class Fl_Scroll_Type : public Fl_Group_Type { - Fl_Menu_Item *subtypes() {return scroll_type_menu;} -public: - virtual const char *type_name() {return scroll_type_name;} - virtual const char *alt_type_name() {return "fltk::ScrollGroup";} - Fl_Widget_Type *_make() {return new Fl_Scroll_Type();} - int pixmapID() { return 19; } - Fl_Widget *enter_live_mode(int top=0); - void copy_properties(); -}; - -extern const char tile_type_name[]; - -class Fl_Tile_Type : public Fl_Group_Type { -public: - virtual const char *type_name() {return tile_type_name;} - virtual const char *alt_type_name() {return "fltk::TileGroup";} - Fl_Widget_Type *_make() {return new Fl_Tile_Type();} - int pixmapID() { return 20; } - void copy_properties(); -}; - -extern const char wizard_type_name[]; - -class Fl_Wizard_Type : public Fl_Group_Type { -public: - virtual const char *type_name() {return wizard_type_name;} - virtual const char *alt_type_name() {return "fltk::WizardGroup";} - Fl_Widget *widget(int X,int Y,int W,int H) { - iwizard *g = new iwizard(X,Y,W,H); Fl_Group::current(0); return g;} - Fl_Widget_Type *_make() {return new Fl_Wizard_Type();} - int pixmapID() { return 21; } -}; - -extern Fl_Menu_Item window_type_menu[]; - -class Fl_Window_Type : public Fl_Widget_Type { -protected: - - Fl_Menu_Item* subtypes() {return window_type_menu;} - - friend class Overlay_Window; - int mx,my; // mouse position during dragging - int x1,y1; // initial position of selection box - int bx,by,br,bt; // bounding box of selection before snapping - int sx,sy,sr,st; // bounding box of selection after snapping to guides - int dx,dy; - int drag; // which parts of bbox are being moved - int numselected; // number of children selected - enum {LEFT=1,RIGHT=2,BOTTOM=4,TOP=8,DRAG=16,BOX=32}; - void draw_overlay(); - void newdx(); - void newposition(Fl_Widget_Type *,int &x,int &y,int &w,int &h); - int handle(int); - virtual void setlabel(const char *); - void write_code1(); - void write_code2(); - Fl_Widget_Type *_make() {return 0;} // we don't call this - Fl_Widget *widget(int,int,int,int) {return 0;} - int recalc; // set by fix_overlay() - void moveallchildren(); - int pixmapID() { return 1; } - -public: - - Fl_Window_Type() { drag = dx = dy = 0; sr_min_w = sr_min_h = sr_max_w = sr_max_h = 0; } - uchar modal, non_modal; - - Fl_Type *make(); - virtual const char *type_name() {return "Fl_Window";} - virtual const char *alt_type_name() {return "fltk::Window";} - - void open(); - - void fix_overlay(); // Update the bounding box, etc - uchar *read_image(int &ww, int &hh); // Read an image of the window - - virtual void write_properties(); - virtual void read_property(const char *); - virtual int read_fdesign(const char*, const char*); - - void add_child(Fl_Type*, Fl_Type*); - void move_child(Fl_Type*, Fl_Type*); - void remove_child(Fl_Type*); - - int is_parent() const {return 1;} - int is_group() const {return 1;} - int is_window() const {return 1;} - - Fl_Widget *enter_live_mode(int top=0); - void leave_live_mode(); - void copy_properties(); - - int sr_min_w, sr_min_h, sr_max_w, sr_max_h; - - static int popupx, popupy; -}; - -class Fl_Widget_Class_Type : private Fl_Window_Type { -public: - Fl_Widget_Class_Type() { - write_public_state = 0; - wc_relative = 0; - } - // state variables for output: - char write_public_state; // true when public: has been printed - char wc_relative; // if true, reposition all child widgets in an Fl_Group - - virtual void write_properties(); - virtual void read_property(const char *); - - void write_code1(); - void write_code2(); - Fl_Type *make(); - virtual const char *type_name() {return "widget_class";} - int pixmapID() { return 48; } - int is_parent() const {return 1;} - int is_code_block() const {return 1;} - int is_decl_block() const {return 1;} - int is_class() const {return 1;} -}; - - -extern Fl_Menu_Item menu_item_type_menu[]; - -class Fl_Menu_Item_Type : public Fl_Widget_Type { -public: - Fl_Menu_Item* subtypes() {return menu_item_type_menu;} - const char* type_name() {return "MenuItem";} - const char* alt_type_name() {return "fltk::Item";} - Fl_Type* make(); - int is_menu_item() const {return 1;} - int is_button() const {return 1;} // this gets shortcut to work - Fl_Widget* widget(int,int,int,int) {return 0;} - Fl_Widget_Type* _make() {return 0;} - const char* menu_name(int& i); - int flags(); - void write_static(); - void write_item(); - void write_code1(); - void write_code2(); - int pixmapID() { return 16; } -}; - -class Fl_Radio_Menu_Item_Type : public Fl_Menu_Item_Type { -public: - const char* type_name() {return "RadioMenuItem";} - Fl_Type* make(); - int pixmapID() { return 55; } -}; - -class Fl_Checkbox_Menu_Item_Type : public Fl_Menu_Item_Type { -public: - const char* type_name() {return "CheckMenuItem";} - Fl_Type* make(); - int pixmapID() { return 54; } -}; - -class Fl_Submenu_Type : public Fl_Menu_Item_Type { -public: - Fl_Menu_Item* subtypes() {return 0;} - const char* type_name() {return "Submenu";} - const char* alt_type_name() {return "fltk::ItemGroup";} - int is_parent() const {return 1;} - int is_button() const {return 0;} // disable shortcut - Fl_Type* make(); - // changes to submenu must propagate up so build_menu is called - // on the parent Fl_Menu_Type: - void add_child(Fl_Type*a, Fl_Type*b) {parent->add_child(a,b);} - void move_child(Fl_Type*a, Fl_Type*b) {parent->move_child(a,b);} - void remove_child(Fl_Type*a) {parent->remove_child(a);} - int pixmapID() { return 18; } -}; - - - -#include <FL/Fl_Menu_.H> -class Fl_Menu_Type : public Fl_Widget_Type { - int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { - Fl_Menu_ *myo = (Fl_Menu_*)(w==4 ? ((Fl_Widget_Type*)this->factory)->o : this->o); - switch (w) { - case 4: - case 0: f = myo->textfont(); s = myo->textsize(); c = myo->textcolor(); break; - case 1: myo->textfont(f); break; - case 2: myo->textsize(s); break; - case 3: myo->textcolor(c); break; - } - return 1; - } -public: - int is_menu_button() const {return 1;} - int is_parent() const {return 1;} - int menusize; - virtual void build_menu(); - Fl_Menu_Type() : Fl_Widget_Type() {menusize = 0;} - ~Fl_Menu_Type() { - if (menusize) delete[] (Fl_Menu_Item*)(((Fl_Menu_*)o)->menu()); - } - void add_child(Fl_Type*, Fl_Type*) {build_menu();} - void move_child(Fl_Type*, Fl_Type*) {build_menu();} - void remove_child(Fl_Type*) {build_menu();} - Fl_Type* click_test(int x, int y); - void write_code2(); - void copy_properties(); -}; - -extern Fl_Menu_Item button_type_menu[]; - -#include <FL/Fl_Menu_Button.H> -class Fl_Menu_Button_Type : public Fl_Menu_Type { - Fl_Menu_Item *subtypes() {return button_type_menu;} -public: - virtual void ideal_size(int &w, int &h) { - Fl_Widget_Type::ideal_size(w, h); - w += 2 * ((o->labelsize() - 3) & ~1) + o->labelsize() - 4; - h = (h / 5) * 5; - if (h < 15) h = 15; - if (w < (15 + h)) w = 15 + h; - } - virtual const char *type_name() {return "Fl_Menu_Button";} - virtual const char *alt_type_name() {return "fltk::MenuButton";} - Fl_Widget *widget(int X,int Y,int W,int H) { - return new Fl_Menu_Button(X,Y,W,H,"menu");} - Fl_Widget_Type *_make() {return new Fl_Menu_Button_Type();} - int pixmapID() { return 26; } -}; - -extern Fl_Menu_Item dummymenu[]; - -#include <FL/Fl_Choice.H> -class Fl_Choice_Type : public Fl_Menu_Type { -public: - virtual void ideal_size(int &w, int &h) { - Fl_Widget_Type::ideal_size(w, h); - int w1 = o->h() - Fl::box_dh(o->box()); - if (w1 > 20) w1 = 20; - w1 = (w1 - 4) / 3; - if (w1 < 1) w1 = 1; - w += 2 * w1 + o->labelsize() - 4; - h = (h / 5) * 5; - if (h < 15) h = 15; - if (w < (15 + h)) w = 15 + h; - } - virtual const char *type_name() {return "Fl_Choice";} - virtual const char *alt_type_name() {return "fltk::Choice";} - Fl_Widget *widget(int X,int Y,int W,int H) { - Fl_Choice *myo = new Fl_Choice(X,Y,W,H,"choice:"); - myo->menu(dummymenu); - return myo; - } - Fl_Widget_Type *_make() {return new Fl_Choice_Type();} - int pixmapID() { return 15; } -}; - -#include <FL/Fl_Input_Choice.H> -class Fl_Input_Choice_Type : public Fl_Menu_Type { - int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { - Fl_Input_Choice *myo = (Fl_Input_Choice*)(w==4 ? ((Fl_Widget_Type*)this->factory)->o : this->o); - switch (w) { - case 4: - case 0: f = (Fl_Font)myo->textfont(); s = myo->textsize(); c = myo->textcolor(); break; - case 1: myo->textfont(f); break; - case 2: myo->textsize(s); break; - case 3: myo->textcolor(c); break; - } - return 1; - } -public: - virtual void ideal_size(int &w, int &h) { - Fl_Input_Choice *myo = (Fl_Input_Choice *)o; - fl_font(myo->textfont(), myo->textsize()); - h = fl_height() + myo->textsize() - 6; - w = o->w() - 20 - Fl::box_dw(o->box()); - int ww = (int)fl_width('m'); - w = ((w + ww - 1) / ww) * ww + 20 + Fl::box_dw(o->box()); - if (h < 15) h = 15; - if (w < (15 + h)) w = 15 + h; - } - virtual const char *type_name() {return "Fl_Input_Choice";} - virtual const char *alt_type_name() {return "fltk::ComboBox";} - virtual Fl_Type* click_test(int,int); - Fl_Widget *widget(int X,int Y,int W,int H) { - Fl_Input_Choice *myo = new Fl_Input_Choice(X,Y,W,H,"input choice:"); - myo->menu(dummymenu); - myo->value("input"); - return myo; - } - Fl_Widget_Type *_make() {return new Fl_Input_Choice_Type();} - virtual void build_menu(); - int pixmapID() { return 53; } - void copy_properties(); -}; - -#include <FL/Fl_Window.H> -#include <FL/Fl_Menu_Bar.H> -class Fl_Menu_Bar_Type : public Fl_Menu_Type { -public: - virtual void ideal_size(int &w, int &h) { - w = o->window()->w(); - h = ((o->labelsize() + Fl::box_dh(o->box()) + 4) / 5) * 5; - if (h < 15) h = 15; - } - virtual const char *type_name() {return "Fl_Menu_Bar";} - virtual const char *alt_type_name() {return "fltk::MenuBar";} - Fl_Widget *widget(int X,int Y,int W,int H) {return new Fl_Menu_Bar(X,Y,W,H);} - Fl_Widget_Type *_make() {return new Fl_Menu_Bar_Type();} - int pixmapID() { return 17; } -}; -// object list operations: -Fl_Widget *make_widget_browser(int X,int Y,int W,int H); -void redraw_widget_browser(Fl_Type*); -extern int modflag; -void delete_all(int selected_only=0); -void selection_changed(Fl_Type* new_current); -void reveal_in_browser(Fl_Type*); -int has_toplevel_function(const char *rtype, const char *sig); - -// file operations: -void write_word(const char *); -void write_string(const char *,...) __fl_attr((__format__ (__printf__, 1, 2))); -int write_file(const char *, int selected_only = 0); -int write_code(const char *cfile, const char *hfile); -int write_strings(const char *sfile); - -int write_declare(const char *, ...) __fl_attr((__format__ (__printf__, 1, 2))); -int is_id(char); -const char* unique_id(void* o, const char*, const char*, const char*); -void write_c(const char*, ...) __fl_attr((__format__ (__printf__, 1, 2))); -void write_cc(const char *, int, const char*, const char*); -void vwrite_c(const char* format, va_list args); -void write_h(const char*, ...) __fl_attr((__format__ (__printf__, 1, 2))); -void write_hc(const char *, int, const char*, const char*); -void write_cstring(const char *); -void write_cstring(const char *,int length); -void write_cdata(const char *,int length); -void write_indent(int n); -void write_open(int); -void write_close(int n); -extern int write_number; -extern int write_sourceview; -void write_public(int state); // writes pubic:/private: as needed -extern int indentation; -extern const char* indent(); - -int read_file(const char *, int merge); -const char *read_word(int wantbrace = 0); -void read_error(const char *format, ...); - -// check legality of c code (sort of) and return error: -const char *c_check(const char *c, int type = 0); - -// replace a string pointer with new value, strips leading/trailing blanks: -int storestring(const char *n, const char * & p, int nostrip=0); - -extern int include_H_from_C; -extern int use_FL_COMMAND; - -/* - This class is needed for additional command line plugins. - */ -class Fl_Commandline_Plugin : public Fl_Plugin { -public: - Fl_Commandline_Plugin(const char *name) - : Fl_Plugin(klass(), name) { } - virtual const char *klass() { return "commandline"; } - // return a unique name for this plugin - virtual const char *name() = 0; - // return a help text for all supported commands - virtual const char *help() = 0; - // handle a command and return the number of args used, or 0 - virtual int arg(int argc, char **argv, int &i) = 0; - // optional test the plugin - virtual int test(const char *a1=0L, const char *a2=0L, const char *a3=0L) { - return 0; - } - // show a GUI panel to edit some data - virtual void show_panel() { } -}; +#endif // _FLUID_FL_TYPE_H diff --git a/fluid/Fl_Widget_Type.cxx b/fluid/Fl_Widget_Type.cxx index 17765dc06..53d0ec06a 100644 --- a/fluid/Fl_Widget_Type.cxx +++ b/fluid/Fl_Widget_Type.cxx @@ -14,17 +14,30 @@ // https://www.fltk.org/bugs.php // +#include "Fl_Widget_Type.h" + +#include "fluid.h" +#include "Fl_Window_Type.h" +#include "Fl_Group_Type.h" +#include "Fl_Menu_Type.h" +#include "Fl_Function_Type.h" +#include "file.h" +#include "code.h" +#include "Fluid_Image.h" +#include "alignment_panel.h" +#include "widget_panel.h" + #include <FL/Fl.H> #include <FL/Fl_Group.H> #include <FL/Fl_Table.H> #include <FL/Fl_Input.H> -#include "Fl_Widget_Type.h" -#include "alignment_panel.h" #include <FL/fl_message.H> #include <FL/Fl_Slider.H> #include <FL/Fl_Spinner.H> #include <FL/Fl_Window.H> +#include <FL/fl_show_colormap.H> #include "../src/flstring.h" + #include <stdio.h> #include <stdlib.h> @@ -35,16 +48,6 @@ // instance, sets the widget pointers, and makes all the display // update correctly... -extern int reading_file; -int force_parent; -extern int gridx; -extern int gridy; -extern int i18n_type; -extern const char* i18n_include; -extern const char* i18n_function; -extern const char* i18n_file; -extern const char* i18n_set; - int Fl_Widget_Type::default_size = FL_NORMAL_SIZE; int Fl_Widget_Type::is_widget() const {return 1;} @@ -164,8 +167,6 @@ Fl_Type *Fl_Widget_Type::make() { return t; } -#include "Fluid_Image.h" - void Fl_Widget_Type::setimage(Fluid_Image *i) { if (i == image || is_window()) return; if (image) image->decrement(); @@ -287,9 +288,6 @@ Fl_Type *sort(Fl_Type *parent) { //////////////////////////////////////////////////////////////// // The control panels! -#include "widget_panel.h" -#include <FL/fl_show_colormap.H> - static Fl_Window *the_panel; // All the callbacks use the argument to indicate whether to load or store. @@ -2089,11 +2087,6 @@ void Fl_Widget_Type::write_static() { } } -const char *Fl_Type::callback_name() { - if (is_name(callback())) return callback(); - return unique_id(this, "cb", name(), label()); -} - extern int varused_test, varused; void Fl_Widget_Type::write_code1() { @@ -2532,8 +2525,6 @@ void Fl_Widget_Type::write_properties() { } } -int pasteoffset; -extern double read_version; void Fl_Widget_Type::read_property(const char *c) { int x,y,w,h; Fl_Font f; int s; Fl_Color cc; if (!strcmp(c,"private")) { @@ -2698,7 +2689,6 @@ Fl_Menu_Item boxmenu1[] = { {"11", 0,0,(void *)FL_DOWN_FRAME}, {0}}; -extern int fdesign_flip; int lookup_symbol(const char *, int &, int numberok = 0); int Fl_Widget_Type::read_fdesign(const char* propname, const char* value) { diff --git a/fluid/Fl_Widget_Type.h b/fluid/Fl_Widget_Type.h index ab33f4e10..6d39fb9f4 100644 --- a/fluid/Fl_Widget_Type.h +++ b/fluid/Fl_Widget_Type.h @@ -18,10 +18,99 @@ // https://www.fltk.org/bugs.php // +#ifndef _FLUID_FL_WIDGET_TYPE_H +#define _FLUID_FL_WIDGET_TYPE_H + #include "Fl_Type.h" -struct Fl_Menu_Item; +#define NUM_EXTRA_CODE 4 + +class Fl_Widget_Type; class Fluid_Image; extern void* const LOAD; extern Fl_Widget_Type *current_widget; // one of the selected ones + +extern const char* subclassname(Fl_Type* l); +extern int is_name(const char *c); +void selection_changed(Fl_Type* new_current); +Fl_Type *sort(Fl_Type *parent); +void comment_cb(class Fl_Text_Editor* i, void *v); + +class Fl_Widget_Type : public Fl_Type { + virtual Fl_Widget *widget(int,int,int,int) = 0; + virtual Fl_Widget_Type *_make() = 0; // virtual constructor + virtual void setlabel(const char *); + + const char *extra_code_[NUM_EXTRA_CODE]; + const char *subclass_; + const char *tooltip_; + const char *image_name_; + const char *inactive_name_; + uchar hotspot_; + +protected: + + void write_static(); + void write_code1(); + void write_widget_code(); + void write_extra_code(); + void write_block_close(); + void write_code2(); + void write_color(const char*, Fl_Color); + Fl_Widget *live_widget; + +public: + static int default_size; + + const char *xclass; // junk string, used for shortcut + Fl_Widget *o; + int public_; + + Fluid_Image *image; + void setimage(Fluid_Image *); + Fluid_Image *inactive; + void setinactive(Fluid_Image *); + + Fl_Widget_Type(); + Fl_Type *make(); + void open(); + + const char *extra_code(int n) const {return extra_code_[n];} + void extra_code(int n,const char *); + const char *subclass() const {return subclass_;} + void subclass(const char *); + const char *tooltip() const {return tooltip_;} + void tooltip(const char *); + const char *image_name() const {return image_name_;} + void image_name(const char *); + const char *inactive_name() const {return inactive_name_;} + void inactive_name(const char *); + uchar hotspot() const {return hotspot_;} + void hotspot(uchar v) {hotspot_ = v;} + uchar resizable() const; + void resizable(uchar v); + + virtual int textstuff(int what, Fl_Font &, int &, Fl_Color &); + virtual Fl_Menu_Item *subtypes(); + + virtual int is_widget() const; + virtual int is_public() const; + + virtual void write_properties(); + virtual void read_property(const char *); + virtual int read_fdesign(const char*, const char*); + + virtual Fl_Widget *enter_live_mode(int top=0); + virtual void leave_live_mode(); + virtual void copy_properties(); + + virtual void ideal_size(int &w, int &h); + virtual void ideal_spacing(int &x, int &y); + + ~Fl_Widget_Type(); + void redraw(); +}; + + +#endif // _FLUID_FL_WIDGET_TYPE_H diff --git a/fluid/Fl_Window_Type.cxx b/fluid/Fl_Window_Type.cxx index ff196d2e1..c42d62af7 100644 --- a/fluid/Fl_Window_Type.cxx +++ b/fluid/Fl_Window_Type.cxx @@ -18,6 +18,16 @@ // https://www.fltk.org/bugs.php // +#include "Fl_Window_Type.h" + +#include "fluid.h" +#include "widget_browser.h" +#include "undo.h" +#include "alignment_panel.h" +#include "file.h" +#include "code.h" +#include "widget_panel.h" + #include <FL/Fl.H> #include <FL/Fl_Overlay_Window.H> #include <FL/fl_message.H> @@ -25,18 +35,12 @@ #include <FL/platform.H> #include <FL/Fl_Menu_Item.H> #include <FL/Fl_Round_Button.H> -#include "Fl_Widget_Type.h" -#include "undo.h" +#include "../src/flstring.h" + #include <math.h> #include <stdlib.h> -#include "alignment_panel.h" #include <stdio.h> -extern int gridx; -extern int gridy; -extern int snap; -extern int show_guides; - int include_H_from_C = 1; int use_FL_COMMAND = 0; extern int i18n_type; @@ -49,8 +53,6 @@ extern Fl_Preferences fluid_prefs; inline int fl_min(int a, int b) { return (a < b ? a : b); } -#include "widget_panel.h" - // Update the XYWH values in the widget panel... static void update_xywh() { if (current_widget && current_widget->is_widget()) { @@ -174,9 +176,6 @@ void i18n_int_cb(Fl_Int_Input *i, void *) { set_modflag(1); } -extern const char* header_file_name; -extern const char* code_file_name; - void show_project_cb(Fl_Widget *, void *) { if(project_window==0) make_project_window(); include_H_from_C_button->value(include_H_from_C); @@ -1350,9 +1349,6 @@ int Fl_Window_Type::handle(int event) { //////////////////////////////////////////////////////////////// -#include <stdio.h> -#include "../src/flstring.h" - void Fl_Window_Type::write_code1() { Fl_Widget_Type::write_code1(); } @@ -1393,7 +1389,6 @@ void Fl_Window_Type::write_properties() { if (o->visible()) write_string("visible"); } -extern int pasteoffset; void Fl_Window_Type::read_property(const char *c) { if (!strcmp(c,"modal")) { modal = 1; diff --git a/fluid/Fl_Window_Type.h b/fluid/Fl_Window_Type.h new file mode 100644 index 000000000..4067d03f9 --- /dev/null +++ b/fluid/Fl_Window_Type.h @@ -0,0 +1,125 @@ +// +// Widget type header file for the Fast Light Tool Kit (FLTK). +// +// Type for creating all subclasses of Fl_Widget +// This should have the widget pointer in it, but it is still in the +// Fl_Type base class. +// +// Copyright 1998-2010 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FL_WINDOW_TYPE_H +#define _FLUID_FL_WINDOW_TYPE_H + +#include "Fl_Widget_Type.h" + +class Fl_Widget_Class_Type; + +extern int include_H_from_C; +extern int use_FL_COMMAND; + +extern Fl_Menu_Item window_type_menu[]; +extern Fl_Widget_Class_Type *current_widget_class; +void toggle_overlays(Fl_Widget *,void *); +void show_project_cb(Fl_Widget *, void *); +void show_grid_cb(Fl_Widget *, void *); +void show_settings_cb(Fl_Widget *, void *); +void show_global_settings_cb(Fl_Widget *, void *); + +class Fl_Window_Type : public Fl_Widget_Type { +protected: + + Fl_Menu_Item* subtypes() {return window_type_menu;} + + friend class Overlay_Window; + int mx,my; // mouse position during dragging + int x1,y1; // initial position of selection box + int bx,by,br,bt; // bounding box of selection before snapping + int sx,sy,sr,st; // bounding box of selection after snapping to guides + int dx,dy; + int drag; // which parts of bbox are being moved + int numselected; // number of children selected + enum {LEFT=1,RIGHT=2,BOTTOM=4,TOP=8,DRAG=16,BOX=32}; + void draw_overlay(); + void newdx(); + void newposition(Fl_Widget_Type *,int &x,int &y,int &w,int &h); + int handle(int); + virtual void setlabel(const char *); + void write_code1(); + void write_code2(); + Fl_Widget_Type *_make() {return 0;} // we don't call this + Fl_Widget *widget(int,int,int,int) {return 0;} + int recalc; // set by fix_overlay() + void moveallchildren(); + int pixmapID() { return 1; } + +public: + + Fl_Window_Type() { drag = dx = dy = 0; sr_min_w = sr_min_h = sr_max_w = sr_max_h = 0; } + uchar modal, non_modal; + + Fl_Type *make(); + virtual const char *type_name() {return "Fl_Window";} + virtual const char *alt_type_name() {return "fltk::Window";} + + void open(); + + void fix_overlay(); // Update the bounding box, etc + uchar *read_image(int &ww, int &hh); // Read an image of the window + + virtual void write_properties(); + virtual void read_property(const char *); + virtual int read_fdesign(const char*, const char*); + + void add_child(Fl_Type*, Fl_Type*); + void move_child(Fl_Type*, Fl_Type*); + void remove_child(Fl_Type*); + + int is_parent() const {return 1;} + int is_group() const {return 1;} + int is_window() const {return 1;} + + Fl_Widget *enter_live_mode(int top=0); + void leave_live_mode(); + void copy_properties(); + + int sr_min_w, sr_min_h, sr_max_w, sr_max_h; + + static int popupx, popupy; +}; + +class Fl_Widget_Class_Type : private Fl_Window_Type { +public: + Fl_Widget_Class_Type() { + write_public_state = 0; + wc_relative = 0; + } + // state variables for output: + char write_public_state; // true when public: has been printed + char wc_relative; // if true, reposition all child widgets in an Fl_Group + + virtual void write_properties(); + virtual void read_property(const char *); + + void write_code1(); + void write_code2(); + Fl_Type *make(); + virtual const char *type_name() {return "widget_class";} + int pixmapID() { return 48; } + int is_parent() const {return 1;} + int is_code_block() const {return 1;} + int is_decl_block() const {return 1;} + int is_class() const {return 1;} +}; + +#endif // _FLUID_FL_WINDOW_TYPE_H diff --git a/fluid/Fluid_Image.cxx b/fluid/Fluid_Image.cxx index 1057f171d..f1f5832b1 100644 --- a/fluid/Fluid_Image.cxx +++ b/fluid/Fluid_Image.cxx @@ -14,22 +14,28 @@ // https://www.fltk.org/bugs.php // +#include "Fluid_Image.h" + +#include "fluid.h" +#include "Fl_Group_Type.h" +#include "Fl_Window_Type.h" +#include "file.h" +#include "code.h" + #include <FL/Fl.H> #include <FL/Fl_Widget.H> +#include <FL/Fl_Window.H> #include <FL/filename.H> #include <FL/fl_string.h> #include <FL/fl_utf8.h> // fl_fopen() -#include "Fl_Type.h" -#include "Fluid_Image.h" +#include <FL/Fl_File_Chooser.H> #include "../src/flstring.h" + #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <stdarg.h> -extern void goto_source_dir(); // in fluid.cxx -extern void leave_source_dir(); // in fluid.cxx - void Fluid_Image::image(Fl_Widget *o) { if (o->window() != o) o->image(img); } @@ -236,8 +242,6 @@ Fluid_Image::~Fluid_Image() { //////////////////////////////////////////////////////////////// -#include <FL/Fl_File_Chooser.H> - const char *ui_find_image_name; Fluid_Image *ui_find_image(const char *oldname) { goto_source_dir(); diff --git a/fluid/Fluid_Image.h b/fluid/Fluid_Image.h index 7020c14f6..99b06d218 100644 --- a/fluid/Fluid_Image.h +++ b/fluid/Fluid_Image.h @@ -19,10 +19,9 @@ // #ifndef FLUID_IMAGE_H -# define FLUID_IMAGE_H - -# include <FL/Fl_Shared_Image.H> +#define FLUID_IMAGE_H +#include <FL/Fl_Shared_Image.H> class Fluid_Image { const char *name_; diff --git a/fluid/Makefile b/fluid/Makefile index 3a9e0f888..c87c05719 100644 --- a/fluid/Makefile +++ b/fluid/Makefile @@ -35,8 +35,10 @@ CPPFILES = \ fluid.cxx \ function_panel.cxx \ pixmaps.cxx \ + shell_command.cxx \ template_panel.cxx \ undo.cxx \ + widget_browser.cxx \ widget_panel.cxx # ExternalCodeEditor: platform specific files diff --git a/fluid/Shortcut_Button.h b/fluid/Shortcut_Button.h index 8726fa654..790415158 100644 --- a/fluid/Shortcut_Button.h +++ b/fluid/Shortcut_Button.h @@ -14,6 +14,9 @@ // https://www.fltk.org/bugs.php // +#ifndef _FLUID_SHORTCUT_BUTTON_H +#define _FLUID_SHORTCUT_BUTTON_H + #include <FL/Fl_Button.H> class Shortcut_Button : public Fl_Button { @@ -24,3 +27,6 @@ public: Shortcut_Button(int X,int Y,int W,int H, const char* l = 0) : Fl_Button(X,Y,W,H,l) {svalue = 0;} }; + +#endif + diff --git a/fluid/StyleParse.cxx b/fluid/StyleParse.cxx index 5d0dd5e5d..b8b8ff4f0 100644 --- a/fluid/StyleParse.cxx +++ b/fluid/StyleParse.cxx @@ -15,11 +15,12 @@ // https://www.fltk.org/bugs.php // +#include "StyleParse.h" + #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> // bsearch() -#include "StyleParse.h" // Sorted list of C/C++ keywords... static const char * const code_keywords[] = { diff --git a/fluid/about_panel.cxx b/fluid/about_panel.cxx index 7dc5fadde..5a6e40e5b 100644 --- a/fluid/about_panel.cxx +++ b/fluid/about_panel.cxx @@ -1,7 +1,7 @@ // // About dialog for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 by Bill Spitzak and others. +// Copyright 1998-2021 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this diff --git a/fluid/about_panel.fl b/fluid/about_panel.fl index a0a302349..74cedb06f 100644 --- a/fluid/about_panel.fl +++ b/fluid/about_panel.fl @@ -5,7 +5,7 @@ code_name {.cxx} comment {// // About dialog for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 by Bill Spitzak and others. +// Copyright 1998-2021 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -36,8 +36,8 @@ Function {make_about_panel()} {open }} {} Fl_Window about_panel { label {About FLUID} open - xywh {340 190 345 180} type Double color 50 selection_color 47 hide hotspot - code0 {\#include "../src/flstring.h"} non_modal + xywh {449 217 345 180} type Double color 50 selection_color 47 hotspot + code0 {\#include "../src/flstring.h"} non_modal visible } { Fl_Box {} { image {icons/fluid-96.xpm} xywh {10 10 115 120} @@ -53,7 +53,7 @@ Version x.x.x} } Fl_Box {} { label {(Copyright)} - comment {Label edited dynamically:} selected + comment {Label edited dynamically:} xywh {135 90 200 45} align 148 code0 {o->label(cbuf);} } @@ -71,5 +71,5 @@ Version x.x.x} } data fluid_org_png { - comment {Embedded image for internal fluid.html web page.} public local filename {../documentation/src/fluid-org.png} + comment {Embedded image for internal fluid.html web page.} selected public local filename {../documentation/src/fluid-org.png} } diff --git a/fluid/about_panel.h b/fluid/about_panel.h index effa7ccb4..d7006c08b 100644 --- a/fluid/about_panel.h +++ b/fluid/about_panel.h @@ -1,7 +1,7 @@ // // About dialog for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 by Bill Spitzak and others. +// Copyright 1998-2021 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this diff --git a/fluid/align_widget.cxx b/fluid/align_widget.cxx index 7a05b6129..f9bf2c02f 100644 --- a/fluid/align_widget.cxx +++ b/fluid/align_widget.cxx @@ -14,10 +14,14 @@ // https://www.fltk.org/bugs.php // +#include "align_widget.h" + +#include "fluid.h" +#include "Fl_Group_Type.h" +#include "undo.h" + #include <FL/Fl.H> #include <FL/Fl_Window.H> -#include "Fl_Widget_Type.h" -#include "undo.h" /** the first behaviour always uses the first selected widget as a reference diff --git a/fluid/align_widget.h b/fluid/align_widget.h new file mode 100644 index 000000000..541894e94 --- /dev/null +++ b/fluid/align_widget.h @@ -0,0 +1,25 @@ +// +// FLUID main entry for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_ALIGN_WIDGET_H +#define _FLUID_ALIGN_WIDGET_H + +class Fl_Widget; + +void align_widget_cb(Fl_Widget *, long); +void widget_size_cb(Fl_Widget *, long); + +#endif // _FLUID_ALIGN_WIDGET_H diff --git a/fluid/alignment_panel.fl b/fluid/alignment_panel.fl index 20b09b575..9d0ed50a3 100644 --- a/fluid/alignment_panel.fl +++ b/fluid/alignment_panel.fl @@ -20,6 +20,12 @@ comment {// } {in_source in_header } +decl {\#include "fluid.h"} {public global +} + +decl {\#include "widget_browser.h"} {public global +} + decl {\#include <FL/Fl_Text_Buffer.H>} {public local } @@ -38,37 +44,16 @@ decl {\#include <FL/fl_ask.H>} {private global decl {\#include <string.h>} {private global } -decl {extern void load_history();} {public local -} - -decl {extern void redraw_browser();} {public local -} - -decl {extern int show_comments;} {public local -} - -decl {extern int G_use_external_editor;} {public local -} - -decl {extern char G_external_editor_command[512];} {public local -} - -decl {extern int show_coredevmenus;} {public local -} - decl {extern struct Fl_Menu_Item *dbmanager_item;} {public local } -decl {extern Fl_Preferences fluid_prefs;} {public local -} - Function {make_project_window()} {open } { Fl_Window project_window { - label {Project Settings} open - xywh {396 475 399 252} type Double hide + label {Project Settings} + xywh {473 246 399 252} type Double code0 {\#include <FL/Fl_Preferences.H>} - code1 {\#include <FL/Fl_Tooltip.H>} modal + code1 {\#include <FL/Fl_Tooltip.H>} modal visible } { Fl_Button {} { label Close @@ -162,11 +147,12 @@ decl {extern void i18n_cb(Fl_Choice *,void *);} {public local decl {void scheme_cb(Fl_Choice *, void *);} {public local } -Function {make_settings_window()} {} { +Function {make_settings_window()} {open +} { Fl_Window settings_window { - label {GUI Settings} open - xywh {355 85 360 355} type Double hide resizable - code0 {o->size_range(o->w(), o->h());} non_modal + label {GUI Settings} + xywh {442 538 360 355} type Double resizable + code0 {o->size_range(o->w(), o->h());} non_modal visible } { Fl_Choice scheme_choice { label {Scheme: } @@ -295,11 +281,11 @@ Examples: } } -Function {make_shell_window()} {open +Function {make_shell_window()} {open selected } { Fl_Window shell_window { - label {Shell Command} open - xywh {761 190 365 125} type Double hide + label {Shell Command} + xywh {873 248 365 125} type Double visible } { Fl_Input shell_command_input { label {Command:} @@ -345,8 +331,8 @@ Function {make_shell_window()} {open } } Fl_Window shell_run_window { - label {Shell Command Output} open - xywh {454 363 555 430} type Double hide resizable + label {Shell Command Output} + xywh {887 409 555 430} type Double resizable visible } { Fl_Simple_Terminal shell_run_terminal { xywh {10 10 535 375} resizable @@ -364,10 +350,11 @@ shell_run_window->hide();} } } -Function {make_layout_window()} {} { +Function {make_layout_window()} {open +} { Fl_Window grid_window { - label {Layout Settings} open - xywh {812 369 310 245} type Double hide non_modal + label {Layout Settings} + xywh {545 376 310 245} type Double non_modal visible } { Fl_Input horizontal_input { label x @@ -558,7 +545,7 @@ Function {writePrefs()} { }} {} } -Function {show_global_settings_window()} {open return_type void +Function {show_global_settings_window()} {return_type void } { code {if (!global_settings_window) make_global_settings_window(); @@ -749,7 +736,7 @@ Default is on.} xywh {245 366 100 25} down_box BORDER_BOX } { MenuItem {} { label off - user_data 0 user_data_type long selected + user_data 0 user_data_type long xywh {30 30 31 20} } MenuItem {} { @@ -781,7 +768,7 @@ Default is on.} xywh {245 442 100 25} down_box BORDER_BOX } { MenuItem {} { label off - user_data 0 user_data_type long selected + user_data 0 user_data_type long xywh {30 30 31 20} } MenuItem {} { diff --git a/fluid/alignment_panel.h b/fluid/alignment_panel.h index e2a9bdc03..0457f4560 100644 --- a/fluid/alignment_panel.h +++ b/fluid/alignment_panel.h @@ -19,17 +19,12 @@ #ifndef alignment_panel_h #define alignment_panel_h #include <FL/Fl.H> +#include "fluid.h" +#include "widget_browser.h" #include <FL/Fl_Text_Buffer.H> #include <FL/Fl_Text_Display.H> #include <FL/filename.H> -extern void load_history(); -extern void redraw_browser(); -extern int show_comments; -extern int G_use_external_editor; -extern char G_external_editor_command[512]; -extern int show_coredevmenus; extern struct Fl_Menu_Item *dbmanager_item; -extern Fl_Preferences fluid_prefs; #include <FL/Fl_Double_Window.H> #include <FL/Fl_Preferences.H> #include <FL/Fl_Tooltip.H> diff --git a/fluid/code.cxx b/fluid/code.cxx index 671cbb1a1..005a07d1c 100644 --- a/fluid/code.cxx +++ b/fluid/code.cxx @@ -14,28 +14,37 @@ // https://www.fltk.org/bugs.php // -#include <stdio.h> -#include <stdlib.h> -#include "../src/flstring.h" -#include <stdarg.h> +#include "code.h" + +#include "Fl_Group_Type.h" +#include "Fl_Window_Type.h" +#include "Fl_Function_Type.h" +#include "alignment_panel.h" +#include "file.h" #include <FL/Fl.H> #include <FL/fl_string.h> -#include "Fl_Type.h" -#include "alignment_panel.h" +#include <FL/filename.H> +#include "../src/flstring.h" -static FILE *code_file; -static FILE *header_file; +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +/// \defgroup cfile C Code File Operations +/// \{ -extern char i18n_program[]; -extern int i18n_type; -extern const char* i18n_include; -extern const char* i18n_function; -extern const char* i18n_file; -extern const char* i18n_set; +static FILE *code_file = NULL; +static FILE *header_file = NULL; -// return true if c can be in a C identifier. I needed this so -// it is not messed up by locale settings: +int indentation = 0; +int write_number = 0; +int write_sourceview = 0; + +/** + Return true if c can be in a C identifier. + I needed this so it is not messed up by locale settings. + */ int is_id(char c) { return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; } @@ -59,6 +68,7 @@ id::~id() { static id* id_root; +// TODO: document me const char* unique_id(void* o, const char* type, const char* name, const char* label) { char buffer[128]; char* q = buffer; @@ -93,9 +103,13 @@ const char* unique_id(void* o, const char* type, const char* name, const char* l //////////////////////////////////////////////////////////////// // return current indentation: -static const char* spaces = " "; -int indentation; + +/** + Return a C string that indents code to the current depth. + */ const char* indent() { + static const char* spaces = " "; + int i = indentation; if (i>16) i = 16; return spaces+16-i; } @@ -149,7 +163,9 @@ int write_declare(const char *format, ...) { int varused_test; int varused; -// write an array of C characters (adds a null): +/** + Write an array of C characters (adds a null). + */ void write_cstring(const char *s, int length) { if (varused_test) { varused = 1; @@ -232,10 +248,14 @@ void write_cstring(const char *s, int length) { putc('\"', code_file); } -// write a C string, quoting characters if necessary: +/** + Write a C string, quoting characters if necessary. + */ void write_cstring(const char *s) {write_cstring(s, (int)strlen(s));} -// write an array of C binary data (does not add a null): +/** + Write an array of C binary data (does not add a null). + */ void write_cdata(const char *s, int length) { if (varused_test) { varused = 1; @@ -269,6 +289,7 @@ void write_cdata(const char *s, int length) { putc('}', code_file); } +// TODO: document me void vwrite_c(const char* format, va_list args) { if (varused_test) { varused = 1; @@ -277,6 +298,7 @@ void vwrite_c(const char* format, va_list args) { vfprintf(code_file, format, args); } +// TODO: document me void write_c(const char* format,...) { va_list args; va_start(args, format); @@ -284,7 +306,9 @@ void write_c(const char* format,...) { va_end(args); } -// write code (c) of size (n) to C file, with optional comment (com) w/o trailing space +/** + Write code (c) of size (n) to C file, with optional comment (com) w/o trailing space. + */ void write_cc(const char *indent, int n, const char *c, const char *com) { if (*com) write_c("%s%.*s; %s\n", indent, n, c, com); @@ -292,6 +316,7 @@ void write_cc(const char *indent, int n, const char *c, const char *com) { write_c("%s%.*s;\n", indent, n, c); } +// TODO: document me void write_h(const char* format,...) { if (varused_test) return; va_list args; @@ -300,7 +325,9 @@ void write_h(const char* format,...) { va_end(args); } -// write code (c) of size (n) to H file, with optional comment (com) w/o trailing space +/** + Write code (c) of size (n) to H file, with optional comment (com) w/o trailing space. + */ void write_hc(const char *indent, int n, const char* c, const char *com) { if (*com) write_h("%s%.*s; %s\n", indent, n, c, com); @@ -308,13 +335,10 @@ void write_hc(const char *indent, int n, const char* c, const char *com) { write_h("%s%.*s;\n", indent, n, c); } -#include <FL/filename.H> -int write_number; -int write_sourceview; -extern Fl_Widget_Class_Type *current_widget_class; -// recursively dump code, putting children between the two parts -// of the parent code: +/** + Recursively dump code, putting children between the two parts of the parent code. + */ static Fl_Type* write_code(Fl_Type* p) { if (write_sourceview) { p->code_position = (int)ftell(code_file); @@ -367,11 +391,8 @@ static Fl_Type* write_code(Fl_Type* p) { return q; } -extern const char* header_file_name; -extern Fl_Class_Type *current_class; - - -/** \brief Write the source and header files for the current design. +/** + Write the source and header files for the current design. If the files already exist, they will be overwritten. @@ -625,11 +646,22 @@ int write_strings(const char *sfile) { return fclose(fp); } -//////////////////////////////////////////////////////////////// - -void Fl_Type::write_static() {} -void Fl_Type::write_code1() { - write_h("// Header for %s\n", title()); - write_c("// Code for %s\n", title()); +/** + Write the public/private/protected keywords inside the class. + This avoids repeating these words if the mode is already set. + */ +void write_public(int state) { + if (!current_class && !current_widget_class) return; + if (current_class && current_class->write_public_state == state) return; + if (current_widget_class && current_widget_class->write_public_state == state) return; + if (current_class) current_class->write_public_state = state; + if (current_widget_class) current_widget_class->write_public_state = state; + switch (state) { + case 0: write_h("private:\n"); break; + case 1: write_h("public:\n"); break; + case 2: write_h("protected:\n"); break; + } } -void Fl_Type::write_code2() {} + +/// \} + diff --git a/fluid/code.h b/fluid/code.h new file mode 100644 index 000000000..00c6c8855 --- /dev/null +++ b/fluid/code.h @@ -0,0 +1,44 @@ +// +// Code output routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_CODE_H +#define _FLUID_CODE_H + +#include <FL/fl_attr.h> + +#include <stdarg.h> + +extern int indentation; +extern int write_number; +extern int write_sourceview; + +int is_id(char c); +const char* unique_id(void* o, const char*, const char*, const char*); +extern const char* indent(); +int write_declare(const char *, ...) __fl_attr((__format__ (__printf__, 1, 2))); +void write_cstring(const char *,int length); +void write_cstring(const char *); +void write_cdata(const char *,int length); +void vwrite_c(const char* format, va_list args); +void write_c(const char*, ...) __fl_attr((__format__ (__printf__, 1, 2))); +void write_cc(const char *, int, const char*, const char*); +void write_h(const char*, ...) __fl_attr((__format__ (__printf__, 1, 2))); +void write_hc(const char *, int, const char*, const char*); +int write_code(const char *cfile, const char *hfile); +int write_strings(const char *sfile); +void write_public(int state); // writes pubic:/private: as needed + +#endif // _FLUID_CODE_H diff --git a/fluid/factory.cxx b/fluid/factory.cxx index 803411d3a..d1b1b664d 100644 --- a/fluid/factory.cxx +++ b/fluid/factory.cxx @@ -22,16 +22,20 @@ // https://www.fltk.org/bugs.php // +#include "factory.h" + +#include "fluid.h" +#include "Fl_Window_Type.h" +#include "undo.h" + #include <FL/Fl.H> #include <FL/Fl_Group.H> #include <FL/Fl_Menu_Item.H> #include <FL/Fl_Pixmap.H> #include <FL/Fl_Tree.H> -#include <stdio.h> #include "../src/flstring.h" -#include "undo.h" -#include "Fl_Widget_Type.h" +#include <stdio.h> extern Fl_Pixmap *pixmap[]; @@ -1116,7 +1120,6 @@ void fill_in_New_Menu() { } // use keyword to pick the type, this is used to parse files: -int reading_file; Fl_Type *Fl_Type_make(const char *tn) { reading_file = 1; // makes labels be null Fl_Type *r = 0; diff --git a/fluid/factory.h b/fluid/factory.h new file mode 100644 index 000000000..aaed57b20 --- /dev/null +++ b/fluid/factory.h @@ -0,0 +1,29 @@ +// +// Widget type header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FACTORY_H +#define _FLUID_FACTORY_H + +struct Fl_Menu_Item; +class Fl_Type; + +extern Fl_Menu_Item New_Menu[]; + +void fill_in_New_Menu(); +Fl_Type *Fl_Type_make(const char *tn); + + +#endif // _FLUID_FACTORY_H diff --git a/fluid/file.cxx b/fluid/file.cxx index 30335a232..1e67ce4c8 100644 --- a/fluid/file.cxx +++ b/fluid/file.cxx @@ -19,21 +19,55 @@ // https://www.fltk.org/bugs.php // -#include <stdio.h> -#include <stdlib.h> -#include "../src/flstring.h" -#include <stdarg.h> +#include "file.h" + +#include "fluid.h" +#include "factory.h" +#include "Fl_Function_Type.h" +#include "Fl_Widget_Type.h" +#include "Fl_Window_Type.h" #include "alignment_panel.h" +#include "widget_browser.h" +#include "code.h" + #include <FL/Fl.H> +#include <FL/Fl_Group.H> #include <FL/fl_string.h> -#include "Fl_Widget_Type.h" +#include <FL/fl_message.H> +#include "../src/flstring.h" -//////////////////////////////////////////////////////////////// -// BASIC FILE WRITING: +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +/// \defgroup flfile .fl Design File Operations +/// \{ + +// This file contains code to read and write .fl file. +// TODO: there is a name confusion with routines that write to the C and Header files which must be fixed. static FILE *fout; +static FILE *fin; + +static int needspace; +static int lineno; +static const char *fname; + +int fdesign_flip; +int fdesign_magic; + +double read_version; + +//////////////////////////////////////////////////////////////// +// BASIC FILE WRITING: -int open_write(const char *s) { +/** + Open teh .fl design file for writing. + If the filename is NULL, associate stdout instead. + \param[in] s the filename or NULL for stdout + \return 1 if successful. 0 if the operation failed + */ +static int open_write(const char *s) { if (!s) {fout = stdout; return 1;} FILE *f = fl_fopen(s,"w"); if (!f) return 0; @@ -41,7 +75,11 @@ int open_write(const char *s) { return 1; } -int close_write() { +/** + Close the .fl desing file. + Don't close, if data was sent to stdout. + */ +static int close_write() { if (fout != stdout) { int x = fclose(fout); fout = stdout; @@ -50,10 +88,9 @@ int close_write() { return 1; } -static int needspace; -int is_id(char); // in code.C - -// write a string, quoting characters if necessary: +/** + Write a string to the .fl file, quoting characters if necessary. + */ void write_word(const char *w) { if (needspace) putc(' ', fout); needspace = 1; @@ -86,9 +123,11 @@ void write_word(const char *w) { putc('}', fout); } -// write an arbitrary formatted word, or a comment, etc. -// if needspace is set, then one space is written before the string -// unless the format starts with a newline character ('\n'): +/** + Write an arbitrary formatted word to the .fl file, or a comment, etc. . + If needspace is set, then one space is written before the string + unless the format starts with a newline character '\\n'. + */ void write_string(const char *format, ...) { va_list args; va_start(args, format); @@ -98,35 +137,43 @@ void write_string(const char *format, ...) { needspace = !isspace(format[strlen(format)-1] & 255); } -// start a new line and indent it for a given nesting level: +/** + Start a new line in the .fl file and indent it for a given nesting level. + */ void write_indent(int n) { fputc('\n',fout); while (n--) {fputc(' ',fout); fputc(' ',fout);} needspace = 0; } -// write a '{' at the given indenting level: +/** + Write a '{' to the .fl file at the given indenting level. + */ void write_open(int) { if (needspace) fputc(' ',fout); fputc('{',fout); needspace = 0; } -// write a '}' at the given indenting level: +/** + Write a '}' to the .fl file at the given indenting level. + */ void write_close(int n) { if (needspace) write_indent(n); fputc('}',fout); needspace = 1; } + //////////////////////////////////////////////////////////////// // BASIC FILE READING: -static FILE *fin; -static int lineno; -static const char *fname; - -int open_read(const char *s) { +/** + Open an .fl file for reading. + \param[in] s filename, if NULL, read from stdin instead + \return 0 if the operation failed, 1 if it succeeded + */ +static int open_read(const char *s) { lineno = 1; if (!s) {fin = stdin; fname = "stdin"; return 1;} FILE *f = fl_fopen(s,"r"); @@ -136,7 +183,11 @@ int open_read(const char *s) { return 1; } -int close_read() { +/** + Close the .fl file. + \return 0 if the operation failed, 1 if it succeeded + */ +static int close_read() { if (fin != stdin) { int x = fclose(fin); fin = 0; @@ -145,8 +196,12 @@ int close_read() { return 1; } -#include <FL/fl_message.H> - +/** + Display an error while reading the file. + If the .fl file isn't opened for reading, pop up an FLTK dialog, otherwise + print to stdout. + \note Matt: I am not sure why it is done this way. Shouldn;t this depend on \c batch_mode? + */ void read_error(const char *format, ...) { va_list args; va_start(args, format); @@ -162,6 +217,9 @@ void read_error(const char *format, ...) { va_end(args); } +/** + Convert a single ASCII char, assumed to be a hex digit, into its decimal value. + */ static int hexdigit(int x) { if (isdigit(x)) return x-'0'; if (isupper(x)) return x-'A'+10; @@ -169,7 +227,11 @@ static int hexdigit(int x) { return 20; } - +/** + Convert an ASCII sequence form the .fl file that starts with a \\ into a single character. + Conversion includes the common C style \\ characters like \\n, \x## hex + values, and \o### octal values. + */ static int read_quoted() { // read whatever character is after a \ . int c,d,x; switch(c = fgetc(fin)) { @@ -203,16 +265,13 @@ static int read_quoted() { // read whatever character is after a \ . return(c); } -// return a word read from the file, or NULL at the EOF: -// This will skip all comments (# to end of line), and evaluate -// all \xxx sequences and use \ at the end of line to remove the newline. -// A word is any one of: -// a continuous string of non-space chars except { and } and # -// everything between matching {...} (unless wantbrace != 0) -// the characters '{' and '}' - static char *buffer; static int buflen; + +/** + A simple growing buffer. + Oh how I wish sometimes we would upgrade to moder C++. + */ static void expand_buffer(int length) { if (length >= buflen) { if (!buflen) { @@ -226,6 +285,17 @@ static void expand_buffer(int length) { } } +/** + Return a word read from the .fl file, or NULL at the EOF. + + This will skip all comments (# to end of line), and evaluate + all \\xxx sequences and use \\ at the end of line to remove the newline. + + A word is any one of: + - a continuous string of non-space chars except { and } and # + - everything between matching {...} (unless wantbrace != 0) + - the characters '{' and '}' + */ const char *read_word(int wantbrace) { int x; @@ -295,19 +365,12 @@ const char *read_word(int wantbrace) { //////////////////////////////////////////////////////////////// -// global int variables: -extern int i18n_type; -extern const char* i18n_include; -extern const char* i18n_function; -extern const char* i18n_file; -extern const char* i18n_set; - - -extern int header_file_set; -extern int code_file_set; -extern const char* header_file_name; -extern const char* code_file_name; - +/** + Write an .fl design description file. + \param[in] filename create this file, and if it exists, overwrite it + \param[in] selected_only write only the selected nodes in the widget_tree. This + is used to implement copy and paste. + */ int write_file(const char *filename, int selected_only) { if (!open_write(filename)) return 0; write_string("# data file for the Fltk User Interface Designer (fluid)\n" @@ -349,12 +412,9 @@ int write_file(const char *filename, int selected_only) { //////////////////////////////////////////////////////////////// // read all the objects out of the input file: -void read_fdesign(); - -double read_version; - -extern Fl_Type *Fl_Type_make(const char *tn); - +/** + Read child node in the .fl design file. + */ static void read_children(Fl_Type *p, int paste) { Fl_Type::current = p; for (;;) { @@ -491,8 +551,12 @@ static void read_children(Fl_Type *p, int paste) { } } -extern void deselect(); - +/** + Read a .fl design file. + \param[in] filename read this file + \param[in] merge if this is set, merge the file into an existing design + \return 0 if the operation failed, 1 if it succeeded + */ int read_file(const char *filename, int merge) { Fl_Type *o; read_version = 0.0; @@ -512,8 +576,7 @@ int read_file(const char *filename, int merge) { //////////////////////////////////////////////////////////////// // Read Forms and XForms fdesign files: -int read_fdesign_line(const char*& name, const char*& value) { - +static int read_fdesign_line(const char*& name, const char*& value) { int length = 0; int x; // find a colon: @@ -550,10 +613,6 @@ int read_fdesign_line(const char*& name, const char*& value) { return 1; } -int fdesign_flip; -int fdesign_magic; -#include <FL/Fl_Group.H> - static const char *class_matcher[] = { "FL_CHECKBUTTON", "Fl_Check_Button", "FL_ROUNDBUTTON", "Fl_Round_Button", @@ -585,6 +644,13 @@ static const char *class_matcher[] = { "24","Fl_Value_Slider", 0}; +/** + Read a XForms design file. + .fl and .fd file start with the same header. Fluid can recognize .fd XForms + Design files by a magic number. It will read them and map XForms widgets onto + FLTK widgets. + \see http://xforms-toolkit.org + */ void read_fdesign() { fdesign_magic = atoi(read_word()); fdesign_flip = (fdesign_magic < 13000); @@ -639,3 +705,6 @@ void read_fdesign() { } } } + +/// \} + diff --git a/fluid/file.h b/fluid/file.h new file mode 100644 index 000000000..18b96492e --- /dev/null +++ b/fluid/file.h @@ -0,0 +1,40 @@ +// +// Fluid file routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FILE_H +#define _FLUID_FILE_H + +#include <FL/fl_attr.h> + +extern double read_version; +extern int fdesign_flip; +extern int fdesign_magic; + +void write_word(const char *); +void write_string(const char *,...) __fl_attr((__format__ (__printf__, 1, 2))); +void write_indent(int n); +void write_open(int); +void write_close(int n); + +void read_error(const char *format, ...); +const char *read_word(int wantbrace = 0); + +int write_file(const char *, int selected_only = 0); + +int read_file(const char *, int merge); +void read_fdesign(); + +#endif // _FLUID_FILE_H diff --git a/fluid/fluid.cxx b/fluid/fluid.cxx index 700c81d63..0779e600d 100644 --- a/fluid/fluid.cxx +++ b/fluid/fluid.cxx @@ -14,56 +14,37 @@ // https://www.fltk.org/bugs.php // +#include "fluid.h" + +#include "Fl_Type.h" +#include "Fl_Function_Type.h" +#include "Fl_Group_Type.h" +#include "Fl_Window_Type.h" +#include "widget_browser.h" +#include "shell_command.h" +#include "factory.h" +#include "pixmaps.h" +#include "undo.h" +#include "file.h" +#include "code.h" + +#include "alignment_panel.h" +#include "function_panel.h" +#include "template_panel.h" +#include "about_panel.h" + #include <FL/Fl.H> #ifdef __APPLE__ #include <FL/platform.H> // for fl_open_callback #endif -#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_Plugin.H> -#include <FL/fl_ask.H> -#include <FL/fl_draw.H> -#include <FL/Fl_File_Chooser.H> #include <FL/Fl_PNG_Image.H> -#include <FL/fl_message.H> -#include <FL/filename.H> #include <FL/Fl_Native_File_Chooser.H> #include <FL/Fl_Printer.H> -#include <FL/fl_utf8.h> #include <FL/fl_string.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> #include <locale.h> // setlocale().. -#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 <direct.h> -# include <windows.h> -# include <io.h> -# include <fcntl.h> -# include <commdlg.h> -# include <FL/platform.H> -#else -# include <unistd.h> -#endif - -#include "pixmaps.h" -#include "about_panel.h" -#include "undo.h" - -#include "Fl_Type.h" extern "C" { @@ -77,46 +58,160 @@ extern "C" #endif // HAVE_LIBPNG && HAVE_LIBZ } +/// \defgroup globals Fluid Global Variables, Functions and Calbacks +/// \{ + // // Globals.. // + +/// Fluid-wide help dialog. static Fl_Help_Dialog *help_dialog = 0; +Fl_Menu_Bar *main_menubar = NULL; +Fl_Window *main_window; + +/// Fluid application preferences, allways accessible, will be flushed when app closes. Fl_Preferences fluid_prefs(Fl_Preferences::USER, "fltk.org", "fluid"); + +/// Align widget position and size when designing, saved in app preferences and project file. int gridx = 5; + +/// Align widget position and size when designing, saved in app preferences and project file. int gridy = 5; + +/// Activate snapping to grid, saved in app preferences and project file. int snap = 1; + +/// Show guides in the design window when positioning widgets, saved in app preferences. int show_guides = 1; + +/// Show widget comments in the browser, saved in app preferences. int show_comments = 1; + +/// Use external editor for editing Fl_Code_Type, saved in app preferences. int G_use_external_editor = 0; + +/// Debugging help for external Fl_Code_Type editor. int G_debug = 0; + +/// Run this command to load an Fl_Code_Type into an external editor, save in app preferences. char G_external_editor_command[512]; -int show_coredevmenus = 1; + + +/// \todo Functionality unclear. +int force_parent = 0; + +/// This is set to create different labels when creating new widgets. +/// \todo Details unclear. +int reading_file = 0; + // File history info... + +/// Stores the absolute filename of the last 10 design files, saved in app preferences. char absolute_history[10][FL_PATH_MAX]; + +/// This list of filenames is computed from \c absolute_history and displayed in the main menu. char relative_history[10][FL_PATH_MAX]; -void load_history(); -void update_history(const char *); +/// Menuitem to save a .fl design file, will be deactivated if the design is unchanged. +Fl_Menu_Item *save_item = NULL; -// Shell command support... -void show_shell_window(); +/// First Menuitem that shows the .fl design file hisory. +Fl_Menu_Item *history_item = NULL; -Fl_Menu_Item *save_item = 0L; -Fl_Menu_Item *history_item = 0L; -Fl_Menu_Item *widgetbin_item = 0L; -Fl_Menu_Item *sourceview_item = 0L; +/// Menuitem to show or hide the widget bin, label will change if bin is visible. +Fl_Menu_Item *widgetbin_item = NULL; + +/// Menuitem to show or hide the source view, label will change if view is visible. +Fl_Menu_Item *sourceview_item = NULL; //////////////////////////////////////////////////////////////// -static const char *filename; -void set_filename(const char *c); -void set_modflag(int mf); -int modflag; +/// Filename of the current .fl design file +static const char *filename = NULL; + +/// Set if the current design has been modified compared to the associated .fl design file. +int modflag = 0; + +/// Application work directory, stored here when temporarily changing to the source code directory. +/// \see goto_source_dir() +static char* pwd = NULL; + +/// Set, if the current working directory is in the source code folder vs. the app working space. +/// \see goto_source_dir() +static char in_source_dir = 0; + +/// Set, if Fluid was started with the command line argument -u +int update_file = 0; // fluid -u + +/// Set, if Fluid was started with the command line argument -c +int compile_file = 0; // fluid -c + +/// Set, if Fluid was started with the command line argument -cs +int compile_strings = 0; // fluic -cs + +/// Set, if Fluid runs in batch mode, and no user interface is activated. +int batch_mode = 0; // if set (-c, -u) don't open display + +/// If set, commandline overrides header file name in .fl file. +int header_file_set = 0; + +/// If set, commandline overrides source code file name in .fl file. +int code_file_set = 0; + +/// Hold the default extension for header files, or the entire filename if set via command line. +const char* header_file_name = ".h"; + +/// Hold the default extension for source code files, or the entire filename if set via command line. +const char* code_file_name = ".cxx"; + + +/// Saved in the .fl design file. +/// \todo document me +int i18n_type = 0; + +/// Saved in the .fl design file. +/// \todo document me +const char* i18n_include = ""; + +/// Saved in the .fl design file. +/// \todo document me +const char* i18n_function = ""; + +/// Saved in the .fl design file. +/// \todo document me +const char* i18n_file = ""; + +/// Saved in the .fl design file. +/// \todo document me +const char* i18n_set = ""; + +/// \todo document me +char i18n_program[FL_PATH_MAX] = ""; + +/// \todo document me +int pasteoffset = 0; + +/// \todo document me +static int ipasteoffset = 0; -static char* pwd; -static char in_source_dir; + +// ---- Sourceview definition + +void update_sourceview_position(); +void update_sourceview_position_cb(Fl_Tabs*, void*); +void update_sourceview_cb(Fl_Button*, void*); +void update_sourceview_timer(void*); + +// ---- + +/** + Change the current working directory to the source code folder. + Remember the the previous directory, so \c leave_source_dir() can return there. + \see leave_source_dir(), pwd, in_source_dir + */ void goto_source_dir() { if (in_source_dir) return; if (!filename || !*filename) return; @@ -136,6 +231,10 @@ void goto_source_dir() { in_source_dir = 1; } +/** + Change the current working directory to its previous directory. + \see goto_source_dir(), pwd, in_source_dir + */ void leave_source_dir() { if (!in_source_dir) return; if (fl_chdir(pwd) < 0) { @@ -144,6 +243,17 @@ void leave_source_dir() { in_source_dir = 0; } +/** + Position the given window window based on entries in the app preferences. + Customizable by user; feature can be switched off. + The window is not shown or hidden by this function, but a value is returned + to indicate the state to the caller. + \param[in] w position this window + \param[in] prefsName name of the preferences item that stores the window settings + \param[in] Visible default value if window is hidden or shown + \param[in] X, Y, W, H default size and position if nothing is specified in the preferences + \return 1 if the caller should make the window visible, 0 if hidden. + */ 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()) { @@ -161,6 +271,11 @@ char position_window(Fl_Window *w, const char *prefsName, int Visible, int X, in return Visible; } +/** + Save the position and visibility state of a window to the app preferences. + \param[in] w save this window data + \param[in] prefsName name of the preferences item that stores the window settings + */ void save_position(Fl_Window *w, const char *prefsName) { Fl_Preferences pos(fluid_prefs, prefsName); pos.set("x", w->x()); @@ -170,9 +285,11 @@ void save_position(Fl_Window *w, const char *prefsName) { pos.set("visible", (int)(w->shown() && w->visible())); } -Fl_Window *main_window; -Fl_Menu_Bar *main_menubar; - +/** + Return the path and filename of a temporary file for cut or duplicated data. + \param[in] which 0 gets the cut/copy/paste buffer, 1 gets the duplication buffer + \return a pointer to a string in a static buffer + */ static char* cutfname(int which = 0) { static char name[2][FL_PATH_MAX]; static char beenhere = 0; @@ -188,10 +305,13 @@ static char* cutfname(int which = 0) { return name[which]; } -// Timer to watch for external editor modifications -// If one or more external editors open, check if their files were modified. -// If so: reload to ram, update size/mtime records, and change fluid's 'modified' state. -// +/** + Timer to watch for external editor modifications. + + If one or more external editors open, check if their files were modified. + If so: reload to ram, update size/mtime records, and change fluid's + 'modified' state. + */ static void external_editor_timer(void*) { int editors_open = ExternalCodeEditor::editors_open(); if ( G_debug ) printf("--- TIMER --- External editors open=%d\n", editors_open); @@ -223,6 +343,12 @@ static void external_editor_timer(void*) { } } +/** + Save the current design to the file given by \c filename. + If automatic, this overwrites an existing file. If iinteractive, if will + verify with the user. + \param[in] v if v is not NULL, or no filename is set, open a filechooser. + */ void save_cb(Fl_Widget *, void *v) { Fl_Native_File_Chooser fnfc; const char *c = filename; @@ -261,6 +387,10 @@ void save_cb(Fl_Widget *, void *v) { } } +/** + Save a design template. + \todo We should document the concept of templates. + */ void save_template_cb(Fl_Widget *, void *) { // Setup the template panel... if (!template_panel) make_template_panel(); @@ -367,6 +497,10 @@ void save_template_cb(Fl_Widget *, void *) { #endif // HAVE_LIBPNG && HAVE_LIBZ } +/** + Reload the file set by \c filename, replacing the current design. + If the design was modified, a dialog will ask for confirmation. + */ void revert_cb(Fl_Widget *,void *) { if (modflag) { if (!fl_choice("This user interface has been changed. Really revert?", @@ -383,6 +517,10 @@ void revert_cb(Fl_Widget *,void *) { undo_clear(); } +/** + Exit Fluid; we hope you had a nice experience. + If the design was modified, a dialog will ask for confirmation. + */ void exit_cb(Fl_Widget *,void *) { // Stop any external editor update timers @@ -433,8 +571,12 @@ void exit_cb(Fl_Widget *,void *) { #ifdef __APPLE__ -void -apple_open_cb(const char *c) { +/** + Handle app launch with an associated filename (macOS only). + Should there be a modified design already, Fluid asks for user confirmation. + \param[in] c the filename of the new design + */ +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", @@ -469,6 +611,11 @@ apple_open_cb(const char *c) { } #endif // __APPLE__ +/** + Open a file chooser and load a new file. + If the current design was modified, Fluid will ask for user confirmation. + \param[in] v if v is set, Fluid will not ask for confirmation. + */ void open_cb(Fl_Widget *, void *v) { if (!v && modflag) { switch (fl_choice("Do you want to save changes to this user\n" @@ -517,6 +664,11 @@ void open_cb(Fl_Widget *, void *v) { } } +/** + Open a file from history. + If the current design was modified, Fluid will ask for user confirmation. + \param[in] v points to the absolute path and filename. + */ void open_history_cb(Fl_Widget *, void *v) { if (modflag) { switch (fl_choice("Do you want to save changes to this user\n" @@ -552,6 +704,11 @@ void open_history_cb(Fl_Widget *, void *v) { } } +/** + Close the current design and create a new, empty one. + If the current design was modified, Fluid will ask for user confirmation. + \param[in] v if v is set, don't ask for confirmation + */ void new_cb(Fl_Widget *, void *v) { // Check if the current file has been modified... if (!v && modflag) { @@ -573,6 +730,12 @@ void new_cb(Fl_Widget *, void *v) { set_filename(NULL); } +/** + Open the template browser and load a new file from templates. + If the current design was modified, Fluid will ask for user confirmation. + \param[in] w widget that caused this request, unused + \param[in] v if v is set, don't ask for confirmation + */ void new_from_template_cb(Fl_Widget *w, void *v) { new_cb(w, v); @@ -668,26 +831,11 @@ void new_from_template_cb(Fl_Widget *w, void *v) { undo_clear(); } -int exit_early = 0; -int update_file = 0; // fluid -u -int compile_file = 0; // fluid -c -int compile_strings = 0; // fluic -cs -int batch_mode = 0; // if set (-c, -u) don't open display -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[FL_PATH_MAX] = ""; - -/** \brief Generate the C++ source and header filenames and write those files. +/** + Generate the C++ source and header filenames and write those files. This function creates the source filename by setting the file - extension to \c code_file_name and a header filename + extension to \c code_file_name and a header filename with the extension \c code_file_name which are both settable by the user. @@ -737,10 +885,16 @@ int write_code_files() { return 0; } +/** + Callback to write C++ code and header files. + */ void write_cb(Fl_Widget *, void *) { write_code_files(); } +/** + Write the strings that are used in i18n. + */ void write_strings_cb(Fl_Widget *, void *) { static const char *exts[] = { ".txt", ".po", ".msg" }; if (!filename) { @@ -764,6 +918,9 @@ void write_strings_cb(Fl_Widget *, void *) { } } +/** + 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"); @@ -772,18 +929,9 @@ void openwidget_cb(Fl_Widget *, void *) { 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; - +/** + User chose to copy the currently selected widgets. + */ void copy_cb(Fl_Widget*, void*) { if (!Fl_Type::current) { fl_beep(); @@ -796,7 +944,9 @@ void copy_cb(Fl_Widget*, void*) { } } -extern void select_only(Fl_Type *); +/** + User chose to cut the currently selected widgets. + */ void cut_cb(Fl_Widget *, void *) { if (!Fl_Type::current) { fl_beep(); @@ -813,8 +963,12 @@ void cut_cb(Fl_Widget *, void *) { while (p && p->selected) p = p->parent; delete_all(1); if (p) select_only(p); + //widget_browser->redraw_lines(); } +/** + User chose to delete the currently selected widgets. + */ void delete_cb(Fl_Widget *, void *) { if (!Fl_Type::current) { fl_beep(); @@ -829,8 +983,9 @@ void delete_cb(Fl_Widget *, void *) { if (p) select_only(p); } -extern int force_parent; - +/** + User chose to paste the widgets from the cut buffer. + */ void paste_cb(Fl_Widget*, void*) { //if (ipasteoffset) force_parent = 1; pasteoffset = ipasteoffset; @@ -847,7 +1002,9 @@ void paste_cb(Fl_Widget*, void*) { force_parent = 0; } -// Duplicate the selected widgets... +/** + Duplicate the selected widgets. + */ void duplicate_cb(Fl_Widget*, void*) { if (!Fl_Type::current) { fl_beep(); @@ -873,29 +1030,25 @@ void duplicate_cb(Fl_Widget*, void*) { force_parent = 0; } -void earlier_cb(Fl_Widget*,void*); - -void later_cb(Fl_Widget*,void*); - -Fl_Type *sort(Fl_Type *parent); - +/** + User wants to sort selected widgets by y coordinate. + */ static void sort_cb(Fl_Widget *,void *) { - sort((Fl_Type*)0); + sort((Fl_Type*)NULL); } -void show_project_cb(Fl_Widget *, void *); -void show_grid_cb(Fl_Widget *, void *); -void show_settings_cb(Fl_Widget *, void *); -void show_global_settings_cb(Fl_Widget *, void *); - -void align_widget_cb(Fl_Widget *, long); -void widget_size_cb(Fl_Widget *, long); - +/** + 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]; @@ -960,16 +1113,25 @@ void show_help(const char *name) { 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; @@ -1036,13 +1198,23 @@ void print_menu_cb(Fl_Widget *, void *) { printjob.end_job(); } -//////////////////////////////////////////////////////////////// +// ---- Main menu bar + +/** + This is the main Fluid menu. -extern Fl_Menu_Item New_Menu[]; + Design history is manipulated right inside this menu structure. + Some menuitem change or deactivate correctly, but most items just trigger + various callbacks. -void toggle_widgetbin_cb(Fl_Widget *, void *); -void toggle_sourceview_cb(Fl_Double_Window *, void *); + \c New_Menu creates new widgets and is explained in detail in another location. + \see New_Menu + \todo This menu need some major modernisation. Menus are too long and their + sorting is not always obvious. + \todo Shortcuts are all over the palce (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', new_cb, 0}, @@ -1136,14 +1308,10 @@ Fl_Menu_Item Main_Menu[] = { {0}, {0}}; -#define BROWSERWIDTH 300 -#define BROWSERHEIGHT 500 -#define WINWIDTH 300 -#define MENUHEIGHT 25 -#define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT) - -extern void fill_in_New_Menu(); - +/** + Change the app's and hence preview the design's scheme. + The scheme setting is stored inthe app preferences. + */ void scheme_cb(Fl_Choice *, void *) { if (batch_mode) return; @@ -1169,6 +1337,10 @@ void scheme_cb(Fl_Choice *, void *) { fluid_prefs.set("scheme", scheme_choice->value()); } +/** + 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(); @@ -1184,7 +1356,10 @@ void toggle_widgetbin_cb(Fl_Widget *, void *) { } } - +/** + Show or hide the source code preview. + The state is stored in the app preferences. + */ void toggle_sourceview_cb(Fl_Double_Window *, void *) { if (!sourceview_panel) { make_sourceview(); @@ -1212,10 +1387,17 @@ void toggle_sourceview_cb(Fl_Double_Window *, void *) { } } +/** + Show or hide the source code preview, called from a button. + The state is stored in the app preferences. + */ void toggle_sourceview_b_cb(Fl_Button*, void *) { toggle_sourceview_cb(0,0); } +/** + Build the main app window and create a few other dialogs. + */ void make_main_window() { if (!batch_mode) { fluid_prefs.get("snap", snap, 1); @@ -1256,7 +1438,13 @@ void make_main_window() { } } -// Load file history from preferences... +/** + 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; @@ -1283,7 +1471,15 @@ void load_history() { } } -// Update file history from preferences... +/** + 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]; @@ -1335,243 +1531,72 @@ void update_history(const char *flname) { fluid_prefs.flush(); } -// ********** portable process class definition ********** - -class Fl_Process { -public: - // construction / destruction - Fl_Process() {_fpt= NULL;} - ~Fl_Process() {if (_fpt) close();} - - // FIXME: popen needs the UTF-8 equivalent fl_popen - FILE * popen (const char *cmd, const char *mode="r"); - //not necessary here: FILE * fl_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, (int)s, _fpt) : NULL;} - - // returns fileno(FILE*): - // (file must be open, i.e. _fpt must be non-null) - // *FIXME* we should find a better solution for the 'fileno' issue - int get_fileno() const { -#ifdef _MSC_VER - return _fileno(_fpt); // suppress MSVC warning -#else - return fileno(_fpt); -#endif - } // non null if file is open - -#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((fl_intptr_t) 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()) { - write_code_files(); - } - if (shell_writemsgs_button->value()) { - write_strings_cb(0, 0); - } - return true; -} +/** + 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; -// Support the full piped shell command... -void -shell_pipe_cb(FL_SOCKET, void*) { - char line[1024]=""; // Line from command output... + if (filename && !batch_mode) + update_history(filename); - if (s_proc.get_line(line, sizeof(line)) != NULL) { - // Add the line to the output list... - shell_run_terminal->append(line); - } else { - // End of file; tell the parent... - Fl::remove_fd(s_proc.get_fileno()); - s_proc.close(); - shell_run_terminal->append("... END SHELL COMMAND ...\n"); - } + set_modflag(modflag); } -void -do_shell_command(Fl_Return_Button*, void*) { - const char *command=NULL; // Command to run +/** + Set the "modified" flag and update the title of the main window. + \param[in] mf 0 to clear the modflag, 1 to mark the design "modified" + */ +void set_modflag(int mf) { + const char *basename; + static char title[FL_PATH_MAX]; - if (!prepare_shell_command(command)) return; + modflag = mf; - // Show the output window and clear things... - shell_run_terminal->text(""); - shell_run_terminal->append(command); - shell_run_terminal->append("\n"); - shell_run_window->label("Shell Command Running..."); + if (main_window) { + if (!filename) basename = "Untitled.fl"; + else if ((basename = strrchr(filename, '/')) != NULL) basename ++; +#if defined(_WIN32) + else if ((basename = strrchr(filename, '\\')) != NULL) basename ++; +#endif // _WIN32 + else basename = filename; - if (s_proc.popen((char *)command) == NULL) { - fl_alert("Unable to run shell command: %s", strerror(errno)); - return; + if (modflag) { + snprintf(title, sizeof(title), "%s (modified)", basename); + main_window->label(title); + } else main_window->label(basename); } - - shell_run_button->deactivate(); - - Fl_Preferences pos(fluid_prefs, "shell_run_Window_pos"); - int x, y, w, h; - pos.get("x", x, -1); - pos.get("y", y, 0); - pos.get("w", w, 640); - pos.get("h", h, 480); - if (x!=-1) { - shell_run_window->resize(x, y, w, h); + // 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 earliest 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); } - shell_run_window->show(); - Fl::add_fd(s_proc.get_fileno(), 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(); + // Enable/disable the Save menu item... + if (modflag) save_item->activate(); + else save_item->deactivate(); } -void -show_shell_window() { - shell_window->hotspot(shell_command_input); - shell_window->show(); -} +// ---- Sourceview implementation -void set_filename(const char *c) { - if (filename) free((void *)filename); - filename = c ? fl_strdup(c) : NULL; +static char *sv_source_filename = NULL; +static char *sv_header_filename = NULL; - if (filename && !batch_mode) - update_history(filename); - - set_modflag(modflag); -} +/** + Update the header and source code highlighting depending on the + currently selected object -// -// 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. -// - -// -// Update the header and source code highlighting depending on the -// currently selected object -// + 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. + */ void update_sourceview_position() { if (!sourceview_panel || !sourceview_panel->visible()) @@ -1605,18 +1630,18 @@ void update_sourceview_position() } } +/** + Callback to update the sourceview position. + */ 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. -// +/** + 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()) @@ -1662,48 +1687,23 @@ void update_sourceview_cb(Fl_Button*, void*) header_file_name = header_file_name_bak; } +/** + This is called by the timer itself + */ 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[FL_PATH_MAX]; - - modflag = mf; - - if (main_window) { - if (!filename) basename = "Untitled.fl"; - else if ((basename = strrchr(filename, '/')) != NULL) basename ++; -#if defined(_WIN32) - else if ((basename = strrchr(filename, '\\')) != NULL) basename ++; -#endif // _WIN32 - 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 earliest 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) save_item->activate(); - else save_item->deactivate(); -} - -//////////////////////////////////////////////////////////////// +// ---- 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][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;} @@ -1721,13 +1721,6 @@ static int arg(int argc, char** argv, int& i) { i += 2; return 2; } - Fl_Plugin_Manager pm("commandline"); - int j, n = pm.plugins(); - for (j=0; j<n; j++) { - Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(j); - int r = pi->arg(argc, argv, i); - if (r) return r; - } return 0; } @@ -1751,8 +1744,27 @@ static void sigint(SIGARG) { 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 diplay 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 MSWindows, 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; @@ -1768,30 +1780,13 @@ int main(int argc,char **argv) { " -o <name> : .cxx output filename, or extension if <name> starts with '.'\n" " -h <name> : .h output filename, or extension if <name> starts with '.'\n" " -d : enable internal debugging\n"; - int len = (int)(strlen(msg) + strlen(argv[0]?argv[0]:"fluid") + strlen(Fl::help)); - Fl_Plugin_Manager pm("commandline"); - int i, n = pm.plugins(); - for (i=0; i<n; i++) { - Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(i); - if (pi) len += (int)strlen(pi->help()); - } - char *buf = (char*)malloc(len+1); - sprintf(buf, msg, argv[0]); - for (i=0; i<n; i++) { - Fl_Commandline_Plugin *pi = (Fl_Commandline_Plugin*)pm.plugin(i); - if (pi) strcat(buf, pi->help()); - } - strcat(buf, Fl::help); #ifdef _MSC_VER - fl_message("%s\n", buf); + fl_message("%s\n", msg); #else - fprintf(stderr, "%s\n", buf); + fprintf(stderr, "%s\n", msg); #endif - free(buf); return 1; } - if (exit_early) - exit(0); const char *c = argv[i]; @@ -1799,7 +1794,6 @@ int main(int argc,char **argv) { make_main_window(); - if (c) set_filename(c); if (!batch_mode) { #ifdef __APPLE__ @@ -1862,3 +1856,6 @@ int main(int argc,char **argv) { return (0); } + +/// \} + diff --git a/fluid/fluid.h b/fluid/fluid.h new file mode 100644 index 000000000..e2370359f --- /dev/null +++ b/fluid/fluid.h @@ -0,0 +1,118 @@ +// +// FLUID main entry for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FLUID_H +#define _FLUID_FLUID_H + +#include <FL/filename.H> +#include <FL/Fl_Preferences.H> +#include <FL/Fl_Menu_Item.H> + +#define BROWSERWIDTH 300 +#define BROWSERHEIGHT 500 +#define WINWIDTH 300 +#define MENUHEIGHT 25 +#define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT) + +class Fl_Double_Window; +class Fl_Window; +class Fl_Menu_Bar; +class Fl_Type; +class Fl_Choice; +class Fl_Button; + +extern int force_parent; + +extern Fl_Preferences fluid_prefs; +extern Fl_Menu_Item Main_Menu[]; +extern Fl_Menu_Bar *main_menubar; +extern Fl_Window *main_window; + +extern int gridx; +extern int gridy; +extern int snap; +extern int show_guides; +extern int show_comments; + +extern int G_use_external_editor; +extern int G_debug; +extern char G_external_editor_command[512]; + +extern int reading_file; + +// File history info... +extern char absolute_history[10][FL_PATH_MAX]; +extern char relative_history[10][FL_PATH_MAX]; +extern void load_history(); +extern void update_history(const char *); + +extern Fl_Menu_Item *save_item; +extern Fl_Menu_Item *history_item; +extern Fl_Menu_Item *widgetbin_item; +extern Fl_Menu_Item *sourceview_item; + +extern int modflag; + +extern void goto_source_dir(); +extern void leave_source_dir(); + +extern int update_file; // fluid -u +extern int compile_file; // fluid -c +extern int compile_strings; // fluic -cs +extern int batch_mode; + +extern int header_file_set; +extern int code_file_set; +extern const char* header_file_name; +extern const char* code_file_name; + +extern int i18n_type; +extern const char* i18n_include; +extern const char* i18n_function; +extern const char* i18n_file; +extern const char* i18n_set;; +extern char i18n_program[FL_PATH_MAX]; + +extern int pasteoffset; + +// ---- public functions + +extern void set_filename(const char *c); +extern void set_modflag(int mf); + +// ---- public callback functions + +extern void save_cb(Fl_Widget *, void *v); +extern void save_template_cb(Fl_Widget *, void *); +extern void revert_cb(Fl_Widget *,void *); +extern void exit_cb(Fl_Widget *,void *); + +#ifdef __APPLE__ +extern void apple_open_cb(const char *c); +#endif // __APPLE__ + +extern void open_cb(Fl_Widget *, void *v); +extern void open_history_cb(Fl_Widget *, void *v); +extern void new_cb(Fl_Widget *, void *v); +extern void new_from_template_cb(Fl_Widget *w, void *v); + +extern int write_code_files(); +extern void write_strings_cb(Fl_Widget *, void *); +extern void align_widget_cb(Fl_Widget *, long); +extern void widget_size_cb(Fl_Widget *, long); +extern void toggle_widgetbin_cb(Fl_Widget *, void *); + +#endif // _FLUID_FLUID_H diff --git a/fluid/function_panel.cxx b/fluid/function_panel.cxx index e6821be2d..6cb60bcd0 100644 --- a/fluid/function_panel.cxx +++ b/fluid/function_panel.cxx @@ -17,14 +17,12 @@ // generated by Fast Light User Interface Designer (fluid) version 1.0400 #include "function_panel.h" -#include <FL/Fl_Pixmap.H> +#include "fluid.h" +#include "pixmaps.h" +#include "factory.h" #include "Fl_Type.h" +#include "widget_browser.h" #include "undo.h" -extern class Fl_Pixmap *pixmap[]; -extern class Fl_Type *Fl_Type_make(const char*); -extern void select_only(Fl_Type*); -extern void exit_cb(Fl_Widget*, void*); -extern void toggle_widgetbin_cb(Fl_Widget*, void*); /** Allow widget navigation on text fields with Tab. diff --git a/fluid/function_panel.fl b/fluid/function_panel.fl index 6ef30500a..d0750b87d 100644 --- a/fluid/function_panel.fl +++ b/fluid/function_panel.fl @@ -20,28 +20,22 @@ comment {// } {in_source in_header } -decl {\#include <FL/Fl_Pixmap.H>} {private local +decl {\#include "fluid.h"} {private local } -decl {\#include "Fl_Type.h"} {private local -} - -decl {\#include "undo.h"} {private local +decl {\#include "pixmaps.h"} {private local } -decl {extern class Fl_Pixmap *pixmap[];} {private local +decl {\#include "factory.h"} {private local } -decl {extern class Fl_Type *Fl_Type_make(const char*);} {private local -} - -decl {extern void select_only(Fl_Type*);} {private local +decl {\#include "Fl_Type.h"} {private local } -decl {extern void exit_cb(Fl_Widget*, void*);} {private global +decl {\#include "widget_browser.h"} {selected private local } -decl {extern void toggle_widgetbin_cb(Fl_Widget*, void*);} {private global +decl {\#include "undo.h"} {private local } Function {use_tab_navigation(int, Fl_Text_Editor*)} { @@ -50,10 +44,11 @@ Function {use_tab_navigation(int, Fl_Text_Editor*)} { code {return 0;} {} } -Function {make_function_panel()} {} { +Function {make_function_panel()} {open +} { Fl_Window function_panel { - label {Function/Method Properties} open - xywh {557 523 343 232} type Double hide resizable modal + label {Function/Method Properties} + xywh {101 713 343 232} type Double resizable modal visible } { Fl_Group {} {open xywh {10 10 270 20} @@ -131,14 +126,15 @@ Function {make_function_panel()} {} { } } -Function {make_code_panel()} {} { +Function {make_code_panel()} {open +} { Fl_Window code_panel { label {Code Properties} callback {if (Fl::event()==FL_SHORTCUT && Fl::event_key()==FL_Escape) return; // ignore Escape -code_panel->hide(); // otherwise hide..} open - xywh {503 450 540 180} type Double labelsize 11 hide resizable - code0 {o->size_range(200, 150);} modal +code_panel->hide(); // otherwise hide..} + xywh {425 882 540 180} type Double labelsize 11 resizable + code0 {o->size_range(200, 150);} modal visible } { Fl_Text_Editor code_input { xywh {10 10 520 130} box DOWN_BOX labelsize 11 textfont 4 textsize 11 resizable @@ -167,11 +163,12 @@ code_input->linenumber_width(60); code_input->linenumber_size(code_input->Fl_Text_Display::textsize());} {} } -Function {make_codeblock_panel()} {} { +Function {make_codeblock_panel()} {open +} { Fl_Window codeblock_panel { - label {Code Block Properties} open - xywh {468 221 300 115} type Double labelsize 11 hide resizable - code0 {o->size_range(o->w(), o->h(), Fl::w(), o->h());} modal + label {Code Block Properties} + xywh {806 735 300 115} type Double labelsize 11 resizable + code0 {o->size_range(o->w(), o->h(), Fl::w(), o->h());} modal visible } { Fl_Input code_before_input { label {Conditional code block} @@ -199,11 +196,12 @@ Function {make_codeblock_panel()} {} { } } -Function {make_declblock_panel()} {} { +Function {make_declblock_panel()} {open +} { Fl_Window declblock_panel { - label {Declaration Block Properties} open - xywh {428 215 300 135} type Double labelsize 11 hide resizable - code0 {o->size_range(o->w(), o->h(), Fl::w(), o->h());} modal + label {Declaration Block Properties} + xywh {806 564 300 135} type Double labelsize 11 resizable + code0 {o->size_range(o->w(), o->h(), Fl::w(), o->h());} modal visible } { Fl_Group {} {open xywh {10 10 280 20} @@ -255,10 +253,11 @@ Function {make_declblock_panel()} {} { } } -Function {make_decl_panel()} {} { +Function {make_decl_panel()} {open +} { Fl_Window decl_panel { - label {Declaration Properties} open - xywh {480 333 343 237} type Double align 80 hide resizable size_range {343 237 0 0} + label {Declaration Properties} + xywh {445 609 343 237} type Double align 80 resizable size_range {343 237 0 0} visible } { Fl_Group {} {open xywh {10 10 270 20} @@ -331,10 +330,11 @@ Function {make_decl_panel()} {} { } } -Function {make_data_panel()} {} { +Function {make_data_panel()} {open +} { Fl_Window data_panel { - label {Inline Data Properties} open - xywh {472 191 343 237} type Double align 80 hide resizable size_range {343 237 0 0} + label {Inline Data Properties} + xywh {449 337 343 237} type Double align 80 resizable size_range {343 237 0 0} visible } { Fl_Group {} {open xywh {10 10 320 20} @@ -419,10 +419,11 @@ Function {make_data_panel()} {} { } } -Function {make_class_panel()} {} { +Function {make_class_panel()} {open +} { Fl_Window class_panel { - label {Class Properties} open - xywh {497 585 342 196} type Double labelsize 11 hide resizable modal size_range {343 188 0 0} + label {Class Properties} + xywh {795 337 342 196} type Double labelsize 11 resizable modal size_range {343 188 0 0} visible } { Fl_Group {} {open xywh {10 10 280 20} hide @@ -540,8 +541,8 @@ Function {make_widgetbin()} {open callback {if (Fl::event()==FL_SHORTCUT && Fl::event_key()==FL_Escape) exit_cb((Fl_Widget*)o, v); else - toggle_widgetbin_cb((Fl_Widget*)o, v);} open - xywh {445 273 600 102} type Single align 80 non_modal visible + toggle_widgetbin_cb((Fl_Widget*)o, v);} + xywh {449 206 600 102} type Single align 80 non_modal visible } { Fl_Group {} { label Code open @@ -844,7 +845,7 @@ else } Fl_Button {} { user_data {"radiomenuitem"} - callback type_make_cb selected + callback type_make_cb tooltip {Radio Menu Item} xywh {425 71 24 24} box THIN_UP_BOX code0 {o->image(pixmap[55]);} } diff --git a/fluid/print_panel.cxx b/fluid/print_panel.cxx index 6b8c8248f..eae17fee5 100644 --- a/fluid/print_panel.cxx +++ b/fluid/print_panel.cxx @@ -17,12 +17,11 @@ // generated by Fast Light User Interface Designer (fluid) version 1.0400 #include "print_panel.h" -#include <stdio.h> -#include <stdlib.h> -#include "../src/flstring.h" +#include "fluid.h" #include <FL/fl_string.h> -#include <FL/Fl_Preferences.H> -extern Fl_Preferences fluid_prefs; +#include "../src/flstring.h" +#include <stdlib.h> +#include <stdio.h> Fl_Double_Window *print_panel=(Fl_Double_Window *)0; diff --git a/fluid/print_panel.fl b/fluid/print_panel.fl index e2042f531..9119d35a9 100644 --- a/fluid/print_panel.fl +++ b/fluid/print_panel.fl @@ -20,29 +20,26 @@ comment {// } {in_source in_header } -decl {\#include <stdio.h>} {private local +decl {\#include "fluid.h"} {selected private local } -decl {\#include <stdlib.h>} {private local +decl {\#include <FL/fl_string.h>} {private local } decl {\#include "../src/flstring.h"} {private local } -decl {\#include <FL/fl_string.h>} {private local -} - -decl {\#include <FL/Fl_Preferences.H>} {private local +decl {\#include <stdlib.h>} {private local } -decl {extern Fl_Preferences fluid_prefs;} {private local +decl {\#include <stdio.h>} {private local } Function {make_print_panel()} {open } { Fl_Window print_panel { - label Print open - xywh {394 209 465 235} type Double hide modal + label Print + xywh {465 222 465 235} type Double modal visible } { Fl_Group print_panel_controls {open xywh {10 10 447 216} @@ -215,8 +212,8 @@ print_collate_group[1 - i]->hide();} Fl_Window print_properties_panel { label {Printer Properties} callback {print_properties_panel->hide(); -print_update_status();} open - xywh {400 537 290 130} type Double hide modal +print_update_status();} + xywh {462 486 290 130} type Double modal visible } { Fl_Choice print_page_size { label {Page Size:} diff --git a/fluid/shell_command.cxx b/fluid/shell_command.cxx new file mode 100644 index 000000000..7e77d1883 --- /dev/null +++ b/fluid/shell_command.cxx @@ -0,0 +1,234 @@ +// +// FLUID main entry for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#include "shell_command.h" + +#include "fluid.h" +#include "alignment_panel.h" + +#include <FL/Fl_Double_Window.H> +#include <FL/fl_message.H> + +#include <errno.h> + +static Fl_Process s_proc; + +/** \class Fl_Process + \todo Explain. + */ + +Fl_Process::Fl_Process() { + _fpt= NULL; +} + +Fl_Process::~Fl_Process() { + if (_fpt) close(); +} + +// FIXME: popen needs the UTF-8 equivalent fl_popen +// 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((fl_intptr_t) 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 +} + +// non-null if file is open +FILE *Fl_Process::desc() const { + return _fpt; +} + +char *Fl_Process::get_line(char * line, size_t s) const { + return _fpt ? fgets(line, (int)s, _fpt) : NULL; +} + +// returns fileno(FILE*): +// (file must be open, i.e. _fpt must be non-null) +// *FIXME* we should find a better solution for the 'fileno' issue +// non null if file is open +int Fl_Process::get_fileno() const { +#ifdef _MSC_VER + return _fileno(_fpt); // suppress MSVC warning +#else + return fileno(_fpt); +#endif +} + +#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; +} + +FILE *Fl_Process::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 +} + +void Fl_Process::clean_close(HANDLE& h) { + if (h!= INVALID_HANDLE_VALUE) CloseHandle(h); + h = INVALID_HANDLE_VALUE; +} + +#endif + + +// 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()) { + write_code_files(); + } + if (shell_writemsgs_button->value()) { + write_strings_cb(0, 0); + } + return true; +} + +// Support the full piped shell command... +void shell_pipe_cb(FL_SOCKET, 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_terminal->append(line); + } else { + // End of file; tell the parent... + Fl::remove_fd(s_proc.get_fileno()); + s_proc.close(); + shell_run_terminal->append("... END SHELL COMMAND ...\n"); + } +} + +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_terminal->text(""); + shell_run_terminal->append(command); + shell_run_terminal->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(); + + Fl_Preferences pos(fluid_prefs, "shell_run_Window_pos"); + int x, y, w, h; + pos.get("x", x, -1); + pos.get("y", y, 0); + pos.get("w", w, 640); + pos.get("h", h, 480); + if (x!=-1) { + shell_run_window->resize(x, y, w, h); + } + shell_run_window->show(); + + Fl::add_fd(s_proc.get_fileno(), 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(); +} + +/** + Show a dialog box to run an external shell command. + */ +void show_shell_window() { + shell_window->hotspot(shell_command_input); + shell_window->show(); +} + diff --git a/fluid/shell_command.h b/fluid/shell_command.h new file mode 100644 index 000000000..cc86e0662 --- /dev/null +++ b/fluid/shell_command.h @@ -0,0 +1,67 @@ +// +// FLUID main entry for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_SHELL_COMMAND_H +#define _FLUID_SHELL_COMMAND_H + +#include <stdio.h> +#include <stdlib.h> + +#if defined(_WIN32) && !defined(__CYGWIN__) +# include <direct.h> +# include <windows.h> +# include <io.h> +# include <fcntl.h> +# include <commdlg.h> +# include <FL/platform.H> +#else +# include <unistd.h> +#endif + +void show_shell_window(); + +class Fl_Process { +public: + Fl_Process(); + ~Fl_Process(); + + FILE *popen(const char *cmd, const char *mode="r"); + int close(); + + FILE * desc() const; + char * get_line(char * line, size_t s) const; + + int get_fileno() const; + +#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(); + static void clean_close(HANDLE& h); +#endif + +protected: + FILE * _fpt; +}; + +#endif // _FLUID_SHELL_COMMAND_H diff --git a/fluid/template_panel.cxx b/fluid/template_panel.cxx index 18b363f4d..04117ba6c 100644 --- a/fluid/template_panel.cxx +++ b/fluid/template_panel.cxx @@ -17,21 +17,20 @@ // generated by Fast Light User Interface Designer (fluid) version 1.0400 #include "template_panel.h" +#include "fluid.h" +#include <FL/Fl_Shared_Image.H> +#include <FL/fl_ask.H> +#include <FL/fl_string.h> +#include <FL/filename.H> +#include "../src/flstring.h" #include <stdio.h> #include <stdlib.h> -#include "../src/flstring.h" -#include <FL/fl_string.h> #include <errno.h> -#include <FL/filename.H> -#include <FL/fl_ask.H> -#include <FL/Fl_Shared_Image.H> -#include <FL/Fl_Preferences.H> #if defined(_WIN32) && !defined(__CYGWIN__) #include <io.h> #else #include <unistd.h> #endif // _WIN32 && !__CYGWIN__ -extern Fl_Preferences fluid_prefs; Fl_Double_Window *template_panel=(Fl_Double_Window *)0; diff --git a/fluid/template_panel.fl b/fluid/template_panel.fl index b0d5b9ff9..9407a7564 100644 --- a/fluid/template_panel.fl +++ b/fluid/template_panel.fl @@ -20,31 +20,31 @@ comment {// } {in_source in_header } -decl {\#include <stdio.h>} {private local +decl {\#include "fluid.h"} {private local } -decl {\#include <stdlib.h>} {private local +decl {\#include <FL/Fl_Shared_Image.H>} {private local } -decl {\#include "../src/flstring.h"} {private local +decl {\#include <FL/fl_ask.H>} {private local } decl {\#include <FL/fl_string.h>} {private local } -decl {\#include <errno.h>} {private local +decl {\#include <FL/filename.H>} {selected private local } -decl {\#include <FL/filename.H>} {private local +decl {\#include "../src/flstring.h"} {private local } -decl {\#include <FL/fl_ask.H>} {private local +decl {\#include <stdio.h>} {private local } -decl {\#include <FL/Fl_Shared_Image.H>} {private local +decl {\#include <stdlib.h>} {private local } -decl {\#include <FL/Fl_Preferences.H>} {private local +decl {\#include <errno.h>} {private local } declblock {\#if defined(_WIN32) && !defined(__CYGWIN__)} {after {\#endif // _WIN32 && !__CYGWIN__} @@ -57,9 +57,6 @@ declblock {\#if defined(_WIN32) && !defined(__CYGWIN__)} {after {\#endif // _WIN } } -decl {extern Fl_Preferences fluid_prefs;} {private local -} - Function {make_template_panel()} {open } { Fl_Window template_panel { @@ -71,8 +68,8 @@ template_preview->image(0); template_browser->deselect(); template_name->value(""); template_instance->value(""); -template_panel->hide();} open - xywh {398 200 460 355} type Double hide resizable modal +template_panel->hide();} + xywh {455 202 460 355} type Double resizable modal visible } { Fl_Browser template_browser { label {Available Templates:} @@ -207,7 +204,7 @@ template_browser->remove(item); template_browser->do_callback();} {} } -Function {template_load()} {open return_type void +Function {template_load()} {return_type void } { code {int i; char name[1024], filename[1400], path[1024], *ptr; @@ -262,6 +259,5 @@ for (i = 0; i < num_files; i ++) { free(files[i]); } -if (num_files > 0) free(files);} {selected - } +if (num_files > 0) free(files);} {} } diff --git a/fluid/undo.cxx b/fluid/undo.cxx index 1afbb09f0..38d70c2e1 100644 --- a/fluid/undo.cxx +++ b/fluid/undo.cxx @@ -14,10 +14,15 @@ // https://www.fltk.org/bugs.php // -#include <FL/Fl.H> -#include "Fl_Type.h" #include "undo.h" + +#include "fluid.h" +#include "file.h" +#include "Fl_Type.h" + +#include <FL/Fl.H> #include <FL/Fl_Preferences.H> +#include <FL/Fl_Menu_Bar.H> #include <FL/filename.H> #include "../src/flstring.h" @@ -30,12 +35,6 @@ #endif // _WIN32 && !__CYGWIN__ -extern Fl_Preferences fluid_prefs; // FLUID preferences -extern Fl_Menu_Item Main_Menu[]; // Main menu -extern Fl_Menu_Bar *main_menubar; // Main menubar - - - // // This file implements an undo system using temporary files; ideally // we'd like to do this in memory, however the current data structures diff --git a/fluid/undo.h b/fluid/undo.h index c1d1aef44..171fe062f 100644 --- a/fluid/undo.h +++ b/fluid/undo.h @@ -15,7 +15,9 @@ // #ifndef undo_h -# define undo_h +#define undo_h + +class Fl_Widget; extern int undo_current; // Current undo level in buffer extern int undo_last; // Last undo level in buffer diff --git a/fluid/widget_browser.cxx b/fluid/widget_browser.cxx new file mode 100644 index 000000000..6d4d1028a --- /dev/null +++ b/fluid/widget_browser.cxx @@ -0,0 +1,507 @@ +// +// Widget Browser code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#include "widget_browser.h" + +#include "fluid.h" +#include "Fl_Widget_Type.h" +#include "pixmaps.h" + +#include <FL/Fl.H> +#include <FL/Fl_Browser_.H> +#include <FL/fl_draw.H> + +/** + \class Widget_Browser + + A widget that displays the nodes in the widget tree. + + The Widget Browser is derived from the FLTK basic browser, extending + tree browsing functionality by using the \c depth component of the double + linked list of \c Fl_Type items. + + \see Fl_Type + */ + +// ---- global variables + +/// Global access to the widget browser. +Widget_Browser *widget_browser = NULL; + +// ---- global functions + +/** + Shortcut to have the widget browser graphics refreshed soon. + */ +void redraw_browser() { + widget_browser->redraw(); +} + +/** + Shortcut to create the widget browser. + */ +Fl_Widget *make_widget_browser(int x,int y,int w,int h) { + return (widget_browser = new Widget_Browser(x,y,w,h)); +} + +/** + Make sure thet the caller is visible in the widget browser. + \param[in] caller scroll the browser in y so that caller + is visible (may be NULL) + */ +void redraw_widget_browser(Fl_Type *caller) +{ + if (caller) + widget_browser->display(caller); + widget_browser->redraw(); +} + +/** + Select or deselect a node in the widget browser. + \param[in] o (de)select this node + \oaram[in] v the new selection state (1=select, 0=de-select) + */ +void select(Fl_Type *o, int v) { + widget_browser->select(o,v,1); +} + +/** + Select a single node in the widget browser, deselect all others. + \param[in] o select this node + */ +void select_only(Fl_Type *o) { + widget_browser->select_only(o,1); +} + +/** + Deselect all nodes in the widget browser. + */ +void deselect() { + widget_browser->deselect(); +} + +/** + Show the selected item in the browser window. + + Make sure that the given item is visible in the browser by opening + all parent groups and moving the item into the visible space. + + \param[in] t show this ite + */ +void reveal_in_browser(Fl_Type *t) { + Fl_Type *p = t->parent; + if (p) { + for (;;) { + if (!p->open_) + p->open_ = 1; + if (!p->parent) break; + p = p->parent; + } + fixvisible(p); + } + widget_browser->display(t); + widget_browser->redraw(); +} + +// ---- local functions + +/** + Copy the given string str to buffer p with no more than maxl characters. + + Add "..." if string was truncated. + + Quote characters are NOT counted. + + \param[out] p return the resulting string in this buffer, terminated with + a NUL byte + \param[in] str copy this string; utf8 aware + \param[in] maxl maximum number of letter to copy until we print + the elipsis (...) + \param[in] auote if set, the resulting string is embedded in double quotes + \returns pointer to end of string (before terminating null byte). + \note the buffer p must be large enough to hold (4 * (maxl+1) + 1) bytes + or (4 * (maxl+1) + 3) bytes if quoted, e.g. "123..." because each UTF-8 + character can consist of 4 bytes, "..." adds 3 bytes, quotes '""' add two + bytes, and the terminating null byte adds another byte. + This supports Unicode code points up to U+10FFFF (standard as of 10/2016). + Sanity checks for illegal UTF-8 sequences are included. + */ +static char *copy_trunc(char *p, const char *str, int maxl, int quote) +{ + int size = 0; // truncated string size in characters + int bs; // size of UTF-8 character in bytes + const char *end = str + strlen(str); // end of input string + if (quote) *p++ = '"'; // opening quote + while (size < maxl) { // maximum <maxl> characters + if (!(*str & (-32))) break; // end of string (0 or control char) + bs = fl_utf8len(*str); // size of next character + if (bs <= 0) break; // some error - leave + if (str + bs > end) break; // UTF-8 sequence beyond end of string + while (bs--) *p++ = *str++; // copy that character into the buffer + size++; // count copied characters + } + if (*str) { // string was truncated + strcpy(p,"..."); p += 3; + } + if (quote) *p++ = '"'; // closing quote + *p = 0; // terminating null byte + return p; +} + +// ---- Widget_Browser implementation + +/** + Create a new instance of the Widget_Browser widget. + + Fluid currently generates only one instance of this browser. If we want + to use multiple browser at some point, we need to refactor a few global + variables, i.e. Fl_Type::first and Fl_Type::last . + + \param[in] X, Y, W, H position and size of widget + \param[in] l optional label + \todo It would be nice to be able to grab one or more nodes and mmove them + within the hierarchy. + */ +Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l) +: Fl_Browser_(X,Y,W,H,l), + pushedtitle(NULL) +{ + type(FL_MULTI_BROWSER); + Fl_Widget::callback(callback_stub); + when(FL_WHEN_RELEASE); +} + +/** + Override the method to find the first item in the list of elements. + \return the first item + */ +void *Widget_Browser::item_first() const { + return Fl_Type::first; +} + +/** + Override the method to find the next item in the list of elements. + \param l this item + \return the next item, irregardless of tree depth, or NULL at the end + */ +void *Widget_Browser::item_next(void *l) const { + return ((Fl_Type*)l)->next; +} + +/** + Override the method to find the previous item in the list of elements. + \param l this item + \return the previous item, irregardless of tree depth, or NULL at the start + */ +void *Widget_Browser::item_prev(void *l) const { + return ((Fl_Type*)l)->prev; +} + +/** + Override the method to check if an item was selected. + \param l this item + \return 1 if selected, 0 if not + \todo what is the difference between selected and new_selected, and why do we do this? + */ +int Widget_Browser::item_selected(void *l) const { + return ((Fl_Type*)l)->new_selected; +} + +/** + Override the method to mark an item selected. + \param l this item + \param[in] v 1 if selecting, 0 if not + */ +void Widget_Browser::item_select(void *l,int v) { + ((Fl_Type*)l)->new_selected = v; +} + +/** + Override the method to return the height of an item representation in Flixels. + \param l this item + \return height in FLTK units (used to be pixels before high res screens) + */ +int Widget_Browser::item_height(void *l) const { + Fl_Type *t = (Fl_Type*)l; + if (t->visible) { + if (show_comments && t->comment()) + return textsize()*2+4; + else + return textsize()+5; + } + return 0; +} + +/** + Override the method to return the estimated height of all items. + \return height in FLTK units + */ +int Widget_Browser::incr_height() const { + return textsize()+2; +} + +/** + Draw an item in the widget browser. + + A browser line starts with a variable size space. This space directly + relates to the level of the type entry. + + If this type has the ability to store children, a triangle follows, + pointing right (closed) or pointing down (open, children shown). + + Next follows an icon that is specific to the type. This makes it easy to + spot certain types. + + Now follows some text. For classes and widgets, this is the type itself, + followed by the name of the object. Other objects show their content as + text, possibly abbreviated with an ellipsis. + + \param v v is a pointer to the actual widget type and can be cast safely + to Fl_Type + \param X,Y these give the position in window coordinates of the top left + corner of this line +*/ +void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const { + // cast to a more general type + Fl_Type *l = (Fl_Type *)v; + + char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul + + // calculate the horizontal start position of this item + // 3 is the edge of the browser + // 13 is the width of the arrow that indicates children for the item + // 18 is the width of the icon + // 12 is the indent per level + X += 3 + 13 + 18 + l->level * 12; + + // calculate the horizontal start position and width of the separator line + int x1 = X; + int w1 = w() - x1; + + // items can contain a comment. If they do, the comment gets a second text + // line inside this browser line + int comment_incr = 0; + if (show_comments && l->comment()) { + copy_trunc(buf, l->comment(), 80, 0); + comment_incr = textsize()-1; + if (l->new_selected) fl_color(fl_contrast(FL_DARK_GREEN,FL_SELECTION_COLOR)); + else fl_color(fl_contrast(FL_DARK_GREEN,color())); + fl_font(textfont()+FL_ITALIC, textsize()-2); + fl_draw(buf, X, Y+12); + Y += comment_incr/2; + comment_incr -= comment_incr/2; + } + + if (l->new_selected) fl_color(fl_contrast(FL_FOREGROUND_COLOR,FL_SELECTION_COLOR)); + else fl_color(FL_FOREGROUND_COLOR); + + // Width=10: Draw the triangle that indicates possible children + if (l->is_parent()) { + X = X - 18 - 13; + if (!l->next || l->next->level <= l->level) { + if (l->open_!=(l==pushedtitle)) { + // an outlined triangle to the right indicates closed item, no children + fl_loop(X,Y+7,X+5,Y+12,X+10,Y+7); + } else { + // an outlined triangle to the bottom indicates open item, no children + fl_loop(X+2,Y+2,X+7,Y+7,X+2,Y+12); + } + } else { + if (l->open_!=(l==pushedtitle)) { + // a filled triangle to the right indicates closed item, with children + fl_polygon(X,Y+7,X+5,Y+12,X+10,Y+7); + } else { + // a filled triangle to the bottom indicates open item, with children + fl_polygon(X+2,Y+2,X+7,Y+7,X+2,Y+12); + } + } + X = X + 13 + 18; + } + + // Width=18: Draw the icon associated with the type. + Fl_Pixmap *pm = pixmap[l->pixmapID()]; + if (pm) pm->draw(X-18, Y); + + // Add tags on top of the icon for locked and protected types. + switch (l->is_public()) { + case 0: lock_pixmap->draw(X - 17, Y); break; + case 2: protected_pixmap->draw(X - 17, Y); break; + } + + if ( l->is_widget() + && !l->is_window() + && ((Fl_Widget_Type*)l)->o + && !((Fl_Widget_Type*)l)->o->visible() + && (!l->parent || ( strcmp(l->parent->type_name(),"Fl_Tabs") + && strcmp(l->parent->type_name(),"Fl_Wizard")) ) + ) + { + invisible_pixmap->draw(X - 17, Y); + } + + // Indent=12 per level: Now write the text that comes after the graphics representation + Y += comment_incr; + if (l->is_widget() || l->is_class()) { + const char* c = subclassname(l); + if (!strncmp(c,"Fl_",3)) c += 3; + fl_font(textfont(), textsize()); + fl_draw(c, X, Y+13); + X += int(fl_width(c)+fl_width('n')); + c = l->name(); + if (c) { + fl_font(textfont()|FL_BOLD, textsize()); + fl_draw(c, X, Y+13); + } else if ((c = l->label())) { + copy_trunc(buf, c, 20, 1); // quoted string + fl_draw(buf, X, Y+13); + } + } else { + copy_trunc(buf, l->title(), 55, 0); + fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize()); + fl_draw(buf, X, Y+13); + } + + // draw a thin line below the item if this item is not selected + // (if it is selected this additional line would look bad) + if (!l->new_selected) { + fl_color(fl_lighter(FL_GRAY)); + fl_line(x1,Y+16,x1+w1,Y+16); + } +} + +/** + Override the method to return the width of an item representation in Flixels. + \param l this item + \return width in FLTK units + */ +int Widget_Browser::item_width(void *v) const { + + char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul + + Fl_Type *l = (Fl_Type *)v; + + if (!l->visible) return 0; + + int W = 3 + 13 + 18 + l->level * 12; + + if (l->is_widget() || l->is_class()) { + const char* c = l->type_name(); + if (!strncmp(c,"Fl_",3)) c += 3; + fl_font(textfont(), textsize()); + W += int(fl_width(c) + fl_width('n')); + c = l->name(); + if (c) { + fl_font(textfont()|FL_BOLD, textsize()); + W += int(fl_width(c)); + } else if (l->label()) { + copy_trunc(buf, l->label(), 20, 1); // quoted string + W += int(fl_width(buf)); + } + } else { + copy_trunc(buf, l->title(), 55, 0); + fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize()); + W += int(fl_width(buf)); + } + + return W; +} + +/** + Callback to tell the FLuid UI when the list of selected items changed. + */ +void Widget_Browser::callback() { + selection_changed((Fl_Type*)selection()); +} + +/** + Override the event handling for this browser. + + The vertical mouse position corresponds to an entry in the type tree. + The horizontal position has the following hot zones: + - 0-3 is the widget frame and ignored + - the next hot zone starts 12*indent pixels further to the right + - the next 13 pixels refer to the arrow that indicates children for the item + - 18 pixels follow for the icon + - the remaining part is filled with text + + \param[in] e the incoming event type + \return 0 if the event is not supported, and 1 if the event was "used up" +*/ +int Widget_Browser::handle(int e) { + static Fl_Type *title; + Fl_Type *l; + int X,Y,W,H; bbox(X,Y,W,H); + switch (e) { + case FL_PUSH: + if (!Fl::event_inside(X,Y,W,H)) break; + l = (Fl_Type*)find_item(Fl::event_y()); + if (l) { + X += 3 + 12*l->level - hposition(); + if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) { + title = pushedtitle = l; + redraw_line(l); + return 1; + } + } + break; + case FL_DRAG: + if (!title) break; + l = (Fl_Type*)find_item(Fl::event_y()); + if (l) { + X += 3 + 12*l->level - hposition(); + if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) ; + else l = 0; + } + if (l != pushedtitle) { + if (pushedtitle) redraw_line(pushedtitle); + if (l) redraw_line(l); + pushedtitle = l; + } + return 1; + case FL_RELEASE: + if (!title) { + l = (Fl_Type*)find_item(Fl::event_y()); + if (l && l->new_selected && (Fl::event_clicks() || Fl::event_state(FL_CTRL))) + l->open(); + break; + } + l = pushedtitle; + title = pushedtitle = 0; + if (l) { + if (l->open_) { + l->open_ = 0; + for (Fl_Type*k = l->next; k&&k->level>l->level; k = k->next) + k->visible = 0; + } else { + l->open_ = 1; + for (Fl_Type*k=l->next; k&&k->level>l->level;) { + k->visible = 1; + if (k->is_parent() && !k->open_) { + Fl_Type *j; + for (j = k->next; j && j->level>k->level; j = j->next) {/*empty*/} + k = j; + } else + k = k->next; + } + } + redraw(); + } + return 1; + } + return Fl_Browser_::handle(e); +} + + diff --git a/fluid/widget_browser.h b/fluid/widget_browser.h new file mode 100644 index 000000000..c00d45052 --- /dev/null +++ b/fluid/widget_browser.h @@ -0,0 +1,62 @@ +// +// Widget Browser code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2021 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_WIDGET_BROWSER_H +#define _FLUID_WIDGET_BROWSER_H + +#include <FL/Fl_Browser_.H> + +class Fl_Type; +class Widget_Browser; + +extern Widget_Browser *widget_browser; + +extern void redraw_browser(); +extern Fl_Widget *make_widget_browser(int x,int y,int w,int h); +extern void redraw_widget_browser(Fl_Type *caller); +extern void select(Fl_Type *o, int v); +extern void select_only(Fl_Type *o); +extern void deselect(); +extern void reveal_in_browser(Fl_Type *t); + +class Widget_Browser : public Fl_Browser_ +{ + friend class Fl_Type; + + static void callback_stub(Fl_Widget *o, void *) { + ((Widget_Browser *)o)->callback(); + } + + Fl_Type* pushedtitle; + + // required routines for Fl_Browser_ subclass: + void *item_first() const ; + void *item_next(void *) const ; + void *item_prev(void *) const ; + int item_selected(void *) const ; + void item_select(void *,int); + int item_width(void *) const ; + int item_height(void *) const ; + void item_draw(void *,int,int,int,int) const ; + int incr_height() const ; + +public: + int handle(int); + void callback(); + Widget_Browser(int,int,int,int,const char * =0); +}; + +#endif // _FLUID_WIDGET_BROWSER_H diff --git a/fluid/widget_panel.cxx b/fluid/widget_panel.cxx index 30bb686ec..31cf0ebd2 100644 --- a/fluid/widget_panel.cxx +++ b/fluid/widget_panel.cxx @@ -17,7 +17,7 @@ // generated by Fast Light User Interface Designer (fluid) version 1.0400 #include "widget_panel.h" -extern void comment_cb(Fl_Text_Editor*, void*); +#include "Fl_Widget_Type.h" static void cb_(Fl_Tabs* o, void* v) { propagate_load((Fl_Group *)o,v); diff --git a/fluid/widget_panel.fl b/fluid/widget_panel.fl index 38a5b34e8..7b29fd4ab 100644 --- a/fluid/widget_panel.fl +++ b/fluid/widget_panel.fl @@ -20,7 +20,7 @@ comment {// } {in_source in_header } -decl {extern void comment_cb(Fl_Text_Editor*, void*);} {private global +decl {\#include "Fl_Widget_Type.h"} {selected private global } Function {make_widget_panel()} { @@ -28,8 +28,8 @@ Function {make_widget_panel()} { } { Fl_Window {} { comment {Use a Double Window to avoid flickering.} open - xywh {560 60 420 400} type Double labelsize 11 align 80 hide resizable hotspot - code0 {o->size_range(o->w(), o->h());} size_range {420 400 0 0} + xywh {500 209 420 400} type Double labelsize 11 align 80 resizable hotspot + code0 {o->size_range(o->w(), o->h());} size_range {420 400 0 0} visible } { Fl_Tabs {} { callback {propagate_load((Fl_Group *)o,v);} open @@ -37,7 +37,7 @@ Function {make_widget_panel()} { } { Fl_Group {} { label GUI - callback propagate_load open + callback propagate_load xywh {10 30 400 330} labelsize 11 when 0 resizable } { Fl_Group {} { @@ -46,7 +46,7 @@ Function {make_widget_panel()} { xywh {95 40 309 20} labelfont 1 labelsize 11 align 4 } { Fl_Input {} { - callback label_cb selected + callback label_cb tooltip {The label text for the widget. Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 1 textsize 11 resizable } @@ -664,7 +664,7 @@ wCallback->do_callback(wCallback, v);} open } } } - Fl_Group {} {open + Fl_Group {} { xywh {10 370 400 20} labelsize 11 } { Fl_Box {} { |
