This sounds like a good approach. I can share parts of my code. Note that I don't have the horizontal scrollbar fully implemented because I don't need it for my application. The vertical scrollbar works well enough. I draw my own scrollbar using a class derived from Fl_Slider. My solution is not ideal because the draw() function calculates whether there's a new scroll bar, and if there is, the entire window is redrawn after the contents appear, making it look like the scrollbar appears after the rest of the content. Ideally the scrollbar would appear with the content when it's first drawn (and I think that there's a lot of logic in Fl_Scroll to make this happen; I didn't want to do all of this).
// The scroll class uses different scroll bars than Fl_Scroll so they match the new look and feel. class hwi_scroll : public Fl_Scroll { public: hwi_scroll(int x, int y, int w, int h); void scroll_type(int t) { scroll_type_ = t; } static void cb_slider(hwi_slider* slider, hwi_scroll* scroll); protected: virtual void draw(void); int scroll_type_ = 0; // uses Fl_Scroll types. Default is never draw bars hwi_slider* scrollbar = nullptr; hwi_slider* hscrollbar = nullptr; };
hwi_scroll::hwi_scroll(int x, int y, int w, int h) : Fl_Scroll(x, y, w, h) { Fl_Scroll::type(0); // don't ever draw base class scrollbars }
void hwi_scroll::draw(void) { bool horizontal = false; // set to true if the horizontal scrollbar should be shown (not completely implemented) bool vertical = false; // set to true if the vertical scrollbar should be shown
// Find last child that is not a slider to get scroll area extents. This assumes that the children are laid out in order. int scroll_height = 0, scroll_width = 0; for (int i = children() - 1; i >= 0; --i) { if (dynamic_cast<Fl_Slider*>(child(i))) continue; if (scroll_type_ & Fl_Scroll::HORIZONTAL && child(i)->x() + child(i)->w() > this->x() + this->w()) { horizontal = true; scroll_width = child(i)->x() + child(i)->w() - this->x() - this->w(); } if (scroll_type_ & Fl_Scroll::VERTICAL && child(i)->y() + child(i)->h() > this->y() + this->h()) { vertical = true; scroll_height = child(i)->y() + child(i)->h() - this->y() - this->h(); } break; }
if (scroll_type_ & Fl_Scroll::HORIZONTAL) { if (scroll_type_ & Fl_Scroll::ALWAYS_ON) horizontal = true; }
if (scroll_type_ & Fl_Scroll::VERTICAL) { if (scroll_type_ & Fl_Scroll::ALWAYS_ON) vertical = true; }
if (horizontal) { scroll_width += 0; // FIXME: temporary get rid of unused variable warning } if (vertical) { if (!scrollbar) {
// make the children smaller to make room for the scroll bar
int slider_width = unit_height; for (int c = 0; c < children(); ++c) { if (child(c)->w() > this->w() - slider_width) child(c)->size(this->w() - slider_width, child(c)->h()); }
this->parent()->begin(); // scroll bar is not actually a child of the scroll class scrollbar = new hwi_slider(this->x() + this->w() - slider_width, this->y(), slider_width, this->h(), ""); scrollbar->bounds(0, scroll_height); scrollbar->callback((Fl_Callback*)cb_slider, this); this->parent()->end();
// FIXME: this works, but it's not ideal, because there's a delay between when the window appears and when the // scrollbar appears. redraw_window = true; } }
I proceeded to develop a solution on my own. The
way I handle it in my scroll subclass is to just ignore the
original scroll bars by setting the type to 0 and then drawing
my own scroll bars the way I want them to by adding my scroll
bar as a child of my scroll class. The scroll logic is done in a
callback for the scroll bar.
That's a very good idea, thanks for sharing it.
Your new class sounds interesting but yes there
are backward compatibility issues that are complicated to
address.
Meanwhile I found a way to do what you want to achieve with the
"old" Fl_Scroll widget. I'm still working on it, but it appears to
be doable.
For backwards compatibility it's necessary to leave the embedded
scrollbars which means wasting some memory if someone (like you)
wants to replace the scrollbars with their own class. The changes
are straight-forward though:
- add new public accessors that return pointers to the scrollbars
- old code can still access the embedded scrollbars but this is
(will be) deprecated
- new code should always access the scrollbars by using the pointers
- the implementation of Fl_Scroll also uses the pointers explicitly
(code changed internally)
- there will be new methods to replace one or both scrollbars with a
user's subclass of Fl_Scrollbar (I'm working on this)
Whenever a user replaces the internal scrollbars with their own, the
embedded scrollbars are no longer used by Fl_Scroll's code, just as
in your implementation. You don't need to implement the scrolling
logic yourself, it's all done by your own scrollbars automagically
;-)
At least as long as you don't want this and replace the callback of
the scrollbars as well for your special scrolling needs.
How does this sound?
Is your own code publicly available, and can you share it? I would
like to see what you had to do to make it work so I don't forget an
essential part. Thanks in advance.
On 8/25/25 21:40 Eric Sokolowsky wrote:
> I'm constructing a new application that runs primarily
under
> Linux/X11, but this question is not platform-specific.
I'm designing
> it to have a custom look and feel [...] I'm now trying to
figure out
> how to derive from Fl_Scroll so I can have a scrolling
list that is
> too large for a single screen. The problem is the
scrollbars that are
> instanced within Fl_Scroll. If they were pointers, I
could remove the
> default instances and replace them with my own, but since
they are not
> pointers, I cannot override their default drawing
behavior (at least
> how to do so is not immediately obvious to me).
You're right, this is a known issue (at least I'm aware of
this). I
thought about it and came to the conclusion that it would be
better to
have pointers and - eventually - methods to replace the
default
scrollbar widgets with ones derived by the user. Fl_Scroll has
some more
issues, particularly the fact that the scrollbars are
(implemented as)
real children of the widget which needs special treatment by
the widget
code and by users if they want to work on children. For
instance,
children() returns two more than the number of "real
children", i.e.
when the widget is instantiated, there are already two
children not
added by the user (the scrollbars).
OTOH, the drawback of using pointers for the scrollbars is
that we need
two more separate memory allocations, but IMHO this is
negligible.
> Does anyone have suggestions on how I might make a
scrolling box with
> a custom look without having to reimplement everything
already in
> Fl_Scroll? If it helps, I plan on only using a vertical
scroll bar and
> not a horizontal scroll bar.
>
> Thanks in advance for any advice.
Well, I don't know if this counts as "advice":
I've been working on another widget with project name
Fl_Scroll_New. It
works well as a proof of concept but it is not sufficiently
tested yet,
and there are no methods yet to replace the scrollbars by
user-derived
subclasses. Therefore I'm hesitating to publish it ...
New features and modifications:
- scrollbars are allocated separately
- scrollbars are NOT visible children of the Fl_Scrollbar_New
class,
i.e. they are not children of its Fl_Group
- children() returns the number of real children, i.e. 0
(zero) when the
widget is instantiated
- all code to reorder children to make the scrollbars the last
children
(in Fl_Scroll) has been removed
- scrollbars are no longer directly accessible as members as
in
Fl_Scroll (members `scrollbar` and `hscrollbar` IIRC)
- maybe more...
All these changes mean that we can't just replace the old
Fl_Scroll
widget with the new implementation because of backwards
compatibility. I
don't know of a better way than to offer another widget, may
it be
called Fl_Scroll_New or whatever.
Other suggestions would be appreciated, but I'd like to avoid
just
setting a `type` and intermixing old and new code within the
same code
base (for maintenance reasons). Maintaining two different
widgets is not
ideal as well, but anyway...
The "advice" would be to wait until we decided how to proceed
and
published the new Fl_Scroll[_New] widget which you can use to
derive
your own subclass of Fl_Scrollbar (and its draw() method).
This will not
be done before FLTK 1.5, but the widget itself would probably
be
compileable with FLTK 1.4.x.
Comments and suggestions (by devs and users) would be
appreciated!
Comments are owned by the poster. All other content is copyright 1998-2025 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.