|
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) ![]() |
00001 // 00002 // "$Id: Fl_Tabs.cxx 8101 2010-12-22 13:06:03Z AlbrechtS $" 00003 // 00004 // Tab widget 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 00029 // This is the "file card tabs" interface to allow you to put lots and lots 00030 // of buttons and switches in a panel, as popularized by many toolkits. 00031 00032 // Each child widget is a card, and its label() is printed on the card tab. 00033 // Clicking the tab makes that card visible. 00034 00035 #include <stdio.h> 00036 #include <FL/Fl.H> 00037 #include <FL/Fl_Tabs.H> 00038 #include <FL/fl_draw.H> 00039 #include <FL/Fl_Tooltip.H> 00040 00041 #define BORDER 2 00042 #define EXTRASPACE 10 00043 #define SELECTION_BORDER 5 00044 00045 // Return the left edges of each tab (plus a fake left edge for a tab 00046 // past the right-hand one). These positions are actually of the left 00047 // edge of the slope. They are either separated by the correct distance 00048 // or by EXTRASPACE or by zero. 00049 // These positions are updated in the private arrays tab_pos[] and 00050 // tab_width[], resp.. If needed, these arrays are (re)allocated. 00051 // Return value is the index of the selected item. 00052 00053 int Fl_Tabs::tab_positions() { 00054 int nc = children(); 00055 if (nc != tab_count) { 00056 clear_tab_positions(); 00057 if (nc) { 00058 tab_pos = (int*)malloc((nc+1)*sizeof(int)); 00059 tab_width = (int*)malloc((nc+1)*sizeof(int)); 00060 } 00061 tab_count = nc; 00062 } 00063 if (nc == 0) return 0; 00064 int selected = 0; 00065 Fl_Widget*const* a = array(); 00066 int i; 00067 char prev_draw_shortcut = fl_draw_shortcut; 00068 fl_draw_shortcut = 1; 00069 00070 tab_pos[0] = Fl::box_dx(box()); 00071 for (i=0; i<nc; i++) { 00072 Fl_Widget* o = *a++; 00073 if (o->visible()) selected = i; 00074 00075 int wt = 0; int ht = 0; 00076 o->measure_label(wt,ht); 00077 00078 tab_width[i] = wt + EXTRASPACE; 00079 tab_pos[i+1] = tab_pos[i] + tab_width[i] + BORDER; 00080 } 00081 fl_draw_shortcut = prev_draw_shortcut; 00082 00083 int r = w(); 00084 if (tab_pos[i] <= r) return selected; 00085 // uh oh, they are too big: 00086 // pack them against right edge: 00087 tab_pos[i] = r; 00088 for (i = nc; i--;) { 00089 int l = r-tab_width[i]; 00090 if (tab_pos[i+1] < l) l = tab_pos[i+1]; 00091 if (tab_pos[i] <= l) break; 00092 tab_pos[i] = l; 00093 r -= EXTRASPACE; 00094 } 00095 // pack them against left edge and truncate width if they still don't fit: 00096 for (i = 0; i<nc; i++) { 00097 if (tab_pos[i] >= i*EXTRASPACE) break; 00098 tab_pos[i] = i*EXTRASPACE; 00099 int W = w()-1-EXTRASPACE*(children()-i) - tab_pos[i]; 00100 if (tab_width[i] > W) tab_width[i] = W; 00101 } 00102 // adjust edges according to visiblity: 00103 for (i = nc; i > selected; i--) { 00104 tab_pos[i] = tab_pos[i-1] + tab_width[i-1]; 00105 } 00106 return selected; 00107 } 00108 00109 // Returns space (height) in pixels needed for tabs. Negative to put them on the bottom. 00110 // Returns full height, if children() = 0. 00111 int Fl_Tabs::tab_height() { 00112 if (children() == 0) return h(); 00113 int H = h(); 00114 int H2 = y(); 00115 Fl_Widget*const* a = array(); 00116 for (int i=children(); i--;) { 00117 Fl_Widget* o = *a++; 00118 if (o->y() < y()+H) H = o->y()-y(); 00119 if (o->y()+o->h() > H2) H2 = o->y()+o->h(); 00120 } 00121 H2 = y()+h()-H2; 00122 if (H2 > H) return (H2 <= 0) ? 0 : -H2; 00123 else return (H <= 0) ? 0 : H; 00124 } 00125 00126 // This is used for event handling (clicks) and by fluid to pick tabs. 00127 // Returns 0, if children() = 0, or if the event is outside of the tabs area. 00128 Fl_Widget *Fl_Tabs::which(int event_x, int event_y) { 00129 if (children() == 0) return 0; 00130 int H = tab_height(); 00131 if (H < 0) { 00132 if (event_y > y()+h() || event_y < y()+h()+H) return 0; 00133 } else { 00134 if (event_y > y()+H || event_y < y()) return 0; 00135 } 00136 if (event_x < x()) return 0; 00137 Fl_Widget *ret = 0L; 00138 int nc = children(); 00139 tab_positions(); 00140 for (int i=0; i<nc; i++) { 00141 if (event_x < x()+tab_pos[i+1]) { 00142 ret = child(i); 00143 break; 00144 } 00145 } 00146 return ret; 00147 } 00148 00149 void Fl_Tabs::redraw_tabs() 00150 { 00151 int H = tab_height(); 00152 if (H >= 0) { 00153 H += Fl::box_dy(box()); 00154 damage(FL_DAMAGE_SCROLL, x(), y(), w(), H); 00155 } else { 00156 H = Fl::box_dy(box()) - H; 00157 damage(FL_DAMAGE_SCROLL, x(), y() + h() - H, w(), H); 00158 } 00159 } 00160 00161 int Fl_Tabs::handle(int event) { 00162 00163 Fl_Widget *o; 00164 int i; 00165 00166 switch (event) { 00167 00168 case FL_PUSH: { 00169 int H = tab_height(); 00170 if (H >= 0) { 00171 if (Fl::event_y() > y()+H) return Fl_Group::handle(event); 00172 } else { 00173 if (Fl::event_y() < y()+h()+H) return Fl_Group::handle(event); 00174 }} 00175 /* FALLTHROUGH */ 00176 case FL_DRAG: 00177 case FL_RELEASE: 00178 o = which(Fl::event_x(), Fl::event_y()); 00179 if (event == FL_RELEASE) { 00180 push(0); 00181 if (o && Fl::visible_focus() && Fl::focus()!=this) { 00182 Fl::focus(this); 00183 redraw_tabs(); 00184 } 00185 if (o && value(o)) { 00186 Fl_Widget_Tracker wp(o); 00187 set_changed(); 00188 do_callback(); 00189 if (wp.deleted()) return 1; 00190 } 00191 Fl_Tooltip::current(o); 00192 } else { 00193 push(o); 00194 } 00195 return 1; 00196 case FL_MOVE: { 00197 int ret = Fl_Group::handle(event); 00198 Fl_Widget *o = Fl_Tooltip::current(), *n = o; 00199 int H = tab_height(); 00200 if ( (H>=0) && (Fl::event_y()>y()+H) ) 00201 return ret; 00202 else if ( (H<0) && (Fl::event_y() < y()+h()+H) ) 00203 return ret; 00204 else { 00205 n = which(Fl::event_x(), Fl::event_y()); 00206 if (!n) n = this; 00207 } 00208 if (n!=o) 00209 Fl_Tooltip::enter(n); 00210 return ret; } 00211 case FL_FOCUS: 00212 case FL_UNFOCUS: 00213 if (!Fl::visible_focus()) return Fl_Group::handle(event); 00214 if (Fl::event() == FL_RELEASE || 00215 Fl::event() == FL_SHORTCUT || 00216 Fl::event() == FL_KEYBOARD || 00217 Fl::event() == FL_FOCUS || 00218 Fl::event() == FL_UNFOCUS) { 00219 redraw_tabs(); 00220 if (Fl::event() == FL_FOCUS || Fl::event() == FL_UNFOCUS) return 0; 00221 else return 1; 00222 } else return Fl_Group::handle(event); 00223 case FL_KEYBOARD: 00224 switch (Fl::event_key()) { 00225 case FL_Left: 00226 if (child(0)->visible()) return 0; 00227 for (i = 1; i < children(); i ++) 00228 if (child(i)->visible()) break; 00229 value(child(i - 1)); 00230 set_changed(); 00231 do_callback(); 00232 return 1; 00233 case FL_Right: 00234 if (child(children() - 1)->visible()) return 0; 00235 for (i = 0; i < children(); i ++) 00236 if (child(i)->visible()) break; 00237 value(child(i + 1)); 00238 set_changed(); 00239 do_callback(); 00240 return 1; 00241 case FL_Down: 00242 redraw(); 00243 return Fl_Group::handle(FL_FOCUS); 00244 default: 00245 break; 00246 } 00247 return Fl_Group::handle(event); 00248 case FL_SHORTCUT: 00249 for (i = 0; i < children(); ++i) { 00250 Fl_Widget *c = child(i); 00251 if (c->test_shortcut(c->label())) { 00252 char sc = !c->visible(); 00253 value(c); 00254 if (sc) set_changed(); 00255 do_callback(); 00256 return 1; 00257 } 00258 } 00259 return Fl_Group::handle(event); 00260 case FL_SHOW: 00261 value(); // update visibilities and fall through 00262 default: 00263 return Fl_Group::handle(event); 00264 00265 } 00266 } 00267 00268 int Fl_Tabs::push(Fl_Widget *o) { 00269 if (push_ == o) return 0; 00270 if ( (push_ && !push_->visible()) || (o && !o->visible()) ) 00271 redraw_tabs(); 00272 push_ = o; 00273 return 1; 00274 } 00275 00283 Fl_Widget* Fl_Tabs::value() { 00284 Fl_Widget* v = 0; 00285 Fl_Widget*const* a = array(); 00286 for (int i=children(); i--;) { 00287 Fl_Widget* o = *a++; 00288 if (v) o->hide(); 00289 else if (o->visible()) v = o; 00290 else if (!i) {o->show(); v = o;} 00291 } 00292 return v; 00293 } 00294 00300 int Fl_Tabs::value(Fl_Widget *newvalue) { 00301 Fl_Widget*const* a = array(); 00302 int ret = 0; 00303 for (int i=children(); i--;) { 00304 Fl_Widget* o = *a++; 00305 if (o == newvalue) { 00306 if (!o->visible()) ret = 1; 00307 o->show(); 00308 } else { 00309 o->hide(); 00310 } 00311 } 00312 return ret; 00313 } 00314 00315 enum {LEFT, RIGHT, SELECTED}; 00316 00317 void Fl_Tabs::draw() { 00318 Fl_Widget *v = value(); 00319 int H = tab_height(); 00320 00321 if (damage() & FL_DAMAGE_ALL) { // redraw the entire thing: 00322 Fl_Color c = v ? v->color() : color(); 00323 00324 draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H), c); 00325 00326 if (selection_color() != c) { 00327 // Draw the top or bottom SELECTION_BORDER lines of the tab pane in the 00328 // selection color so that the user knows which tab is selected... 00329 int clip_y = (H >= 0) ? y() + H : y() + h() + H - SELECTION_BORDER; 00330 fl_push_clip(x(), clip_y, w(), SELECTION_BORDER); 00331 draw_box(box(), x(), clip_y, w(), SELECTION_BORDER, selection_color()); 00332 fl_pop_clip(); 00333 } 00334 if (v) draw_child(*v); 00335 } else { // redraw the child 00336 if (v) update_child(*v); 00337 } 00338 if (damage() & (FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) { 00339 int nc = children(); 00340 int selected = tab_positions(); 00341 int i; 00342 Fl_Widget*const* a = array(); 00343 for (i=0; i<selected; i++) 00344 draw_tab(x()+tab_pos[i], x()+tab_pos[i+1], 00345 tab_width[i], H, a[i], LEFT); 00346 for (i=nc-1; i > selected; i--) 00347 draw_tab(x()+tab_pos[i], x()+tab_pos[i+1], 00348 tab_width[i], H, a[i], RIGHT); 00349 if (v) { 00350 i = selected; 00351 draw_tab(x()+tab_pos[i], x()+tab_pos[i+1], 00352 tab_width[i], H, a[i], SELECTED); 00353 } 00354 } 00355 } 00356 00357 void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) { 00358 int sel = (what == SELECTED); 00359 int dh = Fl::box_dh(box()); 00360 int dy = Fl::box_dy(box()); 00361 char prev_draw_shortcut = fl_draw_shortcut; 00362 fl_draw_shortcut = 1; 00363 00364 Fl_Boxtype bt = (o==push_ &&!sel) ? fl_down(box()) : box(); 00365 00366 // compute offsets to make selected tab look bigger 00367 int yofs = sel ? 0 : BORDER; 00368 00369 if ((x2 < x1+W) && what == RIGHT) x1 = x2 - W; 00370 00371 if (H >= 0) { 00372 if (sel) fl_push_clip(x1, y(), x2 - x1, H + dh - dy); 00373 else fl_push_clip(x1, y(), x2 - x1, H); 00374 00375 H += dh; 00376 00377 Fl_Color c = sel ? selection_color() : o->selection_color(); 00378 00379 draw_box(bt, x1, y() + yofs, W, H + 10 - yofs, c); 00380 00381 // Save the previous label color 00382 Fl_Color oc = o->labelcolor(); 00383 00384 // Draw the label using the current color... 00385 o->labelcolor(sel ? labelcolor() : o->labelcolor()); 00386 o->draw_label(x1, y() + yofs, W, H - yofs, FL_ALIGN_CENTER); 00387 00388 // Restore the original label color... 00389 o->labelcolor(oc); 00390 00391 if (Fl::focus() == this && o->visible()) 00392 draw_focus(box(), x1, y(), W, H); 00393 00394 fl_pop_clip(); 00395 } else { 00396 H = -H; 00397 00398 if (sel) fl_push_clip(x1, y() + h() - H - dy, x2 - x1, H + dy); 00399 else fl_push_clip(x1, y() + h() - H, x2 - x1, H); 00400 00401 H += dh; 00402 00403 Fl_Color c = sel ? selection_color() : o->selection_color(); 00404 00405 draw_box(bt, x1, y() + h() - H - 10, W, H + 10 - yofs, c); 00406 00407 // Save the previous label color 00408 Fl_Color oc = o->labelcolor(); 00409 00410 // Draw the label using the current color... 00411 o->labelcolor(sel ? labelcolor() : o->labelcolor()); 00412 o->draw_label(x1, y() + h() - H, W, H - yofs, FL_ALIGN_CENTER); 00413 00414 // Restore the original label color... 00415 o->labelcolor(oc); 00416 00417 if (Fl::focus() == this && o->visible()) 00418 draw_focus(box(), x1, y() + h() - H, W, H); 00419 00420 fl_pop_clip(); 00421 } 00422 fl_draw_shortcut = prev_draw_shortcut; 00423 } 00424 00446 Fl_Tabs::Fl_Tabs(int X,int Y,int W, int H, const char *l) : 00447 Fl_Group(X,Y,W,H,l) 00448 { 00449 box(FL_THIN_UP_BOX); 00450 push_ = 0; 00451 tab_pos = 0; 00452 tab_width = 0; 00453 tab_count = 0; 00454 } 00455 00456 Fl_Tabs::~Fl_Tabs() { 00457 clear_tab_positions(); 00458 } 00459 00481 void Fl_Tabs::client_area(int &rx, int &ry, int &rw, int &rh, int tabh) { 00482 00483 if (children()) { // use existing values 00484 00485 rx = child(0)->x(); 00486 ry = child(0)->y(); 00487 rw = child(0)->w(); 00488 rh = child(0)->h(); 00489 00490 } else { // calculate values 00491 00492 int y_offset; 00493 int label_height = fl_height(labelfont(), labelsize()) + BORDER*2; 00494 00495 if (tabh == 0) // use default (at top) 00496 y_offset = label_height; 00497 else if (tabh == -1) // use default (at bottom) 00498 y_offset = -label_height; 00499 else 00500 y_offset = tabh; // user given value 00501 00502 rx = x(); 00503 rw = w(); 00504 00505 if (y_offset >= 0) { // labels at top 00506 ry = y() + y_offset; 00507 rh = h() - y_offset; 00508 } else { // labels at bottom 00509 ry = y(); 00510 rh = h() + y_offset; 00511 } 00512 } 00513 } 00514 00515 void Fl_Tabs::clear_tab_positions() { 00516 if (tab_pos) { 00517 free(tab_pos); 00518 tab_pos = 0; 00519 } 00520 if (tab_width){ 00521 free(tab_width); 00522 tab_width = 0; 00523 } 00524 } 00525 00526 // 00527 // End of "$Id: Fl_Tabs.cxx 8101 2010-12-22 13:06:03Z AlbrechtS $". 00528 //