diff options
Diffstat (limited to 'src/Fl_Scroll.cxx')
| -rw-r--r-- | src/Fl_Scroll.cxx | 232 |
1 files changed, 160 insertions, 72 deletions
diff --git a/src/Fl_Scroll.cxx b/src/Fl_Scroll.cxx index 77c35d7a4..085d47bf0 100644 --- a/src/Fl_Scroll.cxx +++ b/src/Fl_Scroll.cxx @@ -52,6 +52,9 @@ void Fl_Scroll::fix_scrollbar_order() { } } +// Draw widget's background and children within a specific clip region +// So widget can just redraw damaged parts. +// void Fl_Scroll::draw_clip(void* v,int X, int Y, int W, int H) { fl_push_clip(X,Y,W,H); Fl_Scroll* s = (Fl_Scroll*)v; @@ -93,6 +96,126 @@ void Fl_Scroll::draw_clip(void* v,int X, int Y, int W, int H) { } /** + Calculate visibility/size/position of scrollbars, find children's bounding box. + The \p si paramater will be filled with data from the calculations. + Derived classes can make use of this call to figure out the scrolling area + eg. during resize() handling. + \param[in] si -- ScrollInfo structure + \returns Structure containing the calculated info. +*/ +void Fl_Scroll::recalc_scrollbars(ScrollInfo &si) { + + // inner box of widget (excluding scrollbars) + si.innerbox_x = x()+Fl::box_dx(box()); + si.innerbox_y = y()+Fl::box_dy(box()); + si.innerbox_w = w()-Fl::box_dw(box()); + si.innerbox_h = h()-Fl::box_dh(box()); + + // accumulate a bounding box for all the children + si.child_l = si.innerbox_x; + si.child_r = si.innerbox_x; + si.child_b = si.innerbox_y; + si.child_t = si.innerbox_y; + int first = 1; + Fl_Widget*const* a = array(); + for (int i=children()-2; i--;) { + Fl_Widget* o = *a++; + if ( first ) { + first = 0; + si.child_l = o->x(); + si.child_r = o->x()+o->w(); + si.child_b = o->y()+o->h(); + si.child_t = o->y(); + } else { + if (o->x() < si.child_l) si.child_l = o->x(); + if (o->y() < si.child_t) si.child_t = o->y(); + if (o->x()+o->w() > si.child_r) si.child_r = o->x()+o->w(); + if (o->y()+o->h() > si.child_b) si.child_b = o->y()+o->h(); + } + } + + // Turn the scrollbars on and off as necessary. + // See if children would fit if we had no scrollbars... + { + int X = si.innerbox_x; + int Y = si.innerbox_y; + int W = si.innerbox_w; + int H = si.innerbox_h; + + si.scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); + si.vneeded = 0; + si.hneeded = 0; + if (type() & VERTICAL) { + if ((type() & ALWAYS_ON) || si.child_t < Y || si.child_b > Y+H) { + si.vneeded = 1; + W -= si.scrollsize; + if (scrollbar.align() & FL_ALIGN_LEFT) X += si.scrollsize; + } + } + if (type() & HORIZONTAL) { + if ((type() & ALWAYS_ON) || si.child_l < X || si.child_r > X+W) { + si.hneeded = 1; + H -= si.scrollsize; + if (scrollbar.align() & FL_ALIGN_TOP) Y += si.scrollsize; + // recheck vertical since we added a horizontal scrollbar + if (!si.vneeded && (type() & VERTICAL)) { + if ((type() & ALWAYS_ON) || si.child_t < Y || si.child_b > Y+H) { + si.vneeded = 1; + W -= si.scrollsize; + if (scrollbar.align() & FL_ALIGN_LEFT) X += si.scrollsize; + } + } + } + } + si.innerchild_x = X; + si.innerchild_y = Y; + si.innerchild_w = W; + si.innerchild_h = H; + } + + // calculate hor scrollbar position + si.hscroll_x = si.innerchild_x; + si.hscroll_y = (scrollbar.align() & FL_ALIGN_TOP) + ? si.innerbox_y + : si.innerbox_y + si.innerbox_h - si.scrollsize; + si.hscroll_w = si.innerchild_w; + si.hscroll_h = si.scrollsize; + + // calculate ver scrollbar position + si.vscroll_x = (scrollbar.align() & FL_ALIGN_LEFT) + ? si.innerbox_x + : si.innerbox_x + si.innerbox_w - si.scrollsize; + si.vscroll_y = si.innerchild_y; + si.vscroll_w = si.scrollsize; + si.vscroll_h = si.innerchild_h; + + // calculate h/v scrollbar values (pos/size/first/total) + si.hpos = si.innerchild_x - si.child_l; + si.hsize = si.innerchild_w; + si.hfirst = 0; + si.htotal = si.child_r - si.child_l; + if ( si.hpos < 0 ) { si.htotal += (-si.hpos); si.hfirst = si.hpos; } + + si.vpos = si.innerchild_y - si.child_t; + si.vsize = si.innerchild_h; + si.vfirst = 0; + si.vtotal = si.child_b - si.child_t; + if ( si.vpos < 0 ) { si.vtotal += (-si.vpos); si.vfirst = si.vpos; } + +// printf("DEBUG --- ScrollInfo ---\n"); +// printf("DEBUG scrollsize: %d\n", si.scrollsize); +// printf("DEBUG hneeded, vneeded: %d %d\n", si.hneeded, si.vneeded); +// printf("DEBUG innerbox xywh: %d %d %d %d\n", si.innerbox_x, si.innerbox_y, si.innerbox_w, si.innerbox_h); +// printf("DEBUG innerchild xywh: %d %d %d %d\n", si.innerchild_x, si.innerchild_y, si.innerchild_w, si.innerchild_h); +// printf("DEBUG child lrbt: %d %d %d %d\n", si.child_l, si.child_r, si.child_b, si.child_t); +// printf("DEBUG hscroll xywh: %d %d %d %d\n", si.hscroll_x, si.hscroll_y, si.hscroll_w, si.hscroll_h); +// printf("DEBUG vscroll xywh: %d %d %d %d\n", si.vscroll_x, si.vscroll_y, si.vscroll_w, si.vscroll_h); +// printf("DEBUG horz scroll vals: %d %d %d %d\n", si.hpos, si.hsize, si.hfirst, si.htotal); +// printf("DEBUG vert scroll vals: %d %d %d %d\n", si.vpos, si.vsize, si.vfirst, si.vtotal); +// printf("DEBUG \n"); +} + +/** Returns the bounding box for the interior of the scrolling area, inside the scrollbars. @@ -157,79 +280,43 @@ void Fl_Scroll::draw() { } } - // accumulate bounding box of children: - int l = X; int r = X; int t = Y; int b = Y; - Fl_Widget*const* a = array(); - for (int i=children()-2; i--;) { - Fl_Object* o = *a++; - if (o->x() < l) l = o->x(); - if (o->y() < t) t = o->y(); - if (o->x()+o->w() > r) r = o->x()+o->w(); - if (o->y()+o->h() > b) b = o->y()+o->h(); - } + // Calculate where scrollbars should go, and draw them + { + ScrollInfo si; + recalc_scrollbars(si); - // turn the scrollbars on and off as necessary: - // See if children would fit if we had no scrollbars... - X = x()+Fl::box_dx(box()); - Y = y()+Fl::box_dy(box()); - W = w()-Fl::box_dw(box()); - H = h()-Fl::box_dh(box()); - int vneeded = 0; - int hneeded = 0; - if (type() & VERTICAL) { - if ((type() & ALWAYS_ON) || t < Y || b > Y+H) { - vneeded = 1; - W -= scrollbar.w(); - if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w(); - } - } - if (type() & HORIZONTAL) { - if ((type() & ALWAYS_ON) || l < X || r > X+W) { - hneeded = 1; - H -= hscrollbar.h(); - if (scrollbar.align() & FL_ALIGN_TOP) Y += hscrollbar.h(); - // recheck vertical since we added a horizontal scrollbar - if (!vneeded && (type() & VERTICAL)) { - if ((type() & ALWAYS_ON) || t < Y || b > Y+H) { - vneeded = 1; - W -= scrollbar.w(); - if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w(); - } + // Now that we know what's needed, make it so. + if (si.vneeded && !scrollbar.visible()) { + scrollbar.set_visible(); + d = FL_DAMAGE_ALL; + } + else if (!si.vneeded && scrollbar.visible()) { + scrollbar.clear_visible(); + draw_clip(this, si.vscroll_x, si.vscroll_y, si.vscroll_w, si.vscroll_h); + d = FL_DAMAGE_ALL; + } + if (si.hneeded && !hscrollbar.visible()) { + hscrollbar.set_visible(); + d = FL_DAMAGE_ALL; + } + else if (!si.hneeded && hscrollbar.visible()) { + hscrollbar.clear_visible(); + draw_clip(this, si.hscroll_x, si.hscroll_y, si.hscroll_w, si.hscroll_h); + d = FL_DAMAGE_ALL; + } + else if ( hscrollbar.h() != si.scrollsize || scrollbar.w() != si.scrollsize ) { + // scrollsize changed + d = FL_DAMAGE_ALL; } - } - } - // Now that we know what's needed, make it so. - if (vneeded && !scrollbar.visible()) { - scrollbar.set_visible(); - d = FL_DAMAGE_ALL; - } - else if (!vneeded && scrollbar.visible()) { - scrollbar.clear_visible(); - draw_clip(this, - scrollbar.align()&FL_ALIGN_LEFT ? X : X+W-scrollbar.w(), - Y, scrollbar.w(), H); - d = FL_DAMAGE_ALL; - } - if (hneeded && !hscrollbar.visible()) { - hscrollbar.set_visible(); - d = FL_DAMAGE_ALL; - } - else if (!hneeded && hscrollbar.visible()) { - hscrollbar.clear_visible(); - draw_clip(this, - X, scrollbar.align()&FL_ALIGN_TOP ? Y : Y+H-hscrollbar.h(), - W, hscrollbar.h()); - d = FL_DAMAGE_ALL; - } - scrollbar.resize(scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar.w() : X+W, - Y, scrollbar.w(), H); - scrollbar.value(oldy = yposition_ = (Y-t), H, 0, b-t); + scrollbar.resize(si.vscroll_x, si.vscroll_y, si.vscroll_w, si.vscroll_h); + oldy = yposition_ = si.vpos; // si.innerchild_y - si.child_t; + scrollbar.value(si.vpos, si.vsize, si.vfirst, si.vtotal); - hscrollbar.resize(X, - scrollbar.align()&FL_ALIGN_TOP ? Y-hscrollbar.h() : Y+H, - W, hscrollbar.h()); - hscrollbar.value(oldx = xposition_ = (X-l), W, 0, r-l); + hscrollbar.resize(si.hscroll_x, si.hscroll_y, si.hscroll_w, si.hscroll_h); + oldx = xposition_ = si.hpos; // si.innerchild_x - si.child_l; + hscrollbar.value(si.hpos, si.hsize, si.hfirst, si.htotal); + } // draw the scrollbars: if (d & FL_DAMAGE_ALL) { @@ -254,7 +341,7 @@ void Fl_Scroll::resize(int X, int Y, int W, int H) { // move all the children: Fl_Widget*const* a = array(); for (int i=children()-2; i--;) { - Fl_Object* o = *a++; + Fl_Widget* o = *a++; o->position(o->x()+dx, o->y()+dy); } if (dw==0 && dh==0) { @@ -312,8 +399,9 @@ Fl_Scroll::Fl_Scroll(int X,int Y,int W,int H,const char* L) hscrollbar(X,Y+H-Fl::scrollbar_size(), W-Fl::scrollbar_size(),Fl::scrollbar_size()) { type(BOTH); - xposition_ = 0; - yposition_ = 0; + xposition_ = oldx = 0; + yposition_ = oldy = 0; + scrollbar_size_ = 0; hscrollbar.type(FL_HORIZONTAL); hscrollbar.callback(hscrollbar_cb); scrollbar.callback(scrollbar_cb); |
