|
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_Scroll.cxx 7903 2010-11-28 21:06:39Z matt $" 00003 // 00004 // Scroll 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 #include <FL/Fl.H> 00029 #include <FL/Fl_Tiled_Image.H> 00030 #include <FL/Fl_Scroll.H> 00031 #include <FL/fl_draw.H> 00032 00034 void Fl_Scroll::clear() { 00035 // Note: the scrollbars are removed from the group before calling 00036 // Fl_Group::clear() to take advantage of the optimized widget removal 00037 // and deletion. Finally they are added to Fl_Scroll's group again. This 00038 // is MUCH faster than removing the widgets one by one (STR #2409). 00039 00040 remove(scrollbar); 00041 remove(hscrollbar); 00042 Fl_Group::clear(); 00043 add(hscrollbar); 00044 add(scrollbar); 00045 } 00046 00048 void Fl_Scroll::fix_scrollbar_order() { 00049 Fl_Widget** a = (Fl_Widget**)array(); 00050 if (a[children()-1] != &scrollbar) { 00051 int i,j; for (i = j = 0; j < children(); j++) 00052 if (a[j] != &hscrollbar && a[j] != &scrollbar) a[i++] = a[j]; 00053 a[i++] = &hscrollbar; 00054 a[i++] = &scrollbar; 00055 } 00056 } 00057 00058 // Draw widget's background and children within a specific clip region 00059 // So widget can just redraw damaged parts. 00060 // 00061 void Fl_Scroll::draw_clip(void* v,int X, int Y, int W, int H) { 00062 fl_push_clip(X,Y,W,H); 00063 Fl_Scroll* s = (Fl_Scroll*)v; 00064 // erase background as needed... 00065 switch (s->box()) { 00066 case FL_NO_BOX : 00067 case FL_UP_FRAME : 00068 case FL_DOWN_FRAME : 00069 case FL_THIN_UP_FRAME : 00070 case FL_THIN_DOWN_FRAME : 00071 case FL_ENGRAVED_FRAME : 00072 case FL_EMBOSSED_FRAME : 00073 case FL_BORDER_FRAME : 00074 case _FL_SHADOW_FRAME : 00075 case _FL_ROUNDED_FRAME : 00076 case _FL_OVAL_FRAME : 00077 case _FL_PLASTIC_UP_FRAME : 00078 case _FL_PLASTIC_DOWN_FRAME : 00079 if (s->parent() == (Fl_Group *)s->window() && Fl::scheme_bg_) { 00080 Fl::scheme_bg_->draw(X-(X%((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->w()), 00081 Y-(Y%((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->h()), 00082 W+((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->w(), 00083 H+((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->h()); 00084 break; 00085 } 00086 00087 default : 00088 fl_color(s->color()); 00089 fl_rectf(X,Y,W,H); 00090 break; 00091 } 00092 Fl_Widget*const* a = s->array(); 00093 for (int i=s->children()-2; i--;) { 00094 Fl_Widget& o = **a++; 00095 s->draw_child(o); 00096 s->draw_outside_label(o); 00097 } 00098 fl_pop_clip(); 00099 } 00100 00109 void Fl_Scroll::recalc_scrollbars(ScrollInfo &si) { 00110 00111 // inner box of widget (excluding scrollbars) 00112 si.innerbox_x = x()+Fl::box_dx(box()); 00113 si.innerbox_y = y()+Fl::box_dy(box()); 00114 si.innerbox_w = w()-Fl::box_dw(box()); 00115 si.innerbox_h = h()-Fl::box_dh(box()); 00116 00117 // accumulate a bounding box for all the children 00118 si.child_l = si.innerbox_x; 00119 si.child_r = si.innerbox_x; 00120 si.child_b = si.innerbox_y; 00121 si.child_t = si.innerbox_y; 00122 int first = 1; 00123 Fl_Widget*const* a = array(); 00124 for (int i=children()-2; i--;) { 00125 Fl_Widget* o = *a++; 00126 if ( first ) { 00127 first = 0; 00128 si.child_l = o->x(); 00129 si.child_r = o->x()+o->w(); 00130 si.child_b = o->y()+o->h(); 00131 si.child_t = o->y(); 00132 } else { 00133 if (o->x() < si.child_l) si.child_l = o->x(); 00134 if (o->y() < si.child_t) si.child_t = o->y(); 00135 if (o->x()+o->w() > si.child_r) si.child_r = o->x()+o->w(); 00136 if (o->y()+o->h() > si.child_b) si.child_b = o->y()+o->h(); 00137 } 00138 } 00139 00140 // Turn the scrollbars on and off as necessary. 00141 // See if children would fit if we had no scrollbars... 00142 { 00143 int X = si.innerbox_x; 00144 int Y = si.innerbox_y; 00145 int W = si.innerbox_w; 00146 int H = si.innerbox_h; 00147 00148 si.scrollsize = scrollbar_size_ ? scrollbar_size_ : Fl::scrollbar_size(); 00149 si.vneeded = 0; 00150 si.hneeded = 0; 00151 if (type() & VERTICAL) { 00152 if ((type() & ALWAYS_ON) || si.child_t < Y || si.child_b > Y+H) { 00153 si.vneeded = 1; 00154 W -= si.scrollsize; 00155 if (scrollbar.align() & FL_ALIGN_LEFT) X += si.scrollsize; 00156 } 00157 } 00158 if (type() & HORIZONTAL) { 00159 if ((type() & ALWAYS_ON) || si.child_l < X || si.child_r > X+W) { 00160 si.hneeded = 1; 00161 H -= si.scrollsize; 00162 if (scrollbar.align() & FL_ALIGN_TOP) Y += si.scrollsize; 00163 // recheck vertical since we added a horizontal scrollbar 00164 if (!si.vneeded && (type() & VERTICAL)) { 00165 if ((type() & ALWAYS_ON) || si.child_t < Y || si.child_b > Y+H) { 00166 si.vneeded = 1; 00167 W -= si.scrollsize; 00168 if (scrollbar.align() & FL_ALIGN_LEFT) X += si.scrollsize; 00169 } 00170 } 00171 } 00172 } 00173 si.innerchild_x = X; 00174 si.innerchild_y = Y; 00175 si.innerchild_w = W; 00176 si.innerchild_h = H; 00177 } 00178 00179 // calculate hor scrollbar position 00180 si.hscroll_x = si.innerchild_x; 00181 si.hscroll_y = (scrollbar.align() & FL_ALIGN_TOP) 00182 ? si.innerbox_y 00183 : si.innerbox_y + si.innerbox_h - si.scrollsize; 00184 si.hscroll_w = si.innerchild_w; 00185 si.hscroll_h = si.scrollsize; 00186 00187 // calculate ver scrollbar position 00188 si.vscroll_x = (scrollbar.align() & FL_ALIGN_LEFT) 00189 ? si.innerbox_x 00190 : si.innerbox_x + si.innerbox_w - si.scrollsize; 00191 si.vscroll_y = si.innerchild_y; 00192 si.vscroll_w = si.scrollsize; 00193 si.vscroll_h = si.innerchild_h; 00194 00195 // calculate h/v scrollbar values (pos/size/first/total) 00196 si.hpos = si.innerchild_x - si.child_l; 00197 si.hsize = si.innerchild_w; 00198 si.hfirst = 0; 00199 si.htotal = si.child_r - si.child_l; 00200 if ( si.hpos < 0 ) { si.htotal += (-si.hpos); si.hfirst = si.hpos; } 00201 00202 si.vpos = si.innerchild_y - si.child_t; 00203 si.vsize = si.innerchild_h; 00204 si.vfirst = 0; 00205 si.vtotal = si.child_b - si.child_t; 00206 if ( si.vpos < 0 ) { si.vtotal += (-si.vpos); si.vfirst = si.vpos; } 00207 00208 // printf("DEBUG --- ScrollInfo ---\n"); 00209 // printf("DEBUG scrollsize: %d\n", si.scrollsize); 00210 // printf("DEBUG hneeded, vneeded: %d %d\n", si.hneeded, si.vneeded); 00211 // printf("DEBUG innerbox xywh: %d %d %d %d\n", si.innerbox_x, si.innerbox_y, si.innerbox_w, si.innerbox_h); 00212 // printf("DEBUG innerchild xywh: %d %d %d %d\n", si.innerchild_x, si.innerchild_y, si.innerchild_w, si.innerchild_h); 00213 // printf("DEBUG child lrbt: %d %d %d %d\n", si.child_l, si.child_r, si.child_b, si.child_t); 00214 // printf("DEBUG hscroll xywh: %d %d %d %d\n", si.hscroll_x, si.hscroll_y, si.hscroll_w, si.hscroll_h); 00215 // printf("DEBUG vscroll xywh: %d %d %d %d\n", si.vscroll_x, si.vscroll_y, si.vscroll_w, si.vscroll_h); 00216 // printf("DEBUG horz scroll vals: %d %d %d %d\n", si.hpos, si.hsize, si.hfirst, si.htotal); 00217 // printf("DEBUG vert scroll vals: %d %d %d %d\n", si.vpos, si.vsize, si.vfirst, si.vtotal); 00218 // printf("DEBUG \n"); 00219 } 00220 00231 void Fl_Scroll::bbox(int& X, int& Y, int& W, int& H) { 00232 X = x()+Fl::box_dx(box()); 00233 Y = y()+Fl::box_dy(box()); 00234 W = w()-Fl::box_dw(box()); 00235 H = h()-Fl::box_dh(box()); 00236 if (scrollbar.visible()) { 00237 W -= scrollbar.w(); 00238 if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w(); 00239 } 00240 if (hscrollbar.visible()) { 00241 H -= hscrollbar.h(); 00242 if (scrollbar.align() & FL_ALIGN_TOP) Y += hscrollbar.h(); 00243 } 00244 } 00245 00246 void Fl_Scroll::draw() { 00247 fix_scrollbar_order(); 00248 int X,Y,W,H; bbox(X,Y,W,H); 00249 00250 uchar d = damage(); 00251 00252 if (d & FL_DAMAGE_ALL) { // full redraw 00253 draw_box(box(),x(),y(),w(),h(),color()); 00254 draw_clip(this, X, Y, W, H); 00255 } else { 00256 if (d & FL_DAMAGE_SCROLL) { 00257 // scroll the contents: 00258 fl_scroll(X, Y, W, H, oldx-xposition_, oldy-yposition_, draw_clip, this); 00259 00260 // Erase the background as needed... 00261 Fl_Widget*const* a = array(); 00262 int L, R, T, B; 00263 L = 999999; 00264 R = 0; 00265 T = 999999; 00266 B = 0; 00267 for (int i=children()-2; i--; a++) { 00268 if ((*a)->x() < L) L = (*a)->x(); 00269 if (((*a)->x() + (*a)->w()) > R) R = (*a)->x() + (*a)->w(); 00270 if ((*a)->y() < T) T = (*a)->y(); 00271 if (((*a)->y() + (*a)->h()) > B) B = (*a)->y() + (*a)->h(); 00272 } 00273 if (L > X) draw_clip(this, X, Y, L - X, H); 00274 if (R < (X + W)) draw_clip(this, R, Y, X + W - R, H); 00275 if (T > Y) draw_clip(this, X, Y, W, T - Y); 00276 if (B < (Y + H)) draw_clip(this, X, B, W, Y + H - B); 00277 } 00278 if (d & FL_DAMAGE_CHILD) { // draw damaged children 00279 fl_push_clip(X, Y, W, H); 00280 Fl_Widget*const* a = array(); 00281 for (int i=children()-2; i--;) update_child(**a++); 00282 fl_pop_clip(); 00283 } 00284 } 00285 00286 // Calculate where scrollbars should go, and draw them 00287 { 00288 ScrollInfo si; 00289 recalc_scrollbars(si); 00290 00291 // Now that we know what's needed, make it so. 00292 if (si.vneeded && !scrollbar.visible()) { 00293 scrollbar.set_visible(); 00294 d = FL_DAMAGE_ALL; 00295 } 00296 else if (!si.vneeded && scrollbar.visible()) { 00297 scrollbar.clear_visible(); 00298 draw_clip(this, si.vscroll_x, si.vscroll_y, si.vscroll_w, si.vscroll_h); 00299 d = FL_DAMAGE_ALL; 00300 } 00301 if (si.hneeded && !hscrollbar.visible()) { 00302 hscrollbar.set_visible(); 00303 d = FL_DAMAGE_ALL; 00304 } 00305 else if (!si.hneeded && hscrollbar.visible()) { 00306 hscrollbar.clear_visible(); 00307 draw_clip(this, si.hscroll_x, si.hscroll_y, si.hscroll_w, si.hscroll_h); 00308 d = FL_DAMAGE_ALL; 00309 } 00310 else if ( hscrollbar.h() != si.scrollsize || scrollbar.w() != si.scrollsize ) { 00311 // scrollsize changed 00312 d = FL_DAMAGE_ALL; 00313 } 00314 00315 scrollbar.resize(si.vscroll_x, si.vscroll_y, si.vscroll_w, si.vscroll_h); 00316 oldy = yposition_ = si.vpos; // si.innerchild_y - si.child_t; 00317 scrollbar.value(si.vpos, si.vsize, si.vfirst, si.vtotal); 00318 00319 hscrollbar.resize(si.hscroll_x, si.hscroll_y, si.hscroll_w, si.hscroll_h); 00320 oldx = xposition_ = si.hpos; // si.innerchild_x - si.child_l; 00321 hscrollbar.value(si.hpos, si.hsize, si.hfirst, si.htotal); 00322 } 00323 00324 // draw the scrollbars: 00325 if (d & FL_DAMAGE_ALL) { 00326 draw_child(scrollbar); 00327 draw_child(hscrollbar); 00328 if (scrollbar.visible() && hscrollbar.visible()) { 00329 // fill in the little box in the corner 00330 fl_color(color()); 00331 fl_rectf(scrollbar.x(), hscrollbar.y(), scrollbar.w(), hscrollbar.h()); 00332 } 00333 } else { 00334 update_child(scrollbar); 00335 update_child(hscrollbar); 00336 } 00337 } 00338 00339 void Fl_Scroll::resize(int X, int Y, int W, int H) { 00340 int dx = X-x(), dy = Y-y(); 00341 int dw = W-w(), dh = H-h(); 00342 Fl_Widget::resize(X,Y,W,H); // resize _before_ moving children around 00343 fix_scrollbar_order(); 00344 // move all the children: 00345 Fl_Widget*const* a = array(); 00346 for (int i=children()-2; i--;) { 00347 Fl_Widget* o = *a++; 00348 o->position(o->x()+dx, o->y()+dy); 00349 } 00350 if (dw==0 && dh==0) { 00351 char pad = ( scrollbar.visible() && hscrollbar.visible() ); 00352 char al = ( (scrollbar.align() & FL_ALIGN_LEFT) != 0 ); 00353 char at = ( (scrollbar.align() & FL_ALIGN_TOP) !=0 ); 00354 scrollbar.position(al?X:X+W-scrollbar.w(), (at&&pad)?Y+hscrollbar.h():Y); 00355 hscrollbar.position((al&&pad)?X+scrollbar.w():X, at?Y:Y+H-hscrollbar.h()); 00356 } else { 00357 // FIXME recalculation of scrollbars needs to be moved out fo "draw()" (STR #1895) 00358 redraw(); // need full recalculation of scrollbars 00359 } 00360 } 00361 00363 void Fl_Scroll::scroll_to(int X, int Y) { 00364 int dx = xposition_-X; 00365 int dy = yposition_-Y; 00366 if (!dx && !dy) return; 00367 xposition_ = X; 00368 yposition_ = Y; 00369 Fl_Widget*const* a = array(); 00370 for (int i=children(); i--;) { 00371 Fl_Widget* o = *a++; 00372 if (o == &hscrollbar || o == &scrollbar) continue; 00373 o->position(o->x()+dx, o->y()+dy); 00374 } 00375 if (parent() == (Fl_Group *)window() && Fl::scheme_bg_) damage(FL_DAMAGE_ALL); 00376 else damage(FL_DAMAGE_SCROLL); 00377 } 00378 00379 void Fl_Scroll::hscrollbar_cb(Fl_Widget* o, void*) { 00380 Fl_Scroll* s = (Fl_Scroll*)(o->parent()); 00381 s->scroll_to(int(((Fl_Scrollbar*)o)->value()), s->yposition()); 00382 } 00383 00384 void Fl_Scroll::scrollbar_cb(Fl_Widget* o, void*) { 00385 Fl_Scroll* s = (Fl_Scroll*)(o->parent()); 00386 s->scroll_to(s->xposition(), int(((Fl_Scrollbar*)o)->value())); 00387 } 00398 Fl_Scroll::Fl_Scroll(int X,int Y,int W,int H,const char* L) 00399 : Fl_Group(X,Y,W,H,L), 00400 scrollbar(X+W-Fl::scrollbar_size(),Y, 00401 Fl::scrollbar_size(),H-Fl::scrollbar_size()), 00402 hscrollbar(X,Y+H-Fl::scrollbar_size(), 00403 W-Fl::scrollbar_size(),Fl::scrollbar_size()) { 00404 type(BOTH); 00405 xposition_ = oldx = 0; 00406 yposition_ = oldy = 0; 00407 scrollbar_size_ = 0; 00408 hscrollbar.type(FL_HORIZONTAL); 00409 hscrollbar.callback(hscrollbar_cb); 00410 scrollbar.callback(scrollbar_cb); 00411 } 00412 00413 int Fl_Scroll::handle(int event) { 00414 fix_scrollbar_order(); 00415 return Fl_Group::handle(event); 00416 } 00417 00418 // 00419 // End of "$Id: Fl_Scroll.cxx 7903 2010-11-28 21:06:39Z matt $". 00420 //