summaryrefslogtreecommitdiff
path: root/fluid/widget_browser.cxx
diff options
context:
space:
mode:
authorMatthias Melcher <git@matthiasm.com>2021-12-17 18:34:51 +0100
committerMatthias Melcher <github@matthiasm.com>2021-12-17 18:38:26 +0100
commit3626e82057e2cb581afbd5495a87c00db7d7c9b8 (patch)
tree74c7cb984c9816542895fdd35c026cd29e908256 /fluid/widget_browser.cxx
parentba3041be6c86c05aef1f505a10df8c8b05e7b8de (diff)
GitHub #326: browser scrolling should be much improved
Code now convinces browser to rebuild when the tree changes by UI. When widgets are move, the current widget should always be visible. It's the responsibility of the UI callback to update the browser.
Diffstat (limited to 'fluid/widget_browser.cxx')
-rw-r--r--fluid/widget_browser.cxx74
1 files changed, 71 insertions, 3 deletions
diff --git a/fluid/widget_browser.cxx b/fluid/widget_browser.cxx
index 901680205..ac1e9da2e 100644
--- a/fluid/widget_browser.cxx
+++ b/fluid/widget_browser.cxx
@@ -175,9 +175,11 @@ static char *copy_trunc(char *p, const char *str, int maxl, int quote)
\todo It would be nice to be able to grab one or more nodes and mmove them
within the hierarchy.
*/
-Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l)
-: Fl_Browser_(X,Y,W,H,l),
-pushedtitle(NULL)
+Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l) :
+ Fl_Browser_(X,Y,W,H,l),
+ pushedtitle(NULL),
+ saved_h_scroll_(0),
+ saved_v_scroll_(0)
{
type(FL_MULTI_BROWSER);
Fl_Widget::callback(callback_stub);
@@ -504,4 +506,70 @@ int Widget_Browser::handle(int e) {
return Fl_Browser_::handle(e);
}
+/**
+ Save the current scrollbar postion during rebuild.
+ */
+void Widget_Browser::save_scroll_position() {
+ saved_h_scroll_ = hposition();
+ saved_v_scroll_ = position();
+}
+
+/**
+ Restore the previous scrollbar postion after rebuild.
+ */
+void Widget_Browser::restore_scroll_position() {
+ hposition(saved_h_scroll_);
+ position(saved_v_scroll_);
+}
+
+/**
+ Rebuild the browser layout to reflect multiple changes.
+ This clears internal caches, recalculates the scroll bar sizes, and
+ sends a redraw() request to the widget.
+ */
+void Widget_Browser::rebuild() {
+ save_scroll_position();
+ new_list();
+ damage(FL_DAMAGE_SCROLL);
+ redraw();
+ restore_scroll_position();
+}
+
+/**
+ Rebuild the browser layout and make sure that the given item is visible.
+ \param[in] inNode pointer to a widget node derived from Fl_Type.
+ */
+void Widget_Browser::display(Fl_Type *inNode) {
+ if (!inNode) {
+ // Alternative: find the first (last?) visible selected item.
+ return;
+ }
+ // remeber our current scroll position
+ int currentV = position(), newV = currentV;
+ int nodeV = 0;
+ // find the inNode in the tree and check, if it is already visible
+ Fl_Type *p=Fl_Type::first;
+ for ( ; p && p!=inNode; p=p->next) {
+ if (p->visible)
+ nodeV += item_height(p);
+ }
+ if (p) {
+ int xx, yy, ww, hh;
+ bbox(xx, yy, ww, hh);
+ int frame_top = xx-x();
+ int frame_bottom = frame_top + hh;
+ int node_height = item_height(inNode);
+ int margin_height = 2 * item_quick_height(inNode);
+ if (margin_height>hh/2) margin_height = hh/2;
+ // is the inNode above the current scroll position?
+ if (nodeV<currentV+margin_height)
+ newV = nodeV - margin_height;
+ else if (nodeV>currentV+frame_bottom-margin_height-node_height)
+ newV = nodeV - frame_bottom + margin_height + node_height;
+ if (newV<0)
+ newV = 0;
+ }
+ if (newV!=currentV)
+ position(newV);
+}