Greg Ercolano wrote:

> Sounds like you might be asking if Fl_Scroll's callback could be
> called whenever any of the scrollers are changed, so that your
> deriving class could do special child management.
> 
> Normally this kind of thing is done by having your child widget
> (the one to be INSIDE the scroller) override its resize(),
> since IIRC, scrolling is implemented by changing the child
> widget's position(), which is essentially a resize() on x/y only,
> leaving w/h alone.
> 
> I believe this is what Duncan and Albrecht are getting at
> with their replies regarding resize(), which at first seems
> unrelated from an 'event delivery' point of view, but might
> actually be another way to do what you want, where the child
> manages itself, rather than your class deriving from Fl_Scroll.

After some more code diving, I have determined that Fl_Scroll maintains its
scrollbars in its draw(). Though this works, it has one drawback as a
derived class cannot easily extend the functionality.

The problem I'm talking about is it is almost futile for a derived class to
maintain its viewable area (the area minus the scrollbars). It is futile
because on a call to the widget's resize(), there is no way on knowing if
the scrollbars are actually visible in the new size. Of course, that is
without duplicating the logic in Fl_Scroll::draw(). Another problem is that
the scrollbars do not have their min and max bounds adjusted upon calling
resize(). They are adjusted in draw().

For example, one widget I have that is derived from Fl_Scroll centres its
children if they fit in the Fl_Scroll when the scrollbars are not visible.
The widget works well, except for one instance when it is resized from
small to large (e.g. maximising the window). The centring of the widgets
happen in the resize() method but after the call to Fl_Scroll::resize(). If
the image is larger than the widget the scrollbars are visible. And say
that you scroll all the way to the right. If the widget is enlarged (e.g.
via maximising the window) the widget centring implementation accesses the
current state of the scrollbars. But since the scrollbars are not actually
updated until draw() is called, the state of the scrollbars (value and
bounds) are wrong. As a result, there is a empty space to the right of the
image because the centering code could not move the widget around during
the resize() call.

Here's some annotated code:


void Fl_Canvas::resize(int X, int Y, int W, int H)
{
   Fl_Scroll::resize(X, Y, W, H);

   // Determine the new viewable area
   recalc_dimensions();

   // Centre align all the layers
   for(int i = 0; i < children(); i++)
   {
      Fl_Widget *w = child(i);

      align_centre(w);
   }
}

void Fl_Canvas::recalc_dimensions()
{
   vx = x() + Fl::box_dx(box());
   vy = y() + Fl::box_dy(box());
   vw = w() - Fl::box_dw(box());
   vh = h() - Fl::box_dh(box());

   if(scrollbar.visible())
      vw -= scrollbar.w();

   if(hscrollbar.visible())
      vh -= hscrollbar.h();
}

void Fl_Canvas::align_centre(Fl_Widget *o)
{
   int sw = w() - Fl::box_dw(box()) - scrollbar.w();
   int sh = h() - Fl::box_dh(box()) - hscrollbar.h();

   // by default, the position o to be at the absolute origin of canvas
   // regardless of viewport position
   int cx = x() - (xposition() - Fl::box_dx(box())); 
   int cy = y() - (yposition() - Fl::box_dy(box()));

   // centre horizontally
   if(o->w() < sw)
      cx = x() + ((sw - o->w()) / 2);

   // centre vertically
   if(o->h() < sh)
      cy = y() + ((sh - o->h()) / 2);

   o->position(cx, cy);
}


Note that the scrollbar.visible() call in recalc_dimensions() will not be
the updated state with the new dimensions of the widget. Also, note that
xposition() in align_centre() will be the value of the scrollbar prior to
resizing. The scrollbar is not adjusted by Fl_Scroll until it's redrawn.

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

Reply via email to