diff options
| author | Greg Ercolano <erco@seriss.com> | 2012-04-22 13:40:02 +0000 |
|---|---|---|
| committer | Greg Ercolano <erco@seriss.com> | 2012-04-22 13:40:02 +0000 |
| commit | f58cd169c08a4be9ae07903a9e61b686bb7a75b6 (patch) | |
| tree | a2a498a84c10cb1c8ba57f52f6511922aa8ce8a1 | |
| parent | dc6e8a5f8ae8c24bf7fb3aa0d702eb4415ace6b5 (diff) | |
Various mods for Fl_Tree
o Fix STR#2828 (E): {Vertical|Widget} Gap
o Moved Fabien's reselected methods to Fl_Tree_Prefs,
return method made const, doxygen, removed underbars from methods
(to follow general API)
o Widgets can now appear to the right of labels.
This can be controlled with item_draw_mode(FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET)
o Cleaned up Fl_Tree_Item::draw(), Fl_Tree::draw()
o New methods:
marginbottom() -- [ABI feature] extra space below last tree element when scrolling
widgetmarginleft() -- [ABI feature] space to left of widget
usericonmarginleft() -- space to left of usericon
labelmarginleft() -- space to left of label
item_draw_mode() -- control how items, widget() are drawn
o Updated Fl_Tree docs, tree-elements.png
o test/tree: added sliders to test the above new features,
added "open all" and "close all" buttons
o Probably other stuff..
TODO: Fix "scroll-beyond-bottom" (STR#2796)
TODO: Fix other items in STR#2828
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@9377 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | FL/Fl_Tree.H | 43 | ||||
| -rw-r--r-- | FL/Fl_Tree_Item.H | 3 | ||||
| -rw-r--r-- | FL/Fl_Tree_Prefs.H | 98 | ||||
| -rw-r--r-- | documentation/src/tree-elements.png | bin | 9673 -> 12750 bytes | |||
| -rw-r--r-- | examples/tree-as-container.cxx | 4 | ||||
| -rw-r--r-- | src/Fl_Tree.cxx | 179 | ||||
| -rw-r--r-- | src/Fl_Tree_Item.cxx | 292 | ||||
| -rw-r--r-- | src/Fl_Tree_Prefs.cxx | 12 |
8 files changed, 405 insertions, 226 deletions
diff --git a/FL/Fl_Tree.H b/FL/Fl_Tree.H index aa43fd2a1..1b8dbd758 100644 --- a/FL/Fl_Tree.H +++ b/FL/Fl_Tree.H @@ -194,17 +194,6 @@ enum Fl_Tree_Reason { FL_TREE_REASON_CLOSED ///< an item was closed }; -#if FLTK_ABI_VERSION >= 10302 -/// \enum Fl_Tree_Item_Select_Mode -/// Defines the ways an item can be (re) selected. -/// -enum Fl_Tree_Item_Reselect_Mode -{ - FL_TREE_SELECTABLE_ONCE=0, /// backward compatible default: an item can only be selected once - FL_TREE_SELECTABLE_ALWAYS, /// needed for new RESELECT feature -}; -#endif - class FL_EXPORT Fl_Tree : public Fl_Group { Fl_Tree_Item *_root; // can be null! Fl_Tree_Item *_item_focus; // item that has focus box @@ -216,20 +205,6 @@ class FL_EXPORT Fl_Tree : public Fl_Group { #if FLTK_ABI_VERSION >= 10302 // NEW: Fl_Tree_Item *_lastselect; - - // NEW: -public: - //! Returns the current item re/selection mode - Fl_Tree_Item_Reselect_Mode item_reselect_mode() const { - return _itemReselectMode; - } - - //! Sets the item re/selection mode - void item_reselect_mode(Fl_Tree_Item_Reselect_Mode mode) { - _itemReselectMode = mode; - } -private: - Fl_Tree_Item_Reselect_Mode _itemReselectMode; #else // OLD: static data inside handle() method #endif @@ -325,8 +300,20 @@ public: void marginleft(int val); int margintop() const; void margintop(int val); +#if FLTK_ABI_VERSION >= 10302 + int marginbottom() const; + void marginbottom(int val); +#endif + int linespacing() const; + void linespacing(int val); int openchild_marginbottom() const; void openchild_marginbottom(int val); + int usericonmarginleft() const; + void usericonmarginleft(int val); + int labelmarginleft() const; + void labelmarginleft(int val); + int widgetmarginleft() const; + void widgetmarginleft(int val); int connectorwidth() const; void connectorwidth(int val); Fl_Image* usericon() const; @@ -347,6 +334,12 @@ public: void selectbox(Fl_Boxtype val); Fl_Tree_Select selectmode() const; void selectmode(Fl_Tree_Select val); +#if FLTK_ABI_VERSION >= 10302 + Fl_Tree_Item_Reselect_Mode item_reselect_mode() const; + void item_reselect_mode(Fl_Tree_Item_Reselect_Mode mode); + Fl_Tree_Item_Draw_Mode item_draw_mode() const; + void item_draw_mode(Fl_Tree_Item_Draw_Mode mode); +#endif int displayed(Fl_Tree_Item *item); void show_item(Fl_Tree_Item *item, int yoff); diff --git a/FL/Fl_Tree_Item.H b/FL/Fl_Tree_Item.H index d090df1b6..9b7a7d56b 100644 --- a/FL/Fl_Tree_Item.H +++ b/FL/Fl_Tree_Item.H @@ -62,7 +62,7 @@ class FL_EXPORT Fl_Tree_Item { char _active; // item activated? char _selected; // item selected? int _xywh[4]; // xywh of this widget (if visible) - int _collapse_xywh[4]; // xywh of collapse icon (if any) + int _collapse_xywh[4]; // xywh of collapse icon (if visible) int _label_xywh[4]; // xywh of label Fl_Widget *_widget; // item's label widget (optional) Fl_Image *_usericon; // item's user-specific icon (optional) @@ -86,6 +86,7 @@ public: int y() const { return(_xywh[1]); } int w() const { return(_xywh[2]); } int h() const { return(_xywh[3]); } + int calc_item_height(const Fl_Tree_Prefs &prefs); void draw(int X, int &Y, int W, Fl_Widget *tree, Fl_Tree_Item *itemfocus, const Fl_Tree_Prefs &prefs, int lastchild=1); void show_self(const char *indent = "") const; void label(const char *val); diff --git a/FL/Fl_Tree_Prefs.H b/FL/Fl_Tree_Prefs.H index 0db3881f7..58eed4044 100644 --- a/FL/Fl_Tree_Prefs.H +++ b/FL/Fl_Tree_Prefs.H @@ -45,7 +45,7 @@ /// Sort order options for items added to the tree /// enum Fl_Tree_Sort { - FL_TREE_SORT_NONE=0, ///< No sorting; items are added in the order defined (default). + FL_TREE_SORT_NONE=0, ///< No sorting; items are added in the order defined (default). FL_TREE_SORT_ASCENDING=1, ///< Add items in ascending sort order. FL_TREE_SORT_DESCENDING=2 ///< Add items in descending sort order. }; @@ -65,10 +65,28 @@ enum Fl_Tree_Connector { enum Fl_Tree_Select { FL_TREE_SELECT_NONE=0, ///< Nothing selected when items are clicked FL_TREE_SELECT_SINGLE=1, ///< Single item selected when item is clicked (default) - FL_TREE_SELECT_MULTI=2 ///< Multiple items can be selected by clicking with - ///< SHIFT or CTRL or mouse drags. + FL_TREE_SELECT_MULTI=2 ///< Multiple items can be selected by clicking + ///< with SHIFT, CTRL or mouse drags. }; +#if FLTK_ABI_VERSION >= 10302 +/// \enum Fl_Tree_Item_Select_Mode +/// Defines the ways an item can be (re) selected. +/// +enum Fl_Tree_Item_Reselect_Mode { + FL_TREE_SELECTABLE_ONCE=0, ///< item can only be selected once (default) + FL_TREE_SELECTABLE_ALWAYS, ///< needed for new RESELECT feature +}; + +/// \enum Fl_Tree_Item_Draw_Mode +/// Tree display style for items. +/// +enum Fl_Tree_Item_Draw_Mode { + FL_TREE_ITEM_DRAW_WIDGET_ONLY=0, ///< if widget() defined, draw it in place of the label (default) + FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET=1 ///< if widget() defined, draw it to right of label +}; +#endif + /// \class Fl_Tree_Prefs /// /// \brief Fl_Tree's Preferences class. @@ -81,12 +99,16 @@ class FL_EXPORT Fl_Tree_Prefs { Fl_Font _labelfont; // label's font face Fl_Fontsize _labelsize; // label's font size int _margintop; // -- - int _marginleft; // |- tree's margins - //int _marginright; // | - //int _marginbottom; // -- + int _marginleft; // |- tree's controllable margins +#if FLTK_ABI_VERSION >= 10302 + int _marginbottom; // -- +#endif int _openchild_marginbottom; // extra space below an open child tree int _usericonmarginleft; // space to left of user icon (if any) int _labelmarginleft; // space to left of label +#if FLTK_ABI_VERSION >= 10302 + int _widgetmarginleft; // space to left of widget +#endif int _connectorwidth; // connector width (right of open/close icon) int _linespacing; // vertical space between lines // Colors @@ -102,6 +124,10 @@ class FL_EXPORT Fl_Tree_Prefs { Fl_Tree_Sort _sortorder; // none, ascening, descending, etc. Fl_Boxtype _selectbox; // selection box type Fl_Tree_Select _selectmode; // selection mode +#if FLTK_ABI_VERSION >= 10302 + Fl_Tree_Item_Reselect_Mode _itemreselectmode; // controls item selection callback() behavior + Fl_Tree_Item_Draw_Mode _itemdrawmode; // controls how items draw label, widget() +#endif public: Fl_Tree_Prefs(); @@ -144,6 +170,18 @@ public: inline void margintop(int val) { _margintop = val; } +#if FLTK_ABI_VERSION >= 10302 + /// Get the bottom margin's value in pixels. + /// This is the extra distance the vertical scroller lets you travel. + inline int marginbottom() const { + return(_marginbottom); + } + /// Set the bottom margin's value in pixels + /// This is the extra distance the vertical scroller lets you travel. + inline void marginbottom(int val) { + _marginbottom = val; + } +#endif /// Get the margin below an open child in pixels inline int openchild_marginbottom() const { return(_openchild_marginbottom); @@ -152,22 +190,6 @@ public: inline void openchild_marginbottom(int val) { _openchild_marginbottom = val; } - - /****** NOT IMPLEMENTED - inline int marginright() const { - return(_marginright); - } - inline void marginright(int val) { - _marginright = val; - } - inline int marginbottom() const { - return(_marginbottom); - } - inline void marginbottom(int val) { - _marginbottom = val; - } - *******/ - /// Get the user icon's left margin value in pixels inline int usericonmarginleft() const { return(_usericonmarginleft); @@ -184,6 +206,16 @@ public: inline void labelmarginleft(int val) { _labelmarginleft = val; } +#if FLTK_ABI_VERSION >= 10302 + /// Get the widget()'s left margin value in pixels + inline int widgetmarginleft() const { + return(_widgetmarginleft); + } + /// Set the widget's left margin value in pixels + inline void widgetmarginleft(int val) { + _widgetmarginleft = val; + } +#endif /// Get the line spacing value in pixels inline int linespacing() const { return(_linespacing); @@ -329,6 +361,28 @@ public: inline void selectmode(Fl_Tree_Select val) { _selectmode = val; } +#if FLTK_ABI_VERSION >= 10302 + /// Returns the current item re/selection mode + Fl_Tree_Item_Reselect_Mode item_reselect_mode() const { + return _itemreselectmode; + } + /// Sets the item re/selection mode + void item_reselect_mode(Fl_Tree_Item_Reselect_Mode mode) { + _itemreselectmode = mode; + } + /// Get the 'item draw mode' used for the tree + inline Fl_Tree_Item_Draw_Mode item_draw_mode() const { + return(_itemdrawmode); + } + /// Set the 'item draw mode' used for the tree to \p val. + /// This affects how items in the tree are drawn, + /// such as when a widget() is defined. + /// See Fl_Tree_Item_Draw_Mode for possible values. + /// + inline void item_draw_mode(Fl_Tree_Item_Draw_Mode val) { + _itemdrawmode = val; + } +#endif }; #endif /*FL_TREE_PREFS_H*/ diff --git a/documentation/src/tree-elements.png b/documentation/src/tree-elements.png Binary files differindex 0e3bbea6a..78997cfec 100644 --- a/documentation/src/tree-elements.png +++ b/documentation/src/tree-elements.png diff --git a/examples/tree-as-container.cxx b/examples/tree-as-container.cxx index 73a7fb580..fa3280a93 100644 --- a/examples/tree-as-container.cxx +++ b/examples/tree-as-container.cxx @@ -23,10 +23,10 @@ #include <FL/Fl_Group.H> #include <FL/Fl_Input.H> -#define MAX_ROWS 80000 +#define MAX_ROWS 20000 #define MAX_FIELDS 5 #define FIELD_WIDTH 70 -#define FIELD_HEIGHT 25 +#define FIELD_HEIGHT 30 class MyData : public Fl_Group { Fl_Input *fields[MAX_FIELDS]; diff --git a/src/Fl_Tree.cxx b/src/Fl_Tree.cxx index 2d68a3037..8769578cc 100644 --- a/src/Fl_Tree.cxx +++ b/src/Fl_Tree.cxx @@ -102,7 +102,6 @@ Fl_Tree::Fl_Tree(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L #if FLTK_ABI_VERSION >= 10302 // NEW _lastselect = 0; - _itemReselectMode = FL_TREE_SELECTABLE_ONCE; #else // OLD: data initialized static inside handle() #endif @@ -372,17 +371,25 @@ void Fl_Tree::draw() { int cy = y() + Fl::box_dy(box()); int cw = w() - Fl::box_dw(box()); int ch = h() - Fl::box_dh(box()); - if (damage() & ~FL_DAMAGE_CHILD) { // redraw entire thing + { // Handle group's bg - Fl_Group::draw_box(); - Fl_Group::draw_label(); + if ( damage() & ~FL_DAMAGE_CHILD) { // redraw entire widget? + Fl_Group::draw_box(); + Fl_Group::draw_label(); + } if ( ! _root ) return; // These values are changed during drawing - // 'Y' will be the lowest point on the tree + // By end, 'Y' will be the lowest point on the tree int X = cx + _prefs.marginleft(); int Y = cy + _prefs.margintop() - (_vscroll->visible() ? _vscroll->value() : 0); int W = cw - _prefs.marginleft(); // - _prefs.marginright(); + // Adjust root's X/W if connectors off + if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) { + X -= _prefs.openicon()->w(); + W += _prefs.openicon()->w(); + } int Ysave = Y; + fl_push_clip(cx,cy,cw,ch); { fl_font(_prefs.labelfont(), _prefs.labelsize()); @@ -393,53 +400,34 @@ void Fl_Tree::draw() { fl_pop_clip(); // Show vertical scrollbar? - int ydiff = (Y+_prefs.margintop())-Ysave; // ydiff=size of tree - int ytoofar = (cy+ch) - Y; // ytoofar -- scrolled beyond bottom (e.g. stow) - - //printf("ydiff=%d ch=%d Ysave=%d ytoofar=%d value=%d\n", - //int(ydiff),int(ch),int(Ysave),int(ytoofar), int(_vscroll->value())); - - if ( ytoofar > 0 ) ydiff += ytoofar; - if ( Ysave<cy || ydiff > ch || int(_vscroll->value()) > 1 ) { - _vscroll->visible(); - - int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size(); - int sx = x()+w()-Fl::box_dx(box())-scrollsize; - int sy = y()+Fl::box_dy(box()); - int sw = scrollsize; - int sh = h()-Fl::box_dh(box()); - _vscroll->show(); - _vscroll->range(0.0,ydiff-ch); - _vscroll->resize(sx,sy,sw,sh); - _vscroll->slider_size(float(ch)/float(ydiff)); - } else { - _vscroll->Fl_Slider::value(0); - _vscroll->hide(); - } - } - // Draw children - fl_push_clip(cx,cy,cw-(_vscroll->visible()?_vscroll->w():0),ch); - // Similar to Fl_Group::draw(), but optimized to ignore drawing - // items outside the viewport. - // TODO: Suggest Fl_Group::draw() do this if clip_children() is enabled. - { - Fl_Widget*const* a = Fl_Group::array(); - if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing: - for (int i=Fl_Group::children(); i--;) { - Fl_Widget& o = **a++; - if ( (o.y()+o.h()) < y() || (o.y() > (y()+h())) ) continue; - Fl_Group::draw_child(o); - Fl_Group::draw_outside_label(o); - } - } else { // only redraw the children that need it: - for (int i=Fl_Group::children(); i--;) { - Fl_Widget& o = **a++; - if ( (o.y()+o.h()) < y() || (o.y() > (y()+h())) ) continue; - Fl_Group::update_child(o); + { +#if FLTK_ABI_VERSION >= 10302 + // NEW + int SY = Y + _prefs.marginbottom(); +#else + // OLD + int SY = Y; +#endif + int ydiff = (SY+_prefs.margintop())-Ysave; // ydiff=size of tree + int ytoofar = (cy+ch) - SY; // ytoofar -- scrolled beyond bottom (e.g. stow) + if ( ytoofar > 0 ) ydiff += ytoofar; + if ( Ysave<cy || ydiff>ch || int(_vscroll->value())>1 ) { + _vscroll->visible(); + int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size(); + int sx = x()+w()-Fl::box_dx(box())-scrollsize; + int sy = y()+Fl::box_dy(box()); + int sw = scrollsize; + int sh = h()-Fl::box_dh(box()); + _vscroll->show(); + _vscroll->resize(sx,sy,sw,sh); + _vscroll->slider_size(float(ch)/float(ydiff)); + _vscroll->range(0.0,ydiff-ch); + } else { + _vscroll->Fl_Slider::value(0); + _vscroll->hide(); } } } - fl_pop_clip(); draw_child(*_vscroll); // draw scroll last } @@ -1399,6 +1387,38 @@ void Fl_Tree::margintop(int val) { redraw(); } +#if FLTK_ABI_VERSION >= 10302 +/// Get the amount of white space (in pixels) that should appear +/// below the last visible item when the vertical scroller is scrolled to the bottom. +/// +int Fl_Tree::marginbottom() const { + return(_prefs.marginbottom()); +} + +/// Sets the amount of white space (in pixels) that should appear +/// below the last visible item when the vertical scroller is scrolled to the bottom. +/// +void Fl_Tree::marginbottom(int val) { + _prefs.marginbottom(val); + redraw(); +} +#endif + +/// Get the amount of white space (in pixels) that should appear +/// between items in the tree. +/// +int Fl_Tree::linespacing() const { + return(_prefs.linespacing()); +} + +/// Sets the amount of white space (in pixels) that should appear +/// between items in the tree. +/// +void Fl_Tree::linespacing(int val) { + _prefs.linespacing(val); + redraw(); +} + /// Get the amount of white space (in pixels) that should appear /// below an open child tree's contents. /// @@ -1413,6 +1433,41 @@ void Fl_Tree::openchild_marginbottom(int val) { _prefs.openchild_marginbottom(val); redraw(); } +/// Get the amount of white space (in pixels) that should appear +/// to the left of the usericon. +int Fl_Tree::usericonmarginleft() const { + return(_prefs.usericonmarginleft()); +} +/// Set the amount of white space (in pixels) that should appear +/// to the left of the usericon. +void Fl_Tree::usericonmarginleft(int val) { + _prefs.usericonmarginleft(val); + redraw(); +} +/// Get the amount of white space (in pixels) that should appear +/// to the left of the label text. +int Fl_Tree::labelmarginleft() const { + return(_prefs.labelmarginleft()); +} +/// Set the amount of white space (in pixels) that should appear +/// to the left of the label text. +void Fl_Tree::labelmarginleft(int val) { + _prefs.labelmarginleft(val); + redraw(); +} +#if FLTK_ABI_VERSION >= 10302 +/// Get the amount of white space (in pixels) that should appear +/// to the left of the child fltk widget (if any). +int Fl_Tree::widgetmarginleft() const { + return(_prefs.widgetmarginleft()); +} +/// Set the amount of white space (in pixels) that should appear +/// to the left of the child fltk widget (if any). +void Fl_Tree::widgetmarginleft(int val) { + _prefs.widgetmarginleft(val); + redraw(); +} +#endif /// Gets the width of the horizontal connection lines (in pixels) /// that appear to the left of each tree item's label. @@ -1570,6 +1625,32 @@ void Fl_Tree::selectmode(Fl_Tree_Select val) { _prefs.selectmode(val); } +#if FLTK_ABI_VERSION >= 10302 +/// Returns the current item re/selection mode +Fl_Tree_Item_Reselect_Mode Fl_Tree::item_reselect_mode() const { + return(_prefs.item_reselect_mode()); +} + +/// Sets the item re/selection mode +void Fl_Tree::item_reselect_mode(Fl_Tree_Item_Reselect_Mode mode) { + _prefs.item_reselect_mode(mode); +} + +/// Get the 'item draw mode' used for the tree +Fl_Tree_Item_Draw_Mode Fl_Tree::item_draw_mode() const { + return(_prefs.item_draw_mode()); +} + +/// Set the 'item draw mode' used for the tree to \p val. +/// This affects how items in the tree are drawn, +/// such as when a widget() is defined. +/// See Fl_Tree_Item_Draw_Mode for possible values. +/// +void Fl_Tree::item_draw_mode(Fl_Tree_Item_Draw_Mode val) { + _prefs.item_draw_mode(val); +} +#endif + /// See if \p item is currently displayed on-screen (visible within the widget). /// This can be used to detect if the item is scrolled off-screen. /// Checks to see if the item's vertical position is within the top and bottom diff --git a/src/Fl_Tree_Item.cxx b/src/Fl_Tree_Item.cxx index 1b28602c9..ea91092fb 100644 --- a/src/Fl_Tree_Item.cxx +++ b/src/Fl_Tree_Item.cxx @@ -26,6 +26,7 @@ // // http://www.fltk.org/str.php // +/////////////////////////////////////////////////////////////////////////// 80 / // Was the last event inside the specified xywh? static int event_inside(const int xywh[4]) { @@ -556,6 +557,25 @@ static void draw_item_focus(Fl_Boxtype B, Fl_Color C, int X, int Y, int W, int H #endif } +/// Return the item's 'visible' height +int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) { + if ( ! _visible ) return(0); + int H = 0; + if ( _label ) { + fl_font(_labelfont, _labelsize); // fldescent() needs this :/ + H = _labelsize + fl_descent() + 1; // at least one pixel space below descender + } + if ( has_children() && prefs.openicon() && H<prefs.openicon()->h() ) + H = prefs.openicon()->h(); + if ( usericon() && H<usericon()->h() ) + H = usericon()->h(); + // NO: we don't use widget's height, we force it to match ours + //if ( widget() && widget()->visible() && H<widget()->h() ) + // H = widget()->h(); + H += prefs.linespacing(); + return(H); +} + /// Draw this item and its children. void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, Fl_Tree_Item *itemfocus, @@ -563,145 +583,167 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, if ( ! _visible ) return; int tree_top = tree->y(); int tree_bot = tree_top + tree->h(); - fl_font(_labelfont, _labelsize); - int H = _labelsize; - if(usericon() && H < usericon()->h()) H = usericon()->h(); - H += prefs.linespacing() + fl_descent(); - // adjust horizontally if we draw no connecting lines - if ( is_root() && prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE ) { - X -= prefs.openicon()->w(); - W += prefs.openicon()->w(); - } - // Colors, fonts - Fl_Color fg = _selected ? fl_contrast(_labelfgcolor, tree->selection_color()) - : _active ? _labelfgcolor - : fl_inactive(_labelfgcolor); - Fl_Color bg = _selected ? _active ? tree->selection_color() - : fl_inactive(tree->selection_color()) - : _labelbgcolor; + int H = calc_item_height(prefs); + // Update the xywh of this item _xywh[0] = X; _xywh[1] = Y; _xywh[2] = W; _xywh[3] = H; - // Text size - int textw=0, texth=0; - fl_measure(_label, textw, texth, 0); - int textycenter = Y+(H/2); + + // Determine collapse icon's xywh + // Note: calculate collapse icon's xywh for possible mouse click detection. + // We don't care about items clipped off the viewport; they won't get mouse events. + // + int item_y_center = Y+(H/2); int &icon_w = _collapse_xywh[2] = prefs.openicon()->w(); int &icon_x = _collapse_xywh[0] = X + (icon_w + prefs.connectorwidth())/2 - 3; - int &icon_y = _collapse_xywh[1] = textycenter - (prefs.openicon()->h()/2); + int &icon_y = _collapse_xywh[1] = item_y_center - (prefs.openicon()->h()/2); _collapse_xywh[3] = prefs.openicon()->h(); + // Horizontal connector values - int hstartx = X+icon_w/2-1; - int hendx = hstartx + prefs.connectorwidth(); - int hcenterx = X + icon_w + ((hendx - (X + icon_w)) / 2); - - // See if we should draw this item - // If this item is root, and showroot() is disabled, don't draw. - // 'clipped' is an optimization to prevent drawing anything offscreen. + // XXX: Must calculate these even if(clipped) because 'draw children' code (below) + // needs hconn_x_center value. (Otherwise, these calculations could be 'clipped') // - char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1; - char clipped = ((Y+H) < tree_top) || (Y>tree_bot) ? 1 : 0; - if ( drawthis ) { - // Draw connectors - if ( prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) { - // Horiz connector between center of icon and text - // if this is root, the connector should not dangle in thin air on the left - if (is_root()) { - if (!clipped) draw_horizontal_connector(hcenterx, hendx, textycenter, prefs); - } else { - if (!clipped) draw_horizontal_connector(hstartx, hendx, textycenter, prefs); - } - if ( has_children() && is_open() ) { - // Small vertical line down to children - if (!clipped) draw_vertical_connector(hcenterx, textycenter, Y+H, prefs); - } - // Connectors for last child - if ( ! is_root() ) { - if ( lastchild ) { - if (!clipped) draw_vertical_connector(hstartx, Y, textycenter, prefs); - } else { - if (!clipped) draw_vertical_connector(hstartx, Y, Y+H, prefs); - } - } - } - // Draw collapse icon - if ( has_children() && prefs.showcollapse() ) { - // Draw icon image - if ( is_open() ) { - if (!clipped) prefs.closeicon()->draw(icon_x,icon_y); - } else { - if (!clipped) prefs.openicon()->draw(icon_x,icon_y); - } - } - // Background for this item - int cw1 = icon_w+prefs.connectorwidth()/2, cw2 = prefs.connectorwidth(); - int cwidth = cw1>cw2 ? cw1 : cw2; - int &bx = _label_xywh[0] = X+(icon_w/2-1+cwidth); - int &by = _label_xywh[1] = Y; - int &bw = _label_xywh[2] = W-(icon_w/2-1+cwidth); - int &bh = _label_xywh[3] = H; - // Draw bg only if different from tree's bg - if ( bg != tree->color() || is_selected() ) { - if ( is_selected() ) { - // Selected? Use selectbox() style - if (!clipped) fl_draw_box(prefs.selectbox(), bx, by, bw, bh, bg); - } else { - // Not Selected? use plain filled rectangle - if (!clipped) { - fl_color(bg); - fl_rectf(bx, by, bw, bh); - } - } + int hconn_x = X+icon_w/2-1; + int hconn_x2 = hconn_x + prefs.connectorwidth(); + int hconn_x_center = X + icon_w + ((hconn_x2 - (X + icon_w)) / 2); + int cw1 = icon_w+prefs.connectorwidth()/2, cw2 = prefs.connectorwidth(); + int conn_w = cw1>cw2 ? cw1 : cw2; + + // Background position + int &bg_x = _label_xywh[0] = X+(icon_w/2-1+conn_w); + int &bg_y = _label_xywh[1] = Y; + int &bg_w = _label_xywh[2] = W-(icon_w/2-1+conn_w); + int &bg_h = _label_xywh[3] = H; + + // Usericon position + int uicon_x = bg_x + ( (usericon() || prefs.usericon()) ? prefs.usericonmarginleft() : 0); + int uicon_w = usericon() ? usericon()->w() : prefs.usericon() ? prefs.usericon()->w() : 0; + + // Label position + int label_x = uicon_x + uicon_w + (_label ? prefs.labelmarginleft() : 0); + + // Recalc widget position + // Do this whether clipped or not, so that when scrolled, + // the widgets move to appropriate 'offscreen' positions + // (so that they don't get mouse events, etc) + // + if ( widget() ) { + int wx = label_x; + int wy = bg_y; + int ww = widget()->w(); // use widget's width + int wh = H; // lock widget's height to item height +#if FLTK_ABI_VERSION >= 10302 + if ( _label && prefs.item_draw_mode() == FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET ) { +#else + if ( _label && !widget() ) { // back compat: don't draw label if widget() present +#endif + fl_font(_labelfont, _labelsize); // fldescent() needs this + int dx,dy,lw,lh; + fl_text_extents(_label,dx,dy,lw,lh); +#if FLTK_ABI_VERSION >= 10302 + // NEW + wx += (lw + prefs.widgetmarginleft()); +#else + // OLD + wx += (lw + 3); +#endif } - // Draw user icon (if any) - int useroff = (icon_w/2-1+cwidth); - if ( usericon() ) { - // Item has user icon? Use it - useroff += prefs.usericonmarginleft(); - icon_y = textycenter - (usericon()->h() >> 1); - if (!clipped) usericon()->draw(X+useroff,icon_y); - useroff += usericon()->w(); - } else if ( prefs.usericon() ) { - // Prefs has user icon? Use it - useroff += prefs.usericonmarginleft(); - icon_y = textycenter - (prefs.usericon()->h() >> 1); - if (!clipped) prefs.usericon()->draw(X+useroff,icon_y); - useroff += prefs.usericon()->w(); + if ( widget()->x() != wx || widget()->y() != wy || + widget()->w() != ww || widget()->h() != wh ) { + widget()->resize(wx,wy,ww,wh); // we'll handle redraw below } - useroff += prefs.labelmarginleft(); - // Draw label - if ( widget() ) { - // Widget? Draw it - int lx = X+useroff; - int ly = by; - int lw = widget()->w(); - int lh = bh; - if ( widget()->x() != lx || widget()->y() != ly || - widget()->w() != lw || widget()->h() != lh ) { - widget()->resize(lx, ly, lw, lh); // fltk will handle drawing this + } + char clipped = ((Y+H) < tree_top) || (Y>tree_bot) ? 1 : 0; + char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1; + if ( !clipped ) { + Fl_Color fg = _selected ? fl_contrast(_labelfgcolor, tree->selection_color()) + : _active ? _labelfgcolor + : fl_inactive(_labelfgcolor); + Fl_Color bg = _selected ? _active ? tree->selection_color() + : fl_inactive(tree->selection_color()) + : _labelbgcolor; + // See if we should draw this item + // If this item is root, and showroot() is disabled, don't draw. + // 'clipped' is an optimization to prevent drawing anything offscreen. + // + if ( drawthis ) { // draw this item at all? + if ( tree->damage() & ~FL_DAMAGE_CHILD ) { // non-child damage? + // Draw connectors + if ( prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) { + // Horiz connector between center of icon and text + // if this is root, the connector should not dangle in thin air on the left + if (is_root()) draw_horizontal_connector(hconn_x_center, hconn_x2, item_y_center, prefs); + else draw_horizontal_connector(hconn_x, hconn_x2, item_y_center, prefs); + // Small vertical line down to children + if ( has_children() && is_open() ) + draw_vertical_connector(hconn_x_center, item_y_center, Y+H, prefs); + // Connectors for last child + if ( !is_root() ) { + if ( lastchild ) draw_vertical_connector(hconn_x, Y, item_y_center, prefs); + else draw_vertical_connector(hconn_x, Y, Y+H, prefs); + } + } + // Draw collapse icon + if ( has_children() && prefs.showcollapse() ) { + // Draw icon image + if ( is_open() ) { + prefs.closeicon()->draw(icon_x,icon_y); + } else { + prefs.openicon()->draw(icon_x,icon_y); + } + } + // Background for this item + // Draw bg only if different from tree's bg + if ( bg != tree->color() || is_selected() ) { + if ( is_selected() ) { // Selected? Use selectbox() style + fl_draw_box(prefs.selectbox(),bg_x,bg_y,bg_w,bg_h,bg); + } else { // Not Selected? use plain filled rectangle + fl_color(bg); + fl_rectf(bg_x,bg_y,bg_w,bg_h); + } + if ( widget() ) widget()->damage(FL_DAMAGE_ALL); // if there's a child widget, we just damaged it + } + // Draw user icon (if any) + if ( usericon() ) { + // Item has user icon? Use it + int uicon_y = item_y_center - (usericon()->h() >> 1); + usericon()->draw(uicon_x,uicon_y); + } else if ( prefs.usericon() ) { + // Prefs has user icon? Use it + int uicon_y = item_y_center - (prefs.usericon()->h() >> 1); + prefs.usericon()->draw(uicon_x,uicon_y); + } + // Draw label +#if FLTK_ABI_VERSION >= 10302 + if ( _label && + ( !widget() || prefs.item_draw_mode() == + FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) { +#else + if ( _label && !widget() ) { // back compat: don't draw label if widget() present +#endif + int label_y = Y+(H/2)+(_labelsize/2)-fl_descent()/2; + fl_color(fg); + fl_font(_labelfont, _labelsize); + fl_draw(_label, label_x, label_y); + } + } // end non-child damage + // Draw child FLTK widget? + if ( widget() && widget()->damage() ) { + widget()->draw(); } - } else { - // No label widget? Draw text label - if ( _label && !clipped ) { - fl_color(fg); - fl_draw(_label, X+useroff, Y+H-fl_descent()-1); + // Draw focus box around item's bg last + if ( this == itemfocus && Fl::visible_focus() && Fl::focus() == tree) { + draw_item_focus(FL_NO_BOX,bg,bg_x+1,bg_y+1,bg_w-1,bg_h-1); } - } - if ( !clipped && - this == itemfocus && - Fl::visible_focus() && - Fl::focus() == tree) { - // Draw focus box around this item - draw_item_focus(FL_NO_BOX,bg,bx+1,by+1,bw-1,bh-1); - } - Y += H; - } // end drawthis - // Draw children + } // end drawthis + } // end clipped + if ( drawthis ) Y += H; // adjust Y (even if clipped) + // Draw child items (if any) if ( has_children() && is_open() ) { - int child_x = drawthis ? // offset children to right, - (hcenterx - (icon_w/2) + 1) : X; // unless didn't drawthis + int child_x = drawthis ? (hconn_x_center - (icon_w/2) + 1) // offset children to right, + : X; // unless didn't drawthis int child_w = W - (child_x-X); int child_y_start = Y; for ( int t=0; t<children(); t++ ) { @@ -715,7 +757,7 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, // Special 'clipped' calculation. (intentional variable shadowing) int clipped = ((child_y_start < tree_top) && (Y < tree_top)) || ((child_y_start > tree_bot) && (Y > tree_bot)); - if (!clipped) draw_vertical_connector(hstartx, child_y_start, Y, prefs); + if (!clipped) draw_vertical_connector(hconn_x, child_y_start, Y, prefs); } } } diff --git a/src/Fl_Tree_Prefs.cxx b/src/Fl_Tree_Prefs.cxx index b8b640d4a..c32262d5b 100644 --- a/src/Fl_Tree_Prefs.cxx +++ b/src/Fl_Tree_Prefs.cxx @@ -125,11 +125,15 @@ Fl_Tree_Prefs::Fl_Tree_Prefs() { _labelsize = FL_NORMAL_SIZE; _marginleft = 6; _margintop = 3; - //_marginright = 3; - //_marginbottom = 3; +#if FLTK_ABI_VERSION >= 10302 + _marginbottom = 20; +#endif _openchild_marginbottom = 0; _usericonmarginleft = 3; _labelmarginleft = 3; +#if FLTK_ABI_VERSION >= 10302 + _widgetmarginleft = 3; +#endif _linespacing = 0; _labelfgcolor = FL_BLACK; _labelbgcolor = FL_WHITE; @@ -148,6 +152,10 @@ Fl_Tree_Prefs::Fl_Tree_Prefs() { _sortorder = FL_TREE_SORT_NONE; _selectbox = FL_FLAT_BOX; _selectmode = FL_TREE_SELECT_SINGLE; +#if FLTK_ABI_VERSION >= 10302 + _itemreselectmode = FL_TREE_SELECTABLE_ONCE; + _itemdrawmode = FL_TREE_ITEM_DRAW_WIDGET_ONLY; +#endif // Let fltk's current 'scheme' affect defaults if ( Fl::scheme() ) { if ( strcmp(Fl::scheme(), "gtk+") == 0 ) { |
