From d7b88a3bcc7e76f38ee5799be7722fd5a10781ef Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Wed, 13 Jan 1999 19:28:54 +0000 Subject: Updated all links so they work between files. Revision 1. git-svn-id: file:///fltk/svn/fltk/trunk@219 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- documentation/subclassing.html | 645 ++++++++++++++++++----------------------- 1 file changed, 282 insertions(+), 363 deletions(-) (limited to 'documentation/subclassing.html') diff --git a/documentation/subclassing.html b/documentation/subclassing.html index 7ed03ed7a..d15f691e2 100644 --- a/documentation/subclassing.html +++ b/documentation/subclassing.html @@ -1,63 +1,51 @@ - - - -

7 - Adding and Extending Widgets

- -This chapter describes how to add your own widgets or extend existing -widgets in FLTK. - + +

7 - Adding and Extending Widgets

+ This chapter describes how to add your own widgets or extend existing +widgets in FLTK.

Subclassing

- -New widgets are created by subclassing an existing FLTK widget, -typically Fl_Widget for controls and Fl_Group for -containers. - -

A control widget typically interacts with the user to receive and/or -display a value of some sort. - -

A container widget holds a list of child widgets and handles moving, -sizing, showing, or hiding them as needed. Fl_Group is the -main container widget class in FLTK, and all of the other containers -(Fl_Pack, Fl_Scroll, Fl_Tabs, Fl_Tile, -and Fl_Window) are subclasses of it. - -

You can also subclass other existing widgets to provide a different look -or user-interface. For example, the button widgets are all subclasses of -Fl_Button since they all interact with the user via a mouse button -click. The only difference is the code that draws the face of the button. - + New widgets are created by subclassing an existing FLTK widget, +typically Fl_Widget for controls and Fl_Group for +containers. +

A control widget typically interacts with the user to receive and/or +display a value of some sort.

+

A container widget holds a list of child widgets and handles moving, +sizing, showing, or hiding them as needed. Fl_Group is the +main container widget class in FLTK, and all of the other containers ( +Fl_Pack, Fl_Scroll, Fl_Tabs, Fl_Tile, +and Fl_Window) are subclasses of it.

+

You can also subclass other existing widgets to provide a different +look or user-interface. For example, the button widgets are all +subclasses of Fl_Button since they all interact with the user +via a mouse button click. The only difference is the code that draws +the face of the button.

Making a Subclass of Fl_Widget

- -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. - + 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.

The Constructor

- -The constructor should access the following arguments: - -

Protected Methods of Fl_Widget

- -The following methods are provided for subclasses to use: - - - -

void Fl_Widget::damage(uchar mask)
-void Fl_Widget::damage(uchar mask, int x, int y, int w, int h)
-uchar Fl_Widget::damage()

- -The first form indicates that a partial update of the object is -needed. The bits in mask are OR'd into damage(). Your -draw() routine can examine these bits to limit what it is -drawing. The public method Fl_Widget::redraw() simply does -Fl_Widget::damage(FL_DAMAGE_ALL). - -

The second form indicates that a region is damaged. If only these -calls are done in a window (no calls to damage(n)) then FLTK + The following methods are provided for subclasses to use: +

+

void Fl_Widget::damage(uchar mask) +
void Fl_Widget::damage(uchar mask, int x, int y, int w, int h) +
uchar Fl_Widget::damage()

+ The first form indicates that a partial update of the object is +needed. The bits in mask are OR'd into damage(). Your +draw() routine can examine these bits to limit what it is drawing. + The public method Fl_Widget::redraw() simply does +Fl_Widget::damage(FL_DAMAGE_ALL). +

The second form indicates that a region is damaged. If only these +calls are done in a window (no calls to damage(n)) then FLTK will clip to the union of all these calls before drawing anything. -This can greatly speed up incremental displays. The mask bits are or'd -into damage() unless this is a Fl_Window widget. - -

The third form returns the bitwise-OR of all damage(n) -calls done since the last draw(). The public method -redraw() does damage(FL_DAMAGE_ALL), but the -implementation of your widget can call the private damage(n). - -

void Fl_Widget::draw_box() const
-
void Fl_Widget::draw_box(Fl_Boxtype b, ulong c) const

- -The first form draws this widget's box(), using the dimensions -of the widget. - -The second form uses b as the box type and c as the -color for the box. - -

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

- -This is the usual function for a draw() method to call to draw -the widget's label. It does not draw the label if it is supposed to be -outside the box (on the assumption that the enclosing group will draw -those labels). - -

The second form uses the passed bounding box instead of the widget's -bounding box. This is useful so "centered" labels are aligned with some -feature, such as a moving slider. - -

The third form draws the label anywhere. It acts as though -FL_ALIGN_INSIDE has been forced on, the label will appear -inside the passed bounding box. This is designed for parent groups to -draw labels with. - -

void Fl_Widget::set_flag(SHORTCUT_LABEL)

- -If your constructor calls this it modifies draw_label() so -that '&' characters cause an underscore to be printed under the next -letter. - -

void Fl_Widget::set_visible()
-void Fl_Widget::clear_visible()

- -Fast inline versions of Fl_Widget::hide() and -Fl_Widget::show(). These do not send the FL_HIDE and -FL_SHOW events to the widget. - -

int Fl_Widget::test_shortcut() const
-static int Fl_Widget::test_shortcut(const char *s)

- -The first version tests Fl_Widget::label() against the current -event (which should be a FL_SHORTCUT event). If the label -contains a '&' character and the character after it matches the key -press, this returns true. This returns false if the -SHORTCUT_LABEL flag is off, if the label is NULL or -does not have a '&' character in it, or if the keypress does not match -the character. - -

The second version lets you do this test against an arbitrary string. - -

uchar Fl_Widget::type() const
-void Fl_Widget::type(uchar t)

- -The property Fl_Widget::type() can return an arbitrary 8-bit -identifier, and can be set with the protected method type(uchar t). -This value had to be provided for Forms compatibility, but you can use -it for any purpose you want. Try to keep the value less than 100 to -not interfere with reserved values. - -

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). -Look 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 to 7). - + This can greatly speed up incremental displays. The mask bits are +or'd into damage() unless this is a Fl_Window widget.

+

The third form returns the bitwise-OR of all damage(n) + calls done since the last draw(). The public method +redraw() does damage(FL_DAMAGE_ALL), but the +implementation of your widget can call the private damage(n).

+

void Fl_Widget::draw_box() const +
void Fl_Widget::draw_box(Fl_Boxtype b, ulong c) const

+ The first form draws this widget's box(), using the +dimensions of the widget. The second form uses b as the box +type and c as the color for the box. +

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

+ This is the usual function for a draw() method to call to +draw the widget's label. It does not draw the label if it is supposed +to be outside the box (on the assumption that the enclosing group will +draw those labels). +

The second form uses the passed bounding box instead of the widget's +bounding box. This is useful so "centered" labels are aligned with some +feature, such as a moving slider.

+

The third form draws the label anywhere. It acts as though +FL_ALIGN_INSIDE has been forced on, the label will appear inside +the passed bounding box. This is designed for parent groups to draw +labels with.

+

void Fl_Widget::set_flag(SHORTCUT_LABEL)

+ If your constructor calls this it modifies draw_label() so +that ''characters cause an underscore to be printed under the next +letter. +

void Fl_Widget::set_visible() +
void Fl_Widget::clear_visible()

+ Fast inline versions of Fl_Widget::hide() and +Fl_Widget::show(). These do not send the FL_HIDE and +FL_SHOW events to the widget. +

int Fl_Widget::test_shortcut() const +
static int Fl_Widget::test_shortcut(const char *s)

+ The first version tests Fl_Widget::label() against the +current event (which should be a FL_SHORTCUT event). If the +label contains a ''character and the character after it matches the key +press, this returns true. This returns false if the SHORTCUT_LABEL + flag is off, if the label is NULL or does not have a +''character in it, or if the keypress does not match the character. +

The second version lets you do this test against an arbitrary +string.

+

uchar Fl_Widget::type() const +
void Fl_Widget::type(uchar t)

+ The property Fl_Widget::type() can return an arbitrary 8-bit +identifier, and can be set with the protected method type(uchar t) +. This value had to be provided for Forms compatibility, but you can +use it for any purpose you want. Try to keep the value less than 100 +to not interfere with reserved values. +

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). + Look 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 to 7).

Handling Events

- -The virtual method int Fl_Widget::handle(int event) is called -to handle each event passed to the widget. It can: - -
    -
  • Change the state of the widget. - -
  • Call Fl_Widget::redraw() - if the widget needs to be redisplayed. - -
  • Call Fl_Widget::damage(n) if - the widget needs a partial-update (assumming you provide - support for this in your Fl_Widget::draw() method). - -
  • Call Fl_Widget::do_callback() - if a callback should be generated. - -
  • Call Fl_Widget::handle() on child widgets. -
- -Events are identified by the integer argument. Other information about -the most recent event is stored in static locations and aquired by -calling the Fl::event_*() functions. -This information remains valid until another event is handled. - -

Here is a sample handle() method for a widget that acts as a -pushbutton and also accepts the keystroke 'x' to cause the callback: - -

    + The virtual method int Fl_Widget::handle(int event) is called 
    +to handle each event passed to the widget. It can: 
    +
      +
    • Change the state of the widget.
    • +
    • Call Fl_Widget::redraw() + if the widget needs to be redisplayed.
    • +
    • Call +Fl_Widget::damage(n) if the widget needs a partial-update +(assumming you provide support for this in your Fl_Widget::draw() + method).
    • +
    • Call +Fl_Widget::do_callback() if a callback should be generated.
    • +
    • Call Fl_Widget::handle() on child widgets.
    • +
    + Events are identified by the integer argument. Other information +about the most recent event is stored in static locations and aquired +by calling the Fl::event_*() + functions. This information remains valid until another event is +handled. +

    Here is a sample handle() method for a widget that acts as +a pushbutton and also accepts the keystroke 'x' to cause the callback:

    +
      +
       int MyClass::handle(int event) {
         switch(event) {
           case FL_PUSH:
      @@ -247,75 +202,63 @@ int MyClass::handle(int event) {
             return 0;
         }
       }
      -
    - -You must return non-zero if your handle() method uses the -event. If you return zero it indicates to the parent widget that it can -try sending the event to another widget. - +
    +
+ You must return non-zero if your handle() method uses the +event. If you return zero it indicates to the parent widget that it can +try sending the event to another widget.

Drawing the Widget

- -The draw() virtual method 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 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). - -

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 fl_clipped and -fl_current_clip and skipping invisible parts. - -

Besides the protected methods described above, FLTK provide a large -number of basic drawing functions, which are described below. - + The draw() virtual method 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 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).

+

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 fl_clipped and fl_current_clip and +skipping invisible parts.

+

Besides the protected methods described above, FLTK provide a large +number of basic drawing functions, which are described +below.

Resizing the Widget

- -The resize(int x, int y, int w, int h) method 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 remain the old size. You must call -resize() on your base class with the same arguments to get the -widget size to actually change. - -

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. - + The resize(int x, int y, int w, int h) method 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 remain the old size. You must call resize() + on your base class with the same arguments to get the widget size to +actually change. +

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.

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 you'll have to duplicate the code in Fl_Group -anyways. - -

Instances of the child widgets may be included in the parent: - -

    + 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 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: - -
      +
      +
    + 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),
      @@ -324,41 +267,41 @@ MyClass::MyClass(int x, int y, int w, int h) :
         ...(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: - -
      +
      +
    + 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();
      +  ((MyClass*)(v->parent())->slider_cb();
       }
       void MyClass::slider_cb() { // normal method
      -  use(the_slider->value());
      +  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. -Note that you don't need to override handle() if your -composite widget does nothing other than pass events to the children: - -
      +
      +
    + If you make the handle() method, you can quickly pass all the +events to the children using the Fl_Group::handle() method. +Note that 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: - -
      +
      +
    + 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
      @@ -372,86 +315,62 @@ int MyClass::draw() {
           }
         }
       }
      -
    - -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 it's 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. - +
    +
+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 it's 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.

Cut and Paste Support

- -FLTK provides routines to cut and paste ASCII text (in the future this -may be UTF-8) between applications: - - - - -It may be possible to cut/paste non-ASCII data by using Fl::add_handler(). - + FLTK provides routines to cut and paste ASCII text (in the future this +may be UTF-8) between applications: + + It may be possible to cut/paste non-ASCII data by using +Fl::add_handler().

Making a subclass of Fl_Window

- -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: - -

    - -
  1. Fl_Window is a subclass of Fl_Group so - make sure your constructor calls end() (unless - you actually want children added to your window). - -
  2. When handling events and drawing, the upper-left corner is - at 0,0, not x(),y() as in other Fl_Widgets. - For instance, to draw a box around the widget, call - draw_box(0, 0, w(), h()), rather than - draw_box( x(), y(), w(), h()). - -
- -You may also want to subclass Fl_Window in order to get access to -different visuals or to change other attributes of the windows. See -Appendix F - Operating System Issues for more -information. - - - - + 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:

+
    +
  1. Fl_Window is a subclass of Fl_Group so make +sure your constructor calls end() (unless you actually +want children added to your window).
  2. +
  3. When handling events and drawing, the upper-left corner is at 0,0, +not x(),y() as in other Fl_Widgets. For instance, to +draw a box around the widget, call draw_box(0, 0, w(), h()), +rather than draw_box( x(), y(), w(), h()).
  4. +
+ You may also want to subclass Fl_Window in order to get +access to different visuals or to change other attributes of the +windows. See Appendix F - Operating +System Issues for more information. \ No newline at end of file -- cgit v1.2.3