Your subclasses can directly descend from Fl_Object or any other subclass of Fl_Object. There are only four virtual methods that you can override to change how FL interacts with your object. They are described quickly here:
virtual int handle(int event);
virtual void draw();
virtual void resize(int,int,int,int);
virtual ~Fl_Object();
These methods are provided for subclasses to use.
Fl_Object(int x, int y, int w, int h, const char
*label=0);
type(0); box(FL_NO_BOX); color(FL_GRAY); color2(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);
uchar type() const;
void type(uchar);
FL 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 FL mechanisim, by having type() have a unique value. This is useful for container objects. To do this, use a value greater than 100. Grep through all the header files for "RESERVED_TYPE" to find an unused number. FL checks for the Fl_Window class using this mechanism in many places, which means you can't use this to differentiate subclasses of Fl_Window...
uchar flags() const;
void set_flag(int c);
void clear_flag(int c);
enum {ACTIVE=1, VISIBLE=2, SHORTCUT_LABEL=64, CHANGED=128};
int test_shortcut() const;
static int test_shortcut(const char *);
The second version lets you do this test to an arbitrary string.
void x(int);
void y(int);
void w(int);
void h(int);
void damage(uchar mask);
void clear_damage(uchar value = 0);
uchar damage()
void set_visible();
void clear_visible();
int handle(int event)
is called to
handle each event passed to the object. 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 handle(), for an object 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 object! } return 1; case FL_SHORTCUT: if (Fl::event_key() == 'x') {do_callback(); return 1;} return 0; default: return 0; } } }
If your object has children objects, it is your responsibility to call handle() on them, after deciding which object to send the event to, and return their return value. For this reason handle() is a public method. You also need to set Fl::belowmouse() or Fl::focus() if you want these events passed to the child.
The return value can be used to communicate information to the parent object. In general non-zero means you understood and used the event, and zero means nothing was done. A return value of zero means the parent object is free to try sending the event to a different object.
Usually it is not useful to pass events to your base class by
calling their handle() routine.
The virtual method draw() is called when Fl wants you to redraw
your object. It should completely update your object. It will be
called if damage() is non-zero, and damage() will be cleared to zero
after it returns.
The functions you can use to draw are described in <FL/fl_draw.H>.
You can also call some protected methods on Fl_Object. Most
of these are shortcuts for things that can be accomplished with the
fl_draw calls:
damage() contains the bitwise-or of all the damage(n) calls to this
object since it was last drawn. You can use this for minimal update,
by assigning meanings to the bits and using damage(n) rather than
redraw() from inside your handle() method.
The redraw() method just does damage(-1), that is it turns all the
bits on. The best way to handle this is to pick a bit (such as
damage()&128) to cause all non-minimul-update parts of your object
(such as the box()) to redraw.
Damage from the window system will also turn all the bits on, but
the static variable If your object has children objects, your draw() routine must draw
them. This is a bit clumsy to allow for minimal update. Calling
redraw() or damage(n) on a child will also do damage(1) on all parent
objects. Thus the 1 bit in damage() indicates that a child needs to
be redrawn.
The following methods on Fl_Object are designed to be called by a
parent object as part of that parent's draw() method. You should not
call them in any other context: You must reserve the '1' bit of damage() to indicate that a child
object needs to be drawn. If possible, you should not do anything
other than draw children when damage()==1.
If any other bits of damage() are on, then your object itself
needs to be redrawn. If in the course of redrawing yourself you
obscure part of a child, call child->redraw_child(). This will draw
the child if it is not clipped and if it does not have
damage() set (this is so when you call the child again below it does
not draw it twice). If you know you have only obscured a portion of
the child it may be faster to use fl_clip to clip to only that area.
If all the bits of damage() are on, then your whole object
is clobbered. This is in fact the state you will be in if your object
is called by redraw_child() from the parent. You must draw
everything, and then call child->redraw_child() on every child.
If the '1' bit in damage() is set, then at some point in your
drawing code, usually at the end, you must call child->draw_child() on
every child. If the child is not clipped and has damage() set, it
will redraw it.
If you are interested in the labels of the child objects, you must
call child->draw_outside_label() on each of them. You can do this
whenever it is appropriate. Or grab the labels and print them with
your own mechanism.
void Fl_Object::draw()
void draw_box() const ;
Draw this object's box(), using the dimensions of the object.
void draw_box(uchar b,ulong c) const ;
Pretend the box()==b and the color()==c and draw this object's box.
void draw_label() const ;
If (align()==FL_ALIGN_CENTER || align()&FL_ALIGN_INSIDE), then draw
this object's label(), using the object's bounding box. Notice that
this does not draw labels outside the object. If the SHORTCUT_LABEL
flag is on, this searches for '&' characters and underscores the next
character.
void draw_label(int x,int y,int w,int h) const
;
Do the same thing except use the passed bounding box. This is useful
so "centered" labels are aligned with some feature.
Minimal Update
fl_clipped
will be true, and output will be
clipped to the rectangle in the static structure
fl_current_clip
. You can use this to avoid calculating
drawings that will not be seen.
Drawing children objects
Draw the labels that are not drawn by draw_label().
void child->draw_outside_label() const;
If damage() is non-zero, and the object is not clipped by
fl_current_clip, and it is not an X window, then call draw() on it and
then clears damage().
void child->draw_child();
If damage() is zero, and the object is not clipped by
fl_current_clip, and it is not an X window, then set damage() to -1
and call draw() on it and then clears the damage() value.
void child->redraw_child();
How to use these methods: