Author: greg.ercolano
Date: 2009-07-11 17:15:06 -0700 (Sat, 11 Jul 2009)
New Revision: 6828
Log:
    Fl_Scroll mods for global scrollbar size control.
    Also, unittest added (scrollbar size) to test these changes.
    Thanks to Albrecht for testing/peer review.



Modified:
   branches/branch-1.3/FL/Fl_Scroll.H
   branches/branch-1.3/src/Fl_Scroll.cxx
   branches/branch-1.3/test/unittests.cxx

Modified: branches/branch-1.3/FL/Fl_Scroll.H
===================================================================
--- branches/branch-1.3/FL/Fl_Scroll.H  2009-07-10 14:06:04 UTC (rev 6827)
+++ branches/branch-1.3/FL/Fl_Scroll.H  2009-07-12 00:15:06 UTC (rev 6828)
@@ -95,11 +95,33 @@
   int xposition_, yposition_;
   int width_, height_;
   int oldx, oldy;
+  int scrollbar_size_;
   static void hscrollbar_cb(Fl_Widget*, void*);
   static void scrollbar_cb(Fl_Widget*, void*);
   void fix_scrollbar_order();
   static void draw_clip(void*,int,int,int,int);
 
+private:
+
+  //
+  //  Structure to manage scrollbar and widget interior sizes.
+  //
+  //  Private for now -- we'd like to expose some of this at 
+  //  some point to solve STR#1895.)
+  //
+  typedef struct {
+      int scrollsize;                                                  // the 
scrollsize (global|local)
+      int innerbox_x, innerbox_y, innerbox_w, innerbox_h;              // 
widget's inner box (excludes scrollbars)
+      int innerchild_x, innerchild_y, innerchild_w, innerchild_h;      // 
widget's inner box including scrollbars
+      int child_l, child_r, child_b, child_t;                          // 
child bounding box: left/right/bottom/top
+      int hneeded, vneeded;                                            // hor 
+ ver scrollbar visibility
+      int hscroll_x, hscroll_y, hscroll_w, hscroll_h;                  // hor 
scrollbar size/position
+      int vscroll_x, vscroll_y, vscroll_w, vscroll_h;                  // ver 
scrollbar size/position
+      int hpos, hsize, hfirst, htotal;                                 // hor 
scrollbar values (pos/size/first/total)
+      int vpos, vsize, vfirst, vtotal;                                 // ver 
scrollbar values (pos/size/first/total)
+  } ScrollInfo;
+  void recalc_scrollbars(ScrollInfo &si);
+
 protected:
 
   void bbox(int&,int&,int&,int&);
@@ -131,6 +153,41 @@
   int yposition() const {return yposition_;}
   void scroll_to(int, int);
   void clear();
+  /**
+    Gets the current size of the scrollbars' troughs, in pixels.
+
+    If this value is zero (default), this widget will use the 
+    Fl::scrollbar_size() value as the scrollbar's width.
+  
+    \returns Scrollbar size in pixels, or 0 if the global Fl::scrollsize() is 
being used.
+    \see Fl::scrollbar_size(int)
+  */
+  int scrollbar_size() const {
+      return(scrollbar_size_);
+  }
+  /**
+    Sets the pixel size of the scrollbars' troughs to the \p size, in pixels.
+
+    Normally you should not need this method, and should use
+    Fl::scrollbar_size(int) instead to manage the size of ALL 
+    your widgets' scrollbars. This ensures your application 
+    has a consistent UI, is the default behavior, and is normally
+    what you want.
+
+    Only use THIS method if you really need to override the global
+    scrollbar size. The need for this should be rare.
+    
+    Setting \p size to the special value of 0 causes the widget to
+    track the global Fl::scrollbar_size(), which is the default.
+    
+    \param[in] size Sets the scrollbar size in pixels.\n
+                    If 0 (default), scrollbar size tracks the global 
Fl::scrollbar_size()
+    \see Fl::scrollbar_size()
+  */
+  void scrollbar_size(int size) {
+      if ( size != scrollbar_size_ ) redraw();
+      scrollbar_size_ = size;
+  }   
 };
 
 #endif

Modified: branches/branch-1.3/src/Fl_Scroll.cxx
===================================================================
--- branches/branch-1.3/src/Fl_Scroll.cxx       2009-07-10 14:06:04 UTC (rev 
6827)
+++ branches/branch-1.3/src/Fl_Scroll.cxx       2009-07-12 00:15:06 UTC (rev 
6828)
@@ -52,6 +52,9 @@
   }
 }
 
+// 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 @@
 }
 
 /**
+   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 @@
     }
   }
 
-  // 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;
       }
-    }
-  }
-  // 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;
-  }
+      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;
+      }
 
-  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 @@
   // 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 @@
     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);

Modified: branches/branch-1.3/test/unittests.cxx
===================================================================
--- branches/branch-1.3/test/unittests.cxx      2009-07-10 14:06:04 UTC (rev 
6827)
+++ branches/branch-1.3/test/unittests.cxx      2009-07-12 00:15:06 UTC (rev 
6828)
@@ -158,6 +158,7 @@
 #include "unittest_text.cxx"
 #include "unittest_images.cxx"
 #include "unittest_viewport.cxx"
+#include "unittest_scrollbarsize.cxx"
 
 
 // callback whenever the browser value changes

_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit

Reply via email to