|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_Widget.cxx 7940 2010-12-02 17:58:58Z greg.ercolano $" 00003 // 00004 // Base widget class for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <FL/Fl.H> 00029 #include <FL/Fl_Widget.H> 00030 #include <FL/Fl_Group.H> 00031 #include <FL/Fl_Tooltip.H> 00032 #include <FL/fl_draw.H> 00033 #include <stdlib.h> 00034 #include "flstring.h" 00035 00036 00038 // for compatibility with Forms, all widgets without callbacks are 00039 // inserted into a "queue" when they are activated, and the forms 00040 // compatibility interaction functions (fl_do_events, etc.) will 00041 // read one widget at a time from this queue and return it: 00042 00043 const int QUEUE_SIZE = 20; 00044 00045 static Fl_Widget *obj_queue[QUEUE_SIZE]; 00046 static int obj_head, obj_tail; 00047 00048 void Fl_Widget::default_callback(Fl_Widget *o, void * /*v*/) { 00049 #if 0 00050 // This is necessary for strict forms compatibility but is confusing. 00051 // Use the parent's callback if this widget does not have one. 00052 for (Fl_Widget *p = o->parent(); p; p = p->parent()) 00053 if (p->callback() != default_callback) { 00054 p->do_callback(o,v); 00055 return; 00056 } 00057 #endif 00058 obj_queue[obj_head++] = o; 00059 if (obj_head >= QUEUE_SIZE) obj_head = 0; 00060 if (obj_head == obj_tail) { 00061 obj_tail++; 00062 if (obj_tail >= QUEUE_SIZE) obj_tail = 0; 00063 } 00064 } 00070 Fl_Widget *Fl::readqueue() { 00071 if (obj_tail==obj_head) return 0; 00072 Fl_Widget *o = obj_queue[obj_tail++]; 00073 if (obj_tail >= QUEUE_SIZE) obj_tail = 0; 00074 return o; 00075 } 00076 /* 00077 This static internal function removes all pending callbacks for a 00078 specific widget from the default callback queue (Fl::readqueue()). 00079 It is only called from Fl_Widget's destructor if the widget 00080 doesn't have an own callback. 00081 Note: There's no need to have this in the Fl:: namespace. 00082 */ 00083 static void cleanup_readqueue(Fl_Widget *w) { 00084 00085 if (obj_tail==obj_head) return; 00086 00087 // Read the entire queue and copy over all valid entries. 00088 // The new head will be determined after the last copied entry. 00089 00090 int old_head = obj_head; // save newest entry 00091 int entry = obj_tail; // oldest entry 00092 obj_head = obj_tail; // new queue start 00093 for (;;) { 00094 Fl_Widget *o = obj_queue[entry++]; 00095 if (entry >= QUEUE_SIZE) entry = 0; 00096 if (o != w) { // valid entry 00097 obj_queue[obj_head++] = o; 00098 if (obj_head >= QUEUE_SIZE) obj_head = 0; 00099 } // valid entry 00100 if (entry == old_head) break; 00101 } 00102 return; 00103 } 00105 00106 int Fl_Widget::handle(int) { 00107 return 0; 00108 } 00109 00111 Fl_Fontsize FL_NORMAL_SIZE = 14; 00112 00113 Fl_Widget::Fl_Widget(int X, int Y, int W, int H, const char* L) { 00114 00115 x_ = X; y_ = Y; w_ = W; h_ = H; 00116 00117 label_.value = L; 00118 label_.image = 0; 00119 label_.deimage = 0; 00120 label_.type = FL_NORMAL_LABEL; 00121 label_.font = FL_HELVETICA; 00122 label_.size = FL_NORMAL_SIZE; 00123 label_.color = FL_FOREGROUND_COLOR; 00124 label_.align_ = FL_ALIGN_CENTER; 00125 tooltip_ = 0; 00126 callback_ = default_callback; 00127 user_data_ = 0; 00128 type_ = 0; 00129 flags_ = VISIBLE_FOCUS; 00130 damage_ = 0; 00131 box_ = FL_NO_BOX; 00132 color_ = FL_GRAY; 00133 color2_ = FL_GRAY; 00134 when_ = FL_WHEN_RELEASE; 00135 00136 parent_ = 0; 00137 if (Fl_Group::current()) Fl_Group::current()->add(this); 00138 } 00139 00140 void Fl_Widget::resize(int X, int Y, int W, int H) { 00141 x_ = X; y_ = Y; w_ = W; h_ = H; 00142 } 00143 00144 // this is useful for parent widgets to call to resize children: 00145 int Fl_Widget::damage_resize(int X, int Y, int W, int H) { 00146 if (x() == X && y() == Y && w() == W && h() == H) return 0; 00147 resize(X, Y, W, H); 00148 redraw(); 00149 return 1; 00150 } 00151 00152 int Fl_Widget::take_focus() { 00153 if (!takesevents()) return 0; 00154 if (!visible_focus()) return 0; 00155 if (!handle(FL_FOCUS)) return 0; // see if it wants it 00156 if (contains(Fl::focus())) return 1; // it called Fl::focus for us 00157 Fl::focus(this); 00158 return 1; 00159 } 00160 00161 extern void fl_throw_focus(Fl_Widget*); // in Fl_x.cxx 00162 00168 Fl_Widget::~Fl_Widget() { 00169 Fl::clear_widget_pointer(this); 00170 if (flags() & COPIED_LABEL) free((void *)(label_.value)); 00171 if (flags() & COPIED_TOOLTIP) free((void *)(tooltip_)); 00172 // remove from parent group 00173 if (parent_) parent_->remove(this); 00174 #ifdef DEBUG_DELETE 00175 if (parent_) { // this should never happen 00176 printf("*** Fl_Widget: parent_->remove(this) failed [%p,%p]\n",parent_,this); 00177 } 00178 #endif // DEBUG_DELETE 00179 parent_ = 0; // Don't throw focus to a parent widget. 00180 fl_throw_focus(this); 00181 // remove stale entries from default callback queue (Fl::readqueue()) 00182 if (callback_ == default_callback) cleanup_readqueue(this); 00183 } 00184 00186 void 00187 Fl_Widget::draw_focus(Fl_Boxtype B, int X, int Y, int W, int H) const { 00188 if (!Fl::visible_focus()) return; 00189 switch (B) { 00190 case FL_DOWN_BOX: 00191 case FL_DOWN_FRAME: 00192 case FL_THIN_DOWN_BOX: 00193 case FL_THIN_DOWN_FRAME: 00194 X ++; 00195 Y ++; 00196 default: 00197 break; 00198 } 00199 00200 fl_color(fl_contrast(FL_BLACK, color())); 00201 00202 #if defined(USE_X11) || defined(__APPLE_QUARTZ__) 00203 fl_line_style(FL_DOT); 00204 fl_rect(X + Fl::box_dx(B), Y + Fl::box_dy(B), 00205 W - Fl::box_dw(B) - 1, H - Fl::box_dh(B) - 1); 00206 fl_line_style(FL_SOLID); 00207 #elif defined(WIN32) 00208 // Windows 95/98/ME do not implement the dotted line style, so draw 00209 // every other pixel around the focus area... 00210 // 00211 // Also, QuickDraw (MacOS) does not support line styles specifically, 00212 // and the hack we use in fl_line_style() will not draw horizontal lines 00213 // on odd-numbered rows... 00214 int i, xx, yy; 00215 00216 X += Fl::box_dx(B); 00217 Y += Fl::box_dy(B); 00218 W -= Fl::box_dw(B) + 2; 00219 H -= Fl::box_dh(B) + 2; 00220 00221 for (xx = 0, i = 1; xx < W; xx ++, i ++) if (i & 1) fl_point(X + xx, Y); 00222 for (yy = 0; yy < H; yy ++, i ++) if (i & 1) fl_point(X + W, Y + yy); 00223 for (xx = W; xx > 0; xx --, i ++) if (i & 1) fl_point(X + xx, Y + H); 00224 for (yy = H; yy > 0; yy --, i ++) if (i & 1) fl_point(X, Y + yy); 00225 #else 00226 # error unsupported platform 00227 #endif // WIN32 00228 } 00229 00230 00231 void Fl_Widget::activate() { 00232 if (!active()) { 00233 clear_flag(INACTIVE); 00234 if (active_r()) { 00235 redraw(); 00236 redraw_label(); 00237 handle(FL_ACTIVATE); 00238 if (inside(Fl::focus())) Fl::focus()->take_focus(); 00239 } 00240 } 00241 } 00242 00243 void Fl_Widget::deactivate() { 00244 if (active_r()) { 00245 set_flag(INACTIVE); 00246 redraw(); 00247 redraw_label(); 00248 handle(FL_DEACTIVATE); 00249 fl_throw_focus(this); 00250 } else { 00251 set_flag(INACTIVE); 00252 } 00253 } 00254 00255 int Fl_Widget::active_r() const { 00256 for (const Fl_Widget* o = this; o; o = o->parent()) 00257 if (!o->active()) return 0; 00258 return 1; 00259 } 00260 00261 void Fl_Widget::show() { 00262 if (!visible()) { 00263 clear_flag(INVISIBLE); 00264 if (visible_r()) { 00265 redraw(); 00266 redraw_label(); 00267 handle(FL_SHOW); 00268 if (inside(Fl::focus())) Fl::focus()->take_focus(); 00269 } 00270 } 00271 } 00272 00273 void Fl_Widget::hide() { 00274 if (visible_r()) { 00275 set_flag(INVISIBLE); 00276 for (Fl_Widget *p = parent(); p; p = p->parent()) 00277 if (p->box() || !p->parent()) {p->redraw(); break;} 00278 handle(FL_HIDE); 00279 fl_throw_focus(this); 00280 } else { 00281 set_flag(INVISIBLE); 00282 } 00283 } 00284 00285 int Fl_Widget::visible_r() const { 00286 for (const Fl_Widget* o = this; o; o = o->parent()) 00287 if (!o->visible()) return 0; 00288 return 1; 00289 } 00290 00291 // return true if widget is inside (or equal to) this: 00292 // Returns false for null widgets. 00293 int Fl_Widget::contains(const Fl_Widget *o) const { 00294 for (; o; o = o->parent_) if (o == this) return 1; 00295 return 0; 00296 } 00297 00298 00299 void 00300 Fl_Widget::label(const char *a) { 00301 if (flags() & COPIED_LABEL) { 00302 // reassigning a copied label remains the same copied label 00303 if (label_.value == a) 00304 return; 00305 free((void *)(label_.value)); 00306 clear_flag(COPIED_LABEL); 00307 } 00308 label_.value=a; 00309 redraw_label(); 00310 } 00311 00312 00313 void 00314 Fl_Widget::copy_label(const char *a) { 00315 if (flags() & COPIED_LABEL) free((void *)(label_.value)); 00316 if (a) { 00317 set_flag(COPIED_LABEL); 00318 label_.value=strdup(a); 00319 } else { 00320 clear_flag(COPIED_LABEL); 00321 label_.value=(char *)0; 00322 } 00323 redraw_label(); 00324 } 00325 00334 void 00335 Fl_Widget::do_callback(Fl_Widget* o,void* arg) { 00336 Fl_Widget_Tracker wp(this); 00337 callback_(o,arg); 00338 if (wp.deleted()) return; 00339 if (callback_ != default_callback) 00340 clear_changed(); 00341 } 00342 00343 // 00344 // End of "$Id: Fl_Widget.cxx 7940 2010-12-02 17:58:58Z greg.ercolano $". 00345 //