MOOS 0.2375
|
00001 // ====================================================================== 00002 // File: Flv_List.cxx - Flv_List implementation 00003 // Program: Flv_List - FLTK List Widget 00004 // Version: 0.1.0 00005 // Started: 11/21/99 00006 // 00007 // Copyright (C) 1999 Laurence Charlton 00008 // 00009 // Description: 00010 // Flv_List implements a scrollable list. No data is stored 00011 // in the widget. Supports headers/footers, natively supports a single 00012 // row height per list. Row grids can be turned on and off. Supports 00013 // no scroll bars as well as horizontal/vertical automatic or always 00014 // on scroll bars. 00015 // Uses absolute row references. 00016 // 00017 // row -1 is defined as the row header 00018 // row -2 is defined as the row footer 00019 // 00020 // This library is free software; you can redistribute it and/or 00021 // modify it under the terms of the GNU Library General Public 00022 // License as published by the Free Software Foundation; either 00023 // version 2 of the License, or (at your option) any later version. 00024 // 00025 // This library is distributed in the hope that it will be useful, 00026 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00027 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00028 // Library General Public License for more details. 00029 // 00030 // You should have received a copy of the GNU Library General Public 00031 // License along with this library; if not, write to the Free Software 00032 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00033 // USA. 00034 // 00035 // Please report all bugs and problems to "lcharlto@mail.coin.missouri.edu" 00036 // ====================================================================== 00037 00038 00039 00040 00041 #include "Flv_List.H" 00042 #include <FL/fl_draw.H> 00043 #include <FL/Fl_Output.H> 00044 #include <stdio.h> 00045 00046 #define DOcb(x) ((vcallback_when & (x))==(x)) 00047 00048 // Resizing constants 00049 #define FUDGE 2 00050 #define MOVE_X 1 00051 #define MOVE_Y 2 00052 #define MOVE_XY (MOVE_X|MOVE_Y) 00053 00054 static void vscrollbar_cb(Fl_Widget* o, void*) 00055 { 00056 Flv_List *s = (Flv_List *)(o->parent()); 00057 s->top_row( ((Fl_Scrollbar *)o)->value() ); 00058 s->damage(FL_DAMAGE_CHILD); 00059 // s->select_start_row( ((Fl_Scrollbar *)o)->value() ); 00060 } 00061 00062 static void hscrollbar_cb(Fl_Widget* o, void*) 00063 { 00064 Flv_List *s = (Flv_List *)(o->parent()); 00065 s->row_offset( ((Fl_Scrollbar *)o)->value() ); 00066 } 00067 00068 Flv_List::Flv_List( int X, int Y, int W, int H, const char *l ) : 00069 Fl_Group(X,Y,W,H,l), 00070 scrollbar(0,0,0,0,0), 00071 hscrollbar(0,0,0,0,0) 00072 { 00073 int r, rh; 00074 00075 edit_row=-1; 00076 #ifdef FLTK_2 00077 style(Fl_Output::default_style); 00078 #else 00079 box(FL_THIN_DOWN_BOX); 00080 #endif 00081 fl_font( text_font(), text_size() ); 00082 fl_measure("X", r, rh ); 00083 00084 // Leave global_style & row_style undefined 00085 // get_default_style(global_style); 00086 00087 if (parent()) 00088 vdead_space_color = parent()->color(); 00089 else 00090 vdead_space_color = FL_GRAY; 00091 00092 scrollbar.callback(vscrollbar_cb); 00093 hscrollbar.callback(hscrollbar_cb); 00094 hscrollbar.type(FL_HORIZONTAL); 00095 00096 vclicks = 0; 00097 vmax_clicks = 2; // Double click the most 00098 vcallback_when = 0xffff; // All Events 00099 veditor = NULL; 00100 vediting = false; 00101 vedit_when = FLV_EDIT_MANUAL; 00102 vwhy_event = 0; 00103 vfeature = FLVF_PERSIST_SELECT; 00104 vhas_scrollbars = FLVS_BOTH; 00105 vlast_row = 0; 00106 vrow = 0; 00107 vrow_offset = 0; 00108 vrow_width = 0; 00109 vrows = 0; 00110 vrows_per_page = 0; 00111 vscrollbar_width = 17; 00112 vselect_locked = true; 00113 vselect_row = 0; 00114 vtop_row = 0; 00115 00116 end(); // Don't put other widgets in this one. 00117 } 00118 00119 Flv_List::~Flv_List() 00120 { 00121 row_style.release(); // Free any memory allocated 00122 } 00123 00124 //================================================================ 00125 // Virtual functions 00126 //================================================================ 00127 void Flv_List::save_editor( Fl_Widget *, int , int ) 00128 { 00129 } 00130 00131 void Flv_List::load_editor( Fl_Widget *, int , int ) 00132 { 00133 } 00134 00135 void Flv_List::position_editor( Fl_Widget *e, int x, int y, int w, int h, Flv_Style & ) 00136 { 00137 e->resize( x, y, w, h ); 00138 } 00139 00140 // Draw a single row 00141 void Flv_List::draw_row( int Offset, int &X, int &Y, int &W, int &H, int R ) 00142 { 00143 Fl_Boxtype bt; 00144 Flv_Style s; 00145 00146 get_style( s, R ); // Guaranteed to fill in style 00147 if (Fl::focus()==this || persist_select()) 00148 add_selection_style( s, R ); // Add selection coloring if applicable 00149 if (row_divider()) 00150 s.border( s.border()|FLVB_BOTTOM ); // Be sure bottom is on 00151 00152 X -= Offset; 00153 00154 draw_border(s,X,Y,W,H); 00155 bt = s.frame(); 00156 00157 fl_color( s.background() ); 00158 fl_rectf(X,Y,W,H ); 00159 #ifdef FLTK_2 00160 bt->draw(X,Y,W,H,s.background()); 00161 bt->inset( X, Y, W, H ); 00162 #else 00163 draw_box( bt, X, Y, W, H, s.background() ); 00164 X+= (Fl::box_dx(bt)); 00165 Y+= (Fl::box_dy(bt)); 00166 W-= (Fl::box_dw(bt)); 00167 H-= (Fl::box_dh(bt)); 00168 #endif 00169 if (R==row() && (Fl::focus()==this || persist_select())) 00170 { 00171 fl_color( fl_contrast(FL_BLACK,selection_color()) ); 00172 fl_rect( X, Y, W, H); 00173 } 00174 X+=s.x_margin(); 00175 Y+=s.y_margin(); 00176 W-=s.x_margin()*2; 00177 H-=s.y_margin()*2; 00178 00179 fl_font( s.font(), s.font_size() ); 00180 if (!active()) 00181 s.foreground( fl_inactive(s.foreground()) ); 00182 fl_color( s.foreground() ); 00183 X += Offset; 00184 if (R==-3) // Draw title 00185 fl_draw(label(), X, Y, W, H, s.align() ); 00186 } 00187 00188 // Handle events 00189 int Flv_List::handle(int event) 00190 { 00191 int t, x, y; 00192 bool bs; 00193 00194 bs = (vselect_row!=vrow); 00195 switch( event ) 00196 { 00197 case FL_DEACTIVATE: 00198 case FL_HIDE: 00199 case FL_LEAVE: 00200 case FL_ENTER: 00201 case FL_ACTIVATE: 00202 case FL_SHOW: 00203 return 1; 00204 00205 case FL_MOVE: 00206 check_cursor(); 00207 Fl_Group::handle(event); 00208 return 1; 00209 case FL_FOCUS: 00210 Fl::focus(this); 00211 damage(FL_DAMAGE_CHILD); 00212 Fl_Group::handle(event); 00213 return 1; 00214 case FL_UNFOCUS: 00215 damage(FL_DAMAGE_CHILD); 00216 Fl_Group::handle(event); 00217 return 1; 00218 case FL_KEYBOARD: 00219 break; 00220 case FL_RELEASE: 00221 Fl_Group::handle(event); 00222 return 1; 00223 case FL_DRAG: 00224 if (check_resize()) 00225 return 1; 00226 case FL_PUSH: 00227 Fl::focus(this); 00228 damage(FL_DAMAGE_CHILD); 00229 x = Fl::event_x(); 00230 y = Fl::event_y(); 00231 t = get_row( x, y ); 00232 00233 // Row header clicked 00234 if (t<0) 00235 { 00236 vwhy_event = 0; 00237 switch( t ) 00238 { 00239 case -3: 00240 if (DOcb(FLVEcb_TITLE_CLICKED)) 00241 vwhy_event = FLVE_TITLE_CLICKED; 00242 break; 00243 case -2: 00244 if (DOcb(FLVEcb_ROW_FOOTER_CLICKED)) 00245 vwhy_event = FLVE_ROW_FOOTER_CLICKED; 00246 break; 00247 case -1: 00248 if (DOcb(FLVEcb_ROW_HEADER_CLICKED)) 00249 vwhy_event = FLVE_ROW_HEADER_CLICKED; 00250 break; 00251 } 00252 if (vwhy_event) 00253 { 00254 do_callback(this, user_data()); 00255 vwhy_event = 0; 00256 } 00257 Fl_Group::handle(event); 00258 return 1; 00259 } 00260 row(t); 00261 00262 if (!multi_select() || 00263 (event==FL_PUSH && !Fl::event_state(FL_SHIFT))) 00264 { 00265 if (bs) 00266 vlast_row = vrow; 00267 if (vselect_row!=vrow) 00268 select_start_row( vrow ); 00269 } 00270 if (event==FL_PUSH) 00271 { 00272 if (DOcb(FLVEcb_CLICKED)) 00273 { 00274 vwhy_event = FLVE_CLICKED; 00275 do_callback(this, user_data()); 00276 vwhy_event = 0; 00277 } 00278 } 00279 Fl_Group::handle(event); 00280 return 1; 00281 00282 default: 00283 return Fl_Group::handle(event); 00284 } 00285 00286 switch(Fl::event_key()) 00287 { 00288 00289 case FL_Up: 00290 if (Fl::event_state(FL_CTRL)) 00291 { 00292 if (vrow>0) 00293 row(0); 00294 } else 00295 row(vrow-1); 00296 break; 00297 00298 case FL_Down: 00299 if (Fl::event_state(FL_CTRL)) 00300 { 00301 if (vrow<vrows-1) 00302 row( vrows-1 ); 00303 } else 00304 { 00305 if (vrow<vrows-1) 00306 row (vrow+1); 00307 } 00308 break; 00309 00310 case FL_Page_Down: 00311 if (Fl::event_state(FL_CTRL)) 00312 { 00313 if (vrow<vrows-1) 00314 row(vrows-1); 00315 } else 00316 { 00317 if (vrow<vrows-1) 00318 row(vrow+page_size()); 00319 } 00320 break; 00321 00322 case FL_Page_Up: 00323 if (Fl::event_state(FL_CTRL)) 00324 { 00325 if (vrow>0) 00326 row(0); 00327 } else 00328 row( vrow-page_size() ); 00329 break; 00330 00331 case FL_Right: 00332 row_offset(vrow_offset+10); 00333 break; 00334 00335 case FL_Left: 00336 row_offset(vrow_offset-10); 00337 break; 00338 00339 default: 00340 return Fl_Group::handle(event); 00341 } 00342 if (!multi_select()) 00343 { 00344 if (bs) 00345 vlast_row = vrow; 00346 if (vselect_row!=vrow) 00347 select_start_row(vrow); 00348 } 00349 if (!Fl::event_state(FL_SHIFT) && vselect_row!=vrow) 00350 select_start_row(vrow); 00351 Fl_Group::handle(event); 00352 return 1; 00353 } 00354 00355 int Flv_List::row_height( int r ) 00356 { 00357 int rh, x; 00358 Flv_Style *rows; 00359 00360 if (!global_style.height_defined()) 00361 { 00362 fl_font( text_font(), text_size() ); 00363 fl_measure("X", x, rh ); 00364 } else 00365 rh = global_style.height(); 00366 if (r<0) 00367 rh += 4; 00368 rows = row_style.find(r); 00369 if (rows) 00370 if (rows->height_defined()) 00371 rh = rows->height(); 00372 return rh; 00373 } 00374 00375 // H is set to height of drawn row not including any grids 00376 int Flv_List::row_height( int n, int r ) 00377 { 00378 if (r>-4 && r<rows()) 00379 row_style[r].height(n); 00380 return row_height(r); 00381 // Note: this is only the constant value, if row_height(r) is a calculated 00382 // value, it's the only way we can really determine row height. 00383 // Don't rely on the value of this function, ALWAYS call row_height(r) 00384 } 00385 00386 int Flv_List::get_row( int x, int y ) 00387 { 00388 int X, Y, W, H; 00389 int rh, rw, t, CY; 00390 00391 // Determine if row was clicked and highlight it 00392 client_area(X,Y,W,H); 00393 if (label()) 00394 { 00395 rh = row_height(-3); 00396 if (Y<=y && y<=Y+rh) 00397 return -3; 00398 Y+=rh; 00399 H-=rh; 00400 } 00401 if (row_header()) 00402 { 00403 rh = row_height(-1); 00404 if (Y<=y && y<=Y+rh) 00405 return -1; 00406 Y+=rh; 00407 H-=rh; 00408 } 00409 if (row_footer()) 00410 { 00411 rh = row_height(-2); 00412 if (Y+H>=y && y>Y+H-rh) 00413 return -2; 00414 H -= rh; 00415 } 00416 rw = row_width(); 00417 if (!rw) 00418 rw = W; 00419 if ( x<X || x>X+W || y<Y || y>=Y+H || x>X-vrow_offset+rw) 00420 return -4; // Out of bounds 00421 00422 for (CY=Y, t=vtop_row; t<vrows && CY<Y+H; t++, CY+=rh ) 00423 { 00424 rh = row_height(t); 00425 if (CY<=y && y<=CY+rh) 00426 return t; 00427 } 00428 return -4; // In grey area? 00429 } 00430 00431 // get trickle down style 00432 void Flv_List::get_style(Flv_Style &s, int R, int ) 00433 { 00434 Flv_Style *rows; 00435 00436 get_default_style(s); // Get default style information 00437 s = global_style; // Add global style information 00438 00439 00440 rows = row_style.skip_to(R); 00441 if (rows) s = *rows; // Add row style information 00442 if (R<0) // Headers/Labels have different default 00443 { // Note: we can still override at cell level 00444 if (parent()) 00445 s.background( parent()->color() ); 00446 else 00447 s.background( FL_WHITE ); 00448 s.frame(FL_THIN_UP_BOX); 00449 s.border( FLVB_NONE ); 00450 s.border_spacing(0); 00451 } 00452 if (R==-3) // If title use label information 00453 { 00454 s.font(label_font()); 00455 s.font_size(label_size()); 00456 s.foreground( label_color() ); 00457 s.align(FL_ALIGN_CLIP); 00458 } 00459 if (rows && R<0) 00460 { 00461 rows = rows->cell_style.skip_to(0); 00462 if (rows && R<0) 00463 s = *rows; 00464 } 00465 } 00466 00467 Flv_Feature Flv_List::feature(Flv_Feature v) 00468 { 00469 if (v!=vfeature) 00470 { 00471 vfeature = v; 00472 vlast_row = vrow; // Redraw all! 00473 if (DOcb(FLVEcb_FEATURE_CHANGED)) 00474 { 00475 vwhy_event = FLVE_FEATURE_CHANGED; 00476 do_callback(this, user_data()); 00477 vwhy_event = 0; 00478 } 00479 damage(FL_DAMAGE_CHILD); // Because features are visible 00480 } 00481 return vfeature; 00482 } 00483 00484 Flv_Feature Flv_List::feature_add(Flv_Feature v) 00485 { 00486 if ( (vfeature&v)!=v ) 00487 { 00488 vfeature |= v; 00489 if (DOcb(FLVEcb_FEATURE_CHANGED)) 00490 { 00491 vwhy_event = FLVE_FEATURE_CHANGED; 00492 do_callback(this, user_data()); 00493 vwhy_event = 0; 00494 } 00495 damage(FL_DAMAGE_CHILD); // Because features are visible 00496 } 00497 return vfeature; 00498 } 00499 00500 Flv_Feature Flv_List::feature_remove(Flv_Feature v) 00501 { 00502 if ( (vfeature&v)!=0 ) 00503 { 00504 vfeature &= (Flv_Feature)(~v); 00505 if (DOcb(FLVEcb_FEATURE_CHANGED)) 00506 { 00507 vwhy_event = FLVE_FEATURE_CHANGED; 00508 do_callback(this, user_data()); 00509 vwhy_event = 0; 00510 } 00511 damage(FL_DAMAGE_CHILD); // Because features are visible 00512 } 00513 return vfeature; 00514 } 00515 00516 Flv_ShowScrollbar Flv_List::has_scrollbar( Flv_ShowScrollbar v ) 00517 { 00518 if (v!=vhas_scrollbars) 00519 { 00520 vhas_scrollbars = v; 00521 damage(FL_DAMAGE_CHILD); 00522 } 00523 return vhas_scrollbars; 00524 } 00525 00526 int Flv_List::edit_when( int v ) 00527 { 00528 if (v!=vedit_when) 00529 { 00530 vedit_when = v; 00531 if (vedit_when!=FLV_EDIT_ALWAYS) 00532 end_edit(); 00533 else 00534 start_edit(); 00535 } 00536 return vedit_when; 00537 } 00538 00539 int Flv_List::bottom_row(void) 00540 { 00541 int r, rh; 00542 int X, Y, W, H, B; 00543 00544 client_area( X, Y, W, H ); 00545 B = Y + H; 00546 00547 for ( r=vtop_row; Y<B && r<vrows; r++, Y+=rh ) 00548 rh = row_height(r); 00549 if (r==vrows) 00550 r = vrows-1; 00551 return r; 00552 } 00553 00554 int Flv_List::row(int n) 00555 { 00556 int X, Y, W, H; 00557 if (n>=vrows) 00558 n=vrows-1; 00559 if (n<0) 00560 n=0; 00561 if (n!=vrow) 00562 { 00563 vrow = n; 00564 client_area(X,Y,W,H); 00565 update_top_row(H); 00566 vlast_row = vrow; 00567 if (DOcb(FLVEcb_ROW_CHANGED)) 00568 { 00569 vwhy_event = FLVE_ROW_CHANGED; 00570 do_callback(this, user_data()); 00571 vwhy_event = 0; 00572 } 00573 damage(FL_DAMAGE_CHILD); 00574 } 00575 return vrow; 00576 } 00577 00578 bool Flv_List::row_resizable( int r ) // Get/Set row locked status 00579 { 00580 Flv_Style s; 00581 get_style(s,r); 00582 return s.resizable(); 00583 } 00584 00585 bool Flv_List::row_resizable( bool n, int r ) 00586 { 00587 row_style[r].resizable(n); 00588 return n; 00589 } 00590 00591 int Flv_List::row_offset( int n ) 00592 { 00593 if (n>vrow_width) 00594 n = vrow_width; 00595 if (n<0) 00596 n = 0; 00597 if (n!=vrow_offset) 00598 { 00599 vrow_offset = n; 00600 vlast_row = vrow; // Make sure we draw everything 00601 damage(FL_DAMAGE_CHILD); 00602 } 00603 return vrow_offset; 00604 } 00605 00606 int Flv_List::rows(int n) 00607 { 00608 if (n>=0 && n!=vrows) 00609 { 00610 vrows = n; 00611 if (vrow>=vrows) 00612 row(vrows-1); 00613 if (vselect_row>vrow) 00614 select_start_row(vrow); 00615 if (DOcb(FLVEcb_ROW_CHANGED)) 00616 { 00617 vwhy_event = FLVE_ROW_CHANGED; 00618 do_callback(this, user_data()); 00619 vwhy_event = 0; 00620 } 00621 damage(FL_DAMAGE_CHILD); 00622 } 00623 return vrows; 00624 } 00625 00626 int Flv_List::rows_per_page( int n ) 00627 { 00628 if (n!=vrows_per_page && n>=0) 00629 vrows_per_page = n; 00630 return vrows_per_page; 00631 } 00632 00633 bool Flv_List::row_selected( int n ) 00634 { 00635 if (vselect_row<vrow) 00636 return (vselect_row<=n && n<=vrow); 00637 else 00638 return (vrow<=n && n<=vselect_row); 00639 } 00640 00641 int Flv_List::row_width( int n ) 00642 { 00643 if (n>=0 && n!=vrow_width) 00644 { 00645 vrow_width = n; 00646 damage(FL_DAMAGE_CHILD); 00647 } 00648 return vrow_width; 00649 } 00650 00651 int Flv_List::scrollbar_width(int n) 00652 { 00653 if (n!=vscrollbar_width && n>0) 00654 { 00655 vscrollbar_width = n; 00656 damage(FL_DAMAGE_CHILD); 00657 } 00658 return vscrollbar_width; 00659 } 00660 00661 int Flv_List::select_start_row(int n) // Set first selected row 00662 { 00663 if (n>=vrows) n=vrows-1; 00664 if (n<0) n=0; 00665 if (n!=vselect_row) 00666 { 00667 vselect_row = n; 00668 vlast_row = vrow; 00669 if (DOcb(FLVEcb_SELECTION_CHANGED)) 00670 { 00671 vwhy_event = FLVE_SELECTION_CHANGED; 00672 do_callback(this, user_data()); 00673 vwhy_event = 0; 00674 } 00675 damage(FL_DAMAGE_CHILD); 00676 } 00677 return vselect_row; 00678 } 00679 00680 //================================================================ 00681 // Protected functions 00682 //================================================================ 00683 void Flv_List::client_area( int &X, int &Y, int &W, int &H ) 00684 { 00685 char sv=0, sh=0; 00686 int th, v, rw; 00687 00688 X = x(); Y = y(); W = w(); H = h(); 00689 #ifdef FLTK_2 00690 box()->inset(X,Y,W,H); 00691 #else 00692 Fl_Boxtype b = box(); 00693 X += Fl::box_dx(b); 00694 Y += Fl::box_dy(b); 00695 W -= Fl::box_dw(b); 00696 H -= Fl::box_dh(b); 00697 #endif 00698 00699 rw = vrow_width; 00700 if (rw==0) rw = W; 00701 00702 if ( (vhas_scrollbars & FLVS_HORIZONTAL_ALWAYS)==FLVS_HORIZONTAL_ALWAYS) 00703 sh = 1; 00704 else if ( (vhas_scrollbars & FLVS_HORIZONTAL)==FLVS_HORIZONTAL ) 00705 { 00706 if (vrow_width!=0) 00707 { 00708 if (rw>W) 00709 sh=1; 00710 else if (rw>W-vscrollbar_width) 00711 sh=-1; // Turn on if rows won't fit 00712 } 00713 } 00714 // We need total height 00715 if ( (vhas_scrollbars & FLVS_VERTICAL_ALWAYS)==FLVS_VERTICAL_ALWAYS ) 00716 sv = 1; 00717 else if ( (vhas_scrollbars & FLVS_VERTICAL)==FLVS_VERTICAL ) 00718 { 00719 th = (label()?row_height(-3):0); 00720 th += (row_header()?row_height(-1):0); 00721 th += (row_footer()?row_height(-2):0); 00722 for (v=0; th<=H && v<rows(); v++ ) 00723 th += row_height(v); 00724 if ( th>H) 00725 sv = 1; 00726 else if ( th > H-vscrollbar_width ) 00727 sv = -1; // Turn on if width in region 00728 } 00729 if (sh<0 && sv>0) sh=1; // Extends to scrollbar obscured region so turn on 00730 if (sv<0 && sh>0) sv=1; // Extends to scrollbar obscured region so turn on 00731 00732 if (sv>0) W-=vscrollbar_width; 00733 if (sh>0) H-=vscrollbar_width; 00734 } 00735 00736 void Flv_List::draw_border(Flv_Style &s, int &X, int &Y, int &W, int &H ) 00737 { 00738 int t; 00739 00740 // Draw outer border if defined 00741 fl_color( s.border_color() ); 00742 if (s.left_border()) 00743 fl_yxline(X, Y, Y+H-1); 00744 if (s.right_border()) 00745 fl_yxline(X+W-1, Y, Y+H-1 ); 00746 if (s.left_border()) 00747 { 00748 X++; 00749 W--; 00750 } 00751 if (s.right_border()) 00752 W--; 00753 00754 if (s.top_border()) 00755 fl_xyline(X, Y, X+W-1 ); 00756 if (s.bottom_border()) 00757 fl_xyline(X, Y+H-1, X+W-1 ); 00758 if (s.top_border()) 00759 { 00760 Y++; 00761 H--; 00762 } 00763 if (s.bottom_border()) 00764 H--; 00765 00766 // Draw spacing between borders 00767 fl_color( color() ); 00768 for (t=0; t<s.border_spacing(); t++ ) 00769 { 00770 00771 fl_rect( X, Y, W, H ); 00772 if (s.left_border()) 00773 { 00774 X++; 00775 W--; 00776 } 00777 if (s.right_border()) 00778 W--; 00779 if (s.top_border()) 00780 { 00781 Y++; 00782 H--; 00783 } 00784 if (s.bottom_border()) 00785 H--; 00786 } 00787 00788 // Draw inner border if defined 00789 fl_color( s.border_color() ); 00790 if (s.inner_left_border()) 00791 fl_yxline(X, Y, Y+H-1); 00792 if (s.inner_right_border()) 00793 fl_yxline(X+W-1, Y, Y+H-1 ); 00794 if (s.inner_left_border()) 00795 { 00796 X++; 00797 W--; 00798 } 00799 if (s.inner_right_border()) 00800 W--; 00801 00802 if (s.inner_top_border()) 00803 fl_xyline(X, Y, X+W-1 ); 00804 if (s.inner_bottom_border()) 00805 fl_xyline(X, Y+H-1, X+W-1 ); 00806 if (s.inner_top_border()) 00807 { 00808 Y++; 00809 H--; 00810 } 00811 if (s.inner_bottom_border()) 00812 H--; 00813 } 00814 00815 // Determine if scrollbars are visible/position and draw 00816 // them if nessasary, also update X,Y,W,H to be inside box 00817 void Flv_List::draw_scrollbars(int &X, int &Y, int &W, int &H ) 00818 { 00819 char sv=0, sh=0; 00820 int th, x, rw; 00821 00822 00823 rw = vrow_width; 00824 if (rw==0) rw = W; 00825 00826 if ( (vhas_scrollbars & FLVS_HORIZONTAL_ALWAYS)==FLVS_HORIZONTAL_ALWAYS) 00827 sh = 1; 00828 else if ( (vhas_scrollbars & FLVS_HORIZONTAL)==FLVS_HORIZONTAL ) 00829 { 00830 if (vrow_width!=0) 00831 { 00832 if (rw>W) 00833 sh=1; 00834 else if (rw>W-vscrollbar_width) 00835 sh=-1; // Turn on if rows won't fit 00836 } 00837 } 00838 // We need total height 00839 if ( (vhas_scrollbars & FLVS_VERTICAL_ALWAYS)==FLVS_VERTICAL_ALWAYS ) 00840 sv = 1; 00841 else if ( (vhas_scrollbars & FLVS_VERTICAL)==FLVS_VERTICAL ) 00842 { 00843 th = (label()?row_height(-3):0); 00844 th += (row_header()?row_height(-1):0); 00845 th += (row_footer()?row_height(-2):0); 00846 for (x=0; th<=H && x<rows(); x++ ) 00847 th += row_height(x); 00848 if ( th>H) 00849 sv = 1; 00850 else if ( th > H-vscrollbar_width ) 00851 sv = -1; // Turn on if width in region 00852 } 00853 if (sh<0 && sv>0) sh=1; // Extends to scrollbar obscured region so turn on 00854 if (sv<0 && sh>0) sv=1; // Extends to scrollbar obscured region so turn on 00855 00856 if (sv>0) W-=vscrollbar_width; 00857 if (sh>0) H-=vscrollbar_width; 00858 00859 // Place scrollbars where they should be 00860 if (sv>0) 00861 { 00862 scrollbar.damage_resize(X+W,Y,vscrollbar_width,H); 00863 scrollbar.value( top_row(), page_size()+1, 0, vrows ); // Fake out page size 00864 scrollbar.linesize( 1 ); 00865 scrollbar.minimum(0); 00866 scrollbar.maximum(vrows-1); 00867 x = H - (vrows*2) - vscrollbar_width*2; 00868 if (x<vscrollbar_width) x = vscrollbar_width; 00869 #ifdef FLTK_2 00870 scrollbar.slider_size(x); 00871 #else 00872 scrollbar.slider_size((double)((double)x/(double)(H-vscrollbar_width*2))); 00873 #endif 00874 scrollbar.Fl_Valuator::value( top_row() ); // , 1, 0, vrows ); 00875 if (!scrollbar.visible()) 00876 scrollbar.set_visible(); 00877 draw_child(scrollbar); 00878 } else 00879 scrollbar.clear_visible(); 00880 00881 00882 if (rw-vrow_offset<W && rw>W) 00883 { 00884 vrow_offset = rw - W; 00885 vlast_row = vrow; // Make sure we update the entire widget 00886 } 00887 00888 if (sh>0) 00889 { 00890 hscrollbar.damage_resize(X,Y+H,W,vscrollbar_width); 00891 hscrollbar.value( vrow_offset, 50, 0, vrow_width ); // Fake out page size 00892 hscrollbar.linesize( 10 ); 00893 hscrollbar.minimum(0); 00894 hscrollbar.maximum(vrow_width-W); 00895 #ifdef FLTK_2 00896 x = W - vrow_width/10 - vscrollbar_width*2; 00897 if (x<vscrollbar_width) x = vscrollbar_width; 00898 hscrollbar.slider_size(x); 00899 #else 00900 x = vrow_width / 10; 00901 hscrollbar.slider_size( (double)((double)x/(double)(W-vscrollbar_width*2))); 00902 #endif 00903 hscrollbar.Fl_Valuator::value( vrow_offset ); // , 1, 0, vrows ); 00904 if (!hscrollbar.visible()) 00905 hscrollbar.set_visible(); 00906 draw_child(hscrollbar); 00907 } else 00908 hscrollbar.clear_visible(); 00909 00910 if (sh>0 && sv>0) // Draw box at ends 00911 { 00912 if (parent()) 00913 fl_color( parent()->color() ); 00914 else 00915 fl_color( FL_WHITE ); 00916 fl_rectf( X+W, Y+H, vscrollbar_width, vscrollbar_width ); 00917 } 00918 } 00919 00920 void Flv_List::update_top_row(int H) 00921 { 00922 int rh, r; 00923 00924 if (vrow<vtop_row) 00925 { 00926 vtop_row = vrow; 00927 vlast_row = vrow; // Make sure we update the entire widget 00928 } else 00929 { 00930 if (label()) 00931 H -= row_height(-3); 00932 if (row_header()) 00933 H -= row_height(-1); 00934 if (row_footer()) 00935 H -= row_height(-2); 00936 for (r=vtop_row; r<=vrow && r<vrows; r++, H-=rh ) 00937 { 00938 rh = row_height(r); 00939 if (rh>H) 00940 break; 00941 } 00942 if (r<=vrow) // Move top row down, so we can see current line 00943 { 00944 vlast_row = vrow; // Make sure we update the entire widget 00945 for( ; r<=vrow; r++, H -= rh ) 00946 { 00947 rh = row_height(r); 00948 vtop_row++; 00949 } 00950 } 00951 // If there're visible rows below the current row 00952 // if (rh<H) 00953 // { 00954 // // Finish computing visible rows 00955 // for (; r<vrows; r++, H-=rh ) 00956 // { 00957 // rh = row_height(r); 00958 // if (rh>H) 00959 // break; 00960 // } 00961 // } 00962 // // Do we need to move the top row up? 00963 // if (rh<H) 00964 // { 00965 // // Too much space at bottom, we need to move top row toward 0 00966 // // If possible. 00967 // vlast_row = vrow; // Make sure we update the entire widget 00968 // for (; vtop_row>0; vtop_row--, H -= rh ) 00969 // { 00970 // rh = row_height(vtop_row); 00971 // if (rh>H) 00972 // break; 00973 // } 00974 // } 00975 } 00976 } 00977 00978 void Flv_List::start_draw(int &X, int &Y, int &W, int &H, int &trow_width ) 00979 { 00980 int rh, CX, CY, CW, CH; 00981 label_type(FL_NO_LABEL); 00982 00983 if (damage()&FL_DAMAGE_ALL) 00984 { 00985 #ifdef FLTK_2 00986 draw_frame(); 00987 #else 00988 draw_box(); 00989 #endif 00990 } 00991 00992 00993 // Get dimension inside box 00994 X = x(); Y = y(); W = w(); H = h(); 00995 #ifdef FLTK_2 00996 box()->inset(X,Y,W,H); 00997 #else 00998 Fl_Boxtype b = box(); 00999 X += Fl::box_dx(b); 01000 Y += Fl::box_dy(b); 01001 W -= Fl::box_dw(b); 01002 H -= Fl::box_dh(b); 01003 #endif 01004 01005 draw_scrollbars( X, Y, W, H ); // Place/set values, update bounding box 01006 01007 trow_width = vrow_width; 01008 if (!trow_width) 01009 trow_width = W; 01010 01011 // Update top row if nessasary 01012 // update_top_row(H); 01013 01014 // Draw Title 01015 if (label()) 01016 { 01017 rh = row_height(-3); 01018 fl_clip( X, Y, W, rh ); 01019 CX=X; CY=Y; CW=W; CH=rh; 01020 Flv_List::draw_row( 0, CX, CY, CW, CH, -3); 01021 fl_pop_clip(); 01022 Y += rh; 01023 H -= rh; 01024 } 01025 01026 // Draw header if visible 01027 if (row_header()) 01028 { 01029 rh = row_height(-1); 01030 fl_clip( X, Y, W, rh ); 01031 CX=X; CY=Y; CW=trow_width; CH=rh; 01032 draw_row( vrow_offset, CX, CY, CW, CH, -1); 01033 fl_pop_clip(); 01034 Y += rh; 01035 H -= rh; 01036 } 01037 // Draw footer 01038 if (row_footer()) 01039 { 01040 rh = row_height(-2); 01041 H -=rh; 01042 fl_clip( X, Y+H, W, rh ); 01043 CX=X; CY=Y+H; CW=trow_width; CH=rh; 01044 draw_row( vrow_offset, CX, CY, CW, CH, -2 ); 01045 fl_pop_clip(); 01046 } 01047 } 01048 01049 // Perform actual draw function 01050 void Flv_List::draw() 01051 { 01052 int r, rh, rw; 01053 int X, Y, W, H, B; 01054 int CX, CY, CW, CH; 01055 Flv_Style s; 01056 01057 // Initially verify we aren't on a locked cell 01058 r = row(); 01059 while(!select_locked()) 01060 { 01061 get_style(s,r); 01062 if (!s.locked()) 01063 { 01064 row(r); 01065 break; 01066 } 01067 r++; 01068 if (r==rows()) 01069 break; 01070 } 01071 // Make sure we have an editor if editing! 01072 if (vediting && !veditor) 01073 switch_editor(row()); 01074 01075 start_draw(X,Y,W,H,rw); 01076 01077 B = W-(rw-vrow_offset); 01078 // Fill-in area at right of list 01079 if (B>0) 01080 { 01081 fl_color( dead_space_color() ); 01082 CY = Y; CH = H; 01083 if (row_header()) 01084 { 01085 CY -= row_height(-1); 01086 CH += row_height(-1); 01087 } 01088 if (row_footer()) 01089 CH += row_height(-2); 01090 fl_rectf( X+rw-vrow_offset, CY, B, CH ); 01091 } 01092 01093 B = Y + H; 01094 fl_clip( X, Y, W, H ); 01095 // Draw rows 01096 for ( r=vtop_row; Y<B && r<vrows; r++, Y+=rh ) 01097 { 01098 rh = row_height(r); 01099 if ( vlast_row==vrow || (vlast_row!=vrow && (r==vlast_row || r==vrow)) ) 01100 { 01101 fl_clip( X, Y, rw, rh); 01102 CX=X; CY=Y; CW=rw; CH=rh; 01103 draw_row( vrow_offset, CX, CY, CW, CH, r ); 01104 fl_pop_clip(); 01105 } 01106 } 01107 vlast_row = vrow; 01108 01109 // Fill-in area at bottom of list 01110 if (Y<B) 01111 { 01112 fl_color( dead_space_color() ); 01113 fl_rectf( X, Y, W, B-Y ); 01114 } 01115 fl_pop_clip(); 01116 } 01117 01118 int Flv_List::page_size(void) 01119 { 01120 int ps, H; 01121 01122 if (vrows_per_page) 01123 ps = vrows_per_page; 01124 else 01125 { 01126 H = h() - 2 * vscrollbar_width; 01127 ps=11; 01128 if (H) 01129 ps=(H/row_height(0)); 01130 ps--; 01131 if (ps<1) 01132 ps=1; 01133 } 01134 return ps; 01135 } 01136 01137 bool Flv_List::move_row( int amount ) 01138 { 01139 int r = row(); 01140 Flv_Style s; 01141 01142 r += amount; 01143 if (r>=rows()) 01144 r = rows()-1; 01145 if (r<0) 01146 r = 0; 01147 01148 while(!select_locked()) 01149 { 01150 get_style(s,r); 01151 if (!s.locked()) 01152 break; 01153 r += (amount<0?-1:1); 01154 if ( r<0 || r>=rows() ) 01155 return false; 01156 } 01157 if (r!=row()) 01158 { 01159 row(r); 01160 return true; 01161 } 01162 return false; 01163 } 01164 01165 void Flv_List::get_default_style( Flv_Style &s ) 01166 { 01167 int r, rh; 01168 01169 // Make sure EVERY feature is defined 01170 s.align(FL_ALIGN_LEFT); 01171 #ifdef FLTK_2 01172 s.background(color()); 01173 #else 01174 s.background(FL_WHITE); 01175 #endif 01176 s.border(FLVB_NONE); 01177 if (parent()) 01178 s.border_color(parent()->color()); 01179 else 01180 s.border_color(FL_WHITE); 01181 s.border_spacing(0); 01182 s.editor(NULL); // No editor 01183 s.font(text_font()); 01184 s.font_size(text_size()); 01185 s.foreground(text_color()); 01186 s.frame(FL_FLAT_BOX); 01187 01188 fl_font( text_font(), text_size() ); 01189 fl_measure("X", r, rh ); 01190 s.height(rh); 01191 s.locked(true); 01192 s.resizable(false); 01193 s.width(40); 01194 s.x_margin(2); 01195 s.y_margin(1); 01196 } 01197 01198 void Flv_List::add_selection_style( Flv_Style &s, int R, int ) 01199 { 01200 if (!multi_select()) // If not multi row selection 01201 select_start_row( row() ); 01202 01203 // Handle row selection 01204 if (row_selected(R)) 01205 { 01206 s.background( selection_color() ); 01207 s.foreground( fl_contrast( text_color(), selection_color() ) ); 01208 } 01209 } 01210 01211 static Fl_Cursor last_cursor = FL_CURSOR_DEFAULT; 01212 static int drag_row=-4, anchor_top; 01213 01214 bool Flv_List::check_resize(void) 01215 { 01216 int ey, h; 01217 bool w=false; 01218 01219 ey = Fl::event_y(); 01220 01221 if (drag_row>-4) 01222 { 01223 if (drag_row==-2) 01224 { 01225 h = anchor_top - ey + row_height(drag_row); 01226 if (h>1) 01227 { 01228 row_style[drag_row].height(h); 01229 damage(FL_DAMAGE_CHILD); 01230 anchor_top = ey; 01231 w = true; 01232 } 01233 } else 01234 { 01235 h = ey-anchor_top; 01236 if (h<1) h=1; 01237 row_style[drag_row].height(h); 01238 damage(FL_DAMAGE_CHILD); 01239 w=true; 01240 } 01241 } 01242 return w; 01243 } 01244 01245 // See if we can resize, if so change cursor 01246 void Flv_List::check_cursor(void) 01247 { 01248 int X, Y, W, H, ey, move=0, WW, size; 01249 int v; 01250 Fl_Cursor cursor; 01251 01252 ey = Fl::event_y(); 01253 client_area(X,Y,W,H); 01254 01255 if (label() && *label()) 01256 { 01257 Y+=row_height(-3); 01258 H-=row_height(-3); 01259 } 01260 01261 // if (full_resize()) // Trival test first 01262 { 01263 if (row_header()) 01264 { 01265 size = row_height(-1); 01266 if (ey>=Y+size-FUDGE && ey<=Y+size+FUDGE) 01267 { 01268 if (row_resizable(-1)) 01269 { 01270 drag_row = -1; 01271 anchor_top = Y; 01272 move |= MOVE_Y; // Moving 01273 } 01274 } 01275 Y += size; 01276 H -= size; 01277 } 01278 if (row_footer()) 01279 { 01280 size = row_height(-2); 01281 if (ey>=Y+H-size-FUDGE && ey<=Y+H-size+FUDGE) 01282 { 01283 if (row_resizable(-2)) 01284 { 01285 drag_row = -2; 01286 anchor_top = ey; 01287 move |= MOVE_Y; // Moving 01288 } 01289 } 01290 H -= size; 01291 } 01292 01293 if ((move & MOVE_Y)==0) 01294 { 01295 WW = Y; 01296 for (v=top_row(); v<rows(); WW+=size, v++ ) 01297 { 01298 size = row_height(v); 01299 if (WW+size+FUDGE>=Y+H) 01300 break; 01301 if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE) 01302 { 01303 if (row_resizable(v)) 01304 { 01305 drag_row = v; 01306 anchor_top = WW; 01307 move |= MOVE_Y; // Moving 01308 } 01309 break; 01310 } 01311 } 01312 } 01313 } 01314 01315 switch( move ) 01316 { 01317 case MOVE_Y: cursor = FL_CURSOR_NS; break; 01318 default: 01319 drag_row = -4; 01320 cursor = FL_CURSOR_DEFAULT; 01321 break; 01322 } 01323 if (cursor!=last_cursor) 01324 { 01325 fl_cursor(cursor,FL_BLACK,FL_WHITE); 01326 last_cursor = cursor; 01327 } 01328 } 01329 01330 void Flv_List::end_edit(void) 01331 { 01332 switch_editor(-1); 01333 } 01334 01335 void Flv_List::start_edit(void) // Start editing 01336 { 01337 if (!vediting) 01338 { 01339 vediting = true; 01340 switch_editor( row() ); 01341 } 01342 } 01343 01344 void Flv_List::cancel_edit(void) // Cancel editing 01345 { 01346 if (veditor) 01347 veditor->hide(); 01348 veditor = NULL; 01349 edit_row = -1; 01350 if (edit_when()!=FLV_EDIT_ALWAYS) 01351 vediting = false; 01352 switch_editor( row() ); 01353 } 01354 01355 void Flv_List::switch_editor( int nr ) 01356 { 01357 Flv_Style s; 01358 01359 if (veditor) 01360 { 01361 if (edit_row>-1) 01362 save_editor( veditor, edit_row ); 01363 edit_row = -1; 01364 veditor->hide(); 01365 veditor = NULL; 01366 } 01367 if (edit_when()==FLV_EDIT_ALWAYS) 01368 vediting = true; 01369 if (nr && vediting ) 01370 { 01371 get_style( s, nr ); 01372 if (s.editor_defined() && !s.locked()) 01373 { 01374 veditor = s.editor(); 01375 if (veditor) 01376 { 01377 edit_row = nr; 01378 load_editor( veditor, nr ); 01379 veditor->damage(FL_DAMAGE_ALL); 01380 veditor->hide(); 01381 veditor->show(); 01382 Fl::focus(veditor); 01383 } 01384 } 01385 } 01386 if (veditor && veditor->parent()!=this) 01387 veditor->parent(this); 01388 } 01389 01390 #ifdef FLTK_2 01391 //================================================================ 01392 // Style stuff? 01393 //================================================================ 01394 static void revert(Fl_Style* s) { 01395 s->selection_color = FL_BLUE_SELECTION_COLOR; 01396 s->selection_text_color = FL_WHITE; 01397 s->off_color = FL_BLACK; 01398 s->box = FL_THIN_DOWN_BOX; 01399 s->color = FL_GRAY_RAMP+1; 01400 } 01401 01402 Fl_Style* Flv_List::default_style = 01403 new Fl_Named_Style("Browser", revert, &Flv_List::default_style); 01404 #endif 01405 01406 01407