summaryrefslogtreecommitdiff
path: root/src/Fl_Scroll.cxx
diff options
context:
space:
mode:
authorGreg Ercolano <erco@seriss.com>2009-07-12 00:15:06 +0000
committerGreg Ercolano <erco@seriss.com>2009-07-12 00:15:06 +0000
commitfe687baefd32a8b962a05085c01a17cd6c7d4a97 (patch)
tree61e91912bed60fcc558d1ecfa4aeea7c39455ec9 /src/Fl_Scroll.cxx
parent9eaf693d4ac56849ffcf05e4c3f3027f4fc06be8 (diff)
Fl_Scroll mods for global scrollbar size control.
Also, unittest added (scrollbar size) to test these changes. Thanks to Albrecht for testing/peer review. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6828 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Scroll.cxx')
-rw-r--r--src/Fl_Scroll.cxx232
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);