Fluid: clean up Code_Writer
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-wayland-arm64 (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled
Build and Test / build-windows-arm (push) Has been cancelled

This commit is contained in:
Matthias Melcher
2026-07-13 23:38:14 +02:00
parent e35b439674
commit 9badcab8f0
8 changed files with 278 additions and 187 deletions
+184 -117
View File
@@ -281,9 +281,9 @@ void Code_Writer::write_cstring(fluid::string_view text) {
// A line break would be ok here. Do not put linebreak in front of
// following characters (0b10......)
if (linelength >= 78) { crc_puts(next_line); linelength = 0; }
linelength++;
}
crc_putc(c);
linelength++;
break;
}
// otherwise we must print it as an octal constant:
@@ -453,7 +453,7 @@ void Code_Writer::write_c_indented(const std::string& codeblock, int additional_
}
/**
Return true if the type can be the member of a class.
Return true if the type can be a member of a class.
Some types are treated differently if they are inside class. Especially within
a Widget Class, children that are widgets are written as part of the
@@ -481,7 +481,7 @@ bool is_class_member(Node *t) {
\return false if it is followed by a widget or code
\see is_class_member(Node *t)
*/
bool is_comment_before_class_member(Node *q) {
static bool is_comment_before_class_member(Node *q) {
if (dynamic_cast<Comment_Node*>(q) && q->next && q->next->level==q->level) {
if (dynamic_cast<Comment_Node*>(q->next))
return is_comment_before_class_member(q->next);
@@ -497,11 +497,9 @@ bool is_comment_before_class_member(Node *q) {
\return pointer to the next sibling
*/
Node* Code_Writer::write_static(Node* p) {
if (write_codeview) p->header_static.start = header_pos();
if (write_codeview) p->code_static.start = code_pos();
mark_start(p->static_data);
p->write_static(*this);
if (write_codeview) p->code_static.end = code_pos();
if (write_codeview) p->header_static.end = header_pos();
mark_end(p->static_data);
Node* q;
for (q = p->next; q && q->level > p->level;) {
@@ -522,11 +520,9 @@ Node* Code_Writer::write_code(Node* p) {
// write all code that comes before the children code
// (but don't write the last comment until the very end)
if (!(p==Fluid.proj.tree.last && dynamic_cast<Comment_Node*>(p))) {
if (write_codeview) p->code1.start = code_pos();
if (write_codeview) p->header1.start = header_pos();
mark_start(p->setup_node);
p->write_code1(*this);
if (write_codeview) p->code1.end = code_pos();
if (write_codeview) p->header1.end = header_pos();
mark_end(p->setup_node);
}
// recursively write the code of all children
Node* q;
@@ -545,11 +541,9 @@ Node* Code_Writer::write_code(Node* p) {
}
// write all code that come after the children
if (write_codeview) p->code2.start = code_pos();
if (write_codeview) p->header2.start = header_pos();
mark_start(p->finalize_node);
p->write_code2(*this);
if (write_codeview) p->code2.end = code_pos();
if (write_codeview) p->header2.end = header_pos();
mark_end(p->finalize_node);
for (q = p->next; q && q->level > p->level;) {
if (is_class_member(q) || is_comment_before_class_member(q)) {
@@ -567,17 +561,15 @@ Node* Code_Writer::write_code(Node* p) {
} else {
for (q = p->next; q && q->level > p->level;) q = write_code(q);
// write all code that come after the children
if (write_codeview) p->code2.start = code_pos();
if (write_codeview) p->header2.start = header_pos();
mark_start(p->finalize_node);
p->write_code2(*this);
if (write_codeview) p->code2.end = code_pos();
if (write_codeview) p->header2.end = header_pos();
mark_end(p->finalize_node);
}
return q;
}
/**
Write the source and header files for the current design.
Write source code and header files.
If the files already exist, they will be overwritten only if the content
has changed. This conservative approach helps reduce unnecessary recompilation.
@@ -589,109 +581,92 @@ Node* Code_Writer::write_code(Node* p) {
\return 0 if the operation failed, 1 if it was successful
*/
int Code_Writer::write_code(const std::string& code_arg, const std::string& header_arg, bool to_codeview) {
code_filename = code_arg;
header_filename = header_arg;
write_codeview = to_codeview;
unique_id_list.clear();
indentation = 0;
current_class = nullptr;
current_widget_class = nullptr;
// Always use string stream buffers for output
code_buffer.str("");
code_buffer.clear();
header_buffer.str("");
header_buffer.clear();
// Remember the last code file location for MergeBack
if (!code_arg.empty() && proj_.write_mergeback_data && !to_codeview) {
std::string filename = proj_.projectfile_path() + proj_.projectfile_name();
int i, n = (int)filename.size();
for (i=0; i<n; i++) if (filename[i]=='\\') filename[i] = '/';
Fl_Preferences build_records(Fl_Preferences::USER_L, "fltk.org", "fluid-build");
Fl_Preferences path(build_records, filename.c_str());
path.set("code", code_arg);
if (!code_arg.empty() && proj_.write_mergeback_data && !to_codeview)
remember_mergeback_paths();
// Write the prologue comment, which may be a copyright notice or other
Node* first_node = write_prologue_comment();
write_prologue();
write_i18n_prologue();
for (Node* p = first_node; p;) {
// write all static data for this & all children first
write_static(p);
// then write the nested code:
p = write_code(p);
}
write_epilogue();
write_epilogue_comment();
// For codeview mode, strings are available via code_string() / header_string()
if (write_codeview)
return 1;
else
return flush();
}
/**
If the first node in the project is a comment, emit it before the actual prologue.
\return the node after the comment (or the first node if it was not a comment)
*/
Node* Code_Writer::write_prologue_comment() {
// if the first entry in the Type tree is a comment, then it is probably
// a copyright notice. We print that before anything else in the file!
Node* first_node = Fluid.proj.tree.first;
if (first_node && dynamic_cast<Comment_Node*>(first_node)) {
if (write_codeview) {
first_node->code1.start = first_node->code2.start = code_pos();
first_node->header1.start = first_node->header2.start = header_pos();
}
mark_start(first_node->setup_node);
mark_start(first_node->finalize_node);
// it is ok to write non-recursive code here, because comments have no children or code2 blocks
first_node->write_code1(*this);
if (write_codeview) {
first_node->code1.end = first_node->code2.end = code_pos();
first_node->header1.end = first_node->header2.end = header_pos();
}
mark_end(first_node->setup_node);
mark_end(first_node->finalize_node);
first_node = first_node->next;
}
return first_node;
}
/**
Write the prologue of the source and header files, including the include guard
and any necessary includes.
*/
void Code_Writer::write_prologue()
{
char version[128];
fl_snprintf(version, sizeof(version),
"// generated by Fast Light User Interface Designer (fluid) version %.4f\n\n",
FL_VERSION);
write_h(std::string(version));
crc_puts(version);
{
// Creating the include guard is more involved than it seems at first glance.
// The include guard is deduced from header filename. However, if the
// filename contains unicode characters, they need to be encoded using
// \Uxxxxxxxx or \\uxxxx encoding to form a valid macro identifier.
//
// But that approach is not portable. Windows does not normalize Unicode
// (ö is the letter \u00F6). macOS normalizes to NFD (ö is \u006F\u0308,
// o followed by a Combining Diaresis ¨).
//
// To make the include guard consistent across l=platforms, it can be
// explicitly set by the user in the Project Settings.
std::string macro_name_str = proj_.include_guard;
if (macro_name_str.empty()) {
std::ostringstream macro_name;
std::string header_name;
const char* a = nullptr;
if (write_codeview) {
header_name = proj_.headerfile_name();
a = header_name.c_str();
} else {
a = fl_filename_name(header_arg.c_str());
}
const char* b = a + strlen(a);
int len = 0;
unsigned ucs = fl_utf8decode(a, b, &len);
if ((ucs > 127) || (!isalpha(ucs) && (ucs != '_')))
macro_name << '_';
while (a < b) {
ucs = fl_utf8decode(a, b, &len);
if (ucs > 0x0000ffff) { // large unicode character
macro_name << "\\U" << std::setw(8) << std::setfill('0') << std::hex << ucs;
} else if (ucs > 127) { // small unicode character or not an ASCI letter or digit
macro_name << "\\u" << std::setw(4) << std::setfill('0') << std::hex << ucs;
} else if (!isalnum(ucs)) {
macro_name << '_';
} else {
macro_name << (char)ucs;
}
a += len;
}
macro_name_str = macro_name.str();
}
write_h("#ifndef " + macro_name_str + "\n");
write_h("#define " + macro_name_str + "\n");
}
std::string guard = header_guard_macro();
write_h("#ifndef " + guard + "\n");
write_h("#define " + guard + "\n");
if (proj_.avoid_early_includes==0) {
write_h_once("#include <FL/Fl.H>");
}
if (!header_arg.empty() && proj_.include_H_from_C) {
if (to_codeview) {
if (!header_filename.empty() && proj_.include_H_from_C) {
if (write_codeview) {
write_c("#include \"CodeView.h\"\n");
} else if (proj_.header_file_name[0] == '.' && strchr(proj_.header_file_name.c_str(), '/') == nullptr) {
write_c("#include \"" + fl_filename_name_str(header_arg) + "\"\n");
write_c("#include \"" + fl_filename_name_str(header_filename) + "\"\n");
} else {
write_c("#include \"" + proj_.header_file_name + "\"\n");
}
}
}
/**
Write the internationalization prologue, including any necessary includes and macros.
*/
void Code_Writer::write_i18n_prologue()
{
std::string loc_include, loc_conditional;
if (proj_.i18n.type==fluid::I18n_Type::GNU) {
loc_include = proj_.i18n.gnu_include;
@@ -743,44 +718,53 @@ int Code_Writer::write_code(const std::string& code_arg, const std::string& head
write_c("#endif\n");
}
}
for (Node* p = first_node; p;) {
// write all static data for this & all children first
write_static(p);
// then write the nested code:
p = write_code(p);
}
}
write_h("#endif\n");
/**
Write the epilogue of the source and header files, including the include guard.
*/
void Code_Writer::write_epilogue()
{
std::string guard = header_guard_macro();
write_h("#endif // " + guard + "\n");
}
/**
If the last node in the project is a comment, emit it after the actual epilogue.
*/
void Code_Writer::write_epilogue_comment() {
Node* last_node = Fluid.proj.tree.last;
if (last_node && (last_node != Fluid.proj.tree.first) && dynamic_cast<Comment_Node*>(last_node)) {
if (write_codeview) {
last_node->code1.start = last_node->code2.start = code_pos();
last_node->header1.start = last_node->header2.start = header_pos();
}
mark_start(last_node->setup_node);
mark_start(last_node->finalize_node);
last_node->write_code1(*this);
if (write_codeview) {
last_node->code1.end = last_node->code2.end = code_pos();
last_node->header1.end = last_node->header2.end = header_pos();
}
mark_end(last_node->setup_node);
mark_end(last_node->finalize_node);
}
}
// For codeview mode, strings are available via code_string() / header_string()
if (write_codeview)
return 1;
/**
Write the contents of code_buffer and header_buffer..
If the files already exist, they will be overwritten only if the content
has changed. This conservative approach helps reduce unnecessary recompilation.
\return 0 if the operation failed, 1 if it was successful
*/
int Code_Writer::flush()
{
// Write code output: to file if filename provided, to stdout otherwise
bool code_ok = true;
if (!code_arg.empty()) {
code_ok = write_file_if_changed(code_arg, code_buffer.str());
if (!code_filename.empty()) {
code_ok = write_file_if_changed(code_filename, code_buffer.str());
} else {
fputs(code_buffer.str().c_str(), stdout);
}
// Write header output: to file if filename provided, to stdout otherwise
bool header_ok = true;
if (!header_arg.empty()) {
header_ok = write_file_if_changed(header_arg, header_buffer.str());
if (!header_filename.empty()) {
header_ok = write_file_if_changed(header_filename, header_buffer.str());
} else {
fputs(header_buffer.str().c_str(), stdout);
}
@@ -788,7 +772,6 @@ int Code_Writer::write_code(const std::string& code_arg, const std::string& head
return code_ok && header_ok ? 1 : 0;
}
/**
Write the public/private/protected keywords inside the class.
This avoids repeating these words if the mode is already set.
@@ -974,6 +957,90 @@ void fluid::CRC32::update(fluid::string_view block) {
}
}
/**
Return the macro name to use for the include guard in the header file.
Creating the include guard is more involved than it seems at first glance.
The include guard is deduced from header filename. However, if the
filename contains unicode characters, they need to be encoded using
\Uxxxxxxxx or \\uxxxx encoding to form a valid macro identifier.
But that approach is not portable. Windows does not normalize Unicode
(ö is the letter \u00F6). macOS normalizes to NFD (ö is \u006F\u0308,
o followed by a Combining Diaresis ¨).
To make the include guard consistent across l=platforms, it can be
explicitly set by the user in the Project Settings.
*/
std::string Code_Writer::header_guard_macro()
{
if (!header_guard_macro_.empty()) {
return header_guard_macro_;
}
header_guard_macro_ = proj_.include_guard;
if (header_guard_macro_.empty()) {
std::ostringstream macro_name;
std::string header_name;
const char* a = nullptr;
if (write_codeview) {
header_name = proj_.headerfile_name();
a = header_name.c_str();
} else {
a = fl_filename_name(header_filename.c_str());
}
const char* b = a + strlen(a);
int len = 0;
unsigned ucs = fl_utf8decode(a, b, &len);
if ((ucs > 127) || (!isalpha(ucs) && (ucs != '_')))
macro_name << '_';
while (a < b) {
ucs = fl_utf8decode(a, b, &len);
if (ucs > 0x0000ffff) { // large unicode character
macro_name << "\\U" << std::setw(8) << std::setfill('0') << std::hex << ucs;
} else if (ucs > 127) { // small unicode character or not an ASCI letter or digit
macro_name << "\\u" << std::setw(4) << std::setfill('0') << std::hex << ucs;
} else if (!isalnum(ucs)) {
macro_name << '_';
} else {
macro_name << (char)ucs;
}
a += len;
}
header_guard_macro_ = macro_name.str();
}
return header_guard_macro_;
}
/**
Remember the last code file location for MergeBack.
This is stored in the user preferences, so that the next time the project is
opened, the code file can be found and merged back into the project.
*/
void Code_Writer::remember_mergeback_paths()
{
std::string filename = proj_.projectfile_path() + proj_.projectfile_name();
int i, n = (int)filename.size();
for (i=0; i<n; i++) if (filename[i]=='\\') filename[i] = '/';
Fl_Preferences build_records(Fl_Preferences::USER_L, "fltk.org", "fluid-build");
Fl_Preferences path(build_records, filename.c_str());
path.set("code", code_filename);
}
void Code_Writer::mark_start(TextSpan2& span) {
if (write_codeview) {
span.c.start = code_pos();
span.h.start = header_pos();
}
}
void Code_Writer::mark_end(TextSpan2& span) {
if (write_codeview) {
span.c.end = code_pos();
span.h.end = header_pos();
}
}
/**
Calculate the CRC32 of a block of text.
This is a convenience function that creates a CRC32 object, adds the block of
+30 -10
View File
@@ -36,6 +36,8 @@ struct Fd_Pointer_Tree;
int is_id(char c);
struct TextSpan2;
namespace fluid {
class Project;
@@ -64,11 +66,11 @@ struct string_view {
};
class CRC32 {
uint32_t crc_;
bool multi_space_ = false;
bool line_start_ = true;
uint32_t crc_ { 0 };
bool multi_space_ { false };
bool line_start_ { true };
public:
CRC32() : crc_(0) {}
CRC32() = default;
void update(fluid::string_view block);
uint32_t value() const { return crc_; }
void reset() { crc_ = 0; multi_space_ = false; line_start_ = true; }
@@ -87,9 +89,13 @@ private:
Project &proj_;
/// string stream buffer for generating C++ code file content
std::ostringstream code_buffer;
std::ostringstream code_buffer { };
/// string stream buffer for generating C++ header file content
std::ostringstream header_buffer;
std::ostringstream header_buffer { };
std::string header_filename { };
std::string code_filename { };
std::string header_guard_macro_ { };
/// tree of unique but human-readable identifiers
std::map<std::string, void*> unique_id_list { };
@@ -104,10 +110,11 @@ private:
fluid::CRC32 crc_ { };
/// current level of source code indentation
int indentation = 0;
int indentation { 0 };
bool file_content_matches(const std::string& filename, const std::string& content);
bool write_file_if_changed(const std::string& filename, const std::string& content);
int flush();
/// Return the current write position in the code output stream.
int code_pos() { return (int)code_buffer.tellp(); }
@@ -121,13 +128,13 @@ protected:
public:
/// set if we write abbreviated file for the source code previewer
/// (disables binary data blocks, for example)
bool write_codeview = false;
bool write_codeview { false };
/// silly thing to prevent declaring unused variables:
/// When this symbol is on, all attempts to write code don't write
/// anything, but set a variable if it looks like the variable "o" is used:
int varused_test = 0;
int varused_test { 0 };
/// set to 1 if varused_test found that a variable is actually used
int varused = 0;
int varused { 0 };
public:
Code_Writer(Project &proj);
@@ -165,13 +172,26 @@ public:
Node* write_code(Node* p);
int write_code(const std::string& code_arg, const std::string& header_arg, bool to_codeview=false);
Node* write_prologue_comment();
void write_prologue();
void write_i18n_prologue();
void write_epilogue();
void write_epilogue_comment();
/// Return the generated source code as a string (valid after write_code() with to_codeview=true).
std::string code_string() const { return code_buffer.str(); }
/// Return the generated header code as a string (valid after write_code() with to_codeview=true).
std::string header_string() const { return header_buffer.str(); }
/// Return the predefined header guard, or generate one based on the header filename if not set.
std::string header_guard_macro();
/// Remember the last destination for later MergeBack calls.
void remember_mergeback_paths();
void tag(proj::Mergeback::Tag prev_type, proj::Mergeback::Tag next_type, unsigned short uid);
void mark_start(TextSpan2& span);
void mark_end(TextSpan2& span);
};
} // namespace io
+7 -2
View File
@@ -85,6 +85,10 @@ struct TextSpan {
int start = -1, end = -1;
};
struct TextSpan2 {
TextSpan h, c;
};
int storestring(const char *n, const char * & p, int nostrip=0);
int storestring(const std::string& n, std::string& p, int nostrip=0);
@@ -180,8 +184,9 @@ public: // things that should not be public:
std::string callback_name(fluid::io::Code_Writer& f);
// text positions of this type in code, header, and project file (see codeview)
TextSpan code_static, code1, code2;
TextSpan header1, header2, header_static;
TextSpan2 static_data;
TextSpan2 setup_node;
TextSpan2 finalize_node;
TextSpan proj1, proj2;
public:
+6 -6
View File
@@ -107,14 +107,14 @@ Node *Tree::find_in_text(int text_type, int crsr) {
for (auto node: all_nodes()) {
switch (text_type) {
case 0:
if (crsr >= node->code1.start && crsr < node->code1.end) return node;
if (crsr >= node->code2.start && crsr < node->code2.end) return node;
if (crsr >= node->code_static.start && crsr < node->code_static.end) return node;
if (crsr >= node->setup_node.c.start && crsr < node->setup_node.c.end) return node;
if (crsr >= node->finalize_node.c.start && crsr < node->finalize_node.c.end) return node;
if (crsr >= node->static_data.c.start && crsr < node->static_data.c.end) return node;
break;
case 1:
if (crsr >= node->header1.start && crsr < node->header1.end) return node;
if (crsr >= node->header2.start && crsr < node->header2.end) return node;
if (crsr >= node->header_static.start && crsr < node->header_static.end) return node;
if (crsr >= node->setup_node.h.start && crsr < node->setup_node.h.end) return node;
if (crsr >= node->finalize_node.h.start && crsr < node->finalize_node.h.end) return node;
if (crsr >= node->static_data.h.start && crsr < node->static_data.h.end) return node;
break;
case 2:
if (crsr >= node->proj1.start && crsr < node->proj1.end) return node;
+23 -23
View File
@@ -50,24 +50,24 @@ void update_codeview_position() {
if (cv_source->visible_r()) {
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
pos0 = Fluid.proj.tree.current->code1.start;
pos1 = Fluid.proj.tree.current->code2.end;
pos0 = Fluid.proj.tree.current->setup_node.c.start;
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
break;
case 1: // static: callbacks, menu declarations
pos0 = Fluid.proj.tree.current->code_static.start;
pos1 = Fluid.proj.tree.current->code_static.end;
pos0 = Fluid.proj.tree.current->static_data.c.start;
pos1 = Fluid.proj.tree.current->static_data.c.end;
break;
case 2: // code: entire implementation block including children
pos0 = Fluid.proj.tree.current->code1.start;
pos1 = Fluid.proj.tree.current->code2.end;
pos0 = Fluid.proj.tree.current->setup_node.c.start;
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->code1.start;
pos1 = Fluid.proj.tree.current->code1.end;
pos0 = Fluid.proj.tree.current->setup_node.c.start;
pos1 = Fluid.proj.tree.current->setup_node.c.end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->code2.start;
pos1 = Fluid.proj.tree.current->code2.end;
pos0 = Fluid.proj.tree.current->finalize_node.c.start;
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
break;
}
if (pos0>=0) {
@@ -82,20 +82,20 @@ void update_codeview_position() {
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
case 1: // static: callbacks, menu declarations
pos0 = Fluid.proj.tree.current->header_static.start;
pos1 = Fluid.proj.tree.current->header_static.end;
pos0 = Fluid.proj.tree.current->static_data.h.start;
pos1 = Fluid.proj.tree.current->static_data.h.end;
break;
case 2: // code: entire implementation block including children
pos0 = Fluid.proj.tree.current->header1.start;
pos1 = Fluid.proj.tree.current->header2.end;
pos0 = Fluid.proj.tree.current->setup_node.h.start;
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->header1.start;
pos1 = Fluid.proj.tree.current->header1.end;
pos0 = Fluid.proj.tree.current->setup_node.h.start;
pos1 = Fluid.proj.tree.current->setup_node.h.end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->header2.start;
pos1 = Fluid.proj.tree.current->header2.end;
pos0 = Fluid.proj.tree.current->finalize_node.h.start;
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
break;
}
if (pos0>=0) {
@@ -375,10 +375,10 @@ static void cb_cv_code_choice_w(Fl_Choice* o, void*) {
Fl_Menu_Item menu_cv_code_choice_w[] = {
{"prolog", 0, nullptr, (void*)(0), 16, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"static", 0, nullptr, (void*)(1), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"code", 0, nullptr, (void*)(2), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"code 1", 0, nullptr, (void*)(3), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"code 2", 0, nullptr, (void*)(4), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"static data", 0, nullptr, (void*)(1), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"instantiate", 0, nullptr, (void*)(2), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"setup", 0, nullptr, (void*)(3), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{"finalize", 0, nullptr, (void*)(4), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0 },
{ nullptr, 0, nullptr, nullptr, 0, 0, 0, 0, 0 }
};
@@ -517,7 +517,7 @@ Fl_Double_Window* make_codeview() {
{ cv_autoposition = new Fl_Light_Button(172, 485, 89, 20, "Auto-Position");
cv_autoposition->labelsize(11);
} // Fl_Light_Button* cv_autoposition
{ cv_code_choice_w = new Fl_Choice(265, 485, 70, 20);
{ cv_code_choice_w = new Fl_Choice(265, 485, 90, 20);
cv_code_choice_w->down_box(FL_BORDER_BOX);
cv_code_choice_w->labelsize(11);
cv_code_choice_w->textsize(11);
+26 -27
View File
@@ -78,24 +78,24 @@ file.} open return_type void
if (cv_source->visible_r()) {
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
pos0 = Fluid.proj.tree.current->code1.start;
pos1 = Fluid.proj.tree.current->code2.end;
pos0 = Fluid.proj.tree.current->setup_node.c.start;
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
break;
case 1: // static: callbacks, menu declarations
pos0 = Fluid.proj.tree.current->code_static.start;
pos1 = Fluid.proj.tree.current->code_static.end;
pos0 = Fluid.proj.tree.current->static_data.c.start;
pos1 = Fluid.proj.tree.current->static_data.c.end;
break;
case 2: // code: entire implementation block including children
pos0 = Fluid.proj.tree.current->code1.start;
pos1 = Fluid.proj.tree.current->code2.end;
pos0 = Fluid.proj.tree.current->setup_node.c.start;
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->code1.start;
pos1 = Fluid.proj.tree.current->code1.end;
pos0 = Fluid.proj.tree.current->setup_node.c.start;
pos1 = Fluid.proj.tree.current->setup_node.c.end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->code2.start;
pos1 = Fluid.proj.tree.current->code2.end;
pos0 = Fluid.proj.tree.current->finalize_node.c.start;
pos1 = Fluid.proj.tree.current->finalize_node.c.end;
break;
}
if (pos0>=0) {
@@ -110,20 +110,20 @@ file.} open return_type void
switch (cv_code_choice) {
case 0: // prolog: not yet (include statements)
case 1: // static: callbacks, menu declarations
pos0 = Fluid.proj.tree.current->header_static.start;
pos1 = Fluid.proj.tree.current->header_static.end;
pos0 = Fluid.proj.tree.current->static_data.h.start;
pos1 = Fluid.proj.tree.current->static_data.h.end;
break;
case 2: // code: entire implementation block including children
pos0 = Fluid.proj.tree.current->header1.start;
pos1 = Fluid.proj.tree.current->header2.end;
pos0 = Fluid.proj.tree.current->setup_node.h.start;
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
break;
case 3: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->header1.start;
pos1 = Fluid.proj.tree.current->header1.end;
pos0 = Fluid.proj.tree.current->setup_node.h.start;
pos1 = Fluid.proj.tree.current->setup_node.h.end;
break;
case 4: // code1: all implementation code before the children
pos0 = Fluid.proj.tree.current->header2.start;
pos1 = Fluid.proj.tree.current->header2.end;
pos0 = Fluid.proj.tree.current->finalize_node.h.start;
pos1 = Fluid.proj.tree.current->finalize_node.h.end;
break;
}
if (pos0>=0) {
@@ -224,8 +224,7 @@ if (cv_project->visible_r()) {
}
if (Fluid.proj.proj_filename)
Fluid.proj.leave_project_dir();
}} {selected
}
}} {}
}
Function {update_codeview_timer(void*)} {
@@ -281,8 +280,8 @@ Function {make_codeview()} {open
} {
Fl_Window codeview_panel {
label {Code View}
callback toggle_codeview_cb open
xywh {389 507 520 515} type Double align 80 resizable size_range {384 120 0 0} visible
callback toggle_codeview_cb open selected
xywh {518 271 520 515} type Double align 80 resizable size_range {384 120 0 0} visible
} {
Fl_Tabs cv_tab {
callback update_codeview_position_cb open
@@ -461,7 +460,7 @@ if (e) {
Fl_Choice cv_code_choice_w {
callback {cv_code_choice = (int)o->mvalue()->argument();
update_codeview_position();} open
xywh {265 485 70 20} down_box BORDER_BOX labelsize 11 textsize 11
xywh {265 485 90 20} down_box BORDER_BOX labelsize 11 textsize 11
} {
MenuItem {} {
label prolog
@@ -469,22 +468,22 @@ update_codeview_position();} open
tooltip {Include statements in header or source code} xywh {0 0 100 20} labelsize 11 hide
}
MenuItem {} {
label static
label {static data}
user_data 1 user_data_type long
tooltip {static declarations in source code} xywh {10 10 100 20} labelsize 11
}
MenuItem {} {
label code
label instantiate
user_data 2 user_data_type long
tooltip {widget code block including children} xywh {20 20 100 20} labelsize 11
}
MenuItem {} {
label {code 1}
label setup
user_data 3 user_data_type long
tooltip {widget code block before children} xywh {30 30 100 20} labelsize 11
}
MenuItem {} {
label {code 2}
label finalize
user_data 4 user_data_type long
tooltip {widget code block after children} xywh {40 40 100 20} labelsize 11
}
+1 -1
View File
@@ -54,6 +54,6 @@ extern Fl_Choice* cv_code_choice_w;
extern void toggle_codeview_b_cb(Fl_Button*, void*);
Fl_Double_Window* make_codeview();
extern Fl_Menu_Item menu_cv_code_choice_w[];
#endif
#endif // codeview_panel_h
//
+1 -1
View File
@@ -151,4 +151,4 @@ extern Fl_Menu_Item menu_9[];
extern Fl_Menu_Item menu_a[];
extern Fl_Menu_Item menu_b[];
extern Fl_Menu_Item menu_c[];
#endif
#endif // widget_panel_h