1998-10-21 20:29:01 +04:00
|
|
|
//
|
|
|
|
// C function type code for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2023-08-26 16:17:28 +03:00
|
|
|
// Copyright 1998-2023 by Bill Spitzak and others.
|
1998-10-21 20:29:01 +04:00
|
|
|
//
|
2011-07-19 08:49:30 +04:00
|
|
|
// 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
|
|
|
|
// file is missing or damaged, see the license at:
|
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// https://www.fltk.org/COPYING.php
|
1998-10-21 20:29:01 +04:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// Please see the following page on how to report bugs and issues:
|
2005-04-16 04:13:17 +04:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// https://www.fltk.org/bugs.php
|
1998-10-21 20:29:01 +04:00
|
|
|
//
|
2021-12-08 17:52:15 +03:00
|
|
|
|
|
|
|
#include "Fl_Function_Type.h"
|
|
|
|
|
|
|
|
#include "fluid.h"
|
|
|
|
#include "Fl_Window_Type.h"
|
|
|
|
#include "Fl_Group_Type.h"
|
|
|
|
#include "widget_browser.h"
|
|
|
|
#include "file.h"
|
|
|
|
#include "code.h"
|
|
|
|
#include "function_panel.h"
|
|
|
|
#include "comments.h"
|
2023-10-27 00:31:12 +03:00
|
|
|
#include "mergeback.h"
|
2023-11-16 15:21:17 +03:00
|
|
|
#include "undo.h"
|
2021-12-08 17:52:15 +03:00
|
|
|
|
2022-01-16 21:02:36 +03:00
|
|
|
#include <FL/fl_string_functions.h>
|
2010-02-15 19:43:51 +03:00
|
|
|
#include <FL/Fl_File_Chooser.H>
|
2021-12-08 17:52:15 +03:00
|
|
|
#include <FL/fl_ask.H>
|
2002-05-16 16:47:44 +04:00
|
|
|
#include "../src/flstring.h"
|
2021-12-08 17:52:15 +03:00
|
|
|
|
2023-11-16 15:21:17 +03:00
|
|
|
#include <zlib.h>
|
|
|
|
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/// Set a current class, so that the code of the children is generated correctly.
|
|
|
|
Fl_Class_Type *current_class = NULL;
|
|
|
|
|
|
|
|
/**
|
2023-07-12 16:27:36 +03:00
|
|
|
\brief Return 1 if the list contains a function with the given signature at the top level.
|
|
|
|
Fl_Widget_Type uses this to check if a callback by a certain signature is
|
|
|
|
already defined by the user within this file. If not, Fl_Widget_Type will
|
|
|
|
generate an `extern $sig$;` statement.
|
|
|
|
\param[in] rtype return type, can be NULL to avoid checking (not used by Fl_Widget_Type)
|
2021-12-08 17:52:15 +03:00
|
|
|
\param[in] sig function signature
|
|
|
|
\return 1 if found.
|
|
|
|
*/
|
|
|
|
int has_toplevel_function(const char *rtype, const char *sig) {
|
|
|
|
Fl_Type *child;
|
|
|
|
for (child = Fl_Type::first; child; child = child->next) {
|
2023-10-20 20:00:42 +03:00
|
|
|
if (!child->is_in_class() && child->is_a(ID_Function)) {
|
2021-12-08 17:52:15 +03:00
|
|
|
const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
|
|
|
|
if (fn->has_signature(rtype, sig))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-05 00:45:49 +03:00
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// quick check of any C code for legality, returns an error message
|
|
|
|
|
|
|
|
static char buffer[128]; // for error messages
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Check a quoted string contains a character.
|
2023-08-26 16:17:28 +03:00
|
|
|
This is used to find a matching " or ' in a string.
|
2021-12-08 17:52:15 +03:00
|
|
|
\param[inout] c start searching here, return where we found \c type
|
|
|
|
\param[in] type find this character
|
|
|
|
\return NULL if the character was found, else a pointer to a static string
|
|
|
|
with an error message
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
const char *_q_check(const char * & c, int type) {
|
|
|
|
for (;;) switch (*c++) {
|
2010-02-15 19:43:51 +03:00
|
|
|
case '\0':
|
|
|
|
sprintf(buffer,"missing %c",type);
|
|
|
|
return buffer;
|
|
|
|
case '\\':
|
|
|
|
if (*c) c++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (*(c-1) == type) return 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Check normal code, match brackets and parenthesis.
|
|
|
|
Recursively run a line of code and make sure that
|
2023-06-04 22:10:43 +03:00
|
|
|
{, [, ", ', and ( are matched.
|
2021-12-08 17:52:15 +03:00
|
|
|
\param[inout] c start searching here, return the end of the search
|
|
|
|
\param[in] type find this character match
|
|
|
|
\return NULL if the character was found, else a pointer to a static string
|
|
|
|
with an error message
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
const char *_c_check(const char * & c, int type) {
|
|
|
|
const char *d;
|
|
|
|
for (;;) switch (*c++) {
|
2010-02-15 19:43:51 +03:00
|
|
|
case 0:
|
|
|
|
if (!type) return 0;
|
2023-06-04 22:10:43 +03:00
|
|
|
sprintf(buffer, "missing '%c'", type);
|
2010-02-15 19:43:51 +03:00
|
|
|
return buffer;
|
|
|
|
case '/':
|
|
|
|
// Skip comments as needed...
|
|
|
|
if (*c == '/') {
|
|
|
|
while (*c != '\n' && *c) c++;
|
|
|
|
} else if (*c == '*') {
|
|
|
|
c++;
|
|
|
|
while ((*c != '*' || c[1] != '/') && *c) c++;
|
|
|
|
if (*c == '*') c+=2;
|
|
|
|
else {
|
|
|
|
return "missing '*/'";
|
|
|
|
}
|
1999-02-19 17:53:04 +03:00
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
break;
|
2023-06-04 22:10:43 +03:00
|
|
|
// case '#':
|
|
|
|
// // treat cpp directives as a comment:
|
2023-08-26 16:17:28 +03:00
|
|
|
// // Matt: a '#' character can appear as a concatenation when defining macros
|
2023-06-04 22:10:43 +03:00
|
|
|
// // Matt: so instead we just silently ignore the '#'
|
|
|
|
// while (*c != '\n' && *c) c++;
|
|
|
|
// break;
|
2010-02-15 19:43:51 +03:00
|
|
|
case '{':
|
|
|
|
if (type==')') goto UNEXPECTED;
|
|
|
|
d = _c_check(c,'}');
|
|
|
|
if (d) return d;
|
|
|
|
break;
|
|
|
|
case '(':
|
|
|
|
d = _c_check(c,')');
|
|
|
|
if (d) return d;
|
|
|
|
break;
|
2023-06-04 22:10:43 +03:00
|
|
|
case '[':
|
|
|
|
d = _c_check(c,']');
|
|
|
|
if (d) return d;
|
|
|
|
break;
|
2010-02-15 19:43:51 +03:00
|
|
|
case '\"':
|
|
|
|
d = _q_check(c,'\"');
|
|
|
|
if (d) return d;
|
|
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
d = _q_check(c,'\'');
|
|
|
|
if (d) return d;
|
|
|
|
break;
|
|
|
|
case '}':
|
|
|
|
case ')':
|
2023-06-04 22:10:43 +03:00
|
|
|
case ']':
|
2010-02-15 19:43:51 +03:00
|
|
|
UNEXPECTED:
|
|
|
|
if (type == *(c-1)) return 0;
|
2023-06-04 22:10:43 +03:00
|
|
|
sprintf(buffer, "unexpected '%c'", *(c-1));
|
2010-02-15 19:43:51 +03:00
|
|
|
return buffer;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Check legality of c code (sort of) and return error:
|
|
|
|
Make sure that {, ", ', and ( are matched.
|
|
|
|
\param[in] c start searching here
|
2023-06-04 22:10:43 +03:00
|
|
|
\param[in] type find this character match (default is 0)
|
2021-12-08 17:52:15 +03:00
|
|
|
\return NULL if the character was found, else a pointer to a static string
|
|
|
|
with an error message
|
|
|
|
\note This function checks every conceivable line of code, which is not
|
|
|
|
always wanted. It can't differentiate characters in comments, and the
|
|
|
|
user may well intend to leave a curly bracket open
|
2024-03-03 00:58:52 +03:00
|
|
|
(i.e. namespace { ... } ). We should make this option user selectable.
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
const char *c_check(const char *c, int type) {
|
|
|
|
return _c_check(c,type);
|
|
|
|
}
|
|
|
|
|
2023-08-26 16:17:28 +03:00
|
|
|
// ---- Fl_Function_Type implementation
|
2021-12-08 17:52:15 +03:00
|
|
|
|
|
|
|
/** \class Fl_Function_Type
|
|
|
|
Manage a C++ function node in the Fluid design.
|
|
|
|
|
|
|
|
A function can have a signature (name followed by arguments), a return type
|
|
|
|
and a comment section. If can be local or global, and it can be declared a C
|
|
|
|
or C++ function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Prototype for a function to be used by the factory.
|
|
|
|
Fl_Function_Type Fl_Function_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Create a new function.
|
|
|
|
*/
|
|
|
|
Fl_Function_Type::Fl_Function_Type() :
|
|
|
|
Fl_Type(),
|
|
|
|
return_type(0L),
|
|
|
|
public_(0),
|
|
|
|
cdecl_(0),
|
|
|
|
constructor(0),
|
|
|
|
havewidgets(0)
|
|
|
|
{ }
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Destructor.
|
|
|
|
*/
|
|
|
|
Fl_Function_Type::~Fl_Function_Type() {
|
|
|
|
if (return_type) free((void*)return_type);
|
|
|
|
}
|
2002-04-26 15:51:54 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Create a new function for the widget tree.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy new function add after current or as last child
|
2021-12-08 17:52:15 +03:00
|
|
|
\return the new node
|
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_Function_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_decl_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Function_Type *o = new Fl_Function_Type();
|
|
|
|
o->name("make_window()");
|
|
|
|
o->return_type = 0;
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
1998-10-06 22:21:25 +04:00
|
|
|
o->factory = this;
|
|
|
|
o->public_ = 1;
|
1999-08-05 13:01:25 +04:00
|
|
|
o->cdecl_ = 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write function specific properties to an .fl file.
|
|
|
|
- "private"/"public" indicates the state of the function
|
|
|
|
- "C" is written if we want a C signature instead of C++
|
|
|
|
- "return_type" is followed by the return type of the function
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Function_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Type::write_properties(f);
|
2008-01-05 00:45:49 +03:00
|
|
|
switch (public_) {
|
2023-01-26 17:23:43 +03:00
|
|
|
case 0: f.write_string("private"); break;
|
|
|
|
case 2: f.write_string("protected"); break;
|
2008-01-05 00:45:49 +03:00
|
|
|
}
|
2023-01-26 17:23:43 +03:00
|
|
|
if (cdecl_) f.write_string("C");
|
1998-10-06 22:21:25 +04:00
|
|
|
if (return_type) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("return_type");
|
|
|
|
f.write_word(return_type);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Read function specific properties fron an .fl file.
|
|
|
|
\param[in] c read from this string
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Function_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!strcmp(c,"private")) {
|
|
|
|
public_ = 0;
|
2008-01-05 00:45:49 +03:00
|
|
|
} else if (!strcmp(c,"protected")) {
|
|
|
|
public_ = 2;
|
1999-08-05 13:01:25 +04:00
|
|
|
} else if (!strcmp(c,"C")) {
|
|
|
|
cdecl_ = 1;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else if (!strcmp(c,"return_type")) {
|
2023-01-26 17:23:43 +03:00
|
|
|
storestring(f.read_word(),return_type);
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::read_property(f, c);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the function_panel dialog box to edit this function.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Function_Type::open() {
|
2023-06-04 22:10:43 +03:00
|
|
|
// fill dialog box
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!function_panel) make_function_panel();
|
2023-01-26 17:23:43 +03:00
|
|
|
f_return_type_input->value(return_type);
|
|
|
|
f_name_input->value(name());
|
2008-01-05 00:45:49 +03:00
|
|
|
if (is_in_class()) {
|
|
|
|
f_public_member_choice->value(public_);
|
|
|
|
f_public_member_choice->show();
|
|
|
|
f_public_choice->hide();
|
2021-12-09 20:25:43 +03:00
|
|
|
f_c_button->hide();
|
2008-01-05 00:45:49 +03:00
|
|
|
} else {
|
2022-02-13 02:54:44 +03:00
|
|
|
f_public_choice->value(public_);
|
2008-01-05 00:45:49 +03:00
|
|
|
f_public_choice->show();
|
|
|
|
f_public_member_choice->hide();
|
2021-12-09 20:25:43 +03:00
|
|
|
f_c_button->show();
|
2008-01-05 00:45:49 +03:00
|
|
|
}
|
1999-08-05 13:01:25 +04:00
|
|
|
f_c_button->value(cdecl_);
|
2008-09-18 02:43:15 +04:00
|
|
|
const char *c = comment();
|
|
|
|
f_comment_input->buffer()->text(c?c:"");
|
1998-10-06 22:21:25 +04:00
|
|
|
function_panel->show();
|
|
|
|
const char* message = 0;
|
|
|
|
for (;;) { // repeat as long as there are errors
|
2023-06-04 22:10:43 +03:00
|
|
|
// - message loop until OK or cancel is pressed
|
1998-10-06 22:21:25 +04:00
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == f_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == f_panel_ok) break;
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
2023-06-04 22:10:43 +03:00
|
|
|
// - check syntax
|
|
|
|
const char *c = f_name_input->value();
|
1998-10-06 22:21:25 +04:00
|
|
|
while (isspace(*c)) c++;
|
2023-06-04 22:10:43 +03:00
|
|
|
message = c_check(c);
|
|
|
|
if (!message) {
|
|
|
|
const char *d = c;
|
|
|
|
for (; *d != '('; d++) if (isspace(*d) || !*d) break;
|
|
|
|
if (*c && *d != '(')
|
|
|
|
message = "must be 'name(arguments)'";
|
|
|
|
}
|
|
|
|
if (!message) {
|
|
|
|
c = f_return_type_input->value();
|
|
|
|
message = c_check(c);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2023-06-04 22:10:43 +03:00
|
|
|
// - alert user
|
|
|
|
if (message) {
|
|
|
|
int v = fl_choice("Potential syntax error detected: %s",
|
2023-11-07 16:52:01 +03:00
|
|
|
"Continue Editing", "Ignore Error", NULL, message);
|
|
|
|
if (v==0) continue; // Continue Editing
|
|
|
|
//if (v==1) { } // Ignore Error and close dialog
|
2023-06-04 22:10:43 +03:00
|
|
|
}
|
|
|
|
// - copy dialog data to target variables
|
2005-08-21 00:30:56 +04:00
|
|
|
int mod = 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
name(f_name_input->value());
|
2023-06-04 22:10:43 +03:00
|
|
|
storestring(f_return_type_input->value(), return_type);
|
2008-01-05 00:45:49 +03:00
|
|
|
if (is_in_class()) {
|
|
|
|
if (public_ != f_public_member_choice->value()) {
|
|
|
|
mod = 1;
|
|
|
|
public_ = f_public_member_choice->value();
|
|
|
|
redraw_browser();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (public_ != f_public_choice->value()) {
|
|
|
|
mod = 1;
|
|
|
|
public_ = f_public_choice->value();
|
|
|
|
redraw_browser();
|
|
|
|
}
|
2005-08-22 01:55:22 +04:00
|
|
|
}
|
|
|
|
if (cdecl_ != f_c_button->value()) {
|
|
|
|
mod = 1;
|
|
|
|
cdecl_ = f_c_button->value();
|
|
|
|
}
|
2008-09-18 02:43:15 +04:00
|
|
|
c = f_comment_input->buffer()->text();
|
|
|
|
if (c && *c) {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (!comment() || strcmp(c, comment())) { set_modflag(1); redraw_browser(); }
|
2008-09-18 02:43:15 +04:00
|
|
|
comment(c);
|
|
|
|
} else {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (comment()) { set_modflag(1); redraw_browser(); }
|
2008-09-18 02:43:15 +04:00
|
|
|
comment(0);
|
|
|
|
}
|
|
|
|
if (c) free((void*)c);
|
2005-08-21 00:30:56 +04:00
|
|
|
if (mod) set_modflag(1);
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
1998-10-06 22:21:25 +04:00
|
|
|
function_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Return 1 if the function is global.
|
|
|
|
\return 1 if public, 0 if local.
|
|
|
|
*/
|
|
|
|
int Fl_Function_Type::is_public() const {
|
|
|
|
return public_;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2023-10-19 13:13:46 +03:00
|
|
|
static bool fd_isspace(int c) {
|
|
|
|
return (c>0 && c<128 && isspace(c));
|
|
|
|
}
|
|
|
|
|
2023-10-27 00:31:12 +03:00
|
|
|
// code duplication: see int is_id(char c) in code.cxx
|
2023-10-19 13:13:46 +03:00
|
|
|
static bool fd_iskeyword(int c) {
|
|
|
|
return (c>0 && c<128 && (isalnum(c) || c=='_'));
|
|
|
|
}
|
|
|
|
|
2023-10-19 18:09:23 +03:00
|
|
|
// remove all function default parameters and `override` keyword
|
|
|
|
static void clean_function_for_implementation(char *out, const char *function_name) {
|
|
|
|
char *sptr = out;
|
|
|
|
const char *nptr = function_name;
|
|
|
|
int skips=0,skipc=0;
|
|
|
|
int nc=0,plevel=0;
|
|
|
|
bool arglist_done = false;
|
|
|
|
for (;*nptr; nc++,nptr++) {
|
|
|
|
if (arglist_done && fd_isspace(nptr[0])) {
|
|
|
|
// skip `override` and `FL_OVERRIDE` keywords if they are following the list of arguments
|
|
|
|
if (strncmp(nptr+1, "override", 8)==0 && !fd_iskeyword(nptr[9])) { nptr += 8; continue; }
|
|
|
|
else if (strncmp(nptr+1, "FL_OVERRIDE", 11)==0 && !fd_iskeyword(nptr[12])) { nptr += 11; continue; }
|
|
|
|
}
|
|
|
|
if (!skips && *nptr=='(') plevel++;
|
|
|
|
else if (!skips && *nptr==')') { plevel--; if (plevel==0) arglist_done = true; }
|
|
|
|
if ( *nptr=='"' && !(nc && *(nptr-1)=='\\') )
|
|
|
|
skips = skips ? 0 : 1;
|
|
|
|
else if(!skips && *nptr=='\'' && !(nc && *(nptr-1)=='\\'))
|
|
|
|
skipc = skipc ? 0 : 1;
|
|
|
|
if(!skips && !skipc && plevel==1 && *nptr =='=' && !(nc && *(nptr-1)=='\'') ) { // ignore '=' case
|
|
|
|
while(*++nptr && (skips || skipc || ( (*nptr!=',' && *nptr!=')') || plevel!=1) )) {
|
|
|
|
if ( *nptr=='"' && *(nptr-1)!='\\' )
|
|
|
|
skips = skips ? 0 : 1;
|
|
|
|
else if(!skips && *nptr=='\'' && *(nptr-1)!='\\')
|
|
|
|
skipc = skipc ? 0 : 1;
|
|
|
|
if (!skips && !skipc && *nptr=='(') plevel++;
|
|
|
|
else if (!skips && *nptr==')') plevel--;
|
|
|
|
}
|
|
|
|
if (*nptr==')') if (--plevel==0) arglist_done = true;
|
|
|
|
}
|
|
|
|
if (sptr < (out + 1024 - 1)) *sptr++ = *nptr;
|
|
|
|
}
|
|
|
|
*sptr = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the code for the source and the header file.
|
|
|
|
This writes the code that goes \b before all children of this class.
|
2023-01-26 17:23:43 +03:00
|
|
|
\see write_code2(Fd_Code_Writer& f)
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Function_Type::write_code1(Fd_Code_Writer& f) {
|
1998-10-06 22:21:25 +04:00
|
|
|
constructor=0;
|
|
|
|
havewidgets = 0;
|
|
|
|
Fl_Type *child;
|
2009-09-24 00:08:30 +04:00
|
|
|
// if the function has no children (hence no body), Fluid will not generate
|
|
|
|
// the function either. This is great if you decide to implement that function
|
|
|
|
// inside another module
|
|
|
|
char havechildren = 0;
|
|
|
|
for (child = next; child && child->level > level; child = child->next) {
|
|
|
|
havechildren = 1;
|
1998-10-20 01:00:26 +04:00
|
|
|
if (child->is_widget()) {
|
1998-10-06 22:21:25 +04:00
|
|
|
havewidgets = 1;
|
1998-10-20 01:00:26 +04:00
|
|
|
break;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2009-09-24 00:08:30 +04:00
|
|
|
}
|
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("\n");
|
2009-09-24 00:08:30 +04:00
|
|
|
if (ismain()) {
|
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("int main(int argc, char **argv) {\n");
|
2009-09-24 00:08:30 +04:00
|
|
|
} else {
|
1999-08-17 09:33:12 +04:00
|
|
|
const char* rtype = return_type;
|
|
|
|
const char* star = "";
|
1999-01-08 00:21:20 +03:00
|
|
|
// from matt: let the user type "static " at the start of type
|
|
|
|
// in order to declare a static method;
|
|
|
|
int is_static = 0;
|
1999-02-17 19:24:45 +03:00
|
|
|
int is_virtual = 0;
|
1999-08-17 09:33:12 +04:00
|
|
|
if (rtype) {
|
|
|
|
if (!strcmp(rtype,"static")) {is_static = 1; rtype = 0;}
|
|
|
|
else if (!strncmp(rtype, "static ",7)) {is_static = 1; rtype += 7;}
|
2017-10-29 00:23:35 +03:00
|
|
|
}
|
|
|
|
if (rtype) {
|
1999-08-17 09:33:12 +04:00
|
|
|
if (!strcmp(rtype, "virtual")) {is_virtual = 1; rtype = 0;}
|
|
|
|
else if (!strncmp(rtype, "virtual ",8)) {is_virtual = 1; rtype += 8;}
|
1999-01-08 00:21:20 +03:00
|
|
|
}
|
1999-08-17 09:33:12 +04:00
|
|
|
if (!rtype) {
|
1999-04-30 20:29:40 +04:00
|
|
|
if (havewidgets) {
|
2008-09-18 02:43:15 +04:00
|
|
|
rtype = subclassname(child);
|
|
|
|
star = "*";
|
1999-08-17 09:33:12 +04:00
|
|
|
} else rtype = "void";
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2000-02-05 12:20:46 +03:00
|
|
|
const char* k = class_name(0);
|
1998-10-06 22:21:25 +04:00
|
|
|
if (k) {
|
2023-12-04 19:42:12 +03:00
|
|
|
f.write_public(public_);
|
2009-09-24 00:08:30 +04:00
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_c(f);
|
1998-10-06 22:21:25 +04:00
|
|
|
if (name()[0] == '~')
|
2008-09-18 02:43:15 +04:00
|
|
|
constructor = 1;
|
1998-10-06 22:21:25 +04:00
|
|
|
else {
|
2008-09-18 02:43:15 +04:00
|
|
|
size_t n = strlen(k);
|
|
|
|
if (!strncmp(name(), k, n) && name()[n] == '(') constructor = 1;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%s", f.indent(1));
|
|
|
|
if (is_static) f.write_h("static ");
|
|
|
|
if (is_virtual) f.write_h("virtual ");
|
1999-01-08 00:21:20 +03:00
|
|
|
if (!constructor) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%s%s ", rtype, star);
|
2009-09-24 00:08:30 +04:00
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%s%s ", rtype, star);
|
1999-01-08 00:21:20 +03:00
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2023-01-26 17:23:43 +03:00
|
|
|
// if this is a subclass, only f.write_h() the part before the ':'
|
1999-02-19 17:33:22 +03:00
|
|
|
char s[1024], *sptr = s;
|
|
|
|
char *nptr = (char *)name();
|
2020-07-01 19:03:10 +03:00
|
|
|
|
1999-06-12 16:59:06 +04:00
|
|
|
while (*nptr) {
|
|
|
|
if (*nptr == ':') {
|
2008-09-18 02:43:15 +04:00
|
|
|
if (nptr[1] != ':') break;
|
|
|
|
// Copy extra ":" for "class::member"...
|
1999-06-12 16:59:06 +04:00
|
|
|
*sptr++ = *nptr++;
|
2020-07-01 19:03:10 +03:00
|
|
|
}
|
1999-06-12 16:59:06 +04:00
|
|
|
*sptr++ = *nptr++;
|
|
|
|
}
|
1999-02-19 17:33:22 +03:00
|
|
|
*sptr = '\0';
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2021-12-09 23:06:04 +03:00
|
|
|
if (s[strlen(s)-1] == '}') { // special case for inlined functions
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%s\n", s);
|
2021-12-09 23:06:04 +03:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%s;\n", s);
|
2021-12-09 23:06:04 +03:00
|
|
|
}
|
2023-10-19 18:09:23 +03:00
|
|
|
if (havechildren) {
|
|
|
|
clean_function_for_implementation(s, name());
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%s::%s {\n", k, s);
|
2023-10-19 18:09:23 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2009-09-24 00:08:30 +04:00
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_c(f);
|
2022-02-13 02:54:44 +03:00
|
|
|
if (public_==1) {
|
2008-09-18 02:43:15 +04:00
|
|
|
if (cdecl_)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("extern \"C\" { %s%s %s; }\n", rtype, star, name());
|
2008-09-18 02:43:15 +04:00
|
|
|
else
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%s%s %s;\n", rtype, star, name());
|
2022-02-13 02:54:44 +03:00
|
|
|
} else if (public_==2) {
|
|
|
|
// write neither the prototype nor static, the function may be declared elsewhere
|
2009-09-24 00:08:30 +04:00
|
|
|
} else {
|
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("static ");
|
1999-08-05 13:01:25 +04:00
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2004-11-20 19:19:04 +03:00
|
|
|
// write everything but the default parameters (if any)
|
2023-10-19 18:09:23 +03:00
|
|
|
char s[1024];
|
|
|
|
if (havechildren) {
|
|
|
|
clean_function_for_implementation(s, name());
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%s%s %s {\n", rtype, star, s);
|
2023-10-19 18:09:23 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2021-12-11 05:33:25 +03:00
|
|
|
if (havewidgets && child && !child->name())
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%s%s* w;\n", f.indent(1), subclassname(child));
|
|
|
|
f.indentation++;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the code for the source and the header file.
|
|
|
|
This writes the code that goes \b after all children of this class.
|
2023-01-26 17:23:43 +03:00
|
|
|
\see write_code1(Fd_Code_Writer& f)
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Function_Type::write_code2(Fd_Code_Writer& f) {
|
2006-07-27 23:26:11 +04:00
|
|
|
Fl_Type *child;
|
|
|
|
const char *var = "w";
|
2009-09-24 00:08:30 +04:00
|
|
|
char havechildren = 0;
|
|
|
|
for (child = next; child && child->level > level; child = child->next) {
|
|
|
|
havechildren = 1;
|
2023-07-19 21:41:58 +03:00
|
|
|
if (child->is_a(ID_Window) && child->name()) var = child->name();
|
2009-09-24 00:08:30 +04:00
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
if (ismain()) {
|
2021-12-11 05:33:25 +03:00
|
|
|
if (havewidgets)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%s%s->show(argc, argv);\n", f.indent(1), var);
|
2021-12-11 05:33:25 +03:00
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%sreturn Fl::run();\n", f.indent(1));
|
2006-07-27 03:27:32 +04:00
|
|
|
} else if (havewidgets && !constructor && !return_type) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%sreturn %s;\n", f.indent(1), var);
|
2006-07-27 03:27:32 +04:00
|
|
|
}
|
2009-09-24 00:08:30 +04:00
|
|
|
if (havechildren)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("}\n");
|
|
|
|
f.indentation = 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Check if the return type and signature s match.
|
|
|
|
\param[in] rtype function return type
|
|
|
|
\param[in] sig function name followed by arguments
|
|
|
|
\return 1 if they match, 0 if not
|
|
|
|
*/
|
2005-08-23 15:28:13 +04:00
|
|
|
int Fl_Function_Type::has_signature(const char *rtype, const char *sig) const {
|
2008-01-05 00:45:49 +03:00
|
|
|
if (rtype && !return_type) return 0;
|
2005-08-23 15:28:13 +04:00
|
|
|
if (!name()) return 0;
|
2020-07-01 19:03:10 +03:00
|
|
|
if ( (rtype==0L || strcmp(return_type, rtype)==0)
|
2005-08-23 15:28:13 +04:00
|
|
|
&& fl_filename_match(name(), sig)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
// ---- Fl_Code_Type declaration
|
|
|
|
|
|
|
|
/** \class Fl_Code_Type
|
|
|
|
Manage a block of C++ code in the Fluid design.
|
|
|
|
|
|
|
|
This node manages an arbitrary block of code inside a function that will
|
|
|
|
be written into the source code file. Fl_Code_Block has no comment field.
|
|
|
|
However, the first line of code will be shown in the widget browser.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Prototype for code to be used by the factory.
|
|
|
|
Fl_Code_Type Fl_Code_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Constructor.
|
|
|
|
*/
|
2021-12-08 20:55:34 +03:00
|
|
|
Fl_Code_Type::Fl_Code_Type() :
|
|
|
|
cursor_position_(0),
|
|
|
|
code_input_scroll_row(0),
|
|
|
|
code_input_scroll_col(0)
|
|
|
|
{}
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Make a new code node.
|
|
|
|
If the parent node is not a function, a message box will pop up and
|
|
|
|
the request will be ignored.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add code after current or as last child
|
|
|
|
\return new Code node
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_Code_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_code_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!p) {
|
|
|
|
fl_message("Please select a function");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Fl_Code_Type *o = new Fl_Code_Type();
|
|
|
|
o->name("printf(\"Hello, World!\\n\");");
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
1998-10-06 22:21:25 +04:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the code_panel or an external editor to edit this code section.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Code_Type::open() {
|
2016-07-19 00:12:25 +03:00
|
|
|
// Using an external code editor? Open it..
|
|
|
|
if ( G_use_external_editor && G_external_editor_command[0] ) {
|
|
|
|
const char *cmd = G_external_editor_command;
|
|
|
|
const char *code = name();
|
2024-04-04 18:43:21 +03:00
|
|
|
if (!code) code = "";
|
2016-07-19 00:12:25 +03:00
|
|
|
if ( editor_.open_editor(cmd, code) == 0 )
|
2023-08-26 16:17:28 +03:00
|
|
|
return; // return if editor opened ok, fall thru to built-in if not
|
2016-07-19 00:12:25 +03:00
|
|
|
}
|
|
|
|
// Use built-in code editor..
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!code_panel) make_code_panel();
|
2002-11-03 03:01:21 +03:00
|
|
|
const char *text = name();
|
|
|
|
code_input->buffer()->text( text ? text : "" );
|
2019-01-14 01:32:34 +03:00
|
|
|
code_input->insert_position(cursor_position_);
|
2021-12-08 20:55:34 +03:00
|
|
|
code_input->scroll(code_input_scroll_row, code_input_scroll_col);
|
1998-10-06 22:21:25 +04:00
|
|
|
code_panel->show();
|
|
|
|
const char* message = 0;
|
|
|
|
for (;;) { // repeat as long as there are errors
|
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == code_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == code_panel_ok) break;
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
2002-11-05 09:45:41 +03:00
|
|
|
char*c = code_input->buffer()->text();
|
2023-06-04 22:10:43 +03:00
|
|
|
message = c_check(c);
|
|
|
|
if (message) {
|
|
|
|
int v = fl_choice("Potential syntax error detected: %s",
|
2023-11-07 16:52:01 +03:00
|
|
|
"Continue Editing", "Ignore Error", NULL, message);
|
|
|
|
if (v==0) continue; // Continue Editing
|
|
|
|
//if (v==1) { } // Ignore Error and close dialog
|
2023-06-04 22:10:43 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
name(c);
|
2002-11-05 09:45:41 +03:00
|
|
|
free(c);
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
}
|
2019-01-14 01:32:34 +03:00
|
|
|
cursor_position_ = code_input->insert_position();
|
2021-12-08 20:55:34 +03:00
|
|
|
code_input_scroll_row = code_input->scroll_row();
|
|
|
|
code_input_scroll_col = code_input->scroll_col();
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
1998-10-06 22:21:25 +04:00
|
|
|
code_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Grab changes from an external editor and write this node.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Code_Type::write(Fd_Project_Writer &f) {
|
2016-07-19 00:12:25 +03:00
|
|
|
// External editor changes? If so, load changes into ram, update mtime/size
|
|
|
|
if ( handle_editor_changes() == 1 ) {
|
|
|
|
main_window->redraw(); // tell fluid to redraw; edits may affect tree's contents
|
|
|
|
}
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::write(f);
|
2016-07-19 00:12:25 +03:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the code block with the correct indentation.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Code_Type::write_code1(Fd_Code_Writer& f) {
|
2016-07-19 00:12:25 +03:00
|
|
|
// External editor changes? If so, load changes into ram, update mtime/size
|
|
|
|
if ( handle_editor_changes() == 1 ) {
|
|
|
|
main_window->redraw(); // tell fluid to redraw; edits may affect tree's contents
|
|
|
|
}
|
2023-10-31 21:33:42 +03:00
|
|
|
// Matt: disabled f.tag(FD_TAG_GENERIC, 0);
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c_indented(name(), 0, '\n');
|
2023-10-31 21:33:42 +03:00
|
|
|
// Matt: disabled f.tag(FD_TAG_CODE, get_uid());
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
See if external editor is open.
|
|
|
|
*/
|
|
|
|
int Fl_Code_Type::is_editing() {
|
|
|
|
return editor_.is_editing();
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Reap the editor's pid
|
|
|
|
\return -2: editor not open
|
|
|
|
\return -1: wait failed
|
|
|
|
\return 0: process still running
|
|
|
|
\return \>0: process finished + reaped (returns pid)
|
|
|
|
*/
|
|
|
|
int Fl_Code_Type::reap_editor() {
|
|
|
|
return editor_.reap_editor();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Handle external editor file modifications.
|
|
|
|
If changed, record keeping is updated and file's contents is loaded into ram
|
|
|
|
\return 0: file unchanged or not editing
|
|
|
|
\return 1: file changed, internal records updated, 'code' has new content
|
|
|
|
\return -1: error getting file info (get_ms_errmsg() has reason)
|
|
|
|
\todo Figure out how saving a fluid file can be intercepted to grab
|
|
|
|
current contents of editor file..
|
|
|
|
*/
|
|
|
|
int Fl_Code_Type::handle_editor_changes() {
|
|
|
|
const char *newcode = 0;
|
|
|
|
switch ( editor_.handle_changes(&newcode) ) {
|
|
|
|
case 1: { // (1)=changed
|
|
|
|
name(newcode); // update value in ram
|
|
|
|
free((void*)newcode);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
case -1: return -1; // (-1)=error -- couldn't read file (dialog showed reason)
|
|
|
|
default: break; // (0)=no change
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-08-26 16:17:28 +03:00
|
|
|
// ---- Fl_CodeBlock_Type implementation
|
2021-12-08 17:52:15 +03:00
|
|
|
|
|
|
|
/** \class Fl_CodeBlock_Type
|
|
|
|
Manage two blocks of C++ code enclosing its children.
|
|
|
|
|
|
|
|
This node manages two lines of code that enclose all children
|
|
|
|
of this node. This is usually an if..then clause.
|
|
|
|
|
|
|
|
\todo this node could support multiple lines of code for each block.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Prototype for a block of code to be used by the factory.
|
|
|
|
Fl_CodeBlock_Type Fl_CodeBlock_type;
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Constructor.
|
|
|
|
*/
|
|
|
|
Fl_CodeBlock_Type::Fl_CodeBlock_Type() :
|
|
|
|
Fl_Type(),
|
|
|
|
after(NULL)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
Destructor.
|
|
|
|
*/
|
|
|
|
Fl_CodeBlock_Type::~Fl_CodeBlock_Type() {
|
|
|
|
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
|
|
|
|
pop up and the request will be ignored.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add after current or as last child
|
|
|
|
\return new CodeBlock
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_CodeBlock_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_code_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!p) {
|
|
|
|
fl_message("Please select a function");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Fl_CodeBlock_Type *o = new Fl_CodeBlock_Type();
|
|
|
|
o->name("if (test())");
|
|
|
|
o->after = 0;
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
1998-10-06 22:21:25 +04:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the specific properties for this node.
|
|
|
|
- "after" is followed by the code that comes after the children
|
|
|
|
The "before" code is stored in the name() field.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_CodeBlock_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Type::write_properties(f);
|
1998-10-06 22:21:25 +04:00
|
|
|
if (after) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("after");
|
|
|
|
f.write_word(after);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
2024-03-03 00:58:52 +03:00
|
|
|
Read the node specific properties.
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_CodeBlock_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!strcmp(c,"after")) {
|
2023-01-26 17:23:43 +03:00
|
|
|
storestring(f.read_word(),after);
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::read_property(f, c);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the codeblock_panel.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_CodeBlock_Type::open() {
|
|
|
|
if (!codeblock_panel) make_codeblock_panel();
|
2023-01-26 17:23:43 +03:00
|
|
|
code_before_input->value(name());
|
|
|
|
code_after_input->value(after);
|
1998-10-06 22:21:25 +04:00
|
|
|
codeblock_panel->show();
|
|
|
|
const char* message = 0;
|
|
|
|
for (;;) { // repeat as long as there are errors
|
2023-06-04 22:10:43 +03:00
|
|
|
// event loop
|
1998-10-06 22:21:25 +04:00
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == codeblock_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == codeblock_panel_ok) break;
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
2023-06-04 22:10:43 +03:00
|
|
|
// check for syntax errors
|
|
|
|
message = c_check(code_before_input->value());
|
|
|
|
if (!message) {
|
|
|
|
message = c_check(code_after_input->value());
|
|
|
|
}
|
|
|
|
// alert user
|
|
|
|
if (message) {
|
|
|
|
int v = fl_choice("Potential syntax error detected: %s",
|
2023-11-07 16:52:01 +03:00
|
|
|
"Continue Editing", "Ignore Error", NULL, message);
|
|
|
|
if (v==0) continue; // Continue Editing
|
|
|
|
//if (v==1) { } // Ignore Error and close dialog
|
2023-06-04 22:10:43 +03:00
|
|
|
}
|
|
|
|
// write to variables
|
|
|
|
name(code_before_input->value());
|
|
|
|
storestring(code_after_input->value(), after);
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
1998-10-06 22:21:25 +04:00
|
|
|
codeblock_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the "before" code.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_CodeBlock_Type::write_code1(Fd_Code_Writer& f) {
|
1998-10-06 22:21:25 +04:00
|
|
|
const char* c = name();
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("%s%s {\n", f.indent(), c ? c : "");
|
|
|
|
f.indentation++;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the "after" code.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_CodeBlock_Type::write_code2(Fd_Code_Writer& f) {
|
|
|
|
f.indentation--;
|
|
|
|
if (after) f.write_c("%s} %s\n", f.indent(), after);
|
|
|
|
else f.write_c("%s}\n", f.indent());
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
// ---- Fl_Decl_Type declaration
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/** \class Fl_Decl_Type
|
|
|
|
Manage the C/C++ declaration of a variable.
|
|
|
|
|
|
|
|
This node manages a single line of code that can be in the header or the source
|
|
|
|
code, and can be made static.
|
|
|
|
|
|
|
|
\todo this node could support multiple lines.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Prototype for a declaration to be used by the factory.
|
|
|
|
Fl_Decl_Type Fl_Decl_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Constructor.
|
|
|
|
*/
|
|
|
|
Fl_Decl_Type::Fl_Decl_Type() :
|
|
|
|
public_(0),
|
|
|
|
static_(1)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
Return 1 if this declaration and its parents are public.
|
|
|
|
*/
|
2020-07-01 19:03:10 +03:00
|
|
|
int Fl_Decl_Type::is_public() const
|
2004-03-11 08:17:12 +03:00
|
|
|
{
|
2010-02-15 19:43:51 +03:00
|
|
|
Fl_Type *p = parent;
|
|
|
|
while (p && !p->is_decl_block()) p = p->parent;
|
|
|
|
if(p && p->is_public() && public_)
|
|
|
|
return public_;
|
|
|
|
else if(!p)
|
|
|
|
return public_;
|
|
|
|
return 0;
|
2004-03-11 08:17:12 +03:00
|
|
|
}
|
2002-04-26 15:51:54 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Make a new declaration.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add after current or as last child
|
|
|
|
\return new Declaration node
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_Decl_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_decl_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Decl_Type *o = new Fl_Decl_Type();
|
|
|
|
o->public_ = 0;
|
2006-05-18 18:40:10 +04:00
|
|
|
o->static_ = 1;
|
1998-10-06 22:21:25 +04:00
|
|
|
o->name("int x;");
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
1998-10-06 22:21:25 +04:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the specific properties.
|
|
|
|
- "private"/"public"/"protected"
|
|
|
|
- "local"/"global" if this is static or not
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Decl_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Type::write_properties(f);
|
2008-01-05 00:45:49 +03:00
|
|
|
switch (public_) {
|
2023-01-26 17:23:43 +03:00
|
|
|
case 0: f.write_string("private"); break;
|
|
|
|
case 1: f.write_string("public"); break;
|
|
|
|
case 2: f.write_string("protected"); break;
|
2008-01-05 00:45:49 +03:00
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
if (static_)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("local");
|
2010-02-15 19:43:51 +03:00
|
|
|
else
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("global");
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Read the specific properties.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Decl_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!strcmp(c,"public")) {
|
|
|
|
public_ = 1;
|
2010-02-15 19:43:51 +03:00
|
|
|
} else if (!strcmp(c,"private")) {
|
|
|
|
public_ = 0;
|
2008-01-05 00:45:49 +03:00
|
|
|
} else if (!strcmp(c,"protected")) {
|
|
|
|
public_ = 2;
|
2010-02-15 19:43:51 +03:00
|
|
|
} else if (!strcmp(c,"local")) {
|
|
|
|
static_ = 1;
|
2006-05-18 18:40:10 +04:00
|
|
|
} else if (!strcmp(c,"global")) {
|
|
|
|
static_ = 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::read_property(f, c);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the decl_panel to edit this node.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Decl_Type::open() {
|
|
|
|
if (!decl_panel) make_decl_panel();
|
2023-12-05 19:54:01 +03:00
|
|
|
decl_input->buffer()->text(name());
|
2008-01-05 00:45:49 +03:00
|
|
|
if (is_in_class()) {
|
|
|
|
decl_class_choice->value(public_);
|
|
|
|
decl_class_choice->show();
|
|
|
|
decl_choice->hide();
|
|
|
|
} else {
|
|
|
|
decl_choice->value((public_&1)|((static_&1)<<1));
|
|
|
|
decl_choice->show();
|
|
|
|
decl_class_choice->hide();
|
|
|
|
}
|
2008-09-18 02:43:15 +04:00
|
|
|
const char *c = comment();
|
|
|
|
decl_comment_input->buffer()->text(c?c:"");
|
1998-10-06 22:21:25 +04:00
|
|
|
decl_panel->show();
|
|
|
|
const char* message = 0;
|
|
|
|
for (;;) { // repeat as long as there are errors
|
2023-06-04 22:10:43 +03:00
|
|
|
// event loop
|
1998-10-06 22:21:25 +04:00
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == decl_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == decl_panel_ok) break;
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
2023-06-04 22:10:43 +03:00
|
|
|
// check values
|
2023-12-05 19:54:01 +03:00
|
|
|
const char*c = decl_input->buffer()->text();
|
1998-10-06 22:21:25 +04:00
|
|
|
while (isspace(*c)) c++;
|
|
|
|
message = c_check(c&&c[0]=='#' ? c+1 : c);
|
2023-06-04 22:10:43 +03:00
|
|
|
// alert user
|
|
|
|
if (message) {
|
|
|
|
int v = fl_choice("Potential syntax error detected: %s",
|
2023-11-07 16:52:01 +03:00
|
|
|
"Continue Editing", "Ignore Error", NULL, message);
|
|
|
|
if (v==0) continue; // Continue Editing
|
|
|
|
//if (v==1) { } // Ignore Error and close dialog
|
2023-06-04 22:10:43 +03:00
|
|
|
}
|
|
|
|
// copy vlaues
|
1998-10-06 22:21:25 +04:00
|
|
|
name(c);
|
2008-01-05 00:45:49 +03:00
|
|
|
if (is_in_class()) {
|
|
|
|
if (public_!=decl_class_choice->value()) {
|
|
|
|
set_modflag(1);
|
|
|
|
public_ = decl_class_choice->value();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (public_!=(decl_choice->value()&1)) {
|
|
|
|
set_modflag(1);
|
|
|
|
public_ = (decl_choice->value()&1);
|
|
|
|
}
|
|
|
|
if (static_!=((decl_choice->value()>>1)&1)) {
|
|
|
|
set_modflag(1);
|
|
|
|
static_ = ((decl_choice->value()>>1)&1);
|
|
|
|
}
|
2006-05-18 18:40:10 +04:00
|
|
|
}
|
2008-09-18 02:43:15 +04:00
|
|
|
c = decl_comment_input->buffer()->text();
|
|
|
|
if (c && *c) {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (!comment() || strcmp(c, comment())) { set_modflag(1); redraw_browser(); }
|
2008-09-18 02:43:15 +04:00
|
|
|
comment(c);
|
|
|
|
} else {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (comment()) { set_modflag(1); redraw_browser(); }
|
2008-09-18 02:43:15 +04:00
|
|
|
comment(0);
|
|
|
|
}
|
|
|
|
if (c) free((void*)c);
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
1998-10-06 22:21:25 +04:00
|
|
|
decl_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the code to the source and header files.
|
|
|
|
\todo There are a lot of side effect in this node depending on the given text
|
2021-12-11 21:43:00 +03:00
|
|
|
and the parent node. They need to be understood and documented.
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Decl_Type::write_code1(Fd_Code_Writer& f) {
|
1998-10-06 22:21:25 +04:00
|
|
|
const char* c = name();
|
|
|
|
if (!c) return;
|
2006-05-28 19:59:29 +04:00
|
|
|
// handle a few keywords differently if inside a class
|
2010-10-29 01:47:01 +04:00
|
|
|
if (is_in_class() && ( (!strncmp(c,"class",5) && isspace(c[5]))
|
|
|
|
|| (!strncmp(c,"typedef",7) && isspace(c[7]))
|
|
|
|
|| (!strncmp(c,"FL_EXPORT",9) && isspace(c[9]))
|
|
|
|
|| (!strncmp(c,"struct",6) && isspace(c[6]))
|
2023-12-05 19:54:01 +03:00
|
|
|
|| (!strncmp(c,"enum",4) && isspace(c[4]))
|
2010-02-15 19:43:51 +03:00
|
|
|
) ) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_public(public_);
|
|
|
|
write_comment_h(f, f.indent(1));
|
|
|
|
f.write_h("%s%s\n", f.indent(1), c);
|
2006-05-28 19:59:29 +04:00
|
|
|
return;
|
|
|
|
}
|
2002-04-28 15:40:26 +04:00
|
|
|
// handle putting #include, extern, using or typedef into decl:
|
2010-10-29 01:47:01 +04:00
|
|
|
if ( (!isalpha(*c) && *c != '~')
|
|
|
|
|| (!strncmp(c,"extern",6) && isspace(c[6]))
|
|
|
|
|| (!strncmp(c,"class",5) && isspace(c[5]))
|
|
|
|
|| (!strncmp(c,"typedef",7) && isspace(c[7]))
|
|
|
|
|| (!strncmp(c,"using",5) && isspace(c[5]))
|
|
|
|
|| (!strncmp(c,"FL_EXPORT",9) && isspace(c[9]))
|
2010-02-15 19:43:51 +03:00
|
|
|
// || !strncmp(c,"struct",6) && isspace(c[6])
|
1999-07-22 11:27:12 +04:00
|
|
|
) {
|
2008-09-18 02:43:15 +04:00
|
|
|
if (public_) {
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_h(f);
|
|
|
|
f.write_h("%s\n", c);
|
2008-09-18 02:43:15 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("%s\n", c);
|
2008-09-18 02:43:15 +04:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
return;
|
|
|
|
}
|
2006-08-23 15:00:22 +04:00
|
|
|
// find the first C++ style comment
|
|
|
|
const char* e = c+strlen(c), *csc = c;
|
|
|
|
while (csc<e && (csc[0]!='/' || csc[1]!='/')) csc++;
|
|
|
|
if (csc!=e) e = csc; // comment found
|
2021-12-20 03:19:00 +03:00
|
|
|
// lose spaces between text and comment, if any
|
2006-08-23 15:00:22 +04:00
|
|
|
while (e>c && e[-1]==' ') e--;
|
2000-02-05 12:20:46 +03:00
|
|
|
if (class_name(1)) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_public(public_);
|
|
|
|
write_comment_h(f, f.indent(1));
|
|
|
|
f.write_hc(f.indent(1), int(e-c), c, csc);
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
|
|
|
if (public_) {
|
2020-07-01 19:03:10 +03:00
|
|
|
if (static_)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("extern ");
|
2008-09-18 02:43:15 +04:00
|
|
|
else
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_h(f);
|
|
|
|
f.write_hc("", int(e-c), c, csc);
|
2020-07-11 19:45:14 +03:00
|
|
|
|
2008-09-18 02:43:15 +04:00
|
|
|
if (static_) {
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_c(f);
|
|
|
|
f.write_cc("", int(e-c), c, csc);
|
2008-09-18 02:43:15 +04:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_c(f);
|
2020-07-01 19:03:10 +03:00
|
|
|
if (static_)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("static ");
|
|
|
|
f.write_cc("", int(e-c), c, csc);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
// ---- Fl_Data_Type declaration
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/** \class Fl_Data_Type
|
|
|
|
Manage data from an external arbitrary file.
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
The content of the file will be stored in binary inside the generated
|
|
|
|
code. This can be used to store images inline in the source code,
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Prototype for a data node to be used by the factory.
|
|
|
|
Fl_Data_Type Fl_Data_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Constructor.
|
|
|
|
*/
|
|
|
|
Fl_Data_Type::Fl_Data_Type() :
|
|
|
|
Fl_Decl_Type(),
|
|
|
|
filename_(NULL),
|
|
|
|
text_mode_(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
Destructor.
|
|
|
|
*/
|
|
|
|
Fl_Data_Type::~Fl_Data_Type() {
|
|
|
|
if (filename_)
|
|
|
|
free((void*)filename_);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Create an empty inline data node.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add after current or as last child
|
|
|
|
\return new inline data node
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_Data_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_decl_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
Fl_Data_Type *o = new Fl_Data_Type();
|
|
|
|
o->public_ = 1;
|
|
|
|
o->static_ = 1;
|
|
|
|
o->filename_ = 0;
|
2018-08-25 18:17:16 +03:00
|
|
|
o->text_mode_ = 0;
|
|
|
|
o->name("myInlineData");
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
2010-02-15 19:43:51 +03:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write additional properties.
|
|
|
|
- "filename" followed by the filename of the file to inline
|
|
|
|
- "textmode" if data is written in ASCII vs. binary
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Data_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Decl_Type::write_properties(f);
|
2010-02-15 19:43:51 +03:00
|
|
|
if (filename_) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("filename");
|
|
|
|
f.write_word(filename_);
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 1) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("textmode");
|
2018-08-25 18:17:16 +03:00
|
|
|
}
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 2) {
|
|
|
|
f.write_string("compressed");
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Read specific properties.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Data_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
2010-02-15 19:43:51 +03:00
|
|
|
if (!strcmp(c,"filename")) {
|
2023-01-26 17:23:43 +03:00
|
|
|
storestring(f.read_word(), filename_, 1);
|
2018-08-25 18:17:16 +03:00
|
|
|
} else if (!strcmp(c,"textmode")) {
|
|
|
|
text_mode_ = 1;
|
2023-11-16 15:21:17 +03:00
|
|
|
} else if (!strcmp(c,"compressed")) {
|
|
|
|
text_mode_ = 2;
|
2010-02-15 19:43:51 +03:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Decl_Type::read_property(f, c);
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the data_panel to edit this node.
|
|
|
|
*/
|
2010-02-15 19:43:51 +03:00
|
|
|
void Fl_Data_Type::open() {
|
|
|
|
if (!data_panel) make_data_panel();
|
2023-01-26 17:23:43 +03:00
|
|
|
data_input->value(name());
|
2010-02-15 19:43:51 +03:00
|
|
|
if (is_in_class()) {
|
|
|
|
data_class_choice->value(public_);
|
|
|
|
data_class_choice->show();
|
|
|
|
data_choice->hide();
|
|
|
|
} else {
|
|
|
|
data_choice->value((public_&1)|((static_&1)<<1));
|
|
|
|
data_choice->show();
|
|
|
|
data_class_choice->hide();
|
|
|
|
}
|
2018-08-25 18:17:16 +03:00
|
|
|
data_mode->value(text_mode_);
|
2010-02-15 19:43:51 +03:00
|
|
|
data_filename->value(filename_?filename_:"");
|
|
|
|
const char *c = comment();
|
|
|
|
data_comment_input->buffer()->text(c?c:"");
|
|
|
|
data_panel->show();
|
|
|
|
for (;;) { // repeat as long as there are errors
|
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == data_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == data_panel_ok) break;
|
|
|
|
else if (w == data_filebrowser) {
|
2022-11-15 19:48:06 +03:00
|
|
|
enter_project_dir();
|
2018-08-27 12:26:49 +03:00
|
|
|
const char *fn = fl_file_chooser("Load Inline Data", 0L, data_filename->value(), 1);
|
2022-11-15 19:48:06 +03:00
|
|
|
leave_project_dir();
|
2010-02-15 19:43:51 +03:00
|
|
|
if (fn) {
|
|
|
|
if (strcmp(fn, data_filename->value()))
|
2020-07-01 19:03:10 +03:00
|
|
|
set_modflag(1);
|
2010-02-15 19:43:51 +03:00
|
|
|
data_filename->value(fn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
|
|
|
// store the variable name:
|
|
|
|
const char*c = data_input->value();
|
2020-07-22 06:15:41 +03:00
|
|
|
char *s = fl_strdup(c), *p = s, *q, *n;
|
2023-06-04 22:10:43 +03:00
|
|
|
for (;;++p) { // remove leading spaces
|
2010-02-15 19:43:51 +03:00
|
|
|
if (!isspace((unsigned char)(*p))) break;
|
|
|
|
}
|
|
|
|
n = p;
|
|
|
|
if ( (!isalpha((unsigned char)(*p))) && ((*p)!='_') && ((*p)!=':') ) goto OOPS;
|
|
|
|
++p;
|
|
|
|
for (;;++p) {
|
|
|
|
if ( (!isalnum((unsigned char)(*p))) && ((*p)!='_') && ((*p)!=':') ) break;
|
|
|
|
}
|
|
|
|
q = p;
|
|
|
|
for (;;++q) {
|
|
|
|
if (!*q) break;
|
|
|
|
if (!isspace((unsigned char)(*q))) goto OOPS;
|
2020-07-01 19:03:10 +03:00
|
|
|
}
|
2023-06-04 22:10:43 +03:00
|
|
|
*p = 0; // remove trailing spaces
|
2010-02-15 19:43:51 +03:00
|
|
|
if (n==q) {
|
2023-06-04 22:10:43 +03:00
|
|
|
OOPS:
|
|
|
|
int v = fl_choice("%s",
|
2023-11-07 16:52:01 +03:00
|
|
|
"Continue Editing", "Ignore Error", NULL,
|
2023-06-04 22:10:43 +03:00
|
|
|
"Variable name must be a C identifier");
|
2023-11-07 16:52:01 +03:00
|
|
|
if (v==0) { free(s); continue; } // Continue Editing
|
|
|
|
//if (v==1) { } // Ignore Error and close dialog
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
2023-11-16 15:21:17 +03:00
|
|
|
undo_checkpoint();
|
2010-02-15 19:43:51 +03:00
|
|
|
name(n);
|
|
|
|
free(s);
|
|
|
|
// store flags
|
|
|
|
if (is_in_class()) {
|
|
|
|
if (public_!=data_class_choice->value()) {
|
|
|
|
set_modflag(1);
|
|
|
|
public_ = data_class_choice->value();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (public_!=(data_choice->value()&1)) {
|
|
|
|
set_modflag(1);
|
|
|
|
public_ = (data_choice->value()&1);
|
|
|
|
}
|
|
|
|
if (static_!=((data_choice->value()>>1)&1)) {
|
|
|
|
set_modflag(1);
|
|
|
|
static_ = ((data_choice->value()>>1)&1);
|
|
|
|
}
|
|
|
|
}
|
2018-08-25 18:17:16 +03:00
|
|
|
text_mode_ = data_mode->value();
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ < 0) text_mode_ = 0;
|
|
|
|
if (text_mode_ > 2) text_mode_ = 2;
|
2010-02-15 19:43:51 +03:00
|
|
|
// store the filename
|
|
|
|
c = data_filename->value();
|
|
|
|
if (filename_ && strcmp(filename_, data_filename->value()))
|
2020-07-01 19:03:10 +03:00
|
|
|
set_modflag(1);
|
2010-02-15 19:43:51 +03:00
|
|
|
else if (!filename_ && *c)
|
|
|
|
set_modflag(1);
|
|
|
|
if (filename_) { free((void*)filename_); filename_ = 0L; }
|
2020-07-22 06:15:41 +03:00
|
|
|
if (c && *c) filename_ = fl_strdup(c);
|
2010-02-15 19:43:51 +03:00
|
|
|
// store the comment
|
|
|
|
c = data_comment_input->buffer()->text();
|
|
|
|
if (c && *c) {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (!comment() || strcmp(c, comment())) { set_modflag(1); redraw_browser(); }
|
2010-02-15 19:43:51 +03:00
|
|
|
comment(c);
|
|
|
|
} else {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (comment()) { set_modflag(1); redraw_browser(); }
|
2010-02-15 19:43:51 +03:00
|
|
|
comment(0);
|
|
|
|
}
|
|
|
|
if (c) free((void*)c);
|
2023-11-16 15:21:17 +03:00
|
|
|
set_modflag(1);
|
2010-02-15 19:43:51 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BREAK2:
|
|
|
|
data_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the content of the external file inline into the source code.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Data_Type::write_code1(Fd_Code_Writer& f) {
|
2010-02-15 19:43:51 +03:00
|
|
|
const char *message = 0;
|
|
|
|
const char *c = name();
|
|
|
|
if (!c) return;
|
|
|
|
const char *fn = filename_;
|
|
|
|
char *data = 0;
|
2010-02-26 02:29:42 +03:00
|
|
|
int nData = -1;
|
2023-11-16 15:21:17 +03:00
|
|
|
int uncompressedDataSize = 0;
|
2010-02-15 19:43:51 +03:00
|
|
|
// path should be set correctly already
|
2024-04-17 18:51:32 +03:00
|
|
|
if (filename_ && !f.write_codeview) {
|
2022-11-15 19:48:06 +03:00
|
|
|
enter_project_dir();
|
2010-11-18 23:00:01 +03:00
|
|
|
FILE *f = fl_fopen(filename_, "rb");
|
2022-11-15 19:48:06 +03:00
|
|
|
leave_project_dir();
|
2010-02-15 19:43:51 +03:00
|
|
|
if (!f) {
|
2018-08-25 18:17:16 +03:00
|
|
|
message = "Can't include data from file. Can't open";
|
2010-02-15 19:43:51 +03:00
|
|
|
} else {
|
|
|
|
fseek(f, 0, SEEK_END);
|
2022-12-10 15:34:00 +03:00
|
|
|
nData = (int)ftell(f);
|
2010-02-15 19:43:51 +03:00
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
if (nData) {
|
|
|
|
data = (char*)calloc(nData, 1);
|
2010-10-29 01:47:01 +04:00
|
|
|
if (fread(data, nData, 1, f)==0) { /* use default */ }
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 2) {
|
|
|
|
uncompressedDataSize = nData;
|
|
|
|
uLong nzData = compressBound(nData);
|
|
|
|
Bytef *zdata = (Bytef*)::malloc(nzData);
|
|
|
|
if (compress(zdata, &nzData, (Bytef*)data, nData) != Z_OK) { /* error */ }
|
|
|
|
::free(data);
|
|
|
|
data = (char*)zdata;
|
|
|
|
nData = (int)nzData;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
} else {
|
2018-08-27 12:26:49 +03:00
|
|
|
fn = filename_ ? filename_ : "<no filename>";
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
2018-08-25 18:38:25 +03:00
|
|
|
if (is_in_class()) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_public(public_);
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 1) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%sstatic const char *%s;\n", f.indent(1), c);
|
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("const char *%s::%s = /* text inlined from %s */\n", class_name(1), c, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cstring(data, nData);
|
2023-11-16 15:21:17 +03:00
|
|
|
} else if (text_mode_ == 2) {
|
|
|
|
f.write_h("%sstatic int %s_size;\n", f.indent(1), c);
|
|
|
|
f.write_h("%sstatic unsigned char %s[%d];\n", f.indent(1), c, nData);
|
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("int %s::%s_size = %d;\n", class_name(1), c, uncompressedDataSize);
|
|
|
|
f.write_c("unsigned char %s::%s[%d] = /* data compressed and inlined from %s */\n", class_name(1), c, nData, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cdata(data, nData);
|
2018-08-25 18:38:25 +03:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("%sstatic unsigned char %s[%d];\n", f.indent(1), c, nData);
|
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("unsigned char %s::%s[%d] = /* data inlined from %s */\n", class_name(1), c, nData, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cdata(data, nData);
|
2018-08-25 18:38:25 +03:00
|
|
|
}
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c(";\n");
|
2010-02-15 19:43:51 +03:00
|
|
|
} else {
|
|
|
|
// the "header only" option does not apply here!
|
|
|
|
if (public_) {
|
|
|
|
if (static_) {
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 1) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("extern const char *%s;\n", c);
|
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("const char *%s = /* text inlined from %s */\n", c, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cstring(data, nData);
|
2023-11-16 15:21:17 +03:00
|
|
|
} else if (text_mode_ == 2) {
|
|
|
|
f.write_h("extern int %s_size;\n", c);
|
|
|
|
f.write_h("extern unsigned char %s[%d];\n", c, nData);
|
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("int %s_size = %d;\n", c, uncompressedDataSize);
|
|
|
|
f.write_c("unsigned char %s[%d] = /* data compressed and inlined from %s */\n", c, nData, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cdata(data, nData);
|
2018-08-25 18:38:25 +03:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("extern unsigned char %s[%d];\n", c, nData);
|
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
|
|
|
f.write_c("unsigned char %s[%d] = /* data inlined from %s */\n", c, nData, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cdata(data, nData);
|
2018-08-25 18:38:25 +03:00
|
|
|
}
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c(";\n");
|
2010-02-15 19:43:51 +03:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
write_comment_h(f);
|
|
|
|
f.write_h("#error Unsupported declaration loading inline data %s\n", fn);
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 1)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("const char *%s = \"abc...\";\n", c);
|
2018-08-25 18:38:25 +03:00
|
|
|
else
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("unsigned char %s[3] = { 1, 2, 3 };\n", c);
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("\n");
|
|
|
|
write_comment_c(f);
|
2020-07-01 19:03:10 +03:00
|
|
|
if (static_)
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("static ");
|
2023-11-16 15:21:17 +03:00
|
|
|
if (text_mode_ == 1) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("const char *%s = /* text inlined from %s */\n", c, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cstring(data, nData);
|
2023-11-16 15:21:17 +03:00
|
|
|
} else if (text_mode_ == 2) {
|
|
|
|
f.write_c("int %s_size = %d;\n", c, uncompressedDataSize);
|
|
|
|
if (static_) f.write_c("static ");
|
|
|
|
f.write_c("unsigned char %s[%d] = /* data compressed and inlined from %s */\n", c, nData, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cdata(data, nData);
|
2018-08-25 18:38:25 +03:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c("unsigned char %s[%d] = /* data inlined from %s */\n", c, nData, fn);
|
|
|
|
if (message) f.write_c("#error %s %s\n", message, fn);
|
|
|
|
f.write_cdata(data, nData);
|
2018-08-25 18:38:25 +03:00
|
|
|
}
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_c(";\n");
|
2010-02-15 19:43:51 +03:00
|
|
|
}
|
|
|
|
}
|
2020-07-01 19:03:10 +03:00
|
|
|
// if we are in interactive mode, we pop up a warning dialog
|
2024-04-17 18:51:32 +03:00
|
|
|
// giving the error: (batch_mode && !write_codeview) ???
|
|
|
|
if (message && !f.write_codeview) {
|
2015-03-09 23:37:45 +03:00
|
|
|
if (batch_mode)
|
2010-02-15 19:43:51 +03:00
|
|
|
fprintf(stderr, "FLUID ERROR: %s %s\n", message, fn);
|
|
|
|
else
|
|
|
|
fl_alert("%s\n%s\n", message, fn);
|
|
|
|
}
|
|
|
|
if (data) free(data);
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
// ---- Fl_DeclBlock_Type declaration
|
2010-02-15 19:43:51 +03:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/** \class Fl_DeclBlock_Type
|
|
|
|
Manage a declaration block.
|
|
|
|
|
|
|
|
Declaration blocks have two text field that are written before and after
|
|
|
|
the children of this block. This block is located at the top level and
|
|
|
|
is written to the source file, and to the header file, if declared public.
|
|
|
|
*/
|
2010-02-15 19:43:51 +03:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/// Prototype for a declaration block to be used by the factory.
|
|
|
|
Fl_DeclBlock_Type Fl_DeclBlock_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Constructor.
|
|
|
|
*/
|
|
|
|
Fl_DeclBlock_Type::Fl_DeclBlock_Type() :
|
|
|
|
Fl_Type(),
|
2024-04-25 18:52:32 +03:00
|
|
|
after(NULL),
|
|
|
|
write_map_(CODE_IN_SOURCE)
|
2021-12-08 17:52:15 +03:00
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
Destructor.
|
|
|
|
*/
|
|
|
|
Fl_DeclBlock_Type::~Fl_DeclBlock_Type() {
|
|
|
|
if (after)
|
2024-04-25 18:52:32 +03:00
|
|
|
::free((void*)after);
|
2021-12-08 17:52:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Return 1 if this block is public.
|
|
|
|
*/
|
2024-04-25 18:52:32 +03:00
|
|
|
int Fl_DeclBlock_Type::is_public() const {
|
|
|
|
return ((write_map_&CODE_IN_HEADER) != 0);
|
|
|
|
}
|
2004-03-11 08:17:12 +03:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Create a new declaration block.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add after current or as last child
|
2024-03-03 00:58:52 +03:00
|
|
|
\return new Declaration Block node
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_DeclBlock_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_decl_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_DeclBlock_Type *o = new Fl_DeclBlock_Type();
|
|
|
|
o->name("#if 1");
|
2024-04-25 18:52:32 +03:00
|
|
|
o->write_map_ = CODE_IN_SOURCE;
|
2020-07-22 06:15:41 +03:00
|
|
|
o->after = fl_strdup("#endif");
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
1998-10-06 22:21:25 +04:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the specific properties.
|
|
|
|
- "public"/"protected"
|
|
|
|
- "after" followed by the second code block.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_DeclBlock_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Type::write_properties(f);
|
2024-04-25 18:52:32 +03:00
|
|
|
// deprecated
|
|
|
|
if (is_public()) f.write_string("public");
|
|
|
|
// new way to map declaration block to various parts of the generated code
|
|
|
|
if (write_map_ != CODE_IN_SOURCE)
|
|
|
|
f.write_string("map %d", write_map_);
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string("after");
|
|
|
|
f.write_word(after);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Read the specific properties.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_DeclBlock_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
2004-03-11 08:17:12 +03:00
|
|
|
if(!strcmp(c,"public")) {
|
2024-04-25 18:52:32 +03:00
|
|
|
write_map_ |= CODE_IN_HEADER;
|
2008-01-05 00:45:49 +03:00
|
|
|
} else if(!strcmp(c,"protected")) {
|
2024-04-25 18:52:32 +03:00
|
|
|
//
|
|
|
|
} else if(!strcmp(c,"map")) {
|
|
|
|
write_map_ = (int)atol(f.read_word());
|
2004-03-11 08:17:12 +03:00
|
|
|
} else if (!strcmp(c,"after")) {
|
2023-01-26 17:23:43 +03:00
|
|
|
storestring(f.read_word(),after);
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::read_property(f, c);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the declblock_panel to edit this node.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_DeclBlock_Type::open() {
|
2024-04-25 18:52:32 +03:00
|
|
|
// build dialog box
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!declblock_panel) make_declblock_panel();
|
2024-04-25 18:52:32 +03:00
|
|
|
// preset all values
|
|
|
|
declblock_before_input->value(name());
|
|
|
|
declblock_after_input->value(after);
|
|
|
|
declblock_static_header->value(write_map_ & STATIC_IN_HEADER);
|
|
|
|
declblock_static_source->value(write_map_ & STATIC_IN_SOURCE);
|
|
|
|
declblock_code_header->value(write_map_ & CODE_IN_HEADER);
|
|
|
|
declblock_code_source->value(write_map_ & CODE_IN_SOURCE);
|
|
|
|
const char *c = comment();
|
|
|
|
declblock_comment_input->buffer()->text(c?c:"");
|
|
|
|
// show modal dialog and loop until satisfied
|
1998-10-06 22:21:25 +04:00
|
|
|
declblock_panel->show();
|
|
|
|
const char* message = 0;
|
|
|
|
for (;;) { // repeat as long as there are errors
|
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == declblock_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == declblock_panel_ok) break;
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
2024-04-25 18:52:32 +03:00
|
|
|
// verify user input
|
|
|
|
const char* a = declblock_before_input->value();
|
2023-01-26 18:23:35 +03:00
|
|
|
while (isspace(*a)) a++;
|
2024-04-25 18:52:32 +03:00
|
|
|
const char* b = declblock_after_input->value();
|
2023-01-26 18:23:35 +03:00
|
|
|
while (isspace(*b)) b++;
|
|
|
|
message = c_check(a&&a[0]=='#' ? a+1 : a);
|
|
|
|
if (!message)
|
|
|
|
message = c_check(b&&b[0]=='#' ? b+1 : b);
|
|
|
|
if (message) {
|
2023-06-04 22:10:43 +03:00
|
|
|
int v = fl_choice("Potential syntax error detected: %s",
|
2023-11-07 16:52:01 +03:00
|
|
|
"Continue Editing", "Ignore Error", NULL, message);
|
|
|
|
if (v==0) continue; // Continue Editing
|
|
|
|
//if (v==1) { } // Ignore Error and close dialog
|
2023-01-26 18:23:35 +03:00
|
|
|
}
|
2024-04-25 18:52:32 +03:00
|
|
|
// store user choices in data structure
|
2023-01-26 18:23:35 +03:00
|
|
|
name(a);
|
|
|
|
storestring(b, after);
|
2024-04-25 18:52:32 +03:00
|
|
|
if (write_map_ & STATIC_IN_HEADER) {
|
|
|
|
if (declblock_static_header->value()==0) {
|
|
|
|
write_map_ &= ~STATIC_IN_HEADER;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (declblock_static_header->value()) {
|
|
|
|
write_map_ |= STATIC_IN_HEADER;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (write_map_ & STATIC_IN_SOURCE) {
|
|
|
|
if (declblock_static_source->value()==0) {
|
|
|
|
write_map_ &= ~STATIC_IN_SOURCE;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (declblock_static_source->value()) {
|
|
|
|
write_map_ |= STATIC_IN_SOURCE;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (write_map_ & CODE_IN_HEADER) {
|
|
|
|
if (declblock_code_header->value()==0) {
|
|
|
|
write_map_ &= ~CODE_IN_HEADER;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (declblock_code_header->value()) {
|
|
|
|
write_map_ |= CODE_IN_HEADER;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (write_map_ & CODE_IN_SOURCE) {
|
|
|
|
if (declblock_code_source->value()==0) {
|
|
|
|
write_map_ &= ~CODE_IN_SOURCE;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (declblock_code_source->value()) {
|
|
|
|
write_map_ |= CODE_IN_SOURCE;
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c = declblock_comment_input->buffer()->text();
|
|
|
|
if (c && *c) {
|
|
|
|
if (!comment() || strcmp(c, comment())) { set_modflag(1); redraw_browser(); }
|
|
|
|
comment(c);
|
|
|
|
} else {
|
|
|
|
if (comment()) { set_modflag(1); redraw_browser(); }
|
|
|
|
comment(0);
|
2005-08-22 01:55:22 +04:00
|
|
|
}
|
2024-04-25 18:52:32 +03:00
|
|
|
if (c) free((void*)c);
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
1998-10-06 22:21:25 +04:00
|
|
|
declblock_panel->hide();
|
|
|
|
}
|
|
|
|
|
2024-04-25 18:52:32 +03:00
|
|
|
/**
|
|
|
|
Write the \b before static code to the source file, and to the header file if declared public.
|
|
|
|
The before code is stored in the name() field.
|
|
|
|
*/
|
|
|
|
void Fl_DeclBlock_Type::write_static(Fd_Code_Writer& f) {
|
|
|
|
const char* c = name();
|
|
|
|
if (c && *c) {
|
|
|
|
if (write_map_ & STATIC_IN_HEADER)
|
|
|
|
f.write_h("%s\n", c);
|
|
|
|
if (write_map_ & STATIC_IN_SOURCE)
|
|
|
|
f.write_c("%s\n", c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Write the \b after static code to the source file, and to the header file if declared public.
|
|
|
|
*/
|
|
|
|
void Fl_DeclBlock_Type::write_static_after(Fd_Code_Writer& f) {
|
|
|
|
const char* c = after;
|
|
|
|
if (c && *c) {
|
|
|
|
if (write_map_ & STATIC_IN_HEADER)
|
|
|
|
f.write_h("%s\n", c);
|
|
|
|
if (write_map_ & STATIC_IN_SOURCE)
|
|
|
|
f.write_c("%s\n", c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the \b before code to the source file, and to the header file if declared public.
|
|
|
|
The before code is stored in the name() field.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_DeclBlock_Type::write_code1(Fd_Code_Writer& f) {
|
1998-10-06 22:21:25 +04:00
|
|
|
const char* c = name();
|
2024-04-17 18:51:32 +03:00
|
|
|
if (c && *c) {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (write_map_ & CODE_IN_HEADER)
|
2024-04-17 18:51:32 +03:00
|
|
|
f.write_h("%s\n", c);
|
2024-04-25 18:52:32 +03:00
|
|
|
if (write_map_ & CODE_IN_SOURCE)
|
|
|
|
f.write_c("%s\n", c);
|
2024-04-17 18:51:32 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the \b after code to the source file, and to the header file if declared public.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_DeclBlock_Type::write_code2(Fd_Code_Writer& f) {
|
1998-10-06 22:21:25 +04:00
|
|
|
const char* c = after;
|
2024-04-17 18:51:32 +03:00
|
|
|
if (c && *c) {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (write_map_ & CODE_IN_HEADER)
|
2024-04-17 18:51:32 +03:00
|
|
|
f.write_h("%s\n", c);
|
2024-04-25 18:52:32 +03:00
|
|
|
if (write_map_ & CODE_IN_SOURCE)
|
|
|
|
f.write_c("%s\n", c);
|
2024-04-17 18:51:32 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
// ---- Fl_Comment_Type declaration
|
|
|
|
|
|
|
|
/** \class Fl_Comment_Type
|
|
|
|
Manage a comment node.
|
|
|
|
|
|
|
|
The comment field takes one or more lines of ASCII text. If the text starts
|
|
|
|
with a '/' and a '*', Fluid assumes that the text is already formatted. If not,
|
|
|
|
every line will be preceded with "// ".
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/// Prototype for a comment node to be used by the factory.
|
|
|
|
Fl_Comment_Type Fl_Comment_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Constructor.
|
|
|
|
*/
|
|
|
|
Fl_Comment_Type::Fl_Comment_Type() :
|
|
|
|
in_c_(1),
|
|
|
|
in_h_(1),
|
|
|
|
style_(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
Make a new comment node.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add after current or as last child
|
|
|
|
\return new Comment node
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_Comment_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_code_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
2005-03-10 00:26:53 +03:00
|
|
|
Fl_Comment_Type *o = new Fl_Comment_Type();
|
|
|
|
o->in_c_ = 1;
|
|
|
|
o->in_h_ = 1;
|
|
|
|
o->style_ = 0;
|
|
|
|
o->name("my comment");
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
2005-03-10 00:26:53 +03:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write respective properties.
|
|
|
|
- "in_source"/"not_in_source" if the comment will be written to the source code
|
|
|
|
- "in_header"/"not_in_header" if the comment will be written to the header file
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Comment_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Type::write_properties(f);
|
|
|
|
if (in_c_) f.write_string("in_source"); else f.write_string("not_in_source");
|
|
|
|
if (in_h_) f.write_string("in_header"); else f.write_string("not_in_header");
|
2005-03-10 00:26:53 +03:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Read extra properties.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Comment_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
2005-03-10 00:26:53 +03:00
|
|
|
if (!strcmp(c,"in_source")) {
|
|
|
|
in_c_ = 1;
|
|
|
|
} else if (!strcmp(c,"not_in_source")) {
|
|
|
|
in_c_ = 0;
|
|
|
|
} else if (!strcmp(c,"in_header")) {
|
|
|
|
in_h_ = 1;
|
|
|
|
} else if (!strcmp(c,"not_in_header")) {
|
|
|
|
in_h_ = 0;
|
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::read_property(f, c);
|
2005-03-10 00:26:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Load available preset comments.
|
|
|
|
Fluid comes with GPL and LGPL preset for comments. Users can
|
2023-08-26 16:17:28 +03:00
|
|
|
add their own presets which are stored per user in a separate
|
2021-12-08 17:52:15 +03:00
|
|
|
preferences database.
|
|
|
|
*/
|
2005-03-10 00:26:53 +03:00
|
|
|
static void load_comments_preset(Fl_Preferences &menu) {
|
2005-04-14 16:29:51 +04:00
|
|
|
static const char * const predefined_comment[] = {
|
2023-07-21 14:34:04 +03:00
|
|
|
"GNU Public License v3/GPL Header", "GNU Public License v3/GPL Footer",
|
|
|
|
"GNU Public License v3/LGPL Header", "GNU Public License v3/LGPL Footer",
|
2020-07-01 19:03:10 +03:00
|
|
|
"FLTK/Header" };
|
2023-07-21 14:34:04 +03:00
|
|
|
int i, n;
|
|
|
|
menu.get("n", n, -1);
|
|
|
|
if (n == -1) menu.set("n", 5);
|
|
|
|
menu.set("version", 10400);
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
|
2020-07-01 19:03:10 +03:00
|
|
|
for (i=0; i<5; i++) {
|
2005-03-10 00:26:53 +03:00
|
|
|
menu.set(Fl_Preferences::Name(i), predefined_comment[i]);
|
|
|
|
db.set(predefined_comment[i], comment_text[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the comment_panel to edit this node.
|
|
|
|
*/
|
2005-03-10 00:26:53 +03:00
|
|
|
void Fl_Comment_Type::open() {
|
|
|
|
if (!comment_panel) make_comment_panel();
|
|
|
|
const char *text = name();
|
|
|
|
{
|
2023-07-21 14:34:04 +03:00
|
|
|
int i=0, n=0, version = 0;
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
|
2005-03-10 00:26:53 +03:00
|
|
|
comment_predefined->clear();
|
|
|
|
comment_predefined->add("_Edit/Add current comment...");
|
|
|
|
comment_predefined->add("_Edit/Remove last selection...");
|
2023-07-21 14:34:04 +03:00
|
|
|
menu.get("version", version, -1);
|
|
|
|
if (version < 10400) load_comments_preset(menu);
|
2005-03-10 00:26:53 +03:00
|
|
|
menu.get("n", n, 0);
|
|
|
|
for (i=0;i<n;i++) {
|
|
|
|
char *text;
|
|
|
|
menu.get(Fl_Preferences::Name(i), text, "");
|
|
|
|
comment_predefined->add(text);
|
|
|
|
free(text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
comment_input->buffer()->text( text ? text : "" );
|
|
|
|
comment_in_source->value(in_c_);
|
|
|
|
comment_in_header->value(in_h_);
|
|
|
|
comment_panel->show();
|
2010-12-20 00:20:10 +03:00
|
|
|
char itempath[FL_PATH_MAX]; itempath[0] = 0;
|
2005-03-10 00:26:53 +03:00
|
|
|
int last_selected_item = 0;
|
|
|
|
for (;;) { // repeat as long as there are errors
|
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == comment_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == comment_panel_ok) break;
|
|
|
|
else if (w == comment_predefined) {
|
|
|
|
if (comment_predefined->value()==1) {
|
|
|
|
// add the current comment to the database
|
|
|
|
const char *xname = fl_input(
|
2010-02-15 19:43:51 +03:00
|
|
|
"Please enter a name to reference the current\ncomment in your database.\n\n"
|
2020-07-01 19:03:10 +03:00
|
|
|
"Use forward slashes '/' to create submenus.",
|
2010-02-15 19:43:51 +03:00
|
|
|
"My Comment");
|
2005-03-10 00:26:53 +03:00
|
|
|
if (xname) {
|
2020-07-22 06:15:41 +03:00
|
|
|
char *name = fl_strdup(xname);
|
2005-03-10 00:26:53 +03:00
|
|
|
for (char*s=name;*s;s++) if (*s==':') *s = ';';
|
|
|
|
int n;
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
|
2005-03-10 00:26:53 +03:00
|
|
|
db.set(name, comment_input->buffer()->text());
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
|
2005-03-10 00:26:53 +03:00
|
|
|
menu.get("n", n, 0);
|
|
|
|
menu.set(Fl_Preferences::Name(n), name);
|
|
|
|
menu.set("n", ++n);
|
|
|
|
comment_predefined->add(name);
|
|
|
|
free(name);
|
|
|
|
}
|
|
|
|
} else if (comment_predefined->value()==2) {
|
|
|
|
// remove the last selected comment from the database
|
|
|
|
if (itempath[0]==0 || last_selected_item==0) {
|
2023-07-21 14:34:04 +03:00
|
|
|
fl_message("Please select an entry from this menu first.");
|
2005-03-28 08:23:32 +04:00
|
|
|
} else if (fl_choice("Are you sure that you want to delete the entry\n"
|
2020-07-01 19:03:10 +03:00
|
|
|
"\"%s\"\nfrom the database?", "Cancel", "Delete",
|
|
|
|
NULL, itempath)) {
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
|
2005-03-10 00:26:53 +03:00
|
|
|
db.deleteEntry(itempath);
|
|
|
|
comment_predefined->remove(last_selected_item);
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
|
2005-03-10 00:35:09 +03:00
|
|
|
int i, n;
|
|
|
|
for (i=4, n=0; i<comment_predefined->size(); i++) {
|
2005-03-10 00:26:53 +03:00
|
|
|
const Fl_Menu_Item *mi = comment_predefined->menu()+i;
|
|
|
|
if (comment_predefined->item_pathname(itempath, 255, mi)==0) {
|
|
|
|
if (itempath[0]=='/') memmove(itempath, itempath+1, 255);
|
|
|
|
if (itempath[0]) menu.set(Fl_Preferences::Name(n++), itempath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
menu.set("n", n);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// load the selected comment from the database
|
|
|
|
if (comment_predefined->item_pathname(itempath, 255)==0) {
|
|
|
|
if (itempath[0]=='/') memmove(itempath, itempath+1, 255);
|
2022-01-19 18:08:29 +03:00
|
|
|
Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
|
2020-07-01 19:03:10 +03:00
|
|
|
char *text;
|
2005-03-10 00:26:53 +03:00
|
|
|
db.get(itempath, text, "(no text found in data base)");
|
|
|
|
comment_input->buffer()->text(text);
|
|
|
|
free(text);
|
|
|
|
last_selected_item = comment_predefined->value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (w == comment_load) {
|
|
|
|
// load a comment from disk
|
2020-07-01 19:03:10 +03:00
|
|
|
fl_file_chooser_ok_label("Use File");
|
2005-03-10 00:26:53 +03:00
|
|
|
const char *fname = fl_file_chooser("Pick a comment", 0L, 0L);
|
2020-07-01 19:03:10 +03:00
|
|
|
fl_file_chooser_ok_label(NULL);
|
2005-03-10 00:26:53 +03:00
|
|
|
if (fname) {
|
|
|
|
if (comment_input->buffer()->loadfile(fname)) {
|
|
|
|
fl_alert("Error loading file\n%s", fname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
|
|
|
char*c = comment_input->buffer()->text();
|
|
|
|
name(c);
|
|
|
|
free(c);
|
2005-08-22 01:55:22 +04:00
|
|
|
int mod = 0;
|
|
|
|
if (in_c_ != comment_in_source->value()) {
|
|
|
|
in_c_ = comment_in_source->value();
|
|
|
|
mod = 1;
|
|
|
|
}
|
|
|
|
if (in_h_ != comment_in_header->value()) {
|
|
|
|
in_h_ = comment_in_header->value();
|
|
|
|
mod = 1;
|
|
|
|
}
|
|
|
|
if (mod) set_modflag(1);
|
2005-03-10 00:26:53 +03:00
|
|
|
break;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
2005-03-10 00:26:53 +03:00
|
|
|
comment_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the comment to the files.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Comment_Type::write_code1(Fd_Code_Writer& f) {
|
2005-03-10 00:26:53 +03:00
|
|
|
const char* c = name();
|
|
|
|
if (!c) return;
|
|
|
|
if (!in_c_ && !in_h_) return;
|
|
|
|
// find out if there is already a valid comment:
|
|
|
|
const char *s = c;
|
|
|
|
while (isspace(*s)) s++;
|
|
|
|
// if this seems to be a C style comment, copy the block as is
|
|
|
|
// (it's up to the user to correctly close the comment)
|
|
|
|
if (s[0]=='/' && s[1]=='*') {
|
2023-01-26 17:23:43 +03:00
|
|
|
if (in_h_) f.write_h("%s\n", c);
|
|
|
|
if (in_c_) f.write_c("%s\n", c);
|
2005-03-10 00:26:53 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// copy the comment line by line, add the double slash if needed
|
2020-07-22 06:15:41 +03:00
|
|
|
char *txt = fl_strdup(c);
|
2005-03-10 00:26:53 +03:00
|
|
|
char *b = txt, *e = txt;
|
|
|
|
for (;;) {
|
|
|
|
// find the end of the line and set it to NUL
|
|
|
|
while (*e && *e!='\n') e++;
|
|
|
|
char eol = *e;
|
|
|
|
*e = 0;
|
|
|
|
// check if there is a C++ style comment at the beginning of the line
|
|
|
|
char *s = b;
|
|
|
|
while (isspace(*s)) s++;
|
|
|
|
if (s!=e && ( s[0]!='/' || s[1]!='/') ) {
|
|
|
|
// if no comment marker was found, we add one ourselves
|
2023-01-26 17:23:43 +03:00
|
|
|
if (in_h_) f.write_h("// ");
|
|
|
|
if (in_c_) f.write_c("// ");
|
2005-03-10 00:26:53 +03:00
|
|
|
}
|
|
|
|
// now copy the rest of the line
|
2023-01-26 17:23:43 +03:00
|
|
|
if (in_h_) f.write_h("%s\n", b);
|
|
|
|
if (in_c_) f.write_c("%s\n", b);
|
2005-03-10 00:26:53 +03:00
|
|
|
if (eol==0) break;
|
|
|
|
*e++ = eol;
|
|
|
|
b = e;
|
|
|
|
}
|
2020-03-08 14:42:30 +03:00
|
|
|
free(txt);
|
2005-03-10 00:26:53 +03:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
// ---- Fl_Class_Type declaration
|
2005-03-10 00:26:53 +03:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/** \class Fl_Class_Type
|
|
|
|
Manage a class declaration and implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// Prototype for a class node to be used by the factory.
|
|
|
|
Fl_Class_Type Fl_Class_type;
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2005-08-23 15:28:13 +04:00
|
|
|
/**
|
2021-12-08 17:52:15 +03:00
|
|
|
Constructor.
|
2005-08-23 15:28:13 +04:00
|
|
|
*/
|
2021-12-08 17:52:15 +03:00
|
|
|
Fl_Class_Type::Fl_Class_Type() :
|
|
|
|
Fl_Type(),
|
|
|
|
subclass_of(NULL),
|
|
|
|
public_(1),
|
|
|
|
class_prefix(NULL)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
Destructor.
|
|
|
|
*/
|
|
|
|
Fl_Class_Type::~Fl_Class_Type() {
|
|
|
|
if (subclass_of)
|
|
|
|
free((void*)subclass_of);
|
|
|
|
if (class_prefix)
|
|
|
|
free((void*)class_prefix);
|
2005-08-23 15:28:13 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Return 1 if this class is marked public.
|
|
|
|
*/
|
|
|
|
int Fl_Class_Type::is_public() const {
|
|
|
|
return public_;
|
|
|
|
}
|
2002-04-26 15:51:54 +04:00
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Set the prefixx string.
|
|
|
|
*/
|
2003-01-28 23:51:17 +03:00
|
|
|
void Fl_Class_Type::prefix(const char*p) {
|
|
|
|
free((void*) class_prefix);
|
2020-07-22 06:15:41 +03:00
|
|
|
class_prefix=fl_strdup(p ? p : "" );
|
2003-01-28 23:51:17 +03:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Make a new class node.
|
2021-12-11 21:43:00 +03:00
|
|
|
\param[in] strategy add after current or as last child
|
|
|
|
\return new Class node
|
2021-12-08 17:52:15 +03:00
|
|
|
*/
|
2021-12-11 21:43:00 +03:00
|
|
|
Fl_Type *Fl_Class_Type::make(Strategy strategy) {
|
2024-09-14 02:10:35 +03:00
|
|
|
Fl_Type *anchor = Fl_Type::current, *p = anchor;
|
|
|
|
if (p && (strategy == kAddAfterCurrent)) p = p->parent;
|
|
|
|
while (p && !p->is_decl_block()) {
|
|
|
|
anchor = p;
|
|
|
|
strategy = kAddAfterCurrent;
|
|
|
|
p = p->parent;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Class_Type *o = new Fl_Class_Type();
|
|
|
|
o->name("UserInterface");
|
2021-12-08 17:52:15 +03:00
|
|
|
o->class_prefix = NULL;
|
|
|
|
o->subclass_of = NULL;
|
1998-10-06 22:21:25 +04:00
|
|
|
o->public_ = 1;
|
2024-09-14 02:10:35 +03:00
|
|
|
o->add(anchor, strategy);
|
1998-10-06 22:21:25 +04:00
|
|
|
o->factory = this;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the respective properties.
|
|
|
|
- ":" followed by the super class
|
|
|
|
- "private"/"protected"
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Class_Type::write_properties(Fd_Project_Writer &f) {
|
|
|
|
Fl_Type::write_properties(f);
|
1998-10-06 22:21:25 +04:00
|
|
|
if (subclass_of) {
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_string(":");
|
|
|
|
f.write_word(subclass_of);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2008-01-05 00:45:49 +03:00
|
|
|
switch (public_) {
|
2023-01-26 17:23:43 +03:00
|
|
|
case 0: f.write_string("private"); break;
|
|
|
|
case 2: f.write_string("protected"); break;
|
2008-01-05 00:45:49 +03:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Read additional properties.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Class_Type::read_property(Fd_Project_Reader &f, const char *c) {
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!strcmp(c,"private")) {
|
|
|
|
public_ = 0;
|
2008-01-05 00:45:49 +03:00
|
|
|
} else if (!strcmp(c,"protected")) {
|
|
|
|
public_ = 2;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else if (!strcmp(c,":")) {
|
2023-01-26 17:23:43 +03:00
|
|
|
storestring(f.read_word(), subclass_of);
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2023-01-26 17:23:43 +03:00
|
|
|
Fl_Type::read_property(f, c);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Open the class_panel to edit the class name and superclass name.
|
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Class_Type::open() {
|
|
|
|
if (!class_panel) make_class_panel();
|
2010-12-20 00:20:10 +03:00
|
|
|
char fullname[FL_PATH_MAX]="";
|
2020-07-01 19:03:10 +03:00
|
|
|
if (prefix() && strlen(prefix()))
|
2003-01-28 23:51:17 +03:00
|
|
|
sprintf(fullname,"%s %s",prefix(),name());
|
2020-07-01 19:03:10 +03:00
|
|
|
else
|
2003-01-28 23:51:17 +03:00
|
|
|
strcpy(fullname, name());
|
2023-01-26 17:23:43 +03:00
|
|
|
c_name_input->value(fullname);
|
|
|
|
c_subclass_input->value(subclass_of);
|
1998-10-06 22:21:25 +04:00
|
|
|
c_public_button->value(public_);
|
2008-09-18 02:43:15 +04:00
|
|
|
const char *c = comment();
|
|
|
|
c_comment_input->buffer()->text(c?c:"");
|
1998-10-06 22:21:25 +04:00
|
|
|
class_panel->show();
|
|
|
|
const char* message = 0;
|
2020-07-01 19:03:10 +03:00
|
|
|
|
2003-01-28 23:51:17 +03:00
|
|
|
char *na=0,*pr=0,*p=0; // name and prefix substrings
|
2020-07-01 19:03:10 +03:00
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
for (;;) { // repeat as long as there are errors
|
2023-06-04 22:10:43 +03:00
|
|
|
// we don;t give the option to ignore this error here because code depends
|
|
|
|
// on this being a C++ identifier
|
2010-10-29 01:47:01 +04:00
|
|
|
if (message) fl_alert("%s", message);
|
1998-10-06 22:21:25 +04:00
|
|
|
for (;;) {
|
|
|
|
Fl_Widget* w = Fl::readqueue();
|
|
|
|
if (w == c_panel_cancel) goto BREAK2;
|
|
|
|
else if (w == c_panel_ok) break;
|
|
|
|
else if (!w) Fl::wait();
|
|
|
|
}
|
|
|
|
const char*c = c_name_input->value();
|
2020-07-22 06:15:41 +03:00
|
|
|
char *s = fl_strdup(c);
|
2003-01-28 23:51:17 +03:00
|
|
|
size_t len = strlen(s);
|
|
|
|
if (!*s) goto OOPS;
|
|
|
|
p = (char*) (s+len-1);
|
|
|
|
while (p>=s && isspace(*p)) *(p--)='\0';
|
|
|
|
if (p<s) goto OOPS;
|
|
|
|
while (p>=s && is_id(*p)) p--;
|
|
|
|
if ( (p<s && !is_id(*(p+1))) || !*(p+1) ) {
|
2010-02-15 19:43:51 +03:00
|
|
|
OOPS: message = "class name must be C++ identifier";
|
2003-01-28 23:51:17 +03:00
|
|
|
free((void*)s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
na=p+1; // now we have the name
|
|
|
|
if(p>s) *p--='\0';
|
|
|
|
while (p>=s && isspace(*p)) *(p--)='\0';
|
|
|
|
while (p>=s && is_id(*p)) p--;
|
|
|
|
if (p<s) p++;
|
|
|
|
if (is_id(*p) && p<na) pr=p; // prefix detected
|
1998-10-06 22:21:25 +04:00
|
|
|
c = c_subclass_input->value();
|
2020-07-01 19:03:10 +03:00
|
|
|
message = c_check(c);
|
2003-01-28 23:51:17 +03:00
|
|
|
if (message) { free((void*)s);continue;}
|
|
|
|
name(na);
|
|
|
|
prefix(pr);
|
|
|
|
free((void*)s);
|
1998-10-06 22:21:25 +04:00
|
|
|
storestring(c, subclass_of);
|
2005-08-22 01:55:22 +04:00
|
|
|
if (public_ != c_public_button->value()) {
|
|
|
|
public_ = c_public_button->value();
|
|
|
|
set_modflag(1);
|
|
|
|
}
|
2008-09-18 02:43:15 +04:00
|
|
|
c = c_comment_input->buffer()->text();
|
|
|
|
if (c && *c) {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (!comment() || strcmp(c, comment())) { set_modflag(1); redraw_browser(); }
|
2008-09-18 02:43:15 +04:00
|
|
|
comment(c);
|
|
|
|
} else {
|
2024-04-25 18:52:32 +03:00
|
|
|
if (comment()) { set_modflag(1); redraw_browser(); }
|
2008-09-18 02:43:15 +04:00
|
|
|
comment(0);
|
|
|
|
}
|
|
|
|
if (c) free((void*)c);
|
1998-10-06 22:21:25 +04:00
|
|
|
break;
|
|
|
|
}
|
2010-02-15 19:43:51 +03:00
|
|
|
BREAK2:
|
1998-10-06 22:21:25 +04:00
|
|
|
class_panel->hide();
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the header code that declares this class.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Class_Type::write_code1(Fd_Code_Writer& f) {
|
1998-10-06 22:21:25 +04:00
|
|
|
parent_class = current_class;
|
|
|
|
current_class = this;
|
|
|
|
write_public_state = 0;
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("\n");
|
|
|
|
write_comment_h(f);
|
2003-01-28 23:51:17 +03:00
|
|
|
if (prefix() && strlen(prefix()))
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("class %s %s ", prefix(), name());
|
2003-01-28 23:51:17 +03:00
|
|
|
else
|
2023-01-26 17:23:43 +03:00
|
|
|
f.write_h("class %s ", name());
|
|
|
|
if (subclass_of) f.write_h(": %s ", subclass_of);
|
|
|
|
f.write_h("{\n");
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2021-12-08 17:52:15 +03:00
|
|
|
/**
|
|
|
|
Write the header code that ends the declaration of this class.
|
|
|
|
*/
|
2023-01-26 17:23:43 +03:00
|
|
|
void Fl_Class_Type::write_code2(Fd_Code_Writer& f) {
|
|
|
|
f.write_h("};\n");
|
1998-10-06 22:21:25 +04:00
|
|
|
current_class = parent_class;
|
|
|
|
}
|
1998-10-21 20:29:01 +04:00
|
|
|
|
2005-08-23 15:28:13 +04:00
|
|
|
/**
|
2018-06-23 23:50:22 +03:00
|
|
|
Return 1 if this class contains a function with the given signature.
|
2005-08-23 15:28:13 +04:00
|
|
|
*/
|
2023-10-20 00:54:31 +03:00
|
|
|
int Fl_Type::has_function(const char *rtype, const char *sig) const {
|
2005-08-23 15:28:13 +04:00
|
|
|
Fl_Type *child;
|
|
|
|
for (child = next; child && child->level > level; child = child->next) {
|
2023-10-20 20:00:42 +03:00
|
|
|
if (child->level == level+1 && child->is_a(ID_Function)) {
|
2005-08-23 15:28:13 +04:00
|
|
|
const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
|
|
|
|
if (fn->has_signature(rtype, sig))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|