1998-10-20 00:46:58 +04:00
|
|
|
//
|
2005-02-06 04:29:54 +03:00
|
|
|
// "$Id$"
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
|
|
|
// Base widget class for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2010-11-29 00:06:39 +03:00
|
|
|
// Copyright 1998-2010 by Bill Spitzak and others.
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Library General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Library General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Library General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
// USA.
|
|
|
|
//
|
2005-04-16 04:13:17 +04:00
|
|
|
// Please report all bugs and problems on the following page:
|
|
|
|
//
|
|
|
|
// http://www.fltk.org/str.php
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/Fl_Widget.H>
|
|
|
|
#include <FL/Fl_Group.H>
|
2001-08-02 19:32:00 +04:00
|
|
|
#include <FL/Fl_Tooltip.H>
|
2001-08-05 00:17:10 +04:00
|
|
|
#include <FL/fl_draw.H>
|
2004-11-23 22:51:03 +03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include "flstring.h"
|
2001-08-02 19:32:00 +04:00
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
2008-09-15 21:46:42 +04:00
|
|
|
// for compatibility with Forms, all widgets without callbacks are
|
1998-10-06 22:21:25 +04:00
|
|
|
// inserted into a "queue" when they are activated, and the forms
|
2008-09-21 02:46:24 +04:00
|
|
|
// compatibility interaction functions (fl_do_events, etc.) will
|
1998-10-06 22:21:25 +04:00
|
|
|
// read one widget at a time from this queue and return it:
|
|
|
|
|
|
|
|
const int QUEUE_SIZE = 20;
|
|
|
|
|
|
|
|
static Fl_Widget *obj_queue[QUEUE_SIZE];
|
|
|
|
static int obj_head, obj_tail;
|
|
|
|
|
|
|
|
void Fl_Widget::default_callback(Fl_Widget *o, void * /*v*/) {
|
|
|
|
#if 0
|
2008-09-15 21:46:42 +04:00
|
|
|
// This is necessary for strict forms compatibility but is confusing.
|
1998-10-06 22:21:25 +04:00
|
|
|
// Use the parent's callback if this widget does not have one.
|
|
|
|
for (Fl_Widget *p = o->parent(); p; p = p->parent())
|
|
|
|
if (p->callback() != default_callback) {
|
|
|
|
p->do_callback(o,v);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
obj_queue[obj_head++] = o;
|
|
|
|
if (obj_head >= QUEUE_SIZE) obj_head = 0;
|
|
|
|
if (obj_head == obj_tail) {
|
|
|
|
obj_tail++;
|
|
|
|
if (obj_tail >= QUEUE_SIZE) obj_tail = 0;
|
|
|
|
}
|
|
|
|
}
|
2008-09-14 02:33:03 +04:00
|
|
|
/**
|
|
|
|
All Fl_Widgets that don't have a callback defined use a
|
2008-12-13 21:31:54 +03:00
|
|
|
default callback that puts a pointer to the widget in this queue,
|
|
|
|
and this method reads the oldest widget out of this queue.
|
2008-09-14 02:33:03 +04:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget *Fl::readqueue() {
|
|
|
|
if (obj_tail==obj_head) return 0;
|
|
|
|
Fl_Widget *o = obj_queue[obj_tail++];
|
|
|
|
if (obj_tail >= QUEUE_SIZE) obj_tail = 0;
|
|
|
|
return o;
|
|
|
|
}
|
2009-12-23 15:53:45 +03:00
|
|
|
/*
|
|
|
|
This static internal function removes all pending callbacks for a
|
|
|
|
specific widget from the default callback queue (Fl::readqueue()).
|
|
|
|
It is only called from Fl_Widget's destructor if the widget
|
|
|
|
doesn't have an own callback.
|
|
|
|
Note: There's no need to have this in the Fl:: namespace.
|
|
|
|
*/
|
|
|
|
static void cleanup_readqueue(Fl_Widget *w) {
|
|
|
|
|
|
|
|
if (obj_tail==obj_head) return;
|
|
|
|
|
|
|
|
// Read the entire queue and copy over all valid entries.
|
|
|
|
// The new head will be determined after the last copied entry.
|
|
|
|
|
|
|
|
int old_head = obj_head; // save newest entry
|
|
|
|
int entry = obj_tail; // oldest entry
|
|
|
|
obj_head = obj_tail; // new queue start
|
|
|
|
for (;;) {
|
|
|
|
Fl_Widget *o = obj_queue[entry++];
|
|
|
|
if (entry >= QUEUE_SIZE) entry = 0;
|
|
|
|
if (o != w) { // valid entry
|
|
|
|
obj_queue[obj_head++] = o;
|
|
|
|
if (obj_head >= QUEUE_SIZE) obj_head = 0;
|
|
|
|
} // valid entry
|
|
|
|
if (entry == old_head) break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
2002-05-24 18:19:19 +04:00
|
|
|
int Fl_Widget::handle(int) {
|
2002-04-13 00:16:07 +04:00
|
|
|
return 0;
|
2002-04-09 21:20:24 +04:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2008-12-13 21:31:54 +03:00
|
|
|
/** Default font size for widgets */
|
2008-08-16 01:11:21 +04:00
|
|
|
Fl_Fontsize FL_NORMAL_SIZE = 14;
|
2000-04-11 12:11:56 +04:00
|
|
|
|
2008-09-11 03:56:49 +04:00
|
|
|
Fl_Widget::Fl_Widget(int X, int Y, int W, int H, const char* L) {
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
x_ = X; y_ = Y; w_ = W; h_ = H;
|
|
|
|
|
2001-08-06 07:17:43 +04:00
|
|
|
label_.value = L;
|
|
|
|
label_.image = 0;
|
|
|
|
label_.deimage = 0;
|
|
|
|
label_.type = FL_NORMAL_LABEL;
|
|
|
|
label_.font = FL_HELVETICA;
|
2008-04-23 23:09:28 +04:00
|
|
|
label_.size = FL_NORMAL_SIZE;
|
2005-10-30 20:42:21 +03:00
|
|
|
label_.color = FL_FOREGROUND_COLOR;
|
2010-01-16 18:56:41 +03:00
|
|
|
label_.align_ = FL_ALIGN_CENTER;
|
2001-08-06 07:17:43 +04:00
|
|
|
tooltip_ = 0;
|
|
|
|
callback_ = default_callback;
|
|
|
|
user_data_ = 0;
|
|
|
|
type_ = 0;
|
2002-07-23 19:07:33 +04:00
|
|
|
flags_ = VISIBLE_FOCUS;
|
2001-08-06 07:17:43 +04:00
|
|
|
damage_ = 0;
|
|
|
|
box_ = FL_NO_BOX;
|
|
|
|
color_ = FL_GRAY;
|
|
|
|
color2_ = FL_GRAY;
|
|
|
|
when_ = FL_WHEN_RELEASE;
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
parent_ = 0;
|
|
|
|
if (Fl_Group::current()) Fl_Group::current()->add(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_Widget::resize(int X, int Y, int W, int H) {
|
|
|
|
x_ = X; y_ = Y; w_ = W; h_ = H;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is useful for parent widgets to call to resize children:
|
|
|
|
int Fl_Widget::damage_resize(int X, int Y, int W, int H) {
|
|
|
|
if (x() == X && y() == Y && w() == W && h() == H) return 0;
|
|
|
|
resize(X, Y, W, H);
|
|
|
|
redraw();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Fl_Widget::take_focus() {
|
|
|
|
if (!takesevents()) return 0;
|
2002-07-23 19:07:33 +04:00
|
|
|
if (!visible_focus()) return 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
if (!handle(FL_FOCUS)) return 0; // see if it wants it
|
|
|
|
if (contains(Fl::focus())) return 1; // it called Fl::focus for us
|
|
|
|
Fl::focus(this);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2001-11-22 18:35:02 +03:00
|
|
|
extern void fl_throw_focus(Fl_Widget*); // in Fl_x.cxx
|
1998-10-06 22:21:25 +04:00
|
|
|
|
2008-09-18 23:09:34 +04:00
|
|
|
/**
|
|
|
|
Destroys the widget, taking care of throwing focus before if any.
|
2009-01-08 20:12:34 +03:00
|
|
|
Destruction removes the widget from any parent group! And groups when
|
|
|
|
destroyed destroy all their children. This is convenient and fast.
|
2008-09-18 23:09:34 +04:00
|
|
|
*/
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget::~Fl_Widget() {
|
2006-04-28 01:40:47 +04:00
|
|
|
Fl::clear_widget_pointer(this);
|
2004-11-23 22:51:03 +03:00
|
|
|
if (flags() & COPIED_LABEL) free((void *)(label_.value));
|
2009-01-08 20:12:34 +03:00
|
|
|
// remove from parent group
|
|
|
|
if (parent_) parent_->remove(this);
|
|
|
|
#ifdef DEBUG_DELETE
|
|
|
|
if (parent_) { // this should never happen
|
|
|
|
printf("*** Fl_Widget: parent_->remove(this) failed [%p,%p]\n",parent_,this);
|
|
|
|
}
|
|
|
|
#endif // DEBUG_DELETE
|
2002-01-07 23:40:02 +03:00
|
|
|
parent_ = 0; // Don't throw focus to a parent widget.
|
1998-10-06 22:21:25 +04:00
|
|
|
fl_throw_focus(this);
|
2009-12-23 15:53:45 +03:00
|
|
|
// remove stale entries from default callback queue (Fl::readqueue())
|
|
|
|
if (callback_ == default_callback) cleanup_readqueue(this);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
2009-03-21 20:08:23 +03:00
|
|
|
/** Draws a focus box for the widget at the given position and size */
|
2001-08-05 00:17:10 +04:00
|
|
|
void
|
|
|
|
Fl_Widget::draw_focus(Fl_Boxtype B, int X, int Y, int W, int H) const {
|
2001-11-03 08:11:34 +03:00
|
|
|
if (!Fl::visible_focus()) return;
|
2001-08-05 18:00:15 +04:00
|
|
|
switch (B) {
|
|
|
|
case FL_DOWN_BOX:
|
|
|
|
case FL_DOWN_FRAME:
|
|
|
|
case FL_THIN_DOWN_BOX:
|
|
|
|
case FL_THIN_DOWN_FRAME:
|
|
|
|
X ++;
|
|
|
|
Y ++;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-11-03 08:11:34 +03:00
|
|
|
fl_color(fl_contrast(FL_BLACK, color()));
|
|
|
|
|
2008-10-14 03:10:43 +04:00
|
|
|
#if defined(USE_X11) || defined(__APPLE_QUARTZ__)
|
|
|
|
fl_line_style(FL_DOT);
|
|
|
|
fl_rect(X + Fl::box_dx(B), Y + Fl::box_dy(B),
|
|
|
|
W - Fl::box_dw(B) - 1, H - Fl::box_dh(B) - 1);
|
|
|
|
fl_line_style(FL_SOLID);
|
|
|
|
#elif defined(WIN32)
|
2001-11-03 08:11:34 +03:00
|
|
|
// Windows 95/98/ME do not implement the dotted line style, so draw
|
|
|
|
// every other pixel around the focus area...
|
2001-12-07 19:28:38 +03:00
|
|
|
//
|
|
|
|
// Also, QuickDraw (MacOS) does not support line styles specifically,
|
2001-12-14 19:48:13 +03:00
|
|
|
// and the hack we use in fl_line_style() will not draw horizontal lines
|
2001-12-07 19:28:38 +03:00
|
|
|
// on odd-numbered rows...
|
2001-11-03 08:11:34 +03:00
|
|
|
int i, xx, yy;
|
|
|
|
|
|
|
|
X += Fl::box_dx(B);
|
|
|
|
Y += Fl::box_dy(B);
|
|
|
|
W -= Fl::box_dw(B) + 2;
|
|
|
|
H -= Fl::box_dh(B) + 2;
|
|
|
|
|
|
|
|
for (xx = 0, i = 1; xx < W; xx ++, i ++) if (i & 1) fl_point(X + xx, Y);
|
|
|
|
for (yy = 0; yy < H; yy ++, i ++) if (i & 1) fl_point(X + W, Y + yy);
|
|
|
|
for (xx = W; xx > 0; xx --, i ++) if (i & 1) fl_point(X + xx, Y + H);
|
|
|
|
for (yy = H; yy > 0; yy --, i ++) if (i & 1) fl_point(X, Y + yy);
|
|
|
|
#else
|
2008-10-14 03:10:43 +04:00
|
|
|
# error unsupported platform
|
2001-11-03 08:11:34 +03:00
|
|
|
#endif // WIN32
|
2001-08-05 00:17:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
void Fl_Widget::activate() {
|
1998-12-15 18:35:19 +03:00
|
|
|
if (!active()) {
|
|
|
|
clear_flag(INACTIVE);
|
|
|
|
if (active_r()) {
|
2002-06-02 21:52:36 +04:00
|
|
|
redraw();
|
2002-10-04 19:59:29 +04:00
|
|
|
redraw_label();
|
1998-12-15 18:35:19 +03:00
|
|
|
handle(FL_ACTIVATE);
|
|
|
|
if (inside(Fl::focus())) Fl::focus()->take_focus();
|
|
|
|
}
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_Widget::deactivate() {
|
1998-12-15 18:35:19 +03:00
|
|
|
if (active_r()) {
|
|
|
|
set_flag(INACTIVE);
|
2002-06-02 21:52:36 +04:00
|
|
|
redraw();
|
2002-10-04 19:59:29 +04:00
|
|
|
redraw_label();
|
1998-12-15 18:35:19 +03:00
|
|
|
handle(FL_DEACTIVATE);
|
|
|
|
fl_throw_focus(this);
|
|
|
|
} else {
|
|
|
|
set_flag(INACTIVE);
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int Fl_Widget::active_r() const {
|
|
|
|
for (const Fl_Widget* o = this; o; o = o->parent())
|
|
|
|
if (!o->active()) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_Widget::show() {
|
1998-12-15 18:35:19 +03:00
|
|
|
if (!visible()) {
|
|
|
|
clear_flag(INVISIBLE);
|
|
|
|
if (visible_r()) {
|
2002-06-02 21:52:36 +04:00
|
|
|
redraw();
|
2002-10-04 19:59:29 +04:00
|
|
|
redraw_label();
|
1998-12-15 18:35:19 +03:00
|
|
|
handle(FL_SHOW);
|
|
|
|
if (inside(Fl::focus())) Fl::focus()->take_focus();
|
|
|
|
}
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_Widget::hide() {
|
1998-12-15 18:35:19 +03:00
|
|
|
if (visible_r()) {
|
|
|
|
set_flag(INVISIBLE);
|
|
|
|
for (Fl_Widget *p = parent(); p; p = p->parent())
|
|
|
|
if (p->box() || !p->parent()) {p->redraw(); break;}
|
|
|
|
handle(FL_HIDE);
|
|
|
|
fl_throw_focus(this);
|
|
|
|
} else {
|
|
|
|
set_flag(INVISIBLE);
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int Fl_Widget::visible_r() const {
|
|
|
|
for (const Fl_Widget* o = this; o; o = o->parent())
|
|
|
|
if (!o->visible()) return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return true if widget is inside (or equal to) this:
|
|
|
|
// Returns false for null widgets.
|
|
|
|
int Fl_Widget::contains(const Fl_Widget *o) const {
|
|
|
|
for (; o; o = o->parent_) if (o == this) return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
1998-10-20 00:46:58 +04:00
|
|
|
|
2004-11-23 22:47:52 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
Fl_Widget::label(const char *a) {
|
|
|
|
if (flags() & COPIED_LABEL) {
|
2005-07-12 01:05:45 +04:00
|
|
|
// reassigning a copied label remains the same copied label
|
|
|
|
if (label_.value == a)
|
|
|
|
return;
|
2004-11-23 22:51:03 +03:00
|
|
|
free((void *)(label_.value));
|
2004-11-23 22:47:52 +03:00
|
|
|
clear_flag(COPIED_LABEL);
|
|
|
|
}
|
|
|
|
label_.value=a;
|
|
|
|
redraw_label();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Fl_Widget::copy_label(const char *a) {
|
2004-11-23 22:51:03 +03:00
|
|
|
if (flags() & COPIED_LABEL) free((void *)(label_.value));
|
2005-02-06 04:29:54 +03:00
|
|
|
if (a) {
|
|
|
|
set_flag(COPIED_LABEL);
|
|
|
|
label_.value=strdup(a);
|
|
|
|
} else {
|
|
|
|
clear_flag(COPIED_LABEL);
|
|
|
|
label_.value=(char *)0;
|
|
|
|
}
|
2004-11-23 22:47:52 +03:00
|
|
|
redraw_label();
|
|
|
|
}
|
|
|
|
|
2009-02-08 17:44:15 +03:00
|
|
|
/** Calls the widget callback.
|
|
|
|
|
|
|
|
Causes a widget to invoke its callback function with arbitrary arguments.
|
2009-02-15 16:49:34 +03:00
|
|
|
|
2009-03-24 04:40:44 +03:00
|
|
|
\param[in] o call the callback with \p o as the widget argument
|
|
|
|
\param[in] arg use \p arg as the user data argument
|
2009-02-08 17:44:15 +03:00
|
|
|
\see callback()
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
Fl_Widget::do_callback(Fl_Widget* o,void* arg) {
|
2010-03-23 20:37:51 +03:00
|
|
|
Fl_Widget_Tracker wp(this);
|
|
|
|
callback_(o,arg);
|
2009-02-08 17:44:15 +03:00
|
|
|
if (wp.deleted()) return;
|
2010-03-23 20:37:51 +03:00
|
|
|
if (callback_ != default_callback)
|
2009-02-08 17:44:15 +03:00
|
|
|
clear_changed();
|
|
|
|
}
|
2004-11-23 22:47:52 +03:00
|
|
|
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
2005-02-06 04:29:54 +03:00
|
|
|
// End of "$Id$".
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|