?? fl_browser_.cxx
字號:
//// "$Id: Fl_Browser_.cxx,v 1.1.1.1 2003/08/07 21:18:39 jasonk Exp $"//// Base Browser widget class for the Fast Light Tool Kit (FLTK).//// Copyright 1998-1999 by Bill Spitzak and others.//// 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.//// Please report all bugs and problems to "fltk-bugs@easysw.com".//#include <FL/Fl.H>#include <FL/Fl_Widget.H>#include <FL/Fl_Browser_.H>#include <FL/fl_draw.H>// This is the base class for browsers. To be useful it must be// subclassed and several virtual functions defined. The// Forms-compatable browser and the file chooser's browser are// subclassed off of this.// Yes, I know this should be a template...// This has been designed so that the subclass has complete control// over the storage of the data, although because next() and prev()// functions are used to index, it works best as a linked list or as a// large block of characters in which the line breaks must be searched// for.// A great deal of work has been done so that the "height" of a data// object does not need to be determined until it is drawn. This was// done for the file chooser, because the height requires doing stat()// to see if the file is a directory, which can be annoyingly slow// over the network./* redraw bits: 1 = redraw children (the scrollbar) 2 = redraw one or two items 4 = redraw all items*/static void scrollbar_callback(Fl_Widget* s, void*) { ((Fl_Browser_*)(s->parent()))->position(int(((Fl_Scrollbar*)s)->value()));}static void hscrollbar_callback(Fl_Widget* s, void*) { ((Fl_Browser_*)(s->parent()))->hposition(int(((Fl_Scrollbar*)s)->value()));}int Fl_Browser_::scrollbar_width_ = 17;// return where to draw the actual box:void Fl_Browser_::bbox(int& X, int& Y, int& W, int& H) const { Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; X = x()+Fl::box_dx(b); Y = y()+Fl::box_dy(b); W = w()-Fl::box_dw(b); H = h()-Fl::box_dh(b); if (scrollbar.visible()) { W -= scrollbar_width_; if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar_width_; } if (W < 0) W = 0; if (hscrollbar.visible()) { H -= scrollbar_width_; if (scrollbar.align() & FL_ALIGN_TOP) Y += scrollbar_width_; } if (H < 0) H = 0;}int Fl_Browser_::leftedge() const { int X, Y, W, H; bbox(X, Y, W, H); return X;}// the scrollbars are resized & placed by draw(), since each one's size// depends on whether the other is visible or not. This skips over// Fl_Group::resize since it moves the scrollbars uselessly.void Fl_Browser_::resize(int X, int Y, int W, int H) { Fl_Widget::resize(X, Y, W, H);}// Cause minimal update to redraw the given item:void Fl_Browser_::redraw_line(void* l) { if (!redraw1 || redraw1 == l) {redraw1 = l; damage(FL_DAMAGE_EXPOSE);} else if (!redraw2 || redraw2 == l) {redraw2 = l; damage(FL_DAMAGE_EXPOSE);} else damage(FL_DAMAGE_SCROLL);}// Figure out top() based on position():void Fl_Browser_::update_top() { if (!top_) top_ = item_first(); if (position_ != real_position_) { void* l; int ly; int y = position_; // start from either head or current position, whichever is closer: if (!top_ || y <= (real_position_/2)) { l = item_first(); ly = 0; } else { l = top_; ly = real_position_-offset_; } if (!l) { top_ = 0; offset_ = 0; real_position_ = 0; } else { int h = item_quick_height(l); // step through list until we find line containing this point: while (ly > y) { void* l1 = item_prev(l); if (!l1) {ly = 0; break;} // hit the top l = l1; h = item_quick_height(l); ly -= h; } while ((ly+h) <= y) { void* l1 = item_next(l); if (!l1) {y = ly+h-1; break;} l = l1; ly += h; h = item_quick_height(l); } // top item must *really* be visible, use slow height: for (;;) { h = item_height(l); if ((ly+h) > y) break; // it is big enough to see // go up to top of previous item: void* l1 = item_prev(l); if (!l1) {ly = y = 0; break;} // hit the top l = l1; y = position_ = ly = ly-item_quick_height(l); } // use it: top_ = l; offset_ = y-ly; real_position_ = y; } damage(FL_DAMAGE_SCROLL); }}// Change position(), top() will update when update_top() is called// (probably by draw() or handle()):void Fl_Browser_::position(int y) { if (y < 0) y = 0; if (y == position_) return; position_ = y; if (y != real_position_) redraw_lines();}void Fl_Browser_::hposition(int x) { if (x < 0) x = 0; if (x == hposition_) return; hposition_ = x; if (x != real_hposition_) redraw_lines();}// Tell whether item is currently displayed:int Fl_Browser_::displayed(void* x) const { int X, Y, W, H; bbox(X, Y, W, H); int yy = H+offset_; for (void* l = top_; l && yy > 0; l = item_next(l)) { if (l == x) return 1; yy -= item_height(l); } return 0;}// Insure this item is displayed:// Messy because we have no idea if it is before top or after bottom:void Fl_Browser_::display(void* x) { update_top(); if (x == item_first()) {position(0); return;} int X, Y, W, H; bbox(X, Y, W, H); void* l = top_; Y = -offset_; // see if it is at the top or just above it: if (l == x) {position(real_position_+Y); return;} // scroll up a bit void* lp = item_prev(l); if (lp == x) {position(real_position_+Y-item_quick_height(lp)); return;} // search forward for it: for (; l; l = item_next(l)) { int h1 = item_quick_height(l); if (l == x) { if (Y <= H) { // it is visible or right at bottom Y = Y+h1-H; // find where bottom edge is if (Y > 0) position(real_position_+Y); // scroll down a bit } else { position(real_position_+Y-(H-h1)/2); // center it } return; } Y += h1; } // search backward for it, if found center it: l = lp; Y = -offset_; for (; l; l = item_prev(l)) { int h1 = item_quick_height(l); Y -= h1; if (l == x) { if ((Y + h1) >= 0) position(real_position_+Y); else position(real_position_+Y-(H-h1)/2); return; } }}// redraw, has side effect of updating top and setting scrollbar:void Fl_Browser_::draw() { int drawsquare = 0; if (damage() & FL_DAMAGE_ALL) { // redraw the box if full redraw Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; draw_box(b, x(), y(), w(), h(), color()); drawsquare = 1; } update_top(); int full_width_ = full_width(); int full_height_ = full_height(); int X, Y, W, H; bbox(X, Y, W, H); int dont_repeat = 0;J1: // see if scrollbar needs to be switched on/off: if ((has_scrollbar_ & VERTICAL) && ( (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) { if (!scrollbar.visible()) { scrollbar.set_visible(); drawsquare = 1; bbox(X, Y, W, H); } } else { top_ = item_first(); real_position_ = offset_ = 0; if (scrollbar.visible()) { scrollbar.clear_visible(); clear_damage(damage()|FL_DAMAGE_SCROLL); } } if ((has_scrollbar_ & HORIZONTAL) && ( (has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_ > W)) { if (!hscrollbar.visible()) { hscrollbar.set_visible(); drawsquare = 1; bbox(X, Y, W, H); } } else { real_hposition_ = 0; if (hscrollbar.visible()) { hscrollbar.clear_visible(); clear_damage(damage()|FL_DAMAGE_SCROLL); } } // Check the vertical scrollbar again, just in case it needs to be drawn // because the horizontal one is drawn. There should be a cleaner way // to do this besides copying the same code... if ((has_scrollbar_ & VERTICAL) && ( (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) { if (!scrollbar.visible()) { scrollbar.set_visible(); drawsquare = 1; bbox(X, Y, W, H); } } else { top_ = item_first(); real_position_ = offset_ = 0; if (scrollbar.visible()) { scrollbar.clear_visible(); clear_damage(damage()|FL_DAMAGE_SCROLL); } } bbox(X, Y, W, H); fl_clip(X, Y, W, H); // for each line, draw it if full redraw or scrolled. Erase background // if not a full redraw or if it is selected: void* l = top(); int yy = -offset_; for (; l && yy < H; l = item_next(l)) { int hh = item_height(l); if (hh <= 0) continue; if ((damage()&(FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) || l == redraw1 || l == redraw2) { if (item_selected(l)) { fl_color(active_r() ? selection_color() : inactive(selection_color())); fl_rectf(X, yy+Y, W, hh); } else if (!(damage()&FL_DAMAGE_ALL)) { fl_color(active_r() ? color() : inactive(color())); fl_rectf(X, yy+Y, W, hh); } if (type() == FL_MULTI_BROWSER && l == selection_) { fl_color(active_r() ? textcolor() : inactive(textcolor())); fl_rect(X+1, yy+Y, W-2, hh); } item_draw(l, X-hposition_, yy+Y, W+hposition_, hh); int w = item_width(l); if (w > max_width) {max_width = w; max_width_item = l;} } yy += hh; } // erase the area below last line: if (!(damage()&FL_DAMAGE_ALL) && yy < H) { fl_color(active_r() ? color() : inactive(color())); fl_rectf(X, yy+Y, W, H-yy); } fl_pop_clip(); redraw1 = redraw2 = 0; if (!dont_repeat) { dont_repeat = 1; // see if changes to full_height caused by calls to slow_height // caused scrollbar state to change, in which case we have to redraw: full_height_ = full_height(); full_width_ = full_width(); if ((has_scrollbar_ & VERTICAL) && ((has_scrollbar_ & ALWAYS_ON) || position_ || full_height_>H)) { if (!scrollbar.visible()) goto J1; } else { if (scrollbar.visible()) goto J1; } if ((has_scrollbar_ & HORIZONTAL) &&
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -