From 51a55bc73660f64e8f4b32b8b4d3858f2a786f7b Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Sun, 16 Mar 2025 17:16:12 -0400 Subject: Fluid: restructuring and rejuvenation of the source code. * Add classes for application and project * Removed all globals from Fluid.h * Extracting args and project history into their own classes * Moving globals into Application class * Initialize values inside headers for some classes. * Undo functionality wrapped in a class inside Project. * File reader and writer are now linked to a project. * Avoid global project access * Nodes (former Types) will be managed by a new Tree class. * Removed static members (hidden globals) form Node/Fl_Type. * Adding Tree iterator. * Use nullptr instead of 0, NULL, or 0L * Renamed Fl_..._Type to ..._Node, FL_OVERRIDE -> override * Renaming ..._type to ...::prototype * Splitting Widget Panel into multiple files. * Moved callback code into widget panel file. * Cleaning up Fluid_Image -> Image_asset * Moving Fd_Snap_Action into new namespace fld::app::Snap_Action etc. * Moved mergeback into proj folder. * `enum ID` is now `enum class Type`. --- fluid/tools/ExternalCodeEditor_UNIX.cxx | 76 +++++++++++++------------- fluid/tools/ExternalCodeEditor_UNIX.h | 4 +- fluid/tools/ExternalCodeEditor_WIN32.cxx | 92 ++++++++++++++++---------------- fluid/tools/ExternalCodeEditor_WIN32.h | 2 +- fluid/tools/autodoc.cxx | 64 +++++++++++----------- fluid/tools/autodoc.h | 2 +- fluid/tools/filename.cxx | 32 ++++++++++- fluid/tools/filename.h | 5 +- 8 files changed, 154 insertions(+), 123 deletions(-) (limited to 'fluid/tools') diff --git a/fluid/tools/ExternalCodeEditor_UNIX.cxx b/fluid/tools/ExternalCodeEditor_UNIX.cxx index bf472d896..9e9ffd00e 100644 --- a/fluid/tools/ExternalCodeEditor_UNIX.cxx +++ b/fluid/tools/ExternalCodeEditor_UNIX.cxx @@ -5,8 +5,8 @@ #include "ExternalCodeEditor_UNIX.h" -#include "app/fluid.h" -#include "app/project.h" +#include "Fluid.h" +#include "Project.h" #include /* Fl_Timeout_Handler.. */ #include /* fl_alert() */ @@ -23,9 +23,11 @@ #include /* free().. */ #include /* snprintf().. */ +using namespace fld; + // 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 +static Fl_Timeout_Handler L_update_timer_cb = nullptr; // app's update timer callback // [Static/Local] See if file exists static int is_file(const char *filename) { @@ -57,7 +59,7 @@ static int is_dir(const char *dirname) { */ ExternalCodeEditor::ExternalCodeEditor() { pid_ = -1; - filename_ = 0; + filename_ = nullptr; file_mtime_ = 0; file_size_ = 0; alert_pipe_[0] = alert_pipe_[1] = -1; @@ -69,11 +71,11 @@ ExternalCodeEditor::ExternalCodeEditor() { This also closes the external editor. */ ExternalCodeEditor::~ExternalCodeEditor() { - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("ExternalCodeEditor() DTOR CALLED (this=%p, pid=%ld)\n", (void*)this, (long)pid_); close_editor(); // close editor, delete tmp file - set_filename(0); // free()s filename + set_filename(nullptr); // free()s filename if (alert_pipe_open_) { Fl::remove_fd(alert_pipe_[0]); @@ -85,12 +87,12 @@ ExternalCodeEditor::~ExternalCodeEditor() { /** Set the filename for the file we wish to edit. Handles memory allocation/free. - If set to NULL, frees memory. + If set to nullptr, 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; + filename_ = val ? fl_strdup(val) : nullptr; } /** @@ -105,7 +107,7 @@ int ExternalCodeEditor::is_editing() { Wait for editor to close */ void ExternalCodeEditor::close_editor() { - if ( G_debug ) printf("close_editor() called: pid=%ld\n", long(pid_)); + if ( Fluid.debug_external_editor ) printf("close_editor() called: pid=%ld\n", long(pid_)); // Wait until editor is closed + reaped while ( is_editing() ) { switch ( reap_editor() ) { @@ -119,7 +121,7 @@ void ExternalCodeEditor::close_editor() { switch ( fl_choice("Please close external editor\npid=%ld file=%s", "Force Close", // button 0 "Closed", // button 1 - 0, // button 2 + nullptr, // button 2 long(pid_), filename() ) ) { case 0: // Force Close kill_editor(); @@ -141,7 +143,7 @@ void ExternalCodeEditor::close_editor() { 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 ( Fluid.debug_external_editor ) printf("kill_editor() called: pid=%ld\n", (long)pid_); if ( !is_editing() ) return; // editor not running? return.. kill(pid_, SIGTERM); // kill editor int wcount = 0; @@ -164,7 +166,7 @@ void ExternalCodeEditor::kill_editor() { } continue; case 1: // process reaped (reap_editor() sets pid_ to -1) - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("*** REAPED KILLED EXTERNAL EDITOR: PID %ld\n", (long)pid_reaped); break; } @@ -185,7 +187,7 @@ void ExternalCodeEditor::kill_editor() { \return -1 error getting file info (strerror() has reason) */ int ExternalCodeEditor::handle_changes(const char **code, int force) { - code[0] = 0; + code[0] = nullptr; if ( !is_editing() ) return 0; // Get current time/size info, see if file changed int changed = 0; @@ -239,13 +241,13 @@ int ExternalCodeEditor::remove_tmpfile() { if ( !tmpfile ) return 0; // Filename set? remove (if exists) and zero filename/mtime/size if ( is_file(tmpfile) ) { - if ( G_debug ) printf("Removing tmpfile '%s'\n", tmpfile); + if ( Fluid.debug_external_editor ) printf("Removing tmpfile '%s'\n", tmpfile); if ( remove(tmpfile) < 0 ) { fl_alert("WARNING: Can't remove() '%s': %s", tmpfile, strerror(errno)); return -1; } } - set_filename(0); + set_filename(nullptr); file_mtime_ = 0; file_size_ = 0; return 1; @@ -268,7 +270,7 @@ const char* ExternalCodeEditor::tmpdir_name() { void ExternalCodeEditor::tmpdir_clear() { const char *tmpdir = tmpdir_name(); if ( is_dir(tmpdir) ) { - if ( G_debug ) printf("Removing tmpdir '%s'\n", tmpdir); + if ( Fluid.debug_external_editor ) printf("Removing tmpdir '%s'\n", tmpdir); if ( rmdir(tmpdir) < 0 ) { fl_alert("WARNING: Can't rmdir() '%s': %s", tmpdir, strerror(errno)); } @@ -278,7 +280,7 @@ void ExternalCodeEditor::tmpdir_clear() { /** Creates temp dir (if doesn't exist) and returns the dirname as a static string. - \return NULL on error, dialog shows reason. + \return nullptr on error, dialog shows reason. */ const char* ExternalCodeEditor::create_tmpdir() { const char *dirname = tmpdir_name(); @@ -286,7 +288,7 @@ const char* ExternalCodeEditor::create_tmpdir() { if ( mkdir(dirname, 0777) < 0 ) { fl_alert("can't create directory '%s': %s", dirname, strerror(errno)); - return NULL; + return nullptr; } } return dirname; @@ -294,13 +296,13 @@ const char* ExternalCodeEditor::create_tmpdir() { /** Returns temp filename in static buffer. - \return NULL if can't, posts dialog explaining why. + \return nullptr if can't, posts dialog explaining why. */ const char* ExternalCodeEditor::tmp_filename() { static char path[FL_PATH_MAX+1]; const char *tmpdir = create_tmpdir(); - if ( !tmpdir ) return 0; - const char *ext = g_project.code_file_name.c_str(); // e.g. ".cxx" + if ( !tmpdir ) return nullptr; + const char *ext = Fluid.proj.code_file_name.c_str(); // e.g. ".cxx" snprintf(path, FL_PATH_MAX, "%s/%p%s", tmpdir, (void*)this, ext); path[FL_PATH_MAX] = 0; return path; @@ -308,12 +310,12 @@ const char* ExternalCodeEditor::tmp_filename() { /** Save string 'code' to 'filename', returning file's mtime/size. - 'code' can be NULL -- writes an empty file if so. + 'code' can be nullptr -- 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) { - if ( code == 0 ) code = ""; // NULL? write an empty file + if ( code == nullptr ) code = ""; // nullptr? write an empty file int fd = open(filename, O_WRONLY|O_CREAT, 0666); if ( fd == -1 ) { fl_alert("ERROR: open() '%s': %s", filename, strerror(errno)); @@ -336,7 +338,7 @@ static int save_file(const char *filename, const char *code) { /** Convert string 's' to array of argv[], useful for execve(). - - 's' will be modified (words will be NULL separated) + - 's' will be modified (words will be nullptr 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 @@ -346,14 +348,14 @@ static int make_args(char *s, // string containing words (gets trashed!) int *aargc, // pointer to argc char ***aargv) { // pointer to argv char *ss, **argv; - if ((argv=(char**)malloc(sizeof(char*) * (strlen(s)/2)))==NULL) { + if ((argv=(char**)malloc(sizeof(char*) * (strlen(s)/2)))==nullptr) { return -1; } int t; - for(t=0; (t==0)?(ss=strtok(s," \t")):(ss=strtok(0," \t")); t++) { + for(t=0; (t==0)?(ss=strtok(s," \t")):(ss=strtok(nullptr," \t")); t++) { argv[t] = ss; } - argv[t] = 0; + argv[t] = nullptr; aargv[0] = argv; aargc[0] = t; return(t); @@ -383,7 +385,7 @@ void ExternalCodeEditor::open_alert_pipe() { */ int ExternalCodeEditor::start_editor(const char *editor_cmd, const char *filename) { - if ( G_debug ) printf("start_editor() cmd='%s', filename='%s'\n", + if ( Fluid.debug_external_editor ) printf("start_editor() cmd='%s', filename='%s'\n", editor_cmd, filename); char cmd[1024]; snprintf(cmd, sizeof(cmd), "%s %s", editor_cmd, filename); @@ -399,7 +401,7 @@ int ExternalCodeEditor::start_editor(const char *editor_cmd, // NOTE: no FLTK calls after a fork. Use a pipe to tell the app if the // command can't launch int nargs; - char **args = 0; + char **args = nullptr; if (make_args(cmd, &nargs, &args) > 0) { execvp(args[0], args); // run command - doesn't return if succeeds if (alert_pipe_open_) { @@ -416,7 +418,7 @@ int ExternalCodeEditor::start_editor(const char *editor_cmd, default: // parent if ( L_editors_open++ == 0 ) // first editor? start timers { start_update_timer(); } - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("--- EDITOR STARTED: pid_=%ld #open=%d\n", (long)pid_, L_editors_open); break; } @@ -426,7 +428,7 @@ int ExternalCodeEditor::start_editor(const char *editor_cmd, /** Try to reap external editor process. - If 'pid_reaped' not NULL, returns PID of reaped editor. + If 'pid_reaped' not nullptr, returns PID of reaped editor. \return -2: editor not open \return -1: waitpid() failed (errno has reason) @@ -453,7 +455,7 @@ int ExternalCodeEditor::reap_editor(pid_t *pid_reaped) { { stop_update_timer(); } break; } - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("*** EDITOR REAPED: pid=%ld #open=%d\n", long(wpid), L_editors_open); return 1; } @@ -462,7 +464,7 @@ int ExternalCodeEditor::reap_editor(pid_t *pid_reaped) { Open external editor using 'editor_cmd' to edit 'code'. 'code' contains multiline code to be edited as a temp file. - 'code' can be NULL -- edits an empty file if so. + 'code' can be nullptr -- edits an empty file if so. \return 0 if succeeds \return -1 if can't open editor (already open, etc), @@ -492,7 +494,7 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, filename(), (long)pid_); return 0; case 1: // process reaped, wpid is pid reaped - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("*** REAPED EXTERNAL EDITOR: PID %ld\n", (long)wpid); break; // fall thru to open new editor instance } @@ -512,7 +514,7 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, file_mtime_ = sbuf.st_mtime; file_size_ = sbuf.st_size; if ( start_editor(editor_cmd, filename()) < 0 ) { // open file in external editor - if ( G_debug ) printf("Editor failed to start\n"); + if ( Fluid.debug_external_editor ) printf("Editor failed to start\n"); return -1; // errors were shown in dialog } return 0; @@ -523,7 +525,7 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, */ void ExternalCodeEditor::start_update_timer() { if ( !L_update_timer_cb ) return; - if ( G_debug ) printf("--- TIMER: STARTING UPDATES\n"); + if ( Fluid.debug_external_editor ) printf("--- TIMER: STARTING UPDATES\n"); Fl::add_timeout(2.0, L_update_timer_cb); } @@ -532,7 +534,7 @@ void ExternalCodeEditor::start_update_timer() { */ void ExternalCodeEditor::stop_update_timer() { if ( !L_update_timer_cb ) return; - if ( G_debug ) printf("--- TIMER: STOPPING UPDATES\n"); + if ( Fluid.debug_external_editor ) printf("--- TIMER: STOPPING UPDATES\n"); Fl::remove_timeout(L_update_timer_cb); } diff --git a/fluid/tools/ExternalCodeEditor_UNIX.h b/fluid/tools/ExternalCodeEditor_UNIX.h index 644f22afa..2142d5a10 100644 --- a/fluid/tools/ExternalCodeEditor_UNIX.h +++ b/fluid/tools/ExternalCodeEditor_UNIX.h @@ -7,7 +7,7 @@ #ifndef _EXTCODEEDITOR_H #define _EXTCODEEDITOR_H -#include "app/fluid.h" +#include "Fluid.h" #include @@ -42,7 +42,7 @@ public: ExternalCodeEditor(); ~ExternalCodeEditor(); int is_editing(); - int reap_editor(pid_t *pid_reaped=NULL); + int reap_editor(pid_t *pid_reaped=nullptr); void close_editor(); const char *filename() { return filename_; } int open_editor(const char *editor_cmd, const char *code); diff --git a/fluid/tools/ExternalCodeEditor_WIN32.cxx b/fluid/tools/ExternalCodeEditor_WIN32.cxx index 09688d16a..64d791400 100644 --- a/fluid/tools/ExternalCodeEditor_WIN32.cxx +++ b/fluid/tools/ExternalCodeEditor_WIN32.cxx @@ -17,8 +17,8 @@ // Note: This entire file Windows only. #include "tools/ExternalCodeEditor_WIN32.h" -#include "app/fluid.h" -#include "app/project.h" +#include "Fluid.h" +#include "Project.h" #include // Fl_Timeout_Handler.. #include // fl_alert() @@ -28,17 +28,17 @@ #include // snprintf() #include -extern int G_debug; // defined in fluid.cxx +using namespace fld; // 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 -static wchar_t *wbuf = NULL; -static char *abuf = NULL; +static wchar_t *wbuf = nullptr; +static char *abuf = nullptr; static wchar_t *utf8_to_wchar(const char *utf8, wchar_t *&wbuf, int lg = -1) { unsigned len = (lg >= 0) ? (unsigned)lg : (unsigned)strlen(utf8); - unsigned wn = fl_utf8toUtf16(utf8, len, NULL, 0) + 1; // Query length + unsigned wn = fl_utf8toUtf16(utf8, len, nullptr, 0) + 1; // Query length wbuf = (wchar_t *)realloc(wbuf, sizeof(wchar_t) * wn); wn = fl_utf8toUtf16(utf8, len, (unsigned short *)wbuf, wn); // Convert string wbuf[wn] = 0; @@ -47,7 +47,7 @@ static wchar_t *utf8_to_wchar(const char *utf8, wchar_t *&wbuf, int lg = -1) { static char *wchar_to_utf8(const wchar_t *wstr, char *&utf8) { unsigned len = (unsigned)wcslen(wstr); - unsigned wn = fl_utf8fromwc(NULL, 0, wstr, len) + 1; // query length + unsigned wn = fl_utf8fromwc(nullptr, 0, wstr, len) + 1; // query length utf8 = (char *)realloc(utf8, wn); wn = fl_utf8fromwc(utf8, wn, wstr, len); // convert string utf8[wn] = 0; @@ -68,7 +68,7 @@ static const char *get_ms_errmsg() { DWORD msize = 0; // Get error message from Windows - msize = FormatMessageW(flags, 0, lastErr, langid, (LPWSTR)&mbuf, 0, NULL); + msize = FormatMessageW(flags, 0, lastErr, langid, (LPWSTR)&mbuf, 0, nullptr); if ( msize == 0 ) { _snprintf(emsg, sizeof(emsg), "Error #%ld", (unsigned long)lastErr); } else { @@ -119,7 +119,7 @@ ExternalCodeEditor::~ExternalCodeEditor() { } // [Protected] Set the filename. Handles memory allocation/free -// If set to NULL, frees memory. +// If set to nullptr, frees memory. // void ExternalCodeEditor::set_filename(const char *val) { if ( filename_ ) free((void*)filename_); @@ -137,7 +137,7 @@ static BOOL CALLBACK terminate_app_enum(HWND hwnd, LPARAM lParam) { GetWindowThreadProcessId(hwnd, &dwID); if (dwID == (DWORD)lParam) { PostMessage(hwnd, WM_CLOSE, 0, 0); - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("terminate_app_enum() sends WIN_CLOSE to hwnd=%p\n", (void*)hwnd); } return TRUE; @@ -154,12 +154,12 @@ static int terminate_app(DWORD pid, DWORD msecTimeout) { // Wait on handle. If it closes, great. If it times out, use TerminateProcess() int ret = 0; if ( WaitForSingleObject(hProc, msecTimeout) != WAIT_OBJECT_0 ) { - if ( G_debug ) { + if ( Fluid.debug_external_editor ) { printf("WARNING: sent WIN_CLOSE, but timeout after %ld msecs.." "trying TerminateProcess\n", msecTimeout); } if ( TerminateProcess(hProc, 0) == 0 ) { - if ( G_debug ) { + if ( Fluid.debug_external_editor ) { printf("ERROR: TerminateProcess() for pid=%ld failed: %s\n", long(pid), get_ms_errmsg()); } @@ -176,7 +176,7 @@ static int terminate_app(DWORD pid, DWORD msecTimeout) { // [Protected] Wait for editor to close void ExternalCodeEditor::close_editor() { - if ( G_debug ) printf("close_editor() called: pid=%ld\n", long(pinfo_.dwProcessId)); + if ( Fluid.debug_external_editor ) printf("close_editor() called: pid=%ld\n", long(pinfo_.dwProcessId)); // Wait until editor is closed + reaped while ( is_editing() ) { switch ( reap_editor() ) { @@ -210,7 +210,7 @@ void ExternalCodeEditor::close_editor() { // The dtor calls this to ensure no editors remain running when fluid exits. // void ExternalCodeEditor::kill_editor() { - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("kill_editor() called: pid=%ld\n", (long)pinfo_.dwProcessId); if ( !is_editing() ) return; switch ( terminate_app(pinfo_.dwProcessId, 500) ) { // kill editor, wait up to 1/2 sec to die @@ -222,7 +222,7 @@ void ExternalCodeEditor::kill_editor() { case 0: { // success -- process reaped DWORD pid = pinfo_.dwProcessId; // save pid reap_cleanup(); // clears pinfo_ - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("*** kill_editor() REAP pid=%ld #open=%ld\n", long(pid), long(L_editors_open)); break; @@ -252,10 +252,10 @@ int ExternalCodeEditor::handle_changes(const char **code, int force) { HANDLE fh = CreateFileW(wbuf, // file to read GENERIC_READ, // reading only FILE_SHARE_READ, // sharing -- allow read share; just getting file size - NULL, // security + nullptr, // security OPEN_EXISTING, // create flags -- must exist 0, // misc flags - NULL); // templates + nullptr); // templates if ( fh == INVALID_HANDLE_VALUE ) return -1; LARGE_INTEGER fsize; // Get file size @@ -315,18 +315,18 @@ int ExternalCodeEditor::handle_changes(const char **code, int force) { // int ExternalCodeEditor::remove_tmpfile() { const char *tmpfile = filename(); - if ( G_debug ) printf("remove_tmpfile() '%s'\n", tmpfile ? tmpfile : "(empty)"); + if ( Fluid.debug_external_editor ) printf("remove_tmpfile() '%s'\n", tmpfile ? tmpfile : "(empty)"); if ( !tmpfile ) return 0; // Filename set? remove (if exists) and zero filename/mtime/size if ( is_file(tmpfile) ) { - if ( G_debug ) printf("Removing tmpfile '%s'\n", tmpfile); + if ( Fluid.debug_external_editor ) printf("Removing tmpfile '%s'\n", tmpfile); utf8_to_wchar(tmpfile, wbuf); if (DeleteFileW(wbuf) == 0) { fl_alert("WARNING: Can't DeleteFile() '%s': %s", tmpfile, get_ms_errmsg()); return -1; } } else { - if ( G_debug ) printf("remove_tmpfile(): is_file(%s) failed\n", tmpfile); + if ( Fluid.debug_external_editor ) printf("remove_tmpfile(): is_file(%s) failed\n", tmpfile); } set_filename(0); memset(&file_mtime_, 0, sizeof(file_mtime_)); @@ -348,7 +348,7 @@ const char* ExternalCodeEditor::tmpdir_name() { static char dirname[100]; _snprintf(dirname, sizeof(dirname), "%s.fluid-%ld", tempdir, (long)GetCurrentProcessId()); - if ( G_debug ) printf("tmpdir_name(): '%s'\n", dirname); + if ( Fluid.debug_external_editor ) printf("tmpdir_name(): '%s'\n", dirname); return dirname; } @@ -358,7 +358,7 @@ const char* ExternalCodeEditor::tmpdir_name() { void ExternalCodeEditor::tmpdir_clear() { const char *tmpdir = tmpdir_name(); if ( is_dir(tmpdir) ) { - if ( G_debug ) printf("Removing tmpdir '%s'\n", tmpdir); + if ( Fluid.debug_external_editor ) printf("Removing tmpdir '%s'\n", tmpdir); utf8_to_wchar(tmpdir, wbuf); if ( RemoveDirectoryW(wbuf) == 0 ) { fl_alert("WARNING: Can't RemoveDirectory() '%s': %s", @@ -368,7 +368,7 @@ 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. +// as a static string. Returns nullptr on error, dialog shows reason. // const char* ExternalCodeEditor::create_tmpdir() { const char *dirname = tmpdir_name(); @@ -377,27 +377,27 @@ const char* ExternalCodeEditor::create_tmpdir() { if (CreateDirectoryW(wbuf, 0) == 0) { fl_alert("can't create directory '%s': %s", dirname, get_ms_errmsg()); - return NULL; + return nullptr; } } return dirname; } // [Protected] Returns temp filename in static buffer. -// Returns NULL if can't, posts dialog explaining why. +// Returns nullptr 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; - const char *ext = g_project.code_file_name.c_str(); // e.g. ".cxx" + const char *ext = Fluid.proj.code_file_name.c_str(); // 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. +// 'code' can be nullptr -- writes an empty file if so. // Returns: // 0 on success // -1 on error (posts dialog with reason) @@ -406,17 +406,17 @@ static int save_file(const char *filename, const char *code, FILETIME &file_mtime, // return these since in win32 it's.. LARGE_INTEGER &file_size) { // ..efficient to get while file open - if ( code == 0 ) code = ""; // NULL? write an empty file + if ( code == 0 ) code = ""; // nullptr? write an empty file memset(&file_mtime, 0, sizeof(file_mtime)); memset(&file_size, 0, sizeof(file_size)); utf8_to_wchar(filename, wbuf); HANDLE fh = CreateFileW(wbuf, // filename GENERIC_WRITE, // write only 0, // sharing -- no share during write - NULL, // security + nullptr, // security CREATE_ALWAYS, // create flags -- recreate FILE_ATTRIBUTE_NORMAL, // misc flags - NULL); // templates + nullptr); // templates if ( fh == INVALID_HANDLE_VALUE ) { fl_alert("ERROR: couldn't create file '%s': %s", filename, get_ms_errmsg()); @@ -426,7 +426,7 @@ static int save_file(const char *filename, DWORD clen = (DWORD)strlen(code); DWORD count = 0; int ret = 0; - if ( WriteFile(fh, code, clen, &count, NULL) == 0 ) { + if ( WriteFile(fh, code, clen, &count, nullptr) == 0 ) { fl_alert("ERROR: WriteFile() '%s': %s", filename, get_ms_errmsg()); ret = -1; // fallthru to CloseHandle() } else if ( count != clen ) { @@ -459,7 +459,7 @@ static int save_file(const char *filename, // int ExternalCodeEditor::start_editor(const char *editor_cmd, const char *filename) { - if ( G_debug ) printf("start_editor() cmd='%s', filename='%s'\n", + if ( Fluid.debug_external_editor ) printf("start_editor() cmd='%s', filename='%s'\n", editor_cmd, filename); // Startup info STARTUPINFOW sinfo; @@ -474,14 +474,14 @@ int ExternalCodeEditor::start_editor(const char *editor_cmd, _snprintf(cmd, sizeof(cmd), "%s %s", editor_cmd, filename); utf8_to_wchar(cmd, wbuf); // Start editor process - if (CreateProcessW(NULL, // app name + if (CreateProcessW(nullptr, // app name wbuf, // command to exec - NULL, // secure attribs - NULL, // thread secure attribs + nullptr, // secure attribs + nullptr, // thread secure attribs FALSE, // handle inheritance 0, // creation flags - NULL, // environ block - NULL, // current dir + nullptr, // environ block + nullptr, // current dir &sinfo, // startup info &pinfo_) == 0 ) { // process info fl_alert("CreateProcess() failed to start '%s': %s", @@ -490,7 +490,7 @@ int ExternalCodeEditor::start_editor(const char *editor_cmd, } if ( L_editors_open++ == 0 ) // first editor? start timers { start_update_timer(); } - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("--- EDITOR STARTED: pid_=%ld #open=%d\n", (long)pinfo_.dwProcessId, L_editors_open); return 0; @@ -512,7 +512,7 @@ void ExternalCodeEditor::reap_cleanup() { } // [Public] Try to reap external editor process -// If 'pid_reaped' not NULL, returns PID of reaped editor. +// If 'pid_reaped' not nullptr, returns PID of reaped editor. // Returns: // -2 -- editor not open // -1 -- WaitForSingleObject() failed (get_ms_errmsg() has reason) @@ -534,7 +534,7 @@ int ExternalCodeEditor::reap_editor(DWORD *pid_reaped) { DWORD wpid = pinfo_.dwProcessId; // save pid reap_cleanup(); // clears pinfo_ if ( pid_reaped ) *pid_reaped = wpid; // return pid to caller - if ( G_debug ) printf("*** EDITOR REAPED: pid=%ld #open=%d\n", + if ( Fluid.debug_external_editor ) printf("*** EDITOR REAPED: pid=%ld #open=%d\n", long(wpid), L_editors_open); return 1; } @@ -548,7 +548,7 @@ int ExternalCodeEditor::reap_editor(DWORD *pid_reaped) { // [Public] Open external editor using 'editor_cmd' to edit 'code'. // // 'code' contains multiline code to be edited as a temp file. -// 'code' can be NULL -- edits an empty file if so. +// 'code' can be nullptr -- edits an empty file if so. // // Returns: // 0 if succeeds @@ -579,7 +579,7 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, filename(), long(pinfo_.dwProcessId)); return 0; case 1: // process reaped, wpid is pid reaped - if ( G_debug ) + if ( Fluid.debug_external_editor ) printf("*** REAPED EXTERNAL EDITOR: PID %ld\n", long(wpid)); break; // fall thru to open new editor instance } @@ -592,12 +592,12 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, return -1; // errors were shown in dialog } if ( start_editor(editor_cmd, filename()) < 0 ) { // open file in external editor - if ( G_debug ) printf("Editor failed to start\n"); + if ( Fluid.debug_external_editor ) printf("Editor failed to start\n"); return -1; // errors were shown in dialog } // New editor opened -- start update timer (if not already) if ( L_update_timer_cb && !Fl::has_timeout(L_update_timer_cb) ) { - if ( G_debug ) printf("--- Editor opened: STARTING UPDATE TIMER\n"); + if ( Fluid.debug_external_editor ) printf("--- Editor opened: STARTING UPDATE TIMER\n"); Fl::add_timeout(2.0, L_update_timer_cb); } return 0; @@ -606,14 +606,14 @@ int ExternalCodeEditor::open_editor(const char *editor_cmd, // [Public/Static] Start update timer void ExternalCodeEditor::start_update_timer() { if ( !L_update_timer_cb ) return; - if ( G_debug ) printf("--- TIMER: STARTING UPDATES\n"); + if ( Fluid.debug_external_editor ) printf("--- TIMER: STARTING UPDATES\n"); Fl::add_timeout(2.0, L_update_timer_cb); } // [Public/Static] Stop update timer void ExternalCodeEditor::stop_update_timer() { if ( !L_update_timer_cb ) return; - if ( G_debug ) printf("--- TIMER: STOPPING UPDATES\n"); + if ( Fluid.debug_external_editor ) printf("--- TIMER: STOPPING UPDATES\n"); Fl::remove_timeout(L_update_timer_cb); } diff --git a/fluid/tools/ExternalCodeEditor_WIN32.h b/fluid/tools/ExternalCodeEditor_WIN32.h index 97d93e495..83c50a742 100644 --- a/fluid/tools/ExternalCodeEditor_WIN32.h +++ b/fluid/tools/ExternalCodeEditor_WIN32.h @@ -43,7 +43,7 @@ public: ExternalCodeEditor(); ~ExternalCodeEditor(); int is_editing(); - int reap_editor(DWORD *pid_reaped=NULL); + int reap_editor(DWORD *pid_reaped=nullptr); void close_editor(); const char *filename() { return filename_; } int open_editor(const char *editor_cmd, const char *code); diff --git a/fluid/tools/autodoc.cxx b/fluid/tools/autodoc.cxx index 295ab8d2f..c87b59bc2 100644 --- a/fluid/tools/autodoc.cxx +++ b/fluid/tools/autodoc.cxx @@ -18,11 +18,11 @@ #include "tools/autodoc.h" -#include "app/fluid.h" -#include "app/project.h" +#include "Fluid.h" +#include "Project.h" #include "nodes/factory.h" -#include "nodes/Fl_Widget_Type.h" -#include "nodes/Fl_Window_Type.h" +#include "nodes/Widget_Node.h" +#include "nodes/Window_Node.h" #include "panels/widget_panel.h" #include "panels/function_panel.h" #include "panels/settings_panel.h" @@ -232,7 +232,7 @@ void blend_alpha_bottom(const Fl_RGB_Image *img, int dy) { created in FLTK resolution, even if the screen uses a higher resolution. \param[in] filename the snapshot will be written to this file in png format - \param[in] w draw a bounding box around all widgets in the NULL terminated list + \param[in] w draw a bounding box around all widgets in the nullptr terminated list \param[in] frame add a margin around the bounding box \param[in] blend add another margin around the bounding box that fades to full transparency \param[in] scale scale everything by this factor before saving it @@ -342,7 +342,7 @@ int fl_snapshot(const char *filename, Fl_Widget *w1, Fl_Widget *w2, const Fl_Rect &blend, double scale) { - Fl_Widget *ww[3] = { w1, w2, NULL }; + Fl_Widget *ww[3] = { w1, w2, nullptr }; return fl_snapshot(filename, ww, frame, blend, scale); } @@ -363,7 +363,7 @@ int fl_snapshot(const char *filename, Fl_Widget *w, const Fl_Rect &blend, double scale) { - Fl_Widget *ww[2] = { w, NULL }; + Fl_Widget *ww[2] = { w, nullptr }; return fl_snapshot(filename, ww, frame, blend, scale); } @@ -383,27 +383,27 @@ void run_autodoc(const std::string &target_dir) { // Fl::scheme("gtk+"); // Create a silly project that contains all widgets that we want to document - new_project(false); + Fluid.new_project(false); - /*Fl_Type *t_func = */ add_new_widget_from_user("Function", Strategy::AS_LAST_CHILD, false); - Fl_Window_Type *t_win = (Fl_Window_Type*)add_new_widget_from_user("Fl_Window", Strategy::AS_LAST_CHILD, false); + /*Node *t_func = */ add_new_widget_from_user("Function", Strategy::AS_LAST_CHILD, false); + Window_Node *t_win = (Window_Node*)add_new_widget_from_user("Fl_Window", Strategy::AS_LAST_CHILD, false); t_win->label("My Main Window"); - Fl_Widget_Type *t_grp = (Fl_Widget_Type*)add_new_widget_from_user("Fl_Group", Strategy::AS_LAST_CHILD, false); + Widget_Node *t_grp = (Widget_Node*)add_new_widget_from_user("Fl_Group", Strategy::AS_LAST_CHILD, false); t_grp->public_ = 0; - Fl_Widget_Type *t_btn = (Fl_Widget_Type*)add_new_widget_from_user("Fl_Button", Strategy::AS_LAST_CHILD, false); + Widget_Node *t_btn = (Widget_Node*)add_new_widget_from_user("Fl_Button", Strategy::AS_LAST_CHILD, false); t_btn->comment("Don't press this button!"); t_btn->name("emergency_btn"); ((Fl_Button*)t_btn->o)->shortcut(FL_COMMAND|'g'); - Fl_Type *t_sldr = add_new_widget_from_user("Fl_Slider", Strategy::AS_LAST_CHILD, false); - Fl_Type *t_inp = add_new_widget_from_user("Fl_Input", Strategy::AS_LAST_CHILD, false); - Fl_Type *t_flx = add_new_widget_from_user("Fl_Flex", Strategy::AS_LAST_CHILD, false); - Fl_Type *t_flxc = add_new_widget_from_user("Fl_Button", Strategy::AS_LAST_CHILD, false); + Node *t_sldr = add_new_widget_from_user("Fl_Slider", Strategy::AS_LAST_CHILD, false); + Node *t_inp = add_new_widget_from_user("Fl_Input", Strategy::AS_LAST_CHILD, false); + Node *t_flx = add_new_widget_from_user("Fl_Flex", Strategy::AS_LAST_CHILD, false); + Node *t_flxc = add_new_widget_from_user("Fl_Button", Strategy::AS_LAST_CHILD, false); select_only(t_grp); - Fl_Type *t_grd = add_new_widget_from_user("Fl_Grid", Strategy::AS_LAST_CHILD, false); - Fl_Type *t_grdc = add_new_widget_from_user("Fl_Button", Strategy::AS_LAST_CHILD, false); + Node *t_grd = add_new_widget_from_user("Fl_Grid", Strategy::AS_LAST_CHILD, false); + Node *t_grdc = add_new_widget_from_user("Fl_Button", Strategy::AS_LAST_CHILD, false); widget_browser->rebuild(); - g_project.update_settings_dialog(); + Fluid.proj.update_settings_dialog(); // TODO: FLUID overview @@ -417,9 +417,9 @@ void run_autodoc(const std::string &target_dir) { // explain menubar? // explain widget browser // explain widget browser entry - main_window->size(350, 320); - fl_snapshot((target_dir + "main_window.png").c_str(), main_window, win_margin, win_blend); - fl_snapshot((target_dir + "main_menubar.png").c_str(), main_menubar, row_margin, row_blend); + Fluid.main_window->size(350, 320); + fl_snapshot((target_dir + "Fluid.main_window.png").c_str(), Fluid.main_window, win_margin, win_blend); + fl_snapshot((target_dir + "main_menubar.png").c_str(), Fluid.main_menubar, row_margin, row_blend); fl_snapshot((target_dir + "main_browser.png").c_str(), widget_browser, FL_SNAP_AREA_CLEAR, Fl_Rect(0, 30, FL_SNAP_TO_WINDOW, 100), row_blend, 2.0); @@ -453,7 +453,7 @@ void run_autodoc(const std::string &target_dir) { codeview_panel->show(); Fl::wait(0.2); Fl::flush(); - update_codeview_cb(NULL, NULL); // must be visible on screen for this to work + update_codeview_cb(nullptr, nullptr); // must be visible on screen for this to work cv_tab->value(cv_source_tab); codeview_panel->redraw(); Fl::flush(); @@ -487,41 +487,41 @@ void run_autodoc(const std::string &target_dir) { // ---- dialog types // list and show all non-widget types and their respective dialog boxes - // -- ID_Function + // -- Type::Function Fl_Window *adoc_function_panel = make_function_panel(); f_name_input->value("count_trees(const char *forest_name)"); f_return_type_input->value("unsigned int"); fl_snapshot((target_dir + "function_panel.png").c_str(), adoc_function_panel, win_margin, win_blend); adoc_function_panel->hide(); - // -- ID_Code + // -- Type::Code Fl_Window *adoc_code_panel = make_code_panel(); code_input->buffer()->text("// increment user count\nif (new_user) {\n user_count++;\n}\n"); fl_snapshot((target_dir + "code_panel.png").c_str(), adoc_code_panel, win_margin, win_blend); adoc_code_panel->hide(); - // -- ID_CodeBlock + // -- Type::CodeBlock Fl_Window *adoc_codeblock_panel = make_codeblock_panel(); code_before_input->value("if (test())"); code_after_input->value("// test widgets added..."); fl_snapshot((target_dir + "codeblock_panel.png").c_str(), adoc_codeblock_panel, win_margin, win_blend); adoc_codeblock_panel->hide(); - // -- ID_Decl + // -- Type::Decl Fl_Window *adoc_decl_panel = make_decl_panel(); decl_class_choice->hide(); decl_input->buffer()->text("const char *damage = \"'tis but a scratch\";"); fl_snapshot((target_dir + "decl_panel.png").c_str(), adoc_decl_panel, win_margin, win_blend); adoc_decl_panel->hide(); - // -- ID_DeclBlock + // -- Type::DeclBlock Fl_Window *adoc_declblock_panel = make_declblock_panel(); declblock_before_input->value("#ifdef NDEBUG"); declblock_after_input->value("#endif // NDEBUG"); fl_snapshot((target_dir + "declblock_panel.png").c_str(), adoc_declblock_panel, win_margin, win_blend); adoc_declblock_panel->hide(); - // -- ID_Class + // -- Type::Class Fl_Window *adoc_class_panel = make_class_panel(); decl_class_choice->hide(); c_name_input->value("Zoo_Giraffe"); @@ -529,15 +529,15 @@ void run_autodoc(const std::string &target_dir) { fl_snapshot((target_dir + "class_panel.png").c_str(), adoc_class_panel, win_margin, win_blend); adoc_class_panel->hide(); - // -- ID_Widget_Class is handled like Fl_Window_Type + // -- Type::Widget_Class is handled like Window_Node - // -- ID_Comment + // -- Type::Comment Fl_Window *adoc_comment_panel = make_comment_panel(); comment_input->buffer()->text("Make sure that the giraffe gets enough hay,\nbut the monkey can't reach it."); fl_snapshot((target_dir + "comment_panel.png").c_str(), adoc_comment_panel, win_margin, win_blend); adoc_comment_panel->hide(); - // -- ID_Data + // -- Type::Data Fl_Window *adoc_data_panel = make_data_panel(); data_class_choice->hide(); data_input->value("emulated_ROM"); diff --git a/fluid/tools/autodoc.h b/fluid/tools/autodoc.h index 33b0bd6fc..136a7e119 100644 --- a/fluid/tools/autodoc.h +++ b/fluid/tools/autodoc.h @@ -1,5 +1,5 @@ // -// Widget snapshot header-only file for the Fast Light Tool Kit (FLTK). +// Self-generate snapshots of user interface for FLUID documentation. // // Copyright 2023-2025 by Bill Spitzak and others. // diff --git a/fluid/tools/filename.cxx b/fluid/tools/filename.cxx index bbd749ce1..a5d6e22b3 100644 --- a/fluid/tools/filename.cxx +++ b/fluid/tools/filename.cxx @@ -1,7 +1,7 @@ // -// Filename expansion routines for the Fast Light Tool Kit (FLTK). +// Filename handling code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2025 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 @@ -95,3 +95,31 @@ std::string fl_filename_shortened(const std::string &filename, int max_chars) { return homed_filename; } } + +/** + Make sure that a path name ends with a forward slash. + \param[in] str directory or path name + \return a new string, ending with a '/' + */ +std::string fld::end_with_slash(const std::string &str) { + char last = str[str.size()-1]; + if (last !='/' && last != '\\') + return str + "/"; + else + return str; +} + +/** + Replace Windows '\\' directory separator with UNix '/' separators. + \param[in] fn a file path in Unix or Windows format + \return a copy of the file path in Unix format. + */ +std::string fld::fix_separators(const std::string &fn) { + std::string ret = fn; + for (size_t i=0; i