Your subclasses can directly descend from Fl_Widget or any subclass of Fl_Widget. Fl_Widget has only four virtual methods, and overriding some or all of these may be necessary.
Parts of this document:
Class(int x, int y, int w, int h, const char* label = 0);
This will allow the class name to be typed into fluid and it will produce the correct call.
The constructor must call the constructor for the base class and pass the same arguments. Fl_Widget's protected constructor sets x(), y(), w(), h(), and label() to the passed values and initializes the other instance variables to:
type(0); box(FL_NO_BOX); color(FL_GRAY); selection_color(FL_GRAY); labeltype(FL_NORMAL_LABEL); labelstyle(FL_NORMAL_STYLE); labelsize(FL_NORMAL_SIZE); labelcolor(FL_BLACK); align(FL_ALIGN_CENTER); callback(default_callback,0); flags(ACTIVE|VISIBLE);
These methods are provided for subclasses to use.
uchar Fl_Widget::type() const;
void Fl_Widget::type(uchar);
Fltk does not use RTTI (Run Time Typing Infomation), to enhance portability. But this may change in the near future if RTTI becomes standard everywhere.
If you don't have RTTI you can use the clumsy fltk mechanisim, by having type() have a unique value. These unique values must be greater than the symbol FL_RESERVED_TYPE (which is 100). Grep through the header files for "FL_RESERVED_TYPE" to find an unused number. If you make a subclass of Fl_Group you must use FL_GROUP+n, and if you make a subclass of Fl_Window you must use FL_WINDOW+n (in both cases n is in the range 1-7).
void Fl_Widget::set_flag(SHORTCUT_LABEL);
int Fl_Widget::test_shortcut() const;
static int Fl_Widget::test_shortcut(const char *);
The second version lets you do this test to an arbitrary string.
void Fl_Widget::x(short);
void Fl_Widget::y(short);
void Fl_Widget::w(short);
void Fl_Widget::h(short);
void Fl_Widget::damage(uchar mask);
void Fl_Widget::damage(uchar mask,int x,int y,int w,int
h);
void Fl_Widget::clear_damage(uchar value = 0);
uchar Fl_Widget::damage()
void Fl_Widget::set_visible();
void Fl_Widget::clear_visible();
void Fl_Widget::draw_box() const ;
void Fl_Widget::draw_box(Fl_Boxtype b,ulong c) const
;
void Fl_Widget::draw_label() const ;
void Fl_Widget::draw_label(int x,int y,int w,int h) const
;
void Fl_Widget::draw_label(int x,int y,int w,int
h,Fl_Align align) const ;
int Fl_Widget::handle(int
event)
is called to handle each event passed to the widget.
It can:Events are identified the small integer argument. Other
information about the most recent event is stored in static locations
and aquired by calling Fl::event_*()
.
This other information remains valid until another event is read from
the X server.
Here is a sample Fl_Widget::handle(), for a widget that acts as a pushbutton and also accepts the keystroke 'x' to cause the callback:
int Fl_Pushbutton::handle(int event) { switch(event) { case FL_PUSH: highlight = 1; redraw(); return 1; case FL_DRAG: {int t = Fl::event_inside(this); if (t != highlight) {highlight = t; redraw();}} return 1; case FL_RELEASE: if (highlight) { highlight = 0; redraw(); do_callback(); // never do anything after a callback, so that the callback // may delete the widget! } return 1; case FL_SHORTCUT: if (Fl::event_key() == 'x') {do_callback(); return 1;} return 0; default: return 0; } } }
You must return non-zero if your handle() method used the event. If you return zero it indicates to the parent that it can try sending another widget the event.
It looks like it is best to make the handle() method public.
The virtual method Fl_Widget::draw() is called when fltk wants you
to redraw your widget. It will be called if and only if damage() is
non-zero, and damage() will be cleared to zero after it returns.
draw() should be declared protected, so that subclasses may call it
but it can't be called from non-drawing code.
damage() contains the bitwise-or of all the damage(n) calls to this
widget since it was last drawn. This can be used for minimal update,
by only redrawing the parts whose bits are set. Fltk will turn
all the bits on if it thinks the entire widget must be redrawn
(for instance due to an expose event). It is easiest to program to
handle this by pretending a bit (usually damage()&128) draw the
non-minimal-update parts of your widget (such as the box()).
Expose events (and the above damage(b,x,y,w,h)) will cause draw()
to be called with fltk's clipping
turned on. You can greatly speed up redrawing in some cases by
testing The functions you can use to draw are described in <FL/fl_draw.H> or any of the protected
Fl_Widget::draw_* methods described above.
This should not call redraw(), at least if only the x() and
y() change. This is because group objects like Fl_Scroll may have a more efficient way of
drawing the new position.
It may be useful to refer to the size the widget was constructed
at, these are stored in Fl_Widget::ix(), iy(), iw(), and ih().
Resize should be declared public.
Instances of the child widgets may be included in the parent:
The constructor has to initialize these instances. They are
automatically add()ed to the group, since the Fl_Group constructor
does begin(). Don't forget to call end():
The child widgets need callbacks. These will be called with a
pointer to the children, but the widget itself may be found in the
parent() pointer of the child. Usually these callbacks can be static
private methods, with a matching private method:
If you make the handle() method, you can quickly pass all the
events to the children (notice that you don't need to override
handle() if your composite widget does nothing other than pass events
to the children):
If you override draw() you need to draw all the children. If
redraw() or damage() is called on a child, damage(1) is done to the
group. Thus the 1 bit of damage() can be used to indicate that a
child needs to be drawn. It is fastest if you avoid drawing anything
else in this case:
Fl_Group provides some protected methods to make drawing easier:
You may want your widget to be a subclass of Fl_Window. This can
be useful if your widget wants to occupy an entire window, and can
also be used to take advantage of system-provided clipping, or to work
with a library that expects a system window id to indicate where to
draw.
Subclassing Fl_Window is almost exactly like subclassing Fl_Widget,
in fact you can easily switch a subclass back and forth. Watch out
for the following differences:
You may also want to subclass Fl_Window in order to get access to
different X visuals or to change other X attributes of the windows,
See here for details.
virtual void Fl_Widget::draw()
fl_clipped
and fl_current_clip
and skipping invisible parts.
virtual void Fl_Widget::resize(int,int,int,int);
This is called when the widget is being resized or moved. The
arguments are the new position, width, and height. x(), y(), w(), and
h() still return the old size. You must call resize() on your
base class with the same arguments to get the widget size to actually
change.
virtual Fl_Widget::~Fl_Widget();
We all know why the destructor must be virtual don't we? Don't forget
to make it public.
Making a Composite/Group Widget
A "composite" widget contains one or more "child" widgets. To do this
you should subclass Fl_Group (it is
possible to make a composite object that is not a subclass of
Fl_Group, but this is very difficult).
class MyClass : public Fl_Group {
Fl_Button the_button;
Fl_Slider the_slider;
...
};
MyClass::MyClass(int x,int y,int w,int h) :
Fl_Group(x,y,w,h),
the_button(x+5,y+5,100,20),
the_slider(x,y+50,w,20)
{
...(you could add dynamically created child widgets here)...
end(); // don't forget to do this!
}
void MyClass::slider_cb(Fl_Widget* v, void *) { // static method
((MyClass*)(v->parent())->slider_cb();
}
void MyClass::slider_cb() { // normal method
use(the_slider->value());
}
int MyClass::handle(int event) {
if (Fl_Group::handle(event)) return 1;
... handle events that children don't want ...
}
int MyClass::draw() {
Fl_Widget*const* a = array();
if (damage()==1) { // only redraw some children
for (int i=children(); i--; a++) update_child(**a);
} else { // total redraw
... draw background graphics ...
// now draw all the children atop the background:
for (int i=children_; i--; a++) {
draw_child(**a);
draw_outside_label(**a); // you may not want to do this
}
}
}
void Fl_Group::draw_outside_label(Fl_Widget&) const;
Draw the labels that are not drawn by draw_label(). If you want more control over the
label positions you might want to call child->draw_label(x,y,w,h,a).
void Fl_Group::draw_child(Fl_Widget&);
This will force the child's damage() bits all to one and call draw()
on it, then clear the damage(). You should call this on all children
if a total redraw of your widget is requested, or if you draw
something (like a background box) that damages the child. Nothing is
done if the child is not visible() or if it is clipped.
void Fl_Group::update_child(Fl_Widget&);
Draws the child only if it's damage() is non-zero. You should call
this on all the children if your own damage is equal to 1. Nothing is
done if the child is not visible() or if it is clipped.
Making a subclass of Fl_Window