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.