summaryrefslogtreecommitdiff
path: root/documentation/subclassing.html
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>1998-12-29 14:21:17 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>1998-12-29 14:21:17 +0000
commit87dd7f0d23eba5c09e71ec6efeb34c6844f5e95f (patch)
treeecd25b3fbecdd2d1c6abf106d0c94ac2b1e9926e /documentation/subclassing.html
parent20adb6834b22523e9d1fecdb7bb8a117f7b6179a (diff)
Revised documentation files.
git-svn-id: file:///fltk/svn/fltk/trunk@177 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'documentation/subclassing.html')
-rw-r--r--documentation/subclassing.html519
1 files changed, 519 insertions, 0 deletions
diff --git a/documentation/subclassing.html b/documentation/subclassing.html
new file mode 100644
index 000000000..414cca67b
--- /dev/null
+++ b/documentation/subclassing.html
@@ -0,0 +1,519 @@
+<HTML>
+<BODY>
+
+<H1 ALIGN=RIGHT><A NAME="subclassing">5 - Adding and Extending Widgets</A></H1>
+
+This chapter describes how to add your own widgets or extend existing widgets in FLTK.
+
+<H2>Subclassing</H2>
+
+<H2>Adding Syntax Highlighting to the Fl_Input Widget</H2>
+
+<H2>Drawing Functions</H2>
+
+<H3>Lines, Rectangles, and Curves, Oh, My!</H3>
+
+<H3>Colors</H3>
+
+<H3>Fonts</H3>
+
+<H3>Images</H3>
+
+<H2><A NAME="Fl_Table">Writing a Table Widget</A></H2>
+
+<H3>Methods</H3>
+
+<H3>Cut and Paste Support</H3>
+
+</BODY>
+</HTML>
+<title>Cut & paste</title>
+<h2>Cut & paste</h2>
+
+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 under X by using <a
+href=events.html#add_handler>Fl::add_handler()</a>.
+
+</ul><h4><code>void Fl::paste(Fl_Widget *receiver)</code></h4><ul>
+
+<P>Set things up so the receiver widget will be called with an <a
+href=events.html#paste>FL_PASTE</a> event some time in the future.
+The reciever should be prepared to be called <i>directly</i> by this,
+or for it to happen <i>later</i>, or possibly <i>not at all</i>. This
+allows the window system to take as long as necessary to retrieve the
+paste buffer (or even to screw up completely) without complex and
+error-prone synchronization code in fltk.
+
+</ul><h4><code>void Fl::selection(Fl_Widget *owner, const char *stuff, int len);
+</code></h4><ul>
+
+<p>Change the current selection. The block of text is copied to an
+internal buffer by Fltk (be careful if doing this in response to an
+FL_PASTE as this <i>may</i> be the same buffer returned by
+event_text()). The selection_owner is set to the passed owner
+(possibly sending FL_SELECTIONCLEAR to the previous owner).
+
+</ul><h4><code>const char* Fl::selection();
+<br>int Fl::selection_length();</code></h4><ul>
+
+You can look at the buffer containing the current selection. Contents
+of this buffer are undefined if this program does not own the X
+selection.
+
+</ul><h4><code>Fl_Widget *Fl::selection_owner() const;
+<br>void Fl::selection_owner(Fl_Widget *);</code></h4><ul>
+
+<p>The single-argument selection_owner(x) call can be used to move the
+selection to another widget or to set the owner to NULL, without
+changing the actual text of the selection. FL_SELECTIONCLEAR is sent
+to the old selection owner, if any.
+
+</ul>
+
+<p><i>Copying the buffer every time the selection is changed is
+obviously wasteful, especially for large selections. I expect an
+interface will be added in a future version to allow the selection to
+be made by a callback function. The current interface will be
+emulated on top of this.</i>
+
+<title>Making a subclass of Fl_Widget</title>
+</ul><h2>Making a subclass of Fl_Widget</h2>
+
+<p>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.
+
+<p>Parts of this document:
+
+<ul>
+
+<li><a href=#constructor>Constructing your Fl_Widget</a>
+
+<li><a href=#protected>Protected methods of Fl_Widget</a>
+
+<li>Virtual functions to override:
+
+<ul>
+
+<li><code><a href=#handle>int Fl_Widget::handle(int
+event);</a></code>
+
+<li><code><a href=#draw>void Fl_Widget::draw();</a></code>
+
+<li><code><a href=#resize>void
+Fl_Widget::resize(int,int,int,int);</a></code>
+
+<li><code><a href=#destructor>Fl_Widget::~Fl_Widget();</a></code>
+
+</ul>
+
+<li><a href=#composite>Making a Composite/Group Widget</a>
+
+<li><a href=#window>Making a subclass of Fl_Window</a>
+
+</ul>
+
+<a name=constructor>
+<h2>Constructing your Fl_Widget</h2>
+
+I recommend your constructor be of this form:
+
+<p><pre>
+ Class(int x, int y, int w, int h, const char* label = 0);
+</pre>
+
+<p>This will allow the class name to be typed into <a
+href=fluid.html>fluid</a> and it will produce the correct call.
+
+<p>The constructor must call the constructor for the base class and
+pass the same arguments. Fl_Widget's protected constructor sets x(),
+y(), w(), h(), and label() to the passed values and initializes the
+other instance variables to:
+
+<p><pre>
+ type(0);
+ box(FL_NO_BOX);
+ color(FL_GRAY);
+ selection_color(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);
+</pre>
+
+<a name=protected>
+<h2>Protected methods of Fl_Widget</h2>
+
+<p>These methods are provided for subclasses to use.
+
+</ul><h4><code>uchar Fl_Widget::type() const;
+<br>void Fl_Widget::type(uchar);
+</code></h4><ul>
+
+The property Fl_Widget::type() can return an arbitrary 8-bit
+identifier, and can be set with the protected method type(uchar).
+This value had to be provided for Forms compatability, but you can use
+it for any purpose you want. Try to keep the value less than 100 to
+not interfere with reserved values.
+
+<p>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.
+
+<p>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). Grep 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-7).
+
+<a name=test_shortcut>
+</ul><h4><code>void Fl_Widget::set_flag(SHORTCUT_LABEL);</code></h4><ul>
+
+If your constructor calls this it modifies draw_label() so that '&'
+characters cause an underscore to be printed under the next letter.
+
+</ul><h4><code>int Fl_Widget::test_shortcut() const;<br>
+static int Fl_Widget::test_shortcut(const char *);</code></h4><ul>
+
+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.
+
+<p>The second version lets you do this test to an arbitrary string.
+
+</ul><h4><code>void Fl_Widget::x(short);
+<br>void Fl_Widget::y(short);
+<br>void Fl_Widget::w(short);
+<br>void Fl_Widget::h(short);</code></h4><ul>
+
+You can directly clobber the values for <a
+href=Fl_Widget.html#xywh>x(), y(), w(), and h()</a>. Make sure you
+know what you are doing. This is most useful for temporarily
+replacing the values before calling handle() or draw() on the base
+class to "fool" it into working in a different area.
+
+<a name=damage>
+</ul><h4><code>void Fl_Widget::damage(uchar mask);</code></h4><ul>
+
+Indicate 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(-1).
+
+</ul><h4><code>void Fl_Widget::damage(uchar mask,int x,int y,int w,int
+h);</code></h4><ul>
+
+Indicate 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, in which case they are forced to the value 6 for
+internal reasons).
+
+</ul><h4><code>void Fl_Widget::clear_damage(uchar value = 0);</code></h4><ul>
+
+Directly set damage() to the passed value. This is provided for
+kludges only.
+
+</ul><h4><code>uchar Fl_Widget::damage()</code></h4><ul>
+
+Return the bitwise-or of all damage(n) calls done since the last
+draw(). The public method redraw() does damage(-1), but the
+implementation of your widget can call the private damage(n).
+
+</ul><h4><code>void Fl_Widget::set_visible();
+<br>void Fl_Widget::clear_visible();</code></h4><ul>
+
+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.
+
+</ul><h4><code>void Fl_Widget::draw_box() const ;</code></h4><ul>
+
+Draw this widget's box(), using the dimensions of the widget.
+
+</ul><h4><code>void Fl_Widget::draw_box(Fl_Boxtype b,ulong c) const
+;</code></h4><ul>
+
+Pretend the box()==b and the color()==c and draw this widget's box.
+
+<a name=draw_label>
+</ul><h4><code>void Fl_Widget::draw_label() const ;</code></h4><ul>
+
+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).
+
+</ul><h4><code>void Fl_Widget::draw_label(int x,int y,int w,int h) const
+;</code></h4><ul>
+
+Do the same thing except use the passed bounding box. This is useful
+so "centered" labels are aligned with some feature, such as a moving
+slider.
+
+</ul><h4><code>void Fl_Widget::draw_label(int x,int y,int w,int
+h,Fl_Align align) const ;</code></h4><ul>
+
+Draw 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.
+
+</ul>
+<a name=handle>
+<h2>virtual int Fl_Widget::handle()</h2>
+
+The virtual method <b><code>int Fl_Widget::handle(int
+event)</code></b> is called to handle each event passed to the widget.
+It can:<ul>
+
+<li>Change the state of the widget.
+
+<li>Call <a href=Fl_Widget.html>Fl_Widget::redraw()</a> if the widget
+needs to be redisplayed.
+
+<li>Call <a href=#damage>Fl_Widget::damage(n)</a> if the widget needs
+a partial-update (assumming you provide support for this in your
+Fl_Widget::draw() method).
+
+<li>Call <a href=Fl_Widget.html>Fl_Widget::do_callback()</a> if a
+callback should be generated.
+
+<li>Call Fl_Widget::handle() on child widgets.
+
+</ul>
+
+<p>Events are identified the small integer argument. Other
+information about the most recent event is stored in static locations
+and aquired by calling <a href=events.html><code>Fl::event_*()</code></a>.
+This other information remains valid until another event is read from
+the X server.
+
+<p>Here is a sample Fl_Widget::handle(), for a widget that acts as a
+pushbutton and also accepts the keystroke 'x' to cause the callback:
+
+<ul><pre>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 widget!
+ }
+ return 1;
+ case FL_SHORTCUT:
+ if (Fl::event_key() == 'x') {do_callback(); return 1;}
+ return 0;
+ default:
+ return 0;
+ }
+ }
+}
+</pre></ul>
+
+<p>You must return non-zero if your handle() method used the event.
+If you return zero it indicates to the parent that it can try sending
+another widget the event.
+
+<p>It looks like it is best to make the handle() method public.
+
+<a name=draw>
+<h2>virtual void Fl_Widget::draw()</h2>
+
+<p>The virtual method Fl_Widget::draw() 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 subclasses may call it
+but it can't be called from non-drawing code.
+
+<p>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
+<i>all</i> the bits on if it thinks the entire widget must be redrawn
+(for instance due to an expose event). It is easiest to program to
+handle this by pretending a bit (usually damage()&128) draw the
+non-minimal-update parts of your widget (such as the box()).
+
+<p>Expose events (and the above damage(b,x,y,w,h)) will cause draw()
+to be called with fltk's <a href=Draw.html#clipping>clipping</a>
+turned on. You can greatly speed up redrawing in some cases by
+testing <code>fl_clipped</code> and <code>fl_current_clip</code>
+and skipping invisible parts.
+
+<p>The functions you can use to draw are described in <a
+href=Draw.html>&lt;FL/fl_draw.H></a> or any of the protected
+Fl_Widget::draw_* methods described above.
+
+<a name=resize>
+<h2>virtual void Fl_Widget::resize(int,int,int,int);</h2>
+
+This 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 return the old size. You must call resize() on your
+base class with the same arguments to get the widget size to actually
+change.
+
+<p>This should <i>not</i> call redraw(), at least if only the x() and
+y() change. This is because group objects like <a
+href=Fl_Scroll.html>Fl_Scroll</a> may have a more efficient way of
+drawing the new position.
+
+<p>It may be useful to refer to the size the widget was constructed
+at, these are stored in Fl_Widget::ix(), iy(), iw(), and ih().
+
+<p>Resize should be declared public.
+
+<a name=destructor>
+<h2>virtual Fl_Widget::~Fl_Widget();</h2>
+
+We all know why the destructor must be virtual don't we? Don't forget
+to make it public.
+
+<a name=composite>
+<h2>Making a Composite/Group Widget</h2>
+
+A "composite" widget contains one or more "child" widgets. To do this
+you should subclass <a href=Fl_Group.html>Fl_Group</a> (it is
+possible to make a composite object that is not a subclass of
+Fl_Group, but this is very difficult).
+
+<p>Instances of the child widgets may be included in the parent:
+
+<ul><pre>class MyClass : public Fl_Group {
+ Fl_Button the_button;
+ Fl_Slider the_slider;
+ ...
+};
+</pre></ul>
+
+<p>The constructor has to initialize these instances. They are
+automatically add()ed to the group, since the Fl_Group constructor
+does begin(). <i>Don't forget to call end():</i>
+
+<ul><pre>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!
+}
+</pre></ul>
+
+<p>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:
+
+<ul><pre>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());
+}
+</pre></ul>
+
+<p>If you make the handle() method, you can quickly pass all the
+events to the children (notice that you don't need to override
+handle() if your composite widget does nothing other than pass events
+to the children):
+
+<ul><pre>int MyClass::handle(int event) {
+ if (Fl_Group::handle(event)) return 1;
+ ... handle events that children don't want ...
+}
+</pre></ul>
+
+<p>If you override draw() you need to draw all the children. If
+redraw() or damage() is called on a child, damage(1) is done to the
+group. Thus the 1 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:
+
+<ul><pre>int MyClass::draw() {
+ Fl_Widget*const* a = array();
+ if (damage()==1) { // 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
+ }
+ }
+}
+</pre></ul>
+
+<p>Fl_Group provides some protected methods to make drawing easier:
+
+</ul><h4><code>void Fl_Group::draw_outside_label(Fl_Widget&) const;</code></h4><ul>
+
+Draw the labels that are <i>not</i> drawn by <a
+href=#draw_label>draw_label()</a>. If you want more control over the
+label positions you might want to call child->draw_label(x,y,w,h,a).
+
+</ul><h4><code>void Fl_Group::draw_child(Fl_Widget&);</code></h4><ul>
+
+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.
+
+</ul><h4><code>void Fl_Group::update_child(Fl_Widget&);</code></h4><ul>
+
+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 1. Nothing is
+done if the child is not visible() or if it is clipped.
+
+</ul>
+
+<a name=window>
+<h2>Making a subclass of Fl_Window</h2>
+
+<p>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.
+
+<p>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:
+
+<ol>
+
+<li>Fl_Window is a subclass of Fl_Group so <i>make sure your constructor
+calls end()</i> (unless you actually want children added to your
+window).
+
+<li>When handling events and drawing, the lower-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()).
+
+
+</ol>
+
+<p>You may also want to subclass Fl_Window in order to get access to
+different X visuals or to change other X attributes of the windows,
+<a href=x.html#window>See here for details</a>.
+
+<p><a href = index.html>(back to contents)</a>