DO NOT REPLY TO THIS MESSAGE.  INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.

[STR New]

Link: http://www.fltk.org/str.php?L2767
Version: 1.3-feature


This patch fixes a problem where select() is used to select an item before
drawing (and in other instances) since the horizontal or virtual scrollbar
may be reported as visible when they won't be in the end (and the other way
around).  For example, browser box that is created to a certain size (up to
a max) based on number of items, example 2, now 2 items are added, select
(2) is used to select the second item, what ends up being drawn is 2nd
item at the top (first item scrolled off) with a scrollbar that is jacked
up because it's small.  Occurs because hscrollbar was reported as visible
at the time.  There are probably lots of similar conditions that occur. 
This patch fixes it, and adds a new item_quick_width so we can always
calculate the full size (quickly) instead of only partial (per scroll of
screen) if the widest item was deleted.   I've tested basic functionality,
probably need browser test app in test folder to allow adding/removing
items so edge cases and dynamiclly adding/removing items is fully tested.


Link: http://www.fltk.org/str.php?L2767
Version: 1.3-feature
Index: FL/Fl_Browser.H
===================================================================
--- FL/Fl_Browser.H     (revision 9168)
+++ FL/Fl_Browser.H     (working copy)
@@ -100,6 +100,7 @@
   void item_select(void* item, int val);
   int item_height(void* item) const ;
   int item_width(void* item) const ;
+  int item_quick_width(void *item) const;
   void item_draw(void* item, int X, int Y, int W, int H) const ;
   int full_height() const ;
   int incr_height() const ;
Index: FL/Fl_Browser_.H
===================================================================
--- FL/Fl_Browser_.H    (revision 9168)
+++ FL/Fl_Browser_.H    (working copy)
@@ -61,7 +61,6 @@
   int hposition_;      // where user wants it panned to
   int real_hposition_; // the current horizontal scrolling position
   int offset_;         // how far down top_ item the real_position is
-  int max_width;       // widest object seen so far
   uchar has_scrollbar_;        // which scrollbars are enabled
   Fl_Font textfont_;
   Fl_Fontsize textsize_;
@@ -69,12 +68,14 @@
   void* top_;          // which item scrolling position is in
   void* selection_;    // which is selected (except for FL_MULTI_BROWSER)
   void *redraw1,*redraw2; // minimal update pointers
-  void* max_width_item;        // which item has max_width_
   int scrollbar_size_; // size of scrollbar trough
 
   void update_top();
 
 protected:
+  int max_width;       // widest object seen so far
+  void* max_width_item;        // which item has max_width_
+  void set_scrollbar_visiblity();
 
   // All of the following must be supplied by the subclass:
   /**
@@ -118,6 +119,7 @@
     \returns The width of the item in pixels.
   */
   virtual int item_width(void *item) const = 0;
+  virtual int item_quick_width(void *item) const;
   virtual int item_quick_height(void *item) const ;
   /**
     This method must be provided by the subclass to draw the \p item
Index: src/Fl_Browser.cxx
===================================================================
--- src/Fl_Browser.cxx  (revision 9168)
+++ src/Fl_Browser.cxx  (working copy)
@@ -42,15 +42,17 @@
 #define NOTDISPLAYED 2
 
 // WARNING:
-//       Fl_File_Chooser.cxx also has a definition of this structure 
(FL_BLINE).
+//       Fl_File_Browser.cxx also has a definition of this structure 
(FL_BLINE).
 //       Changes to FL_BLINE *must* be reflected in Fl_File_Chooser.cxx as 
well.
 //       This hack in Fl_File_Chooser should be solved.
 //
+// NOTE: This is all fixed in STR2756
 struct FL_BLINE {      // data is in a linked list of these
   FL_BLINE* prev;
   FL_BLINE* next;
   void* data;
   Fl_Image* icon;
+  int width;
   short length;                // sizeof(txt)-1, may be longer than string
   char flags;          // selected, displayed
   char txt[1];         // start of allocated array
@@ -292,6 +294,7 @@
   strcpy(t->txt, newtext);
   t->data = d;
   t->icon = 0;
+  t->width=item_width(t);
   insert(line, t);
 }
 
@@ -337,6 +340,7 @@
     t = n;
   }
   strcpy(t->txt, newtext);
+  t->width=item_width(t);
   redraw_line(t);
 }
 
@@ -411,7 +415,16 @@
   return hmax; // previous version returned hmax+2!
 }
 
+
 /**
+  Returns width of item in pixels.
+  */
+
+int Fl_Browser::item_quick_width(void *item) const {
+  return ((FL_BLINE*)item)->width;
+}
+
+/**
   Returns width of \p item in pixels.
   This takes into account embedded \@ codes within the text() label.
   \param[in] item The item whose width is returned.
@@ -745,6 +758,10 @@
   if (t->flags & NOTDISPLAYED) {
     t->flags &= ~NOTDISPLAYED;
     full_height_ += item_height(t);
+    if (t->width > max_width) {
+      max_width=t->width;
+      max_width_item=t;
+    }
     if (Fl_Browser_::displayed(t)) redraw();
   }
 }
@@ -762,6 +779,10 @@
   FL_BLINE* t = find_line(line);
   if (!(t->flags & NOTDISPLAYED)) {
     full_height_ -= item_height(t);
+    if (max_width_item==t) {
+      max_width=0;
+      max_width_item=0;
+    }
     t->flags |= NOTDISPLAYED;
     if (Fl_Browser_::displayed(t)) redraw();
   }
Index: src/Fl_Browser_.cxx
===================================================================
--- src/Fl_Browser_.cxx (revision 9168)
+++ src/Fl_Browser_.cxx (working copy)
@@ -247,6 +247,12 @@
   update_top();
   if (item == item_first()) {position(0); return;}
 
+  // make sure scrollbar set properly  so scrolling/centering works
+  // proper, espically for the last line item which could be hidden
+  // by horizontal scrollbar if it's visible (which it would be
+  // prior to the first draw() call).
+  set_scrollbar_visiblity();
+
   int X, Y, W, H, Yp; bbox(X, Y, W, H);
   void* l = top_;
   Y = Yp = -offset_;
@@ -321,74 +327,123 @@
 #endif
 }
 
-// redraw, has side effect of updating top and setting scrollbar:
-/**
-  Draws the list within the normal widget bounding box.
+/***
+ determine if the scrollbars should be visible or not
+ and make adjustment as needed
 */
-void Fl_Browser_::draw() {
-  int drawsquare = 0;
-  update_top();
+void Fl_Browser_::set_scrollbar_visiblity()
+{
   int full_width_ = full_width();
   int full_height_ = full_height();
+
+  // note that the width may be reset to zero once the widest
+  // added item is removed.  at that point we want to scan
+  // all lines for the widest.
+  if (full_width_==0) {
+    max_width=0;
+    for (void* p = item_first(); p; p = item_next(p)) {
+      int ww=item_quick_width(p);
+      if (ww > max_width) {
+        max_width = ww;
+        max_width_item = p;
+      }
+    }
+    full_width_=max_width;
+  }
+
+  // this is here only to catch some new class from allowing
+  // full_height_ to go to zero when it shouldn't be
+  if (full_height_==0) {
+    full_height_=Fl_Browser_::full_height();
+  }
+
+  // save scrollbar visible status before adjustment to minimize
+  // drawing via damage.
+  unsigned int sb_vis=scrollbar.visible();
+  unsigned int hsb_vis=hscrollbar.visible();
+
+  // turn off horizontal so vertical scrollbar can determine if it
+  // needs to turn on without the horizontal scrollbar.
+  hscrollbar.clear_visible();
+
+  // now get area available
   int X, Y, W, H; bbox(X, Y, W, H);
-  int dont_repeat = 0;
-J1:
-  if (damage() & FL_DAMAGE_ALL) { // redraw the box if full redraw
-    Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
-    draw_box(b, x(), y(), w(), h(), color());
-    drawsquare = 1;
-  }
-  // see if scrollbar needs to be switched on/off:
+
+  // setup vertical scrollbar
   if ((has_scrollbar_ & VERTICAL) && (
        (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) {
     if (!scrollbar.visible()) {
       scrollbar.set_visible();
-      drawsquare = 1;
       bbox(X, Y, W, H);
     }
-  } else {
-    top_ = item_first(); real_position_ = offset_ = 0;
+  }
+  else {
     if (scrollbar.visible()) {
       scrollbar.clear_visible();
-      clear_damage((uchar)(damage()|FL_DAMAGE_SCROLL));
+      bbox(X, Y, W, H);
     }
   }
 
+  // setup horizontal scrollbar
   if ((has_scrollbar_ & HORIZONTAL) && (
        (has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_ > W)) {
-    if (!hscrollbar.visible()) {
+    // horizontal scrollbar needed
       hscrollbar.set_visible();
-      drawsquare = 1;
+    bbox(X, Y, W, H);
+    // check if vertical scrollbar now needed
+    if ((has_scrollbar_ & VERTICAL) && !scrollbar.visible() && full_height_ > 
H) {
+      scrollbar.set_visible();
       bbox(X, Y, W, H);
     }
-  } else {
-    real_hposition_ = 0;
-    if (hscrollbar.visible()) {
-      hscrollbar.clear_visible();
-      clear_damage((uchar)(damage()|FL_DAMAGE_SCROLL));
     }
+  else {
+    // already cleared before setup of vertical scrollbar above
   }
 
-  // Check the vertical scrollbar again, just in case it needs to be drawn
-  // because the horizontal one is drawn.  There should be a cleaner way
-  // to do this besides copying the same code...
-  if ((has_scrollbar_ & VERTICAL) && (
-       (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) {
-    if (!scrollbar.visible()) {
-      scrollbar.set_visible();
-      drawsquare = 1;
-      bbox(X, Y, W, H);
+  // determine how scrollbars may have changed
+  if (sb_vis!=scrollbar.visible()) {
+    // check if it used to be enabled, if so, reset to ensure all
+    // items start at top.
+    if (sb_vis) {
+      top_ = item_first();
+      real_position_ = offset_ = 0;
     }
-  } else {
-    top_ = item_first(); real_position_ = offset_ = 0;
-    if (scrollbar.visible()) {
-      scrollbar.clear_visible();
+    // cause redraw of widget
+    damage(FL_DAMAGE_ALL);
+  }
+
+  if (hsb_vis!=hscrollbar.visible()) {
+    // check if it used to be enabled, if so, clear any damaged
+    // scroll request and ensure at column 0.
+    if (hsb_vis) {
+      real_hposition_ = 0;
       clear_damage((uchar)(damage()|FL_DAMAGE_SCROLL));
     }
+    // cause redraw of widget
+    damage(FL_DAMAGE_ALL);
   }
+}
 
-  bbox(X, Y, W, H);
 
+// redraw, has side effect of updating top and setting scrollbar:
+/**
+  Draws the list within the normal widget bounding box.
+*/
+void Fl_Browser_::draw() {
+  int drawsquare = 0;
+  update_top();
+
+  // enable/disable scrollbar based on items
+  set_scrollbar_visiblity();
+
+  int X, Y, W, H; bbox(X, Y, W, H);
+
+  if (damage() & FL_DAMAGE_ALL) { // redraw the box if full redraw
+    Fl_Boxtype b = box() ? box() : FL_DOWN_BOX;
+    draw_box(b, x(), y(), w(), h(), color());
+    drawsquare = 1;
+  }
+
   fl_push_clip(X, Y, W, H);
   // for each line, draw it if full redraw or scrolled.  Erase background
   // if not a full redraw or if it is selected:
@@ -411,8 +466,6 @@
        draw_box(FL_BORDER_FRAME, X, yy+Y, W, hh, color());
        draw_focus(FL_NO_BOX, X, yy+Y, W+1, hh+1);
       }
-      int ww = item_width(l);
-      if (ww > max_width) {max_width = ww; max_width_item = l;}
     }
     yy += hh;
   }
@@ -425,43 +478,19 @@
   fl_pop_clip();
   redraw1 = redraw2 = 0;
 
-  if (!dont_repeat) {
-    dont_repeat = 1;
-    // see if changes to full_height caused by calls to slow_height
-    // caused scrollbar state to change, in which case we have to redraw:
-    full_height_ = full_height();
-    full_width_ = full_width();
-    if ((has_scrollbar_ & VERTICAL) &&
-       ((has_scrollbar_ & ALWAYS_ON) || position_ || full_height_>H)) {
-      if (!scrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; }
-    } else {
-      if (scrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; }
-    }
-    if ((has_scrollbar_ & HORIZONTAL) &&
-       ((has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_>W)) {
-      if (!hscrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; }
-    } else {
-      if (hscrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; }
-    }
-  }
-
   // update the scrollbars and redraw them:
   int scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size();
   int dy = top_ ? item_quick_height(top_) : 0; if (dy < 10) dy = 10;
   if (scrollbar.visible()) {
-    scrollbar.damage_resize(
-       scrollbar.align()&FL_ALIGN_LEFT ? X-scrollsize : X+W,
-       Y, scrollsize, H);
-    scrollbar.value(position_, H, 0, full_height_);
+    scrollbar.damage_resize(scrollbar.align()&FL_ALIGN_LEFT ? X-scrollsize : 
X+W, Y, scrollsize, H);
+    scrollbar.value(position_, H, 0, full_height());
     scrollbar.linesize(dy);
     if (drawsquare) draw_child(scrollbar);
     else update_child(scrollbar);
   }
   if (hscrollbar.visible()) {
-    hscrollbar.damage_resize(
-       X, scrollbar.align()&FL_ALIGN_TOP ? Y-scrollsize : Y+H,
-       W, scrollsize);
-    hscrollbar.value(hposition_, W, 0, full_width_);
+    hscrollbar.damage_resize(X, scrollbar.align()&FL_ALIGN_TOP ? Y-scrollsize 
: Y+H, W, scrollsize);
+    hscrollbar.value(hposition_, W, 0, full_width());
     hscrollbar.linesize(dy);
     if (drawsquare) draw_child(hscrollbar);
     else update_child(hscrollbar);
@@ -1027,6 +1056,20 @@
 // Default versions of some of the virtual functions:
 
 /**
+  This method may be provided by the subclass to return the width of the
+  \p item, in pixels.
+  Allow for two additional pixels for the list selection box.
+  This method differs from item_width in that it is only called for
+  selection and scrolling operations.
+  The default implementation calls item_width.
+  \param[in] item The item whose width to return.
+  \returns The width, in pixels.
+*/
+int Fl_Browser_::item_quick_width(void* item) const {
+  return item_width(item);
+}
+
+/**
   This method may be provided by the subclass to return the height of the
   \p item, in pixels.  
   Allow for two additional pixels for the list selection box.
Index: src/Fl_File_Browser.cxx
===================================================================
--- src/Fl_File_Browser.cxx     (revision 9168)
+++ src/Fl_File_Browser.cxx     (working copy)
@@ -80,6 +80,7 @@
   FL_BLINE     *next;          // Next item in list
   void         *data;          // Pointer to data (function)
   Fl_Image      *icon;         // Pointer to optional icon
+  int       width;      // width of item
   short                length;         // sizeof(txt)-1, may be longer than 
string
   char         flags;          // selected, displayed
   char         txt[1];         // start of allocated array
_______________________________________________
fltk-dev mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-dev

Reply via email to