summaryrefslogtreecommitdiff
path: root/fluid
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2005-11-03 20:43:19 +0000
committerMatthias Melcher <fltk@matthiasm.com>2005-11-03 20:43:19 +0000
commit1a5288e8feb3673fa864d4aa4e4c09c9577a0670 (patch)
treea23a587c1f13fcc490ae35e57dc0735007d9ee01 /fluid
parent5cdf984737d7a7f55006e3ca04f28451dfe2099c (diff)
Fluid Source Code preview panel with automatic refresh and selected object code highlighting.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4630 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'fluid')
-rw-r--r--fluid/CodeEditor.h1
-rw-r--r--fluid/Fl_Type.cxx2
-rw-r--r--fluid/Fl_Type.h4
-rw-r--r--fluid/Fl_Widget_Type.cxx3
-rw-r--r--fluid/code.cxx56
-rw-r--r--fluid/fluid.cxx150
-rw-r--r--fluid/function_panel.cxx87
-rw-r--r--fluid/function_panel.fl67
-rw-r--r--fluid/function_panel.h12
9 files changed, 372 insertions, 10 deletions
diff --git a/fluid/CodeEditor.h b/fluid/CodeEditor.h
index 4b646849b..04c51bd09 100644
--- a/fluid/CodeEditor.h
+++ b/fluid/CodeEditor.h
@@ -67,6 +67,7 @@ class CodeEditor : public Fl_Text_Editor {
CodeEditor(int X, int Y, int W, int H, const char *L=0);
~CodeEditor();
+ int top_line() { return get_absolute_top_line_number(); }
};
#endif // !CodeEditor_h
diff --git a/fluid/Fl_Type.cxx b/fluid/Fl_Type.cxx
index 222444cd5..92e1c807c 100644
--- a/fluid/Fl_Type.cxx
+++ b/fluid/Fl_Type.cxx
@@ -436,6 +436,8 @@ Fl_Type::Fl_Type() {
callback_ = 0;
rtti = 0;
level = 0;
+ code_line = header_line = -1;
+ code_line_end = header_line_end = -1;
}
static void fixvisible(Fl_Type *p) {
diff --git a/fluid/Fl_Type.h b/fluid/Fl_Type.h
index e76368c08..18f6f5303 100644
--- a/fluid/Fl_Type.h
+++ b/fluid/Fl_Type.h
@@ -72,6 +72,9 @@ public: // things that should not be public:
Fl_Type *factory;
const char *callback_name();
+ int code_line, header_line;
+ int code_line_end, header_line_end;
+
public:
virtual ~Fl_Type();
@@ -737,6 +740,7 @@ void write_indent(int n);
void write_open(int);
void write_close(int n);
extern int write_number;
+extern int write_sourceview;
void write_public(int state); // writes pubic:/private: as needed
extern int indentation;
extern const char* indent();
diff --git a/fluid/Fl_Widget_Type.cxx b/fluid/Fl_Widget_Type.cxx
index 19bf16926..accaa3a2a 100644
--- a/fluid/Fl_Widget_Type.cxx
+++ b/fluid/Fl_Widget_Type.cxx
@@ -1710,6 +1710,7 @@ Fl_Type *Fl_Type::current;
extern void redraw_overlays();
extern void redraw_browser();
+extern void update_sourceview_position();
// Called when ui changes what objects are selected:
// p is selected object, null for all deletions (we must throw away
@@ -1742,6 +1743,8 @@ void selection_changed(Fl_Type *p) {
redraw_overlays();
// load the panel with the new settings:
load_panel();
+ // update the source viewer to show the code for the selected object
+ update_sourceview_position();
}
////////////////////////////////////////////////////////////////
diff --git a/fluid/code.cxx b/fluid/code.cxx
index d50f37fd9..25f68fc45 100644
--- a/fluid/code.cxx
+++ b/fluid/code.cxx
@@ -263,13 +263,21 @@ void write_h(const char* format,...) {
#include <FL/filename.H>
int write_number;
+int write_sourceview;
// recursively dump code, putting children between the two parts
// of the parent code:
static Fl_Type* write_code(Fl_Type* p) {
- // don't write the last comment until the very end
+ if (write_sourceview) {
+ p->code_line = (int)ftell(code_file);
+ if (p->header_line_end==-1)
+ p->header_line = (int)ftell(header_file);
+ }
+ // write all code that come before the children code
+ // (but don't write the last comment until the very end)
if (!(p==Fl_Type::last && p->is_comment()))
p->write_code1();
+ // recursively write the code of all children
Fl_Type* q;
if (p->is_widget() && p->is_class()) {
// Handle widget classes specially
@@ -283,6 +291,7 @@ static Fl_Type* write_code(Fl_Type* p) {
}
}
+ // write all code that come after the children
p->write_code2();
for (q = p->next; q && q->level > p->level;) {
@@ -298,27 +307,35 @@ static Fl_Type* write_code(Fl_Type* p) {
write_h("};\n");
} else {
for (q = p->next; q && q->level > p->level;) q = write_code(q);
-
+ // write all code that come after the children
p->write_code2();
}
+ if (write_sourceview) {
+ p->code_line_end = (int)ftell(code_file);
+ if (p->header_line_end==-1)
+ p->header_line_end = (int)ftell(header_file);
+ }
return q;
}
extern const char* header_file_name;
int write_code(const char *s, const char *t) {
+ const char *filemode = "w";
+ if (write_sourceview)
+ filemode = "wb";
write_number++;
delete id_root; id_root = 0;
indentation = 0;
if (!s) code_file = stdout;
else {
- FILE *f = fopen(s,"w");
+ FILE *f = fopen(s, filemode);
if (!f) return 0;
code_file = f;
}
if (!t) header_file = stdout;
else {
- FILE *f = fopen(t,"w");
+ FILE *f = fopen(t, filemode);
if (!f) {fclose(code_file); return 0;}
header_file = f;
}
@@ -326,8 +343,16 @@ int write_code(const char *s, const char *t) {
// a copyright notice. We print that before anything else in the file!
Fl_Type* first_type = Fl_Type::first;
if (first_type && first_type->is_comment()) {
- // this is ok, because comments have no children or code2 blocks
+ if (write_sourceview) {
+ first_type->code_line = (int)ftell(code_file);
+ first_type->header_line = (int)ftell(header_file);
+ }
+ // it is ok to write non-recusive code here, because comments have no children or code2 blocks
first_type->write_code1();
+ if (write_sourceview) {
+ first_type->code_line_end = (int)ftell(code_file);
+ first_type->header_line_end = (int)ftell(header_file);
+ }
first_type = first_type->next;
}
@@ -373,9 +398,20 @@ int write_code(const char *s, const char *t) {
}
for (Fl_Type* p = first_type; p;) {
// write all static data for this & all children first
+ if (write_sourceview) p->header_line = (int)ftell(header_file);
p->write_static();
- for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next)
+ if (write_sourceview) {
+ p->header_line_end = (int)ftell(header_file);
+ if (p->header_line==p->header_line_end) p->header_line_end = -1;
+ }
+ for (Fl_Type* q = p->next; q && q->level > p->level; q = q->next) {
+ if (write_sourceview) q->header_line = (int)ftell(header_file);
q->write_static();
+ if (write_sourceview) {
+ q->header_line_end = (int)ftell(header_file);
+ if (q->header_line==q->header_line_end) q->header_line_end = -1;
+ }
+ }
// then write the nested code:
p = write_code(p);
}
@@ -388,7 +424,15 @@ int write_code(const char *s, const char *t) {
Fl_Type* last_type = Fl_Type::last;
if (last_type && last_type->is_comment()) {
+ if (write_sourceview) {
+ last_type->code_line = (int)ftell(code_file);
+ last_type->header_line = (int)ftell(header_file);
+ }
last_type->write_code1();
+ if (write_sourceview) {
+ last_type->code_line_end = (int)ftell(code_file);
+ last_type->header_line_end = (int)ftell(header_file);
+ }
}
int x = fclose(code_file);
diff --git a/fluid/fluid.cxx b/fluid/fluid.cxx
index 789d1bac0..cf52c3260 100644
--- a/fluid/fluid.cxx
+++ b/fluid/fluid.cxx
@@ -381,6 +381,14 @@ void exit_cb(Fl_Widget *,void *) {
save_position(widgetbin_panel,"widgetbin_pos");
delete widgetbin_panel;
}
+ if (sourceview_panel) {
+ Fl_Preferences svp(fluid_prefs, "sourceview");
+ svp.set("autorefresh", sv_autorefresh->value());
+ svp.set("autoposition", sv_autoposition->value());
+ svp.set("tab", sv_tab->find(sv_tab->value()));
+ save_position(sourceview_panel,"sourceview_pos");
+ delete sourceview_panel;
+ }
if (about_panel)
delete about_panel;
if (help_dialog)
@@ -1550,6 +1558,7 @@ void print_cb(Fl_Return_Button *, void *) {
extern Fl_Menu_Item New_Menu[];
void toggle_widgetbin_cb(Fl_Widget *, void *);
+void toggle_sourceview_cb(Fl_Double_Window *, void *);
Fl_Menu_Item Main_Menu[] = {
{"&File",0,0,0,FL_SUBMENU},
@@ -1596,7 +1605,9 @@ Fl_Menu_Item Main_Menu[] = {
{"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER},
{"Hide O&verlays",FL_CTRL+FL_SHIFT+'o',toggle_overlays},
#define WIDGETBIN_ITEM 41
- {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb, 0, FL_MENU_DIVIDER},
+ {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb},
+#define SOURCEVIEW_ITEM 42
+ {"Show Source Code...",FL_ALT+FL_SHIFT+'s', (Fl_Callback*)toggle_sourceview_cb, 0, FL_MENU_DIVIDER},
{"Pro&ject Settings...",FL_ALT+'p',show_project_cb},
{"GU&I Settings...",FL_ALT+FL_SHIFT+'p',show_settings_cb},
{0},
@@ -1688,6 +1699,37 @@ void toggle_widgetbin_cb(Fl_Widget *, void *) {
}
+void toggle_sourceview_cb(Fl_Double_Window *, void *) {
+ if (!sourceview_panel) {
+ make_sourceview();
+ sourceview_panel->callback((Fl_Callback*)toggle_sourceview_cb);
+ Fl_Preferences svp(fluid_prefs, "sourceview");
+ int autorefresh;
+ svp.get("autorefresh", autorefresh, 1);
+ sv_autorefresh->value(autorefresh);
+ int autoposition;
+ svp.get("autoposition", autoposition, 1);
+ sv_autoposition->value(autoposition);
+ int tab;
+ svp.get("tab", tab, 0);
+ if (tab>=0 && tab<sv_tab->children()) sv_tab->value(sv_tab->child(tab));
+ if (!position_window(sourceview_panel,"sourceview_pos", 0, 320, 120, 550, 500)) return;
+ }
+
+ if (sourceview_panel->visible()) {
+ sourceview_panel->hide();
+ Main_Menu[SOURCEVIEW_ITEM].label("Show Source Code...");
+ } else {
+ sourceview_panel->show();
+ Main_Menu[SOURCEVIEW_ITEM].label("Hide Source Code...");
+ update_sourceview_cb(0,0);
+ }
+}
+
+void toggle_sourceview_b_cb(Fl_Button*, void *) {
+ toggle_sourceview_cb(0,0);
+}
+
void make_main_window() {
fluid_prefs.get("snap", snap, 1);
fluid_prefs.get("gridx", gridx, 5);
@@ -1933,6 +1975,102 @@ void set_filename(const char *c) {
set_modflag(modflag);
}
+//
+// The Source View system offers an immediate preview of the code
+// files that will be generated by FLUID. It also marks the code
+// generated for the last selected item in the header and the source
+// file.
+//
+// Can we patent this? ;-) - Matt, mm@matthiasm.com
+//
+
+//
+// Update the header and source code highlighting depending on the
+// currently selected object
+//
+void update_sourceview_position()
+{
+ if (sv_autoposition->value()==0)
+ return;
+ if (sourceview_panel && sourceview_panel->visible() && Fl_Type::current) {
+ int pos0, pos1;
+ if (sv_source->visible_r()) {
+ pos0 = Fl_Type::current->code_line;
+ pos1 = Fl_Type::current->code_line_end;
+ if (pos0>=0) {
+ if (pos1<pos0)
+ pos1 = pos0;
+ sv_source->buffer()->highlight(pos0, pos1);
+ int line = sv_source->buffer()->count_lines(0, pos0);
+ sv_source->scroll(line, 0);
+ }
+ }
+ if (sv_header->visible_r()) {
+ pos0 = Fl_Type::current->header_line;
+ pos1 = Fl_Type::current->header_line_end;
+ if (pos0>=0) {
+ if (pos1<pos0)
+ pos1 = pos0;
+ sv_header->buffer()->highlight(pos0, pos1);
+ int line = sv_header->buffer()->count_lines(0, pos0);
+ sv_header->scroll(line, 0);
+ }
+ }
+ }
+}
+
+void update_sourceview_position_cb(Fl_Tabs*, void*)
+{
+ update_sourceview_position();
+}
+
+static char *sv_source_filename = 0;
+static char *sv_header_filename = 0;
+
+//
+// Generate a header and source file in a temporary directory and
+// load those into the Code Viewer widgets.
+//
+void update_sourceview_cb(Fl_Button*, void*)
+{
+ // generate space for the source and header file filenames
+ if (!sv_source_filename) {
+ sv_source_filename = (char*)malloc(FL_PATH_MAX);
+ fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX);
+ strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX);
+ }
+ if (!sv_header_filename) {
+ sv_header_filename = (char*)malloc(FL_PATH_MAX);
+ fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX);
+ strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX);
+ }
+ // generate the code and load the files
+ if (sourceview_panel && sourceview_panel->visible())
+ {
+ write_sourceview = 1;
+ // generate files
+ if (write_code(sv_source_filename, sv_header_filename))
+ {
+ // load file into source editor
+ int pos = sv_source->top_line();
+ sv_source->buffer()->loadfile(sv_source_filename);
+ sv_source->scroll(pos, 0);
+ // load file into header editor
+ pos = sv_header->top_line();
+ sv_header->buffer()->loadfile(sv_header_filename);
+ sv_header->scroll(pos, 0);
+ // update the source code highlighting
+ update_sourceview_position();
+ }
+ write_sourceview = 0;
+ }
+}
+
+void update_sourceview_timer(void*)
+{
+ update_sourceview_cb(0,0);
+}
+
// Set the "modified" flag and update the title of the main window...
void set_modflag(int mf) {
const char *basename;
@@ -1953,6 +2091,15 @@ void set_modflag(int mf) {
main_window->label(title);
} else main_window->label(basename);
}
+ // if the UI was modified in any way, update the Source View panel
+ if (sourceview_panel && sourceview_panel->visible() && sv_autorefresh->value())
+ {
+ // we will only update ealiest 0.5 seconds after the last change, and only
+ // if no other change was made, so dragging a widget will not generate any
+ // CPU load
+ Fl::remove_timeout(update_sourceview_timer, 0);
+ Fl::add_timeout(0.5, update_sourceview_timer, 0);
+ }
// Enable/disable the Save menu item...
if (modflag) Main_Menu[SAVE_ITEM].activate();
@@ -2030,6 +2177,7 @@ int main(int argc,char **argv) {
position_window(main_window,"main_window_pos", 1, 10, 30, WINWIDTH, WINHEIGHT );
main_window->show(argc,argv);
toggle_widgetbin_cb(0,0);
+ toggle_sourceview_cb(0,0);
if (!c && openlast_button->value() && absolute_history[0][0]) {
// Open previous file when no file specified...
open_history_cb(0, absolute_history[0]);
diff --git a/fluid/function_panel.cxx b/fluid/function_panel.cxx
index 04c1461b1..2cc95cad1 100644
--- a/fluid/function_panel.cxx
+++ b/fluid/function_panel.cxx
@@ -839,6 +839,93 @@ Fl_Window* make_widgetbin() {
return w;
}
+Fl_Double_Window *sourceview_panel=(Fl_Double_Window *)0;
+
+Fl_Tabs *sv_tab=(Fl_Tabs *)0;
+
+CodeEditor *sv_source=(CodeEditor *)0;
+
+CodeEditor *sv_header=(CodeEditor *)0;
+
+Fl_Light_Button *sv_autorefresh=(Fl_Light_Button *)0;
+
+Fl_Light_Button *sv_autoposition=(Fl_Light_Button *)0;
+
+Fl_Double_Window* make_sourceview() {
+ Fl_Double_Window* w;
+ { Fl_Double_Window* o = sourceview_panel = new Fl_Double_Window(544, 500, "Code View");
+ w = o;
+ o->callback((Fl_Callback*)toggle_sourceview_cb);
+ { Fl_Tabs* o = sv_tab = new Fl_Tabs(20, 10, 500, 440);
+ o->callback((Fl_Callback*)update_sourceview_position_cb);
+ { Fl_Group* o = new Fl_Group(20, 35, 500, 415, "Source");
+ o->labelsize(13);
+ { CodeEditor* o = sv_source = new CodeEditor(25, 40, 490, 405);
+ o->box(FL_DOWN_FRAME);
+ o->color(FL_BACKGROUND2_COLOR);
+ o->selection_color(FL_SELECTION_COLOR);
+ o->labeltype(FL_NORMAL_LABEL);
+ o->labelfont(0);
+ o->labelsize(14);
+ o->labelcolor(FL_FOREGROUND_COLOR);
+ o->textfont(4);
+ o->textsize(11);
+ o->align(FL_ALIGN_TOP);
+ o->when(FL_WHEN_RELEASE);
+ Fl_Group::current()->resizable(o);
+ }
+ o->end();
+ Fl_Group::current()->resizable(o);
+ }
+ { Fl_Group* o = new Fl_Group(20, 35, 500, 415, "Header");
+ o->labelsize(13);
+ o->hide();
+ { CodeEditor* o = sv_header = new CodeEditor(25, 40, 490, 405);
+ o->box(FL_DOWN_FRAME);
+ o->color(FL_BACKGROUND2_COLOR);
+ o->selection_color(FL_SELECTION_COLOR);
+ o->labeltype(FL_NORMAL_LABEL);
+ o->labelfont(0);
+ o->labelsize(14);
+ o->labelcolor(FL_FOREGROUND_COLOR);
+ o->textfont(4);
+ o->textsize(11);
+ o->align(FL_ALIGN_TOP);
+ o->when(FL_WHEN_RELEASE);
+ Fl_Group::current()->resizable(o);
+ }
+ o->end();
+ }
+ o->end();
+ Fl_Group::current()->resizable(o);
+ }
+ { Fl_Group* o = new Fl_Group(20, 460, 500, 25);
+ { Fl_Button* o = new Fl_Button(20, 460, 80, 25, "refresh");
+ o->labelsize(11);
+ o->callback((Fl_Callback*)update_sourceview_cb);
+ }
+ { Fl_Light_Button* o = sv_autorefresh = new Fl_Light_Button(105, 460, 80, 25, "autorefresh");
+ o->labelsize(11);
+ o->callback((Fl_Callback*)update_sourceview_cb);
+ }
+ { Fl_Light_Button* o = sv_autoposition = new Fl_Light_Button(190, 460, 80, 25, "autoposition");
+ o->labelsize(11);
+ }
+ { Fl_Button* o = new Fl_Button(440, 460, 80, 25, "close");
+ o->labelsize(11);
+ o->callback((Fl_Callback*)toggle_sourceview_b_cb);
+ }
+ { Fl_Box* o = new Fl_Box(275, 460, 160, 25);
+ Fl_Group::current()->resizable(o);
+ }
+ o->end();
+ }
+ o->size_range(384, 120);
+ o->end();
+ }
+ return w;
+}
+
//
// End of "$Id$".
//
diff --git a/fluid/function_panel.fl b/fluid/function_panel.fl
index e4c668100..032a75f0e 100644
--- a/fluid/function_panel.fl
+++ b/fluid/function_panel.fl
@@ -28,7 +28,7 @@ comment {//
//
// http://www.fltk.org/str.php
//
-} {selected in_source in_header
+} {in_source in_header
}
decl {\#include <FL/Fl_Pixmap.H>} {}
@@ -353,9 +353,9 @@ Function {make_widgetbin()} {open
} {
Fl_Window widgetbin_panel {
label {Widget Bin}
- xywh {413 185 520 85} type Single hide non_modal
+ xywh {413 185 520 85} type Single non_modal visible
} {
- Fl_Group {} {open
+ Fl_Group {} {
xywh {3 3 79 79} box THIN_DOWN_BOX
} {
Fl_Button {} {
@@ -684,6 +684,67 @@ Function {make_widgetbin()} {open
}
}
+Function {make_sourceview()} {open
+} {
+ Fl_Window sourceview_panel {
+ label {Code View}
+ callback toggle_sourceview_cb open
+ xywh {388 212 544 500} type Double resizable size_range {384 120 0 0} visible
+ } {
+ Fl_Tabs sv_tab {
+ callback update_sourceview_position_cb open
+ xywh {20 10 500 440} resizable
+ } {
+ Fl_Group {} {
+ label Source open
+ xywh {20 35 500 415} labelsize 13 resizable
+ } {
+ Fl_Text_Editor sv_source {
+ xywh {25 40 490 405} textfont 4 textsize 11 resizable
+ code0 {\#include "CodeEditor.h"}
+ class CodeEditor
+ }
+ }
+ Fl_Group {} {
+ label Header open
+ xywh {20 35 500 415} labelsize 13 hide
+ } {
+ Fl_Text_Editor sv_header {
+ xywh {25 40 490 405} textfont 4 textsize 11 resizable
+ code0 {\#include "CodeEditor.h"}
+ class CodeEditor
+ }
+ }
+ }
+ Fl_Group {} {open
+ xywh {20 460 500 25}
+ } {
+ Fl_Button {} {
+ label refresh
+ callback update_sourceview_cb
+ xywh {20 460 80 25} labelsize 11
+ }
+ Fl_Light_Button sv_autorefresh {
+ label autorefresh
+ xywh {105 460 80 25} labelsize 11
+ code0 {o->callback((Fl_Callback*)update_sourceview_cb);}
+ }
+ Fl_Light_Button sv_autoposition {
+ label autoposition
+ xywh {190 460 80 25} labelsize 11
+ }
+ Fl_Button {} {
+ label close
+ callback toggle_sourceview_b_cb selected
+ xywh {440 460 80 25} labelsize 11
+ }
+ Fl_Box {} {
+ xywh {275 460 160 25} resizable
+ }
+ }
+ }
+}
+
comment {
//
// End of "$Id$".
diff --git a/fluid/function_panel.h b/fluid/function_panel.h
index e0e315e03..cd8c5254c 100644
--- a/fluid/function_panel.h
+++ b/fluid/function_panel.h
@@ -92,6 +92,18 @@ void type_make_cb(Fl_Widget*w,void*d);
extern Fl_Window *widgetbin_panel;
extern void type_make_cb(Fl_Button*, void*);
Fl_Window* make_widgetbin();
+extern void toggle_sourceview_cb(Fl_Double_Window*, void*);
+extern Fl_Double_Window *sourceview_panel;
+#include <FL/Fl_Tabs.H>
+extern void update_sourceview_position_cb(Fl_Tabs*, void*);
+extern Fl_Tabs *sv_tab;
+extern CodeEditor *sv_source;
+extern CodeEditor *sv_header;
+extern void update_sourceview_cb(Fl_Button*, void*);
+extern Fl_Light_Button *sv_autorefresh;
+extern Fl_Light_Button *sv_autoposition;
+extern void toggle_sourceview_b_cb(Fl_Button*, void*);
+Fl_Double_Window* make_sourceview();
#endif
//