#|-------------------- 1.27 |# "./bb-support.cpp" 43608 /* bb-support.cpp */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BB_USE_FLU # include #endif #include "Table.h" #define BBEXPORT extern "C" #define ___bool bool #define ___safe #define WIDGET void ** #define widget_type(x) ((int)((x)[ 2 ]) >> 1) #define widget_ptr(x) (((void **)((x)[ 3 ]))[ 1 ]) #define widget_rlist(x) (((void ***)((x)[ 5 ]))[ 1 ]) #define widget_children(x) (((void ***)((x)[ 7 ]))[ 1 ]) typedef void (*BBCallback)(Fl_Widget *, void *); typedef int (*BBHandlerCallback)(Fl_Widget *, int event); #include "bb.h" BBEXPORT void BBSetCallback(WIDGET widget, BBCallback callback); BBEXPORT void *BBAddMenuItem(WIDGET menu, char *label, char *shortcut, BBCallback callback); BBEXPORT char *BBGetSelection(WIDGET widget); BBEXPORT void BBSetHandler(WIDGET widget, BBHandlerCallback callback); static void BBRedrawGLWindow(Fl_Gl_Window *); static void *BBAddResource(WIDGET widget, void *r, int i); class BBGLWindow: public Fl_Gl_Window { public: void *cbid; BBCallback cb; BBGLWindow(int x, int y, int w, int h, const char *label = 0): Fl_Gl_Window(x, y, w, h, label) {} void draw() { BBRedrawGLWindow(this); } }; class BBLiveImage: public Fl_Widget { private: unsigned char *data_; int d_, w_, h_; public: BBLiveImage(int x, int y, int w, int h, char *label = 0): Fl_Widget(x, y, w, h, label) { d_ = 0; data_ = 0; } void setData(unsigned char *data) { data_ = data; } void setDepth(int d) { d_ = d; } void setWidth(int w) { w_ = w; } void setHeight(int h) { h_ = h; } int width() { return w_; } int height() { return h_; } protected: void draw() { if(data_ != 0) if(d_ == 1) fl_draw_image_mono(data_, x(), y(), w_, h_); else fl_draw_image(data_, x(), y(), w_, h_, d_); } int handle(int event) { switch(event) { case FL_PUSH: do_callback(); return 1; default: return Fl_Widget::handle(event); } } }; template class BBHandler: public Widget { BBHandlerCallback handler; public: BBHandler(int w, int h) : Widget(w, h), handler(0) {} BBHandler(int x, int y, int w, int h) : Widget(x, y, w, h), handler(0) {} virtual int handle(int event) { if(handler) { int ret = handler(this, event); if(ret >= 0) // ret < 0 => call ancestor handle return ret; } return Widget::handle(event); } void set_handler(BBHandlerCallback cb) { handler = cb; } }; class BBImage { bool shared; Fl_Image *img; static bool img_regged; public: BBImage(const char *name) : shared(true) { if(!img_regged) { fl_register_images(); img_regged = true; } img = Fl_Shared_Image::get(name); } BBImage(Fl_Image *img_) : shared(false) { img = img_; } ~BBImage() { if(shared) ((Fl_Shared_Image *)img)->release(); else delete img; } Fl_Image *get() { return img; } }; bool BBImage::img_regged = false; static unsigned int cb_count = 1; double BBStart(char *scm) { Fl::visual(FL_RGB|FL_DOUBLE); Fl::scheme(scm); return Fl::version(); } void BBStop() { } void *BBCreateWidget(int type, int x, int y, int w, int h) { switch(type) { case BB_WINDOW: { Fl_Window *win = new BBHandler(w, h); if(x != -1) win->position(x, y); return win; } case BB_GLWINDOW: { BBGLWindow *win = new BBHandler(x, y, w, h); return win; } case BB_DOUBLEWINDOW: return new BBHandler(x, y, w, h); case BB_BUTTON: return new BBHandler(x, y, w, h); case BB_RETURNBUTTON: return new BBHandler(x, y, w, h); case BB_CHECKBOX: return new BBHandler(x, y, w, h); case BB_CHOICEBUTTON: return new BBHandler(x, y, w, h); case BB_MENUBUTTON: return new BBHandler(x, y, w, h); case BB_ENTRY: { Fl_Input *inp = new BBHandler(x, y, w, h); inp->when(FL_WHEN_ENTER_KEY_ALWAYS); return inp; } case BB_INTENTRY: { Fl_Int_Input *inp = new BBHandler(x, y, w, h); inp->when(FL_WHEN_ENTER_KEY_ALWAYS); return inp; } case BB_FLOATENTRY: { Fl_Float_Input *inp = new BBHandler(x, y, w, h); inp->when(FL_WHEN_ENTER_KEY_ALWAYS); return inp; } case BB_EDIT: return new BBHandler(x, y, w, h); case BB_TEXTEDITOR: { Fl_Text_Editor *ed = new BBHandler(x, y, w, h); ed->buffer(new Fl_Text_Buffer); return ed; } case BB_COUNTER: return new BBHandler(x, y, w, h); case BB_DIAL: return new BBHandler(x, y, w, h); case BB_LABEL: { Fl_Box *b = new BBHandler(x, y, w, h); b->box(FL_FLAT_BOX); return b; } case BB_SLIDER: return new BBHandler(x, y, w, h); case BB_ADJUSTER: return new BBHandler(x, y, w, h); case BB_ROLLER: return new BBHandler(x, y, w, h); case BB_LIST: return new BBHandler(x, y, w, h); case BB_RADIOBUTTON: return new BBHandler(x, y, w, h); case BB_MENUBAR: return new BBHandler(x, y, w, h); case BB_PROGRESS: return new BBHandler(x, y, w, h); case BB_TABS: return new BBHandler(x, y, w, h); case BB_GROUP: return new BBHandler(x, y, w, h); case BB_TILE: return new BBHandler(x, y, w, h); case BB_PACK: return new BBHandler(x, y, w, h); case BB_SCROLL: return new BBHandler(x, y, w, h); case BB_LIGHTBUTTON: return new BBHandler(x, y, w, h); case BB_CLOCK: return new BBHandler(x, y, w, h); case BB_LIVEIMAGE: return new BBHandler(x, y, w, h); #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *tree = new BBHandler(x, y, w, h); tree->allow_dnd(false); tree->double_click_opens(true); tree->insertion_mode(FLU_INSERT_BACK); tree->open_without_children(false); tree->open_on_select(false); tree->selection_drag_mode(FLU_DRAG_TO_SELECT); tree->selection_mode(FLU_SINGLE_SELECT); tree->show_branches(true); tree->show_connectors(true); tree->show_root(true); tree->show_leaves(true); return tree; } #endif case BB_TABLE: return new BBHandler(x, y, w,h); case BB_HTMLVIEW: return new Fl_Help_View(x, y, w,h); default: return 0; } } void BBDestroyWidget(WIDGET widget) { Fl_Widget *w = reinterpret_cast(widget_ptr(widget)); Fl_Group *p = w->parent(); if(p != NULL) p->remove(w); delete w; } void BBSetIntProperty(WIDGET widget, int item, int property, int value) { static bool setting_int_property = false; if(setting_int_property) return; Fl_Widget *w = (Fl_Widget *)widget_ptr(widget); switch(property) { case BB_X: w->position(value, w->y()); break; case BB_Y: w->position(w->x(), value); break; case BB_WIDTH: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE && item == BB_CONNECTOR) { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); t->connector_style(t->connector_color(), t->connector_style(), value); } else #endif if(widget_type(widget) == BB_TABLE && item >= 0) ((Table *)widget_ptr(widget))->columnWidth(item, value); else w->size(value, w->h()); break; case BB_HEIGHT: w->size(w->w(), value); break; case BB_BOX: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE) ((Flu_Tree_Browser *)w)->box((Fl_Boxtype)value); else #endif w->box((Fl_Boxtype)value); break; case BB_TYPE: w->type(value); break; case BB_VALIDCONTEXT: ((Fl_Gl_Window *)widget_ptr(widget))->valid(value); break; case BB_VALUE: switch(widget_type(widget)) { case BB_RADIOBUTTON: case BB_CHECKBOX: ((Fl_Button *)widget_ptr(widget))->value(value); break; case BB_PROGRESS: ((Fl_Progress *)widget_ptr(widget))->value(value); break; case BB_LIST: ((Fl_Select_Browser *)widget_ptr(widget))->value(value); break; case BB_CHOICEBUTTON: ((Fl_Choice *)widget_ptr(widget))->value(value); break; #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser::Node *n = ((Flu_Tree_Browser *)w)->find(value); if(n) { Flu_Tree_Browser::Node *p = n->parent(); while (p && !p->open()) // expand all parents { p->open(true); p = p->parent(); } n->select_only(); ((Flu_Tree_Browser *)w)->set_hilighted(n); } } break; #endif case BB_TABLE: ((Table *)w)->value(value); break; default: ((Fl_Valuator *)widget_ptr(widget))->value(value); } break; case BB_RESIZABLE: { switch(widget_type(widget)) { case BB_WINDOW: { Fl_Window *g = (Fl_Window *)widget_ptr(widget); g->resizable(value ? g : 0); break; } case BB_GLWINDOW: { Fl_Gl_Window *g = (Fl_Gl_Window *)widget_ptr(widget); g->resizable(value ? g : 0); break; } } break; } case BB_MODAL: if(value) ((Fl_Window *)widget_ptr(widget))->set_modal(); break; case BB_DIRECTION: w->type(value); break; case BB_COLOR: if(widget_type(widget) == BB_LIVEIMAGE) ((BBLiveImage *)widget_ptr(widget))->setDepth(value); #ifdef BB_USE_FLU else if(widget_type(widget) == BB_TREE) { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); if(item == BB_CONNECTOR) t->connector_style((Fl_Color)value, t->connector_style(), t->connector_width()); else t->color(value); } #endif else w->color(value); break; case BB_LABELCOLOR: w->labelcolor(value); break; case BB_LABELSIZE: w->labelsize(value); break; case BB_LABELFONT: w->labelfont(value); break; case BB_FOCUS: w->take_focus(); break; case BB_SPACING: ((Fl_Pack *)widget_ptr(widget))->spacing(value); break; case BB_XPOSITION: ((Fl_Scroll *)widget_ptr(widget))->position(value, ((Fl_Scroll *)widget_ptr(widget))->yposition()); break; case BB_YPOSITION: ((Fl_Scroll *)widget_ptr(widget))->position(((Fl_Scroll *)widget_ptr(widget))->yposition(), value); break; case BB_TEXTCOLOR: switch(widget_type(widget)) { #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); switch(item) { case BB_ROOT: t->root_color((Fl_Color)value); break; case BB_BRANCH: t->branch_text((Fl_Color)value, t->branch_font(), t->branch_size()); break; case BB_LEAF: t->leaf_text((Fl_Color)value, t->leaf_font(), t->leaf_size()); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label_color((Fl_Color)value); } } } break; #endif case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: ((Fl_Input *)widget_ptr(widget))->textcolor(value); break; case BB_TEXTEDITOR: ((Fl_Text_Editor *)widget_ptr(widget))->textcolor(value); break; case BB_HTMLVIEW: ((Fl_Help_View *)widget_ptr(widget))->textcolor((Fl_Color)value); break; } break; case BB_TEXTSIZE: switch(widget_type(widget)) { #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); switch(item) { case BB_ROOT: t->root_size(value); break; case BB_BRANCH: t->branch_text(t->branch_color(), t->branch_font(), value); break; case BB_LEAF: t->leaf_text(t->leaf_color(), t->leaf_font(), value); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label_size(value); } } } break; #endif case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: ((Fl_Input *)widget_ptr(widget))->textsize(value); break; case BB_TEXTEDITOR: ((Fl_Text_Editor *)widget_ptr(widget))->textsize(value); break; case BB_HTMLVIEW: ((Fl_Help_View *)widget_ptr(widget))->textsize(value); break; } break; case BB_TEXTFONT: switch(widget_type(widget)) { #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); switch(item) { case BB_ROOT: t->root_font((Fl_Font)value); break; case BB_BRANCH: t->branch_text(t->branch_color(), (Fl_Font)value, t->branch_size()); break; case BB_LEAF: t->leaf_text(t->leaf_color(), (Fl_Font)value, t->leaf_size()); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label_font((Fl_Font)value); } } } break; #endif case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: ((Fl_Input *)widget_ptr(widget))->textfont(value); break; case BB_TEXTEDITOR: ((Fl_Text_Editor *)widget_ptr(widget))->textfont(value); break; case BB_HTMLVIEW: ((Fl_Help_View *)widget_ptr(widget))->textfont(value); break; } break; case BB_SELECTIONCOLOR: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE) ((Flu_Tree_Browser *)widget_ptr(widget))->selection_color(value); else #endif w->selection_color(value); break; case BB_VISIBLE: switch(widget_type(widget)) { case BB_WINDOW: case BB_DOUBLEWINDOW: { Fl_Window *win = (Fl_Window *)widget_ptr(widget); if(value) win->show(); else win->hide(); break; } default: if(value) w->show(); else w->hide(); } break; case BB_WHEN: w->when(value); break; case BB_POSITION: switch(widget_type(widget)) { case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: { Fl_Input_ *inp = (Fl_Input_ *)widget_ptr(widget); int n = value == -1 ? inp->size() : value; inp->position(n, inp->mark()); break; } case BB_TEXTEDITOR: { Fl_Text_Editor *ep = (Fl_Text_Editor *)widget_ptr(widget); ep->insert_position(value); break; } } break; case BB_MARK: switch(widget_type(widget)) { case BB_ENTRY: case BB_INTENTRY: case BB_FLOATENTRY: case BB_EDIT: { Fl_Input_ *inp = (Fl_Input_ *)widget_ptr(widget); int n = value == -1 ? inp->size() : value; inp->mark(n); break; } case BB_TEXTEDITOR: { Fl_Text_Editor *ep = (Fl_Text_Editor *)widget_ptr(widget); int n = value == -1 ? ep->buffer()->length() : value; ep->insert_position(n); break; } } break; case BB_READONLY: ((Fl_Input_ *)widget_ptr(widget))->readonly(value); break; case BB_IMAGEWIDTH: ((BBLiveImage *)widget_ptr(widget))->setWidth(value); break; case BB_IMAGEHEIGHT: ((BBLiveImage *)widget_ptr(widget))->setHeight(value); break; case BB_SIZE: break; case BB_ALIGN: if(widget_type(widget) == BB_TABLE && item >= 0) ((Table *)widget_ptr(widget))->columnAlign(item, (Fl_Align)value); else w->align(value); break; default: setting_int_property = true; BBSetDoubleProperty(widget, property, value); setting_int_property = false; } } void BBSetStringProperty(WIDGET widget, int item, int item2, int property, char *value) { Fl_Widget *w = (Fl_Widget *)widget_ptr(widget); switch(property) { case BB_TEXT: switch(widget_type(widget)) { case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: case BB_ENTRY: ((Fl_Input *)widget_ptr(widget))->value(value); break; case BB_WINDOW: case BB_DOUBLEWINDOW: case BB_GLWINDOW: ((Fl_Window *)widget_ptr(widget))->label(value); break; #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); if(item == BB_ROOT) t->label(value); else { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label(value); } } break; #endif case BB_TEXTEDITOR: ((Fl_Text_Editor *)widget_ptr(widget))->buffer()->text(value); break; case BB_HTMLVIEW: ((Fl_Help_View *)w)->value(value); break; case BB_TABLE: if(item2 > -1) { if(item > -1) ((Table *)w)->valueAt(item, item2, value); else ((Table *)w)->columnTitle(item2, value); break; } /* fall through! */ default: w->label((char *)BBAddResource(widget, strdup(value), WRES_LABEL)); } break; case BB_TOOLTIP: w->tooltip((char *)BBAddResource(widget, strdup(value), WRES_TOOLTIP)); break; case BB_VALUE: if(widget_type(widget) == BB_HTMLVIEW) ((Fl_Help_View *)w)->load(value); } } void BBSetCallback(WIDGET widget, BBCallback callback) { Fl_Widget *w = (Fl_Widget *)widget_ptr(widget); switch(widget_type(widget)) { case BB_GLWINDOW: { BBGLWindow *glw = (BBGLWindow *)widget_ptr(widget); glw->cb = callback; glw->cbid = (void *)cb_count++; break; } default: w->callback(callback, (void *)cb_count++); } } void BBSetHandler(WIDGET widget, BBHandlerCallback cb) { switch(widget_type(widget)) { case BB_WINDOW: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_DOUBLEWINDOW: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_GLWINDOW: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_BUTTON: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_RETURNBUTTON: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_CHOICEBUTTON: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_MENUBUTTON: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_CHECKBOX: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_ENTRY: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_EDIT: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_TEXTEDITOR: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_INTENTRY: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_FLOATENTRY: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_COUNTER: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_DIAL: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_LABEL: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_SLIDER: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_ADJUSTER: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_ROLLER: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_LIST: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_RADIOBUTTON: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_MENUBAR: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_PROGRESS: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_TABS: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_GROUP: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_TILE: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_PACK: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_SCROLL: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_LIGHTBUTTON: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_CLOCK: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; case BB_LIVEIMAGE: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; #ifdef BB_USE_FLU case BB_TREE: ((BBHandler*)widget_ptr(widget))->set_handler(cb); break; #endif case BB_TABLE: ((BBHandler
*)widget_ptr(widget))->set_handler(cb); break; case BB_HTMLVIEW: ((Fl_Help_View*)widget_ptr(widget))->link((Fl_Help_Func *)cb); break; } } void BBSetDoubleProperty(WIDGET widget, int property, double value) { static bool setting_double_property = false; if(setting_double_property) return; switch(property) { case BB_VALUE: switch(widget_type(widget)) { case BB_RADIOBUTTON: case BB_CHECKBOX: case BB_TABS: case BB_CHOICEBUTTON: BBSetIntProperty(widget, -1, property, (int)value); break; case BB_PROGRESS: ((Fl_Progress *)widget_ptr(widget))->value(value); break; case BB_CLOCK: ((Fl_Clock *)widget_ptr(widget))->value((unsigned long)value); break; default: ((Fl_Valuator *)widget_ptr(widget))->value(value); } break; case BB_MAXIMUM: switch(widget_type(widget)) { case BB_PROGRESS: ((Fl_Progress *)widget_ptr(widget))->maximum(value); break; case BB_DIAL: ((Fl_Dial *)widget_ptr(widget))->angle2((short)value); break; } break; case BB_MINIMUM: switch(widget_type(widget)) { case BB_PROGRESS: ((Fl_Progress *)widget_ptr(widget))->minimum(value); break; case BB_DIAL: ((Fl_Dial *)widget_ptr(widget))->angle1((short)value); break; } break; default: setting_double_property = true; BBSetIntProperty(widget, -1, property, (int)value); setting_double_property = false; } } int BBGetIntProperty(WIDGET widget, int item, int property) { static int getting_int_property = false; if(getting_int_property) return 0; Fl_Widget *w = (Fl_Widget *)widget_ptr(widget); int result; switch(property) { case BB_X: result = w->x(); break; case BB_Y: result = w->y(); break; case BB_WIDTH: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE && item == BB_CONNECTOR) result = ((Flu_Tree_Browser *)widget_ptr(widget))->connector_width(); else #endif if(widget_type(widget) == BB_TABLE && item >= 0) result = ((Table *)widget_ptr(widget))->columnWidth(item); else result = w->w(); break; case BB_HEIGHT: result = w->h(); break; case BB_BOX: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE) result = ((Flu_Tree_Browser *)w)->box(); else #endif result = w->box(); break; case BB_TYPE: result = w->type(); break; case BB_VALIDCONTEXT: result = ((Fl_Gl_Window *)widget_ptr(widget))->valid(); break; case BB_RESIZABLE: result = ((Fl_Group *)widget_ptr(widget))->resizable() != 0; break; case BB_MODAL: result = ((Fl_Window *)widget_ptr(widget))->modal(); break; case BB_DIRECTION: result = w->type(); break; case BB_COLOR: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE && item == BB_CONNECTOR) result = ((Flu_Tree_Browser *)widget_ptr(widget))->connector_color(); else #endif result = w->color(); break; case BB_LABELCOLOR: result = w->labelcolor(); break; case BB_LABELSIZE: result = w->labelsize(); break; case BB_LABELFONT: result = w->labelfont(); break; case BB_VALUE: switch(widget_type(widget)) { case BB_RADIOBUTTON: case BB_CHECKBOX: result = ((Fl_Button *)widget_ptr(widget))->value(); break; case BB_PROGRESS: result = (int)((Fl_Progress *)widget_ptr(widget))->value(); break; case BB_LIST: result = ((Fl_Select_Browser *)widget_ptr(widget))->value(); break; case BB_CHOICEBUTTON: result = ((Fl_Choice *)widget_ptr(widget))->value(); break; #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser::Node *n = ((Flu_Tree_Browser *)widget_ptr(widget))->get_selected(1); if(n) result = n->id(); else result = -1; break; } #endif case BB_TABLE: result = ((Table *)w)->value(); break; default: result = (int)((Fl_Valuator *)widget_ptr(widget))->value(); break; } break; case BB_SPACING: result = ((Fl_Pack *)widget_ptr(widget))->spacing(); break; case BB_XPOSITION: result = ((Fl_Scroll *)widget_ptr(widget))->xposition(); break; case BB_YPOSITION: result = ((Fl_Scroll *)widget_ptr(widget))->yposition(); break; case BB_TEXTCOLOR: result = 0; switch(widget_type(widget)) { #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); switch(item) { case BB_ROOT: result = t->root_color(); break; case BB_BRANCH: result = t->branch_color(); break; case BB_LEAF: result = t->leaf_color(); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label_color(); break; } } } break; #endif case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: result = ((Fl_Input *)widget_ptr(widget))->textcolor(); break; case BB_TEXTEDITOR: result = ((Fl_Text_Editor *)widget_ptr(widget))->textcolor(); break; case BB_HTMLVIEW: result = ((Fl_Help_View *)widget_ptr(widget))->textcolor(); break; } break; case BB_TEXTSIZE: result = 0; switch(widget_type(widget)) { #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); switch(item) { case BB_ROOT: result = t->root_size(); break; case BB_BRANCH: result = t->branch_size(); break; case BB_LEAF: result = t->leaf_size(); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label_size(); break; } } } break; #endif case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: result = ((Fl_Input *)widget_ptr(widget))->textsize(); break; case BB_TEXTEDITOR: result = ((Fl_Text_Editor *)widget_ptr(widget))->textsize(); break; case BB_HTMLVIEW: result = ((Fl_Help_View *)widget_ptr(widget))->textsize(); break; } break; case BB_TEXTFONT: result = 0; switch(widget_type(widget)) { #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(widget); switch(item) { case BB_ROOT: result = t->root_font(); break; case BB_BRANCH: result = t->branch_font(); break; case BB_LEAF: result = t->leaf_font(); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) n->label_font(); break; } } } break; #endif case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: result = ((Fl_Input *)widget_ptr(widget))->textfont(); break; case BB_TEXTEDITOR: result = ((Fl_Text_Editor *)widget_ptr(widget))->textfont(); break; case BB_HTMLVIEW: result = ((Fl_Help_View *)widget_ptr(widget))->textfont(); break; } break; case BB_SELECTIONCOLOR: #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE) result = ((Flu_Tree_Browser *)widget_ptr(widget))->selection_color(); else #endif result = w->selection_color(); break; case BB_VISIBLE: result = w->visible(); break; case BB_WHEN: result = w->when(); break; case BB_POSITION: result = 0; switch(widget_type(widget)) { case BB_EDIT: case BB_ENTRY: case BB_INTENTRY: case BB_FLOATENTRY: result = ((Fl_Input_ *)widget_ptr(widget))->position(); break; case BB_TEXTEDITOR: result = ((Fl_Text_Editor *)widget_ptr(widget))->insert_position(); break; } break; case BB_MARK: result = 0; switch(widget_type(widget)) { case BB_EDIT: case BB_ENTRY: case BB_INTENTRY: case BB_FLOATENTRY: result = ((Fl_Input_ *)widget_ptr(widget))->mark(); break; case BB_TEXTEDITOR: result = ((Fl_Text_Editor *)widget_ptr(widget))->insert_position(); break; } break; case BB_READONLY: result = ((Fl_Input_ *)widget_ptr(widget))->readonly(); break; case BB_IMAGEWIDTH: result = ((BBLiveImage *)widget_ptr(widget))->width(); break; case BB_IMAGEHEIGHT: result = ((BBLiveImage *)widget_ptr(widget))->height(); break; case BB_FOCUS: result = 0; break; case BB_SIZE: result = ((Fl_Menu_ *)widget_ptr(widget))->size(); break; case BB_ALIGN: if(widget_type(widget) == BB_TABLE && item >= 0) result = ((Table *)widget_ptr(widget))->columnAlign(item); else result = w->align(); break; #ifdef BB_USE_FLU case BB_CALLBACK_REASON: if(widget_type(widget) == BB_TREE) result = ((Flu_Tree_Browser *)widget_ptr(widget))->callback_reason(); else result = -1; break; case BB_CALLBACK_NODE: if(widget_type(widget) == BB_TREE) { Flu_Tree_Browser::Node *n = ((Flu_Tree_Browser *)widget_ptr(widget))->callback_node(); if(n) result = n->id(); } else result = -1; break; #endif default: getting_int_property = true; result = (int)BBGetDoubleProperty(widget, property); getting_int_property = false; } return result; } double BBGetDoubleProperty(WIDGET widget, int property) { static bool getting_double_property = false; if(getting_double_property) return 0; double result; switch(property) { case BB_VALUE: switch(widget_type(widget)) { case BB_RADIOBUTTON: case BB_CHECKBOX: result = ((Fl_Button *)widget_ptr(widget))->value(); break; case BB_CHOICEBUTTON: result = ((Fl_Choice *)widget_ptr(widget))->value(); break; case BB_PROGRESS: result = ((Fl_Progress *)widget_ptr(widget))->value(); break; case BB_CLOCK: result = (double)((Fl_Clock *)widget_ptr(widget))->value(); break; default: result = ((Fl_Valuator *)widget_ptr(widget))->value(); break; } break; case BB_MAXIMUM: switch(widget_type(widget)) { case BB_PROGRESS: result = ((Fl_Progress *)widget_ptr(widget))->maximum(); break; case BB_DIAL: result = ((Fl_Dial *)widget_ptr(widget))->angle2(); break; default: getting_double_property = true; result = BBGetIntProperty(widget, -1, property); getting_double_property = false; break; } case BB_MINIMUM: switch(widget_type(widget)) { case BB_PROGRESS: result = ((Fl_Progress *)widget_ptr(widget))->minimum(); break; case BB_DIAL: result = ((Fl_Dial *)widget_ptr(widget))->angle1(); break; default: getting_double_property = true; result = BBGetIntProperty(widget, -1, property); getting_double_property = false; break; } default: getting_double_property = true; result = BBGetIntProperty(widget, -1, property); getting_double_property = false; break; } return result; } char *BBGetStringProperty(WIDGET widget, int item, int item2, int property) { Fl_Widget *w = (Fl_Widget *)widget_ptr(widget); switch(property) { case BB_TEXT: switch(widget_type(widget)) { case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: case BB_ENTRY: return (char *)((Fl_Input *)widget_ptr(widget))->value(); case BB_GLWINDOW: case BB_DOUBLEWINDOW: case BB_TEXTEDITOR: return ((Fl_Text_Editor *)widget_ptr(widget))->buffer()->text(); case BB_WINDOW: return (char *)((Fl_Window *)widget_ptr(widget))->label(); #ifdef BB_USE_FLU case BB_TREE: if(item == BB_ROOT) return (char *)((Flu_Tree_Browser *)widget_ptr(widget))->label(); else { Flu_Tree_Browser::Node *n = ((Flu_Tree_Browser *)widget_ptr(widget))->find(item); if(n) return (char *)n->label(); else return 0; } #endif case BB_HTMLVIEW: return (char *)((Fl_Help_View *)w)->value(); case BB_TABLE: if(item2 > -1) { if(item > -1) return ((Table *)w)->valueAt(item, item2); else return (char *)((Table *)w)->columnTitle(item2); } /* fall through! */ default: return (char *)w->label(); } case BB_TOOLTIP: return (char *)w->tooltip(); case BB_VALUE: if(widget_type(widget) == BB_HTMLVIEW) return (char *)((Fl_Help_View *)w)->filename(); default: return 0; } } int BBRunEventLoop(bool wait, double tm) { if(!wait) return (int)Fl::wait(tm); else return Fl::run(); } static char *args[BBMAX_SHOW_ARGS] = {0}; void BBSetArg(int i, char *a) { if(i < BBMAX_SHOW_ARGS) args[i] = strdup(a); } void BBShowWindow(WIDGET widget, int argc) { Fl_Window *w = (Fl_Window *)widget_ptr(widget); if(argc) { Fl::args(argc, args); w->show(argc, args); for(int i = 0; i < argc; i++) free(args[i]); } else w->show(); } void BBRedrawWidget(WIDGET widget) { Fl_Widget *w = (Fl_Widget *)widget_ptr(widget); w->redraw(); } void BBBeginGroup(WIDGET widget) { ((Fl_Group *)widget_ptr(widget))->begin(); } void BBEndGroup(WIDGET widget) { ((Fl_Group *)widget_ptr(widget))->end(); } void* BBPixmap(void *xpm) { return (void *)new BBImage(new Fl_Pixmap((char *const *)xpm)); } void BBSetImage(WIDGET widget, int item, void *img) { switch(widget_type(widget)) { case BB_LIVEIMAGE: ((BBLiveImage *)widget_ptr(widget))->setData((unsigned char *)img); break; #ifdef BB_USE_FLU case BB_TREE: { Flu_Tree_Browser *t = ((Flu_Tree_Browser *)widget_ptr(widget)); Fl_Image *im = ((BBImage *)img)->get(); switch(item) { case BB_ROOT: if(t->get_root()) t->get_root()->branch_icons(im, im); break; case BB_BRANCH: t->branch_icons(im, im); break; case BB_LEAF: t->leaf_icon(im); break; case BB_CONNECTOR: t->collapse_icons(im, im); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) { if(n->is_branch()) n->branch_icons(im, im); else n->leaf_icon(im); } break; } } break; } #endif default: Fl_Image *im = ((BBImage *)img)->get(); ((Fl_Widget *)widget_ptr(widget))->image(im); } } void BBSetImage2(WIDGET widget, int item, void *iclosed, void *iopen) { #ifdef BB_USE_FLU if(widget_type(widget) == BB_TREE) { Flu_Tree_Browser *t = ((Flu_Tree_Browser *)widget_ptr(widget)); Fl_Image *i1 = ((BBImage *)iclosed)->get(); Fl_Image *i2 = ((BBImage *)iopen)->get(); switch(item) { case BB_ROOT: if(t->get_root()) t->get_root()->branch_icons(i1, i2); break; case BB_BRANCH: t->branch_icons(i1, i2); break; case BB_CONNECTOR: t->collapse_icons(i1, i2); break; default: { Flu_Tree_Browser::Node *n = t->find(item); if(n) { if(n->is_branch()) n->branch_icons(i1, i2); else n->leaf_icon(i1); } break; } } } #endif } void *BBRawImage(void *data, int w, int h, int d) { return new BBImage(new Fl_RGB_Image((const unsigned char *)data, w, h, d)); } void *BBLoadImage(char *name) { return new BBImage(name); } int BBImageDim(void *image, int dim) { Fl_Image *img = ((BBImage *)image)->get(); switch(dim) { case BB_IMAGEWIDTH: return img->w(); case BB_IMAGEHEIGHT: return img->h(); case BB_COLOR: return img->d(); case BB_SIZE: return img->count(); default: return 0; } } void *BBImageData(void *image, int i) { Fl_Image *img = ((BBImage *)image)->get(); return (void *)(img->data()[i]); } void BBAddItem(WIDGET widget, char *str, int pos) { switch(widget_type(widget)) { case BB_LIST: { Fl_Browser *b = (Fl_Browser *)widget_ptr(widget); if(pos > 0) b->insert(pos, str); else { b->add(str); b->bottomline(b->size()); } } break; case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: ((Fl_Input *)widget_ptr(widget))->insert(str); break; case BB_TEXTEDITOR: { Fl_Text_Editor *ep = (Fl_Text_Editor *)widget_ptr(widget); if(pos != 1) ep->buffer()->insert(ep->insert_position(), str); else ep->buffer()->replace_selection(str); break; } } } void BBRemoveItem(WIDGET widget, int n) { if(widget_type(widget) == BB_LIST) { if(n == -1) ((Fl_Browser *)widget_ptr(widget))->clear(); else ((Fl_Browser *)widget_ptr(widget))->remove(n + 1); } #ifdef BB_USE_FLU else if(widget_type(widget) == BB_TREE) { ((Flu_Tree_Browser *)widget_ptr(widget))->remove(n); } #endif else if(widget_type(widget) == BB_TABLE) { ((Table *)widget_ptr(widget))->removeRow(n); } } int BBMessage(int type, char *text, char *def, char *c1, char *c2) { switch(type) { case BB_MESSAGE: fl_message(text); return 0; case BB_ALERT: fl_alert(text); return 0; case BB_ASK: return fl_ask(text); case BB_CHOICE: return fl_ask(text, def, c1, c2); default: return 0; } } char *BBSelectFile(char *message, char *pattern, char *fname) { return fl_file_chooser(message, pattern, fname); } char *BBSelectDir(char *message, char *fname) { return fl_dir_chooser(message, fname, 0); } void *BBAddMenuItem(WIDGET menu, char *label, char *shortcut, BBCallback callback) { ((Fl_Menu_ *)widget_ptr(menu))->add(label, shortcut != 0 ? strdup(shortcut) : 0, callback, (void *)cb_count); return (void *)(cb_count++); } int BBAddTreeItem(WIDGET tree, char *text, int parent, int pos, WIDGET widget) { #ifdef BB_USE_FLU Flu_Tree_Browser *t = (Flu_Tree_Browser *)widget_ptr(tree); Fl_Widget *w = widget && widget != (WIDGET)6 // not #f ? (Fl_Widget *)widget_ptr(widget) : 0; Flu_Tree_Browser::Node *n = 0; Flu_Tree_Browser::Node *p = 0; if(parent != -1 && (p = t->find(parent))) { if(pos != -1) // add with parent and posistion { n = p->insert(text, pos); if(n) n->widget(w); } else // add with parent n = t->add(p, text, w); } else // add with full path n = t->add(text, w); if(n) return n->id(); else return -1; #else return -1; #endif } void BBAddWidget(WIDGET widget, WIDGET child) { ((Fl_Group *)widget_ptr(widget))->add((Fl_Widget *)widget_ptr(child)); } void BBSetWidgetProperty(WIDGET w1, int property, WIDGET w2) { switch(property) { case BB_RESIZABLEWIDGET: ((Fl_Group *)widget_ptr(w1))->resizable((Fl_Widget *)widget_ptr(w2)); break; case BB_TABS: ((Fl_Tabs *)widget_ptr(w1))->value((Fl_Widget *)widget_ptr(w2)); break; } } void BBRemoveAllItems(WIDGET widget) { switch(widget_type(widget)) { case BB_LIST: ((Fl_Browser *)widget_ptr(widget))->clear(); break; #ifdef BB_USE_FLU case BB_TREE: ((Flu_Tree_Browser *)widget_ptr(widget))->clear(); break; #endif case BB_TABLE: ((Table *)widget_ptr(widget))->clear(true); // remove columns too break; } } void BBRemoveImage(void *img) { delete (BBImage *)img; } unsigned long BBRGB(int r, int g, int b) { return fl_rgb_color(r, g, b); } char *BBGetSelection(WIDGET widget) { switch(widget_type(widget)) { case BB_ENTRY: case BB_EDIT: case BB_INTENTRY: case BB_FLOATENTRY: { Fl_Input_ *inp = (Fl_Input_ *)widget_ptr(widget); int p = inp->position(); int m = inp->mark(); int n = p - m; if(n < 0) n = -n; char *buf = (char *)malloc(n + 1); if(buf == 0) return 0; strncpy(buf, inp->value() + (p < m ? p : m), n); buf[ n ] = '\0'; return buf; } case BB_TEXTEDITOR: { int p1, p2; Fl_Text_Buffer *bp = ((Fl_Text_Editor *)widget_ptr(widget))->buffer(); bp->selection_position(&p1, &p2); if(!bp->selected()) return 0; int n = p2 - p1; char *buf = (char *)malloc(n + 1); if(buf == 0) return 0; memcpy(buf, bp->text_range(p1, p2), n); buf[ n ] = '\0'; return buf; } default: return 0; } } void BBSetSelection(WIDGET widget, int start, int end) { if(widget_type(widget) == BB_TEXTEDITOR) ((Fl_Text_Editor *)widget_ptr(widget))->buffer()->select(start, end); } void BBRedrawGLWindow(Fl_Gl_Window *w) { BBGLWindow *glw = (BBGLWindow *)w; glw->cb(glw, glw->cbid); } void *BBAddResource(WIDGET widget, void *res, int index) { void **rptr = widget_rlist(widget); void *old = rptr[ index ]; if(old != 0) free(old); rptr[ index ] = res; return res; } int BBSelectColor(char *title, unsigned char *rgb) { return fl_color_chooser(title, rgb[ 0 ], rgb[ 1 ], rgb[ 2 ]); } int BBSelectColorIndex(int col) { return fl_show_colormap((Fl_Color)col); } char *BBGetInput(char *label, char *def) { return (char *)fl_input(label, def); } void BBActivateMenuItem(WIDGET mbar, int index, bool flag) { if(widget_type(mbar) != BB_MENUBAR) return; Fl_Menu_ *m = (Fl_Menu_ *)widget_ptr(mbar); int s = m->size(); if(index < s) { const Fl_Menu_Item *item = m->menu(); int bits = item[ index ].flags; m->mode(index, flag ? (bits & ~FL_MENU_INACTIVE) : (bits | FL_MENU_INACTIVE)); } } void BBAddTableColumn(WIDGET widget, char *text) { ((Table *)widget_ptr(widget))->addColumn(text); } void BBAddTableCell(WIDGET widget, char *text) { ((Table *)widget_ptr(widget))->addCell(text); } int BBGetEventInt(int event) { switch(event) { case BBE_CLICKS: return Fl::event_clicks(); case BBE_KEY: return Fl::event_key(); case BBE_LENGTH: return Fl::event_length(); case BBE_X: return Fl::event_x(); case BBE_Y: return Fl::event_y(); case BBE_X_ROOT: return Fl::event_x_root(); case BBE_Y_ROOT: return Fl::event_y_root(); case BBE_DX: return Fl::event_dx(); case BBE_DY: return Fl::event_dy(); } return 0; } bool BBGetEventBool(int event) { switch(event) { case BBE_ALT: return Fl::event_alt(); case BBE_BUTTON1: return Fl::event_button1(); case BBE_BUTTON2: return Fl::event_button2(); case BBE_BUTTON3: return Fl::event_button3(); case BBE_CTRL: return Fl::event_ctrl(); case BBE_IS_CLICK: return Fl::event_is_click(); case BBE_SHIFT: return Fl::event_shift(); } return false; } char *BBGetEventString(int event) { if(event == BBE_TEXT) return (char *)Fl::event_text(); return 0; } void BBSetEventInt(int event, int val) { if(event == BBE_CLICKS) Fl::event_clicks(val); } void BBSetEventBool(int event, bool /*val*/) { if(event == BBE_IS_CLICK) Fl::event_is_click(0); } #|-------------------- 1.27 |# "./Table.cxx" 32714 /* Copyright (c) 2004 Markus Niemistö Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Modified by Sergey Khorev */ #include #include #include #include #include #include "Table.h" #define DAMAGE_HEADER FL_DAMAGE_USER1 #define DAMAGE_ROWS FL_DAMAGE_USER2 int stringcompare(const char *s1, const char *s2) { if (!s1) return (s2 ? -1 : 0); else if (!s2) return (s1 ? 1 : 0); else #ifdef _MSC_VER return stricmp(s1, s2); #else return strcasecmp(s1, s2); #endif } /* * ====================================== * void Table.drawHeader(int x, int y); * ====================================== * * Draws header buttons starting at (x, y). */ void Table::drawHeader(int x, int y) { int w; struct ColumnInfo col; fl_font(labelfont(), headerHeight - 4); /* * Draw all header cells that aren't clipped. */ for (int i = leftCol; i <= rightCol; i++) { col = header[i]; // Draw box if (pushed != i) fl_draw_box(FL_THIN_UP_BOX, x, y, w = col.width, headerHeight, FL_GRAY); else fl_draw_box(FL_THIN_DOWN_BOX, x, y, w = col.width, headerHeight, FL_GRAY); fl_color(labelcolor()); // Draw labels if (col.title != NULL) fl_draw(col.title, x + 2, y - 1, w - 2, headerHeight, col.align); x += w; // Draw "the sort arrow", if any. if (sortColumn == i) { int mod = headerHeight - 10; if (!ascent) fl_polygon(x - mod - 6, y + 5, x - mod / 2 - 6, y + mod + 5, x - 6, y + 5); else fl_polygon(x - mod - 6, y + mod + 5, x - mod / 2 - 6, y + 5, x - 6, y + mod + 5); } } } /* * ============================================================= * void Table.drawRow(int row, char *rowData[], int x, int y); * ============================================================= * * Draws all items in the row. Starts drawing from (x, y). */ void Table::drawRow(int row, char *rowData[], int x, int y) { int w; ColumnInfo col; fl_font(labelfont(), rowHeight - 3); // Draw background box. if (row != selected) { fl_rectf(iX, y, tableWidth - hScroll->value(), rowHeight, color()); fl_color(labelcolor()); } else if (Fl::focus() == this) { fl_rectf(iX, y, tableWidth - hScroll->value(), rowHeight, selection_color()); fl_color(color()); // Draw focus fl_line_style(FL_DOT); fl_rect(iX, y, tableWidth - hScroll->value(), rowHeight); fl_line_style(FL_SOLID); } else { fl_rectf(iX, y, tableWidth - hScroll->value(), rowHeight, selection_color()); fl_color(color()); } const char *str; // Draw the data. for (int i = leftCol; i <= rightCol; i++) { w = (col = header[i]).width; if ((str = rowData[i]) != NULL) fl_draw(str, x, y - 1, w - 2, rowHeight + 1, col.align); x += w; } } /* * ======================================================= * Table.Table(int x, int y, int w, int h, char *label); * ======================================================= * * This is standard FLTK constructor. See FLTK documentation for * more information. */ Table::Table(int x, int y, int w, int h, char *label) : Fl_Group(x, y, w, h, label) { labelsize(18); // Setup variables. align((Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); box(FL_THIN_DOWN_FRAME); color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); when(FL_WHEN_CHANGED); // Create scrollbars. vScroll = new Fl_Scrollbar(x + w - scrollbarSize, y, scrollbarSize, h + scrollbarSize); vScroll->type(FL_VERTICAL); vScroll->linesize(3 * rowHeight); vScroll->callback(scrollCallback, (void*)this); vScroll->hide(); hScroll = new Fl_Scrollbar(x, y + h - scrollbarSize, w, scrollbarSize); hScroll->type(FL_HORIZONTAL); hScroll->callback(scrollCallback, (void*)this); hScroll->hide(); Fl_Group::end(); // Setup the rest of the variables to reasonable defaults. nCols = nRows = 0; cPos = 0; dragX = 0; resizing = -1; pushed = -1; curRow = NULL; sortColumn = -1; selected = -1; canSort = true; canResize = true; ascent = false; noMoreColumns = false; dimensionsChanged = false; toBeSorted = false; headerEnabled = true; } /* * ================= * Table.~Table(); * ================= * * Destructor. */ Table::~Table() { clear(); } /* * ==================================== * bool Table.headerOn(); * void Table.headerOn(bool enabled); * ==================================== * * These methods get or set the value of variable controlling * whether header buttons are displayed. */ bool Table::headerOn() const { return headerEnabled; } void Table::headerOn(bool enabled) { headerEnabled = enabled; dimensionsChanged = true; redraw(); } /* * ===================================== * bool Table.allowResize(); * void Table.allowResize(bool allow); * ===================================== * * These methods get or set the value of variable controlling * whether user may resize columns by dragging the column border. */ bool Table::allowResize() const { return canResize; } void Table::allowResize(bool allow) { canResize = allow; } /* * =================================== * bool Table.allowSort(); * void Table.allowSort(bool allow); * =================================== * * These methods get or set the value of variable controlling * whether user can determine how data on table is sorted by * clicking on the header buttons. */ bool Table::allowSort() const { return canSort; } void Table::allowSort(bool allow) { canSort = allow; } /* * ================================== * int Table.headerSize(); * void Table.headerSize(int size); * ================================== * * These methods get or set the value of variable controlling * the height of header buttons. */ int Table::headerSize() const { return headerHeight; } void Table::headerSize(int height) { headerHeight = height; dimensionsChanged = true; redraw(); } /* * =============================== * int Table.rowSize(); * void Table.rowSize(int size); * =============================== * * These methods get or set the value of variable controlling * the height of rows. */ int Table::rowSize() const { return rowHeight; } void Table::rowSize(int height) { rowHeight = height; vScroll->linesize(3 * height); dimensionsChanged = true; redraw(); } /* * =================================== * int Table.scrollbSize(); * void Table.scrollbSize(int size); * =================================== * * These methods get or set the value of variable controlling * the size (width) of the scrollbars. */ int Table::scrollbSize() const { return scrollbarSize; } void Table::scrollbSize(int size) { scrollbarSize = size; dimensionsChanged = true; redraw(); } /* * ===================================================== * Fl_Align Table.columnAlign(int column); * void Table.columnAlign(int column, Fl_Align align); * ===================================================== * * These methods get or set the value of variable controlling * the alignment of the specified column. */ Fl_Align Table::columnAlign(int column) const { if ((column < 0) && (column >= nCols)) return (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP); /* NOT REACHED */ return header[column].align; } void Table::columnAlign(int column, Fl_Align align) { if ((column < 0) && (column >= nCols)) return; /* NOT REACHED */ header[column].align = (Fl_Align)(align | FL_ALIGN_CLIP); redraw(); } /* * ===================================================== * int Table.columnWidth(int column); * void Table.columnWidth(int column, int width); * ===================================================== * * These methods get or set the value of variable controlling * the width of the specified column. */ int Table::columnWidth(int column) const { if ((column < 0) && (column >= nCols)) return 0; /* NOT REACHED */ return header[column].width; } void Table::columnWidth(int column, int width) { if ((column < 0) && (column >= nCols)) return; /* NOT REACHED */ header[column].width = width; dimensionsChanged = true; redraw(); } /* * ======================================================== * const char *Table.columnTitle(int column); * void Table.columnTitle(int column, const char *title); * ======================================================== * * These methods get or set the value of variable controlling * the width of the specified column. */ const char *Table::columnTitle(int column) { if ((column < 0) && (column >= nCols)) return NULL; /* NOT REACHED */ return header[column].title; } void Table::columnTitle(int column, const char *title) { if ((column < 0) && (column >= nCols)) return; /* NOT REACHED */ free((void*)header[column].title); header[column].title = strdup(title); damage(DAMAGE_HEADER); } /* * =================== * int Table.rows(); * =================== * * Returns the number of rows in table. */ int Table::rows() { return nRows; } /* * ====================== * int Table.columns(); * ====================== * * Returns the number of columns in table. */ int Table::columns() { return nCols; } /* * ================================== * void Table.value(int selection); * ================================== * * Sets the currently selected row. */ void Table::value(int selection) { if ((selection >= -1) && (selection < nRows)) selected = selection; damage(DAMAGE_ROWS); } /* * ==================== * int Table.value(); * ==================== * * Returns the number of the currently selected row. */ int Table::value() { return selected; } /* * ==================================================================== * void Table.addColumn(const char *label, int width, Fl_Align align); * ==================================================================== * * Adds column with label as title, width and align as * sort function. */ void Table::addColumn(const char *label, int width, Fl_Align align) { if (!noMoreColumns) { struct ColumnInfo col; dimensionsChanged = true; col.title = strdup(label); col.width = width; col.align = (Fl_Align)(align | FL_ALIGN_CLIP); header.push_back(col); nCols++; } } /* * ================================= * void Table.addCell(char *data); * ================================= * * Adds a cell with data to the table. */ void Table::addCell(const char *data) { if (!noMoreColumns) noMoreColumns = true; if ((cPos >= nCols) || (curRow == NULL)) { this->data.push_back(curRow = new char*[nCols]); for(int i = 0; i < nCols; i++) curRow[i] = NULL; dimensionsChanged = true; nRows++; cPos = 0; } if (data != NULL) curRow[cPos] = strdup(data); else curRow[cPos] = strdup(""); if (cPos == sortColumn) toBeSorted = true; cPos++; } /* * ================================ * void Table.removeRow(int row); * ================================ * * Removes row referenced by row. */ void Table::removeRow(int row) { if ((row == -1) && (selected >= 0)) row = selected; if ((row >= 0) && (row < nRows)) { char **rowData = data[row]; if (rowData == curRow) curRow = NULL; for (int i = 0; i < nCols; i++) free(rowData[i]); delete[] rowData; data.erase(row); nRows--; dimensionsChanged = true; toBeSorted = true; selected = -1; } } /* * ======================================= * void Table.clear(bool removeColumns); * ======================================= * * Frees all data in table. If removeColumns is true, frees also header * structures. */ void Table::clear(bool removeColumns) { nRows = 0; curRow = NULL; cPos = 0; // Delete row data. char **row; for (int j = 0; j < data.size(); ++j) { row = data[j]; for (int i = 0; i < nCols; i++) free(row[i]); delete[] row; } data.clear(); if (removeColumns) { // Delete header data. for (int i = 0; i < header.size(); ++i) free((void*)header[i].title); header.clear(); nCols = 0; } selected = -1; noMoreColumns = false; dimensionsChanged = true; } /* * ============================================ * char *Table.valueAt(int row, int column); * ============================================ * * Returns value in cell referenced by row and column. */ char *Table::valueAt(int row, int column) { if ((row >= 0) && (row < nRows) && (column >= 0) && (column < nCols)) return data[row][column]; else if ((row == -1) && (selected >= 0) && (column >= 0) && (column < nCols)) return data[selected][column]; else return NULL; } /* * ====================================================== * void Table.valueAt(int row, int column, char *data); * ====================================================== * * Sets alue in cell referenced by row and column. */ void Table::valueAt(int row, int column, char *data) { if ((row == -1) && (selected >= 0)) row = selected; if ((row >= 0) && (row < nRows) && (column >= 0) && (column < nCols)) { if (column == sortColumn) toBeSorted = true; if (this->data[row][column] != NULL) free(this->data[row][column]); this->data[row][column] = strdup(data); } } /* * ===================================== * const char **Table.getRow(int row); * ===================================== * * Returns pointer to the data of the row number row. */ const char **Table::getRow(int row) { if ((row == -1) && (selected >= 0)) row = selected; if ((row >= 0) && (row < nRows)) return (const char**)data[row]; else return NULL; } /* * ================================================================ * Table.where(int x, int y, int &row, int &column, int &resize); * ================================================================ * * Finds corresponding row and column for x and y coordinates. This function * uses Fl::event_inside() method. * * row = -1 means header and row = -2 means that coordinates don't * correspond any cell. */ void Table::where(int x, int y, int &row, int &column, int &resize) { int temp, temp2; // Inside the header if ((nCols > 0) && headerEnabled && Fl::event_inside(oX, oY, iW, headerHeight)) { row = -1; temp = leftColX + iX - hScroll->value(); // Scan visible columns until found one that matches. for (column = leftCol; column <= rightCol; column++ ) { temp2 = temp; // Near the left border of the column header if ((x >= temp) && (x <= temp + 3)) { resize = 1; return; /* NOT REACHED */ } // Near the right border of the column header else if ((x >= (temp += header[column].width) - 3) && (x < temp)) { resize = 2; return; /* NOT REACHED */ } // Somewhere else else if ((x >= temp2) && (x < temp)) { resize = 0; return; /* NOT REACHED */ } } } // Header /* * Now the harder one. X and Y lie somewhere in the table. * Find correct row and column. */ else if ((nRows > 0) && Fl::event_inside(iX, iY, iW, iH)) { temp = topRowY; int yMod = iY - vScroll->value(); int leftX = leftColX + iX - hScroll->value(); // Scan rows for (row = topRow; row <= bottomRow; row++) { int temp2 = leftX; for (column = leftCol; column <= rightCol; column++) { if (Fl::event_inside(temp2, temp + yMod, header[column].width, rowHeight)) return; /* NOT REACHED */ temp2 += header[column].width; } temp += rowHeight; } } row = column = -2; } /* * ============================== * int Table.handle(int event); * ============================== * * FLTK internal. Handles incoming events. */ int Table::handle(int event) { int ret = 0; int row, column, resize; if (event != FL_KEYDOWN) ret = Fl_Group::handle(event); /* * MAIN SWITCH */ switch (event) { /* * PUSH event */ case FL_PUSH: // Test if pushed on scrollbars. if (vScroll->visible() && Fl::event_inside(vScroll->x(), vScroll->y(), vScroll->w(), vScroll->h())) break; if (hScroll->visible() && Fl::event_inside(hScroll->x(), hScroll->y(), hScroll->w(), hScroll->h())) break; // Which row/column are we over? where(Fl::event_x(), Fl::event_y(), row, column, resize); switch (row) { // Push on nothing... Not interested case -2: if (selected != -1) { selected = -1; damage(DAMAGE_ROWS); } break; // Push on header. case -1: if ((canResize) && (Fl::event_button() == FL_LEFT_MOUSE) && (resize != 0)) { resizing = (resize == 1) ? column - 1 : column; dragX = Fl::event_x(); ret = 1; } else if ((canSort) && (Fl::event_button() == FL_LEFT_MOUSE)) { pushed = column; damage(DAMAGE_HEADER); ret = 1; } break; // Push on cell. default: bool changed = selected != row; selected = row; // Create new selection char **tableRow = data[selected]; int col; // size: (nCols - 1) tabs + \0 int selsize = strlen(tableRow[0]) + nCols; for (col = 1; col < nCols; col++) { if (tableRow[col] != NULL) selsize += strlen(tableRow[col]); } char *selection = new char[selsize]; strcpy(selection, tableRow[0]); for (col = 1; col < nCols; col++) { strcat(selection, "\t"); if (tableRow[col] != NULL) strcat(selection, tableRow[col]); } Fl::selection(*this, selection, selsize); delete[] selection; // Update view. damage(DAMAGE_ROWS); take_focus(); // Callback if ((Fl::event_clicks() != 0) && !changed && (when() & TABLE_WHEN_DCLICK)) { Fl::event_is_click(0); do_callback(); } else if (changed && (when() & FL_WHEN_CHANGED)) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); ret = 1; break; } // switch(row) break; /* * DRAG event */ case FL_DRAG: // Resizing... if (resizing > -1 ) { int offset = dragX - Fl::event_x(); int newWidth = header[resizing].width - offset; // Width must be at least 1. if (newWidth < 1) newWidth = 1; // Test if column really is resized. if (header[resizing].width != newWidth) { header[resizing].width = newWidth; dragX = Fl::event_x(); resized(); redraw(); } ret = 1; } break; /* * RELEASE event */ case FL_RELEASE: // Which row/column are we over? where(Fl::event_x(), Fl::event_y(), row, column, resize); // Restore cursor and end resizing. if (Fl::event_button() == FL_LEFT_MOUSE) { fl_cursor(FL_CURSOR_DEFAULT, labelcolor(), color()); if ((pushed == column) && canSort) { if (sortColumn != pushed) { sortColumn = pushed; ascent = true; } else ascent = !ascent; sort(); redraw(); } pushed = -1; resizing = -1; ret = 1; } // Callback. if ((row >= 0) && (when() & FL_WHEN_RELEASE)) do_callback(); break; /* * MOVE event */ case FL_MOVE: // Which row/column are we over? where(Fl::event_x(), Fl::event_y(), row, column, resize); // If near header boundary. if ((row == -1) && canResize && resize) fl_cursor(FL_CURSOR_WE, labelcolor(), color()); else fl_cursor(FL_CURSOR_DEFAULT, labelcolor(), color()); ret = 1; break; case FL_ENTER: case FL_LEAVE: if (event == FL_LEAVE) fl_cursor(FL_CURSOR_DEFAULT, labelcolor(), color()); ret = 1; break; case FL_FOCUS: if ((nRows > 0) && (selected < 0)) selected = 0; case FL_UNFOCUS: if (Fl::visible_focus()) { damage(DAMAGE_ROWS); ret = 1; } break; /* * KEYDOWN event */ case FL_KEYDOWN: switch(Fl::event_key()) { case FL_Enter: if ((selected > -1) && (when() & TABLE_WHEN_DCLICK) || (when() & FL_WHEN_ENTER_KEY)) do_callback(); ret = 1; break; case FL_Up: // Does it make sense to move up? if (selected > 0) { selected--; // Is scrolling needed if ((selected < topRow) || (selected > bottomRow)) scrollTo(rowHeight * selected); else damage(DAMAGE_ROWS); // Callback if (when() & FL_WHEN_CHANGED) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); } ret = 1; break; case FL_Down: // Does it make sense to move down? if ((selected >= 0) && (selected < (nRows - 1))) { selected++; // Scroll if needed if ((selected >= bottomRow) || (selected < topRow)) scrollTo(rowHeight * (selected + 1) - iH); else damage(DAMAGE_ROWS); // Callback if (when() & FL_WHEN_CHANGED) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); } ret = 1; break; case FL_Page_Up: // Does it make sense to move up? if (selected > 0) { // Number of rows on the 'page' int step = iH / rowHeight; // Change selection if (selected >= step) selected -= step; else selected = 0; // Scroll if needed if ((selected < topRow) || (selected > bottomRow)) scrollTo(selected * rowHeight); else damage(DAMAGE_ROWS); // Callback if (when() & FL_WHEN_CHANGED) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); } ret = 1; break; case FL_Page_Down: // Does it make sense to move down? if ((selected >= 0) && (selected < (nRows - 1))) { // Number of rows on the 'page' int step = iH / rowHeight; // Change selection if ((selected += step) > nRows) selected = nRows - 1; // Scroll if needed if ((selected >= bottomRow) || (selected < topRow)) scrollTo(rowHeight * (selected + 1) - iH); else damage(DAMAGE_ROWS); // Callback if (when() & FL_WHEN_CHANGED) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); } ret = 1; break; case FL_Home: // Does it make sense to move up? if ((selected > 0) && (nRows > 0)) { selected = 0; scrollTo(0); damage(DAMAGE_ROWS); // Callback if (when() & FL_WHEN_CHANGED) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); } ret = 1; break; case FL_End: // Does it make sense to move down? if ((selected >= 0) && (nRows > 0)) { selected = nRows - 1; scrollTo(rowHeight * (selected + 1) - iH); damage(DAMAGE_ROWS); // Callback if (when() & FL_WHEN_CHANGED) do_callback(); else if (when() & FL_WHEN_NOT_CHANGED) do_callback(); } ret = 1; break; } break; } return ret; } /* * =============================== * void Table.scrollTo(int pos); * =============================== * * Scrolls table to given position. */ void Table::scrollTo(int pos) { if (!vScroll->visible()) { damage(DAMAGE_ROWS); return; /* NOT REACHED */ } int max = (int)vScroll->Fl_Valuator::maximum(); if (pos < 0) pos = 0; else if (pos > max) pos = max; vScroll->Fl_Valuator::value(pos); scrolled(); damage(DAMAGE_ROWS); } /* * =========================================== * void Table.sort(int column, bool ascent); * =========================================== * * Sets sortColumn and ascent and sorts table. Does not redraw. */ void Table::sort(int column, bool ascent) { if ((column < -1) || (column >= nCols)) return; sortColumn = column; this->ascent = ascent; sort(); } void Table::aSort(int start, int end) { int i, j; const char *x; char **temp; x = data[(start + end) / 2][sortColumn]; i = start; j = end; for (;;) { while ((i < end) && (stringcompare(data[i][sortColumn], x) < 0)) i++; while ((j > 0) && (stringcompare(data[j][sortColumn], x) > 0)) j--; while ((i < end) && (i != j) && (stringcompare(data[i][sortColumn], data[j][sortColumn]) == 0)) i++; if (i == j) break; temp = data[i]; data[i] = data[j]; data[j] = temp; } if (start < --i) aSort(start, i); if (end > ++j) aSort(j, end); } void Table::dSort(int start, int end) { int i, j; const char *x; char **temp; x = data[(start + end) / 2][sortColumn]; i = start; j = end; for (;;) { while ((i < end) && (stringcompare(data[i][sortColumn], x) > 0)) i++; while ((j > 0) && (stringcompare(data[j][sortColumn], x) < 0)) j--; while ((i < end) && (i != j) && (stringcompare(data[i][sortColumn], data[j][sortColumn]) == 0)) i++; if (i == j) break; temp = data[i]; data[i] = data[j]; data[j] = temp; } if (start < --i) dSort(start, i); if (end > ++j) dSort(j, end); } /* * ==================== * void Table.sort(); * ==================== * * Sorts table according sortColumn and ascent. Does not redraw. */ void Table::sort() { if ((sortColumn == -1) || !canSort) return; /* NOT REACHED */ toBeSorted = false; // Sort in descending order. if ((nRows > 1) && ascent) aSort(0, nRows - 1); // Sort in ascending order. else if (nRows > 1) dSort(0, nRows - 1); } /* * ==================================================== * void Table.getSort(int &sortColumn, bool &ascent); * ==================================================== * * Set sortColumn and ascent according to current sort policy. */ void Table::getSort(int &sortColumn, bool &ascent) { sortColumn = this->sortColumn; ascent = this->ascent; } /* * ==================== * void Table.draw(); * ==================== * * FLTK internal. Called when Table widget needs to be drawn. */ void Table::draw() { int damage; if (dimensionsChanged) { dimensionsChanged = false; resized(); } if (toBeSorted) sort(); damage = Fl_Widget::damage(); // Draw children. if (damage & (FL_DAMAGE_ALL | FL_DAMAGE_CHILD)) { fl_push_clip(oX, oY, oW, oH); Fl_Group::draw(); fl_pop_clip(); } // Draw box. if (damage & FL_DAMAGE_ALL) { // Draw box. draw_box(box(), x(), y(), w(), h(), FL_GRAY); // Draw label. draw_label(); } // Draw header. int xPos = leftColX + iX - hScroll->value(); if (headerEnabled && (damage & (FL_DAMAGE_ALL | DAMAGE_HEADER)) && (nCols > 0)) { fl_push_clip(iX, oY, iW, headerHeight); drawHeader(xPos, oY); fl_pop_clip(); } // Draw all the cells. if ((damage & (FL_DAMAGE_ALL | DAMAGE_ROWS)) && (nRows > 0) && (nCols > 0)) { fl_push_clip(iX, iY, iW, iH); int yMod = iY - vScroll->value(); for (int row = topRow, rowY = topRowY; row <= bottomRow; row++, rowY += rowHeight) drawRow(row, data[row], xPos, rowY + yMod); fl_pop_clip(); } fl_push_clip(oX, oY, oW, oH); // Table height smaller than window? Fill remainder with rectangle if (tableWidth < iW) fl_rectf(iX + tableWidth, oY, iW - tableWidth, oH, FL_GRAY); if (tableHeight < iH) fl_rectf(iX, iY + tableHeight, iW, iH - tableHeight, FL_GRAY); // Both scrollbars? Draw little box in lower right if (vScroll->visible() && hScroll->visible()) fl_rectf(vScroll->x(), hScroll->y(), vScroll->w(), hScroll->h(), FL_GRAY); fl_pop_clip(); } /* * ================================================ * void Table.resize(int x, int y, int w, int h); * ================================================ * * FLTK internal. Called when Table widget is resized. */ void Table::resize(int x, int y, int w, int h) { Fl_Widget::resize(x, y, w, h); resized(); damage(FL_DAMAGE_ALL); } /* * ============================== * void Table.calcDimensions(); * ============================== * * Calculates table dimensions. */ void Table::calcDimensions() { // Calculate width and height of the table (in pixels). tableWidth = 0; for (int i = 0; i < nCols; i++) tableWidth +=header[i].width; tableHeight = nRows * rowHeight; Fl_Boxtype b; iX = oX = x() + Fl::box_dx(b = box()); iY = oY = y() + Fl::box_dy(b); iW = oW = w() - Fl::box_dw(b); iH = oH = h() - Fl::box_dh(b); // Trim inner size if header enabled. if (headerEnabled) { iY += headerHeight; iH -= headerHeight; } // Hide scrollbars if window is large enough int hideV = (tableHeight <= iH), hideH = (tableWidth <= iW); if (!hideH & hideV) hideV = (tableHeight - iH - scrollbarSize) <= 0; if (!hideV & hideH) hideH = (tableWidth - iW + scrollbarSize) <= 0; if (hideV) { vScroll->hide(); vScroll->Fl_Valuator::value(0); } else { vScroll->show(); iW -= scrollbarSize; } if (hideH) { hScroll->hide(); hScroll->Fl_Valuator::value(0); } else { hScroll->show(); iH -= scrollbarSize; } } /* * ======================== * void Table.scrolled(); * ======================== * * Calculates visible are after scroll or adding data. */ void Table::scrolled() { int y, row, voff = vScroll->value(); // First visible row row = voff / rowHeight; topRow = (row >= nRows) ? (nRows - 1) : row; if ((y = topRow * rowHeight) > voff) { topRow--; y -= rowHeight; } topRowY = y; // Last visible row row = (voff + iH) / rowHeight; bottomRow = (row >= nRows) ? (nRows - 1) : row; // First visible column int x, col, h = hScroll->value(); for (col = x = 0; col < nCols; col++) { x += header[col].width; if (x >= h) { x -= header[col].width; break; } } leftCol = (col >= nCols) ? (nCols - 1) : col; leftColX = x; // Last visible column h += iW; for (; col < nCols; col++) { x += header[col].width; if (x >= h) break; } rightCol = (col >= nCols) ? (nCols - 1) : col; } /* * ======================= * void Table.resized(); * ======================= * * Calculates scrollbar properties after resizing or adding data. */ void Table::resized() { calcDimensions(); // Calculate properties for vertical scrollbar. if (vScroll->visible()) { vScroll->bounds(0, tableHeight - iH); vScroll->resize(oX + oW - scrollbarSize, oY, scrollbarSize, oH - (hScroll->visible() ? scrollbarSize : 0)); vScroll->Fl_Valuator::value(vScroll->clamp(vScroll->value())); vScroll->slider_size(iH > tableHeight ? 1 : (float)iH / tableHeight); } // Calculate properties for horizontal scrollbar. if (hScroll->visible()) { hScroll->bounds(0, tableWidth - iW); hScroll->resize(oX, oY + oH - scrollbarSize, oW - (vScroll->visible() ? scrollbarSize : 0), scrollbarSize); hScroll->Fl_Valuator::value(hScroll->clamp(hScroll->value())); hScroll->slider_size(iW > tableWidth ? 1 : (float)iW / tableWidth); } scrolled(); dimensionsChanged = false; } /* * =========================================================== * void Table.scrollCallback(Fl_Widget *widget, void *data); * =========================================================== * * Internal callback for scrollbars. Scrolls view. */ void Table::scrollCallback(Fl_Widget *widget, void *data) { Table *me = (Table*)data; me->scrolled(); if (widget == me->vScroll) me->damage(DAMAGE_ROWS); else me->damage(DAMAGE_ROWS | DAMAGE_HEADER); } void Table::labelsize(uchar s) { Fl_Group::labelsize(s); headerHeight = labelsize(); rowHeight = labelsize() - 1; scrollbarSize = labelsize() - 3; } #|-------------------- 1.27 |# "./Table.h" 5473 /* Copyright (c) 2004 Markus Niemistö Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Modified by Sergey Khorev to get rid of overkilling STL stuff * Some reformatting was done * Get rid of unneeded stuff * Added binding to system colors */ #ifndef __TABLE_HH #define __TABLE_HH #include #include #include #include #include #define TABLE_WHEN_DCLICK 16 // very simple replacement to STL vector // even doesn't call destructors on its items template class minivector { T *_data; size_t _size; // size size_t _asize; // allocated size public: minivector() : _data (0), _size(0), _asize(0) {} ~minivector() { free(_data); } T& operator[] (size_t i) { return _data[i]; } const T& operator[] (size_t i) const { return _data[i]; } size_t erase(size_t i) { if (i < _size - 1) memmove(_data + i, _data + i + 1, (_size - i - 1) * sizeof(T)); --_size; if (_size * 2 < _asize && _asize > 2) { _asize /= 2; _data = (T *)realloc(_data, _asize); } return i; } size_t size() { return _size; } void push_back(const T &t) { if (_asize == _size) { if (_asize == 0) _asize = 2; else _asize *= 2; // double allocated size _data = (T *)realloc(_data, _asize* sizeof(T)); } _data[_size++] = t; } void clear() { _asize = _size = 0; free(_data); _data = 0; } }; class Table : public Fl_Group { private: struct ColumnInfo { const char *title; int width; Fl_Align align; }; // Scrollbars Fl_Scrollbar *hScroll, *vScroll; // Column data minivector header; // Cell data minivector data; // Table dimensions int tableHeight, tableWidth; int oX, oY, oW, oH; // Outer dimensions (widget - box) int iX, iY, iW, iH; /* * Table area dimensions * (outer dimension - header - scrollbars) */ // For optimization int topRow, bottomRow, leftCol, rightCol; int topRowY, leftColX; int nCols, nRows; // Number of rows and columns int cPos; // Column where new entry is added. int resizing, dragX; int pushed; int sortColumn; // Object sizes int scrollbarSize; int headerHeight; int rowHeight; int selected; char **curRow; // Various flags bool ascent; bool canResize, canSort; bool noMoreColumns; bool toBeSorted; bool dimensionsChanged; bool headerEnabled; void dSort(int start, int end); void aSort(int start, int end); protected: virtual int handle(int event); virtual void drawHeader(int x, int y); virtual void drawRow(int row, char *rowData[], int x, int y); virtual void draw(); virtual void resize(int x, int y, int w, int h); void calcDimensions(); void scrolled(); void resized(); static void scrollCallback(Fl_Widget *widget, void *data); public: Table(int x, int y, int w, int h, char *label = NULL); ~Table(); bool headerOn() const; void headerOn(bool enabled); bool allowResize() const; void allowResize(bool allow); bool allowSort() const; void allowSort(bool allow); int headerSize() const; void headerSize(int height); int rowSize() const; void rowSize(int height); int scrollbSize() const; void scrollbSize(int size); Fl_Align columnAlign(int column) const; void columnAlign(int column, Fl_Align align); int columnWidth(int column) const; void columnWidth(int column, int width); const char *columnTitle(int column); void columnTitle(int column, const char *title); void sort(); void sort(int column, bool ascent); void getSort(int &sortColumn, bool &ascent); void addColumn(const char *label, int width = 150, Fl_Align align = (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP)); void addCell(const char *data); void removeRow(int row); void clear(bool removeColumns = false); void where(int x, int y, int &row, int &column, int &resize); void scrollTo(int pos); int columns(); int rows(); void value(int selection); int value(); char *valueAt(int row, int column); void valueAt(int row, int column, char *data); const char **getRow(int row); uchar labelsize() const { return Fl_Group::labelsize(); } void labelsize(uchar); }; #endif #|-------------------- 1.27 |# "./bb.setup" 1784 ;;;; bb.setup -*- Scheme -*- (define (missing) (error "Sorry, FLTK (http://www.fltk.org) must be installed to use this extension") ) (case (build-platform) [(mingw32) (let ((flu (getenv "FLU"))) (make/proc (list (list "bb-support.o" '("bb-support.cpp" "bb.h") (lambda () (run (g++ -Os -fomit-frame-pointer -c -DWIN32 -mwindows -mno-cygwin ,(if flu (string-append "-DBB_USE_FLU -I" flu) "") bb-support.cpp)) (run (g++ -Os -fomit-frame-pointer -c -DWIN32 -mwindows -mno-cygwin Table.cxx)) ) ) ) "bb-support.o") (run (csc bb.scm -s -O3 -d1 -J -L "\"bb-support.o Table.o -lfltk\"" -L "\"-lfltk_images -lfltk_gl -lfltk_jpeg -lfltk_png -lfltk_z\"" -L "\"-luser32 -lopengl32 -lgdi32 -lole32 -luuid -lcomctl32\"" -L "\"-lwsock32 -lshell32 -ladvapi32\"" -lfltk -lole32 -luuid -lcomctl32 -lwsock32 ,(if flu (string-append "-L \"-L" flu "/lib -lflu\"") "") -ld g++) ) )] [else (let ([has-flu? (zero? (system "flu-config --cxxflags >/dev/null"))]) (make/proc (list (list "bb-support.o" '("bb-support.cpp" "bb.h") (lambda () (run (g++ -g -fPIC -c ,(if has-flu? " `flu-config --cxxflags` -DBB_USE_FLU " "") " `fltk-config --cflags` " bb-support.cpp)) (run (g++ -g -fPIC -c " `fltk-config --cflags` " Table.cxx)) ) ) ) "bb-support.o") (run (csc bb.scm -s -O3 -J -d1 -L "\"bb-support.o Table.o `fltk-config --use-images --use-gl --ldflags --libs`\"" ,(if has-flu? "-L \"`flu-config --ldflags`\" -L \"`flu-config --libs`\" " "") -ld g++) ) ) ] ) (compile -s -O3 -d0 bb.import.scm) (install-extension 'bb '("bb.so" "bb.import.so") `((version 1.27))) ;;; vim: ft=scheme #|-------------------- 1.27 |# "./bb.h" 7730 /* bb.h */ #define WIDGET_RESOURCE_MAX 2 #define WRES_LABEL 0 #define WRES_TOOLTIP 1 enum { BB_WINDOW, BB_DOUBLEWINDOW, BB_BUTTON, BB_RETURNBUTTON, BB_CHECKBOX, BB_CHOICEBUTTON, BB_MENUBUTTON, BB_ENTRY, BB_EDIT, BB_INTENTRY, BB_FLOATENTRY, BB_COUNTER, BB_DIAL, BB_LABEL, BB_SLIDER, BB_ADJUSTER, BB_ROLLER, BB_LIST, BB_RADIOBUTTON, BB_MENUBAR, BB_PROGRESS, BB_TABS, BB_GROUP, BB_TILE, BB_PACK, BB_SCROLL, BB_LIGHTBUTTON, BB_GLWINDOW, BB_CLOCK, BB_LIVEIMAGE, BB_TREE, BB_TEXTEDITOR, BB_TABLE, BB_HTMLVIEW }; enum { BB_X, BB_Y, BB_WIDTH, BB_HEIGHT, BB_TEXT, BB_VALUE, BB_BOX, BB_TYPE, BB_RESIZABLE, BB_MODAL, BB_DIRECTION, BB_COLOR, BB_FOCUS, BB_RESIZABLEWIDGET, BB_MAXIMUM, BB_MINIMUM, BB_LABELCOLOR, BB_LABELSIZE, BB_LABELFONT, BB_SPACING, BB_POSITION, BB_XPOSITION, BB_YPOSITION, BB_TEXTCOLOR, BB_TEXTSIZE, BB_TEXTFONT, BB_SELECTIONCOLOR, BB_TOOLTIP, BB_VISIBLE, BB_MARK, BB_READONLY, BB_WHEN, BB_VALIDCONTEXT, BB_CALLBACK, BB_IMAGE, BB_IMAGEWIDTH, BB_IMAGEHEIGHT, BB_SIZE, BB_ALIGN, BB_HANDLER, BB_CALLBACK_REASON, // for Tree BB_CALLBACK_NODE }; /* flags for item-properties */ enum { BB_ROOT = -1, BB_BRANCH = -2, BB_LEAF = -3, BB_CONNECTOR = -4 }; enum { BB_GRAY0 = 32, // 'A' BB_DARK3 = 39, // 'H' BB_DARK2 = 45, // 'N' BB_DARK1 = 47, // 'P' BB_LIGHT1 = 50, // 'S' BB_LIGHT2 = 52, // 'U' BB_LIGHT3 = 54, // 'W' BB_GRAY = 49, BB_BLACK = 56, BB_RED = 88, BB_GREEN = 63, BB_YELLOW = 95, BB_BLUE = 216, BB_MAGENTA = 248, BB_CYAN = 223, BB_DARK_RED = 72, BB_DARK_GREEN = 60, BB_DARK_YELLOW = 76, BB_DARK_BLUE = 136, BB_DARK_MAGENTA = 152, BB_DARK_CYAN = 140, BB_WHITE = 255 }; #define BB_NORMAL_DIAL 0 #define BB_LINE_DIAL 1 #define BB_FILL_DIAL 2 enum { BB_VERTICAL, BB_HORIZONTAL, BB_VERT_FILL_SLIDER, BB_HOR_FILL_SLIDER, BB_VERT_NICE_SLIDER, BB_HOR_NICE_SLIDER }; enum { BB_NO_BOX, BB_FLAT_BOX, BB_UP_BOX, BB_DOWN_BOX, BB_UP_FRAME, BB_DOWN_FRAME, BB_THIN_UP_BOX, BB_THIN_DOWN_BOX, BB_THIN_UP_FRAME, BB_THIN_DOWN_FRAME, BB_ENGRAVED_BOX, BB_EMBOSSED_BOX, BB_ENGRAVED_FRAME, BB_EMBOSSED_FRAME, BB_BORDER_BOX }; enum { BB_MESSAGE, BB_ALERT, BB_ASK, BB_CHOICE }; enum { BB_SCROLL_HORIZONTAL = 1, BB_SCROLL_VERTICAL = 2, BB_SCROLL_BOTH = 3, BB_SCROLL_ALWAYS_ON = 4, BB_SCROLL_HORIZONTAL_ALWAYS = 5, BB_SCROLL_VERTICAL_ALWAYS = 6, BB_SCROLL_BOTH_ALWAYS = 7 }; enum { BB_HELVETICA = 0, BB_HELVETICA_BOLD, BB_HELVETICA_ITALIC, BB_HELVETICA_BOLD_ITALIC, BB_COURIER, BB_COURIER_BOLD, BB_COURIER_ITALIC, BB_COURIER_BOLD_ITALIC, BB_TIMES, BB_TIMES_BOLD, BB_TIMES_ITALIC, BB_TIMES_BOLD_ITALIC, BB_SYMBOL, BB_SCREEN, BB_SCREEN_BOLD }; enum { BB_CENTER = 0, BB_TOP = 1, BB_BOTTOM = 2, BB_LEFT = 4, BB_RIGHT = 8, BB_INSIDE = 16, BB_TEXT_OVER_IMAGE = 32, BB_IMAGE_OVER_TEXT = 0, BB_CLIP = 64, BB_WRAP = 128 }; enum { BB_WHEN_NEVER = 0, BB_WHEN_CHANGED = 1, BB_WHEN_RELEASE = 4, BB_WHEN_RELEASE_ALWAYS= 6, BB_WHEN_ENTER_KEY = 8, BB_WHEN_NOT_CHANGED = 2 // modifier bit to disable changed() test }; #define BBMAX_SHOW_ARGS 32 /* event properties */ enum { BBE_ALT, BBE_BUTTON1, BBE_BUTTON2, BBE_BUTTON3, BBE_CLICKS, BBE_CTRL, BBE_IS_CLICK, BBE_KEY, BBE_LENGTH, BBE_SHIFT, BBE_X, BBE_Y, BBE_X_ROOT, BBE_Y_ROOT, BBE_DX, BBE_DY, BBE_TEXT }; /* keyboard codes */ enum { BB_Button = 0xfee8, // use Fl_Button + n for button n BB_BackSpace = 0xff08, BB_Tab = 0xff09, BB_Enter = 0xff0d, BB_Pause = 0xff13, BB_Scroll_Lock = 0xff14, BB_Escape = 0xff1b, BB_Home = 0xff50, BB_Left = 0xff51, BB_Up = 0xff52, BB_Right = 0xff53, BB_Down = 0xff54, BB_Page_Up = 0xff55, BB_Page_Down = 0xff56, BB_End = 0xff57, BB_Print = 0xff61, BB_Insert = 0xff63, BB_Menu = 0xff67, // the "menu/apps" key on XFree86 BB_Help = 0xff68, // the 'help' key on Mac keyboards BB_Num_Lock = 0xff7f, BB_KP = 0xff80, // use FL_KP+'x' for 'x' on numeric keypad BB_KP_Enter = 0xff8d, // same as Fl_KP+'\r' BB_KP_Last = 0xffbd, // use to range-check keypad BB_F = 0xffbd, // use FL_F+n for function key n BB_F_Last = 0xffe0, // use to range-check function keys BB_Shift_L = 0xffe1, BB_Shift_R = 0xffe2, BB_Control_L = 0xffe3, BB_Control_R = 0xffe4, BB_Caps_Lock = 0xffe5, BB_Meta_L = 0xffe7, // the left MSWindows key on XFree86 BB_Meta_R = 0xffe8, // the right MSWindows key on XFree86 BB_Alt_L = 0xffe9, BB_Alt_R = 0xffea, BB_Delete = 0xffff }; /* callback reasons */ enum { BB_HILIGHTED, BB_UNHILIGHTED, BB_SELECTED, BB_UNSELECTED, BB_OPENED, BB_CLOSED, BB_DOUBLE_CLICK, BB_WIDGET_CALLBACK, BB_MOVED_NODE, BB_NEW_NODE, BB_NOTHING }; BBEXPORT double BBStart(char *); BBEXPORT void BBStop(); BBEXPORT void *BBCreateWidget(int type, int x, int y, int w, int h); BBEXPORT ___safe void BBDestroyWidget(WIDGET widget); BBEXPORT ___safe void BBSetIntProperty(WIDGET widget, int item, int property, int value); BBEXPORT ___safe void BBSetDoubleProperty(WIDGET widget, int property, double value); BBEXPORT ___safe void BBSetStringProperty(WIDGET widget, int item, int item2, int property, char *value); BBEXPORT int BBGetIntProperty(WIDGET widget, int item, int property); BBEXPORT double BBGetDoubleProperty(WIDGET widget, int property); BBEXPORT char *BBGetStringProperty(WIDGET widget, int item, int item2, int property); BBEXPORT ___safe int BBRunEventLoop(___bool wait, double secs); BBEXPORT ___safe void BBShowWindow(WIDGET widget, int argc); BBEXPORT void BBRedrawWidget(WIDGET widget); BBEXPORT void BBBeginGroup(WIDGET widget); BBEXPORT void BBEndGroup(WIDGET widget); BBEXPORT void *BBPixmap(void *xpm); BBEXPORT void BBSetImage(WIDGET widget, int item, void *img); BBEXPORT void BBSetImage2(WIDGET widget, int item, void *iclosed, void *iopen); BBEXPORT void BBAddItem(WIDGET widget, char *str, int pos); BBEXPORT int BBAddTreeItem(WIDGET tree, char *text, int parent, int pos, WIDGET widget); BBEXPORT void BBRemoveItem(WIDGET widget, int n); BBEXPORT int BBMessage(int type, char *text, char *c1, char *c2, char *c3); BBEXPORT char *BBSelectFile(char *message, char *pattern, char *fname); BBEXPORT char *BBSelectDir(char *message, char *fname); BBEXPORT void BBSetWidgetProperty(WIDGET w1, int property, WIDGET w2); BBEXPORT void BBRemoveAllItems(WIDGET widget); BBEXPORT void BBAddWidget(WIDGET w, WIDGET c); BBEXPORT unsigned long BBRGB(int r, int g, int b); BBEXPORT char *BBGetSelection(WIDGET widget); BBEXPORT void *BBLoadImage(char *name); BBEXPORT void *BBRawImage(void *data, int w, int h, int d); BBEXPORT void BBRemoveImage(void *img); BBEXPORT int BBSelectColor(char *title, unsigned char *rgb); BBEXPORT int BBSelectColorIndex(int col); BBEXPORT char *BBGetInput(char *label, char *def); BBEXPORT void BBActivateMenuItem(WIDGET m, int index, ___bool flag); BBEXPORT int BBGetEventInt(int event); BBEXPORT ___bool BBGetEventBool(int event); BBEXPORT char *BBGetEventString(int event); BBEXPORT void BBSetEventInt(int event, int val); BBEXPORT void BBSetEventBool(int event, ___bool val); BBEXPORT void BBSetArg(int i, char *a); BBEXPORT int BBImageDim(void *data, int dim); BBEXPORT void *BBImageData(void *image, int i); BBEXPORT void BBAddTableColumn(WIDGET widget, char *text); BBEXPORT void BBAddTableCell(WIDGET widget, char *text); BBEXPORT void BBSetSelection(WIDGET widget, int start, int end); #|-------------------- 1.27 |# "./bb.meta" 367 ;;; bb.meta -*- Scheme -*- ((synopsis "An easy-to-use GUI toolkit based on FLTK") (license "BSD") (category ui) (needs silex easyffi matchable) (doc-from-wiki) (author "felix winkelmann") (files "bb.setup" "bb.h" "bb.scm" "bb-support.cpp" "bb.meta" "Table.h" "tests/simple-test.scm" "tests/notes.scm" "tests/shell.scm" "tests/event-handlers.scm" "Table.cxx")) #|-------------------- 1.27 |# "./bb.scm" 34252 ;;;; bb.scm ; ; Copyright (c) 2000-2004, Felix L. Winkelmann ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following ; conditions are met: ; ; Redistributions of source code must retain the above copyright notice, this list of conditions and the following ; disclaimer. ; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following ; disclaimer in the documentation and/or other materials provided with the distribution. ; Neither the name of the author nor the names of its contributors may be used to endorse or promote ; products derived from this software without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS ; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ; POSSIBILITY OF SUCH DAMAGE. ; ; Send bugs, suggestions and ideas to: ; ; felix@call-with-current-continuation.org ; ; Felix L. Winkelmann ; Steinweg 1A ; 37130 Gleichen, OT Weissenborn ; Germany (module bb (bb:make-widget bb:make-widgets bb:property bb:widget? bb:message bb:add! bb:remove! bb:get-input bb:init bb:set-menu-item-active! bb:group bb:run bb:redraw bb:show bb:select-file bb:select-directory bb:rgb bb:image bb:select-color bb:event bb:image-data bb:root-element bb:find-element bb:find-widget bb:element-content bb:render bb:element? bb:element-widget bb:element-children bb:element-parent bb:element-id bb:element-tag bb:element-attributes) (import scheme chicken foreign) (use extras srfi-1 utils srfi-4 easyffi data-structures matchable) (foreign-parse/declare #<" (##sys#slot w 3)) ) (define bb:init (let ([initd #f]) (lambda scheme (unless initd (set! initd (bb:Start (optional scheme #f))) ) initd) ) ) (define widget-ids `((window ,bb:WINDOW) (glwindow ,bb:GLWINDOW) (double-window ,bb:DOUBLEWINDOW) (button ,bb:BUTTON) (return-button ,bb:RETURNBUTTON) (choice-button ,bb:CHOICEBUTTON) (menu-button ,bb:MENUBUTTON) (check-box ,bb:CHECKBOX) (entry ,bb:ENTRY) (edit ,bb:EDIT) (text-editor ,bb:TEXTEDITOR) (int-entry ,bb:INTENTRY) (float-entry ,bb:FLOATENTRY) (counter ,bb:COUNTER) (dial ,bb:DIAL) (label ,bb:LABEL) (slider ,bb:SLIDER) (adjuster ,bb:ADJUSTER) (roller ,bb:ROLLER) (list ,bb:LIST) (radio-button ,bb:RADIOBUTTON) (progress ,bb:PROGRESS) (tabs ,bb:TABS) (tile ,bb:TILE) (pack ,bb:PACK) (group ,bb:GROUP) (scroll ,bb:SCROLL) (clock ,bb:CLOCK) (light-button ,bb:LIGHTBUTTON) (live-image ,bb:LIVEIMAGE) (menu-bar ,bb:MENUBAR) (tree ,bb:TREE) (table ,bb:TABLE) (html-view ,bb:HTMLVIEW) ) ) (define property-ids `((x ,bb:X) (y ,bb:Y) (width ,bb:WIDTH) (height ,bb:HEIGHT) (text ,bb:TEXT) (value ,bb:VALUE) (box ,bb:BOX) (type ,bb:TYPE) (resizable ,bb:RESIZABLE) (modal ,bb:MODAL) (direction ,bb:DIRECTION) (color ,bb:COLOR) (focus ,bb:FOCUS) (callback ,bb:CALLBACK) (image ,bb:IMAGE) (when ,bb:WHEN) (spacing ,bb:SPACING) (maximum ,bb:MAXIMUM) (minimum ,bb:MINIMUM) (label-color ,bb:LABELCOLOR) (label-size ,bb:LABELSIZE) (label-font ,bb:LABELFONT) (x-position ,bb:XPOSITION) (y-position ,bb:YPOSITION) (text-color ,bb:TEXTCOLOR) (text-size ,bb:TEXTSIZE) (text-font ,bb:TEXTFONT) (selection-color ,bb:SELECTIONCOLOR) (tooltip ,bb:TOOLTIP) (visible ,bb:VISIBLE) (position ,bb:POSITION) (read-only ,bb:READONLY) (valid-context ,bb:VALIDCONTEXT) (mark ,bb:MARK) (image-width ,bb:IMAGEWIDTH) (image-height ,bb:IMAGEHEIGHT) (size ,bb:SIZE) (align ,bb:ALIGN) (handler ,bb:HANDLER) (resizable-widget ,bb:RESIZABLEWIDGET) (callback-reason ,bb:CALLBACK_REASON) (callback-node ,bb:CALLBACK_NODE) ) ) (define item-ids `((root ,bb:ROOT) (branch ,bb:BRANCH) (leaf ,bb:LEAF) (connector ,bb:CONNECTOR) ) ) (define special-bool-properties '(resizable modal visible read-only valid-context) ) (define special-int-properties '(box type direction when text-font callback-reason align label-font) ) (define special-int-property-values0 '(no-box scroll-horizontal vertical never helvetica hilighted center) ) (define value-ids `((gray0 ,bb:GRAY0) (dark3 ,bb:DARK3) (dark2 ,bb:DARK2) (dark1 ,bb:DARK1) (light1 ,bb:LIGHT1) (light2 ,bb:LIGHT2) (light3 ,bb:LIGHT3) (gray ,bb:GRAY) (black ,bb:BLACK) (red ,bb:RED) (green ,bb:GREEN) (yellow ,bb:YELLOW) (blue ,bb:BLUE) (magenta ,bb:MAGENTA) (cyan ,bb:CYAN) (dark-red ,bb:DARK_RED) (dark-green ,bb:DARK_GREEN) (dark-yellow ,bb:DARK_YELLOW) (dark-blue ,bb:DARK_BLUE) (dark-magenta ,bb:DARK_MAGENTA) (dark-cyan ,bb:DARK_CYAN) (white ,bb:WHITE) (scroll-horizontal ,bb:SCROLL_HORIZONTAL) (scroll-vertical ,bb:SCROLL_VERTICAL) (scroll-both ,bb:SCROLL_BOTH) (scroll-always-on ,bb:SCROLL_ALWAYS_ON) (scroll-horizontal-always ,bb:SCROLL_HORIZONTAL_ALWAYS) (scroll-vertical-always ,bb:SCROLL_VERTICAL_ALWAYS) (scroll-both-always ,bb:SCROLL_BOTH_ALWAYS) (vertical ,bb:VERTICAL) (horizontal ,bb:HORIZONTAL) (vertical-fill-slider ,bb:VERT_FILL_SLIDER) (horizontal-fill-slider ,bb:HOR_FILL_SLIDER) (vertical-nice-slider ,bb:VERT_NICE_SLIDER) (horizontal-nice-slider ,bb:HOR_NICE_SLIDER) (normal-dial ,bb:NORMAL_DIAL) (line-dial ,bb:LINE_DIAL) (fill-dial ,bb:FILL_DIAL) (no-box ,bb:NO_BOX) (flat-box ,bb:FLAT_BOX) (up-box ,bb:UP_BOX) (down-box ,bb:DOWN_BOX) (up-frame ,bb:UP_FRAME) (down-frame ,bb:DOWN_FRAME) (thin-up-box ,bb:THIN_UP_BOX) (thin-down-box ,bb:THIN_DOWN_BOX) (thin-up-frame ,bb:THIN_UP_FRAME) (thin-down-frame ,bb:THIN_DOWN_FRAME) (engraved-box ,bb:ENGRAVED_BOX) (embossed-box ,bb:EMBOSSED_BOX) (engraved-frame ,bb:ENGRAVED_FRAME) (embossed-frame ,bb:EMBOSSED_FRAME) (border-box ,bb:BORDER_BOX) (never ,bb:WHEN_NEVER) (changed ,bb:WHEN_CHANGED) (released ,bb:WHEN_RELEASE) (always ,bb:WHEN_NOT_CHANGED) (enter ,bb:WHEN_ENTER_KEY) (helvetica ,bb:HELVETICA) (helvetica-bold ,bb:HELVETICA_BOLD) (helvetica-italic ,bb:HELVETICA_ITALIC) (helvetica-bold-italic ,bb:HELVETICA_BOLD_ITALIC) (courier ,bb:COURIER) (courier-bold ,bb:COURIER_BOLD) (courier-italic ,bb:COURIER_ITALIC) (courier-bold-italic ,bb:COURIER_BOLD_ITALIC) (times ,bb:TIMES) (times-bold ,bb:TIMES_BOLD) (times-italic ,bb:TIMES_ITALIC) (times-bold-italic ,bb:TIMES_BOLD_ITALIC) (symbol ,bb:SYMBOL) (screen ,bb:SCREEN) (screen-bold ,bb:SCREEN_BOLD) (hilighted ,bb:HILIGHTED) (unhilighted ,bb:UNHILIGHTED) (selected ,bb:SELECTED) (unselected ,bb:UNSELECTED) (opened ,bb:OPENED) (closed ,bb:CLOSED) (double-click ,bb:DOUBLE_CLICK) (widget-callback ,bb:WIDGET_CALLBACK) (moved-node ,bb:MOVED_NODE) (new-node ,bb:NEW_NODE) (nothing ,bb:NOTHING) (center ,bb:CENTER) (top ,bb:TOP) (bottom ,bb:BOTTOM) (left ,bb:LEFT) (right ,bb:RIGHT) (inside ,bb:INSIDE) (text-over-image ,bb:TEXT_OVER_IMAGE) (image-over-text ,bb:IMAGE_OVER_TEXT) (clip ,bb:CLIP) (wrap ,bb:WRAP) ) ) (define special-int-property-values (let ([ids (lambda (s v) (cons s (find-tail (lambda (p) (eq? (car p) v)) value-ids)) ) ] ) (map ids special-int-properties special-int-property-values0) ) ) (define (property id) (or (and-let* ([a (assq id property-ids)]) (cadr a)) (error "invalid property" id) ) ) (define (item widget) (if (pair? widget) (values (car widget) (cond [(fixnum? (cadr widget)) (cadr widget)] [(assq (cadr widget) item-ids) => cadr] [else -1]) (if (and (pair? (cdr widget)) (pair? (cddr widget)) (fixnum? (caddr widget))) (caddr widget) -1) ) (values widget -1 -1) ) ) (define (property-value x) (or (and-let* ([a (assq x value-ids)]) (cadr a)) (error "invalid value specifier" x) ) ) (define (make-image x) (let ([xx (if (and (pair? x) (null? (cdr x))) (car x) x)]) (cond [(string? xx) (bb:image xx)] [(and (not (##sys#immediate? xx)) (##sys#pointer? xx)) xx] [else (error "Invalid value for image property")] ) ) ) (define (bb:set! widget prop x) (let-values ([(p) (property prop)] [(w i i2) (item widget)]) (cond [(fixnum? x) (bb:SetIntProperty w i p x)] [(symbol? x) (bb:SetIntProperty w i p (property-value x))] [(eq? x #f) (bb:SetIntProperty w i p 0)] [(eq? x #t) (bb:SetIntProperty w i p 1)] [(number? x) (bb:SetDoubleProperty w p x)] [(or (and (pair? prop) (eq? (car prop) 'image)) (eq? prop 'image)) (if (pair? x) (bb:SetImage2 w i (make-image (car x)) (make-image (cdr x))) (bb:SetImage w i (make-image x))) ] [(and (pair? prop) (eq? prop 'selection)) (bb:SetSelection w (car prop) (cdr prop)) ] [(string? x) (bb:SetStringProperty w i i2 p x)] [(widget? x) (bb:SetWidgetProperty w p x)] [(procedure? x) (if (eq? prop 'callback) (bb:SetCallback w x) (bb:SetHandler w x) ) ] [(list? x) (bb:SetIntProperty w i p (apply bitwise-ior (map property-value x)))] [(and (not (##sys#immediate? x)) (##sys#pointer? x)) (bb:SetImage w i x)] [else (error "invalid property" prop x)] ) ) ) (define (bb:get widget p0) (if (eq? p0 'selection) (bb:selection widget) (let-values ([(p) (property p0)] [(w i i2) (item widget)]) (cond [(eq? bb:TEXT p) (bb:GetStringProperty w i i2 p)] [(eq? bb:VALUE p) (cond [(eq? (widget-name w) 'html-view) (bb:GetStringProperty w i i2 p)] [(memq (widget-name w) '(radio-button check-box light-button)) (eq? 1 (bb:GetIntProperty w i p))] [(memq (widget-name w) '(list tree table)) (bb:GetIntProperty w i p)] [else (bb:GetDoubleProperty w p)] ) ] [else (let ([val (bb:GetIntProperty w i p)]) (cond [(memq p0 special-bool-properties) (not (zero? val))] [(memq p0 special-int-properties) (let ([a (find (lambda (p) (eq? (cadr p) val)) (cdr (assq p0 special-int-property-values)))]) (if a (car a) val) ) ] [else val] ) ) ] ) ) ) ) (define bb:property (getter-with-setter bb:get bb:set!)) (define (find-frames str) (let* ([frames '()] [strs (list->vector (string-split str "\n"))] [w (string-length (vector-ref strs 0))] [h (vector-length strs)] ) (define (scan-right c x0 y0) (let loop ([x x0]) (cond [(>= x w) #f] [(char=? c (at x y0)) (substring (vector-ref strs y0) x0 x) ] [else (loop (add1 x))] ) ) ) (define (at x y) (string-ref (vector-ref strs y) x)) (define (extract-frame c x1 y1) (let loop ([x x1]) (if (or (>= x w) (not (char=? c (at x y1)))) (let loop ([y y1]) (if (or (>= y h) (not (char=? c (at x1 y)))) (vector x1 y1 (- x x1) (- y y1) c '()) (loop (add1 y)) ) ) (loop (add1 x)) ) ) ) (define (scan-frame frame) (match frame [#(x0 y0 w h _ (set! update)) (let ([info '()]) (do ([x 1 (add1 x)]) ((>= x (sub1 w))) (do ([y 1 (add1 y)]) ((>= y (sub1 h))) (let ([c (at (+ x0 x) (+ y0 y))]) (when (memq c special-chars) (if (memq c delimiters) (and-let* ([s (scan-right c (+ x0 x 1) (+ y0 y))]) (set! info (alist-cons c (scan-right c (+ x0 x 1) (+ y0 y)) info)) ) (set! info (cons c info)) ) ) ) ) ) (update info) ) ] ) ) (do ([y 0 (add1 y)]) ((>= y h)) (do ([x 0 (add1 x)]) ((>= x w)) (let ([c (at x y)]) (cond [(and (or (char-upper-case? c) (memv c (list #\< #\> #\* #\%))) (or (zero? x) (not (char=? c (at (sub1 x) y)))) (or (zero? y) (not (char=? c (at x (sub1 y))))) ) (let ([frame (extract-frame c x y)]) (set! frames (cons frame frames)) (scan-frame frame) (set! x (+ x (vector-ref frame 2) -1)) ) ] [(memq c delimiters) (and-let* ([s (scan-right c (add1 x) y)]) (set! x (+ x (string-length s))) ) ] ) ) ) ) (values frames w h) ) ) (define delimiters '(#\" #\| #\: #\# #\')) (define special-chars '(#\" #\| #\: #\# #\')) (define direction-map `(("v" . ,bb:VERTICAL) ("h" . ,bb:HORIZONTAL) ("vfill" . ,bb:VERT_FILL_SLIDER) ("hfill" . ,bb:HOR_FILL_SLIDER) ("vnice" . ,bb:VERT_NICE_SLIDER) ("hnice" . ,bb:HOR_NICE_SLIDER) ) ) (define box-type-map `(("no" . ,bb:NO_BOX) ("flat" . ,bb:FLAT_BOX) ("up" . ,bb:UP_BOX) ("down" . ,bb:DOWN_BOX) ("thinup" . ,bb:THIN_UP_BOX) ("thindown" . ,bb:THIN_DOWN_BOX) ("upframe" . ,bb:UP_FRAME) ("downframe" . ,bb:DOWN_FRAME) ("thinupframe" . ,bb:THIN_UP_FRAME) ("thindownframe" . ,bb:THIN_DOWN_FRAME) ("engraved" . ,bb:ENGRAVED_BOX) ("embossed" . ,bb:EMBOSSED_BOX) ("engravedframe" . ,bb:ENGRAVED_FRAME) ("embossedframe" . ,bb:EMBOSSED_FRAME) ("border" . ,bb:BORDER_BOX) ) ) (define color-map `(("gray" . ,bb:GRAY) ("black" . ,bb:BLACK) ("red" . ,bb:RED) ("green" . ,bb:GREEN) ("yellow" . ,bb:YELLOW) ("blue" . ,bb:BLUE) ("magenta" . ,bb:MAGENTA) ("cyan" . ,bb:CYAN) ("darkred" . ,bb:DARK_RED) ("darkgreen" . ,bb:DARK_GREEN) ("darkyellow" . ,bb:DARK_YELLOW) ("darkblue" . ,bb:DARK_BLUE) ("darkmagenta" . ,bb:DARK_MAGENTA) ("darkcyan" . ,bb:DARK_CYAN) ("white" . ,bb:WHITE) ) ) (define widget-map '((#\B . button) (#\C . check-xbox) (#\E . entry) (#\I . edit) (#\N . counter) (#\M . menu-bar) (#\D . dial) (#\S . slider) (#\A . adjuster) (#\L . list) (#\W . label) (#\O . radio-button) (#\P . progress) (#\T . tabs) (#\X . tile) (#\F . glwindow) (#\G . group) (#\J . clock) (#\V . live-image) (#\K . pack) (#\Z . scroll) (#\R . roller) (#\H . choice-button) (#\< . return-button) (#\% . int-entry) (#\* . float-entry) (#\> . menu-button) (#\Y . tree) ) ) (define (bb:make-widgets str fw fh . cmap) (let ([cmap (optional cmap '())]) (let-values ([(frames w h) (find-frames str)]) (let ([wf (/ fw w)] [hf (/ fh h)] ) (define (adjust-x x) (inexact->exact (round (* x wf)))) (define (adjust-y y) (inexact->exact (round (* y hf)))) (map (match-lambda [#(x y w h c info) (let ([m (assq c cmap)]) (when m (set! c (cadr m))) (let ([widget (bb:make-widget (or (and-let* ([a (assq c widget-map)]) (cdr a)) 'label) (adjust-x x) (adjust-y y) (adjust-x w) (adjust-y h) ) ] ) (for-each (match-lambda [(#\" . str) (bb:SetStringProperty widget -1 -1 bb:TEXT str) ] [(#\| . str) (for-each (lambda (str) (cond [(assoc str direction-map) => (lambda (a) (bb:SetIntProperty widget -1 bb:DIRECTION (cdr a))) ] [(assoc str box-type-map) => (lambda (a) (bb:SetIntProperty widget -1 bb:BOX (cdr a))) ] [(assoc str color-map) => (lambda (a) (bb:SetIntProperty widget -1 bb:COLOR (cdr a))) ] [else (error "bad widget property spec" str)] ) ) (string-split str ",") ) ] [(#\: . str) (bb:SetCallback widget (read (open-input-string str))) ] [(#\' . str) (for-each (cut bb:AddItem widget <> 0) (string-split str ",")) ] [(#\# . str) (bb:SetImage widget -1 (bb:image (string->symbol str))) (bb:RedrawWidget widget) ] [_ #f] ) info) (if m (cons (caddr m) widget) (cons c widget) ) ) ) ] ) frames) ) ) ) ) (define callback-table '()) (define-external (BBGenericCallback (c-pointer w) (c-pointer u)) void (let ([cb (assoc w callback-table)]) (if cb ((cdr cb)) (let ([cb (assoc u callback-table)]) (when cb ((cdr cb))) ) ) ) ) (define bb:SetCallback (let ([bb:SetCallback bb:SetCallback]) (lambda (w cb) (let* ([ptr (widget-ptr w)] [a (assoc ptr callback-table)] [cb (cond [(symbol? cb) (eval `(lambda () (,cb)))] [(pair? cb) (eval `(lambda () ,cb))] [else cb] ) ] ) (bb:SetCallback w (location BBGenericCallback)) (if a (set-cdr! a cb) (set! callback-table (alist-cons ptr cb callback-table)) ) ) ) ) ) (define handler-table '()) (define events ; the order is defined by FL_XXX event values! '#(no-event ; 0 push release enter leave drag focus unfocus keydown keyup close ; 10 move shortcut deactivate activate hide show paste selectionclear mousewheel dnd-enter ; 20 dnd-drag dnd-leave dnd-release ; 23 ) ) (define-external (BBGenericHandler (c-pointer w) (int event)) int (let ([cb (assoc w handler-table)]) (if cb (let ([res ((cdr cb) ; call user-supplied callback-handler (if (fx< event 24) (vector-ref events event) 'unknown) ) ] ) (if (boolean? res) (if res 1 0) ; convert boolean to int -1) ) ; call ancestor handler 0) ) ) (define-external (BBGenericLink (c-pointer w) (c-string uri)) c-string (let ([cb (assoc w handler-table)]) (if cb ((cdr cb) uri); call user-supplied link-handler 0) ) ) (define bb:SetHandler (let ([bb:SetHandler bb:SetHandler]) (lambda (w cb) (let* ([ptr (widget-ptr w)] [a (assoc ptr handler-table)] [cb (cond [(symbol? cb) (eval `(lambda () (,cb)))] [(pair? cb) (eval `(lambda () ,cb))] [else cb] ) ] ) (if (eq? (widget-name w) 'html-view) (bb:SetHandler w (location BBGenericLink)) (bb:SetHandler w (location BBGenericHandler)) ) (if a (set-cdr! a cb) (set! handler-table (alist-cons ptr cb handler-table)) ) ) ) ) ) (define key-codes `((,bb:BackSpace backspace) (,bb:Tab tab) (,bb:Enter enter) (,bb:Pause pause) (,bb:Scroll_Lock scroll-lock) (,bb:Escape escape) (,bb:Home home) (,bb:Left left) (,bb:Up up) (,bb:Right right) (,bb:Down down) (,bb:Page_Up page-up) (,bb:Page_Down page-down) (,bb:End end) (,bb:Print print) (,bb:Insert insert) (,bb:Menu menu) (,bb:Help help) (,bb:Num_Lock num-lock) (,bb:Shift_L shift-l) (,bb:Shift_R shift-r) (,bb:Control_L control-l) (,bb:Control_R control-r) (,bb:Caps_Lock caps-lock) (,bb:Meta_L meta-l) (,bb:Meta_R meta-r) (,bb:Alt_L alt-l) (,bb:Alt_R alt-r) (,bb:Delete delete) ) ) (define bb:decode-key (let ([bb:GetEventInt bb:GetEventInt]) (lambda (key) (let ([val (bb:GetEventInt key)]) (cond [(fx<= val 255) (integer->char val)] ; ordinary kbd key [(and (fx> val bb:Button) (fx< (- val bb:Button) 4)) ; mouse (string->symbol (string-append "button" (->string (- val bb:Button))))] [(and (fx>= val bb:KP) (fx<= val bb:KP_Last)) (cons (integer->char (- val bb:KP)) 'kp)] [(and (fx>= val bb:F) (fx<= val bb:F_Last)) (string->symbol (string-append "F" (->string (- val bb:F))))] [(assv val key-codes) => cadr] [else 'unknown]) ) ) ) ) (define event-ids `((alt ,bb:E_ALT ,bb:GetEventBool) (button1 ,bb:E_BUTTON1 ,bb:GetEventBool) (button2 ,bb:E_BUTTON2 ,bb:GetEventBool) (button3 ,bb:E_BUTTON3 ,bb:GetEventBool) (clicks ,bb:E_CLICKS ,bb:GetEventInt) (ctrl ,bb:E_CTRL ,bb:GetEventBool) (click? ,bb:E_IS_CLICK ,bb:GetEventBool) (key ,bb:E_KEY ,bb:decode-key) (length ,bb:E_LENGTH ,bb:GetEventInt) (shift ,bb:E_SHIFT ,bb:GetEventBool) (x ,bb:E_X ,bb:GetEventInt) (y ,bb:E_Y ,bb:GetEventInt) (x-root ,bb:E_X_ROOT ,bb:GetEventInt) (y-root ,bb:E_Y_ROOT ,bb:GetEventInt) (dx ,bb:E_DX ,bb:GetEventInt) (dy ,bb:E_DY ,bb:GetEventInt) (text ,bb:E_TEXT ,bb:GetEventString) ) ) (define (event id) (let ([a (assq id event-ids)]) (if a (values (cadr a) (caddr a)) (error "invalid event" id) ) ) ) (define (bb:event-get evt) (let-values ([(id get) (event evt)]) (get id) ) ) (define bb:event-set! (let ([bb:SetEventInt bb:SetEventInt] [bb:SetEventBool bb:SetEventBool]) (lambda (evt val) (case evt [(clicks) (bb:SetEventInt bb:E_CLICKS val)] [(click?) (bb:SetEventBool bb:E_IS_CLICK val)] [else (error "event property is not modifiable")] ) ) ) ) (define bb:event (getter-with-setter bb:event-get bb:event-set!)) (define (widget t) (or (and-let* ([a (assq t widget-ids)]) (cadr a)) (error "invalid widget type" t) ) ) (define current-parent #f) (define (bb:make-widget id . args) (let* ([t (widget id)] [w (make-widget t (match args [(w h) (bb:CreateWidget t -1 -1 w h)] [args (apply bb:CreateWidget t args)] ) id (foreign-value "C_calloc(sizeof(void *), WIDGET_RESOURCE_MAX)" c-pointer) current-parent '() ) ] ) (when current-parent (widget-children-set! current-parent (cons w (widget-children current-parent))) ) w) ) (define message-ids `((message ,bb:MESSAGE) (alert ,bb:ALERT) (ask ,bb:ASK) (choice ,bb:CHOICE) ) ) (define bb:message (lambda (type . args) (if (null? args) (bb:Message bb:MESSAGE (->string type) #f #f #f) (let-optionals args ([text #f] [s1 #f] [s2 #f] [s3 #f]) (bb:Message (or (and-let* ([a (assq type message-ids)]) (cadr a)) (error "invalid message type" type) ) (->string text) s1 s2 s3) ) ) ) ) (define (bb:get-input label . def) (bb:GetInput label (optional def #f)) ) (define bb:AddMenuItem (let ([bb:AddMenuItem bb:AddMenuItem]) (lambda (menu text cb . sc) (let* ([cb (cond [(symbol? cb) (eval `(lambda () (,cb)))] [(pair? cb) (eval `(lambda () ,cb))] [else cb] ) ] [u (bb:AddMenuItem menu text (optional sc #f) (location BBGenericCallback))] ) (set! callback-table (alist-cons u cb callback-table)) ) ) ) ) (define bb:AddTreeItem (let ([bb:AddTreeItem bb:AddTreeItem]) (lambda (tree text . more) (let-optionals more ([parent -1] [pos -1] [widget #f]) (bb:AddTreeItem tree text parent pos widget) ) ) ) ) (define bb:AddTableItems (let ([bb:AddTableCell bb:AddTableCell] [bb:AddTableColumn bb:AddTableColumn]) (lambda (table text . more) (if (eq? text 'column) (for-each (cut bb:AddTableColumn table <>) more) (for-each (cut bb:AddTableCell table <>) (cons text more)) ) ) ) ) (define bb:set-menu-item-active! bb:ActivateMenuItem) (define bb:run (match-lambda* [(or () (#t)) (bb:RunEventLoop #t 0)] [(#f) (bb:RunEventLoop #f 0)] [((? number? n)) (bb:RunEventLoop #f n)] ) ) (define (bb:add! w text . more) (case (widget-name w) [(menu-bar choice-button menu-button) (apply bb:AddMenuItem w text more)] [(tree) (apply bb:AddTreeItem w text more)] [(table) (apply bb:AddTableItems w text more)] [else (if (widget? text) (bb:AddWidget w text) (bb:AddItem w text (let ((m (optional more -1))) (case m ((#t) 1) ((#f) 0) (else m) ) ) ) ) ] ) ) (define (delete-callback ptr tbl) (let loop ([tbl tbl]) (cond [(null? tbl) '()] [(equal? ptr (car tbl)) (cdr tbl)] [else (cons (car tbl) (loop (cdr tbl)))] ) ) ) (define (remove-callbacks w) (let ([ptr (widget-ptr w)]) (set! callback-table (delete-callback ptr callback-table)) (set! handler-table (delete-callback ptr handler-table)) (for-each remove-callbacks (widget-children w)) ) ) (define (bb:remove! w . x) (if (null? x) (if (widget? w) (begin (remove-callbacks w) (release-all-resources w) (bb:RemoveAllItems w) (bb:DestroyWidget w) ) (bb:RemoveImage w) ) (bb:RemoveItem w (let ([i (car x)]) (if (eq? i #t) -1 i))) ) ) (foreign-parse/declare #<> 24) & 0xff));" "lst = C_block_item(lst, 1);" "C_set_block_item(lst, 0, C_fix((rgb >> 16) & 0xff));" "lst = C_block_item(lst, 1);" "C_set_block_item(lst, 0, C_fix((rgb >> 8) & 0xff));" "return(lst0);") ] ) (lambda (r . gb) (if (pair? gb) (apply bb:RGB r gb) (split r (list 0 0 0)) ) ) ) ) (define (bb:group w thunk) (let ([p0 #f]) (dynamic-wind (lambda () (set! p0 current-parent) (set! current-parent w) (bb:BeginGroup w) ) thunk (lambda () (set! current-parent p0) (bb:EndGroup w) ) ) ) ) (define (bb:image x . more) (or (if (null? more) (cond [(and (not (##sys#immediate? x)) (##sys#pointer? x)) (bb:Pixmap x)] [(string? x) (bb:LoadImage x)] [else (error "invalid image type" x)] ) (match more [(w h d) (bb:RawImage x w h d)] [_ (error "bad number of arguments" more)] ) ) (error "can't access image" x) ) ) (define (bb:image-data i) (let ([w (bb:ImageDim i bb:IMAGEWIDTH)] [h (bb:ImageDim i bb:IMAGEHEIGHT)] [d (bb:ImageDim i bb:COLOR)] [c (bb:ImageDim i bb:SIZE)]) (values (let loop ([p '()] [c (- c 1)]) (if (fx< c 0) p (loop (cons (bb:ImageData i c) p) (- c 1)) ) ) w h d) ) ) (define (bb:select-color . more) (define (choose title r g b) (let ([vec (u8vector r g b)]) (and (not (zero? (bb:SelectColor title vec))) (apply bb:RGB (u8vector->list vec)) ) ) ) (let-optionals more ([col 0] [title "Please select a color"]) (cond [(fixnum? col) (bb:SelectColorIndex col)] [(symbol? col) (bb:SelectColorIndex (property-value col))] [(vector? col) (apply choose title (vector->list))] [(list? col) (apply choose title col)] [(string? col) (choose col 128 128 128)] [else (choose title 128 128 128)] ) ) ) ;;; SXML stuff: (define-record element tag ; symbol id ; any (eq?) content ; string children ; (element ...) parent ; element | #f widget ; widget x y ; int width height ; int properties ; ((symbol . value) ...) attributes) ; ((symbol . string) ...) (define bb:element? element?) (define bb:root-element (make-parameter #f)) (define bb:element-widget element-widget) (define bb:element-parent element-parent) (define bb:element-children element-children) (define bb:element-id element-id) (define bb:element-tag element-tag) (define bb:element-attributes element-attributes) (define bb:element-content element-content) (define (bb:find-element id . root) (let loop ([root (optional root (bb:root-element))]) (if (eq? id (element-id root)) root (any loop (element-children root)) ) ) ) (define (bb:find-widget . args) (bb:element-widget (apply bb:find-element args) ) ) (define (bb:render sxml) (let ([elt (let render ([sxml sxml] [parent #f]) (match sxml [(tag ('@ attrs ...) body ...) (unless (assq tag widget-ids) (error "invalid tag" tag) ) (let-values ([(content subs) (partition string? body)]) (let ([elt (make-element tag #f (and (pair? content) (string-intersperse content "")) '() parent #f #f #f #f #f '() '()) ] ) (element-children-set! elt (map (cut render <> elt) subs)) (parse-attributes! elt attrs) elt) ) ] [(tag body ...) (render `(,tag (@) ,@body) parent)] [_ (error "invalid SXML syntax" sxml)] ) ) ] ) (bb:root-element elt) (realize elt) (bb:show (element-widget elt)) elt) ) (define (parse-attributes! elt attrs) (for-each (lambda (attr) (let loop ([attr attr]) (match attr [(a val) (cond [(assq a special-attributes) => (lambda (a) ((third a) elt ((second a) val)) ) ] [(eq? a 'callback) (element-properties-set! elt (alist-cons 'callback (>callback val) (element-properties elt))) ] [(assq a property-ids) => (lambda (_) (element-properties-set! elt (alist-cons a (>property a val) (element-properties elt)) ) ) ] [else (element-attributes-set! elt (alist-cons a val (element-attributes elt)))] ) ] [(a) (loop `(,a ,(->string a)))] ) ) ) attrs) ) (define (>callback x) (cond [(procedure? x) x] [(symbol? x) (>callback (symbol->string x))] [(string? x) (let ([x (read (open-input-string x))]) (if (symbol? x) (eval x) (eval `(lambda () ,x)) ) ) ] [(list? x) (eval `(lambda () ,x))] [else (error "invalid callback value" x)] ) ) (define (>property name x) (case name [(x y width height spacing maximum minimum x-position y-position text-size position mark image-width image-height label-size) (cond [(number? x) x] [(string? x) (string->number x)] [else (error "invalid numeric attribute" x name)] ) ] [(text tooltip) (->string x)] [(color text-color selection-color label-color) (cond [(number? x) x] [(string? x) (if (and (= (string-length x) 7) (char=? #\# (string-ref x 0)) ) (bb:RGB (string->number (substring x 1 3) 16) (string->number (substring x 3 5) 16) (string->number (substring x 5 7) 16) ) (string->symbol x) ) ] [(symbol? x) x] [else (error "invalid color attribute" x name)] ) ] [(resizable visible focus modal read-only valid-context) (cond [(boolean? x) x] [(string? x) (not (string=? "no" x))] [else #t] ) ] [(resizable-widget) (cond [(symbol? x) x] [(string? x) (string->symbol x)] [else (string->symbol (->string x))] ) ] [(when) (cond [(symbol? x) x] [(list? x) x] [else (map string->symbol (string-split (->string x) ", "))] ) ] [else (cond [(number? x) x] [(string? x) (or (string->number x) x)] [(symbol? x) x] [else (error "invalid property value" x name)] ) ] ) ) (define (>position x) (cond [(number? x) (inexact->exact x)] [(string? x) (if (and (> (string-length x) 0) (or (memq (string-ref x 0) '(#\+ #\-)) (char=? #\% (string-ref x (sub1 (string-length x)))) ) ) x (inexact->exact (string->number x)) ) ] [else (error "bad positional attribute" x)] ) ) (define (>id x) (cond [(string? x) (string->symbol x)] [(symbol? x) x] [else (string->symbol (->string x))] ) ) (define special-attributes `((x ,>position ,element-x-set!) (y ,>position ,element-y-set!) (width ,>position ,element-width-set!) (height ,>position ,element-height-set!) (id ,>id ,element-id-set!) ) ) (define (realize elt0) (define (getxy n x) (cond [(not x) n] [(number? x) x] [(memq (string-ref x 0) '(#\+ #\-)) (+ n (string->number x))] [(char=? #\% (string-ref x (sub1 (string-length x)))) (inexact->exact (round (* (string->number (substring x 0 (sub1 (string-length x)))) n 0.01))) ] [else (error "invalid dimensional property" elt0 x)] ) ) (let loop ([elt elt0] [w #f] [h #f]) (let* ([tag (element-tag elt)] [refx (if (eq? elt elt0) -1 0)] [refy (if (eq? elt elt0) -1 0)] [refw (or w 640)] [refh (or h 480)] [x (or (getxy refx (element-x elt)) refx)] [y (or (getxy refy (element-y elt)) refy)] [w (or (getxy refw (element-width elt)))] [h (or (getxy refh (element-height elt)))] [widget (bb:make-widget tag x y w h)] ) (element-x-set! elt x) (element-y-set! elt y) (element-width-set! elt w) (element-height-set! elt h) (element-widget-set! elt widget) (and-let* ([c (element-content elt)]) (set! (bb:property widget 'text) c) ) (for-each (match-lambda [('resizable-widget . _) #f] [('callback . cb) (bb:set! widget 'callback cb)] [(a . val) (bb:set! widget a val)] ) (element-properties elt) ) (let ([cont (lambda () (for-each (cut loop <> w h) (element-children elt)))]) (if (memq tag '(window double-window group tabs tile pack scroll)) (bb:group widget cont) (cont) ) ) (and-let* ([a (assq 'resizable-widget (element-properties elt))]) (bb:set! widget 'resizable-widget (element-widget (or (bb:find-element (cdr a)) (error "element not found" (cdr a))))) ) ) ) ) (implicit-exit-handler (let ((old (implicit-exit-handler))) (lambda () (bb:Stop) (old) ) ) ) )