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
This commit is contained in:
Matthias Melcher 2005-11-03 20:43:19 +00:00
parent 5cdf984737
commit 1a5288e8fe
9 changed files with 372 additions and 10 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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();

View File

@ -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();
}
////////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -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]);

View File

@ -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$".
//

View File

@ -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$".

View File

@ -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
//