core/vgui/vgui_grid_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_grid_tableau.cxx
00002 #include "vgui_grid_tableau.h"
00003 //:
00004 // \file
00005 // \brief   See vgui_grid_tableau.h for a description of this file.
00006 
00007 #include <vcl_iostream.h>
00008 #include <vgui/vgui_macro.h>
00009 #include <vgui/vgui_clear_tableau.h>
00010 
00011 bool operator==(vgui_grid_tableau_data const &a,
00012                 vgui_grid_tableau_data const &b)
00013 {
00014   return
00015     a.handle == b.handle &&
00016     a.tab_pos == b.tab_pos &&
00017     a.is_default == b.is_default &&
00018     a.time_selected == b.time_selected;
00019 }
00020 
00021 //------------------------------------------------------------------------------
00022 // Initialisation, constructors and destructor.
00023 //------------------------------------------------------------------------------
00024 void vgui_grid_tableau::init(unsigned initial_cols, unsigned initial_rows)
00025 {
00026   cond_row_add    = vgui_event_condition(vgui_key('='), vgui_CTRL);
00027   cond_row_remove = vgui_event_condition(vgui_key('-'), vgui_CTRL);
00028   cond_col_add    = vgui_event_condition(vgui_key('='));
00029   cond_col_remove = vgui_event_condition(vgui_key('-'));
00030   cond_flip_fwd   = vgui_event_condition(vgui_PAGE_DOWN);
00031   cond_flip_bwd   = vgui_event_condition(vgui_PAGE_UP);
00032   cond_select     = vgui_event_condition(vgui_LEFT);
00033   cond_deselect   = vgui_event_condition(vgui_MIDDLE);
00034 
00035   INCREMENT_COLS = 50;
00036   INCREMENT_ROWS = 50;
00037 
00038   grid_size_changeable = true;
00039   unique_selected_ = false;
00040 
00041 #ifdef DEBUG
00042     vcl_cerr << "vgui_grid_tableau::init: initialising grid with "
00043              << initial_cols << " columns and " << initial_rows << " rows\n";
00044 #endif
00045   nb_cols = initial_cols;
00046   nb_rows = initial_rows;
00047   max_cols = initial_cols + INCREMENT_COLS;
00048   max_rows = initial_rows + INCREMENT_ROWS;
00049   last_selected[0] = last_selected[1] = 0;
00050   default_tab = vgui_clear_tableau_new();
00051 
00052   grid_pos = vbl_array_2d<grid_data>(max_cols, max_rows);
00053   for (unsigned i = 0; i < nb_cols; i++)
00054   {
00055     for (unsigned j = 0; j < nb_rows; j++)
00056     {
00057       add_default(i, j);
00058     }
00059   }
00060 }
00061 
00062 //------------------------------------------------------------------------------
00063 //: Makes a bitab.
00064 //------------------------------------------------------------------------------
00065 vgui_grid_tableau::vgui_grid_tableau(vgui_tableau_sptr const& l, vgui_tableau_sptr const& r)
00066 {
00067   init(2, 1);
00068   add_next(l);
00069   add_next(r);
00070 }
00071 
00072 //------------------------------------------------------------------------------
00073 //: Makes a tritab.
00074 //------------------------------------------------------------------------------
00075 vgui_grid_tableau::vgui_grid_tableau(vgui_tableau_sptr const& l, vgui_tableau_sptr const& m, vgui_tableau_sptr const& r)
00076 {
00077   init(3, 1);
00078   add_next(l);
00079   add_next(m);
00080   add_next(r);
00081 }
00082 
00083 //------------------------------------------------------------------------------
00084 //: Given the column number, returns the x coord for that column.
00085 //  Note col_pos is numbered from 0.
00086 //------------------------------------------------------------------------------
00087 float vgui_grid_tableau::get_x(unsigned col_pos)
00088 {
00089   if (col_pos < nb_cols)
00090     return col_pos * get_w();
00091   else
00092   {
00093     vgui_macro_warning << "Error in get_x: col_pos = " << col_pos << ", max = " << nb_cols << vcl_endl;
00094     return 0;
00095   }
00096 }
00097 
00098 //------------------------------------------------------------------------------
00099 //: Given the row number, returns the y coord for that row.
00100 //  Note row_pos is numbered from 0.
00101 //  Note that poly_tableau coord system starts in the bottom left and we want
00102 //  rows to be numbered from the top down.
00103 //------------------------------------------------------------------------------
00104 float vgui_grid_tableau::get_y(unsigned row_pos)
00105 {
00106   if (row_pos < nb_rows)
00107     return (nb_rows - row_pos - 1) * get_h();
00108   else
00109   {
00110     vgui_macro_warning << "Error in get_y: row_pos = " << row_pos << ", max = " << nb_rows << vcl_endl;
00111     return 0;
00112   }
00113 }
00114 
00115 //------------------------------------------------------------------------------
00116 //: Get the width of each column.
00117 //------------------------------------------------------------------------------
00118 float vgui_grid_tableau::get_w() { return 1.0f/nb_cols; }
00119 
00120 //------------------------------------------------------------------------------
00121 //: Get the height of each row.
00122 //------------------------------------------------------------------------------
00123 float vgui_grid_tableau::get_h() { return 1.0f/nb_rows; }
00124 
00125 //------------------------------------------------------------------------------
00126 //: Adds the default tableau to the given space in the grid (but not to the vcl_list of tableaux).
00127 //  Note, it is assumed that the given grid position is empty or uninitialized
00128 //  so nothing is removed from the grid position before the default is added.
00129 //------------------------------------------------------------------------------
00130 void vgui_grid_tableau::add_default(unsigned col_pos, unsigned row_pos)
00131 {
00132   if (col_pos < nb_cols && row_pos < nb_rows)
00133   {
00134     grid_pos(col_pos, row_pos).handle
00135       = this->add(default_tab, get_x(col_pos), get_y(row_pos), get_w(), get_h());
00136     grid_pos(col_pos, row_pos).tab_pos = -1;
00137     grid_pos(col_pos, row_pos).is_default = true;
00138     grid_pos(col_pos, row_pos).time_selected = -1;
00139   }
00140 }
00141 
00142 
00143 //------------------------------------------------------------------------------
00144 //: Adds a tableau to the next free space in the grid and to the end of the vcl_list of tableaux.
00145 //  If there are no free spaces and the grid size is changeable then it adds a
00146 //  new column to the RHS of the grid and adds the new tableau to the top of it.
00147 //------------------------------------------------------------------------------
00148 void vgui_grid_tableau::add_next(vgui_tableau_sptr const& tab, unsigned& col,
00149                                  unsigned& row)
00150 {
00151   tabs.push_back(tab);
00152 
00153   for (unsigned j = 0; j < nb_rows; j++)
00154   {
00155     for (unsigned i = 0; i < nb_cols; i++)
00156     {
00157        // Find the next space in the grid without a tableau:
00158        if (grid_pos(i,j).is_default)
00159        {
00160          this->remove(grid_pos(i,j).handle);
00161          grid_pos(i,j).handle = this->add(tab, get_x(i), get_y(j), get_w(), get_h());
00162          grid_pos(i,j).tab_pos = tabs.size() - 1;
00163          grid_pos(i,j).is_default = false;
00164 #ifdef DEBUG
00165          vcl_cerr << "vgui_grid_tableau::add_next: adding tableau to col = "<< i <<", row = "<< j << '\n';
00166 #endif
00167          row = j; col = i;
00168          return;
00169        }
00170     }
00171   }
00172   // fsm: this flag should control how events are handled, not whether a client
00173   // can change the layout of the grid tableau.
00174   //if (uses_plus_minus_events)
00175 
00176   // kym: only because you gave it that funny name!!!  I'm putting this back in here
00177   // (with its original name) because I think it is needed. Events are handled separately
00178   if (grid_size_changeable)
00179   {
00180     // If we have got here then there are no free spaces in the grid.
00181 #ifdef DEBUG
00182     vcl_cerr << "vgui_grid_tableau::add_next: current grid is full, adding another column\n";
00183 #endif
00184     add_column();
00185     unsigned col_pos = nb_cols - 1;
00186     unsigned row_pos = 0;
00187     this->remove(grid_pos(col_pos, row_pos).handle);
00188     grid_pos(col_pos, row_pos).handle
00189       = this->add(tab, get_x(col_pos), get_y(row_pos), get_w(), get_h());
00190     grid_pos(col_pos, row_pos).tab_pos = tabs.size() - 1;
00191     grid_pos(col_pos, row_pos).is_default = false;
00192 #ifdef DEBUG
00193     vcl_cerr << "vgui_grid_tableau::add_next: adding tableau to col = "<< col_pos <<", row = "<< row_pos << '\n';
00194 #endif
00195     row = row_pos; col = col_pos;
00196   }
00197 }
00198 
00199 void vgui_grid_tableau::add_next(vgui_tableau_sptr const& tab)
00200 {
00201   unsigned row=0, col = 0;
00202   if (!row&&!col)this->add_next(tab, col, row);//suppress warnings
00203 }
00204 
00205 //------------------------------------------------------------------------------
00206 //: Add (or replace the tableau at the given position with) the given tableau.
00207 //  Adds the given tableau to the end of the vcl_list of tableaux.
00208 //------------------------------------------------------------------------------
00209 void vgui_grid_tableau::add_at(vgui_tableau_sptr const& tab, unsigned col_pos, unsigned row_pos)
00210 {
00211   // This function leaks core because a tableau which is replaced by another
00212   // is still referenced by the smart pointer in `tabs'. why do we need a
00213   // separate array of tableaux? can't we just put them in the grid_data
00214   // structure? -- fsm
00215 
00216   // kym - This isn't a core leak!! It is intentional that pointers to
00217   // tableaux are kept - this means that we can flip through the list of
00218   // tableaux using page up and down but not display all tableaux at the
00219   // same time (see xcv for an example of this).  Each grid position provides
00220   // a view of the deck of tableaux kept in 'tabs'.
00221   if (col_pos < nb_cols && row_pos < nb_rows)
00222   {
00223 #ifdef DEBUG
00224     vcl_cerr << "vgui_grid_tableau::add_at: adding tableau at col = "<< col_pos <<", row = "<< row_pos << '\n';
00225 #endif
00226     tabs.push_back(tab);
00227     this->remove(grid_pos(col_pos, row_pos).handle);
00228     grid_pos(col_pos, row_pos).handle = this->add(tab, get_x(col_pos), get_y(row_pos), get_w(), get_h());
00229     grid_pos(col_pos, row_pos).tab_pos = tabs.size()-1;
00230     grid_pos(col_pos, row_pos).is_default = false;
00231     layout_grid();
00232   }
00233   else {
00234     vcl_cerr << __FILE__ ": in add_at():\n"
00235              << __FILE__ ": nb_cols nb_rows = " << nb_cols << ' ' << nb_rows << vcl_endl
00236              << __FILE__ ": col_pos row_pos = " << col_pos << ' ' << row_pos << vcl_endl;
00237   }
00238 }
00239 
00240 //------------------------------------------------------------------------------
00241 //: Removes the tableau at the given grid coordinates from the display and from the vcl_list of tableau.
00242 //  It is replaced in the grid by the default tableau.
00243 //------------------------------------------------------------------------------
00244 void vgui_grid_tableau::remove_at(unsigned col_pos, unsigned row_pos)
00245 {
00246 #ifdef DEBUG
00247   vcl_cerr << "vgui_grid_tableau::remove_at: removing tableau at col = " << col_pos << ", row = " << row_pos << '\n';
00248 #endif
00249   if (col_pos < nb_cols && row_pos < nb_rows)
00250   {
00251     if (! grid_pos(col_pos, row_pos).is_default)
00252     {
00253       this->remove(grid_pos(col_pos, row_pos).handle);
00254       tabs.erase(tabs.begin() + grid_pos(col_pos, row_pos).tab_pos);
00255       grid_pos(col_pos, row_pos).handle
00256         = this->add(default_tab, get_x(col_pos), get_y(row_pos), get_w(), get_h());
00257       grid_pos(col_pos, row_pos).tab_pos = -1;
00258       grid_pos(col_pos, row_pos).is_default = true;
00259       layout_grid();
00260     }
00261   }
00262   else {
00263     vcl_cerr << __FILE__ ": in remove_at():\n"
00264              << __FILE__ ": nb_cols nb_rows = " << nb_cols << ' ' << nb_rows << vcl_endl
00265              << __FILE__ ": col_pos row_pos = " << col_pos << ' ' << row_pos << vcl_endl;
00266   }
00267 }
00268 
00269 //------------------------------------------------------------------------------
00270 //: Returns a pointer to the tableau at the given position.
00271 //------------------------------------------------------------------------------
00272 vgui_tableau_sptr vgui_grid_tableau::get_tableau_at(unsigned col_pos, unsigned row_pos)
00273 {
00274   if (col_pos < nb_cols && row_pos < nb_rows &&
00275       ! grid_pos(col_pos, row_pos).is_default)
00276     return this->get(grid_pos(col_pos, row_pos).handle);
00277 
00278   if (col_pos >= nb_cols)
00279     vgui_macro_warning << "Given column number " << col_pos
00280                        << " is out of range, max value = " << nb_cols-1 << vcl_endl;
00281   else if ( row_pos >= nb_rows)
00282     vgui_macro_warning << "Given row number " << row_pos
00283                        << " is out of range, max value = " << nb_rows-1 << vcl_endl;
00284 #ifdef DEBUG
00285   else vgui_macro_warning << "Only default tableau at (" << col_pos << ", " << row_pos << ").\n";
00286 #endif
00287   return vgui_tableau_sptr();
00288 }
00289 
00290 //------------------------------------------------------------------------------
00291 //:  Returns the bounds of the grid cell in screen coordinates at the specified col and row.
00292 //   The computation is based on dividing the entire viewport by the number of row and columns.
00293 //------------------------------------------------------------------------------
00294 bool vgui_grid_tableau::cell_bounding_box(unsigned col, unsigned row,
00295                                           float& xmin, float& ymin,
00296                                           float& xmax, float& ymax)
00297 {
00298   if (col>=nb_cols || row>=nb_rows)
00299     return false;
00300   vgui_poly_tableau_vp_sc_snapshot snap;
00301   float x0 = snap.vp[0], y0 = snap.vp[1];
00302   float w  = snap.vp[2],  h = snap.vp[3];
00303   float dx = w/nb_cols, dy = h/nb_rows;
00304   xmin = x0 + col*dx; ymin = y0 + row*dy;
00305   xmax = xmin + dx; ymax = ymin + dy;
00306   return true;
00307 }
00308 
00309 //------------------------------------------------------------------------------
00310 //: Returns the active tableau, this is the tableau with the mouse in.
00311 //  Note that there is only one active tableau, while there may be many
00312 //  selected tableaux.
00313 //------------------------------------------------------------------------------
00314 void vgui_grid_tableau::get_active_position(unsigned* col_pos, unsigned* row_pos)
00315 {
00316   *col_pos = nb_cols + 1;
00317   *row_pos = nb_rows + 1;
00318   int current_handle;
00319   current_handle = this->get_current_id();
00320 
00321   if (current_handle == -1)
00322   {
00323     return;
00324   }
00325 
00326   for (unsigned i = 0; i < nb_cols; i++)
00327   {
00328     for (unsigned j = 0; j < nb_rows; j++)
00329     {
00330       if (grid_pos(i,j).handle == current_handle)
00331       {
00332         *col_pos = i;
00333         *row_pos = j;
00334         return;
00335       }
00336     }
00337   }
00338 }
00339 
00340 //------------------------------------------------------------------------------
00341 //: Returns the most recently selected column and row positions.
00342 //------------------------------------------------------------------------------
00343 void vgui_grid_tableau::get_last_selected_position(
00344   unsigned* col_pos, unsigned* row_pos)
00345 {
00346   *col_pos = last_selected[0];
00347   *row_pos = last_selected[1];
00348 }
00349 
00350 //------------------------------------------------------------------------------
00351 //: Select a certain tableau
00352 //------------------------------------------------------------------------------
00353 void vgui_grid_tableau::set_selected(int r, int c, bool onoff)
00354 {
00355   int time = onoff ? 1000 : -1;
00356 
00357   if ((unsigned int)r < nb_rows && (unsigned int)c < nb_cols) {
00358     grid_pos(c,r).time_selected = time;
00359   } else {
00360     vcl_cerr << "vgui_grid_tableau::set_selected: (r,c) > (cols,rows)\n";
00361   }
00362 }
00363 
00364 //------------------------------------------------------------------------------
00365 //: Gets the positions and times of selection of the selected tableaux.
00366 //  The number of selected tableau is returned.  Their positions are returned
00367 //  in the vcl_vectors passed in as parameters.
00368 //  Note, a tableau is selected if it has been clicked on by the left mouse
00369 //  button.  It can be deselected by clicking with the middle mouse button.
00370 //------------------------------------------------------------------------------
00371 int vgui_grid_tableau::get_selected_positions(vcl_vector<int>* col_pos,
00372                                               vcl_vector<int>* row_pos,
00373                                               vcl_vector<int>* times)
00374 {
00375   int nb_selected = 0;
00376   for (unsigned i = 0; i < nb_cols; i++)
00377   {
00378     for (unsigned j = 0; j < nb_rows; j++)
00379     {
00380       if (grid_pos(i,j).time_selected != -1)
00381       {
00382         col_pos->push_back(i);
00383         row_pos->push_back(j);
00384         times->push_back(grid_pos(i,j).time_selected);
00385         nb_selected++;
00386       }
00387     }
00388   }
00389   return nb_selected;
00390 }
00391 
00392 //------------------------------------------------------------------------------
00393 //: Redraw the grid of tableaux keeping each tableau in its current row and column.
00394 //  If for example a new column had been added, using this would redraw the
00395 //  grid with that column empty.
00396 //------------------------------------------------------------------------------
00397 void vgui_grid_tableau::layout_grid()
00398 {
00399 #ifdef DEBUG
00400   vcl_cerr << "vgui_grid_tableau::layout_grid: redrawing grid keeping current row and column positions\n";
00401 #endif
00402   for (unsigned i = 0; i < nb_cols; i++)
00403   {
00404     for (unsigned j = 0; j < nb_rows; j++)
00405     {
00406       this->move(grid_pos(i,j).handle, get_x(i), get_y(j), get_w(), get_h());
00407     }
00408   }
00409 }
00410 
00411 //------------------------------------------------------------------------------
00412 //: Redraw the grid of tableaux packing them in without gaps, filling each row from top left downwards.
00413 //------------------------------------------------------------------------------
00414 void vgui_grid_tableau::layout_grid2()
00415 {
00416 #ifdef DEBUG
00417   vcl_cerr << "vgui_grid_tableau::layout_grid2: redrawing grid without gaps\n";
00418 #endif
00419   unsigned grid_col = 0;
00420   unsigned grid_row = 0;
00421   for (unsigned j = 0; j < nb_rows; j++)
00422   {
00423     for (unsigned i = 0; i < nb_cols; i++)
00424     {
00425       this->move(grid_pos(i,j).handle, get_x(grid_col), get_y(grid_row), get_w(), get_h());
00426       grid_pos(grid_col, grid_row).handle = grid_pos(i,j).handle;
00427       grid_pos(grid_col, grid_row).tab_pos = grid_pos(i,j).tab_pos;
00428       if (i != grid_col || j != grid_row)
00429         grid_pos(i,j).handle = -1;
00430       if (grid_col < (nb_cols - 1))
00431         grid_col++;
00432       else
00433       {
00434         grid_row++;
00435         grid_col = 0;
00436       }
00437     }
00438   }
00439 }
00440 
00441 //------------------------------------------------------------------------------
00442 //: Add an empty column to the RHS of the grid.
00443 //------------------------------------------------------------------------------
00444 void vgui_grid_tableau::add_column()
00445 {
00446   nb_cols++;
00447 #ifdef DEBUG
00448   vcl_cerr << "vgui_grid_tableau::add_column: number of columns is now " << nb_cols << '\n';
00449 #endif
00450 
00451   if (nb_cols > max_cols)
00452   {
00453     // Increase size of max cols - FIXME
00454     vcl_cerr << "vgui_grid_tableau::add_column(): Warning: nb_cols > max_cols\n";
00455   }
00456 
00457   for (unsigned j = 0; j < nb_rows; j++)
00458     add_default(nb_cols-1, j);
00459 
00460   layout_grid();
00461 }
00462 
00463 //------------------------------------------------------------------------------
00464 //: Remove last column on RHS of the grid.
00465 //------------------------------------------------------------------------------
00466 void vgui_grid_tableau::remove_column()
00467 {
00468   if (nb_cols > 1)
00469   {
00470     for (unsigned j = 0; j < nb_rows; j++)
00471     {
00472       this->remove(grid_pos(nb_cols-1, j).handle);
00473     }
00474     nb_cols--;
00475 #ifdef DEBUG
00476     vcl_cerr << "vgui_grid_tableau::remove_column: number of columns is now " << nb_cols << '\n';
00477 #endif
00478     layout_grid();
00479   }
00480 }
00481 
00482 //------------------------------------------------------------------------------
00483 //: Add an empty row to the bottom of the grid.
00484 //------------------------------------------------------------------------------
00485 void vgui_grid_tableau::add_row()
00486 {
00487   nb_rows++;
00488 #ifdef DEBUG
00489   vcl_cerr << "vgui_grid_tableau::add_row: number of rows is now " << nb_rows << '\n';
00490 #endif
00491   if (nb_rows > max_rows)
00492   {
00493     // Increase size of max_rows - FIXME
00494     vcl_cerr << "vgui_grid_tableau::add_row(): Warning: nb_rows > max_rows\n";
00495   }
00496   for (unsigned i = 0; i < nb_cols; i++)
00497   {
00498     add_default(i, nb_rows-1);
00499   }
00500   layout_grid();
00501 }
00502 
00503 //------------------------------------------------------------------------------
00504 //: Remove last row on the bottom of the grid
00505 //------------------------------------------------------------------------------
00506 void vgui_grid_tableau::remove_row()
00507 {
00508   if (nb_rows > 1)
00509   {
00510     for (unsigned i = 0; i < nb_cols; i++)
00511     {
00512       this->remove(grid_pos(i, nb_rows-1).handle);
00513     }
00514     nb_rows--;
00515 #ifdef DEBUG
00516     vcl_cerr << "vgui_grid_tableau::remove_row: number of rows is now " << nb_rows << '\n';
00517 #endif
00518     layout_grid();
00519   }
00520 }
00521 
00522 //------------------------------------------------------------------------------
00523 //: Flip forwards through the list of tableaux.
00524 //------------------------------------------------------------------------------
00525 void vgui_grid_tableau::page_up()
00526 {
00527   unsigned row_pos, col_pos;
00528   get_active_position(&col_pos, &row_pos);
00529 #ifdef DEBUG
00530   vcl_cerr << "vgui_grid_tableau::page_up called on col_pos = " <<  col_pos << ", row_pos = " << row_pos << '\n';
00531 #endif
00532 
00533   if (col_pos < nb_cols && row_pos < nb_rows)
00534   {
00535     // Get the index of the tableau currently in that position:
00536     unsigned tab_index = grid_pos(col_pos, row_pos).tab_pos;
00537 
00538     if (tab_index < (tabs.size() - 1) &&
00539         ! grid_pos(col_pos, row_pos).is_default)
00540     {
00541       this->replace(grid_pos(col_pos, row_pos).handle, tabs[tab_index + 1]);
00542       grid_pos(col_pos, row_pos).tab_pos++;
00543     }
00544     else
00545     {
00546       this->replace(grid_pos(col_pos, row_pos).handle, tabs[0]);
00547       grid_pos(col_pos, row_pos).tab_pos = 0;
00548       grid_pos(col_pos, row_pos).is_default = false;
00549     }
00550   }
00551 }
00552 
00553 //------------------------------------------------------------------------------
00554 //: Flip backwards through the list of tableaux.
00555 //------------------------------------------------------------------------------
00556 void vgui_grid_tableau::page_down()
00557 {
00558   unsigned row_pos, col_pos;
00559   get_active_position(&col_pos, &row_pos);
00560 #ifdef DEBUG
00561   vcl_cerr << "vgui_grid_tableau::page_down called on col_pos = " <<  col_pos << ", row_pos = " << row_pos << '\n';
00562 #endif
00563 
00564   if (col_pos < nb_cols && row_pos < nb_rows)
00565   {
00566     // Get the index of the tableau currently in that position:
00567     unsigned tab_index = grid_pos(col_pos, row_pos).tab_pos;
00568 
00569     if (tab_index > 0 &&
00570         ! grid_pos(col_pos, row_pos).is_default)
00571     {
00572       this->replace(grid_pos(col_pos, row_pos).handle, tabs[tab_index - 1]);
00573       grid_pos(col_pos, row_pos).tab_pos--;
00574     }
00575     else
00576     {
00577       this->replace(grid_pos(col_pos, row_pos).handle, tabs[tabs.size()-1]);
00578       grid_pos(col_pos, row_pos).tab_pos = tabs.size()-1;
00579       grid_pos(col_pos, row_pos).is_default = false;
00580     }
00581   }
00582 }
00583 
00584 //------------------------------------------------------------------------------
00585 //: Make the current tableau selected by saving the current time.
00586 //  Set the outline color to red.
00587 //------------------------------------------------------------------------------
00588 void vgui_grid_tableau::select_current(int time)
00589 {
00590   unsigned col, row;
00591   get_active_position(&col, &row);
00592   bool redraw_needed = false;
00593   if (grid_pos(col, row).time_selected == -1)
00594     redraw_needed = true;
00595   grid_pos(col, row).time_selected = time;
00596   last_selected[0] = col;
00597   last_selected[1] = row;
00598   if (redraw_needed)
00599   {
00600     set_outline_color(grid_pos(col,row).handle, 1,0,0);
00601     post_redraw();
00602   }
00603 
00604   if (unique_selected_)
00605   {
00606     redraw_needed = false;
00607     for (unsigned r = 0; r<nb_rows; ++r)
00608       for (unsigned c = 0; c<nb_cols; ++c)
00609         if (!(c==col&&r==row))
00610           if (grid_pos(c,r).time_selected != -1)
00611           {
00612             grid_pos(c, r).time_selected = -1;
00613             set_outline_color(grid_pos(c,r).handle, 1,1,1);
00614             redraw_needed = true;
00615           }
00616     if (redraw_needed) post_redraw();
00617   }
00618 }
00619 
00620 //------------------------------------------------------------------------------
00621 //: Mark the current table as deselected by setting the time to -1.
00622 //  Set the outline color to white.
00623 //------------------------------------------------------------------------------
00624 void vgui_grid_tableau::deselect_current()
00625 {
00626   unsigned col, row;
00627   get_active_position(&col, &row);
00628   if (grid_pos(col,row).time_selected != -1)
00629   {
00630     grid_pos(col, row).time_selected = -1;
00631     set_outline_color(grid_pos(col,row).handle, 1,1,1);
00632     post_redraw();
00633   }
00634 }
00635 
00636 //------------------------------------------------------------------------------
00637 //: Handle any events matching the {vgui_event_condition}s.
00638 //  All other events go to the base class.
00639 //------------------------------------------------------------------------------
00640 bool vgui_grid_tableau::handle(const vgui_event &e)
00641 {
00642   if (cond_row_add(e))
00643   {
00644     add_row();
00645     return true;
00646   }
00647   else if (cond_row_remove(e))
00648   {
00649     remove_row();
00650     return true;
00651   }
00652   else if (cond_col_add(e))
00653   {
00654     add_column();
00655     return true;
00656   }
00657   else if (cond_col_remove(e))
00658   {
00659     remove_column();
00660     return true;
00661   }
00662   else if (cond_flip_fwd(e))
00663   {
00664     page_up();
00665     return true;
00666   }
00667   else if (cond_flip_bwd(e))
00668   {
00669     page_down();
00670     return true;
00671   }
00672   else if (cond_select(e))
00673   {
00674     select_current(e.timestamp);
00675     // let event go to base class too.
00676   }
00677   else if (cond_deselect(e))
00678   {
00679     deselect_current();
00680     // let event go to base class too.
00681   }
00682 
00683   // We are not interested in other events, so pass event to base class:
00684   return vgui_poly_tableau::handle(e);
00685 }