Fluid: remove three global state variables

* improves handling of class in class
  (still not recommended)
This commit is contained in:
Matthias Melcher
2026-08-13 18:10:45 +02:00
parent 7f5dae5bd8
commit 786bdbfd54
9 changed files with 47 additions and 50 deletions
+36 -13
View File
@@ -474,10 +474,11 @@ void Code_Writer::write_c_indented(const std::string& codeblock, int additional_
bool is_class_member(Node *t) {
return dynamic_cast<Function_Node*>(t)
|| dynamic_cast<Decl_Node*>(t)
|| dynamic_cast<Data_Node*>(t);
// || dynamic_cast<Class_Node*>(t) // FLUID can't handle a class inside a class
// || dynamic_cast<Widget_Class_Node*>(t) // ???
// || dynamic_cast<DeclBlock_Node*>(t) // Declaration blocks are generally not handled well
|| dynamic_cast<Data_Node*>(t)
|| dynamic_cast<Class_Node*>(t) // Caution, class in a class mostly untested
|| dynamic_cast<Widget_Class_Node*>(t) // Caution, class in a class mostly untested
// || dynamic_cast<DeclBlock_Node*>(t) // Declaration blocks are generally not handled well
;
}
/**
@@ -537,8 +538,16 @@ Node* Code_Writer::write_code(Node* p) {
}
// recursively write the code of all children
Node* q;
if (p->is_widget() && p->is_class()) {
// Handle widget classes specially
if (dynamic_cast<Widget_Class_Node*>(p)) {
// Legacy handling for Widget_Class_Node:
// As the name suggests, these are widgets and classes at the same time.
// The implementation is a class that generates a collection of widgets
// in a Fl_Group of Fl_Window (or derived).
// Problem is, widgets are created directly as children of Widget_Class_Node
// instead of inside a constructor. So below we have to treat all children
// that are widgets in write_code1(), and all children that are regular
// class members (Methods, Variables) *after* write_code2().
// \todo Widgets should be required to be in a constructor
for (q = p->next; q && q->level > p->level;) {
// note: maybe declaration blocks should be handled like comments in the context
if (!is_class_member(q) && !is_comment_before_class_member(q)) {
@@ -568,7 +577,7 @@ Node* Code_Writer::write_code(Node* p) {
}
write_h("};\n");
current_widget_class = nullptr;
class_stack.pop_back();
} else {
for (q = p->next; q && q->level > p->level;) q = write_code(q);
// write all code that come after the children
@@ -788,12 +797,26 @@ int Code_Writer::flush()
This avoids repeating these words if the mode is already set.
\param[in] state 0 for private, 1 for public, 2 for protected
*/
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;
if (current_class) current_class->write_public_state = state;
if (current_widget_class) current_widget_class->write_public_state = state;
void Code_Writer::write_public(int state)
{
if (class_stack.empty()) {
return;
}
auto* top = class_stack.back();
auto* current_class = dynamic_cast<Class_Node*>(top);
auto* current_widget_class = dynamic_cast<Widget_Class_Node*>(top);
if (current_class) {
if (current_class->write_public_state == state)
return;
current_class->write_public_state = state;
} else if (current_widget_class) {
if (current_widget_class->write_public_state == state)
return;
current_widget_class->write_public_state = state;
} else {
return;
}
switch (state) {
case 0: write_h("private:\n"); break;
case 1: write_h("public:\n"); break;
+4
View File
@@ -130,6 +130,10 @@ public:
/// (disables binary data blocks, for example)
bool write_codeview { false };
/// Set while we are descending inside a Class or Widget Class node, so we can
/// write public/private/protected keywords as needed.
std::vector<Node*> class_stack { };
public:
Code_Writer(Project &proj);
Code_Writer(const Code_Writer &) = delete;
+3 -7
View File
@@ -41,9 +41,6 @@ using namespace fluid;
using namespace fluid::io;
using namespace fluid::proj;
/// Set a current class, so that the code of the children is generated correctly.
Class_Node *current_class = nullptr;
/**
Check if the node tree has a top-level function with the given return type and signature.
\param[in] return_type_regex regex for the return type of the function,
@@ -1492,9 +1489,8 @@ void Class_Node::open() {
Write the header code that declares this class.
*/
void Class_Node::write_code1(fluid::io::Code_Writer& f) {
parent_class = current_class;
current_class = this;
write_public_state = 0;
f.class_stack.push_back(this);
write_public_state = 0; // private:
f.write_h("\n");
write_comment_h(f);
if (!prefix().empty())
@@ -1512,6 +1508,6 @@ void Class_Node::write_code1(fluid::io::Code_Writer& f) {
*/
void Class_Node::write_code2(fluid::io::Code_Writer& f) {
f.write_h("};\n");
current_class = parent_class;
f.class_stack.pop_back();
}
-1
View File
@@ -36,7 +36,6 @@
#include <string>
extern class Class_Node *current_class;
bool has_toplevel_function(const std::string& return_type_regex, const std::string& function_sig_regex);
-14
View File
@@ -109,10 +109,6 @@
#include <stdlib.h>
#include <stdio.h>
// ---- global variables
Node *in_this_only; // set if menu popped-up in window
// ---- various functions
/**
@@ -120,11 +116,6 @@ Node *in_this_only; // set if menu popped-up in window
*/
void select_all_cb(Fl_Widget *,void *) {
Node *p = Fluid.proj.tree.current ? Fluid.proj.tree.current->parent : nullptr;
if (in_this_only) {
Node *t = p;
for (; t && t != in_this_only; t = t->parent) {/*empty*/}
if (t != in_this_only) p = in_this_only;
}
for (;;) {
if (p) {
int foundany = 0;
@@ -147,11 +138,6 @@ void select_all_cb(Fl_Widget *,void *) {
*/
void select_none_cb(Fl_Widget *,void *) {
Node *p = Fluid.proj.tree.current ? Fluid.proj.tree.current->parent : nullptr;
if (in_this_only) {
Node *t = p;
for (; t && t != in_this_only; t = t->parent) {/*empty*/}
if (t != in_this_only) p = in_this_only;
}
for (;;) {
if (p) {
int foundany = 0;
+3 -12
View File
@@ -793,7 +793,6 @@ void toggle_restricted_cb(Fl_Check_Button *o, void *v) {
extern void select(Node *,int);
extern void select_only(Node *);
extern void deselect();
extern Node* in_this_only;
extern void fix_group_size(Node *t);
extern Fl_Menu_Item New_Menu[];
@@ -1003,7 +1002,6 @@ int Window_Node::handle(int event) {
return 1;
}
in_this_only = this;
popupx = Fl::event_x();
popupy = Fl::event_y();
// If the selected widget at dnd start and the drop target are the same,
@@ -1022,7 +1020,6 @@ int Window_Node::handle(int event) {
}
popupx = 0x7FFFFFFF;
popupy = 0x7FFFFFFF; // mark as invalid (MAXINT)
in_this_only = nullptr;
widget_browser->display(Fluid.proj.tree.current);
widget_browser->rebuild();
return 1;
@@ -1033,13 +1030,11 @@ int Window_Node::handle(int event) {
drag = dx = dy = 0;
// test for popup menu:
if (Fl::event_button() >= 3) {
in_this_only = this; // modifies how some menu items work.
static const Fl_Menu_Item* myprev;
popupx = mx; popupy = my;
const Fl_Menu_Item* m = New_Menu->popup(mx,my,"New",myprev);
if (m && m->callback()) {myprev = m; m->do_callback(this->o);}
popupx = 0x7FFFFFFF; popupy = 0x7FFFFFFF; // mark as invalid (MAXINT)
in_this_only = nullptr;
return 1;
}
// find the innermost item clicked on:
@@ -1186,10 +1181,8 @@ int Window_Node::handle(int event) {
}}
case FL_SHORTCUT: {
in_this_only = this; // modifies how some menu items work.
const Fl_Menu_Item* m = Fluid.main_menu->test_shortcut();
if (m && m->callback()) m->do_callback(this->o);
in_this_only = nullptr;
return (m != nullptr);}
default:
@@ -1314,8 +1307,6 @@ int Window_Node::read_fdesign(const char* propname, const char* value) {
Widget_Class_Node Widget_Class_Node::prototype;
Widget_Class_Node *current_widget_class = nullptr;
/**
Create and add a new Widget Class node.
\param[in] strategy add after current or as last child
@@ -1386,9 +1377,8 @@ void Widget_Class_Node::write_code1(fluid::io::Code_Writer& f) {
#if 0
Widget_Node::write_code1(fluid::io::Code_Writer& f);
#endif // 0
current_widget_class = this;
write_public_state = 1;
f.class_stack.push_back(this);
write_public_state = 1; // public:, because the constructors follow.
std::string c = subclass();
if (c.empty()) c = "Fl_Group";
@@ -1487,6 +1477,7 @@ void Widget_Class_Node::write_code2(fluid::io::Code_Writer& f) {
f.write_c(f.indent() + "resize(X, Y, W, H);\n");
f.indent_less();
f.write_c("}\n");
//class_stack.pop_back(); is called in Code_Writer::write_code(Node* p)
}
-1
View File
@@ -27,7 +27,6 @@
class Widget_Class_Node;
extern Fl_Menu_Item window_type_menu[];
extern Widget_Class_Node *current_widget_class;
void toggle_overlays(Fl_Widget *,void *);
void toggle_guides(Fl_Widget *,void *);
+1 -1
View File
@@ -2723,7 +2723,7 @@ static void cb_Reset(Fl_Button* o, void* v) {
o->parent()->do_callback(o->parent(), LOAD);
widget_browser->redraw();
widget_browser->save_prefs();
//fl ▲ ----------~=-=~==~~=~------------~-=~~~~-~~=~-~~=~~=~- ▲ fl//
//fl ▲ ----------~=-=~==~~=~------------~~-~~~==~=-=-=-~-=--~ ▲ fl//
}
static void cb_Close(Fl_Button*, void*) {
@@ -73,7 +73,6 @@ private:
static void cb_6(Fl_Button*, void*);
inline void cb_7_i(Fl_Button*, void*);
static void cb_7(Fl_Button*, void*);
public:
void grid_child_cb(fluid::widget::Formula_Input* i, void* v, int what);
};
#endif // Grid_Child_Tab_h