summaryrefslogtreecommitdiff
path: root/documentation/src/subclassing.dox
diff options
context:
space:
mode:
authorFabien Costantini <fabien@onepost.net>2008-10-17 11:26:30 +0000
committerFabien Costantini <fabien@onepost.net>2008-10-17 11:26:30 +0000
commit69dbe4ea9cf540310a276be574eb98a59102f64e (patch)
treefce047e46faa7fd0c6a992249173b9f6659e617f /documentation/src/subclassing.dox
parent09cfc1a1ea00f7edf394e647f1f32e5b0913f564 (diff)
now renaming restoring dir src_doc src.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6452 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'documentation/src/subclassing.dox')
-rw-r--r--documentation/src/subclassing.dox531
1 files changed, 531 insertions, 0 deletions
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 <I>subclassing</I> an existing FLTK widget,
+typically <tt>Fl_Widget</tt> for controls and <tt>Fl_Group</tt> 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. <tt>Fl_Group</tt> is the
+main composite widget widget class in FLTK, and all of the other composite
+widgets (<tt>Fl_Pack</tt>, <tt>Fl_Scroll</tt>, <tt>Fl_Tabs</tt>,
+<tt>Fl_Tile</tt>, and <tt>Fl_Window</tt>) 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 <tt>Fl_Button</tt> 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 <tt>Fl_Widget</tt> or any
+subclass of <tt>Fl_Widget</tt>. <tt>Fl_Widget</tt> 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
+<A href="fluid.html#FLUID">FLUID</A>
+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
+
+<tt>Fl_Widget</tt>'s protected constructor sets <tt>x()</tt>, <tt>y()</tt>,
+<tt>w()</tt>, <tt>h()</tt>, and <tt>label()</tt> 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 <A href="#clear_visible"><tt>Fl_Widget::clear_visible</tt></A>
+\li <A href="#damage"><tt>Fl_Widget::damage</tt></A>
+\li <A href="#draw_box"><tt>Fl_Widget::draw_box</tt></A>
+\li <A href="#draw_focus"><tt>Fl_Widget::draw_focus</tt></A>
+\li <A href="#draw_label"><tt>Fl_Widget::draw_label</tt></A>
+\li <A href="#set_flag"><tt>Fl_Widget::set_flag</tt></A>
+\li <A href="#set_visible"><tt>Fl_Widget::set_visible</tt></A>
+\li <A href="#test_shortcut"><tt>Fl_Widget::test_shortcut</tt></A>
+\li <A href="#type"><tt>Fl_Widget::type</tt></A>
+
+<A name="damage"></A> <!-- For old HTML links only ! -->
+void Fl_Widget::damage(uchar mask) <br>
+void Fl_Widget::damage(uchar mask, int x, int y, int w, int h) <br>
+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 <tt>damage()</tt>. Your <tt>
+draw()</tt> routine can examine these bits to limit what it is
+drawing. The public method <tt>Fl_Widget::redraw()</tt> simply does
+<tt> Fl_Widget::damage(FL_DAMAGE_ALL)</tt>, but the implementation of
+your widget can call the private <tt>damage(n)</tt>.
+
+\par
+The second form indicates that a region is damaged. If only these
+calls are done in a window (no calls to <tt>damage(n)</tt>) 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 <tt>damage()</tt> unless this is a <tt>Fl_Window</tt> widget.
+
+\par
+The third form returns the bitwise-OR of all <tt>damage(n)</tt>
+calls done since the last <tt>draw()</tt>.
+
+\par
+<I>When redrawing your widgets you should look at the damage bits to
+see what parts of your widget need redrawing.</I> The <tt>handle()</tt>
+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() &amp; FL_DAMAGE_ALL) {
+ ... draw frame/box and other static stuff ...
+ }
+
+ if (damage() &amp; (FL_DAMAGE_ALL | 1)) draw_part1();
+ if (damage() &amp; (FL_DAMAGE_ALL | 2)) draw_part2();
+ if (damage() &amp; (FL_DAMAGE_ALL | 4)) draw_part3();
+}
+\endcode
+
+<A name="draw_box"></A> <!-- For old HTML links only ! -->
+void Fl_Widget::draw_box() const <br>
+void Fl_Widget::draw_box(Fl_Boxtype b, ulong c) const
+
+\par
+The first form draws this widget's <tt>box()</tt>, using the
+dimensions of the widget. The second form uses <tt>b</tt> as the box
+type and <tt>c</tt> as the color for the box.
+
+<A name="draw_focus"></A> <!-- For old HTML links only ! -->
+void Fl_Widget::draw_focus() const <br>
+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.
+
+<A name="draw_label"></A> <!-- For old HTML links only ! -->
+void Fl_Widget::draw_label() const <br>
+void Fl_Widget::draw_label(int x, int y, int w, int h) const <br>
+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 <tt>draw()</tt> 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 &quot;centered&quot; labels are aligned with some
+feature, like a moving slider.
+
+\par
+The third form draws the label anywhere. It acts as though <tt>
+FL_ALIGN_INSIDE</tt> has been forced on so the label will appear inside
+the passed bounding box. This is designed for parent groups to draw
+labels with.
+
+<A name="set_flag"></A> <!-- For old HTML links only ! -->
+void Fl_Widget::set_flag(SHORTCUT_LABEL)
+
+\par
+Modifies <tt>draw_label()</tt> so that '&amp;' characters cause an underscore
+to be printed under the next letter.
+
+<A name="set_visible"></A> <!-- For old HTML links only ! -->
+<A name="clear_visible"></A> <!-- For old HTML links only ! -->
+void Fl_Widget::set_visible() <br>
+void Fl_Widget::clear_visible()
+
+\par
+Fast inline versions of <tt>Fl_Widget::hide()</tt> and <tt>
+Fl_Widget::show()</tt>. These do not send the <tt>FL_HIDE</tt> and <tt>
+FL_SHOW</tt> events to the widget.
+
+<A name="test_shortcut"></A> <!-- For old HTML links only ! -->
+int Fl_Widget::test_shortcut() const <br>
+static int Fl_Widget::test_shortcut(const char *s)
+
+\par
+The first version tests <tt>Fl_Widget::label()</tt> against the
+current event (which should be a <tt>FL_SHORTCUT</tt> event). If the
+label contains a '&amp;' character and the character after it matches the key
+press, this returns true. This returns false if the <tt>SHORTCUT_LABEL</tt>
+flag is off, if the label is <tt>NULL</tt> or does not have a
+'&amp;' 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.
+
+<A name="type"></A> <!-- For old HTML links only ! -->
+uchar Fl_Widget::type() const <br>
+void Fl_Widget::type(uchar t)
+
+\par
+The property <tt>Fl_Widget::type()</tt> can return an arbitrary 8-bit
+identifier, and can be set with the protected method <tt>type(uchar t)</tt>.
+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 <tt>type()</tt> use a unique value. These unique values must
+be greater than the symbol <tt>FL_RESERVED_TYPE</tt> (which is 100).
+Look through the header files for <tt>FL_RESERVED_TYPE</tt> to find an
+unused number. If you make a subclass of <tt>Fl_Window</tt>
+you must use <tt>FL_WINDOW + n</tt> (<tt>n</tt> must be in the
+range 1 to 7).
+
+<A NAME="handle"></A> <!-- For old HTML links only ! -->
+\section subclassing_events Handling Events
+
+The virtual method <tt>int Fl_Widget::handle(int event)</tt> is called
+to handle each event passed to the widget. It can:
+
+\li Change the state of the widget.
+\li Call
+ <A href="Fl_Widget.html#Fl_Widget.redraw"><tt>Fl_Widget::redraw()</tt></A>
+ if the widget needs to be redisplayed.
+\li Call
+ <A href="Fl_Widget.html#Fl_Widget.damage"><tt>Fl_Widget::damage(n)</tt></A>
+ if the widget needs a partial-update (assuming you provide support for
+ this in your
+ <A href="#draw"><tt>Fl_Widget::draw()</tt></A>
+ method).
+\li Call
+ <A href="Fl_Widget.html#Fl_Widget.do_callback"><tt>Fl_Widget::do_callback()</tt></A>
+ if a callback should be generated.
+\li Call <tt>Fl_Widget::handle()</tt> 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
+<A href="events.html#events"><tt>Fl::event_*()</tt></A>
+functions. This information remains valid until another event is
+handled.
+
+Here is a sample <tt>handle()</tt> 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 <tt>handle()</tt> method
+uses the event. If you return zero, the parent widget will try
+sending the event to another widget.
+
+<A NAME="draw"></A> <!-- For old HTML links only ! -->
+\section subclassing_drawing Drawing the Widget
+
+The <tt>draw()</tt> virtual method is called when FLTK wants
+you to redraw your widget. It will be called if and only if
+<tt>damage()</tt> is non-zero, and <tt>damage()</tt> will be
+cleared to zero after it returns. The <tt>draw()</tt> method
+should be declared protected so that it can't be called from
+non-drawing code.
+
+The <tt>damage()</tt> value contains the bitwise-OR of all
+the <tt>damage(n)</tt> 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
+<tt>FL_DAMAGE_ALL</tt> bit if it thinks the entire widget must
+be redrawn, e.g. for an expose event.
+
+Expose events (and the above <tt>damage(b,x,y,w,h)</tt>) will cause <tt>
+draw()</tt> to be called with FLTK's <A href="drawing.html#clipping">
+clipping</A> turned on. You can greatly speed up redrawing in some
+cases by testing <tt>fl_not_clipped(x,y,w,h)</tt> or <tt>fl_clip_box(...)</tt>
+and skipping invisible parts.
+
+Besides the protected methods described above, FLTK provides a large
+number of basic drawing functions, which are described
+<A href="drawing.html#drawing">below</A>.
+
+\section subclassing_resizing Resizing the Widget
+
+The <tt>resize(int x, int y, int w, int h)</tt> method is called when
+the widget is being resized or moved. The arguments are the new
+position, width, and height. <tt>x()</tt>, <tt>y()</tt>, <tt>w()</tt>,
+and <tt>h()</tt> still remain the old size. You must call <tt>resize()</tt>
+on your base class with the same arguments to get the widget size to
+actually change.
+
+This should <I>not</I> call <tt>redraw()</tt>, at least if only the <tt>
+x()</tt> and <tt>y()</tt> change. This is because composite widgets like
+<A href="Fl_Scroll.html#Fl_Scroll"><tt>Fl_Scroll</tt></A>
+may have a more efficient way of drawing the new position.
+
+\section subclassing_composite Making a Composite Widget
+
+A &quot;composite&quot; widget contains one or more &quot;child&quot; widgets.
+To make a composite widget you should subclass
+<A href="Fl_Group.html#Fl_Group"><tt>Fl_Group</tt></A>.
+It is possible to make a composite object that is not a subclass of
+<tt>Fl_Group</tt>, but you'll have to duplicate the code in <tt>Fl_Group</tt>
+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
+<tt>add()</tt>ed to the group, since the Fl_Group constructor does
+Fl_Group::begin().
+<I>Don't forget to call Fl_Group::end() or use the Fl_End pseudo-class:</I>
+
+\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 <tt>parent()</tt>
+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-&gt;parent())-&gt;slider_cb();
+}
+void MyClass::slider_cb() { // normal method
+ use(the_slider-&gt;value());
+}
+\endcode
+
+If you make the <tt>handle()</tt> method, you can quickly pass all the
+events to the children using the <tt>Fl_Group::handle()</tt> method.
+You don't need to override <tt>handle()</tt> 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 <tt>draw()</tt> you need to draw all the
+children. If <tt>redraw()</tt> or <tt>damage()</tt> is called
+on a child, <tt>damage(FL_DAMAGE_CHILD)</tt> is done to the
+group, so this bit of <tt>damage()</tt> 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
+
+<tt>Fl_Group</tt> provides some protected methods to make drawing
+easier:
+
+\li <A href="#draw_child">draw_child</A>
+\li <A href="#draw_outside_label">draw_outside_label</A>
+\li <A href="#update_child">update_child</A>
+
+<A name="draw_child"></A> <!-- For old HTML links only ! -->
+void Fl_Group::draw_child(Fl_Widget&)
+
+\par
+This will force the child's <tt>damage()</tt> bits all to one and call <tt>
+draw()</tt> on it, then clear the <tt>damage()</tt>. 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 <tt>visible()</tt> or if it is
+clipped.
+
+<A name="draw_outside_label"></A> <!-- For old HTML links only ! -->
+void Fl_Group::draw_outside_label(Fl_Widget&) const
+
+\par
+Draw the labels that are <I>not</I> drawn by <A href="#draw_label"><tt>
+draw_label()</tt></A>. If you want more control over the label
+positions you might want to call <tt>child-&gt;draw_label(x,y,w,h,a)</tt>.
+
+<A name="update_child"></A> <!-- For old HTML links only ! -->
+void Fl_Group::update_child(Fl_Widget&)
+
+\par
+Draws the child only if its <tt>damage()</tt> 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 <tt>visible()</tt>
+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 <A href="Fl.html#Fl.paste"><tt>Fl::paste</tt></A>
+\li <A href="Fl.html#Fl.selection"><tt>Fl::selection</tt></A>
+\li <A href="Fl.html#Fl.selection_owner"><tt>Fl::selection_owner</tt></A>
+
+It may be possible to cut/paste non-text data by using
+<A href="osissues.html#add_handler"><tt>Fl::add_handler()</tt></A>.
+
+\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
+<A href="Fl.html#Fl.dnd"><tt>Fl::dnd()</tt></A>.
+
+Drop attempts are handled via <A href="events.html#dnd">events</A>:
+
+\li <tt>FL_DND_ENTER</tt>
+\li <tt>FL_DND_DRAG</tt>
+\li <tt>FL_DND_LEAVE</tt>
+\li <tt>FL_DND_RELEASE</tt>
+\li <tt>FL_PASTE</tt>
+
+\section subclassing_fl_window Making a subclass of Fl_Window
+
+You may want your widget to be a subclass of
+<tt>Fl_Window</tt>, <tt>Fl_Double_Window</tt>, or
+<tt>FL_Gl_Window</tt>. 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 <tt>Fl_Window</tt>is almost exactly like
+subclassing <tt>Fl_Group</tt>, and in fact you can easily
+switch a subclass back and forth. Watch out for the following
+differences:
+
+-# <tt>Fl_Window</tt> is a subclass of <tt>Fl_Group</tt> so
+ <I>make sure your constructor calls <tt>end()</tt></I>
+ unless you actually want children added to your window.
+
+-# When handling events and drawing, the upper-left corner is at
+ 0,0, not <tt>x(),y()</tt> as in other <tt>Fl_Widget</tt>'s.
+ For instance, to draw a box around the widget, call
+ <tt>draw_box(0, 0, w(), h())</tt>, rather than
+ <tt>draw_box(x(), y(), w(), h())</tt>.
+
+You may also want to subclass <tt>Fl_Window</tt> in order to
+get access to different visuals or to change other attributes of
+the windows. See
+<A href="osissues.html">"Appendix F - Operating System Issues"</A>
+for more information.
+
+\htmlonly
+<hr>
+<a class="el" href="index.html">[Index]</a> &nbsp;&nbsp;
+<a class="el" href="events.html">[Previous]&nbsp; 6 - Handling Events</a>&nbsp;
+<a class="el" href="opengl.html">[Next]&nbsp; 8 - Using OpenGL</a>&nbsp;
+\endhtmlonly
+*/