1998-10-20 00:46:58 +04:00
|
|
|
//
|
2001-12-01 16:59:50 +03:00
|
|
|
// "$Id: Fl_Tabs.cxx,v 1.6.2.10.2.4 2001/12/01 13:59:50 easysw Exp $"
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
|
|
|
// Tab widget for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2001-01-22 18:13:41 +03:00
|
|
|
// Copyright 1998-2001 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.
|
|
|
|
//
|
2000-06-06 01:21:24 +04:00
|
|
|
// Please report all bugs and problems to "fltk-bugs@fltk.org".
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
// This is the "file card tabs" interface to allow you to put lots and lots
|
|
|
|
// of buttons and switches in a panel, as popularized by many toolkits.
|
|
|
|
|
|
|
|
// Each child widget is a card, and it's label() is printed on the card tab.
|
|
|
|
// Clicking the tab makes that card visible.
|
|
|
|
|
2001-08-05 19:34:28 +04:00
|
|
|
#include <stdio.h>
|
1998-10-06 22:21:25 +04:00
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/Fl_Tabs.H>
|
|
|
|
#include <FL/fl_draw.H>
|
|
|
|
|
2001-12-01 16:59:50 +03:00
|
|
|
#define BORDER 2
|
|
|
|
#define EXTRASPACE 10
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
// return the left edges of each tab (plus a fake left edge for a tab
|
|
|
|
// past the right-hand one). These position are actually of the left
|
|
|
|
// edge of the slope. They are either seperated by the correct distance
|
2001-12-01 16:59:50 +03:00
|
|
|
// or by EXTRASPACE or by zero.
|
1998-10-06 22:21:25 +04:00
|
|
|
// Return value is the index of the selected item.
|
|
|
|
|
|
|
|
int Fl_Tabs::tab_positions(int* p, int* w) {
|
1999-10-15 13:01:48 +04:00
|
|
|
int selected = -1;
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
int i;
|
|
|
|
p[0] = 0;
|
|
|
|
for (i=0; i<children(); i++) {
|
|
|
|
Fl_Widget* o = *a++;
|
1999-10-15 13:01:48 +04:00
|
|
|
if (o->visible()) selected = i;
|
1998-10-06 22:21:25 +04:00
|
|
|
if (o->label()) {
|
|
|
|
int wt = 0; int ht = 0; o->measure_label(wt,ht);
|
2001-12-01 16:59:50 +03:00
|
|
|
w[i] = wt+EXTRASPACE;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else
|
2001-12-01 16:59:50 +03:00
|
|
|
w[i] = EXTRASPACE;
|
|
|
|
p[i+1] = p[i]+w[i]+BORDER;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
2001-12-01 16:59:50 +03:00
|
|
|
int r = this->w();
|
1998-10-06 22:21:25 +04:00
|
|
|
if (p[i] <= r) return selected;
|
|
|
|
// uh oh, they are too big:
|
|
|
|
// pack them against right edge:
|
|
|
|
p[i] = r;
|
|
|
|
for (i = children(); i--;) {
|
|
|
|
int l = r-w[i];
|
2001-12-01 16:59:50 +03:00
|
|
|
if (p[i+1] < l) l = p[i+1];
|
1998-10-06 22:21:25 +04:00
|
|
|
if (p[i] <= l) break;
|
|
|
|
p[i] = l;
|
2001-12-01 16:59:50 +03:00
|
|
|
r -= EXTRASPACE;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
// pack them against left edge and truncate width if they still don't fit:
|
|
|
|
for (i = 0; i<children(); i++) {
|
2001-12-01 16:59:50 +03:00
|
|
|
if (p[i] >= i*EXTRASPACE) break;
|
|
|
|
p[i] = i*EXTRASPACE;
|
|
|
|
int W = this->w()-1-EXTRASPACE*(children()-i) - p[i];
|
1998-10-06 22:21:25 +04:00
|
|
|
if (w[i] > W) w[i] = W;
|
|
|
|
}
|
|
|
|
// adjust edges according to visiblity:
|
|
|
|
for (i = children(); i > selected; i--) {
|
|
|
|
p[i] = p[i-1]+w[i-1];
|
|
|
|
}
|
|
|
|
return selected;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return space needed for tabs. Negative to put them on the bottom:
|
|
|
|
int Fl_Tabs::tab_height() {
|
|
|
|
int H = h();
|
|
|
|
int H2 = y();
|
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
for (int i=children(); i--;) {
|
|
|
|
Fl_Widget* o = *a++;
|
|
|
|
if (o->y() < y()+H) H = o->y()-y();
|
|
|
|
if (o->y()+o->h() > H2) H2 = o->y()+o->h();
|
|
|
|
}
|
|
|
|
H2 = y()+h()-H2;
|
2001-12-01 16:59:50 +03:00
|
|
|
if (H2 > H) return (H2 <= 0) ? 0 : -H2;
|
|
|
|
else return (H <= 0) ? 0 : H;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// this is used by fluid to pick tabs:
|
|
|
|
Fl_Widget *Fl_Tabs::which(int event_x, int event_y) {
|
|
|
|
int H = tab_height();
|
|
|
|
if (H < 0) {
|
|
|
|
if (event_y > y()+h() || event_y < y()+h()+H) return 0;
|
|
|
|
} else {
|
|
|
|
if (event_y > y()+H || event_y < y()) return 0;
|
|
|
|
}
|
|
|
|
if (event_x < x()) return 0;
|
|
|
|
int p[128], w[128];
|
2001-12-01 16:59:50 +03:00
|
|
|
tab_positions(p, w);
|
1998-10-06 22:21:25 +04:00
|
|
|
for (int i=0; i<children(); i++) {
|
2001-12-01 16:59:50 +03:00
|
|
|
if (event_x < x()+p[i+1]) return child(i);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Fl_Tabs::handle(int event) {
|
|
|
|
|
|
|
|
Fl_Widget *o;
|
2001-08-05 19:34:28 +04:00
|
|
|
int i;
|
1998-10-06 22:21:25 +04:00
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
|
|
|
|
case FL_PUSH: {
|
|
|
|
int H = tab_height();
|
|
|
|
if (H >= 0) {
|
|
|
|
if (Fl::event_y() > y()+H) goto DEFAULT;
|
|
|
|
} else {
|
|
|
|
if (Fl::event_y() < y()+h()+H) goto DEFAULT;
|
|
|
|
}}
|
2001-11-03 22:24:22 +03:00
|
|
|
if (Fl::visible_focus()) take_focus();
|
1998-10-06 22:21:25 +04:00
|
|
|
case FL_DRAG:
|
|
|
|
case FL_RELEASE:
|
|
|
|
o = which(Fl::event_x(), Fl::event_y());
|
1999-11-16 10:39:59 +03:00
|
|
|
if (event == FL_RELEASE) {push(0); if (o && value(o)) do_callback();}
|
1998-10-06 22:21:25 +04:00
|
|
|
else push(o);
|
|
|
|
return 1;
|
2001-08-05 19:34:28 +04:00
|
|
|
case FL_FOCUS:
|
|
|
|
case FL_UNFOCUS:
|
2001-11-03 22:24:22 +03:00
|
|
|
if (Fl::visible_focus()) {
|
|
|
|
redraw();
|
|
|
|
return 1;
|
|
|
|
} else return 0;
|
2001-08-05 19:34:28 +04:00
|
|
|
case FL_KEYBOARD:
|
|
|
|
switch (Fl::event_key()) {
|
|
|
|
case FL_Left:
|
|
|
|
if (child(0)->visible()) return 0;
|
|
|
|
for (i = 1; i < children(); i ++)
|
|
|
|
if (child(i)->visible()) break;
|
|
|
|
value(child(i - 1));
|
2001-11-25 19:38:11 +03:00
|
|
|
do_callback();
|
2001-08-05 19:34:28 +04:00
|
|
|
return 1;
|
|
|
|
case FL_Right:
|
|
|
|
if (child(children() - 1)->visible()) return 0;
|
|
|
|
for (i = 0; i < children(); i ++)
|
|
|
|
if (child(i)->visible()) break;
|
|
|
|
value(child(i + 1));
|
2001-11-25 19:38:11 +03:00
|
|
|
do_callback();
|
2001-08-05 19:34:28 +04:00
|
|
|
return 1;
|
|
|
|
case FL_Down:
|
|
|
|
redraw();
|
|
|
|
return Fl_Group::handle(FL_FOCUS);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
default:
|
|
|
|
DEFAULT:
|
|
|
|
return Fl_Group::handle(event);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Fl_Tabs::push(Fl_Widget *o) {
|
|
|
|
if (push_ == o) return 0;
|
1999-10-15 13:01:48 +04:00
|
|
|
if (push_ && !push_->visible() || o && !o->visible())
|
|
|
|
damage(FL_DAMAGE_EXPOSE);
|
1998-10-06 22:21:25 +04:00
|
|
|
push_ = o;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1999-10-15 13:01:48 +04:00
|
|
|
// The value() is the first visible child (or the last child if none
|
|
|
|
// are visible) and this also hides any other children.
|
|
|
|
// This allows the tabs to be deleted, moved to other groups, and
|
|
|
|
// show()/hide() called without it screwing up.
|
1998-10-06 22:21:25 +04:00
|
|
|
Fl_Widget* Fl_Tabs::value() {
|
1999-10-15 13:01:48 +04:00
|
|
|
Fl_Widget* v = 0;
|
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
for (int i=children(); i--;) {
|
|
|
|
Fl_Widget* o = *a++;
|
|
|
|
if (v) o->hide();
|
|
|
|
else if (o->visible()) v = o;
|
|
|
|
else if (!i) {o->show(); v = o;}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
1999-10-15 13:01:48 +04:00
|
|
|
// Setting the value hides all other children, and makes this one
|
|
|
|
// visible, iff it is really a child:
|
|
|
|
int Fl_Tabs::value(Fl_Widget *newvalue) {
|
|
|
|
Fl_Widget*const* a = array();
|
2000-08-30 09:51:39 +04:00
|
|
|
int ret = 0;
|
1999-10-15 13:01:48 +04:00
|
|
|
for (int i=children(); i--;) {
|
|
|
|
Fl_Widget* o = *a++;
|
|
|
|
if (o == newvalue) {
|
2000-08-30 09:51:39 +04:00
|
|
|
if (!o->visible()) ret = 1;
|
1999-10-15 13:01:48 +04:00
|
|
|
o->show();
|
|
|
|
} else {
|
|
|
|
o->hide();
|
|
|
|
}
|
|
|
|
}
|
2000-08-30 09:51:39 +04:00
|
|
|
return ret;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
enum {LEFT, RIGHT, SELECTED};
|
|
|
|
|
|
|
|
void Fl_Tabs::draw() {
|
|
|
|
Fl_Widget *v = value();
|
|
|
|
int H = tab_height();
|
2001-12-01 16:59:50 +03:00
|
|
|
|
1998-10-21 18:21:44 +04:00
|
|
|
if (damage() & FL_DAMAGE_ALL) { // redraw the entire thing:
|
2000-10-17 10:53:20 +04:00
|
|
|
fl_color(color());
|
|
|
|
fl_rectf(x(), y()+(H>=0?0:h()+H), w(), H>=0?H:-H);
|
2001-12-01 16:59:50 +03:00
|
|
|
draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H), v ? v->color() : color());
|
1998-11-05 19:04:53 +03:00
|
|
|
if (v) draw_child(*v);
|
1998-10-06 22:21:25 +04:00
|
|
|
} else { // redraw the child
|
1998-11-05 19:04:53 +03:00
|
|
|
if (v) update_child(*v);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
1998-10-19 21:53:09 +04:00
|
|
|
if (damage() & (FL_DAMAGE_EXPOSE|FL_DAMAGE_ALL)) {
|
1998-10-06 22:21:25 +04:00
|
|
|
int p[128]; int w[128];
|
|
|
|
int selected = tab_positions(p,w);
|
|
|
|
int i;
|
|
|
|
Fl_Widget*const* a = array();
|
|
|
|
for (i=0; i<selected; i++)
|
|
|
|
draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], LEFT);
|
|
|
|
for (i=children()-1; i > selected; i--)
|
|
|
|
draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], RIGHT);
|
1999-10-15 13:01:48 +04:00
|
|
|
if (v) {
|
|
|
|
i = selected;
|
|
|
|
draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], SELECTED);
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
|
|
|
|
int sel = (what == SELECTED);
|
2001-12-01 16:59:50 +03:00
|
|
|
int dh = Fl::box_dh(box());
|
|
|
|
int dy = Fl::box_dy(box());
|
|
|
|
|
|
|
|
if ((x2 < x1+W) && what == RIGHT) x1 = x2 - W;
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
if (H >= 0) {
|
2001-12-01 16:59:50 +03:00
|
|
|
if (sel) fl_clip(x1, y(), x2 - x1, H + dh - dy);
|
|
|
|
else fl_clip(x1, y(), x2 - x1, H);
|
|
|
|
|
|
|
|
H += dh;
|
|
|
|
|
|
|
|
draw_box(box(), x1, y(), W, H, o->color());
|
|
|
|
|
|
|
|
o->draw_label(x1, y(), W, H, FL_ALIGN_CENTER);
|
|
|
|
|
|
|
|
if (Fl::focus() == this && o->visible())
|
|
|
|
draw_focus(box(), x1, y(), W, H);
|
|
|
|
|
|
|
|
fl_pop_clip();
|
1998-10-06 22:21:25 +04:00
|
|
|
} else {
|
2001-12-01 16:59:50 +03:00
|
|
|
H = -H;
|
|
|
|
|
|
|
|
if (sel) fl_clip(x1, y() + h() - H - dy, x2 - x1, H + dy);
|
|
|
|
else fl_clip(x1, y() + h() - H, x2 - x1, H);
|
|
|
|
|
|
|
|
H += dh;
|
|
|
|
|
|
|
|
draw_box(box(), x1, y() + h() - H, W, H, o->color());
|
|
|
|
|
|
|
|
o->draw_label(x1, y() + h() - H, W, H, FL_ALIGN_CENTER);
|
2001-08-05 19:34:28 +04:00
|
|
|
|
|
|
|
if (Fl::focus() == this && o->visible())
|
2001-12-01 16:59:50 +03:00
|
|
|
draw_focus(box(), x1, y() + h() - H, W, H);
|
|
|
|
|
|
|
|
fl_pop_clip();
|
2001-08-05 19:34:28 +04:00
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Fl_Tabs::Fl_Tabs(int X,int Y,int W, int H, const char *l) :
|
1999-10-15 13:01:48 +04:00
|
|
|
Fl_Group(X,Y,W,H,l)
|
|
|
|
{
|
|
|
|
box(FL_THIN_UP_BOX);
|
|
|
|
push_ = 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
1998-10-20 00:46:58 +04:00
|
|
|
|
|
|
|
//
|
2001-12-01 16:59:50 +03:00
|
|
|
// End of "$Id: Fl_Tabs.cxx,v 1.6.2.10.2.4 2001/12/01 13:59:50 easysw Exp $".
|
1998-10-20 00:46:58 +04:00
|
|
|
//
|