summaryrefslogtreecommitdiff
path: root/src/Fl_Tabs.cxx
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>1998-10-06 18:21:25 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>1998-10-06 18:21:25 +0000
commitf9039b2ae21988783feae9b362818e7923e82d14 (patch)
tree6d6fe3679d73448758f9794e7d4d4f6b22a4adad /src/Fl_Tabs.cxx
parent67e89232f9ba067825a158734a09e0fa21aacbe3 (diff)
Initial revision
git-svn-id: file:///fltk/svn/fltk/trunk@2 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Tabs.cxx')
-rw-r--r--src/Fl_Tabs.cxx234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/Fl_Tabs.cxx b/src/Fl_Tabs.cxx
new file mode 100644
index 000000000..44e2d7ecf
--- /dev/null
+++ b/src/Fl_Tabs.cxx
@@ -0,0 +1,234 @@
+// Fl_Tabs.C
+
+// 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.
+
+#include <FL/Fl.H>
+#include <FL/Fl_Tabs.H>
+#include <FL/fl_draw.H>
+
+#define BORDER 10
+#define TABSLOPE 8
+
+// 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
+// or by TABSLOPE or by zero.
+// Return value is the index of the selected item.
+
+int Fl_Tabs::tab_positions(int* p, int* w) {
+ int selected = 0;
+ Fl_Widget*const* a = array();
+ int i;
+ p[0] = 0;
+ for (i=0; i<children(); i++) {
+ Fl_Widget* o = *a++;
+ if (o == value_) selected = i;
+ if (o->label()) {
+ int wt = 0; int ht = 0; o->measure_label(wt,ht);
+ w[i] = wt+TABSLOPE;
+ } else
+ w[i] = 2*TABSLOPE;
+ p[i+1] = p[i]+w[i];
+ }
+ int r = this->w()-TABSLOPE-1;
+ 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];
+ if (p[i+1]-TABSLOPE < l) l = p[i+1]-TABSLOPE;
+ if (p[i] <= l) break;
+ p[i] = l;
+ r -= TABSLOPE;
+ }
+ // pack them against left edge and truncate width if they still don't fit:
+ for (i = 0; i<children(); i++) {
+ if (p[i] >= i*TABSLOPE) break;
+ p[i] = i*TABSLOPE;
+ int W = this->w()-1-TABSLOPE*(children()-i) - p[i];
+ 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;
+ if (H2 > H) {
+ H = H2-Fl::box_dy(box());
+ return (H <= 0) ? 0 : -H;
+ } else {
+ H = H-Fl::box_dy(box());
+ return (H <= 0) ? 0 : H;
+ }
+}
+
+// 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];
+ int selected = tab_positions(p, w);
+ int d = (event_y-(H>=0?y():y()+h()))*TABSLOPE/H;
+ for (int i=0; i<children(); i++) {
+ if (event_x < x()+p[i+1]+(i<selected ? TABSLOPE-d : d)) return child(i);
+ }
+ return 0;
+}
+
+int Fl_Tabs::handle(int event) {
+
+ Fl_Widget *o;
+
+ 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;
+ }}
+ case FL_DRAG:
+ case FL_RELEASE:
+ o = which(Fl::event_x(), Fl::event_y());
+ if (event == FL_RELEASE) {push(0); if (o) value(o);}
+ else push(o);
+ return 1;
+
+ default:
+ DEFAULT:
+ value(); // initialize value & visibility if value_ == 0
+ return Fl_Group::handle(event);
+
+ }
+}
+
+int Fl_Tabs::push(Fl_Widget *o) {
+ if (push_ == o) return 0;
+ if (push_ && push_ != value_ || o && o != value_) damage(2);
+ push_ = o;
+ return 1;
+}
+
+Fl_Widget* Fl_Tabs::value() {
+ Fl_Widget *v = value_;
+ if (!v) {
+ // If value() has not been called, find first visible() child:
+ Fl_Widget*const* a = array();
+ for (int i=children(); i--;) {
+ Fl_Widget* o = *a++;
+ if (v) o->hide();
+ else if (o->visible()) v = o;
+ }
+ if (!v) return 0; // no children...
+ value_ = v;
+ }
+ return v;
+}
+
+int Fl_Tabs::value(Fl_Widget *o) {
+ if (value_ == o) return 0;
+ if (o) o->show();
+ if (value_) value_->hide();
+ value_ = o;
+ redraw();
+ do_callback();
+ return 1;
+}
+
+enum {LEFT, RIGHT, SELECTED};
+
+void Fl_Tabs::draw() {
+ Fl_Widget *v = value();
+ int H = tab_height();
+ if (damage() & ~3) { // redraw the entire thing:
+ fl_clip(x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H));
+ draw_box(box(), x(), y(), w(), h(), v->color());
+ fl_pop_clip();
+ draw_child(*v);
+ } else { // redraw the child
+ update_child(*v);
+ }
+ if (damage() & 2) {
+ 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);
+ i = selected;
+ draw_tab(x()+p[i], x()+p[i+1], w[i], H, a[i], SELECTED);
+ }
+}
+
+void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
+ if (x2 < x1+W) {
+ if (what == LEFT) {
+ if (x1+W < x2+TABSLOPE) x2 = x1+W;
+ else x2 += TABSLOPE;
+ } else {
+ if (x1+W < x2+TABSLOPE) x1 = x2-W;
+ else x1 -= TABSLOPE;
+ }
+ }
+ int sel = (what == SELECTED);
+ fl_color(o->color());
+ if (H >= 0) {
+ fl_polygon(x1, y()+H+sel, x1+TABSLOPE, y(), x2, y(),
+ x2+TABSLOPE, y()+H+sel);
+ fl_color(!sel && o==push_ ? FL_DARK3 : FL_LIGHT3);
+ fl_line(x1, y()+H, x1+TABSLOPE, y(), x2, y());
+ if (sel) {
+ if (x1>x()) fl_xyline(x(), y()+H, x1);
+ if (x2+TABSLOPE < x()+w()-1) fl_xyline(x2+TABSLOPE, y()+H, x()+w()-1);
+ }
+ fl_color(!sel && o==push_ ? FL_LIGHT3 : FL_DARK3);
+ fl_line(x2, y(), x2+TABSLOPE, y()+H);
+ } else {
+ fl_polygon(x1, y()+h()+H-sel, x1+TABSLOPE, y()+h(), x2, y()+h(),
+ x2+TABSLOPE, y()+h()+H-sel);
+ fl_color(!sel && o==push_ ? FL_LIGHT3 : FL_DARK3);
+ fl_line(x1+TABSLOPE, y()+h()-1, x2, y()+h()-1, x2+TABSLOPE, y()+h()+H);
+ if (sel) {
+ if (x1>x()) fl_xyline(x(), y()+h()+H, x1);
+ if (x2+TABSLOPE < x()+w()-1) fl_xyline(x2+TABSLOPE, y()+h()+H,x()+w()-1);
+ }
+ fl_color(!sel && o==push_ ? FL_DARK3 : FL_LIGHT3);
+ fl_line(x1, y()+h()+H, x1+TABSLOPE, y()+h()-1);
+ }
+ if (x2-x1 > 2*TABSLOPE)
+ o->draw_label(what==LEFT ? x1+TABSLOPE : x2-W+TABSLOPE,
+ y()+(H<0?h()+H-3:0), W-TABSLOPE,
+ (H<0?-H:H)+3, FL_ALIGN_CENTER);
+}
+
+Fl_Tabs::Fl_Tabs(int X,int Y,int W, int H, const char *l) :
+ Fl_Group(X,Y,W,H,l) {
+ box(FL_THIN_UP_BOX);
+ value_ = push_ = 0;
+}