diff options
Diffstat (limited to 'fluid/io')
| -rw-r--r-- | fluid/io/Code_Writer.cxx | 79 | ||||
| -rw-r--r-- | fluid/io/Code_Writer.h | 18 | ||||
| -rw-r--r-- | fluid/io/Project_Reader.cxx | 266 | ||||
| -rw-r--r-- | fluid/io/Project_Reader.h | 45 | ||||
| -rw-r--r-- | fluid/io/Project_Writer.cxx | 771 | ||||
| -rw-r--r-- | fluid/io/Project_Writer.h | 61 |
6 files changed, 117 insertions, 1123 deletions
diff --git a/fluid/io/Code_Writer.cxx b/fluid/io/Code_Writer.cxx index b77cad147..cbd6443e2 100644 --- a/fluid/io/Code_Writer.cxx +++ b/fluid/io/Code_Writer.cxx @@ -14,30 +14,21 @@ // https://www.fltk.org/bugs.php // -#include "io/code.h" +#include "io/Code_Writer.h" -#include "app/fluid.h" -#include "app/undo.h" -#include "io/file.h" -#include "nodes/Fl_Group_Type.h" +#include "app/project.h" #include "nodes/Fl_Window_Type.h" #include "nodes/Fl_Function_Type.h" -#include "tools/fluid_filename.h" -#include <FL/Fl.H> -#include <FL/fl_string_functions.h> -#include <FL/fl_ask.H> #include "../src/flstring.h" -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - #include <zlib.h> /// \defgroup cfile C Code File Operations /// \{ +using namespace fld; +using namespace fld::io; /** Return true if c can be in a C identifier. @@ -201,9 +192,9 @@ Fd_Identifier_Tree::~Fd_Identifier_Tree() { \param[in] type is the first word of the ID \param[in] name if name is set, it is appended to the ID \param[in] label else if label is set, it is appended, skipping non-keyword characters - \return buffer to a unique identifier, managed by Fd_Code_Writer, so caller must NOT free() it + \return buffer to a unique identifier, managed by Code_Writer, so caller must NOT free() it */ -const char* Fd_Code_Writer::unique_id(void* o, const char* type, const char* name, const char* label) { +const char* Code_Writer::unique_id(void* o, const char* type, const char* name, const char* label) { char buffer[128]; char* q = buffer; char* q_end = q + 128 - 8 - 1; // room for hex number and NUL @@ -253,7 +244,7 @@ const char* Fd_Code_Writer::unique_id(void* o, const char* type, const char* nam \param[in] set generate this indent depth \return pointer to a static string */ -const char *Fd_Code_Writer::indent(int set) { +const char *Code_Writer::indent(int set) { static const char* spaces = " "; int i = set * 2; if (i>32) i = 32; @@ -265,7 +256,7 @@ const char *Fd_Code_Writer::indent(int set) { Return a C string that indents code to the current source file depth. \return pointer to a static string */ -const char *Fd_Code_Writer::indent() { +const char *Code_Writer::indent() { return indent(indentation); } @@ -275,7 +266,7 @@ const char *Fd_Code_Writer::indent() { change the `indentation` variable; offset can be negative \return pointer to a static string */ -const char *Fd_Code_Writer::indent_plus(int offset) { +const char *Code_Writer::indent_plus(int offset) { return indent(indentation+offset); } @@ -325,7 +316,7 @@ Fd_Pointer_Tree::~Fd_Pointer_Tree() { \param[in] format printf-style formatting text, followed by a vararg list \return 1 if the text was written to the file, 0 if it was previously written. */ -int Fd_Code_Writer::write_h_once(const char *format, ...) { +int Code_Writer::write_h_once(const char *format, ...) { va_list args; char buf[1024]; va_start(args, format); @@ -349,7 +340,7 @@ int Fd_Code_Writer::write_h_once(const char *format, ...) { \param[in] format printf-style formatting text, followed by a vararg list \return 1 if the text was written to the file, 0 if it was previously written. */ -int Fd_Code_Writer::write_c_once(const char *format, ...) { +int Code_Writer::write_c_once(const char *format, ...) { va_list args; char buf[1024]; va_start(args, format); @@ -380,7 +371,7 @@ int Fd_Code_Writer::write_c_once(const char *format, ...) { \param[in] pp ay pointer \return true if found in the tree, false if added to the tree */ -bool Fd_Code_Writer::c_contains(void *pp) { +bool Code_Writer::c_contains(void *pp) { Fd_Pointer_Tree **p = &ptr_in_code; while (*p) { if ((*p)->ptr == pp) return true; @@ -408,7 +399,7 @@ bool Fd_Code_Writer::c_contains(void *pp) { \see f.write_cstring(const char*) */ -void Fd_Code_Writer::write_cstring(const char *s, int length) { +void Code_Writer::write_cstring(const char *s, int length) { const char *next_line = "\"\n\""; if (varused_test) { varused = 1; @@ -489,7 +480,7 @@ void Fd_Code_Writer::write_cstring(const char *s, int length) { \param[in] s write this string \see f.write_cstring(const char*, int) */ -void Fd_Code_Writer::write_cstring(const char *s) { +void Code_Writer::write_cstring(const char *s) { write_cstring(s, (int)strlen(s)); } @@ -501,7 +492,7 @@ void Fd_Code_Writer::write_cstring(const char *s) { \param[in] s a block of binary data, interpreted as unsigned bytes \param[in] length size of the block in bytes */ -void Fd_Code_Writer::write_cdata(const char *s, int length) { +void Code_Writer::write_cdata(const char *s, int length) { if (varused_test) { varused = 1; return; @@ -539,7 +530,7 @@ void Fd_Code_Writer::write_cdata(const char *s, int length) { \param[in] format printf-style formatting text \param[in] args list of arguments */ -void Fd_Code_Writer::vwrite_c(const char* format, va_list args) { +void Code_Writer::vwrite_c(const char* format, va_list args) { if (varused_test) { varused = 1; return; @@ -551,7 +542,7 @@ void Fd_Code_Writer::vwrite_c(const char* format, va_list args) { Print a formatted line to the source file. \param[in] format printf-style formatting text, followed by a vararg list */ -void Fd_Code_Writer::write_c(const char* format,...) { +void Code_Writer::write_c(const char* format,...) { va_list args; va_start(args, format); vwrite_c(format, args); @@ -566,7 +557,7 @@ void Fd_Code_Writer::write_c(const char* format,...) { \param[in] c line of code \param[in] com optional commentary */ -void Fd_Code_Writer::write_cc(const char *indent, int n, const char *c, const char *com) { +void Code_Writer::write_cc(const char *indent, int n, const char *c, const char *com) { write_c("%s%.*s", indent, n, c); char cc = c[n-1]; if (cc!='}' && cc!=';') @@ -580,7 +571,7 @@ void Fd_Code_Writer::write_cc(const char *indent, int n, const char *c, const ch Print a formatted line to the header file. \param[in] format printf-style formatting text, followed by a vararg list */ -void Fd_Code_Writer::write_h(const char* format,...) { +void Code_Writer::write_h(const char* format,...) { if (varused_test) return; va_list args; va_start(args, format); @@ -596,7 +587,7 @@ void Fd_Code_Writer::write_h(const char* format,...) { \param[in] c line of code \param[in] com optional commentary */ -void Fd_Code_Writer::write_hc(const char *indent, int n, const char* c, const char *com) { +void Code_Writer::write_hc(const char *indent, int n, const char* c, const char *com) { write_h("%s%.*s", indent, n, c); char cc = c[n-1]; if (cc!='}' && cc!=';') @@ -613,7 +604,7 @@ void Fd_Code_Writer::write_hc(const char *indent, int n, const char* c, const ch \param[in] inTrailWith append this character if the last line did not end with a newline, usually 0 or newline. */ -void Fd_Code_Writer::write_c_indented(const char *textlines, int inIndent, char inTrailWith) { +void Code_Writer::write_c_indented(const char *textlines, int inIndent, char inTrailWith) { if (textlines) { indentation += inIndent; for (;;) { @@ -686,7 +677,7 @@ bool is_comment_before_class_member(Fl_Type *q) { \param[in] p write this type and all its children \return pointer to the next sibling */ -Fl_Type* Fd_Code_Writer::write_static(Fl_Type* p) { +Fl_Type* Code_Writer::write_static(Fl_Type* p) { if (write_codeview) p->header_static_start = (int)ftell(header_file); if (write_codeview) p->code_static_start = (int)ftell(code_file); p->write_static(*this); @@ -708,7 +699,7 @@ Fl_Type* Fd_Code_Writer::write_static(Fl_Type* p) { \param[in] p write this type and all its children \return pointer to the next sibling */ -Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) { +Fl_Type* Code_Writer::write_code(Fl_Type* p) { // write all code that comes before the children code // (but don't write the last comment until the very end) if (!(p==Fl_Type::last && p->is_a(ID_Comment))) { @@ -777,7 +768,7 @@ Fl_Type* Fd_Code_Writer::write_code(Fl_Type* p) { \param[in] t filename of the header file \return 0 if the operation failed, 1 if it was successful */ -int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_codeview) { +int Code_Writer::write_code(const char *s, const char *t, bool to_codeview) { write_codeview = to_codeview; delete id_root; id_root = 0; indentation = 0; @@ -939,7 +930,7 @@ int Fd_Code_Writer::write_code(const char *s, const char *t, bool to_codeview) { This avoids repeating these words if the mode is already set. \param[in] state 0 for private, 1 for public, 2 for protected */ -void Fd_Code_Writer::write_public(int state) { +void Code_Writer::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; @@ -955,7 +946,7 @@ void Fd_Code_Writer::write_public(int state) { /** Create and initialize a new C++ source code writer. */ -Fd_Code_Writer::Fd_Code_Writer() +Code_Writer::Code_Writer() : code_file(NULL), header_file(NULL), id_root(NULL), @@ -977,7 +968,7 @@ Fd_Code_Writer::Fd_Code_Writer() /** Release all resources. */ -Fd_Code_Writer::~Fd_Code_Writer() +Code_Writer::~Code_Writer() { delete id_root; delete ptr_in_code; @@ -994,7 +985,7 @@ Fd_Code_Writer::~Fd_Code_Writer() \param[in] type FD_TAG_GENERIC, FD_TAG_CODE, FD_TAG_MENU_CALLBACK, or FD_TAG_WIDGET_CALLBACK \param[in] uid the unique id of the current type */ -void Fd_Code_Writer::tag(int type, unsigned short uid) { +void Code_Writer::tag(int type, unsigned short uid) { if (g_project.write_mergeback_data) fprintf(code_file, "//~fl~%d~%04x~%08x~~\n", type, (int)uid, (unsigned int)block_crc_); block_crc_ = crc32(0, NULL, 0); @@ -1011,7 +1002,7 @@ void Fd_Code_Writer::tag(int type, unsigned short uid) { if we are the start of a line, used to find leading whitespace \return the new CRC */ -unsigned long Fd_Code_Writer::block_crc(const void *data, int n, unsigned long in_crc, bool *inout_line_start) { +unsigned long Code_Writer::block_crc(const void *data, int n, unsigned long in_crc, bool *inout_line_start) { if (!data) return 0; if (n==-1) n = (int)strlen((const char*)data); bool line_start = true; @@ -1038,7 +1029,7 @@ unsigned long Fd_Code_Writer::block_crc(const void *data, int n, unsigned long i \param[in] data a pointer to the data block \param[in] n the size of the data in bytes, or -1 to use strlen() */ -void Fd_Code_Writer::crc_add(const void *data, int n) { +void Code_Writer::crc_add(const void *data, int n) { block_crc_ = block_crc(data, n, block_crc_, &block_line_start_); } @@ -1047,7 +1038,7 @@ void Fd_Code_Writer::crc_add(const void *data, int n) { \param[in] format printf style formatting string \return see fprintf(FILE *, *const char*, ...) */ -int Fd_Code_Writer::crc_printf(const char *format, ...) { +int Code_Writer::crc_printf(const char *format, ...) { va_list args; va_start(args, format); int ret = crc_vprintf(format, args); @@ -1061,7 +1052,7 @@ int Fd_Code_Writer::crc_printf(const char *format, ...) { \param[in] args list of arguments \return see fprintf(FILE *, *const char*, ...) */ -int Fd_Code_Writer::crc_vprintf(const char *format, va_list args) { +int Code_Writer::crc_vprintf(const char *format, va_list args) { if (g_project.write_mergeback_data) { int n = vsnprintf(block_buffer_, block_buffer_size_, format, args); if (n > block_buffer_size_) { @@ -1082,7 +1073,7 @@ int Fd_Code_Writer::crc_vprintf(const char *format, va_list args) { \param[in] text any text, no requirements to end in a newline or such \return see fputs(const char*, FILE*) */ -int Fd_Code_Writer::crc_puts(const char *text) { +int Code_Writer::crc_puts(const char *text) { if (g_project.write_mergeback_data) { crc_add(text); } @@ -1091,11 +1082,11 @@ int Fd_Code_Writer::crc_puts(const char *text) { /** Write a single ASCII character to the code file. If MergeBack is enabled, the CRC calculation is continued. - \note to write UTF-8 characters, use Fd_Code_Writer::crc_puts(const char *text) + \note to write UTF-8 characters, use Code_Writer::crc_puts(const char *text) \param[in] c any character between 0 and 127 inclusive \return see fputc(int, FILE*) */ -int Fd_Code_Writer::crc_putc(int c) { +int Code_Writer::crc_putc(int c) { if (g_project.write_mergeback_data) { uchar uc = (uchar)c; crc_add(&uc, 1); diff --git a/fluid/io/Code_Writer.h b/fluid/io/Code_Writer.h index 758e7bf45..b4a6518b4 100644 --- a/fluid/io/Code_Writer.h +++ b/fluid/io/Code_Writer.h @@ -14,8 +14,8 @@ // https://www.fltk.org/bugs.php // -#ifndef _FLUID_CODE_H -#define _FLUID_CODE_H +#ifndef FLUID_IO_CODE_WRITER_H +#define FLUID_IO_CODE_WRITER_H #include <FL/fl_attr.h> @@ -31,7 +31,10 @@ struct Fd_Pointer_Tree; int is_id(char c); int write_strings(const std::string &filename); -class Fd_Code_Writer +namespace fld { +namespace io { + +class Code_Writer { protected: /// file pointer for the C++ code file @@ -77,8 +80,8 @@ public: int varused; public: - Fd_Code_Writer(); - ~Fd_Code_Writer(); + Code_Writer(); + ~Code_Writer(); const char* unique_id(void* o, const char*, const char*, const char*); /// Increment source code indentation level. void indent_more() { indentation++; } @@ -109,4 +112,7 @@ public: static unsigned long block_crc(const void *data, int n=-1, unsigned long in_crc=0, bool *inout_line_start=NULL); }; -#endif // _FLUID_CODE_H +} // namespace io +} // namespace fld + +#endif // FLUID_IO_CODE_WRITER_H diff --git a/fluid/io/Project_Reader.cxx b/fluid/io/Project_Reader.cxx index ba1afeb1b..ff88238ba 100644 --- a/fluid/io/Project_Reader.cxx +++ b/fluid/io/Project_Reader.cxx @@ -19,37 +19,33 @@ // https://www.fltk.org/bugs.php // -#include "io/file.h" +#include "io/Project_Reader.h" #include "app/fluid.h" +#include "app/project.h" #include "app/shell_command.h" #include "app/undo.h" -#include "io/code.h" +#include "app/Fd_Snap_Action.h" #include "nodes/factory.h" #include "nodes/Fl_Function_Type.h" #include "nodes/Fl_Widget_Type.h" #include "nodes/Fl_Grid_Type.h" #include "nodes/Fl_Window_Type.h" -#include "panels/settings_panel.h" #include "widgets/Node_Browser.h" -#include <FL/Fl.H> -#include <FL/Fl_Group.H> -#include <FL/fl_string_functions.h> +#include <FL/Fl_Window.H> #include <FL/fl_message.H> -#include "../src/flstring.h" - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> /// \defgroup flfile .fl Project File Operations /// \{ +using namespace fld; +using namespace fld::io; + // This file contains code to read and write .fl files. /// If set, we read an old fdesign file and widget y coordinates need to be flipped. -int fdesign_flip = 0; +int fld::io::fdesign_flip = 0; /** \brief Read a .fl project file. @@ -61,26 +57,12 @@ int fdesign_flip = 0; \param[in] strategy add new nodes after current or as last child \return 0 if the operation failed, 1 if it succeeded */ -int read_file(const char *filename, int merge, Strategy strategy) { - Fd_Project_Reader f; +int fld::io::read_file(const char *filename, int merge, Strategy strategy) { + Project_Reader f; strategy.source(Strategy::FROM_FILE); return f.read_project(filename, merge, strategy); } -/** \brief Write an .fl design description file. - - The .fl file format is documented in `fluid/README_fl.txt`. - - \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. - \return 0 if the operation failed, 1 if it succeeded - */ -int write_file(const char *filename, int selected_only, bool to_codeview) { - Fd_Project_Writer out; - return out.write_project(filename, selected_only, to_codeview); -} - /** Convert a single ASCII char, assumed to be a hex digit, into its decimal value. \param[in] x ASCII character @@ -94,14 +76,14 @@ static int hexdigit(int x) { return 20; } -// ---- Fd_Project_Reader ---------------------------------------------- MARK: - +// ---- Project_Reader ---------------------------------------------- MARK: - /** A simple growing buffer. Oh how I wish sometimes we would upgrade to modern C++. \param[in] length minimum length in bytes */ -void Fd_Project_Reader::expand_buffer(int length) { +void Project_Reader::expand_buffer(int length) { if (length >= buflen) { if (!buflen) { buflen = length+1; @@ -115,7 +97,7 @@ void Fd_Project_Reader::expand_buffer(int length) { } /** \brief Construct local project reader. */ -Fd_Project_Reader::Fd_Project_Reader() +Project_Reader::Project_Reader() : fin(NULL), lineno(0), fname(NULL), @@ -126,7 +108,7 @@ Fd_Project_Reader::Fd_Project_Reader() } /** \brief Release project reader resources. */ -Fd_Project_Reader::~Fd_Project_Reader() +Project_Reader::~Project_Reader() { // fname is not copied, so do not free it if (buffer) @@ -138,7 +120,7 @@ Fd_Project_Reader::~Fd_Project_Reader() \param[in] s filename, if NULL, read from stdin instead \return 0 if the operation failed, 1 if it succeeded */ -int Fd_Project_Reader::open_read(const char *s) { +int Project_Reader::open_read(const char *s) { lineno = 1; if (!s) { fin = stdin; @@ -157,7 +139,7 @@ int Fd_Project_Reader::open_read(const char *s) { Close the .fl file. \return 0 if the operation failed, 1 if it succeeded */ -int Fd_Project_Reader::close_read() { +int Project_Reader::close_read() { if (fin != stdin) { int x = fclose(fin); fin = 0; @@ -170,7 +152,7 @@ int Fd_Project_Reader::close_read() { Return the name part of the current filename and path. \return a pointer into a string that is not owned by this class */ -const char *Fd_Project_Reader::filename_name() { +const char *Project_Reader::filename_name() { return fl_filename_name(fname); } @@ -180,7 +162,7 @@ const char *Fd_Project_Reader::filename_name() { values, and \\o### octal values. \return a character in the ASCII range */ -int Fd_Project_Reader::read_quoted() { // read whatever character is after a \ . +int Project_Reader::read_quoted() { // read whatever character is after a \ . int c,d,x; switch(c = nextchar()) { case '\n': lineno++; return -1; @@ -225,7 +207,7 @@ int Fd_Project_Reader::read_quoted() { // read whatever character is after a previous call, and there is no need to waste time searching for them. \return the last type that was created */ -Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strategy, char skip_options) { +Fl_Type *Project_Reader::read_children(Fl_Type *p, int merge, Strategy strategy, char skip_options) { Fl_Type::current = p; Fl_Type *last_child_read = NULL; Fl_Type *t = NULL; @@ -432,7 +414,7 @@ Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strate \param[in] strategy add new nodes after current or as last child \return 0 if the operation failed, 1 if it succeeded */ -int Fd_Project_Reader::read_project(const char *filename, int merge, Strategy strategy) { +int Project_Reader::read_project(const char *filename, int merge, Strategy strategy) { Fl_Type *o; undo_suspend(); read_version = 0.0; @@ -482,7 +464,7 @@ int Fd_Project_Reader::read_project(const char *filename, int merge, Strategy st operations. \param[in] format printf style format string, followed by an argument list */ -void Fd_Project_Reader::read_error(const char *format, ...) { +void Project_Reader::read_error(const char *format, ...) { va_list args; va_start(args, format); if (!fin) { // FIXME: this line suppresses any error messages in interactive mode @@ -515,7 +497,7 @@ void Fd_Project_Reader::read_error(const char *format, ...) { overwrite this buffer. If wantbrace is not set, but we read a leading '{', the returned string will be stripped of its leading and trailing braces. */ -const char *Fd_Project_Reader::read_word(int wantbrace) { +const char *Project_Reader::read_word(int wantbrace) { int x; // skip all the whitespace before it: @@ -585,7 +567,7 @@ const char *Fd_Project_Reader::read_word(int wantbrace) { /** Read a word and interpret it as an integer value. \return integer value, or 0 if the word is not an integer */ -int Fd_Project_Reader::read_int() { +int Project_Reader::read_int() { const char *word = read_word(); if (word) { return atoi(word); @@ -601,7 +583,7 @@ int Fd_Project_Reader::read_int() { \param[out] value string \return 0 if end of file, else 1 */ -int Fd_Project_Reader::read_fdesign_line(const char*& name, const char*& value) { +int Project_Reader::read_fdesign_line(const char*& name, const char*& value) { int length = 0; int x; // find a colon: @@ -727,7 +709,7 @@ static void forms_end(Fl_Group *g, int flip) { FLTK widgets. \see http://xforms-toolkit.org */ -void Fd_Project_Reader::read_fdesign() { +void Project_Reader::read_fdesign() { int fdesign_magic = atoi(read_word()); fdesign_flip = (fdesign_magic < 13000); Fl_Widget_Type *window = 0; @@ -782,202 +764,4 @@ void Fd_Project_Reader::read_fdesign() { } } -// ---- Fd_Project_Writer ---------------------------------------------- MARK: - - -/** \brief Construct local project writer. */ -Fd_Project_Writer::Fd_Project_Writer() -: fout(NULL), - needspace(0), - write_codeview_(false) -{ -} - -/** \brief Release project writer resources. */ -Fd_Project_Writer::~Fd_Project_Writer() -{ -} - -/** - Open the .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 - */ -int Fd_Project_Writer::open_write(const char *s) { - if (!s) { - fout = stdout; - } else { - FILE *f = fl_fopen(s,"wb"); - if (!f) return 0; - fout = f; - } - return 1; -} - -/** - Close the .fl design file. - Don't close, if data was sent to stdout. - \return 1 if succeeded, 0 if fclose failed - */ -int Fd_Project_Writer::close_write() { - if (fout != stdout) { - int x = fclose(fout); - fout = stdout; - return x >= 0; - } - return 1; -} - -/** \brief 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. - \param[in] sv if set, this file will be used by codeview - \return 0 if the operation failed, 1 if it succeeded - */ -int Fd_Project_Writer::write_project(const char *filename, int selected_only, bool sv) { - write_codeview_ = sv; - undo_suspend(); - if (!open_write(filename)) { - undo_resume(); - return 0; - } - write_string("# data file for the Fltk User Interface Designer (fluid)\n" - "version %.4f",FL_VERSION); - if(!g_project.include_H_from_C) - write_string("\ndo_not_include_H_from_C"); - if(g_project.use_FL_COMMAND) - write_string("\nuse_FL_COMMAND"); - if (g_project.utf8_in_src) - write_string("\nutf8_in_src"); - if (g_project.avoid_early_includes) - write_string("\navoid_early_includes"); - if (g_project.i18n_type) { - write_string("\ni18n_type %d", g_project.i18n_type); - switch (g_project.i18n_type) { - case FD_I18N_NONE: - break; - case FD_I18N_GNU : /* GNU gettext */ - write_string("\ni18n_include"); write_word(g_project.i18n_gnu_include.c_str()); - write_string("\ni18n_conditional"); write_word(g_project.i18n_gnu_conditional.c_str()); - write_string("\ni18n_gnu_function"); write_word(g_project.i18n_gnu_function.c_str()); - write_string("\ni18n_gnu_static_function"); write_word(g_project.i18n_gnu_static_function.c_str()); - break; - case FD_I18N_POSIX : /* POSIX catgets */ - write_string("\ni18n_include"); write_word(g_project.i18n_pos_include.c_str()); - write_string("\ni18n_conditional"); write_word(g_project.i18n_pos_conditional.c_str()); - if (!g_project.i18n_pos_file.empty()) { - write_string("\ni18n_pos_file"); - write_word(g_project.i18n_pos_file.c_str()); - } - write_string("\ni18n_pos_set"); write_word(g_project.i18n_pos_set.c_str()); - break; - } - } - - if (!selected_only) { - write_string("\nheader_name"); write_word(g_project.header_file_name.c_str()); - write_string("\ncode_name"); write_word(g_project.code_file_name.c_str()); - g_layout_list.write(this); - if (g_shell_config) - g_shell_config->write(this); - if (g_project.write_mergeback_data) - write_string("\nmergeback %d", g_project.write_mergeback_data); - } - - for (Fl_Type *p = Fl_Type::first; p;) { - if (!selected_only || p->selected) { - p->write(*this); - write_string("\n"); - int q = p->level; - for (p = p->next; p && p->level > q; p = p->next) {/*empty*/} - } else { - p = p->next; - } - } - int ret = close_write(); - undo_resume(); - return ret; -} - -/** - Write a string to the .fl file, quoting characters if necessary. - \param[in] w NUL terminated text - */ -void Fd_Project_Writer::write_word(const char *w) { - if (needspace) putc(' ', fout); - needspace = 1; - if (!w || !*w) {fprintf(fout,"{}"); return;} - const char *p; - // see if it is a single word: - for (p = w; is_id(*p); p++) ; - if (!*p) {fprintf(fout,"%s",w); return;} - // see if there are matching braces: - int n = 0; - for (p = w; *p; p++) { - if (*p == '{') n++; - else if (*p == '}') {n--; if (n<0) break;} - } - int mismatched = (n != 0); - // write out brace-quoted string: - putc('{', fout); - for (; *w; w++) { - switch (*w) { - case '{': - case '}': - if (!mismatched) break; - case '\\': - case '#': - putc('\\',fout); - break; - } - putc(*w,fout); - } - putc('}', fout); -} - -/** - 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. - \param[in] format printf style formatting string followed by a list of arguments - */ -void Fd_Project_Writer::write_string(const char *format, ...) { - va_list args; - va_start(args, format); - if (needspace && *format != '\n') fputc(' ',fout); - vfprintf(fout, format, args); - va_end(args); - needspace = !isspace(format[strlen(format)-1] & 255); -} - -/** - Start a new line in the .fl file and indent it for a given nesting level. - \param[in] n indent level - */ -void Fd_Project_Writer::write_indent(int n) { - fputc('\n',fout); - while (n--) {fputc(' ',fout); fputc(' ',fout);} - needspace = 0; -} - -/** - Write a '{' to the .fl file at the given indenting level. - */ -void Fd_Project_Writer::write_open() { - if (needspace) fputc(' ',fout); - fputc('{',fout); - needspace = 0; -} - -/** - Write a '}' to the .fl file at the given indenting level. - \param[in] n indent level - */ -void Fd_Project_Writer::write_close(int n) { - if (needspace) write_indent(n); - fputc('}',fout); - needspace = 1; -} - /// \} diff --git a/fluid/io/Project_Reader.h b/fluid/io/Project_Reader.h index 470cc1a7b..20928d25f 100644 --- a/fluid/io/Project_Reader.h +++ b/fluid/io/Project_Reader.h @@ -14,21 +14,26 @@ // https://www.fltk.org/bugs.php // -#ifndef _FLUID_FILE_H -#define _FLUID_FILE_H +#ifndef FLUID_IO_PROJECT_READER_H +#define FLUID_IO_PROJECT_READER_H #include "nodes/Fl_Type.h" #include <FL/fl_attr.h> +#include <stdio.h> + + class Fl_Type; +namespace fld { +namespace io { + extern int fdesign_flip; int read_file(const char *, int merge, Strategy strategy=Strategy::FROM_FILE_AS_LAST_CHILD); -int write_file(const char *, int selected_only = 0, bool to_codeview = false); -class Fd_Project_Reader +class Project_Reader { protected: /// Project input file @@ -51,8 +56,8 @@ public: double read_version; public: - Fd_Project_Reader(); - ~Fd_Project_Reader(); + Project_Reader(); + ~Project_Reader(); int open_read(const char *s); int close_read(); const char *filename_name(); @@ -66,29 +71,7 @@ public: void read_fdesign(); }; -class Fd_Project_Writer -{ -protected: - // Project output file, always opened in "wb" mode - FILE *fout; - /// If set, one space is written before text unless the format starts with a newline character - int needspace; - /// Set if this file will be used in the codeview dialog - bool write_codeview_; - -public: - Fd_Project_Writer(); - ~Fd_Project_Writer(); - int open_write(const char *s); - int close_write(); - int write_project(const char *filename, int selected_only, bool codeview); - void write_word(const char *); - void write_string(const char *,...) __fl_attr((__format__ (__printf__, 2, 3))); - void write_indent(int n); - void write_open(); - void write_close(int n); - FILE *file() const { return fout; } - bool write_codeview() const { return write_codeview_; } -}; +} // namespace io +} // namespace fld -#endif // _FLUID_FILE_H +#endif // FLUID_IO_PROJECT_READER_H diff --git a/fluid/io/Project_Writer.cxx b/fluid/io/Project_Writer.cxx index ba1afeb1b..26af62f37 100644 --- a/fluid/io/Project_Writer.cxx +++ b/fluid/io/Project_Writer.cxx @@ -19,53 +19,19 @@ // https://www.fltk.org/bugs.php // -#include "io/file.h" +#include "io/Project_Writer.h" #include "app/fluid.h" +#include "app/project.h" #include "app/shell_command.h" #include "app/undo.h" -#include "io/code.h" -#include "nodes/factory.h" -#include "nodes/Fl_Function_Type.h" -#include "nodes/Fl_Widget_Type.h" -#include "nodes/Fl_Grid_Type.h" -#include "nodes/Fl_Window_Type.h" -#include "panels/settings_panel.h" -#include "widgets/Node_Browser.h" - -#include <FL/Fl.H> -#include <FL/Fl_Group.H> -#include <FL/fl_string_functions.h> -#include <FL/fl_message.H> -#include "../src/flstring.h" - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> +#include "app/Fd_Snap_Action.h" /// \defgroup flfile .fl Project File Operations /// \{ -// This file contains code to read and write .fl files. - -/// If set, we read an old fdesign file and widget y coordinates need to be flipped. -int fdesign_flip = 0; - -/** \brief Read a .fl project file. - - The .fl file format is documented in `fluid/README_fl.txt`. - - \param[in] filename read this file - \param[in] merge if this is set, merge the file into an existing project - at Fl_Type::current - \param[in] strategy add new nodes after current or as last child - \return 0 if the operation failed, 1 if it succeeded - */ -int read_file(const char *filename, int merge, Strategy strategy) { - Fd_Project_Reader f; - strategy.source(Strategy::FROM_FILE); - return f.read_project(filename, merge, strategy); -} +using namespace fld; +using namespace fld::io; /** \brief Write an .fl design description file. @@ -76,716 +42,15 @@ int read_file(const char *filename, int merge, Strategy strategy) { is used to implement copy and paste. \return 0 if the operation failed, 1 if it succeeded */ -int write_file(const char *filename, int selected_only, bool to_codeview) { - Fd_Project_Writer out; +int fld::io::write_file(const char *filename, int selected_only, bool to_codeview) { + Project_Writer out; return out.write_project(filename, selected_only, to_codeview); } -/** - Convert a single ASCII char, assumed to be a hex digit, into its decimal value. - \param[in] x ASCII character - \return decimal value or 20 if character is not a valid hex digit (0..9,a..f,A..F) - */ -static int hexdigit(int x) { - if ((x < 0) || (x > 127)) return 20; - if (isdigit(x)) return x-'0'; - if (isupper(x)) return x-'A'+10; - if (islower(x)) return x-'a'+10; - return 20; -} - -// ---- Fd_Project_Reader ---------------------------------------------- MARK: - - -/** - A simple growing buffer. - Oh how I wish sometimes we would upgrade to modern C++. - \param[in] length minimum length in bytes - */ -void Fd_Project_Reader::expand_buffer(int length) { - if (length >= buflen) { - if (!buflen) { - buflen = length+1; - buffer = (char*)malloc(buflen); - } else { - buflen = 2*buflen; - if (length >= buflen) buflen = length+1; - buffer = (char *)realloc((void *)buffer,buflen); - } - } -} - -/** \brief Construct local project reader. */ -Fd_Project_Reader::Fd_Project_Reader() -: fin(NULL), - lineno(0), - fname(NULL), - buffer(NULL), - buflen(0), - read_version(0.0) -{ -} - -/** \brief Release project reader resources. */ -Fd_Project_Reader::~Fd_Project_Reader() -{ - // fname is not copied, so do not free it - if (buffer) - ::free(buffer); -} - -/** - 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 - */ -int Fd_Project_Reader::open_read(const char *s) { - lineno = 1; - if (!s) { - fin = stdin; - fname = "stdin"; - } else { - FILE *f = fl_fopen(s, "rb"); - if (!f) - return 0; - fin = f; - fname = s; - } - return 1; -} - -/** - Close the .fl file. - \return 0 if the operation failed, 1 if it succeeded - */ -int Fd_Project_Reader::close_read() { - if (fin != stdin) { - int x = fclose(fin); - fin = 0; - return x >= 0; - } - return 1; -} - -/** - Return the name part of the current filename and path. - \return a pointer into a string that is not owned by this class - */ -const char *Fd_Project_Reader::filename_name() { - return fl_filename_name(fname); -} - -/** - Convert an ASCII sequence from the \.fl file following a previously read `\\` into a single character. - Conversion includes the common C style \\ characters like \\n, \\x## hex - values, and \\o### octal values. - \return a character in the ASCII range - */ -int Fd_Project_Reader::read_quoted() { // read whatever character is after a \ . - int c,d,x; - switch(c = nextchar()) { - case '\n': lineno++; return -1; - case 'a' : return('\a'); - case 'b' : return('\b'); - case 'f' : return('\f'); - case 'n' : return('\n'); - case 'r' : return('\r'); - case 't' : return('\t'); - case 'v' : return('\v'); - case 'x' : /* read hex */ - for (c=x=0; x<3; x++) { - int ch = nextchar(); - d = hexdigit(ch); - if (d > 15) {ungetc(ch,fin); break;} - c = (c<<4)+d; - } - break; - default: /* read octal */ - if (c<'0' || c>'7') break; - c -= '0'; - for (x=0; x<2; x++) { - int ch = nextchar(); - d = hexdigit(ch); - if (d>7) {ungetc(ch,fin); break;} - c = (c<<3)+d; - } - break; - } - return(c); -} - -/** - Recursively read child nodes in the .fl design file. - - If this is the first call, also read the global settings for this design. - - \param[in] p parent node or NULL - \param[in] merge if set, merge into existing design, else replace design - \param[in] strategy add nodes after current or as last child - \param[in] skip_options this is set if the options were already found in - a previous call, and there is no need to waste time searching for them. - \return the last type that was created - */ -Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strategy, char skip_options) { - Fl_Type::current = p; - Fl_Type *last_child_read = NULL; - Fl_Type *t = NULL; - for (;;) { - const char *c = read_word(); - REUSE_C: - if (!c) { - if (p && !merge) - read_error("Missing '}'"); - break; - } - - if (!strcmp(c,"}")) { - if (!p) read_error("Unexpected '}'"); - break; - } - - // Make sure that we don't go through the list of options for child nodes - if (!skip_options) { - // this is the first word in a .fd file: - if (!strcmp(c,"Magic:")) { - read_fdesign(); - return NULL; - } - - if (!strcmp(c,"version")) { - c = read_word(); - read_version = strtod(c,0); - if (read_version<=0 || read_version>double(FL_VERSION+0.00001)) - read_error("unknown version '%s'",c); - continue; - } - - // back compatibility with Vincent Penne's original class code: - if (!p && !strcmp(c,"define_in_struct")) { - Fl_Type *t = add_new_widget_from_file("class", Strategy::FROM_FILE_AS_LAST_CHILD); - t->name(read_word()); - Fl_Type::current = p = t; - merge = 1; // stops "missing }" error - continue; - } - - if (!strcmp(c,"do_not_include_H_from_C")) { - g_project.include_H_from_C=0; - goto CONTINUE; - } - if (!strcmp(c,"use_FL_COMMAND")) { - g_project.use_FL_COMMAND=1; - goto CONTINUE; - } - if (!strcmp(c,"utf8_in_src")) { - g_project.utf8_in_src=1; - goto CONTINUE; - } - if (!strcmp(c,"avoid_early_includes")) { - g_project.avoid_early_includes=1; - goto CONTINUE; - } - if (!strcmp(c,"i18n_type")) { - g_project.i18n_type = static_cast<Fd_I18n_Type>(atoi(read_word())); - goto CONTINUE; - } - if (!strcmp(c,"i18n_gnu_function")) { - g_project.i18n_gnu_function = read_word(); - goto CONTINUE; - } - if (!strcmp(c,"i18n_gnu_static_function")) { - g_project.i18n_gnu_static_function = read_word(); - goto CONTINUE; - } - if (!strcmp(c,"i18n_pos_file")) { - g_project.i18n_pos_file = read_word(); - goto CONTINUE; - } - if (!strcmp(c,"i18n_pos_set")) { - g_project.i18n_pos_set = read_word(); - goto CONTINUE; - } - if (!strcmp(c,"i18n_include")) { - if (g_project.i18n_type == FD_I18N_GNU) - g_project.i18n_gnu_include = read_word(); - else if (g_project.i18n_type == FD_I18N_POSIX) - g_project.i18n_pos_include = read_word(); - goto CONTINUE; - } - if (!strcmp(c,"i18n_conditional")) { - if (g_project.i18n_type == FD_I18N_GNU) - g_project.i18n_gnu_conditional = read_word(); - else if (g_project.i18n_type == FD_I18N_POSIX) - g_project.i18n_pos_conditional = read_word(); - goto CONTINUE; - } - if (!strcmp(c,"header_name")) { - if (!g_project.header_file_set) g_project.header_file_name = read_word(); - else read_word(); - goto CONTINUE; - } - - if (!strcmp(c,"code_name")) { - if (!g_project.code_file_set) g_project.code_file_name = read_word(); - else read_word(); - goto CONTINUE; - } - - if (!strcmp(c, "snap")) { - g_layout_list.read(this); - goto CONTINUE; - } - - if (!strcmp(c, "gridx") || !strcmp(c, "gridy")) { - // grid settings are now global - read_word(); - goto CONTINUE; - } - - if (strcmp(c, "shell_commands")==0) { - if (g_shell_config) { - g_shell_config->read(this); - } else { - read_word(); - } - goto CONTINUE; - } - - if (!strcmp(c, "mergeback")) { - g_project.write_mergeback_data = read_int(); - goto CONTINUE; - } - } - t = add_new_widget_from_file(c, strategy); - if (!t) { - read_error("Unknown word \"%s\"", c); - continue; - } - last_child_read = t; - // After reading the first widget, we no longer need to look for options - skip_options = 1; - - t->name(read_word()); - - c = read_word(1); - if (strcmp(c,"{") && t->is_class()) { // <prefix> <name> - ((Fl_Class_Type*)t)->prefix(t->name()); - t->name(c); - c = read_word(1); - } - - if (strcmp(c,"{")) { - read_error("Missing property list for %s\n",t->title()); - goto REUSE_C; - } - - t->folded_ = 1; - for (;;) { - const char *cc = read_word(); - if (!cc || !strcmp(cc,"}")) break; - t->read_property(*this, cc); - } - - if (t->can_have_children()) { - c = read_word(1); - if (strcmp(c,"{")) { - read_error("Missing child list for %s\n",t->title()); - goto REUSE_C; - } - read_children(t, 0, Strategy::FROM_FILE_AS_LAST_CHILD, skip_options); - t->postprocess_read(); - // FIXME: this has no business in the file reader! - // TODO: this is called whenever something is pasted from the top level into a grid - // It makes sense to make this more universal for other widget types too. - if (merge && t && t->parent && t->parent->is_a(ID_Grid)) { - if (Fl_Window_Type::popupx != 0x7FFFFFFF) { - ((Fl_Grid_Type*)t->parent)->insert_child_at(((Fl_Widget_Type*)t)->o, Fl_Window_Type::popupx, Fl_Window_Type::popupy); - } else { - ((Fl_Grid_Type*)t->parent)->insert_child_at_next_free_cell(((Fl_Widget_Type*)t)->o); - } - } - - t->layout_widget(); - } - - if (strategy.placement() == Strategy::AS_FIRST_CHILD) { - strategy.placement(Strategy::AFTER_CURRENT); - } - if (strategy.placement() == Strategy::AFTER_CURRENT) { - Fl_Type::current = t; - } else { - Fl_Type::current = p; - } - - CONTINUE:; - } - if (merge && last_child_read && last_child_read->parent) { - last_child_read->parent->postprocess_read(); - last_child_read->parent->layout_widget(); - } - return last_child_read; -} - -/** \brief Read a .fl project file. - \param[in] filename read this file - \param[in] merge if this is set, merge the file into an existing project - at Fl_Type::current - \param[in] strategy add new nodes after current or as last child - \return 0 if the operation failed, 1 if it succeeded - */ -int Fd_Project_Reader::read_project(const char *filename, int merge, Strategy strategy) { - Fl_Type *o; - undo_suspend(); - read_version = 0.0; - if (!open_read(filename)) { - undo_resume(); - return 0; - } - if (merge) - deselect(); - else - g_project.reset(); - read_children(Fl_Type::current, merge, strategy); - // clear this - Fl_Type::current = 0; - // Force menu items to be rebuilt... - for (o = Fl_Type::first; o; o = o->next) { - if (o->is_a(ID_Menu_Manager_)) { - o->add_child(0,0); - } - } - for (o = Fl_Type::first; o; o = o->next) { - if (o->selected) { - Fl_Type::current = o; - break; - } - } - selection_changed(Fl_Type::current); - if (g_shell_config) { - g_shell_config->rebuild_shell_menu(); - g_shell_config->update_settings_dialog(); - } - g_layout_list.update_dialogs(); - g_project.update_settings_dialog(); - int ret = close_read(); - undo_resume(); - return ret; -} - -/** - 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? - \todo Not happy about this function. Output channel should depend on `batch_mode` - as the note above already states. I want to make all file readers and writers - depend on an error handling base class that outputs a useful analysis of file - operations. - \param[in] format printf style format string, followed by an argument list - */ -void Fd_Project_Reader::read_error(const char *format, ...) { - va_list args; - va_start(args, format); - if (!fin) { // FIXME: this line suppresses any error messages in interactive mode - char buffer[1024]; // TODO: hides class member "buffer" - vsnprintf(buffer, sizeof(buffer), format, args); - fl_message("%s", buffer); - } else { - fprintf(stderr, "%s:%d: ", fname, lineno); - vfprintf(stderr, format, args); - fprintf(stderr, "\n"); - } - va_end(args); -} - -/** - 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 '}' - - \param[in] wantbrace if set, reading a `{` as the first non-space character - will return the string `"{"`, if clear, a `{` is seen as the start of a word - \return a pointer to the internal buffer, containing a copy of the word. - Don't free the buffer! Note that most (all?) other file operations will - overwrite this buffer. If wantbrace is not set, but we read a leading '{', - the returned string will be stripped of its leading and trailing braces. - */ -const char *Fd_Project_Reader::read_word(int wantbrace) { - int x; - - // skip all the whitespace before it: - for (;;) { - x = nextchar(); - if (x < 0 && feof(fin)) { // eof - return 0; - } else if (x == '#') { // comment - do x = nextchar(); while (x >= 0 && x != '\n'); - lineno++; - continue; - } else if (x == '\n') { - lineno++; - } else if (!isspace(x & 255)) { - break; - } - } - - expand_buffer(100); - - if (x == '{' && !wantbrace) { - - // read in whatever is between braces - int length = 0; - int nesting = 0; - for (;;) { - x = nextchar(); - if (x<0) {read_error("Missing '}'"); break;} - else if (x == '#') { // embedded comment - do x = nextchar(); while (x >= 0 && x != '\n'); - lineno++; - continue; - } else if (x == '\n') lineno++; - else if (x == '\\') {x = read_quoted(); if (x<0) continue;} - else if (x == '{') nesting++; - else if (x == '}') {if (!nesting--) break;} - buffer[length++] = x; - expand_buffer(length); - } - buffer[length] = 0; - return buffer; - - } else if (x == '{' || x == '}') { - // all the punctuation is a word: - buffer[0] = x; - buffer[1] = 0; - return buffer; - - } else { - - // read in an unquoted word: - int length = 0; - for (;;) { - if (x == '\\') {x = read_quoted(); if (x<0) continue;} - else if (x<0 || isspace(x & 255) || x=='{' || x=='}' || x=='#') break; - buffer[length++] = x; - expand_buffer(length); - x = nextchar(); - } - ungetc(x, fin); - buffer[length] = 0; - return buffer; - - } -} - -/** Read a word and interpret it as an integer value. - \return integer value, or 0 if the word is not an integer - */ -int Fd_Project_Reader::read_int() { - const char *word = read_word(); - if (word) { - return atoi(word); - } else { - return 0; - } -} - -/** Read fdesign name/value pairs. - Fdesign is the file format of the XForms UI designer. It stores lists of name - and value pairs separated by a colon: `class: FL_LABELFRAME`. - \param[out] name string - \param[out] value string - \return 0 if end of file, else 1 - */ -int Fd_Project_Reader::read_fdesign_line(const char*& name, const char*& value) { - int length = 0; - int x; - // find a colon: - for (;;) { - x = nextchar(); - if (x < 0 && feof(fin)) return 0; - if (x == '\n') {length = 0; continue;} // no colon this line... - if (!isspace(x & 255)) { - buffer[length++] = x; - expand_buffer(length); - } - if (x == ':') break; - } - int valueoffset = length; - buffer[length-1] = 0; - - // skip to start of value: - for (;;) { - x = nextchar(); - if ((x < 0 && feof(fin)) || x == '\n' || !isspace(x & 255)) break; - } - - // read the value: - for (;;) { - if (x == '\\') {x = read_quoted(); if (x<0) continue;} - else if (x == '\n') break; - buffer[length++] = x; - expand_buffer(length); - x = nextchar(); - } - buffer[length] = 0; - name = buffer; - value = buffer+valueoffset; - return 1; -} - -/// Lookup table from fdesign .fd files to .fl files -static const char *class_matcher[] = { - "FL_CHECKBUTTON", "Fl_Check_Button", - "FL_ROUNDBUTTON", "Fl_Round_Button", - "FL_ROUND3DBUTTON", "Fl_Round_Button", - "FL_LIGHTBUTTON", "Fl_Light_Button", - "FL_FRAME", "Fl_Box", - "FL_LABELFRAME", "Fl_Box", - "FL_TEXT", "Fl_Box", - "FL_VALSLIDER", "Fl_Value_Slider", - "FL_MENU", "Fl_Menu_Button", - "3", "FL_BITMAP", - "1", "FL_BOX", - "71","FL_BROWSER", - "11","FL_BUTTON", - "4", "FL_CHART", - "42","FL_CHOICE", - "61","FL_CLOCK", - "25","FL_COUNTER", - "22","FL_DIAL", - "101","FL_FREE", - "31","FL_INPUT", - "12","Fl_Light_Button", - "41","FL_MENU", - "23","FL_POSITIONER", - "13","Fl_Round_Button", - "21","FL_SLIDER", - "2", "FL_BOX", // was FL_TEXT - "62","FL_TIMER", - "24","Fl_Value_Slider", - 0}; - - -/** - Finish a group of widgets and optionally transform its children's coordinates. - - Implements the same functionality as Fl_Group::forms_end() from the forms - compatibility library would have done: - - - resize the group to surround its children if the group's w() == 0 - - optionally flip the \p y coordinates of all children relative to the group's window - - Fl_Group::end() the group - - \note Copied from forms_compatibility.cxx and modified as a static fluid - function so we don't have to link to fltk_forms. - - \param[in] g the Fl_Group widget - \param[in] flip flip children's \p y coordinates if true (non-zero) - */ -static void forms_end(Fl_Group *g, int flip) { - // set the dimensions of a group to surround its contents - const int nc = g->children(); - if (nc && !g->w()) { - Fl_Widget*const* a = g->array(); - Fl_Widget* o = *a++; - int rx = o->x(); - int ry = o->y(); - int rw = rx+o->w(); - int rh = ry+o->h(); - for (int i = nc - 1; i--;) { - o = *a++; - if (o->x() < rx) rx = o->x(); - if (o->y() < ry) ry = o->y(); - if (o->x() + o->w() > rw) rw = o->x() + o->w(); - if (o->y() + o->h() > rh) rh = o->y() + o->h(); - } - g->Fl_Widget::resize(rx, ry, rw-rx, rh-ry); - } - // flip all the children's coordinate systems: - if (nc && flip) { - Fl_Widget* o = (g->as_window()) ? g : g->window(); - int Y = o->h(); - Fl_Widget*const* a = g->array(); - for (int i = nc; i--;) { - Fl_Widget* ow = *a++; - int newy = Y - ow->y() - ow->h(); - ow->Fl_Widget::resize(ow->x(), newy, ow->w(), ow->h()); - } - } - g->end(); -} - -/** - 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 Fd_Project_Reader::read_fdesign() { - int fdesign_magic = atoi(read_word()); - fdesign_flip = (fdesign_magic < 13000); - Fl_Widget_Type *window = 0; - Fl_Widget_Type *group = 0; - Fl_Widget_Type *widget = 0; - if (!Fl_Type::current) { - Fl_Type *t = add_new_widget_from_file("Function", Strategy::FROM_FILE_AS_LAST_CHILD); - t->name("create_the_forms()"); - Fl_Type::current = t; - } - for (;;) { - const char *name; - const char *value; - if (!read_fdesign_line(name, value)) break; - - if (!strcmp(name,"Name")) { - - window = (Fl_Widget_Type*)add_new_widget_from_file("Fl_Window", Strategy::FROM_FILE_AS_LAST_CHILD); - window->name(value); - window->label(value); - Fl_Type::current = widget = window; - - } else if (!strcmp(name,"class")) { - - if (!strcmp(value,"FL_BEGIN_GROUP")) { - group = widget = (Fl_Widget_Type*)add_new_widget_from_file("Fl_Group", Strategy::FROM_FILE_AS_LAST_CHILD); - Fl_Type::current = group; - } else if (!strcmp(value,"FL_END_GROUP")) { - if (group) { - Fl_Group* g = (Fl_Group*)(group->o); - g->begin(); - forms_end(g, fdesign_flip); - Fl_Group::current(0); - } - group = widget = 0; - Fl_Type::current = window; - } else { - for (int i = 0; class_matcher[i]; i += 2) - if (!strcmp(value,class_matcher[i])) { - value = class_matcher[i+1]; break;} - widget = (Fl_Widget_Type*)add_new_widget_from_file(value, Strategy::FROM_FILE_AS_LAST_CHILD); - if (!widget) { - printf("class %s not found, using Fl_Button\n", value); - widget = (Fl_Widget_Type*)add_new_widget_from_file("Fl_Button", Strategy::FROM_FILE_AS_LAST_CHILD); - } - } - - } else if (widget) { - if (!widget->read_fdesign(name, value)) - printf("Ignoring \"%s: %s\"\n", name, value); - } - } -} - -// ---- Fd_Project_Writer ---------------------------------------------- MARK: - +// ---- Project_Writer ---------------------------------------------- MARK: - /** \brief Construct local project writer. */ -Fd_Project_Writer::Fd_Project_Writer() +Project_Writer::Project_Writer() : fout(NULL), needspace(0), write_codeview_(false) @@ -793,7 +58,7 @@ Fd_Project_Writer::Fd_Project_Writer() } /** \brief Release project writer resources. */ -Fd_Project_Writer::~Fd_Project_Writer() +Project_Writer::~Project_Writer() { } @@ -803,7 +68,7 @@ Fd_Project_Writer::~Fd_Project_Writer() \param[in] s the filename or NULL for stdout \return 1 if successful. 0 if the operation failed */ -int Fd_Project_Writer::open_write(const char *s) { +int Project_Writer::open_write(const char *s) { if (!s) { fout = stdout; } else { @@ -819,7 +84,7 @@ int Fd_Project_Writer::open_write(const char *s) { Don't close, if data was sent to stdout. \return 1 if succeeded, 0 if fclose failed */ -int Fd_Project_Writer::close_write() { +int Project_Writer::close_write() { if (fout != stdout) { int x = fclose(fout); fout = stdout; @@ -835,7 +100,7 @@ int Fd_Project_Writer::close_write() { \param[in] sv if set, this file will be used by codeview \return 0 if the operation failed, 1 if it succeeded */ -int Fd_Project_Writer::write_project(const char *filename, int selected_only, bool sv) { +int Project_Writer::write_project(const char *filename, int selected_only, bool sv) { write_codeview_ = sv; undo_suspend(); if (!open_write(filename)) { @@ -904,7 +169,7 @@ int Fd_Project_Writer::write_project(const char *filename, int selected_only, bo Write a string to the .fl file, quoting characters if necessary. \param[in] w NUL terminated text */ -void Fd_Project_Writer::write_word(const char *w) { +void Project_Writer::write_word(const char *w) { if (needspace) putc(' ', fout); needspace = 1; if (!w || !*w) {fprintf(fout,"{}"); return;} @@ -942,7 +207,7 @@ void Fd_Project_Writer::write_word(const char *w) { unless the format starts with a newline character \\n. \param[in] format printf style formatting string followed by a list of arguments */ -void Fd_Project_Writer::write_string(const char *format, ...) { +void Project_Writer::write_string(const char *format, ...) { va_list args; va_start(args, format); if (needspace && *format != '\n') fputc(' ',fout); @@ -955,7 +220,7 @@ void Fd_Project_Writer::write_string(const char *format, ...) { Start a new line in the .fl file and indent it for a given nesting level. \param[in] n indent level */ -void Fd_Project_Writer::write_indent(int n) { +void Project_Writer::write_indent(int n) { fputc('\n',fout); while (n--) {fputc(' ',fout); fputc(' ',fout);} needspace = 0; @@ -964,7 +229,7 @@ void Fd_Project_Writer::write_indent(int n) { /** Write a '{' to the .fl file at the given indenting level. */ -void Fd_Project_Writer::write_open() { +void Project_Writer::write_open() { if (needspace) fputc(' ',fout); fputc('{',fout); needspace = 0; @@ -974,7 +239,7 @@ void Fd_Project_Writer::write_open() { Write a '}' to the .fl file at the given indenting level. \param[in] n indent level */ -void Fd_Project_Writer::write_close(int n) { +void Project_Writer::write_close(int n) { if (needspace) write_indent(n); fputc('}',fout); needspace = 1; diff --git a/fluid/io/Project_Writer.h b/fluid/io/Project_Writer.h index 470cc1a7b..c6e50ca7c 100644 --- a/fluid/io/Project_Writer.h +++ b/fluid/io/Project_Writer.h @@ -14,59 +14,21 @@ // https://www.fltk.org/bugs.php // -#ifndef _FLUID_FILE_H -#define _FLUID_FILE_H - -#include "nodes/Fl_Type.h" +#ifndef FLUID_IO_PROJECT_WRITER_H +#define FLUID_IO_PROJECT_WRITER_H #include <FL/fl_attr.h> +#include <stdio.h> + class Fl_Type; -extern int fdesign_flip; +namespace fld { +namespace io { -int read_file(const char *, int merge, Strategy strategy=Strategy::FROM_FILE_AS_LAST_CHILD); int write_file(const char *, int selected_only = 0, bool to_codeview = false); -class Fd_Project_Reader -{ -protected: - /// Project input file - FILE *fin; - /// Number of most recently read line - int lineno; - /// Pointer to the file path and name (not copied!) - const char *fname; - /// Expanding buffer to store the most recently read word - char *buffer; - /// Exact size of the expanding buffer in bytes - int buflen; - - void expand_buffer(int length); - - int nextchar() { for (;;) { int ret = fgetc(fin); if (ret!='\r') return ret; } } - -public: - /// Holds the file version number after reading the "version" tag - double read_version; - -public: - Fd_Project_Reader(); - ~Fd_Project_Reader(); - int open_read(const char *s); - int close_read(); - const char *filename_name(); - int read_quoted(); - Fl_Type *read_children(Fl_Type *p, int merge, Strategy strategy, char skip_options=0); - int read_project(const char *, int merge, Strategy strategy=Strategy::FROM_FILE_AS_LAST_CHILD); - void read_error(const char *format, ...); - const char *read_word(int wantbrace = 0); - int read_int(); - int read_fdesign_line(const char*& name, const char*& value); - void read_fdesign(); -}; - -class Fd_Project_Writer +class Project_Writer { protected: // Project output file, always opened in "wb" mode @@ -77,8 +39,8 @@ protected: bool write_codeview_; public: - Fd_Project_Writer(); - ~Fd_Project_Writer(); + Project_Writer(); + ~Project_Writer(); int open_write(const char *s); int close_write(); int write_project(const char *filename, int selected_only, bool codeview); @@ -91,4 +53,7 @@ public: bool write_codeview() const { return write_codeview_; } }; -#endif // _FLUID_FILE_H +} // namespace io +} // namespace fld + +#endif // FLUID_IO_PROJECT_WRITER_H |
