From 497afccb07164373e0de6639e754d7d691f1926f Mon Sep 17 00:00:00 2001 From: Fabien Costantini Date: Tue, 14 Oct 2008 22:12:25 +0000 Subject: Doxygen pdf man: First version added in documentation/fltk.pdf, old doc removed, images, dox files moved to a new src directory. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6431 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- documentation/src/subclassing.dox | 531 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 531 insertions(+) create mode 100644 documentation/src/subclassing.dox (limited to 'documentation/src/subclassing.dox') diff --git a/documentation/src/subclassing.dox b/documentation/src/subclassing.dox new file mode 100644 index 000000000..a13e0a011 --- /dev/null +++ b/documentation/src/subclassing.dox @@ -0,0 +1,531 @@ +/** + + \page subclassing 7 - Adding and Extending Widgets + + +This chapter describes how to add your own widgets or extend existing +widgets in FLTK. + +\section subclassing_subclassing Subclassing + +New widgets are created by subclassing an existing FLTK widget, +typically Fl_Widget for controls and Fl_Group for +composite widgets. + +A control widget typically interacts with the user to receive and/or +display a value of some sort. + +A composite widget widget holds a list of child widgets and handles moving, +sizing, showing, or hiding them as needed. Fl_Group is the +main composite widget widget class in FLTK, and all of the other composite +widgets (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. + +\section subclassing_fl_widget 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. + +\section subclassing_constructor The Constructor + +The constructor should have the following arguments: + +\code +MyClass(int x, int y, int w, int h, const char *label = 0); +\endcode + +This will allow the class to be used in +FLUID +without problems. + +The constructor must call the constructor for the base class and +pass the same arguments: + +\code +MyClass::MyClass(int x, int y, int w, int h, const char *label) +: Fl_Widget(x, y, w, h, label) { +// do initialization stuff... +} +\endcode + +Fl_Widget's protected constructor sets x(), y(), +w(), h(), and label() to the passed values +and initializes the other instance variables to: + +\code +type(0); +box(FL_NO_BOX); +color(FL_BACKGROUND_COLOR); +selection_color(FL_BACKGROUND_COLOR); +labeltype(FL_NORMAL_LABEL); +labelstyle(FL_NORMAL_STYLE); +labelsize(FL_NORMAL_SIZE); +labelcolor(FL_FOREGROUND_COLOR); +align(FL_ALIGN_CENTER); +callback(default_callback,0); +flags(ACTIVE|VISIBLE); +image(0); +deimage(0); +\endcode + +\section subclassing_protected Protected Methods of Fl_Widget + +The following methods are provided for subclasses to use: + +\li Fl_Widget::clear_visible +\li Fl_Widget::damage +\li Fl_Widget::draw_box +\li Fl_Widget::draw_focus +\li Fl_Widget::draw_label +\li Fl_Widget::set_flag +\li Fl_Widget::set_visible +\li Fl_Widget::test_shortcut +\li Fl_Widget::type + + +void Fl_Widget::damage(uchar mask)
+void Fl_Widget::damage(uchar mask, int x, int y, int w, int h)
+uchar Fl_Widget::damage() + +\par +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), but the implementation of +your widget can call the private damage(n). + +\par +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. + +\par +The third form returns the bitwise-OR of all damage(n) +calls done since the last draw(). + +\par +When redrawing your widgets you should look at the damage bits to +see what parts of your widget need redrawing. The handle() +method can then set individual damage bits to limit the amount of drawing +that needs to be done: +\code +MyClass::handle(int event) { + ... + if (change_to_part1) damage(1); + if (change_to_part2) damage(2); + if (change_to_part3) damage(4); +} + +MyClass::draw() { + if (damage() & FL_DAMAGE_ALL) { + ... draw frame/box and other static stuff ... + } + + if (damage() & (FL_DAMAGE_ALL | 1)) draw_part1(); + if (damage() & (FL_DAMAGE_ALL | 2)) draw_part2(); + if (damage() & (FL_DAMAGE_ALL | 4)) draw_part3(); +} +\endcode + + +void Fl_Widget::draw_box() const
+void Fl_Widget::draw_box(Fl_Boxtype b, ulong c) const + +\par +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_focus() const
+void Fl_Widget::draw_focus(Fl_Boxtype b, int x, int y, int w, int h) const + +\par +Draws a focus box inside the widgets bounding box. The second +form allows you to specify a different bounding 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 + +\par +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). + +\par +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, like a moving slider. + +\par +The third form draws the label anywhere. It acts as though +FL_ALIGN_INSIDE has been forced on so 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) + +\par +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() + +\par +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) + +\par +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. + +\par +The second version lets you do this test against an arbitrary string. + + +uchar Fl_Widget::type() const
+void Fl_Widget::type(uchar t) + +\par +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. + +\par +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. + +\par +If you don't have RTTI you can use the clumsy FLTK mechanisim, by +having type() use 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_Window +you must use FL_WINDOW + n (n must be in the +range 1 to 7). + + +\section subclassing_events Handling Events + +The virtual method int Fl_Widget::handle(int event) is called +to handle each event passed to the widget. It can: + +\li Change the state of the widget. +\li Call + Fl_Widget::redraw() + if the widget needs to be redisplayed. +\li Call + Fl_Widget::damage(n) + if the widget needs a partial-update (assuming you provide support for + this in your + Fl_Widget::draw() + method). +\li Call + Fl_Widget::do_callback() + if a callback should be generated. +\li 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: + +\code +int MyClass::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, as the callback + // may delete the widget! + } + return 1; + case FL_SHORTCUT: + if (Fl::event_key() == 'x') { + do_callback(); + return 1; + } + return 0; + default: + return Fl_Widget::handle(event); + } +} +\endcode + +You must return non-zero if your handle() method +uses the event. If you return zero, the parent widget will try +sending the event to another widget. + + +\section subclassing_drawing 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. The draw() method +should be declared protected so that it can't be called from +non-drawing code. + +The damage() value 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 on the +FL_DAMAGE_ALL bit if it thinks the entire widget must +be redrawn, e.g. for 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_not_clipped(x,y,w,h) or fl_clip_box(...) +and skipping invisible parts. + +Besides the protected methods described above, FLTK provides a large +number of basic drawing functions, which are described +below. + +\section subclassing_resizing 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 composite widgets like +Fl_Scroll +may have a more efficient way of drawing the new position. + +\section subclassing_composite Making a Composite Widget + +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: + +\code +class MyClass : public Fl_Group { + Fl_Button the_button; + Fl_Slider the_slider; + ... +}; +\endcode + +The constructor has to initialize these instances. They are automatically +add()ed to the group, since the Fl_Group constructor does +Fl_Group::begin(). +Don't forget to call Fl_Group::end() or use the Fl_End pseudo-class: + +\code +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! +} +\endcode + +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: + +\code +void MyClass::static_slider_cb(Fl_Widget* v, void *) { // static method + ((MyClass*)(v->parent())->slider_cb(); +} +void MyClass::slider_cb() { // normal method + use(the_slider->value()); +} +\endcode + +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: + +\code +int MyClass::handle(int event) { + if (Fl_Group::handle(event)) return 1; + ... handle events that children don't want ... +} +\endcode + +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: + +\code +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 need to do this + } + } +} +\endcode + +Fl_Group provides some protected methods to make drawing +easier: + +\li draw_child +\li draw_outside_label +\li update_child + + +void Fl_Group::draw_child(Fl_Widget&) + +\par +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 + +\par +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&) + +\par +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. + +\section subclassing_cutnpaste Cut and Paste Support + +FLTK provides routines to cut and paste 8-bit text (in the future this +may be UTF-8) between applications: + +\li Fl::paste +\li Fl::selection +\li Fl::selection_owner + +It may be possible to cut/paste non-text data by using +Fl::add_handler(). + +\section subclassing_dragndrop Drag And Drop Support + +FLTK provides routines to drag and drop 8-bit text between applications: + +Drag'n'drop operations are are initiated by copying data to the +clipboard and calling the function +Fl::dnd(). + +Drop attempts are handled via events: + +\li FL_DND_ENTER +\li FL_DND_DRAG +\li FL_DND_LEAVE +\li FL_DND_RELEASE +\li FL_PASTE + +\section subclassing_fl_window Making a subclass of Fl_Window + +You may want your widget to be a subclass of +Fl_Window, Fl_Double_Window, or +FL_Gl_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_Windowis almost exactly like +subclassing Fl_Group, and in fact you can easily +switch a subclass back and forth. Watch out for the following +differences: + +-# Fl_Window is a subclass of Fl_Group so + make sure your constructor calls end() + unless you actually want children added to your window. + +-# When handling events and drawing, the upper-left corner is at + 0,0, not x(),y() as in other Fl_Widget's. + 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. + +\htmlonly +
+[Index]    +[Previous]  6 - Handling Events  +[Next]  8 - Using OpenGL  +\endhtmlonly +*/ -- cgit v1.2.3