summaryrefslogtreecommitdiff
path: root/fluid/io
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2025-03-08 00:14:09 +0100
committerMatthias Melcher <github@matthiasm.com>2025-03-08 00:14:27 +0100
commit15ad447e2a0301b2aa4ea350615ae71f0e5e5ef5 (patch)
tree706f8f9a6317f1074951e6174a4857ebafbca117 /fluid/io
parentca22660bbb7efe4b38ab5af6a233a1ef5ef33389 (diff)
Fluid: last incremental chage, restructuring
Diffstat (limited to 'fluid/io')
-rw-r--r--fluid/io/Code_Writer.cxx79
-rw-r--r--fluid/io/Code_Writer.h18
-rw-r--r--fluid/io/Project_Reader.cxx266
-rw-r--r--fluid/io/Project_Reader.h45
-rw-r--r--fluid/io/Project_Writer.cxx771
-rw-r--r--fluid/io/Project_Writer.h61
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