MOOS 0.2375
|
00001 // ====================================================================== 00002 // File: Flv_Table.cxx - Flv_Table implementation 00003 // Program: Flv_Table - FLTK Table Widget 00004 // Version: 0.1.0 00005 // Started: 11/21/99 00006 // 00007 // Copyright (C) 1999 Laurence Charlton 00008 // 00009 // Description: 00010 // Flv_Table implements a table/grid. No data is stored 00011 // in the widget. Supports headers/footers for rows and columns, 00012 // natively supports a single row height and column width per table. 00013 // Row and column grids can be turned on and off. Supports no scroll 00014 // bars as well as horizontal/vertical automatic or always on scroll bars. 00015 // Also support cell selection and row selection modes. In row selection 00016 // mode it acts like a pumped-up list widget. 00017 // Uses absolute cell references. 00018 // 00019 // row -1 is defined as the row header 00020 // row -2 is defined as the row footer 00021 // 00022 // This library is free software; you can redistribute it and/or 00023 // modify it under the terms of the GNU Library General Public 00024 // License as published by the Free Software Foundation; either 00025 // version 2 of the License, or (at your option) any later version. 00026 // 00027 // This library is distributed in the hope that it will be useful, 00028 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00029 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00030 // Library General Public License for more details. 00031 // 00032 // You should have received a copy of the GNU Library General Public 00033 // License along with this library; if not, write to the Free Software 00034 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00035 // USA. 00036 // ====================================================================== 00037 00038 00039 #include "Flv_Table.H" 00040 #include <FL/Enumerations.H> 00041 #include <FL/fl_draw.H> 00042 #include <stdio.h> 00043 00044 #define DOcb(x) ((callback_when() & (x))==(x)) 00045 00046 // Resizing constants 00047 #define FUDGE 2 00048 #define MOVE_X 1 00049 #define MOVE_Y 2 00050 #define MOVE_XY (MOVE_X|MOVE_Y) 00051 00052 #ifndef max 00053 #define max(a,b) ((a)>(b)?(a):(b)) 00054 #endif 00055 #ifndef min 00056 #define min(a,b) ((a)<(b)?(a):(b)) 00057 #endif 00058 00059 static Fl_Cursor last_cursor = FL_CURSOR_DEFAULT; 00060 static int drag_col=-4, drag_row=-4, anchor_left, anchor_top; 00061 00062 00063 Flv_Table::Flv_Table( int X, int Y, int W, int H, const char *l ) : 00064 Flv_List(X,Y,W,H,l) 00065 { 00066 edit_col = -1; 00067 vcol = 0; 00068 vcols = 0; 00069 vcol_width = 40; 00070 vmove_on_enter = FLV_MOVE_ON_ENTER_COL_ROW; 00071 vselect_col = 0; 00072 vbuttons = FLV_BUTTON1 | FLV_BUTTON2 | FLV_BUTTON3; 00073 } 00074 00075 Flv_Table::~Flv_Table() 00076 { 00077 } 00078 00079 // Probbably won't need to over-ride this for future table widgets 00080 void Flv_Table::draw_row( int Offset, int &X, int &Y, int &, int &H, int R ) 00081 { 00082 int c, cw, CX, FW; 00083 int dX, dY, dW, dH; 00084 int TX, TY, TW, TH; 00085 Flv_Style s; 00086 00087 // Calculate clipping height 00088 client_area(dX,dY,dW,dH); 00089 00090 FW = (col_footer()?col_width(-2):0); 00091 00092 CX = X; 00093 00094 // Draw column header 00095 if (col_header()) 00096 { 00097 cw = col_width(-1); // Column width 00098 TX = CX; TY = Y; TW = cw; TH = H; 00099 draw_cell( 0, TX, TY, TW, TH, R, -1 ); 00100 CX += cw; 00101 dX += cw; 00102 dW -= cw; 00103 } 00104 00105 dW -= FW; 00106 // Draw column footer 00107 if (FW) 00108 { 00109 TX = dX+dW; TY = Y; TW = FW; TH = H; 00110 draw_cell( 0, TX, TY, TW, TH, R, -2 ); 00111 } 00112 00113 fl_clip( dX, Y, dW, H ); // Clip data area 00114 for (c=0; c<vcols && CX-Offset<dX+dW; c++, CX+=cw ) 00115 { 00116 cw = col_width(c); // Column width 00117 if (CX-Offset+cw<dX) // Before left 00118 continue; 00119 fl_clip( CX-Offset, Y, cw, H ); 00120 TX = CX; TY = Y; TW = cw; TH = H; 00121 draw_cell( Offset, TX, TY, TW, TH, R, c ); 00122 fl_pop_clip(); 00123 } 00124 // If we're selecting a row, put the box around it. 00125 if (R==row() && select_row() ) 00126 { 00127 fl_color( fl_contrast(FL_BLACK, selection_color()) ); 00128 fl_rect( dX, Y, dW, H ); 00129 } 00130 // Fill-in area at right of list 00131 if (CX-Offset<dX+dW) 00132 { 00133 cw = dX+dW-(CX-Offset); 00134 fl_color( dead_space_color() ); 00135 fl_rectf( CX-Offset, Y, cw, H ); 00136 } 00137 fl_pop_clip(); 00138 } 00139 00140 // You will certainly want to override this 00141 void Flv_Table::draw_cell( int Offset, int &X, int &Y, int &W, int &H, int R, int C ) 00142 { 00143 Fl_Boxtype bt; 00144 Flv_Style s; 00145 00146 X -= Offset; 00147 00148 get_style(s, R, C); 00149 if (Fl::focus()==this || persist_select()) 00150 add_selection_style(s, R, C); 00151 00152 if (row_divider()) 00153 s.border( s.border()|FLVB_BOTTOM ); 00154 if (col_divider()) 00155 s.border( s.border()|FLVB_RIGHT ); 00156 00157 draw_border( s, X, Y, W, H ); 00158 bt = s.frame(); 00159 00160 fl_color( s.background() ); 00161 fl_rectf(X,Y,W,H ); 00162 #ifdef FLTK_2 00163 bt->draw(X,Y,W,H,s.background()); 00164 // Normally you would use the next line to get the client area to draw 00165 bt->inset( X, Y, W, H ); 00166 #else 00167 draw_box( bt, X, Y, W, H, s.background() ); 00168 // Normally you would use the next lines to get the client area to draw 00169 X+= (Fl::box_dx(bt)); 00170 Y+= (Fl::box_dy(bt)); 00171 W-= (Fl::box_dw(bt)); 00172 H-= (Fl::box_dh(bt)); 00173 #endif 00174 // Drawing selection rectangle for cell 00175 if (R>-1 && C>-1 && R==row() && C==col() && !select_row() && 00176 (Fl::focus()==this || persist_select())) 00177 { 00178 fl_color( fl_contrast(text_color(), selection_color()) ); 00179 fl_rect( X, Y, W, H); 00180 } 00181 00182 X+=s.x_margin(); 00183 Y+=s.y_margin(); 00184 W-=s.x_margin()*2; 00185 H-=s.y_margin()*2; 00186 X += Offset; 00187 // Get set-up to draw text 00188 fl_font( s.font(), s.font_size() ); 00189 if (!active()) 00190 s.foreground( fl_inactive(s.foreground()) ); 00191 fl_color(s.foreground()); 00192 } 00193 00194 bool Flv_Table::get_cell_bounds( int &X, int &Y, int &W, int &H, int R, int C ) 00195 { 00196 int x, y, w, h, r, rh, B, cx; 00197 00198 X = Y = W = H = 0; 00199 cell_area(x,y,w,h); 00200 B = y+h; 00201 00202 for (r=top_row(); r<rows() && r<R; y += rh, r++ ) 00203 { 00204 rh = row_height(r); 00205 if (y>B) 00206 break; 00207 } 00208 if (r!=R) 00209 return false; 00210 Y = y; 00211 H = row_height(R); 00212 if (Y+H>B) 00213 H = B-Y; 00214 00215 cx = x - row_offset(); 00216 for (r=0; r<cols() && r<C; cx += rh, r++ ) 00217 { 00218 rh = col_width(r); 00219 if (cx>x+w) 00220 break; 00221 } 00222 rh = col_width(r); 00223 if (r!=C || cx+rh<x) 00224 { 00225 X = Y = W = H = 0; 00226 return false; 00227 } 00228 00229 X = cx; 00230 if (X<x) 00231 { 00232 rh -= (x-X); 00233 X = x; 00234 } 00235 if (X+rh>x+w) 00236 rh = (x+w)-X; 00237 if (rh>w) 00238 rh = w; 00239 if (rh<0) 00240 rh = 0; 00241 W = rh; 00242 return true; 00243 } 00244 00245 void Flv_Table::draw(void) 00246 { 00247 int r, rh, rw; 00248 int X, Y, W, H, B, FW; 00249 int CX, CY, CW, CH; 00250 Flv_Style s; 00251 int t, c; 00252 // char buf[30]; 00253 00254 // Initially verify we aren't on a locked cell 00255 r = row(); 00256 c = col(); 00257 while(!select_locked()) 00258 { 00259 get_style(s,r,c); 00260 if (!s.locked()) 00261 { 00262 row(r); 00263 col(c); 00264 break; 00265 } 00266 c++; 00267 if (c==cols()) 00268 { 00269 c = 0; 00270 r++; 00271 if (r==rows()) 00272 break; 00273 } 00274 } 00275 00276 // Make sure we have an editor if editing! 00277 // if (!veditor && vediting) 00278 // switch_editor(row(),col()); 00279 00280 // We need to know what the row width will be 00281 // so we'll calculate that and then let normal drawing 00282 // take over. 00283 if (!feature_test(FLVF_MULTI_SELECT)) 00284 select_start_col(vcol); 00285 00286 for (c=cols(), rw=t=0; t<c; t++ ) 00287 rw += col_width(t); 00288 if (col_header()) 00289 rw += col_width(-1); 00290 if (col_footer()) 00291 rw += col_width(-2); 00292 00293 row_width(rw); // Set the row width so we can draw intelligently 00294 00295 start_draw(X,Y,W,H,rw); 00296 00297 // This is why draw is here and we're not using the code from 00298 // Flv_List... It sucks, but I really didn't like the flickering 00299 // from the column footers getting erased and then redrawn... 00300 FW = (col_footer()?col_width(-2):0); 00301 00302 B = W-(rw-row_offset())-FW; 00303 // Fill-in area at right of list 00304 if (B>0) 00305 { 00306 fl_color( dead_space_color() ); 00307 fl_rectf( X+rw-row_offset(), Y, B, H ); 00308 } 00309 00310 B = Y + H; 00311 fl_clip( X, Y, W, H ); 00312 // Draw rows 00313 for ( r=top_row(); Y<B && r<rows(); r++, Y+=rh ) 00314 { 00315 rh = row_height(r); 00316 if ( vlast_row==row() || (vlast_row!=row() && (r==vlast_row || r==row())) ) 00317 { 00318 fl_clip( X, Y, W, rh); 00319 CX=X; CY=Y; CW=rw; CH=rh; 00320 draw_row( row_offset(), CX, CY, CW, CH, r ); 00321 fl_pop_clip(); 00322 } 00323 } 00324 vlast_row = row(); 00325 00326 // Fill-in area at bottom of list 00327 if (Y<B) 00328 { 00329 if (parent()) 00330 fl_color( parent()->color() ); 00331 else 00332 fl_color( FL_WHITE ); 00333 fl_rectf( X, Y, W, B-Y ); 00334 } 00335 fl_pop_clip(); 00336 } 00337 00338 00339 void Flv_Table::add_selection_style( Flv_Style &s, int R, int C ) 00340 { 00341 if (!multi_select()) // If not multi row selection 00342 { 00343 select_start_row( row() ); 00344 select_start_col( col() ); 00345 } 00346 if (R>-1 && C>-1) 00347 if ( (select_row() && row_selected(R)) || 00348 (!select_row() && cell_selected(R,C)) ) 00349 { 00350 s.background( selection_color() ); 00351 s.foreground( selection_text_color()); 00352 } 00353 } 00354 00355 void Flv_Table::cell_area(int &X, int &Y, int &W, int &H ) 00356 { 00357 client_area(X,Y,W,H); 00358 if (label() && *label()) 00359 { 00360 Y += row_height(FLV_TITLE); 00361 H -= row_height(FLV_TITLE); 00362 } 00363 00364 if (row_header()) 00365 { 00366 Y += row_height(FLV_ROW_HEADER); 00367 H -= row_height(FLV_ROW_HEADER); 00368 } 00369 if (row_footer()) 00370 { 00371 H -= row_height(FLV_ROW_FOOTER); 00372 } 00373 if (col_header()) 00374 { 00375 X += col_width(FLV_COL_HEADER); 00376 W -= col_width(FLV_COL_HEADER); 00377 } 00378 if (col_footer()) 00379 { 00380 W -= col_width(FLV_COL_FOOTER); 00381 } 00382 } 00383 00384 bool Flv_Table::cell_selected(int R, int C) 00385 { 00386 return (col_selected(C) && row_selected(R)); 00387 } 00388 00389 int Flv_Table::col_width(int C) // Get column width 00390 { 00391 int fw = vcol_width; 00392 Flv_Style *cols; 00393 00394 if (global_style.width_defined()) 00395 fw = global_style.width(); 00396 cols = col_style.find(C); 00397 if (cols) 00398 if (cols->width_defined()) 00399 fw = cols->width(); 00400 return fw; 00401 } 00402 00403 int Flv_Table::col_width(int n, int c) // Set column width 00404 { 00405 int cw = col_width(c); 00406 00407 if (c<-3) c=-3; 00408 if (c>=vcols) c=vcols-1; 00409 if (n<0) n=0; 00410 if (n!=cw) 00411 { 00412 col_style[c].width(n); 00413 damage(FL_DAMAGE_CHILD); 00414 } 00415 return col_width(c); 00416 } 00417 00418 void Flv_Table::get_style( Flv_Style &s, int R, int C ) 00419 { 00420 Flv_Style *rows, *cols, *cells; 00421 00422 Flv_List::get_style( s, R ); 00423 rows = row_style.skip_to(R); 00424 00425 if (R!=-3) 00426 { 00427 cols = col_style.skip_to(C); 00428 if (cols) s = *cols; 00429 } 00430 00431 if (C<0 || R<0) // Headers/Labels have different default 00432 { // Note: we can still override at cell level 00433 if (parent()) 00434 s.background( parent()->color() ); 00435 else 00436 s.background( FL_WHITE ); 00437 s.frame(FL_THIN_UP_BOX); 00438 s.border( FLVB_NONE ); 00439 s.border_spacing(0); 00440 } 00441 00442 cells = (rows?rows->cell_style.skip_to(C):NULL); 00443 if (cells) s = *cells; 00444 } 00445 00446 int Flv_Table::handle(int event) 00447 { 00448 int stat=0, x, y, X,Y,W,H, r, c; 00449 Flv_Style s; 00450 00451 switch(event) 00452 { 00453 case FL_RELEASE: 00454 case FL_DRAG: 00455 if (!vediting || !veditor) 00456 break; 00457 00458 case FL_PUSH: 00459 if (Fl::event_button1()==0) 00460 break; 00461 if (drag_row!=-4 || drag_col!=-4) 00462 break; 00463 x = Fl::event_x(); 00464 y = Fl::event_y(); 00465 if (!vediting) 00466 { 00467 if (edit_when()==FLV_EDIT_MANUAL) 00468 break; 00469 r = row(); 00470 c = col(); 00471 if (r<0 || c<0) 00472 break; 00473 cell_area(X,Y,W,H); 00474 stat = internal_handle(event); 00475 if (stat && r==row() && c==col() && x>=X && x<X+W && y>=Y && y<Y+H ) 00476 { 00477 start_edit(); 00478 return 1; 00479 } 00480 return 0; 00481 } 00482 00483 // If these are occur outside the editor, we don't want the 00484 // child widget processing them 00485 if (x<veditor->x() || y<veditor->y() || x>veditor->x()+veditor->w() || 00486 y>veditor->y()+veditor->h()) 00487 break; 00488 stat = veditor->handle(event); 00489 if (stat) 00490 { 00491 veditor->draw(); 00492 return 1; 00493 } 00494 break; 00495 } 00496 00497 if (event==FL_SHORTCUT && vediting) 00498 { 00499 if (Fl::event_key()==FL_Enter) 00500 { 00501 end_edit(); // Save editor/ quit editing 00502 Fl::focus(this); 00503 // take_focus(); 00504 internal_handle(FL_KEYBOARD); 00505 damage(FL_DAMAGE_CHILD); 00506 return 1; 00507 } 00508 switch( Fl::event_key() ) 00509 { 00510 case FL_Shift_L: 00511 case FL_Shift_R: 00512 case FL_Control_L: 00513 case FL_Control_R: 00514 case FL_Meta_L: 00515 case FL_Meta_R: 00516 case FL_Alt_L: 00517 case FL_Alt_R: 00518 break; 00519 default: 00520 stat = internal_handle(FL_KEYBOARD); 00521 } 00522 } else 00523 { 00524 stat = internal_handle(event); 00525 if (!stat) 00526 { 00527 // Jump start editing if automatic 00528 if (event==FL_KEYBOARD && !vediting && edit_when()==FLV_EDIT_AUTOMATIC ) 00529 { 00530 switch( Fl::event_key() ) 00531 { 00532 case FL_Shift_L: 00533 case FL_Shift_R: 00534 case FL_Control_L: 00535 case FL_Control_R: 00536 case FL_Meta_L: 00537 case FL_Meta_R: 00538 case FL_Alt_L: 00539 case FL_Alt_R: 00540 break; 00541 default: 00542 start_edit(); 00543 if (veditor) 00544 { 00545 stat = veditor->handle(event); 00546 if (stat) 00547 { 00548 Fl::focus(veditor); 00549 // veditor->take_focus(); 00550 veditor->draw(); 00551 return 1; 00552 } 00553 } 00554 cancel_edit(); 00555 } 00556 } 00557 } 00558 } 00559 00560 if (veditor && Fl::focus()==this) 00561 { 00562 Fl::focus(veditor); 00563 // veditor->take_focus(); 00564 veditor->handle(FL_FOCUS); 00565 } 00566 if (stat && veditor) 00567 veditor->draw(); 00568 return stat; 00569 } 00570 00571 int Flv_Table::internal_handle(int event) 00572 { 00573 int TX, TY, r, c, cd, rd; 00574 Flv_Style s; 00575 static int LX, LY; 00576 00577 // Added by ARH to fix compiler warning 00578 r=0; 00579 00580 switch( event ) 00581 { 00582 case FL_KEYBOARD: 00583 break; 00584 00585 case FL_ENTER: 00586 case FL_LEAVE: 00587 vclicks = 0; 00588 return Fl_Group::handle(event); 00589 00590 case FL_FOCUS: 00591 case FL_UNFOCUS: 00592 return 1; 00593 00594 case FL_MOVE: 00595 TY = Fl::event_y(); 00596 TX = Fl::event_x(); 00597 if ( LX-TX<-3 || LX-TX>3 || LY-TY<-3 || LY-TY>3 ) 00598 { 00599 LX = TX; 00600 LY = TY; 00601 vclicks = 0; 00602 } 00603 check_cursor(); 00604 return Fl_Group::handle(event); 00605 00606 case FL_RELEASE: 00607 drag_row = drag_col = -4; 00608 Fl_Group::handle(event); 00609 return 1; 00610 00611 case FL_DRAG: 00612 vclicks=0; 00613 if (check_resize()) 00614 return 1; 00615 case FL_PUSH: 00616 // Dragging not clicking 00617 if (drag_row!=-4 || drag_col != -4) 00618 return 1; 00619 r = 0; 00620 if (Fl::event_button1() && (buttons() & FLV_BUTTON1)) r=1; 00621 if (Fl::event_button2() && (buttons() & FLV_BUTTON2)) r=1; 00622 if (Fl::event_button3() && (buttons() & FLV_BUTTON3)) r=1; 00623 if (r==0) 00624 { 00625 vclicks = 0; 00626 return 0; 00627 } 00628 00629 // Determine if col was clicked and highlight it 00630 TY = Fl::event_y(); 00631 TX = Fl::event_x(); 00632 r = get_row(TX,TY); 00633 c = get_col(TX,TY); 00634 if (r==-4 && c==-4) 00635 { 00636 vclicks = 0; 00637 return Fl_Group::handle(event); 00638 } 00639 if ( LX-TX>-3 && LX-TX<3 && LY-TY>-3 && LY-TY<3) 00640 vclicks++; 00641 else 00642 { 00643 vclicks=1; 00644 LX = TX; 00645 LY = TY; 00646 } 00647 00648 damage(FL_DAMAGE_CHILD); 00649 rd = (r>row()?1:r==row()?0:-1); 00650 cd = (c>col()?1:c==col()?0:-1); 00651 if (r>=0) 00652 row(r); 00653 if (c>=0) 00654 col(c); 00655 00656 if (!multi_select() || 00657 (event==FL_PUSH && !Fl::event_state(FL_SHIFT))) 00658 { 00659 select_start_row(row()); 00660 select_start_col(col()); 00661 } 00662 00663 // At least one header clicked 00664 if (r<0 || c<0) 00665 { 00666 if (r>-4 && c>-4 && r<0 && c<0 && r!=-3) 00667 { 00668 if ( DOcb(FLVEcb_ALL_CLICKED) ) 00669 { 00670 vwhy_event = FLVE_ALL_CLICKED; 00671 do_callback(this, user_data()); 00672 vwhy_event = 0; 00673 } 00674 return 1; 00675 } 00676 00677 if ( c>=0 || r==-3 ) 00678 { 00679 vwhy_event = 0; 00680 switch( r ) 00681 { 00682 case -3: 00683 if (DOcb(FLVEcb_TITLE_CLICKED)) 00684 vwhy_event = FLVE_TITLE_CLICKED; 00685 break; 00686 case -2: 00687 if (DOcb(FLVEcb_ROW_FOOTER_CLICKED)) 00688 vwhy_event = FLVE_ROW_FOOTER_CLICKED; 00689 break; 00690 case -1: 00691 if (DOcb(FLVEcb_ROW_HEADER_CLICKED)) 00692 vwhy_event = FLVE_ROW_HEADER_CLICKED; 00693 break; 00694 } 00695 if (vwhy_event) 00696 { 00697 do_callback(this, user_data()); 00698 vwhy_event = 0; 00699 return 1; 00700 } 00701 } 00702 if ( r>=0 ) 00703 { 00704 vwhy_event = 0; 00705 switch( c ) 00706 { 00707 case -2: 00708 if (DOcb(FLVEcb_COL_FOOTER_CLICKED)) 00709 vwhy_event = FLVE_COL_FOOTER_CLICKED; 00710 break; 00711 case -1: 00712 if (DOcb(FLVEcb_COL_HEADER_CLICKED)) 00713 vwhy_event = FLVE_COL_HEADER_CLICKED; 00714 break; 00715 } 00716 if (vwhy_event) 00717 { 00718 do_callback(this, user_data()); 00719 vwhy_event = 0; 00720 return 1; 00721 } 00722 } 00723 return 0; 00724 } 00725 00726 00727 if (event==FL_PUSH && (rd || cd)) 00728 { 00729 // Skip over locked cells 00730 while(!select_locked()) 00731 { 00732 get_style(s,r,c); 00733 if (!s.locked()) 00734 { 00735 if (r!=row() || c!=col()) 00736 vclicks=0; 00737 row(r); 00738 col(c); 00739 break; 00740 } 00741 r += rd; 00742 c += cd; 00743 if ( r<0 || r>=rows() || c<0 || c>=cols() ) 00744 break; 00745 } 00746 } 00747 if (event==FL_PUSH) 00748 { 00749 if (DOcb(FLVEcb_CLICKED)) 00750 { 00751 vwhy_event = FLVE_CLICKED; 00752 do_callback(this, user_data()); 00753 vwhy_event = 0; 00754 } 00755 if (vclicks>=vmax_clicks) 00756 vclicks=0; 00757 } 00758 return 1; 00759 00760 default: 00761 return Fl_Group::handle(event); 00762 } 00763 00764 switch(Fl::event_key()) 00765 { 00766 case FL_Enter: 00767 switch( vmove_on_enter) 00768 { 00769 case FLV_MOVE_ON_ENTER_ROW_COL: 00770 if (!move_row(1)) 00771 { 00772 row(0); 00773 col(col()+1); 00774 if (!select_locked()) 00775 { 00776 get_style(s,r,col()); 00777 if (!s.locked()) 00778 move_row(1); 00779 } 00780 } 00781 return 1; 00782 case FLV_MOVE_ON_ENTER_COL_ROW: 00783 if (!move_col(1)) 00784 { 00785 col(0); 00786 row(row()+1); 00787 if (!select_locked()) 00788 { 00789 get_style(s,r,col()); 00790 if (!s.locked()) 00791 move_row(1); 00792 } 00793 } 00794 return 1; 00795 } 00796 return 0; 00797 00798 case FL_Up: 00799 if (Fl::event_state(FL_CTRL)) 00800 move_row(-row()); 00801 else 00802 move_row(-1); 00803 break; 00804 00805 case FL_Down: 00806 if (Fl::event_state(FL_CTRL)) 00807 move_row(rows()); 00808 else 00809 move_row(1); 00810 break; 00811 00812 case FL_Page_Down: 00813 if (Fl::event_state(FL_CTRL)) 00814 move_row( rows() ); 00815 else 00816 move_row(page_size()); 00817 break; 00818 00819 case FL_Page_Up: 00820 if (Fl::event_state(FL_CTRL)) 00821 move_row(-row()); 00822 else 00823 move_row(-page_size()); 00824 break; 00825 00826 case FL_Home: 00827 // Adjust rows before columns so we redraw everything 00828 if (Fl::event_state(FL_CTRL)) 00829 move_row(-rows()); 00830 move_col(-cols()); 00831 break; 00832 case FL_End: 00833 // Adjust rows before columns so we redraw everything 00834 if (Fl::event_state(FL_CTRL)) 00835 move_row(rows()); 00836 move_col(cols()); 00837 break; 00838 00839 case FL_Right: 00840 if (select_row()) 00841 return 0; 00842 if (Fl::event_state(FL_CTRL)) 00843 move_col(cols()); 00844 else 00845 move_col(1); 00846 break; 00847 00848 case FL_Left: 00849 if (select_row()) 00850 return 0; 00851 if (Fl::event_state(FL_CTRL)) 00852 move_col(-col()); 00853 else 00854 move_col(-1); 00855 break; 00856 00857 default: 00858 return Fl_Group::handle(event); 00859 } 00860 00861 if (!multi_select() || !Fl::event_state(FL_SHIFT)) 00862 { 00863 select_start_col(col()); 00864 select_start_row(row()); 00865 } 00866 return 1; 00867 } 00868 00869 int Flv_Table::row(int n) 00870 { 00871 int X,Y,W,H; 00872 00873 if (n>=rows()) 00874 n=rows()-1; 00875 if (n<0) 00876 n=0; 00877 if (n!=vrow) 00878 { 00879 vrow = n; 00880 client_area(X,Y,W,H); 00881 update_top_row(H); 00882 end_edit(); 00883 if (edit_when()==FLV_EDIT_ALWAYS) 00884 switch_editor( row(), col() ); 00885 vlast_row = vrow; 00886 if (DOcb(FLVEcb_ROW_CHANGED)) 00887 { 00888 vwhy_event = FLVE_ROW_CHANGED; 00889 do_callback(this, user_data()); 00890 vwhy_event = 0; 00891 } 00892 damage(FL_DAMAGE_CHILD); 00893 } 00894 return vrow; 00895 } 00896 00897 int Flv_Table::col( int n ) 00898 { 00899 Flv_Style s; 00900 00901 if (n>=vcols) 00902 n=vcols-1; 00903 if (n<0) 00904 n=0; 00905 if (n!=vcol) 00906 { 00907 vcol = n; 00908 end_edit(); 00909 if (edit_when()==FLV_EDIT_ALWAYS) 00910 switch_editor( row(), col() ); 00911 00912 adjust_for_cell(); 00913 if (DOcb(FLVEcb_COL_CHANGED)) 00914 { 00915 vwhy_event = FLVE_COL_CHANGED; 00916 do_callback(this, user_data()); 00917 vwhy_event = 0; 00918 } 00919 damage(FL_DAMAGE_CHILD); 00920 } 00921 return vcol; 00922 } 00923 00924 bool Flv_Table::col_resizable(int c) // Get/set column locked status 00925 { 00926 Flv_Style *s; 00927 bool l=true; 00928 if (global_style.resizable_defined()) 00929 l = global_style.resizable(); 00930 s = col_style.find(c); 00931 if (s) 00932 if (s->resizable_defined()) 00933 l = s->resizable(); 00934 return l; 00935 } 00936 00937 bool Flv_Table::col_resizable( bool n, int c) 00938 { 00939 col_style[c].resizable(n); 00940 return n; 00941 } 00942 00943 int Flv_Table::cols( int n ) 00944 { 00945 if (n>=0 && n!=vcols) 00946 { 00947 vcols = n; 00948 if (vcol>=vcols) 00949 col(vcols-1); 00950 if (vselect_col>vcol) 00951 select_start_col(vcol); 00952 update_width(); 00953 if (DOcb(FLVEcb_COLS_CHANGED)) 00954 { 00955 vwhy_event = FLVE_COLS_CHANGED; 00956 do_callback(this, user_data()); 00957 vwhy_event = 0; 00958 } 00959 damage(FL_DAMAGE_CHILD); 00960 } 00961 return vcols; 00962 } 00963 00964 bool Flv_Table::col_selected(int n) 00965 { 00966 if (vselect_col<vcol) 00967 return (vselect_col<=n && n<=vcol); 00968 else 00969 return (vcol<=n && n<=vselect_col); 00970 } 00971 00972 // Get column from x,y 00973 int Flv_Table::get_col( int x, int y ) 00974 { 00975 int X, Y, W, H, CX; 00976 int rw, cw, t, Offset; 00977 00978 client_area(X,Y,W,H); 00979 if (label()) 00980 { 00981 cw = row_height(-3); 00982 Y+=cw; 00983 H-=cw; 00984 } 00985 if (col_header()) 00986 { 00987 cw = col_width(-1); 00988 if (X<=x && x<=X+cw) 00989 return -1; 00990 X+=cw; 00991 W-=cw; 00992 } 00993 if (col_footer()) 00994 { 00995 cw = col_width(-2); 00996 if (X+W>=x && x>=X+W-cw) 00997 return -2; 00998 W -= cw; 00999 } 01000 01001 rw = row_width(); 01002 if (!rw) 01003 rw = W; 01004 if ( x<X || x>=X+W || y<Y || y>=Y+H || x>X-row_offset()+rw) 01005 return -4; 01006 01007 Offset = row_offset(); 01008 for (CX=X, t=0; t<vcols && CX-Offset<X+W; t++, CX+=cw ) 01009 { 01010 cw = col_width(t); 01011 if (x>=CX-Offset && x<CX-Offset+cw) 01012 return t; 01013 } 01014 return -4; // In grey area at bottom? 01015 } 01016 01017 int Flv_Table::select_start_col(int n) 01018 { 01019 if (n>=vcols) 01020 n=vcols-1; 01021 if (n<0) 01022 n=0; 01023 if (n!=vselect_col) 01024 { 01025 vselect_col = n; 01026 if (DOcb(FLVEcb_SELECTION_CHANGED)) 01027 { 01028 vwhy_event = FLVE_SELECTION_CHANGED; 01029 do_callback(this, user_data()); 01030 vwhy_event = 0; 01031 } 01032 damage(FL_DAMAGE_CHILD); 01033 } 01034 return vselect_col; 01035 } 01036 01037 void Flv_Table::update_width() 01038 { 01039 int rw, n; 01040 01041 for (rw=n=0; n<vcols; n++ ) 01042 rw+=(col_width(n)); 01043 if (col_header()) 01044 rw+=col_width(-1); 01045 if (col_footer()) 01046 rw+=col_width(-2); 01047 if (rw!=row_width()) 01048 { 01049 row_width(rw); 01050 damage(FL_DAMAGE_CHILD); 01051 } 01052 } 01053 01054 void Flv_Table::adjust_for_cell() 01055 { 01056 int n, o, cw; 01057 int X, Y, W, H; 01058 01059 for (n=o=0; n<col(); n++ ) 01060 o+=col_width(n); 01061 if (row_offset()>o) 01062 row_offset(o); 01063 else 01064 { 01065 client_area(X,Y,W,H); 01066 if (col_footer()) 01067 W -= col_width(-2); 01068 if (col_header()) 01069 W -= col_width(-2); 01070 cw = col_width(col()); 01071 if (o+cw-row_offset()>W) 01072 { 01073 row_offset(o+cw-W); 01074 damage(FL_DAMAGE_CHILD); 01075 } 01076 } 01077 } 01078 01079 bool Flv_Table::check_resize(void) 01080 { 01081 int ex, ey, v; 01082 int X, Y, W, H; 01083 01084 if (drag_row<-3 && drag_col<-2) 01085 return false; 01086 01087 client_area(X,Y,W,H); 01088 ex = Fl::event_x(); 01089 ey = Fl::event_y(); 01090 01091 if (drag_row==-3) 01092 { 01093 v = ey-anchor_top; 01094 if (v<2) v=2; 01095 row_style[drag_row].height(v); 01096 damage(FL_DAMAGE_CHILD); 01097 return true; 01098 } 01099 01100 if (label() && *label()) 01101 { 01102 Y += row_height(-3); 01103 H -= row_height(-3); 01104 } 01105 01106 if (drag_col>-3) 01107 { 01108 if (drag_col==-2) 01109 { 01110 v = anchor_left - ex + col_width(drag_col); 01111 if (col_header()) 01112 { 01113 X += col_width(-1); 01114 W -= col_width(-1); 01115 } 01116 if (v>W-1) 01117 { 01118 v = W-1; 01119 anchor_left = X+W-v; 01120 } 01121 if (v<2) 01122 { 01123 v=2; 01124 anchor_left = X+W-2; 01125 } 01126 col_style[drag_col].width(v); 01127 damage(FL_DAMAGE_CHILD); 01128 if (v!=W-1 && v!=2) 01129 anchor_left = ex; 01130 } else 01131 { 01132 v = ex-anchor_left; 01133 if (drag_col==-1) 01134 { 01135 // Make sure it's in the grid 01136 if (col_footer()) 01137 W-=col_width(-2); 01138 if (v > W-1 ) 01139 v = W-1; 01140 } 01141 if (v<2) 01142 v=2; 01143 col_width(v,drag_col); 01144 damage(FL_DAMAGE_CHILD); 01145 } 01146 } 01147 01148 // Resize row 01149 if (drag_row>-4) 01150 { 01151 if (drag_row==-2) 01152 { 01153 v = anchor_top - ey + row_height(drag_row); 01154 if (row_header()) 01155 { 01156 H-=row_height(-1); 01157 Y+=row_height(-1); 01158 } 01159 if (v>H-1) 01160 { 01161 v = H-1; 01162 anchor_top = Y+H-v; 01163 } 01164 if (v<2) 01165 { 01166 v = 2; 01167 anchor_top = Y+H-2; 01168 } 01169 row_style[drag_row].height(v); 01170 damage(FL_DAMAGE_CHILD); 01171 if (v!=2 && v!=H-1) 01172 anchor_top = ey; 01173 } else 01174 { 01175 v = ey-anchor_top; 01176 if (drag_row==-1) 01177 { 01178 if (row_footer()) 01179 H-=row_height(-2); 01180 if (v>H-1) 01181 v = H-1; 01182 } 01183 if (v<2) v=2; 01184 row_height(v,drag_row); 01185 damage(FL_DAMAGE_CHILD); 01186 } 01187 } 01188 return true; 01189 } 01190 01191 // See if we can resize, if so change cursor 01192 void Flv_Table::check_cursor(void) 01193 { 01194 int X, Y, W, H, R, ey, ex, move=0, WW, size; 01195 int v; 01196 bool resize, inh, inv; 01197 Fl_Cursor cursor; 01198 01199 // Assume total miss 01200 drag_row = drag_col = -4; 01201 cursor = FL_CURSOR_DEFAULT; 01202 01203 ex = Fl::event_x(); 01204 ey = Fl::event_y(); 01205 client_area(X,Y,W,H); 01206 inh = (ex>=X && ex<X+W); 01207 inv = (ey>=Y && ey<Y+H); 01208 01209 if (label() && *label()) 01210 { 01211 size = row_height(-3); 01212 Y+=size; 01213 H-=size; 01214 resize = (ey>=Y-FUDGE && ey<=Y+FUDGE && inh); 01215 if (resize) 01216 { 01217 if (row_resizable(-3)) 01218 { 01219 drag_row = -3; 01220 anchor_top = Y-size; 01221 move |= MOVE_Y; 01222 } 01223 } 01224 } 01225 01226 // Trival tests to see if we're in region 01227 resize = full_resize(); 01228 if (!resize) 01229 { 01230 if (row_header()) 01231 { 01232 size = row_height(-1); 01233 resize |= (ey>=Y && ey<=Y+size+FUDGE && inh); 01234 } 01235 if (!resize) 01236 { 01237 if (row_footer()) 01238 { 01239 size = row_height(-2); 01240 resize |= (ey<=Y+H && ey>=Y+H-size-FUDGE && inh); 01241 } 01242 if (!resize) 01243 { 01244 if (col_header()) 01245 { 01246 size = col_width(-1); 01247 resize |= (ex>=X && ex<=X+size+FUDGE && inh); 01248 } 01249 if (!resize) 01250 { 01251 if (col_footer()) 01252 { 01253 size = col_width(-2); 01254 resize |= (ex<=X+W && ex>=X+W-size-FUDGE && inh); 01255 } 01256 } 01257 } 01258 } 01259 } 01260 01261 if (!resize) // In general region? 01262 { 01263 if (cursor!=last_cursor) 01264 { 01265 fl_cursor(cursor,FL_BLACK,FL_WHITE); 01266 last_cursor = cursor; 01267 } 01268 return; 01269 } 01270 01271 // ================================================================== 01272 // Sweep columns 01273 WW = X; 01274 if (col_header()) 01275 { 01276 size = col_width(-1); 01277 if (ex>=WW+size-FUDGE && ex<=WW+size+FUDGE && inv) 01278 { 01279 if (col_resizable(-1) && (move & MOVE_Y)==0) 01280 { 01281 drag_col = -1; 01282 anchor_left = WW; 01283 move |= MOVE_X; 01284 } 01285 } 01286 WW += size; 01287 X += size; 01288 W -= size; 01289 } 01290 01291 if (col_footer()) 01292 { 01293 size = col_width(-2); 01294 if (ex>=X+W-size-FUDGE && ex<=X+W-size+FUDGE && inv) 01295 { 01296 if (col_resizable(-2)) 01297 { 01298 drag_col = -2; 01299 anchor_left = ex; 01300 move |= MOVE_X; 01301 } 01302 } 01303 W -= size; 01304 } 01305 01306 if ( (move & MOVE_X)==0 ) 01307 { 01308 R = X-row_offset()+row_width()+FUDGE; // Right edge of row 01309 for (WW-=row_offset(), v=0; WW<R && WW<X+W && v<cols(); WW+=size, v++ ) 01310 { 01311 size = col_width(v); 01312 if (WW+size<X) // Off left 01313 continue; 01314 if (ex>=WW+size-FUDGE && ex<=WW+size+FUDGE && inv) 01315 { 01316 if (col_resizable(v)) 01317 { 01318 drag_col = v; 01319 anchor_left = WW; 01320 move |= MOVE_X; // Moving col 01321 } 01322 break; 01323 } 01324 } 01325 } 01326 if (col_header()) 01327 { 01328 X-=col_width(-1); 01329 W+=col_width(-1); 01330 } 01331 if (col_footer()) 01332 W+=col_width(-2); 01333 01334 // ================================================================== 01335 // Sweep rows 01336 WW = Y; 01337 if (row_header()) 01338 { 01339 size = row_height(-1); 01340 if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE && inh) 01341 { 01342 if (row_resizable(-1)) 01343 { 01344 drag_row = -1; 01345 anchor_top = WW; 01346 move |= MOVE_Y; 01347 } 01348 } 01349 WW += size; 01350 Y += size; 01351 H -= size; 01352 } 01353 if (row_footer()) 01354 { 01355 size = row_height(-2); 01356 if (ey>=Y+H-size-FUDGE && ey<=Y+H-size+FUDGE && inh) 01357 { 01358 if (row_resizable(-2)) 01359 { 01360 drag_row = -2; 01361 anchor_top = ey; 01362 move |= MOVE_Y; 01363 } 01364 } 01365 H -= size; 01366 } 01367 if ( (move & MOVE_Y)==0 ) 01368 { 01369 for (v=top_row(); v<rows(); WW+=size, v++ ) 01370 { 01371 size = row_height(v); 01372 if (WW+size-FUDGE>=Y+H) 01373 break; 01374 if (ey>=WW+size-FUDGE && ey<=WW+size+FUDGE && inh) 01375 { 01376 if (row_resizable(v)) 01377 { 01378 drag_row = v; 01379 anchor_top = WW; 01380 move |= MOVE_Y; // Moving 01381 } 01382 break; 01383 } 01384 } 01385 } 01386 01387 switch( move ) 01388 { 01389 case MOVE_X: cursor = FL_CURSOR_WE; drag_row=-4; break; 01390 case MOVE_Y: cursor = FL_CURSOR_NS; drag_col=-4; break; 01391 case MOVE_XY: cursor = FL_CURSOR_NWSE; break; 01392 default: 01393 drag_row = drag_col = -4; 01394 cursor = FL_CURSOR_DEFAULT; 01395 break; 01396 } 01397 if (cursor!=last_cursor) 01398 { 01399 fl_cursor(cursor,FL_BLACK,FL_WHITE); 01400 last_cursor = cursor; 01401 } 01402 } 01403 01404 bool Flv_Table::move_row( int amount ) 01405 { 01406 Flv_Style s; 01407 int r = row(); 01408 01409 if (!amount) 01410 return true; 01411 01412 r += amount; 01413 if (r>=rows()) 01414 r = rows()-1; 01415 if (r<0) 01416 r = 0; 01417 01418 while(!select_locked()) 01419 { 01420 get_style(s,r,col()); 01421 if (!s.locked()) 01422 break; 01423 r += (amount<0?-1:1); 01424 if ( r<0 || r>=rows() ) 01425 return false; 01426 } 01427 if (r!=row()) 01428 { 01429 row(r); 01430 return true; 01431 } 01432 return false; 01433 } 01434 01435 bool Flv_Table::move_col( int amount ) 01436 { 01437 Flv_Style s; 01438 int c = col(); 01439 01440 if (!amount) 01441 return true; 01442 01443 c += amount; 01444 if (c>=cols()) 01445 c = cols()-1; 01446 if (c<0) 01447 c = 0; 01448 01449 while(!select_locked()) 01450 { 01451 get_style(s,row(),c); 01452 if (!s.locked()) 01453 break; 01454 c += (amount<0?-1:1); 01455 if ( c<0 || c>=rows() ) 01456 return false; 01457 } 01458 if (c!=col()) 01459 { 01460 col(c); 01461 return true; 01462 } 01463 return false; 01464 } 01465 01466 01467 int Flv_Table::edit_when( int v ) 01468 { 01469 int wfocused = (Fl::focus()==veditor); 01470 if (v!=vedit_when) 01471 { 01472 vedit_when = v; 01473 if (vedit_when!=FLV_EDIT_ALWAYS) 01474 end_edit(); 01475 else 01476 start_edit(); 01477 } 01478 if (wfocused && !vediting) 01479 { 01480 Fl::focus(this); 01481 // take_focus(); 01482 redraw(); 01483 } 01484 return vedit_when; 01485 } 01486 01487 01488 void Flv_Table::start_edit(void) // Start editing 01489 { 01490 if (!vediting) 01491 { 01492 vediting = true; 01493 switch_editor( row(), col() ); 01494 } 01495 } 01496 01497 void Flv_Table::end_edit(void) 01498 { 01499 int wfocused = (Fl::focus()==veditor); 01500 if (veditor) 01501 switch_editor(-1,-1); 01502 if (wfocused && !vediting) 01503 { 01504 Fl::focus(this); 01505 // take_focus(); 01506 redraw(); 01507 } 01508 } 01509 01510 void Flv_Table::cancel_edit(void) // Cancel editing 01511 { 01512 int wfocused = (Fl::focus()==veditor); 01513 if (veditor) 01514 { 01515 veditor->hide(); 01516 veditor->draw(); 01517 } 01518 veditor = NULL; 01519 edit_row = -1; 01520 edit_col = -1; 01521 vediting = false; 01522 // switch_editor(-1, -1); 01523 if (wfocused && !vediting) 01524 { 01525 Fl::focus(this); 01526 // take_focus(); 01527 redraw(); 01528 } 01529 } 01530 01531 void Flv_Table::switch_editor( int nr, int nc ) 01532 { 01533 Flv_Style s; 01534 int x, y, w, h, wfocused; 01535 // char buf[30]; 01536 01537 wfocused = (Fl::focus()==veditor); 01538 01539 if (veditor) 01540 { 01541 if (edit_row>-1 && edit_col>-1) 01542 save_editor( veditor, edit_row, edit_col ); 01543 edit_row=-1; 01544 edit_col=-1; 01545 veditor->hide(); 01546 veditor->draw(); 01547 veditor = NULL; 01548 } 01549 if (edit_when()==FLV_EDIT_ALWAYS) 01550 { 01551 vediting = true; 01552 if (nr<0) 01553 nr = row(); 01554 if (nc<0) 01555 nc = col(); 01556 } 01557 01558 if (nr>-1 && nc>-1 && vediting) 01559 { 01560 get_style( s, nr, nc ); 01561 if (s.editor_defined() && !s.locked()) 01562 { 01563 veditor = s.editor(); 01564 if (veditor) 01565 { 01566 edit_row = nr; 01567 edit_col = nc; 01568 veditor->hide(); 01569 get_cell_bounds(x,y,w,h,nr,nc); 01570 position_editor(veditor, x,y,w,h, s); 01571 load_editor( veditor, nr, nc ); 01572 veditor->show(); 01573 Fl::focus(veditor); 01574 // veditor->take_focus(); 01575 veditor->handle(FL_FOCUS); 01576 veditor->damage(FL_DAMAGE_ALL); 01577 veditor->draw(); 01578 } 01579 } 01580 } 01581 if (!veditor) 01582 { 01583 vediting=false; 01584 edit_row=-1; 01585 edit_col=-1; 01586 } 01587 if (!veditor && wfocused) 01588 { 01589 Fl::focus(this); 01590 // take_focus(); 01591 handle(FL_FOCUS); 01592 } 01593 } 01594