themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_Widget.cxx
bloba8be544043f52a70c4eeffba16d79dee62838de7
1 //
2 // "$Id: Fl_Widget.cxx 7940 2010-12-02 17:58:58Z greg.ercolano $"
3 //
4 // Base widget class for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
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
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 #include <FL/Fl.H>
29 #include <FL/Fl_Widget.H>
30 #include <FL/Fl_Group.H>
31 #include <FL/Fl_Tooltip.H>
32 #include <FL/fl_draw.H>
33 #include <stdlib.h>
34 #include "flstring.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*/) {
49 #if 0
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) {
54 p->do_callback(o,v);
55 return;
57 #endif
58 obj_queue[obj_head++] = o;
59 if (obj_head >= QUEUE_SIZE) obj_head = 0;
60 if (obj_head == obj_tail) {
61 obj_tail++;
62 if (obj_tail >= QUEUE_SIZE) obj_tail = 0;
65 /**
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;
74 return o;
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
93 for (;;) {
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;
99 } // valid entry
100 if (entry == old_head) break;
102 return;
104 ////////////////////////////////////////////////////////////////
106 int Fl_Widget::handle(int) {
107 return 0;
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;
117 label_.value = L;
118 label_.image = 0;
119 label_.deimage = 0;
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;
125 tooltip_ = 0;
126 callback_ = default_callback;
127 user_data_ = 0;
128 type_ = 0;
129 flags_ = VISIBLE_FOCUS;
130 damage_ = 0;
131 box_ = FL_NO_BOX;
132 color_ = FL_GRAY;
133 color2_ = FL_GRAY;
134 when_ = FL_WHEN_RELEASE;
136 parent_ = 0;
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;
147 resize(X, Y, W, H);
148 redraw();
149 return 1;
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
157 Fl::focus(this);
158 return 1;
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);
174 #ifdef DEBUG_DELETE
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 */
186 void
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,
193 X + Fl::box_dx(B),
194 Y + Fl::box_dy(B),
195 W - Fl::box_dw(B) - 1,
196 H - Fl::box_dh(B) - 1, fl_color() );
200 void Fl_Widget::activate() {
201 if (!active()) {
202 clear_flag(INACTIVE);
203 if (active_r()) {
204 redraw();
205 redraw_label();
206 handle(FL_ACTIVATE);
207 if (inside(Fl::focus())) Fl::focus()->take_focus();
212 void Fl_Widget::deactivate() {
213 if (active_r()) {
214 set_flag(INACTIVE);
215 redraw();
216 redraw_label();
217 handle(FL_DEACTIVATE);
218 fl_throw_focus(this);
219 } else {
220 set_flag(INACTIVE);
224 int Fl_Widget::active_r() const {
225 for (const Fl_Widget* o = this; o; o = o->parent())
226 if (!o->active()) return 0;
227 return 1;
230 void Fl_Widget::show() {
231 if (!visible()) {
232 clear_flag(INVISIBLE);
233 if (visible_r()) {
234 damage( FL_DAMAGE_EXPOSE );
235 // redraw_label();
236 handle(FL_SHOW);
237 if (inside(Fl::focus())) Fl::focus()->take_focus();
242 void Fl_Widget::hide() {
243 if (visible_r()) {
244 set_flag(INVISIBLE);
245 for (Fl_Widget *p = parent(); p; p = p->parent())
246 if (p->box() || !p->parent()) {p->redraw(); break;}
247 handle(FL_HIDE);
248 fl_throw_focus(this);
249 } else {
250 set_flag(INVISIBLE);
254 int Fl_Widget::visible_r() const {
255 for (const Fl_Widget* o = this; o; o = o->parent())
256 if (!o->visible()) return 0;
257 return 1;
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;
264 return 0;
268 void
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)
273 return;
274 free((void *)(label_.value));
275 clear_flag(COPIED_LABEL);
277 if ( ( !a || !label_.value ) || strcmp( a, label_.value ) )
278 redraw_label();
279 label_.value=a;
283 void
284 Fl_Widget::copy_label(const char *a) {
285 if ( ( !a || !label_.value ) || strcmp( a, label_.value ) )
286 redraw_label();
288 if (flags() & COPIED_LABEL) free((void *)(label_.value));
290 if (a) {
291 set_flag(COPIED_LABEL);
292 label_.value=strdup(a);
293 } else {
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
306 \see callback()
308 void
309 Fl_Widget::do_callback(Fl_Widget* o,void* arg) {
310 Fl_Widget_Tracker wp(this);
311 callback_(o,arg);
312 if (wp.deleted()) return;
313 if (callback_ != default_callback)
314 clear_changed();
318 // End of "$Id: Fl_Widget.cxx 7940 2010-12-02 17:58:58Z greg.ercolano $".