Fluid: Modernize Function Nodes
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled

This commit is contained in:
Matthias Melcher
2026-01-05 01:29:08 +01:00
parent 48617a8075
commit 11325da073
4 changed files with 115 additions and 166 deletions
+45 -74
View File
@@ -188,25 +188,6 @@ const char *c_check(const char *c, int type) {
/// Prototype for a function to be used by the factory.
Function_Node Function_Node::prototype;
/**
Create a new function.
*/
Function_Node::Function_Node() :
Node(),
return_type_(nullptr),
public_(0),
declare_c_(0),
constructor(0),
havewidgets(0)
{ }
/**
Destructor.
*/
Function_Node::~Function_Node() {
if (return_type_) free((void*)return_type_);
}
/**
Create a new function for the widget tree.
\param[in] strategy add new function after current or as last child
@@ -223,7 +204,7 @@ Node *Function_Node::make(Strategy strategy) {
}
Function_Node *o = new Function_Node();
o->name("make_window()");
o->return_type_ = nullptr;
o->return_type_.clear();
o->add(anchor, strategy);
o->factory = this;
o->public_ = 1;
@@ -244,9 +225,9 @@ void Function_Node::write_properties(fld::io::Project_Writer &f) {
case 2: f.write_string("protected"); break;
}
if (declare_c_) f.write_string("C");
if (return_type_) {
if (!return_type().empty()) {
f.write_string("return_type");
f.write_word(return_type_);
f.write_word(return_type().c_str());
}
}
@@ -262,7 +243,7 @@ void Function_Node::read_property(fld::io::Project_Reader &f, const char *c) {
} else if (!strcmp(c,"C")) {
declare_c_ = 1;
} else if (!strcmp(c,"return_type")) {
storestring(f.read_word(),return_type_);
return_type(f.read_word());
} else {
Node::read_property(f, c);
}
@@ -354,25 +335,37 @@ void Function_Node::write_code1(fld::io::Code_Writer& f) {
if (havechildren)
f.write_c("int main(int argc, char **argv) {\n");
} else {
const char* rtype = return_type_;
const char* star = "";
std::string rtype = return_type();
std::string star = "";
// from matt: let the user type "static " at the start of type
// in order to declare a static method;
int is_static = 0;
int is_virtual = 0;
if (rtype) {
if (!strcmp(rtype,"static")) {is_static = 1; rtype = nullptr;}
else if (!strncmp(rtype, "static ",7)) {is_static = 1; rtype += 7;}
if (!rtype.empty()) {
if (rtype == "static") {
is_static = 1;
rtype.clear();
} else if (rtype.compare(0, 7, "static ")==0) {
is_static = 1;
rtype.erase(0, 7);
}
}
if (rtype) {
if (!strcmp(rtype, "virtual")) {is_virtual = 1; rtype = nullptr;}
else if (!strncmp(rtype, "virtual ",8)) {is_virtual = 1; rtype += 8;}
if (!rtype.empty()) {
if (rtype == "virtual") {
is_virtual = 1;
rtype.clear();
} else if (rtype.compare(0, 8, "virtual ")==0) {
is_virtual = 1;
rtype.erase(0, 8);
}
}
if (!rtype) {
if (rtype.empty()) {
if (havewidgets) {
rtype = subclassname(child);
star = "*";
} else rtype = "void";
} else {
rtype = "void";
}
}
const char* k = class_name(0);
@@ -390,9 +383,9 @@ void Function_Node::write_code1(fld::io::Code_Writer& f) {
if (is_static) f.write_h("static ");
if (is_virtual) f.write_h("virtual ");
if (!constructor) {
f.write_h("%s%s ", rtype, star);
f.write_h("%s%s ", rtype.c_str(), star.c_str());
if (havechildren)
f.write_c("%s%s ", rtype, star);
f.write_c("%s%s ", rtype.c_str(), star.c_str());
}
// if this is a subclass, only f.write_h() the part before the ':'
@@ -423,9 +416,9 @@ void Function_Node::write_code1(fld::io::Code_Writer& f) {
write_comment_c(f);
if (public_==1) {
if (declare_c_)
f.write_h("extern \"C\" { %s%s %s; }\n", rtype, star, name());
f.write_h("extern \"C\" { %s%s %s; }\n", rtype.c_str(), star.c_str(), name());
else
f.write_h("%s%s %s;\n", rtype, star, name());
f.write_h("%s%s %s;\n", rtype.c_str(), star.c_str(), name());
} else if (public_==2) {
// write neither the prototype nor static, the function may be declared elsewhere
} else {
@@ -437,7 +430,7 @@ void Function_Node::write_code1(fld::io::Code_Writer& f) {
char s[1024];
if (havechildren) {
clean_function_for_implementation(s, name());
f.write_c("%s%s %s {\n", rtype, star, s);
f.write_c("%s%s %s {\n", rtype.c_str(), star.c_str(), s);
}
}
}
@@ -466,7 +459,7 @@ void Function_Node::write_code2(fld::io::Code_Writer& f) {
f.write_c("%s%s->show(argc, argv);\n", f.indent(1), var);
if (havechildren)
f.write_c("%sreturn Fl::run();\n", f.indent(1));
} else if (havewidgets && !constructor && !return_type_) {
} else if (havewidgets && !constructor && return_type().empty()) {
f.write_c("%sreturn %s;\n", f.indent(1), var);
}
if (havechildren)
@@ -481,10 +474,11 @@ void Function_Node::write_code2(fld::io::Code_Writer& f) {
\return 1 if they match, 0 if not
*/
int Function_Node::has_signature(const char *rtype, const char *sig) const {
if (rtype && !return_type_) return 0;
if (!name()) return 0;
if ( (rtype==nullptr || strcmp(return_type_, rtype)==0)
&& fl_filename_match(name(), sig)) {
if (rtype && return_type().empty())
return 0;
if (!name())
return 0;
if ( (rtype==nullptr || (return_type() == rtype)) && fl_filename_match(name(), sig)) {
return 1;
}
return 0;
@@ -503,15 +497,6 @@ int Function_Node::has_signature(const char *rtype, const char *sig) const {
/// Prototype for code to be used by the factory.
Code_Node Code_Node::prototype;
/**
Constructor.
*/
Code_Node::Code_Node() :
cursor_position_(0),
code_input_scroll_row(0),
code_input_scroll_col(0)
{}
/**
Make a new code node.
If the parent node is not a function, a message box will pop up and
@@ -633,22 +618,6 @@ int Code_Node::handle_editor_changes() {
/// Prototype for a block of code to be used by the factory.
CodeBlock_Node CodeBlock_Node::prototype;
/**
Constructor.
*/
CodeBlock_Node::CodeBlock_Node() :
Node(),
after(nullptr)
{ }
/**
Destructor.
*/
CodeBlock_Node::~CodeBlock_Node() {
if (after)
free((void*)after);
}
/**
Make a new code block.
If the parent node is not a function or another codeblock, a message box will
@@ -671,7 +640,7 @@ Node *CodeBlock_Node::make(Strategy strategy) {
}
CodeBlock_Node *o = new CodeBlock_Node();
o->name("if (test())");
o->after = nullptr;
o->end_code_.clear();
o->add(anchor, strategy);
o->factory = this;
return o;
@@ -684,9 +653,9 @@ Node *CodeBlock_Node::make(Strategy strategy) {
*/
void CodeBlock_Node::write_properties(fld::io::Project_Writer &f) {
Node::write_properties(f);
if (after) {
if (!end_code().empty()) {
f.write_string("after");
f.write_word(after);
f.write_word(end_code().c_str());
}
}
@@ -695,7 +664,7 @@ void CodeBlock_Node::write_properties(fld::io::Project_Writer &f) {
*/
void CodeBlock_Node::read_property(fld::io::Project_Reader &f, const char *c) {
if (!strcmp(c,"after")) {
storestring(f.read_word(),after);
end_code(f.read_word());
} else {
Node::read_property(f, c);
}
@@ -722,8 +691,10 @@ void CodeBlock_Node::write_code1(fld::io::Code_Writer& f) {
*/
void CodeBlock_Node::write_code2(fld::io::Code_Writer& f) {
f.indentation--;
if (after) f.write_c("%s} %s\n", f.indent(), after);
else f.write_c("%s}\n", f.indent());
if (!end_code().empty())
f.write_c("%s} %s\n", f.indent(), end_code().c_str());
else
f.write_c("%s}\n", f.indent());
}
// ---- Decl_Node declaration
+38 -20
View File
@@ -1,7 +1,7 @@
//
// C function Node header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2025 by Bill Spitzak and others.
// Copyright 1998-2026 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -49,21 +49,25 @@ class Function_Node : public Node
public:
typedef Node super;
static Function_Node prototype;
private:
const char* return_type_;
char public_, declare_c_, constructor, havewidgets;
std::string return_type_;
char public_ = 0;
char declare_c_ = 0;
char constructor = 0;
char havewidgets = 0;
public:
Function_Node();
~Function_Node();
Function_Node() = default;
~Function_Node() override = default;
Node *make(Strategy strategy) override;
void write_code1(fld::io::Code_Writer& f) override;
void write_code2(fld::io::Code_Writer& f) override;
void open() override;
int ismain() {return name_ == nullptr;}
const char *type_name() override {return "Function";}
const char *title() override {
return name() ? name() : "main()";
}
const char *title() override { return name() ? name() : "main()"; }
int can_have_children() const override {return 1;}
int is_code_block() const override {return 1;}
int is_public() const override;
@@ -72,8 +76,8 @@ public:
void write_properties(fld::io::Project_Writer &f) override;
void read_property(fld::io::Project_Reader &f, const char *) override;
int has_signature(const char *, const char*) const;
const char *return_type() { return return_type_; }
void return_type(const char *t) { storestring(t, return_type_); }
std::string return_type() const { return return_type_; }
void return_type(const std::string& t) { storestring(t, return_type_); }
char visibility() { return public_; }
void visibility(char v) { public_ = v; }
char declare_c() { return declare_c_; }
@@ -87,13 +91,17 @@ class Code_Node : public Node
public:
typedef Node super;
static Code_Node prototype;
int cursor_position_;
int code_input_scroll_row;
int code_input_scroll_col;
private:
int cursor_position_ = 0;
int code_input_scroll_row_ = 0;
int code_input_scroll_col_ = 0;
ExternalCodeEditor editor_;
public:
Code_Node();
Code_Node() = default;
~Code_Node() override = default;
Node *make(Strategy strategy) override;
void write(fld::io::Project_Writer &f) override;
void write_code1(fld::io::Code_Writer& f) override;
@@ -107,6 +115,12 @@ public:
int is_editing();
int reap_editor();
int handle_editor_changes();
int cursor_position() { return cursor_position_; }
int code_input_scroll_row() { return code_input_scroll_row_; }
int code_input_scroll_col() { return code_input_scroll_col_; }
void save_editor_state(int pos, int row, int col) {
cursor_position_ = pos; code_input_scroll_row_ = row; code_input_scroll_col_ = col;
}
};
// ---- CodeBlock_Node declaration
@@ -116,11 +130,14 @@ class CodeBlock_Node : public Node
public:
typedef Node super;
static CodeBlock_Node prototype;
private:
const char* after;
std::string end_code_;
public:
CodeBlock_Node();
~CodeBlock_Node();
CodeBlock_Node() = default;
~CodeBlock_Node() override = default;
Node *make(Strategy strategy) override;
void write_code1(fld::io::Code_Writer& f) override;
void write_code2(fld::io::Code_Writer& f) override;
@@ -133,8 +150,8 @@ public:
bool is_a(Type inType) const override { return (inType==Type::CodeBlock) ? true : super::is_a(inType); }
void write_properties(fld::io::Project_Writer &f) override;
void read_property(fld::io::Project_Reader &f, const char *) override;
const char *end_code() { return after; }
void end_code(const char *c) { storestring(c, after); }
std::string end_code() { return end_code_; }
void end_code(const std::string& c) { storestring(c, end_code_); }
};
// ---- Decl_Node declaration
@@ -176,9 +193,10 @@ class Data_Node : public Decl_Node
public:
typedef Decl_Node super;
static Data_Node prototype;
private:
std::string filename_;
int output_format_ { 0 };
int output_format_ = 0;
public:
Data_Node() = default;
+17 -37
View File
@@ -3295,19 +3295,11 @@ static void cb_End1(Fl_Input* o, void* v) {
//fl ▼ ---------------------- callback ~~-~~=~=-~=-~-=~~~=-=~ ▼ fl//
if (!current_node || !current_node->is_a(Type::CodeBlock)) return;
CodeBlock_Node* nd = (CodeBlock_Node*)current_node;
if (v == LOAD) {
o->value( nd->end_code() );
} else {
const char *nn = nd->end_code();
if ( ( nn && (strcmp(nn, o->value()) != 0))
|| (!nn && (strcmp("", o->value()) != 0)) )
{
nd->end_code( o->value() );
Fluid.proj.set_modflag(1);
}
}
//fl ▲ ----------~=----=-~-=~-------------=~~--=--~=~=--~-~~- ▲ fl//
update_current(o, v,
[nd](){return nd->end_code();},
[nd](std::string s){nd->end_code(s);}
);
//fl ▲ ----------~=----=-~-=~----------~~~~-~-=~--=-=~~=---~~ ▲ fl//
}
static void cb_Comment4(Fl_Text_Editor* o, void* v) {
@@ -3348,13 +3340,12 @@ static void cb_1c(fld::widget::Code_Editor* o, void* v) {
//fl ▼ ---------------------- callback ~-=--~=~~==~=~=~-~--=~ ▼ fl//
if (!current_node || !current_node->is_a(Type::Code)) return;
Code_Node* nd = (Code_Node*)current_node;
if (v == LOAD) {
if (v == LOAD) {
the_panel->label("Code Editor");
const char *cmttext = nd->name();
o->buffer()->text( cmttext ? cmttext : "" );
o->insert_position(nd->cursor_position_);
o->scroll(nd->code_input_scroll_row, nd->code_input_scroll_col);
o->insert_position(nd->cursor_position());
o->scroll(nd->code_input_scroll_row(), nd->code_input_scroll_col());
} else {
char *c = o->buffer()->text();
const char *nn = nd->name();
@@ -3365,12 +3356,12 @@ static void cb_1c(fld::widget::Code_Editor* o, void* v) {
Fluid.proj.set_modflag(1);
redraw_browser();
}
nd->cursor_position_ = o->insert_position();
nd->code_input_scroll_row = o->scroll_row();
nd->code_input_scroll_col = o->scroll_col();
nd->save_editor_state(o->insert_position(),
o->scroll_row(),
o->scroll_col());
free(c);
}
//fl ▲ ----------=~=~=~~=--=~----------~~=~~--==-=----=-~~=~~ ▲ fl//
//fl ▲ ----------=~=~=~~=--=~------------=-----~=~~-~-=-~~=~= ▲ fl//
}
Fl_Tabs *func_tabs=(Fl_Tabs *)0;
@@ -3496,22 +3487,11 @@ static void cb_Return(fld::widget::Code_Editor* o, void* v) {
//fl ▼ ---------------------- callback -~=--~-~=~=~~~---=~~=~ ▼ fl//
if (!current_node || !current_node->is_a(Type::Function)) return;
Function_Node* nd = (Function_Node*)current_node;
if (v == LOAD) {
const char *cmttext = nd->return_type();
o->buffer()->text( cmttext ? cmttext : "" );
} else {
char *c = o->buffer()->text();
const char *nn = nd->return_type();
if ( ( nn && (strcmp(nn, c) != 0))
|| (!nn && (strcmp("", c) != 0)) )
{
nd->return_type(c);
Fluid.proj.set_modflag(1);
}
free(c);
}
//fl ▲ ----------~=~~=~~==~~------------~~=------=~-=~==~-~-- ▲ fl//
update_current(o, v,
[nd](){return nd->return_type();},
[nd](std::string s){nd->return_type(s);}
);
//fl ▲ ----------~=~~=~~==~~-----------~~=~=-~=~-~-~-=~-=~--~ ▲ fl//
}
static void cb_Comment5(Fl_Text_Editor* o, void* v) {
+15 -35
View File
@@ -528,7 +528,7 @@ Function {make_widget_panel()} {uid 9310
} {
Fl_Tabs widget_tabs {uid ce20
callback {if (current_widget)
propagate_load((Fl_Group *)o,v);} selected
propagate_load((Fl_Group *)o,v);}
xywh {10 10 400 350} selection_color 12 labelsize 11 labelcolor 7 when 0
code0 {o->show();}
} {
@@ -3525,18 +3525,10 @@ if (v == LOAD) {
label {End Code:}
callback {if (!current_node || !current_node->is_a(Type::CodeBlock)) return;
CodeBlock_Node* nd = (CodeBlock_Node*)current_node;
if (v == LOAD) {
o->value( nd->end_code() );
} else {
const char *nn = nd->end_code();
if ( ( nn && (strcmp(nn, o->value()) != 0))
|| (!nn && (strcmp("", o->value()) != 0)) )
{
nd->end_code( o->value() );
Fluid.proj.set_modflag(1);
}
}}
update_current(o, v,
[nd](){return nd->end_code();},
[nd](std::string s){nd->end_code(s);}
);}
tooltip {condition end: `while (x==1);`, or empty} xywh {95 75 305 20} labelfont 1 labelsize 11 textfont 4 textsize 11
}
Fl_Text_Editor {} {uid 13f0
@@ -3578,13 +3570,12 @@ if (v == LOAD) {
Fl_Text_Editor {} {uid ff87
callback {if (!current_node || !current_node->is_a(Type::Code)) return;
Code_Node* nd = (Code_Node*)current_node;
if (v == LOAD) {
if (v == LOAD) {
the_panel->label("Code Editor");
const char *cmttext = nd->name();
o->buffer()->text( cmttext ? cmttext : "" );
o->insert_position(nd->cursor_position_);
o->scroll(nd->code_input_scroll_row, nd->code_input_scroll_col);
o->insert_position(nd->cursor_position());
o->scroll(nd->code_input_scroll_row(), nd->code_input_scroll_col());
} else {
char *c = o->buffer()->text();
const char *nn = nd->name();
@@ -3595,9 +3586,9 @@ if (v == LOAD) {
Fluid.proj.set_modflag(1);
redraw_browser();
}
nd->cursor_position_ = o->insert_position();
nd->code_input_scroll_row = o->scroll_row();
nd->code_input_scroll_col = o->scroll_col();
nd->save_editor_state(o->insert_position(),
o->scroll_row(),
o->scroll_col());
free(c);
}}
xywh {15 40 390 315} box DOWN_BOX labelsize 11 when 15 textfont 4 textsize 11 resizable
@@ -3763,21 +3754,10 @@ if (v == LOAD) {
label {Return Type:}
callback {if (!current_node || !current_node->is_a(Type::Function)) return;
Function_Node* nd = (Function_Node*)current_node;
if (v == LOAD) {
const char *cmttext = nd->return_type();
o->buffer()->text( cmttext ? cmttext : "" );
} else {
char *c = o->buffer()->text();
const char *nn = nd->return_type();
if ( ( nn && (strcmp(nn, c) != 0))
|| (!nn && (strcmp("", c) != 0)) )
{
nd->return_type(c);
Fluid.proj.set_modflag(1);
}
free(c);
}}
update_current(o, v,
[nd](){return nd->return_type();},
[nd](std::string s){nd->return_type(s);}
);}
tooltip {return type, or blank to return outermost widget} xywh {95 160 310 50} labelfont 1 labelsize 11 align 132 textsize 11 resizable
code0 {\#include "widgets/Code_Editor.h"}
code1 {o->add_key_binding(FL_Tab, 0, use_tab_navigation);}