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)  

Fl_Widget.cxx

Go to the documentation of this file.
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 //