summaryrefslogtreecommitdiff
path: root/fluid/Fl_Function_Type.cxx
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2025-03-07 16:34:35 +0100
committerMatthias Melcher <github@matthiasm.com>2025-03-07 16:34:48 +0100
commit1985aefc0e502048f92b91beef87c0dfbe669fed (patch)
treeaf62874def4590e437a47784b4428d975ceb262f /fluid/Fl_Function_Type.cxx
parent42a04c064d4b31c3a85210311f3ada163c406a25 (diff)
Restructuring Fluid source files.
Diffstat (limited to 'fluid/Fl_Function_Type.cxx')
-rw-r--r--fluid/Fl_Function_Type.cxx2156
1 files changed, 0 insertions, 2156 deletions
diff --git a/fluid/Fl_Function_Type.cxx b/fluid/Fl_Function_Type.cxx
deleted file mode 100644
index 935cd6405..000000000
--- a/fluid/Fl_Function_Type.cxx
+++ /dev/null
@@ -1,2156 +0,0 @@
-//
-// C function type code for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2023 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-#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"
-#include "mergeback.h"
-#include "undo.h"
-
-#include <FL/fl_string_functions.h>
-#include <FL/Fl_File_Chooser.H>
-#include <FL/fl_ask.H>
-#include "../src/flstring.h"
-
-#include <zlib.h>
-
-
-/// Set a current class, so that the code of the children is generated correctly.
-Fl_Class_Type *current_class = NULL;
-
-/**
- \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)
- \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) {
- if (!child->is_in_class() && child->is_a(ID_Function)) {
- const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
- if (fn->has_signature(rtype, sig))
- return 1;
- }
- }
- return 0;
-}
-
-
-////////////////////////////////////////////////////////////////
-// quick check of any C code for legality, returns an error message
-
-static char buffer[128]; // for error messages
-
-/**
- Check a quoted string contains a character.
- This is used to find a matching " or ' in a string.
- \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
- */
-const char *_q_check(const char * & c, int type) {
- for (;;) switch (*c++) {
- case '\0':
- sprintf(buffer,"missing %c",type);
- return buffer;
- case '\\':
- if (*c) c++;
- break;
- default:
- if (*(c-1) == type) return 0;
- }
-}
-
-/**
- Check normal code, match brackets and parenthesis.
- Recursively run a line of code and make sure that
- {, [, ", ', and ( are matched.
- \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
- */
-const char *_c_check(const char * & c, int type) {
- const char *d;
- for (;;) switch (*c++) {
- case 0:
- if (!type) return 0;
- sprintf(buffer, "missing '%c'", type);
- 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 '*/'";
- }
- }
- break;
-// case '#':
-// // treat cpp directives as a comment:
-// // Matt: a '#' character can appear as a concatenation when defining macros
-// // Matt: so instead we just silently ignore the '#'
-// while (*c != '\n' && *c) c++;
-// break;
- case '{':
- if (type==')') goto UNEXPECTED;
- d = _c_check(c,'}');
- if (d) return d;
- break;
- case '(':
- d = _c_check(c,')');
- if (d) return d;
- break;
- case '[':
- d = _c_check(c,']');
- if (d) return d;
- break;
- case '\"':
- d = _q_check(c,'\"');
- if (d) return d;
- break;
- case '\'':
- d = _q_check(c,'\'');
- if (d) return d;
- break;
- case '}':
- case ')':
- case ']':
- UNEXPECTED:
- if (type == *(c-1)) return 0;
- sprintf(buffer, "unexpected '%c'", *(c-1));
- return buffer;
- }
-}
-
-/**
- Check legality of c code (sort of) and return error:
- Make sure that {, ", ', and ( are matched.
- \param[in] c start searching here
- \param[in] type find this character match (default is 0)
- \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
- (i.e. namespace { ... } ). We should make this option user selectable.
- */
-const char *c_check(const char *c, int type) {
- return _c_check(c,type);
-}
-
-// ---- Fl_Function_Type implementation
-
-/** \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)
-{ }
-
-/**
- Destructor.
- */
-Fl_Function_Type::~Fl_Function_Type() {
- if (return_type) free((void*)return_type);
-}
-
-/**
- Create a new function for the widget tree.
- \param[in] strategy add new function after current or as last child
- \return the new node
- */
-Fl_Type *Fl_Function_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_decl_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- Fl_Function_Type *o = new Fl_Function_Type();
- o->name("make_window()");
- o->return_type = 0;
- o->add(anchor, strategy);
- o->factory = this;
- o->public_ = 1;
- o->cdecl_ = 0;
- return o;
-}
-
-/**
- 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
- */
-void Fl_Function_Type::write_properties(Fd_Project_Writer &f) {
- Fl_Type::write_properties(f);
- switch (public_) {
- case 0: f.write_string("private"); break;
- case 2: f.write_string("protected"); break;
- }
- if (cdecl_) f.write_string("C");
- if (return_type) {
- f.write_string("return_type");
- f.write_word(return_type);
- }
-}
-
-/**
- Read function specific properties fron an .fl file.
- \param[in] c read from this string
- */
-void Fl_Function_Type::read_property(Fd_Project_Reader &f, const char *c) {
- if (!strcmp(c,"private")) {
- public_ = 0;
- } else if (!strcmp(c,"protected")) {
- public_ = 2;
- } else if (!strcmp(c,"C")) {
- cdecl_ = 1;
- } else if (!strcmp(c,"return_type")) {
- storestring(f.read_word(),return_type);
- } else {
- Fl_Type::read_property(f, c);
- }
-}
-
-/**
- Open the function_panel dialog box to edit this function.
- */
-void Fl_Function_Type::open() {
- // fill dialog box
- if (!function_panel) make_function_panel();
- f_return_type_input->value(return_type);
- f_name_input->value(name());
- if (is_in_class()) {
- f_public_member_choice->value(public_);
- f_public_member_choice->show();
- f_public_choice->hide();
- f_c_button->hide();
- } else {
- f_public_choice->value(public_);
- f_public_choice->show();
- f_public_member_choice->hide();
- f_c_button->show();
- }
- f_c_button->value(cdecl_);
- const char *c = comment();
- f_comment_input->buffer()->text(c?c:"");
- function_panel->show();
- const char* message = 0;
- for (;;) { // repeat as long as there are errors
- // - message loop until OK or cancel is pressed
- 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();
- }
- // - check syntax
- const char *c = f_name_input->value();
- while (isspace(*c)) c++;
- 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);
- }
- // - alert user
- if (message) {
- int v = fl_choice("Potential syntax error detected: %s",
- "Continue Editing", "Ignore Error", NULL, message);
- if (v==0) continue; // Continue Editing
- //if (v==1) { } // Ignore Error and close dialog
- }
- // - copy dialog data to target variables
- int mod = 0;
- name(f_name_input->value());
- storestring(f_return_type_input->value(), return_type);
- 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();
- }
- }
- if (cdecl_ != f_c_button->value()) {
- mod = 1;
- cdecl_ = f_c_button->value();
- }
- c = f_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);
- }
- if (c) free((void*)c);
- if (mod) set_modflag(1);
- break;
- }
-BREAK2:
- function_panel->hide();
-}
-
-/**
- Return 1 if the function is global.
- \return 1 if public, 0 if local.
- */
-int Fl_Function_Type::is_public() const {
- return public_;
-}
-
-static bool fd_isspace(int c) {
- return (c>0 && c<128 && isspace(c));
-}
-
-// code duplication: see int is_id(char c) in code.cxx
-static bool fd_iskeyword(int c) {
- return (c>0 && c<128 && (isalnum(c) || c=='_'));
-}
-
-// 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';
-}
-
-
-/**
- Write the code for the source and the header file.
- This writes the code that goes \b before all children of this class.
- \see write_code2(Fd_Code_Writer& f)
- */
-void Fl_Function_Type::write_code1(Fd_Code_Writer& f) {
- constructor=0;
- havewidgets = 0;
- Fl_Type *child;
- // 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;
- if (child->is_widget()) {
- havewidgets = 1;
- break;
- }
- }
- if (havechildren)
- f.write_c("\n");
- if (ismain()) {
- if (havechildren)
- f.write_c("int main(int argc, char **argv) {\n");
- } else {
- const char* rtype = return_type;
- const char* star = "";
- // from matt: let the user type "static " at the start of type
- // in order to declare a static method;
- int is_static = 0;
- int is_virtual = 0;
- if (rtype) {
- if (!strcmp(rtype,"static")) {is_static = 1; rtype = 0;}
- else if (!strncmp(rtype, "static ",7)) {is_static = 1; rtype += 7;}
- }
- if (rtype) {
- if (!strcmp(rtype, "virtual")) {is_virtual = 1; rtype = 0;}
- else if (!strncmp(rtype, "virtual ",8)) {is_virtual = 1; rtype += 8;}
- }
- if (!rtype) {
- if (havewidgets) {
- rtype = subclassname(child);
- star = "*";
- } else rtype = "void";
- }
-
- const char* k = class_name(0);
- if (k) {
- f.write_public(public_);
- if (havechildren)
- write_comment_c(f);
- if (name()[0] == '~')
- constructor = 1;
- else {
- size_t n = strlen(k);
- if (!strncmp(name(), k, n) && name()[n] == '(') constructor = 1;
- }
- f.write_h("%s", f.indent(1));
- if (is_static) f.write_h("static ");
- if (is_virtual) f.write_h("virtual ");
- if (!constructor) {
- f.write_h("%s%s ", rtype, star);
- if (havechildren)
- f.write_c("%s%s ", rtype, star);
- }
-
- // if this is a subclass, only f.write_h() the part before the ':'
- char s[1024], *sptr = s;
- char *nptr = (char *)name();
-
- while (*nptr) {
- if (*nptr == ':') {
- if (nptr[1] != ':') break;
- // Copy extra ":" for "class::member"...
- *sptr++ = *nptr++;
- }
- *sptr++ = *nptr++;
- }
- *sptr = '\0';
-
- if (s[strlen(s)-1] == '}') { // special case for inlined functions
- f.write_h("%s\n", s);
- } else {
- f.write_h("%s;\n", s);
- }
- if (havechildren) {
- clean_function_for_implementation(s, name());
- f.write_c("%s::%s {\n", k, s);
- }
- } else {
- if (havechildren)
- write_comment_c(f);
- if (public_==1) {
- if (cdecl_)
- f.write_h("extern \"C\" { %s%s %s; }\n", rtype, star, name());
- else
- f.write_h("%s%s %s;\n", rtype, star, name());
- } else if (public_==2) {
- // write neither the prototype nor static, the function may be declared elsewhere
- } else {
- if (havechildren)
- f.write_c("static ");
- }
-
- // write everything but the default parameters (if any)
- char s[1024];
- if (havechildren) {
- clean_function_for_implementation(s, name());
- f.write_c("%s%s %s {\n", rtype, star, s);
- }
- }
- }
-
- if (havewidgets && child && !child->name())
- f.write_c("%s%s* w;\n", f.indent(1), subclassname(child));
- f.indentation++;
-}
-
-/**
- Write the code for the source and the header file.
- This writes the code that goes \b after all children of this class.
- \see write_code1(Fd_Code_Writer& f)
- */
-void Fl_Function_Type::write_code2(Fd_Code_Writer& f) {
- Fl_Type *child;
- const char *var = "w";
- char havechildren = 0;
- for (child = next; child && child->level > level; child = child->next) {
- havechildren = 1;
- if (child->is_a(ID_Window) && child->name()) var = child->name();
- }
-
- if (ismain()) {
- if (havewidgets)
- f.write_c("%s%s->show(argc, argv);\n", f.indent(1), var);
- if (havechildren)
- f.write_c("%sreturn Fl::run();\n", f.indent(1));
- } else if (havewidgets && !constructor && !return_type) {
- f.write_c("%sreturn %s;\n", f.indent(1), var);
- }
- if (havechildren)
- f.write_c("}\n");
- f.indentation = 0;
-}
-
-/**
- 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
- */
-int Fl_Function_Type::has_signature(const char *rtype, const char *sig) const {
- if (rtype && !return_type) return 0;
- if (!name()) return 0;
- if ( (rtype==0L || strcmp(return_type, rtype)==0)
- && fl_filename_match(name(), sig)) {
- return 1;
- }
- return 0;
-}
-
-// ---- 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.
- */
-Fl_Code_Type::Fl_Code_Type() :
- cursor_position_(0),
- code_input_scroll_row(0),
- code_input_scroll_col(0)
-{}
-
-/**
- Make a new code node.
- If the parent node is not a function, a message box will pop up and
- the request will be ignored.
- \param[in] strategy add code after current or as last child
- \return new Code node
- */
-Fl_Type *Fl_Code_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_code_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- if (!p) {
- fl_message("Please select a function");
- return 0;
- }
- Fl_Code_Type *o = new Fl_Code_Type();
- o->name("printf(\"Hello, World!\\n\");");
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- Open the code_panel or an external editor to edit this code section.
- */
-void Fl_Code_Type::open() {
- // 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();
- if (!code) code = "";
- if ( editor_.open_editor(cmd, code) == 0 )
- return; // return if editor opened ok, fall thru to built-in if not
- }
- // Use built-in code editor..
- if (!code_panel) make_code_panel();
- const char *text = name();
- code_input->buffer()->text( text ? text : "" );
- code_input->insert_position(cursor_position_);
- code_input->scroll(code_input_scroll_row, code_input_scroll_col);
- 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();
- }
- char*c = code_input->buffer()->text();
- message = c_check(c);
- if (message) {
- int v = fl_choice("Potential syntax error detected: %s",
- "Continue Editing", "Ignore Error", NULL, message);
- if (v==0) continue; // Continue Editing
- //if (v==1) { } // Ignore Error and close dialog
- }
- name(c);
- free(c);
- break;
- }
- cursor_position_ = code_input->insert_position();
- code_input_scroll_row = code_input->scroll_row();
- code_input_scroll_col = code_input->scroll_col();
-BREAK2:
- code_panel->hide();
-}
-
-/**
- Grab changes from an external editor and write this node.
- */
-void Fl_Code_Type::write(Fd_Project_Writer &f) {
- // 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
- }
- Fl_Type::write(f);
-}
-
-/**
- Write the code block with the correct indentation.
- */
-void Fl_Code_Type::write_code1(Fd_Code_Writer& f) {
- // 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
- }
- // Matt: disabled f.tag(FD_TAG_GENERIC, 0);
- f.write_c_indented(name(), 0, '\n');
- // Matt: disabled f.tag(FD_TAG_CODE, get_uid());
-}
-
-/**
- See if external editor is open.
- */
-int Fl_Code_Type::is_editing() {
- return editor_.is_editing();
-}
-
-/**
- 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;
-}
-
-// ---- Fl_CodeBlock_Type implementation
-
-/** \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;
-
-/**
- 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.
- \param[in] strategy add after current or as last child
- \return new CodeBlock
- */
-Fl_Type *Fl_CodeBlock_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_code_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- 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;
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- 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.
- */
-void Fl_CodeBlock_Type::write_properties(Fd_Project_Writer &f) {
- Fl_Type::write_properties(f);
- if (after) {
- f.write_string("after");
- f.write_word(after);
- }
-}
-
-/**
- Read the node specific properties.
- */
-void Fl_CodeBlock_Type::read_property(Fd_Project_Reader &f, const char *c) {
- if (!strcmp(c,"after")) {
- storestring(f.read_word(),after);
- } else {
- Fl_Type::read_property(f, c);
- }
-}
-
-/**
- Open the codeblock_panel.
- */
-void Fl_CodeBlock_Type::open() {
- if (!codeblock_panel) make_codeblock_panel();
- code_before_input->value(name());
- code_after_input->value(after);
- codeblock_panel->show();
- const char* message = 0;
- for (;;) { // repeat as long as there are errors
- // event loop
- 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();
- }
- // 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",
- "Continue Editing", "Ignore Error", NULL, message);
- if (v==0) continue; // Continue Editing
- //if (v==1) { } // Ignore Error and close dialog
- }
- // write to variables
- name(code_before_input->value());
- storestring(code_after_input->value(), after);
- break;
- }
-BREAK2:
- codeblock_panel->hide();
-}
-
-/**
- Write the "before" code.
- */
-void Fl_CodeBlock_Type::write_code1(Fd_Code_Writer& f) {
- const char* c = name();
- f.write_c("%s%s {\n", f.indent(), c ? c : "");
- f.indentation++;
-}
-
-/**
- Write the "after" code.
- */
-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());
-}
-
-// ---- Fl_Decl_Type declaration
-
-/** \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.
- */
-int Fl_Decl_Type::is_public() const
-{
- 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;
-}
-
-/**
- Make a new declaration.
- \param[in] strategy add after current or as last child
- \return new Declaration node
- */
-Fl_Type *Fl_Decl_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_decl_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- Fl_Decl_Type *o = new Fl_Decl_Type();
- o->public_ = 0;
- o->static_ = 1;
- o->name("int x;");
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- Write the specific properties.
- - "private"/"public"/"protected"
- - "local"/"global" if this is static or not
- */
-void Fl_Decl_Type::write_properties(Fd_Project_Writer &f) {
- Fl_Type::write_properties(f);
- switch (public_) {
- case 0: f.write_string("private"); break;
- case 1: f.write_string("public"); break;
- case 2: f.write_string("protected"); break;
- }
- if (static_)
- f.write_string("local");
- else
- f.write_string("global");
-}
-
-/**
- Read the specific properties.
- */
-void Fl_Decl_Type::read_property(Fd_Project_Reader &f, const char *c) {
- if (!strcmp(c,"public")) {
- public_ = 1;
- } else if (!strcmp(c,"private")) {
- public_ = 0;
- } else if (!strcmp(c,"protected")) {
- public_ = 2;
- } else if (!strcmp(c,"local")) {
- static_ = 1;
- } else if (!strcmp(c,"global")) {
- static_ = 0;
- } else {
- Fl_Type::read_property(f, c);
- }
-}
-
-/**
- Open the decl_panel to edit this node.
- */
-void Fl_Decl_Type::open() {
- if (!decl_panel) make_decl_panel();
- decl_input->buffer()->text(name());
- 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();
- }
- const char *c = comment();
- decl_comment_input->buffer()->text(c?c:"");
- decl_panel->show();
- const char* message = 0;
- for (;;) { // repeat as long as there are errors
- // event loop
- 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();
- }
- // check values
- const char*c = decl_input->buffer()->text();
- while (isspace(*c)) c++;
- message = c_check(c&&c[0]=='#' ? c+1 : c);
- // alert user
- if (message) {
- int v = fl_choice("Potential syntax error detected: %s",
- "Continue Editing", "Ignore Error", NULL, message);
- if (v==0) continue; // Continue Editing
- //if (v==1) { } // Ignore Error and close dialog
- }
- // copy vlaues
- name(c);
- 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);
- }
- }
- c = decl_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);
- }
- if (c) free((void*)c);
- break;
- }
-BREAK2:
- decl_panel->hide();
-}
-
-/**
- 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
- and the parent node. They need to be understood and documented.
- */
-void Fl_Decl_Type::write_code1(Fd_Code_Writer& f) {
- const char* c = name();
- if (!c) return;
- // handle a few keywords differently if inside a class
- 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]))
- || (!strncmp(c,"enum",4) && isspace(c[4]))
- ) ) {
- f.write_public(public_);
- write_comment_h(f, f.indent(1));
- f.write_h("%s%s\n", f.indent(1), c);
- return;
- }
- // handle putting #include, extern, using or typedef into decl:
- 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]))
- // || !strncmp(c,"struct",6) && isspace(c[6])
- ) {
- if (public_) {
- write_comment_h(f);
- f.write_h("%s\n", c);
- } else {
- write_comment_c(f);
- f.write_c("%s\n", c);
- }
- return;
- }
- // 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
- // lose spaces between text and comment, if any
- while (e>c && e[-1]==' ') e--;
- if (class_name(1)) {
- f.write_public(public_);
- write_comment_h(f, f.indent(1));
- f.write_hc(f.indent(1), int(e-c), c, csc);
- } else {
- if (public_) {
- if (static_)
- f.write_h("extern ");
- else
- write_comment_h(f);
- f.write_hc("", int(e-c), c, csc);
-
- if (static_) {
- write_comment_c(f);
- f.write_cc("", int(e-c), c, csc);
- }
- } else {
- write_comment_c(f);
- if (static_)
- f.write_c("static ");
- f.write_cc("", int(e-c), c, csc);
- }
- }
-}
-
-// ---- Fl_Data_Type declaration
-
-/** \class Fl_Data_Type
- Manage data from an external arbitrary file.
-
- 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.
- \param[in] strategy add after current or as last child
- \return new inline data node
- */
-Fl_Type *Fl_Data_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_decl_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- Fl_Data_Type *o = new Fl_Data_Type();
- o->public_ = 1;
- o->static_ = 1;
- o->filename_ = 0;
- o->text_mode_ = 0;
- o->name("myInlineData");
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- Write additional properties.
- - "filename" followed by the filename of the file to inline
- - "textmode" if data is written in ASCII vs. binary
- */
-void Fl_Data_Type::write_properties(Fd_Project_Writer &f) {
- Fl_Decl_Type::write_properties(f);
- if (filename_) {
- f.write_string("filename");
- f.write_word(filename_);
- }
- if (text_mode_ == 1) {
- f.write_string("textmode");
- }
- if (text_mode_ == 2) {
- f.write_string("compressed");
- }
-}
-
-/**
- Read specific properties.
- */
-void Fl_Data_Type::read_property(Fd_Project_Reader &f, const char *c) {
- if (!strcmp(c,"filename")) {
- storestring(f.read_word(), filename_, 1);
- } else if (!strcmp(c,"textmode")) {
- text_mode_ = 1;
- } else if (!strcmp(c,"compressed")) {
- text_mode_ = 2;
- } else {
- Fl_Decl_Type::read_property(f, c);
- }
-}
-
-/**
- Open the data_panel to edit this node.
- */
-void Fl_Data_Type::open() {
- if (!data_panel) make_data_panel();
- data_input->value(name());
- 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();
- }
- data_mode->value(text_mode_);
- 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) {
- enter_project_dir();
- const char *fn = fl_file_chooser("Load Inline Data", 0L, data_filename->value(), 1);
- leave_project_dir();
- if (fn) {
- if (strcmp(fn, data_filename->value()))
- set_modflag(1);
- data_filename->value(fn);
- }
- }
- else if (!w) Fl::wait();
- }
- // store the variable name:
- const char*c = data_input->value();
- char *s = fl_strdup(c), *p = s, *q, *n;
- for (;;++p) { // remove leading spaces
- 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;
- }
- *p = 0; // remove trailing spaces
- if (n==q) {
- OOPS:
- int v = fl_choice("%s",
- "Continue Editing", "Ignore Error", NULL,
- "Variable name must be a C identifier");
- if (v==0) { free(s); continue; } // Continue Editing
- //if (v==1) { } // Ignore Error and close dialog
- }
- undo_checkpoint();
- 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);
- }
- }
- text_mode_ = data_mode->value();
- if (text_mode_ < 0) text_mode_ = 0;
- if (text_mode_ > 2) text_mode_ = 2;
- // store the filename
- c = data_filename->value();
- if (filename_ && strcmp(filename_, data_filename->value()))
- set_modflag(1);
- else if (!filename_ && *c)
- set_modflag(1);
- if (filename_) { free((void*)filename_); filename_ = 0L; }
- if (c && *c) filename_ = fl_strdup(c);
- // store the comment
- c = data_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);
- }
- if (c) free((void*)c);
- set_modflag(1);
- break;
- }
-BREAK2:
- data_panel->hide();
-}
-
-/**
- Write the content of the external file inline into the source code.
- */
-void Fl_Data_Type::write_code1(Fd_Code_Writer& f) {
- const char *message = 0;
- const char *c = name();
- if (!c) return;
- const char *fn = filename_;
- char *data = 0;
- int nData = -1;
- int uncompressedDataSize = 0;
- // path should be set correctly already
- if (filename_ && !f.write_codeview) {
- enter_project_dir();
- FILE *f = fl_fopen(filename_, "rb");
- leave_project_dir();
- if (!f) {
- message = "Can't include data from file. Can't open";
- } else {
- fseek(f, 0, SEEK_END);
- nData = (int)ftell(f);
- fseek(f, 0, SEEK_SET);
- if (nData) {
- data = (char*)calloc(nData, 1);
- if (fread(data, nData, 1, f)==0) { /* use default */ }
- 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;
- }
- }
- fclose(f);
- }
- } else {
- fn = filename_ ? filename_ : "<no filename>";
- }
- if (is_in_class()) {
- f.write_public(public_);
- if (text_mode_ == 1) {
- 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);
- } 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);
- } else {
- 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);
- }
- f.write_c(";\n");
- } else {
- // the "header only" option does not apply here!
- if (public_) {
- if (static_) {
- if (text_mode_ == 1) {
- 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);
- } 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);
- } else {
- 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);
- }
- f.write_c(";\n");
- } else {
- write_comment_h(f);
- f.write_h("#error Unsupported declaration loading inline data %s\n", fn);
- if (text_mode_ == 1)
- f.write_h("const char *%s = \"abc...\";\n", c);
- else
- f.write_h("unsigned char %s[3] = { 1, 2, 3 };\n", c);
- }
- } else {
- f.write_c("\n");
- write_comment_c(f);
- if (static_)
- f.write_c("static ");
- if (text_mode_ == 1) {
- 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);
- } 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);
- } else {
- 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);
- }
- f.write_c(";\n");
- }
- }
- // if we are in interactive mode, we pop up a warning dialog
- // giving the error: (batch_mode && !write_codeview) ???
- if (message && !f.write_codeview) {
- if (batch_mode)
- fprintf(stderr, "FLUID ERROR: %s %s\n", message, fn);
- else
- fl_alert("%s\n%s\n", message, fn);
- }
- if (data) free(data);
-}
-
-// ---- Fl_DeclBlock_Type declaration
-
-/** \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.
- */
-
-/// 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(),
- after(NULL),
- write_map_(CODE_IN_SOURCE)
-{ }
-
-/**
- Destructor.
- */
-Fl_DeclBlock_Type::~Fl_DeclBlock_Type() {
- if (after)
- ::free((void*)after);
-}
-
-/**
- Return 1 if this block is public.
- */
-int Fl_DeclBlock_Type::is_public() const {
- return ((write_map_&CODE_IN_HEADER) != 0);
-}
-
-/**
- Create a new declaration block.
- \param[in] strategy add after current or as last child
- \return new Declaration Block node
- */
-Fl_Type *Fl_DeclBlock_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT)) p = p->parent;
- while (p && !p->is_decl_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- Fl_DeclBlock_Type *o = new Fl_DeclBlock_Type();
- o->name("#if 1");
- o->write_map_ = CODE_IN_SOURCE;
- o->after = fl_strdup("#endif");
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- Write the specific properties.
- - "public"/"protected"
- - "after" followed by the second code block.
- */
-void Fl_DeclBlock_Type::write_properties(Fd_Project_Writer &f) {
- Fl_Type::write_properties(f);
- // 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_);
- f.write_string("after");
- f.write_word(after);
-}
-
-/**
- Read the specific properties.
- */
-void Fl_DeclBlock_Type::read_property(Fd_Project_Reader &f, const char *c) {
- if(!strcmp(c,"public")) {
- write_map_ |= CODE_IN_HEADER;
- } else if(!strcmp(c,"protected")) {
- //
- } else if(!strcmp(c,"map")) {
- write_map_ = (int)atol(f.read_word());
- } else if (!strcmp(c,"after")) {
- storestring(f.read_word(),after);
- } else {
- Fl_Type::read_property(f, c);
- }
-}
-
-/**
- Open the declblock_panel to edit this node.
- */
-void Fl_DeclBlock_Type::open() {
- // build dialog box
- if (!declblock_panel) make_declblock_panel();
- // 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
- 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();
- }
- // verify user input
- const char* a = declblock_before_input->value();
- while (isspace(*a)) a++;
- const char* b = declblock_after_input->value();
- 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) {
- int v = fl_choice("Potential syntax error detected: %s",
- "Continue Editing", "Ignore Error", NULL, message);
- if (v==0) continue; // Continue Editing
- //if (v==1) { } // Ignore Error and close dialog
- }
- // store user choices in data structure
- name(a);
- storestring(b, after);
- 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);
- }
- if (c) free((void*)c);
- break;
- }
-BREAK2:
- declblock_panel->hide();
-}
-
-/**
- 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);
- }
-}
-
-/**
- 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.
- */
-void Fl_DeclBlock_Type::write_code1(Fd_Code_Writer& f) {
- const char* c = name();
- if (c && *c) {
- if (write_map_ & CODE_IN_HEADER)
- f.write_h("%s\n", c);
- if (write_map_ & CODE_IN_SOURCE)
- f.write_c("%s\n", c);
- }
-}
-
-/**
- Write the \b after code to the source file, and to the header file if declared public.
- */
-void Fl_DeclBlock_Type::write_code2(Fd_Code_Writer& f) {
- const char* c = after;
- if (c && *c) {
- if (write_map_ & CODE_IN_HEADER)
- f.write_h("%s\n", c);
- if (write_map_ & CODE_IN_SOURCE)
- f.write_c("%s\n", c);
- }
-}
-
-// ---- 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 "// ".
- */
-
-/// 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.
- \param[in] strategy add after current or as last child
- \return new Comment node
- */
-Fl_Type *Fl_Comment_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_code_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- Fl_Comment_Type *o = new Fl_Comment_Type();
- o->in_c_ = 1;
- o->in_h_ = 1;
- o->style_ = 0;
- o->name("my comment");
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- 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
- */
-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");
-}
-
-/**
- Read extra properties.
- */
-void Fl_Comment_Type::read_property(Fd_Project_Reader &f, const char *c) {
- 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 {
- Fl_Type::read_property(f, c);
- }
-}
-
-/**
- Load available preset comments.
- Fluid comes with GPL and LGPL preset for comments. Users can
- add their own presets which are stored per user in a separate
- preferences database.
- */
-static void load_comments_preset(Fl_Preferences &menu) {
- static const char * const predefined_comment[] = {
- "GNU Public License v3/GPL Header", "GNU Public License v3/GPL Footer",
- "GNU Public License v3/LGPL Header", "GNU Public License v3/LGPL Footer",
- "FLTK/Header" };
- int i, n;
- menu.get("n", n, -1);
- if (n == -1) menu.set("n", 5);
- menu.set("version", 10400);
- Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
- for (i=0; i<5; i++) {
- menu.set(Fl_Preferences::Name(i), predefined_comment[i]);
- db.set(predefined_comment[i], comment_text[i]);
- }
-}
-
-/**
- Open the comment_panel to edit this node.
- */
-void Fl_Comment_Type::open() {
- if (!comment_panel) make_comment_panel();
- const char *text = name();
- {
- int i=0, n=0, version = 0;
- Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
- comment_predefined->clear();
- comment_predefined->add("_Edit/Add current comment...");
- comment_predefined->add("_Edit/Remove last selection...");
- menu.get("version", version, -1);
- if (version < 10400) load_comments_preset(menu);
- 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();
- char itempath[FL_PATH_MAX]; itempath[0] = 0;
- 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(
- "Please enter a name to reference the current\ncomment in your database.\n\n"
- "Use forward slashes '/' to create submenus.",
- "My Comment");
- if (xname) {
- char *name = fl_strdup(xname);
- for (char*s=name;*s;s++) if (*s==':') *s = ';';
- int n;
- Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
- db.set(name, comment_input->buffer()->text());
- Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
- 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) {
- fl_message("Please select an entry from this menu first.");
- } else if (fl_choice("Are you sure that you want to delete the entry\n"
- "\"%s\"\nfrom the database?", "Cancel", "Delete",
- NULL, itempath)) {
- Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
- db.deleteEntry(itempath);
- comment_predefined->remove(last_selected_item);
- Fl_Preferences menu(Fl_Preferences::USER_L, "fltk.org", "fluid_comments_menu");
- int i, n;
- for (i=4, n=0; i<comment_predefined->size(); i++) {
- 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);
- Fl_Preferences db(Fl_Preferences::USER_L, "fltk.org", "fluid_comments");
- char *text;
- 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
- fl_file_chooser_ok_label("Use File");
- const char *fname = fl_file_chooser("Pick a comment", 0L, 0L);
- fl_file_chooser_ok_label(NULL);
- 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);
- 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);
- break;
- }
-BREAK2:
- comment_panel->hide();
-}
-
-/**
- Write the comment to the files.
- */
-void Fl_Comment_Type::write_code1(Fd_Code_Writer& f) {
- 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]=='*') {
- if (in_h_) f.write_h("%s\n", c);
- if (in_c_) f.write_c("%s\n", c);
- return;
- }
- // copy the comment line by line, add the double slash if needed
- char *txt = fl_strdup(c);
- 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
- if (in_h_) f.write_h("// ");
- if (in_c_) f.write_c("// ");
- }
- // now copy the rest of the line
- if (in_h_) f.write_h("%s\n", b);
- if (in_c_) f.write_c("%s\n", b);
- if (eol==0) break;
- *e++ = eol;
- b = e;
- }
- free(txt);
-}
-
-// ---- Fl_Class_Type declaration
-
-/** \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;
-
-/**
- Constructor.
- */
-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);
-}
-
-/**
- Return 1 if this class is marked public.
- */
-int Fl_Class_Type::is_public() const {
- return public_;
-}
-
-/**
- Set the prefixx string.
- */
-void Fl_Class_Type::prefix(const char*p) {
- free((void*) class_prefix);
- class_prefix=fl_strdup(p ? p : "" );
-}
-
-/**
- Make a new class node.
- \param[in] strategy add after current or as last child
- \return new Class node
- */
-Fl_Type *Fl_Class_Type::make(Strategy strategy) {
- Fl_Type *anchor = Fl_Type::current, *p = anchor;
- if (p && (strategy.placement() == Strategy::AFTER_CURRENT))
- p = p->parent;
- while (p && !p->is_decl_block()) {
- anchor = p;
- strategy.placement(Strategy::AFTER_CURRENT);
- p = p->parent;
- }
- Fl_Class_Type *o = new Fl_Class_Type();
- o->name("UserInterface");
- o->class_prefix = NULL;
- o->subclass_of = NULL;
- o->public_ = 1;
- o->add(anchor, strategy);
- o->factory = this;
- return o;
-}
-
-/**
- Write the respective properties.
- - ":" followed by the super class
- - "private"/"protected"
- */
-void Fl_Class_Type::write_properties(Fd_Project_Writer &f) {
- Fl_Type::write_properties(f);
- if (subclass_of) {
- f.write_string(":");
- f.write_word(subclass_of);
- }
- switch (public_) {
- case 0: f.write_string("private"); break;
- case 2: f.write_string("protected"); break;
- }
-}
-
-/**
- Read additional properties.
- */
-void Fl_Class_Type::read_property(Fd_Project_Reader &f, const char *c) {
- if (!strcmp(c,"private")) {
- public_ = 0;
- } else if (!strcmp(c,"protected")) {
- public_ = 2;
- } else if (!strcmp(c,":")) {
- storestring(f.read_word(), subclass_of);
- } else {
- Fl_Type::read_property(f, c);
- }
-}
-
-/**
- Open the class_panel to edit the class name and superclass name.
- */
-void Fl_Class_Type::open() {
- if (!class_panel) make_class_panel();
- char fullname[FL_PATH_MAX]="";
- if (prefix() && strlen(prefix()))
- sprintf(fullname,"%s %s",prefix(),name());
- else
- strcpy(fullname, name());
- c_name_input->value(fullname);
- c_subclass_input->value(subclass_of);
- c_public_button->value(public_);
- const char *c = comment();
- c_comment_input->buffer()->text(c?c:"");
- class_panel->show();
- const char* message = 0;
-
- char *na=0,*pr=0,*p=0; // name and prefix substrings
-
- for (;;) { // repeat as long as there are errors
- // we don;t give the option to ignore this error here because code depends
- // on this being a C++ identifier
- if (message) fl_alert("%s", message);
- 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();
- char *s = fl_strdup(c);
- 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) ) {
- OOPS: message = "class name must be C++ identifier";
- 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
- c = c_subclass_input->value();
- message = c_check(c);
- if (message) { free((void*)s);continue;}
- name(na);
- prefix(pr);
- free((void*)s);
- storestring(c, subclass_of);
- if (public_ != c_public_button->value()) {
- public_ = c_public_button->value();
- set_modflag(1);
- }
- c = c_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);
- }
- if (c) free((void*)c);
- break;
- }
-BREAK2:
- class_panel->hide();
-}
-
-/**
- Write the header code that declares this class.
- */
-void Fl_Class_Type::write_code1(Fd_Code_Writer& f) {
- parent_class = current_class;
- current_class = this;
- write_public_state = 0;
- f.write_h("\n");
- write_comment_h(f);
- if (prefix() && strlen(prefix()))
- f.write_h("class %s %s ", prefix(), name());
- else
- f.write_h("class %s ", name());
- if (subclass_of) f.write_h(": %s ", subclass_of);
- f.write_h("{\n");
-}
-
-/**
- Write the header code that ends the declaration of this class.
- */
-void Fl_Class_Type::write_code2(Fd_Code_Writer& f) {
- f.write_h("};\n");
- current_class = parent_class;
-}
-
-/**
- Return 1 if this class contains a function with the given signature.
- */
-int Fl_Type::has_function(const char *rtype, const char *sig) const {
- Fl_Type *child;
- for (child = next; child && child->level > level; child = child->next) {
- if (child->level == level+1 && child->is_a(ID_Function)) {
- const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
- if (fn->has_signature(rtype, sig))
- return 1;
- }
- }
- return 0;
-}