2 // "$Id: Fl_Widget.cxx 7940 2010-12-02 17:58:58Z greg.ercolano $"
4 // Base widget class for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 #include <FL/Fl_Widget.H>
30 #include <FL/Fl_Group.H>
31 #include <FL/Fl_Tooltip.H>
32 #include <FL/fl_draw.H>
37 ////////////////////////////////////////////////////////////////
38 // for compatibility with Forms, all widgets without callbacks are
39 // inserted into a "queue" when they are activated, and the forms
40 // compatibility interaction functions (fl_do_events, etc.) will
41 // read one widget at a time from this queue and return it:
43 const int QUEUE_SIZE
= 20;
45 static Fl_Widget
*obj_queue
[QUEUE_SIZE
];
46 static int obj_head
, obj_tail
;
48 void Fl_Widget::default_callback(Fl_Widget
*o
, void * /*v*/) {
50 // This is necessary for strict forms compatibility but is confusing.
51 // Use the parent's callback if this widget does not have one.
52 for (Fl_Widget
*p
= o
->parent(); p
; p
= p
->parent())
53 if (p
->callback() != default_callback
) {
58 obj_queue
[obj_head
++] = o
;
59 if (obj_head
>= QUEUE_SIZE
) obj_head
= 0;
60 if (obj_head
== obj_tail
) {
62 if (obj_tail
>= QUEUE_SIZE
) obj_tail
= 0;
66 All Fl_Widgets that don't have a callback defined use a
67 default callback that puts a pointer to the widget in this queue,
68 and this method reads the oldest widget out of this queue.
70 Fl_Widget
*Fl::readqueue() {
71 if (obj_tail
==obj_head
) return 0;
72 Fl_Widget
*o
= obj_queue
[obj_tail
++];
73 if (obj_tail
>= QUEUE_SIZE
) obj_tail
= 0;
77 This static internal function removes all pending callbacks for a
78 specific widget from the default callback queue (Fl::readqueue()).
79 It is only called from Fl_Widget's destructor if the widget
80 doesn't have an own callback.
81 Note: There's no need to have this in the Fl:: namespace.
83 static void cleanup_readqueue(Fl_Widget
*w
) {
85 if (obj_tail
==obj_head
) return;
87 // Read the entire queue and copy over all valid entries.
88 // The new head will be determined after the last copied entry.
90 int old_head
= obj_head
; // save newest entry
91 int entry
= obj_tail
; // oldest entry
92 obj_head
= obj_tail
; // new queue start
94 Fl_Widget
*o
= obj_queue
[entry
++];
95 if (entry
>= QUEUE_SIZE
) entry
= 0;
96 if (o
!= w
) { // valid entry
97 obj_queue
[obj_head
++] = o
;
98 if (obj_head
>= QUEUE_SIZE
) obj_head
= 0;
100 if (entry
== old_head
) break;
104 ////////////////////////////////////////////////////////////////
106 int Fl_Widget::handle(int) {
110 /** Default font size for widgets */
111 Fl_Fontsize FL_NORMAL_SIZE
= 14;
113 Fl_Widget::Fl_Widget(int X
, int Y
, int W
, int H
, const char* L
) {
115 x_
= X
; y_
= Y
; w_
= W
; h_
= H
;
120 label_
.type
= FL_NORMAL_LABEL
;
121 label_
.font
= FL_HELVETICA
;
122 label_
.size
= FL_NORMAL_SIZE
;
123 label_
.color
= FL_FOREGROUND_COLOR
;
124 label_
.align_
= FL_ALIGN_CENTER
;
126 callback_
= default_callback
;
129 flags_
= VISIBLE_FOCUS
;
134 when_
= FL_WHEN_RELEASE
;
137 if (Fl_Group::current()) Fl_Group::current()->add(this);
140 void Fl_Widget::resize(int X
, int Y
, int W
, int H
) {
141 x_
= X
; y_
= Y
; w_
= W
; h_
= H
;
144 // this is useful for parent widgets to call to resize children:
145 int Fl_Widget::damage_resize(int X
, int Y
, int W
, int H
) {
146 if (x() == X
&& y() == Y
&& w() == W
&& h() == H
) return 0;
152 int Fl_Widget::take_focus() {
153 if (!takesevents()) return 0;
154 if (!visible_focus()) return 0;
155 if (!handle(FL_FOCUS
)) return 0; // see if it wants it
156 if (contains(Fl::focus())) return 1; // it called Fl::focus for us
161 extern void fl_throw_focus(Fl_Widget
*); // in Fl_x.cxx
164 Destroys the widget, taking care of throwing focus before if any.
165 Destruction removes the widget from any parent group! And groups when
166 destroyed destroy all their children. This is convenient and fast.
168 Fl_Widget::~Fl_Widget() {
169 Fl::clear_widget_pointer(this);
170 if (flags() & COPIED_LABEL
) free((void *)(label_
.value
));
171 if (flags() & COPIED_TOOLTIP
) free((void *)(tooltip_
));
172 // remove from parent group
173 if (parent_
) parent_
->remove(this);
175 if (parent_
) { // this should never happen
176 printf("*** Fl_Widget: parent_->remove(this) failed [%p,%p]\n",parent_
,this);
178 #endif // DEBUG_DELETE
179 parent_
= 0; // Don't throw focus to a parent widget.
180 fl_throw_focus(this);
181 // remove stale entries from default callback queue (Fl::readqueue())
182 if (callback_
== default_callback
) cleanup_readqueue(this);
185 /** Draws a focus box for the widget at the given position and size */
187 Fl_Widget::draw_focus(Fl_Boxtype B
, int X
, int Y
, int W
, int H
) const {
188 if (!Fl::visible_focus()) return;
190 fl_color(fl_contrast(FL_BLACK
, color()));
192 fl_draw_box( FL_FOCUS_FRAME
,
195 W
- Fl::box_dw(B
) - 1,
196 H
- Fl::box_dh(B
) - 1, fl_color() );
200 void Fl_Widget::activate() {
202 clear_flag(INACTIVE
);
207 if (inside(Fl::focus())) Fl::focus()->take_focus();
212 void Fl_Widget::deactivate() {
217 handle(FL_DEACTIVATE
);
218 fl_throw_focus(this);
224 int Fl_Widget::active_r() const {
225 for (const Fl_Widget
* o
= this; o
; o
= o
->parent())
226 if (!o
->active()) return 0;
230 void Fl_Widget::show() {
232 clear_flag(INVISIBLE
);
234 damage( FL_DAMAGE_EXPOSE
);
237 if (inside(Fl::focus())) Fl::focus()->take_focus();
242 void Fl_Widget::hide() {
245 for (Fl_Widget
*p
= parent(); p
; p
= p
->parent())
246 if (p
->box() || !p
->parent()) {p
->redraw(); break;}
248 fl_throw_focus(this);
254 int Fl_Widget::visible_r() const {
255 for (const Fl_Widget
* o
= this; o
; o
= o
->parent())
256 if (!o
->visible()) return 0;
260 // return true if widget is inside (or equal to) this:
261 // Returns false for null widgets.
262 int Fl_Widget::contains(const Fl_Widget
*o
) const {
263 for (; o
; o
= o
->parent_
) if (o
== this) return 1;
269 Fl_Widget::label(const char *a
) {
270 if (flags() & COPIED_LABEL
) {
271 // reassigning a copied label remains the same copied label
272 if (label_
.value
== a
)
274 free((void *)(label_
.value
));
275 clear_flag(COPIED_LABEL
);
277 if ( ( !a
|| !label_
.value
) || strcmp( a
, label_
.value
) )
284 Fl_Widget::copy_label(const char *a
) {
285 if ( ( !a
|| !label_
.value
) || strcmp( a
, label_
.value
) )
288 if (flags() & COPIED_LABEL
) free((void *)(label_
.value
));
291 set_flag(COPIED_LABEL
);
292 label_
.value
=strdup(a
);
294 clear_flag(COPIED_LABEL
);
295 label_
.value
=(char *)0;
300 /** Calls the widget callback.
302 Causes a widget to invoke its callback function with arbitrary arguments.
304 \param[in] o call the callback with \p o as the widget argument
305 \param[in] arg use \p arg as the user data argument
309 Fl_Widget::do_callback(Fl_Widget
* o
,void* arg
) {
310 Fl_Widget_Tracker
wp(this);
312 if (wp
.deleted()) return;
313 if (callback_
!= default_callback
)
318 // End of "$Id: Fl_Widget.cxx 7940 2010-12-02 17:58:58Z greg.ercolano $".