source: rtems-graphics-toolkit/fltk-1.1.10/src/Fl_Tabs.cxx @ 513eea1

Last change on this file since 513eea1 was 513eea1, checked in by Joel Sherrill <joel.sherrill@…>, on 01/09/10 at 22:43:24

2010-01-08 Joel Sherrill <joel.sherrill@…>

fltk 1.1.10. imported

  • ORIGIN: Updated.
  • Property mode set to 100644
File size: 10.5 KB
Line 
1//
2// "$Id$"
3//
4// Tab widget for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2005 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25//     http://www.fltk.org/str.php
26//
27
28// This is the "file card tabs" interface to allow you to put lots and lots
29// of buttons and switches in a panel, as popularized by many toolkits.
30
31// Each child widget is a card, and it's label() is printed on the card tab.
32// Clicking the tab makes that card visible.
33
34#include <stdio.h>
35#include <FL/Fl.H>
36#include <FL/Fl_Tabs.H>
37#include <FL/fl_draw.H>
38#include <FL/Fl_Tooltip.H>
39
40#define BORDER 2
41#define EXTRASPACE 10
42
43// return the left edges of each tab (plus a fake left edge for a tab
44// past the right-hand one).  These position are actually of the left
45// edge of the slope.  They are either seperated by the correct distance
46// or by EXTRASPACE or by zero.
47// Return value is the index of the selected item.
48
49int Fl_Tabs::tab_positions(int* p, int* wp) {
50  int selected = 0;
51  Fl_Widget*const* a = array();
52  int i;
53  char prev_draw_shortcut = fl_draw_shortcut;
54  fl_draw_shortcut = 1;
55
56  p[0] = Fl::box_dx(box());
57  for (i=0; i<children(); i++) {
58    Fl_Widget* o = *a++;
59    if (o->visible()) selected = i;
60
61    int wt = 0; int ht = 0;
62    o->measure_label(wt,ht);
63
64    wp[i]  = wt+EXTRASPACE;
65    p[i+1] = p[i]+wp[i]+BORDER;
66  }
67  fl_draw_shortcut = prev_draw_shortcut;
68
69  int r = w();
70  if (p[i] <= r) return selected;
71  // uh oh, they are too big:
72  // pack them against right edge:
73  p[i] = r;
74  for (i = children(); i--;) {
75    int l = r-wp[i];
76    if (p[i+1] < l) l = p[i+1];
77    if (p[i] <= l) break;
78    p[i] = l;
79    r -= EXTRASPACE;
80  }
81  // pack them against left edge and truncate width if they still don't fit:
82  for (i = 0; i<children(); i++) {
83    if (p[i] >= i*EXTRASPACE) break;
84    p[i] = i*EXTRASPACE;
85    int W = w()-1-EXTRASPACE*(children()-i) - p[i];
86    if (wp[i] > W) wp[i] = W;
87  }
88  // adjust edges according to visiblity:
89  for (i = children(); i > selected; i--) {
90    p[i] = p[i-1]+wp[i-1];
91  }
92  return selected;
93}
94
95// return space needed for tabs.  Negative to put them on the bottom:
96int Fl_Tabs::tab_height() {
97  int H = h();
98  int H2 = y();
99  Fl_Widget*const* a = array();
100  for (int i=children(); i--;) {
101    Fl_Widget* o = *a++;
102    if (o->y() < y()+H) H = o->y()-y();
103    if (o->y()+o->h() > H2) H2 = o->y()+o->h();
104  }
105  H2 = y()+h()-H2;
106  if (H2 > H) return (H2 <= 0) ? 0 : -H2;
107  else return (H <= 0) ? 0 : H;
108}
109
110// this is used by fluid to pick tabs:
111Fl_Widget *Fl_Tabs::which(int event_x, int event_y) {
112  int H = tab_height();
113  if (H < 0) {
114    if (event_y > y()+h() || event_y < y()+h()+H) return 0;
115  } else {
116    if (event_y > y()+H || event_y < y()) return 0;
117  }
118  if (event_x < x()) return 0;
119  int p[128], wp[128];
120  tab_positions(p, wp);
121  for (int i=0; i<children(); i++) {
122    if (event_x < x()+p[i+1]) return child(i);
123  }
124  return 0;
125}
126
127void Fl_Tabs::redraw_tabs()
128{
129  int H = tab_height();
130  if (H >= 0) {
131    H += Fl::box_dy(box());
132    damage(FL_DAMAGE_SCROLL, x(), y(), w(), H);
133  } else {
134    H = Fl::box_dy(box()) - H;
135    damage(FL_DAMAGE_SCROLL, x(), y() + h() - H, w(), H);
136  }
137}
138
139int Fl_Tabs::handle(int event) {
140
141  Fl_Widget *o;
142  int i;
143
144  switch (event) {
145
146  case FL_PUSH: {
147    int H = tab_height();
148    if (H >= 0) {
149      if (Fl::event_y() > y()+H) return Fl_Group::handle(event);
150    } else {
151      if (Fl::event_y() < y()+h()+H) return Fl_Group::handle(event);
152    }}
153  case FL_DRAG:
154  case FL_RELEASE:
155    o = which(Fl::event_x(), Fl::event_y());
156    if (event == FL_RELEASE) {
157      push(0);
158      if (o && Fl::visible_focus() && Fl::focus()!=this) {
159        Fl::focus(this);
160        redraw_tabs();
161      }
162      if (o && value(o)) {
163        set_changed();
164        do_callback();
165      }
166      Fl_Tooltip::current(o);
167    } else {
168      push(o);
169    }
170    return 1;
171  case FL_MOVE: {
172    int ret = Fl_Group::handle(event);
173    Fl_Widget *o = Fl_Tooltip::current(), *n = o;
174    int H = tab_height();
175    if ( (H>=0) && (Fl::event_y()>y()+H) )
176      return ret;
177    else if ( (H<0) && (Fl::event_y() < y()+h()+H) )
178      return ret;
179    else {
180      n = which(Fl::event_x(), Fl::event_y());
181      if (!n) n = this;
182    }
183    if (n!=o)
184      Fl_Tooltip::enter(n);
185    return ret; }
186  case FL_FOCUS:
187  case FL_UNFOCUS:
188    if (!Fl::visible_focus()) return Fl_Group::handle(event);
189    if (Fl::event() == FL_RELEASE ||
190        Fl::event() == FL_SHORTCUT ||
191        Fl::event() == FL_KEYBOARD ||
192        Fl::event() == FL_FOCUS ||
193        Fl::event() == FL_UNFOCUS) {
194      redraw_tabs();
195      if (Fl::event() == FL_FOCUS || Fl::event() == FL_UNFOCUS) return 0;
196      else return 1;
197    } else return Fl_Group::handle(event);
198  case FL_KEYBOARD:
199    switch (Fl::event_key()) {
200      case FL_Left:
201        if (child(0)->visible()) return 0;
202        for (i = 1; i < children(); i ++)
203          if (child(i)->visible()) break;
204        value(child(i - 1));
205        set_changed();
206        do_callback();
207        return 1;
208      case FL_Right:
209        if (child(children() - 1)->visible()) return 0;
210        for (i = 0; i < children(); i ++)
211          if (child(i)->visible()) break;
212        value(child(i + 1));
213        set_changed();
214        do_callback();
215        return 1;
216      case FL_Down:
217        redraw();
218        return Fl_Group::handle(FL_FOCUS);
219      default:
220        break;
221    }
222    return Fl_Group::handle(event);
223  case FL_SHORTCUT:
224    for (i = 0; i < children(); ++i) {
225      Fl_Widget *c = child(i);
226      if (c->test_shortcut(c->label())) {
227        char sc = !c->visible();
228        value(c);
229        if (sc) set_changed();
230        do_callback();
231        return 1;
232      }
233    }
234    return Fl_Group::handle(event);
235  case FL_SHOW:
236    value(); // update visibilities and fall through
237  default:
238    return Fl_Group::handle(event);
239
240  }
241}
242
243int Fl_Tabs::push(Fl_Widget *o) {
244  if (push_ == o) return 0;
245  if (push_ && !push_->visible() || o && !o->visible())
246    redraw_tabs();
247  push_ = o;
248  return 1;
249}
250
251// The value() is the first visible child (or the last child if none
252// are visible) and this also hides any other children.
253// This allows the tabs to be deleted, moved to other groups, and
254// show()/hide() called without it screwing up.
255Fl_Widget* Fl_Tabs::value() {
256  Fl_Widget* v = 0;
257  Fl_Widget*const* a = array();
258  for (int i=children(); i--;) {
259    Fl_Widget* o = *a++;
260    if (v) o->hide();
261    else if (o->visible()) v = o;
262    else if (!i) {o->show(); v = o;}
263  }
264  return v;
265}
266
267// Setting the value hides all other children, and makes this one
268// visible, iff it is really a child:
269int Fl_Tabs::value(Fl_Widget *newvalue) {
270  Fl_Widget*const* a = array();
271  int ret = 0;
272  for (int i=children(); i--;) {
273    Fl_Widget* o = *a++;
274    if (o == newvalue) {
275      if (!o->visible()) ret = 1;
276      o->show();
277    } else {
278      o->hide();
279    }
280  }
281  return ret;
282}
283
284enum {LEFT, RIGHT, SELECTED};
285
286void Fl_Tabs::draw() {
287  Fl_Widget *v = value();
288  int H = tab_height();
289
290  if (damage() & FL_DAMAGE_ALL) { // redraw the entire thing:
291    Fl_Color c = v ? v->color() : color();
292
293    draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H), c);
294
295    if (selection_color() != c) {
296      // Draw the top 5 lines of the tab pane in the selection color so
297      // that the user knows which tab is selected...
298      if (H >= 0) fl_push_clip(x(), y() + H, w(), 5);
299      else fl_push_clip(x(), y() + h() - H - 4, w(), 5);
300
301      draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H),
302               selection_color());
303
304      fl_pop_clip();
305    }
306    if (v) draw_child(*v);
307  } else { // redraw the child
308    if (v) update_child(*v);
309  }
310  if (damage() & (FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) {
311    int p[128]; int wp[128];
312    int selected = tab_positions(p,wp);
313    int i;
314    Fl_Widget*const* a = array();
315    for (i=0; i<selected; i++)
316      draw_tab(x()+p[i], x()+p[i+1], wp[i], H, a[i], LEFT);
317    for (i=children()-1; i > selected; i--)
318      draw_tab(x()+p[i], x()+p[i+1], wp[i], H, a[i], RIGHT);
319    if (v) {
320      i = selected;
321      draw_tab(x()+p[i], x()+p[i+1], wp[i], H, a[i], SELECTED);
322    }
323  }
324}
325
326void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) {
327  int sel = (what == SELECTED);
328  int dh = Fl::box_dh(box());
329  int dy = Fl::box_dy(box());
330  char prev_draw_shortcut = fl_draw_shortcut;
331  fl_draw_shortcut = 1;
332
333  Fl_Boxtype bt = (o==push_ &&!sel) ? fl_down(box()) : box();
334
335  // compute offsets to make selected tab look bigger
336  int yofs = sel ? 0 : BORDER;
337
338  if ((x2 < x1+W) && what == RIGHT) x1 = x2 - W;
339
340  if (H >= 0) {
341    if (sel) fl_clip(x1, y(), x2 - x1, H + dh - dy);
342    else fl_clip(x1, y(), x2 - x1, H);
343
344    H += dh;
345
346    Fl_Color c = sel ? selection_color() : o->selection_color();
347
348    draw_box(bt, x1, y() + yofs, W, H + 10 - yofs, c);
349
350    // Save the previous label color
351    Fl_Color oc = o->labelcolor();
352
353    // Draw the label using the current color...
354    o->labelcolor(sel ? labelcolor() : o->labelcolor());   
355    o->draw_label(x1, y() + yofs, W, H - yofs, FL_ALIGN_CENTER);
356
357    // Restore the original label color...
358    o->labelcolor(oc);
359
360    if (Fl::focus() == this && o->visible())
361      draw_focus(box(), x1, y(), W, H);
362
363    fl_pop_clip();
364  } else {
365    H = -H;
366
367    if (sel) fl_clip(x1, y() + h() - H - dy, x2 - x1, H + dy);
368    else fl_clip(x1, y() + h() - H, x2 - x1, H);
369
370    H += dh;
371
372    Fl_Color c = sel ? selection_color() : o->selection_color();
373
374    draw_box(bt, x1, y() + h() - H - 10, W, H + 10 - yofs, c);
375
376    // Save the previous label color
377    Fl_Color oc = o->labelcolor();
378
379    // Draw the label using the current color...
380    o->labelcolor(sel ? labelcolor() : o->labelcolor());
381    o->draw_label(x1, y() + h() - H, W, H - yofs, FL_ALIGN_CENTER);
382
383    // Restore the original label color...
384    o->labelcolor(oc);
385
386    if (Fl::focus() == this && o->visible())
387      draw_focus(box(), x1, y() + h() - H, W, H);
388
389    fl_pop_clip();
390  }
391  fl_draw_shortcut = prev_draw_shortcut;
392}
393
394Fl_Tabs::Fl_Tabs(int X,int Y,int W, int H, const char *l) :
395  Fl_Group(X,Y,W,H,l)
396{
397  box(FL_THIN_UP_BOX);
398  push_ = 0;
399}
400
401//
402// End of "$Id$".
403//
Note: See TracBrowser for help on using the repository browser.