| Century Embedded Technologies Nano-X SDK and Developer's Guide | ||
|---|---|---|
| Prev | Chapter 13. Extending and Adding Widgets | Next |
A "composite" widget contains one or more "child" widgets. To make a composite widget you should subclass Fl_Group. It is possible to make a composite object that is not a subclass of Fl_Group, but you'll have to duplicate the code in Fl_Group anyways.
Instances of the child widgets may be included in the parent:
class MyClass : public Fl_Group {
Fl_Button the_button;
Fl_Slider the_slider;
...
};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() or use the Fl_End pseudo-class:
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!
}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:
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());
}If you make the handle() method, you can quickly pass all the events to the children using the Fl_Group::handle() method. You don't need to override handle() if your composite widget does nothing other than pass events to the children:
int MyClass::handle(int event) {
if (Fl_Group::handle(event)) return 1;
... handle events that children don't want ...
}If you override draw() you need to draw all the children. If redraw() or damage() is called on a child, damage(FL_DAMAGE_CHILD) is done to the group, so this 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:
int MyClass::draw() {
Fl_Widget *const*a = array();
if (damage() == FL_DAMAGE_CHILD) { // 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
}
}
}Fl_Group provides some protected methods to make drawing easier:
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::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::update_child(Fl_Widget&)
Draws the child only if its damage() is non-zero. You should call this on all the children if your own damage is equal to FL_DAMAGE_CHILD. Nothing is done if the child is not visible() or if it is clipped.