diff --git a/fluid/app/Image_Asset.cxx b/fluid/app/Image_Asset.cxx deleted file mode 100644 index e9ef17d2e..000000000 --- a/fluid/app/Image_Asset.cxx +++ /dev/null @@ -1,489 +0,0 @@ -// -// Image Helper code for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2026 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 "proj/Image_Asset.h" - -#include "Fluid.h" -#include "io/Project_Reader.h" -#include "io/Project_Writer.h" -#include "io/Code_Writer.h" -#include "nodes/Group_Node.h" -#include "nodes/Window_Node.h" -#include "tools/filename.h" - -#include -#include -#include -#include -#include // fl_fopen() -#include -#include -#include -#include "../src/flstring.h" - -#include -#include -#include -#include -#include -#include - - - -/** - \brief Write the contents of the image file as binary source code. - - Write the contents of the image file as C++ code, so the image is available in - the target app in the original binary format, for example: - ``` - { 1, 2, 3, ...} - ``` - \param f Write code to this C++ source code file - \param fmt short name of file contents for error message - \return 0 if the file could not be opened or read - */ -size_t Image_Asset::write_static_binary(fld::io::Code_Writer& f, const char* fmt) { - size_t nData = 0; - Fluid.proj.enter_project_dir(); - FILE *in = fl_fopen(filename(), "rb"); - Fluid.proj.leave_project_dir(); - if (!in) { - write_file_error(f, fmt); - return 0; - } else { - fseek(in, 0, SEEK_END); - nData = ftell(in); - fseek(in, 0, SEEK_SET); - if (nData) { - char *data = (char*)calloc(nData, 1); - if (fread(data, nData, 1, in)==0) { /* ignore */ } - f.write_cdata(data, (int)nData); - free(data); - } - fclose(in); - } - return nData; -} - - -/** - \brief Write the contents of the image file as text with escaped special characters. - - This function is only useful for writing out image formats that are ASCII text - based, like svg and pixmaps. Other formats should use write_static_binary(). - - \param f Write code to this C++ source code file - \param fmt short name of file contents for error message - \return 0 if the file could not be opened or read - */ -size_t Image_Asset::write_static_text(fld::io::Code_Writer& f, const char* fmt) { - size_t nData = 0; - Fluid.proj.enter_project_dir(); - FILE *in = fl_fopen(filename(), "rb"); - Fluid.proj.leave_project_dir(); - if (!in) { - write_file_error(f, fmt); - return 0; - } else { - fseek(in, 0, SEEK_END); - nData = ftell(in); - fseek(in, 0, SEEK_SET); - if (nData) { - char *data = (char*)calloc(nData+1, 1); - if (fread(data, nData, 1, in)==0) { /* ignore */ } - f.write_cstring(data, (int)nData); - free(data); - } - fclose(in); - } - return nData; -} - - -/** - \brief Write the contents of the image file as uncompressed RGB. - - Write source code that generates the uncompressed RGB image data at compile - time, and an initializer that creates the image at run time. - - \todo If the ld() value is not 0 and not d()*w(), the image data is not - written correctly. There is no check if the data is actually in RGB format. - - \param f Write code to this C++ source code file - \param fmt short name of file contents for error message - \return 0 if the file could not be opened or read - */ -void Image_Asset::write_static_rgb(fld::io::Code_Writer& f, const char* idata_name) { - // Write image data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - const int extra_data = image_->ld() ? (image_->ld()-image_->w()*image_->d()) : 0; - f.write_cdata(image_->data()[0], (image_->w() * image_->d() + extra_data) * image_->h()); - f.write_c(";\n"); - write_initializer(f, "Fl_RGB_Image", "%s, %d, %d, %d, %d", idata_name, image_->w(), image_->h(), image_->d(), image_->ld()); -} - - -/** - \brief Write the static image data into the source file. - - Write source code that generates the image data at compile time, and an - initializer that creates the image at run time. - - If \p compressed is set, write the original image format, which requires - linking the matching image reader at runtime, or if we want to store the raw - uncompressed pixels, which makes images fast, needs no reader, but takes a - lot of memory (current default for PNG) - - \param f Write code to this C++ source code file - \param compressed write data in the original compressed file format - */ -void Image_Asset::write_static(fld::io::Code_Writer& f, int compressed) { - if (!image_) return; - const char *idata_name = f.unique_id(this, "idata", fl_filename_name(filename()), nullptr); - initializer_function_ = f.unique_id(this, "image", fl_filename_name(filename()), nullptr); - - if (is_animated_gif_) { - // Write animated gif image data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - size_t nData = write_static_binary(f, "AnimGIF"); - f.write_c(";\n"); - write_initializer(f, "Fl_Anim_GIF_Image", "\"%s\", %s, %d", fl_filename_name(filename()), idata_name, nData); - } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(filename()), ".gif")==0) { - // Write gif image data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - size_t nData = write_static_binary(f, "GIF"); - f.write_c(";\n"); - write_initializer(f, "Fl_GIF_Image", "\"%s\", %s, %d", fl_filename_name(filename()), idata_name, nData); - } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(filename()), ".bmp")==0) { - // Write bmp image data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - size_t nData = write_static_binary(f, "BMP"); - f.write_c(";\n"); - write_initializer(f, "Fl_BMP_Image", "\"%s\", %s, %d", fl_filename_name(filename()), idata_name, nData); - } else if (image_->count() > 1) { - // Write Pixmap data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const char* %s[] = {\n", idata_name); - f.write_cstring(image_->data()[0], (int)strlen(image_->data()[0])); - - int i; - int ncolors, chars_per_color; - sscanf(image_->data()[0], "%*d%*d%d%d", &ncolors, &chars_per_color); - - if (ncolors < 0) { - f.write_c(",\n"); - f.write_cstring(image_->data()[1], ncolors * -4); - i = 2; - } else { - for (i = 1; i <= ncolors; i ++) { - f.write_c(",\n"); - f.write_cstring(image_->data()[i], (int)strlen(image_->data()[i])); - } - } - for (; i < image_->count(); i ++) { - f.write_c(",\n"); - f.write_cstring(image_->data()[i], image_->w() * chars_per_color); - } - f.write_c("\n};\n"); - write_initializer(f, "Fl_Pixmap", "%s", idata_name); - } else if (image_->d() == 0) { - // Write Bitmap data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - f.write_cdata(image_->data()[0], ((image_->w() + 7) / 8) * image_->h()); - f.write_c(";\n"); - write_initializer(f, "Fl_Bitmap", "%s, %d, %d, %d", idata_name, ((image_->w() + 7) / 8) * image_->h(), image_->w(), image_->h()); - } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(filename()), ".jpg")==0) { - // Write jpeg image data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - size_t nData = write_static_binary(f, "JPEG"); - f.write_c(";\n"); - write_initializer(f, "Fl_JPEG_Image", "\"%s\", %s, %d", fl_filename_name(filename()), idata_name, nData); - } else if (compressed && fl_ascii_strcasecmp(fl_filename_ext(filename()), ".png")==0) { - // Write png image data... - f.write_c("\n"); - f.write_c_once("#include \n"); - f.write_c("static const unsigned char %s[] =\n", idata_name); - size_t nData = write_static_binary(f, "PNG"); - f.write_c(";\n"); - write_initializer(f, "Fl_PNG_Image", "\"%s\", %s, %d", fl_filename_name(filename()), idata_name, nData); - } -#ifdef FLTK_USE_SVG - else if (fl_ascii_strcasecmp(fl_filename_ext(filename()), ".svg")==0 || fl_ascii_strcasecmp(fl_filename_ext(filename()), ".svgz")==0) { - bool gzipped = (strcmp(fl_filename_ext(filename()), ".svgz") == 0); - // Write svg image data... - if (compressed) { - f.write_c("\n"); - f.write_c_once("#include \n"); - if (gzipped) { - f.write_c("static const unsigned char %s[] =\n", idata_name); - size_t nData = write_static_binary(f, "SVGZ"); - f.write_c(";\n"); - write_initializer(f, "Fl_SVG_Image", "\"%s\", %s, %ld", fl_filename_name(filename()), idata_name, nData); - } else { - f.write_c("static const char %s[] =\n", idata_name); - write_static_text(f, "SVG"); - f.write_c(";\n"); - write_initializer(f, "Fl_SVG_Image", "\"%s\", %s", fl_filename_name(filename()), idata_name); - } - } else { - // if FLUID runs from the command line, make sure that the image is not - // only loaded but also rasterized, so we can write the RGB image data - Fl_RGB_Image* rgb_image = nullptr; - Fl_SVG_Image* svg_image = nullptr; - if (image_->d()>0) - rgb_image = (Fl_RGB_Image*)image_->image(); - if (rgb_image) - svg_image = rgb_image->as_svg_image(); - if (svg_image) { - svg_image->resize(svg_image->w(), svg_image->h()); - write_static_rgb(f, idata_name); - } else { - write_file_error(f, "RGB_from_SVG"); - } - } - } -#endif // FLTK_USE_SVG - else { - write_static_rgb(f, idata_name); - } -} - - -/** - \brief Write a warning message to the generated code file that the image asset - can't be read. - - This writes a #warning directive to the generated code file which contains the - filename of the image asset and the error message as returned by strerror(errno). - The current working directory is also printed for debugging purposes. - \param f The C++ source code file to write the warning message to. - \param fmt The format string for the image file type. - */ -void Image_Asset::write_file_error(fld::io::Code_Writer& f, const char *fmt) { - f.write_c("#warning Cannot read %s file \"%s\": %s\n", fmt, filename(), strerror(errno)); - Fluid.proj.enter_project_dir(); - f.write_c("// Searching in path \"%s\"\n", fl_getcwd(nullptr, FL_PATH_MAX)); - Fluid.proj.leave_project_dir(); -} - - -/** - \brief Outputs code that loads and returns an Fl_Image. - - The generated code loads the image if it hasn't been loaded yet, and then - returns a pointer to the image. - - \code - static Fl_Image *'initializer_function_'() { - static Fl_Image *image = 0L; - if (!image) - image = new 'type_name'('product of format and remaining args'); - return image; - } - \endcode - - \param f Write the C++ code to this file. - \param image_class Name of the Fl_Image class, for example Fl_GIF_Image. - \param format Format string for additional parameters for the constructor. - */ -void Image_Asset::write_initializer(fld::io::Code_Writer& f, const char *image_class, const char *format, ...) { - va_list ap; - va_start(ap, format); - f.write_c("static Fl_Image* %s() {\n", initializer_function_.c_str()); - if (is_animated_gif_) - f.write_c("%sFl_GIF_Image::animate = true;\n", f.indent(1)); - f.write_c("%sstatic Fl_Image* image = nullptr;\n", f.indent(1)); - f.write_c("%sif (!image)\n", f.indent(1)); - f.write_c("%simage = new %s(", f.indent(2), image_class); - f.vwrite_c(format, ap); - f.write_c(");\n"); - f.write_c("%sreturn image;\n", f.indent(1)); - f.write_c("}\n"); - va_end(ap); -} - - -/** - \brief Outputs code that attaches an image to an Fl_Widget or Fl_Menu_Item. - - The generated code will call the image initializer function and assign - the resulting image to the widget. - - \param f Write the C++ code to this file. - \param bind If true, use bind_image() instead of image(). - \param var Name of the Fl_Widget or Fl_Menu_Item to attach the image to. - \param inactive If true, use deimage() instead of image(). - */ -void Image_Asset::write_code(fld::io::Code_Writer& f, int bind, const char *var, int inactive) { - if (image_) { - f.write_c("%s%s->%s%s( %s() );\n", - f.indent(), - var, - bind ? "bind_" : "", - inactive ? "deimage" : "image", - initializer_function_.c_str()); - if (is_animated_gif_) - f.write_c("%s((Fl_Anim_GIF_Image*)(%s()))->canvas(%s, Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS);\n", - f.indent(), - initializer_function_.c_str(), - var); - } -} - - -/** - \brief Outputs code that calls the image initializer function. - - The generated code calls the image initializer function, loading an image and - assigning it to a Fl_Menu_Item. - - \param f Write the C++ code to this file. - \param inactive Unused. - */ -void Image_Asset::write_inline(fld::io::Code_Writer& f, int inactive) { - (void)inactive; - if (image_) { - f.write_c("%s()", initializer_function_.c_str()); - } -} - - -/** - \brief Finds an image asset by filename. - - If the image asset has already been loaded, it is returned from the cache. - If the image asset has not been loaded, it is loaded from the file system. - If the image asset cannot be loaded, nullptr is returned. - - \param iname The filename of the image asset to find. - \returns The image asset, or nullptr if it cannot be loaded. - */ -std::shared_ptr Image_Asset::find(const std::string& iname) { - if (iname.empty()) return nullptr; - - // First search to see if it exists already. If it does, return it. - auto existing = Fluid.proj.image_assets.find(iname); - if (existing) return existing; - - // Check if a file by that name exists. - Fluid.proj.enter_project_dir(); - FILE *f = fl_fopen(iname.c_str(),"rb"); - if (!f) { - if (Fluid.batch_mode) - fprintf(stderr, "Can't open image file:\n%s\n%s", iname.c_str(), strerror(errno)); - else - fl_message("Can't open image file:\n%s\n%s", iname.c_str(), strerror(errno)); - Fluid.proj.leave_project_dir(); - return nullptr; - } - fclose(f); - - // We found the file. Create the asset. - std::shared_ptr asset(new Image_Asset(iname)); - if (!asset->image_ || !asset->image_->w() || !asset->image_->h()) { - if (Fluid.batch_mode) - fprintf(stderr, "Can't read image file:\n%s\nunrecognized image format", iname.c_str()); - else - fl_message("Can't read image file:\n%s\nunrecognized image format", iname.c_str()); - Fluid.proj.leave_project_dir(); - return nullptr; - } - - // Add the new asset to our image asset map and return it to the caller. - Fluid.proj.image_assets.insert(iname, asset); - Fluid.proj.leave_project_dir(); - return asset; -} - -/** - \brief Construct an image asset from a file in the project directory. - - \param iname The name of the image file in the project directory. -*/ -Image_Asset::Image_Asset(const std::string& iname) -{ - filename_ = iname; - image_.reset(Fl_Shared_Image::get(iname.c_str())); - if (image_ && !iname.empty()) { - std::string ext = fl_filename_ext_str(iname); - if (fl_ascii_strcasecmp(ext.c_str(), ".gif")==0) { - int fc = Fl_Anim_GIF_Image::frame_count(iname.c_str()); - if (fc > 0) is_animated_gif_ = true; - } - } -} - -/** - \brief Destructor for the Image_Asset class. - - This destructor removes the image asset from the global image asset map - and releases the associated shared image if it exists. It ensures that - any resources associated with the Image_Asset are properly cleaned up - when the object is destroyed. -*/ -Image_Asset::~Image_Asset() { - Fluid.proj.image_assets.erase(filename_); -} - -//////////////////////////////////////////////////////////////// - -/** - \brief Displays a file chooser for the user to select an image file. - - This function displays a file chooser dialog with the title "Image?" and - the current working directory set to the project directory. The file - chooser displays files with the extensions .bm, .bmp, .gif, .jpg, .pbm, - .pgm, .png, .ppm, .xbm, .xpm, and .svg (and .svgz if zlib support is - enabled). The function returns a pointer to an Image_Asset object that - references the selected image. If the user cancels the file chooser or - selects a file that does not exist, the function returns nullptr. - - \param oldname The default filename to display in the file chooser. - - \return A pointer to an Image_Asset object that references the selected - image, or nullptr if the user cancels the file chooser or selects a file - that does not exist. The asset is automaticly added to the global image - asset map. -*/ -std::shared_ptr ui_find_image(const char *oldname) { - Fluid.proj.enter_project_dir(); - fl_file_chooser_ok_label("Use Image"); - const char *name = fl_file_chooser("Image?", - "Image Files (*.{bm,bmp,gif,jpg,pbm,pgm,png,ppm,xbm,xpm,svg" -#ifdef HAVE_LIBZ - ",svgz" -#endif - "})", - oldname,1); - fl_file_chooser_ok_label(nullptr); - std::shared_ptr ret = (name && *name) ? Image_Asset::find(name) : nullptr; - Fluid.proj.leave_project_dir(); - return ret; -} - diff --git a/fluid/app/args.cxx b/fluid/app/args.cxx index b9d958e8c..9638611b8 100644 --- a/fluid/app/args.cxx +++ b/fluid/app/args.cxx @@ -32,6 +32,10 @@ using namespace fld::app; \param[in] argv pointer to an array of arguments \return 0 if the args were handled successfully, -1 if there was an error and the usage message was shown. + + \todo argument to override the application directory, helpful when running in batch mode + \todo argument to run a specific shell command as set in shell_command list + \todo maybe argument to extract embedded files, i.e. CMakeLists.txt ? */ int Args::load(int argc,char **argv) { int i = 1; diff --git a/fluid/nodes/Widget_Node.cxx b/fluid/nodes/Widget_Node.cxx index 8c6c2c00c..ae93edfd6 100644 --- a/fluid/nodes/Widget_Node.cxx +++ b/fluid/nodes/Widget_Node.cxx @@ -1181,7 +1181,7 @@ void live_mode_cb(Fl_Button* o, void *) { static Fl_Window* live_window = nullptr; if (!current_widget) { - o->value(0); + wLiveMode->value(0); return; }