KiCad PCB EDA Suite
grid_tricks.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <grid_tricks.h>
26 #include <wx/defs.h>
27 #include <wx/event.h>
28 #include <wx/tokenzr.h>
29 #include <wx/clipbrd.h>
30 #include <wx/log.h>
32 
33 
34 // It works for table data on clipboard for an Excel spreadsheet,
35 // why not us too for now.
36 #define COL_SEP wxT( '\t' )
37 #define ROW_SEP wxT( '\n' )
38 
39 
41  m_grid( aGrid )
42 {
43  m_sel_row_start = 0;
44  m_sel_col_start = 0;
45  m_sel_row_count = 0;
46  m_sel_col_count = 0;
47 
48  aGrid->Connect( wxEVT_GRID_CELL_LEFT_CLICK,
49  wxGridEventHandler( GRID_TRICKS::onGridCellLeftClick ), nullptr, this );
50  aGrid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK,
51  wxGridEventHandler( GRID_TRICKS::onGridCellLeftDClick ), nullptr, this );
52  aGrid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK,
53  wxGridEventHandler( GRID_TRICKS::onGridCellRightClick ), nullptr, this );
54  aGrid->Connect( wxEVT_GRID_LABEL_RIGHT_CLICK,
55  wxGridEventHandler( GRID_TRICKS::onGridLabelRightClick ), nullptr, this );
56  aGrid->Connect( wxEVT_GRID_LABEL_LEFT_CLICK,
57  wxGridEventHandler( GRID_TRICKS::onGridLabelLeftClick ), nullptr, this );
58  aGrid->Connect( GRIDTRICKS_FIRST_ID, GRIDTRICKS_LAST_ID, wxEVT_COMMAND_MENU_SELECTED,
59  wxCommandEventHandler( GRID_TRICKS::onPopupSelection ), nullptr, this );
60  aGrid->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( GRID_TRICKS::onKeyDown ), nullptr, this );
61  aGrid->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( GRID_TRICKS::onUpdateUI ),
62  nullptr, this );
63 
64  // The handlers that control the tooltips must be on the actual grid window, not the grid
65  aGrid->GetGridWindow()->Connect( wxEVT_MOTION,
66  wxMouseEventHandler( GRID_TRICKS::onGridMotion ), nullptr, this );
67 }
68 
69 
70 bool GRID_TRICKS::toggleCell( int aRow, int aCol, bool aPreserveSelection )
71 {
72  auto renderer = m_grid->GetCellRenderer( aRow, aCol );
73  bool isCheckbox = ( dynamic_cast<wxGridCellBoolRenderer*>( renderer ) != nullptr );
74  renderer->DecRef();
75 
76  if( isCheckbox )
77  {
78  if( !aPreserveSelection )
79  m_grid->ClearSelection();
80 
81  m_grid->SetGridCursor( aRow, aCol );
82 
83  wxGridTableBase* model = m_grid->GetTable();
84 
85  if( model->CanGetValueAs( aRow, aCol, wxGRID_VALUE_BOOL )
86  && model->CanSetValueAs( aRow, aCol, wxGRID_VALUE_BOOL ) )
87  {
88  model->SetValueAsBool( aRow, aCol, !model->GetValueAsBool( aRow, aCol ) );
89  }
90  else // fall back to string processing
91  {
92  if( model->GetValue( aRow, aCol ) == wxT( "1" ) )
93  model->SetValue( aRow, aCol, wxT( "0" ) );
94  else
95  model->SetValue( aRow, aCol, wxT( "1" ) );
96  }
97 
98  // Mac needs this for the keyboard events; Linux appears to always need it.
99  m_grid->ForceRefresh();
100 
101  // Let any clients know
102  wxGridEvent event( m_grid->GetId(), wxEVT_GRID_CELL_CHANGED, m_grid, aRow, aCol );
103  event.SetString( model->GetValue( aRow, aCol ) );
104  m_grid->GetEventHandler()->ProcessEvent( event );
105 
106  return true;
107  }
108 
109  return false;
110 }
111 
112 
113 bool GRID_TRICKS::showEditor( int aRow, int aCol )
114 {
115  if( m_grid->GetGridCursorRow() != aRow || m_grid->GetGridCursorCol() != aCol )
116  m_grid->SetGridCursor( aRow, aCol );
117 
118  if( m_grid->IsEditable() && !m_grid->IsReadOnly( aRow, aCol ) )
119  {
120  m_grid->ClearSelection();
121 
122  if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
123  {
124  wxArrayInt rows = m_grid->GetSelectedRows();
125 
126  if( rows.size() != 1 || rows.Item( 0 ) != aRow )
127  m_grid->SelectRow( aRow );
128  }
129 
130  // For several reasons we can't enable the control here. There's the whole
131  // SetInSetFocus() issue/hack in wxWidgets, and there's also wxGrid's MouseUp
132  // handler which doesn't notice it's processing a MouseUp until after it has
133  // disabled the editor yet again. So we re-use wxWidgets' slow-click hack,
134  // which is processed later in the MouseUp handler.
135  //
136  // It should be pointed out that the fact that it's wxWidgets' hack doesn't
137  // make it any less of a hack. Be extra careful with any modifications here.
138  // See, in particular, https://bugs.launchpad.net/kicad/+bug/1817965.
140 
141  return true;
142  }
143 
144  return false;
145 }
146 
147 
148 void GRID_TRICKS::onGridCellLeftClick( wxGridEvent& aEvent )
149 {
150  int row = aEvent.GetRow();
151  int col = aEvent.GetCol();
152 
153  // Don't make users click twice to toggle a checkbox or edit a text cell
154  if( !aEvent.GetModifiers() )
155  {
156  if( toggleCell( row, col ) )
157  return;
158 
159  if( showEditor( row, col ) )
160  return;
161  }
162 
163  aEvent.Skip();
164 }
165 
166 
167 void GRID_TRICKS::onGridCellLeftDClick( wxGridEvent& aEvent )
168 {
169  if( !handleDoubleClick( aEvent ) )
170  onGridCellLeftClick( aEvent );
171 }
172 
173 
174 void GRID_TRICKS::onGridMotion( wxMouseEvent& aEvent )
175 {
176  // Always skip the event
177  aEvent.Skip();
178 
179  wxPoint pt = aEvent.GetPosition();
180  wxPoint pos = m_grid->CalcScrolledPosition( wxPoint( pt.x, pt.y ) );
181 
182  int col = m_grid->XToCol( pos.x );
183  int row = m_grid->YToRow( pos.y );
184 
185  // Empty tooltip if the cell doesn't exist or the column doesn't have tooltips
186  if( ( col == wxNOT_FOUND ) || ( row == wxNOT_FOUND ) || !m_tooltipEnabled[col] )
187  {
188  m_grid->GetGridWindow()->SetToolTip( "" );
189  return;
190  }
191 
192  // Set the tooltip to the string contained in the cell
193  m_grid->GetGridWindow()->SetToolTip( m_grid->GetCellValue( row, col ) );
194 }
195 
196 
197 bool GRID_TRICKS::handleDoubleClick( wxGridEvent& aEvent )
198 {
199  // Double-click processing must be handled by specific sub-classes
200  return false;
201 }
202 
203 
205 {
206  wxGridCellCoordsArray topLeft = m_grid->GetSelectionBlockTopLeft();
207  wxGridCellCoordsArray botRight = m_grid->GetSelectionBlockBottomRight();
208 
209  wxArrayInt cols = m_grid->GetSelectedCols();
210  wxArrayInt rows = m_grid->GetSelectedRows();
211 
212  if( topLeft.Count() && botRight.Count() )
213  {
214  m_sel_row_start = topLeft[0].GetRow();
215  m_sel_col_start = topLeft[0].GetCol();
216 
217  m_sel_row_count = botRight[0].GetRow() - m_sel_row_start + 1;
218  m_sel_col_count = botRight[0].GetCol() - m_sel_col_start + 1;
219  }
220  else if( cols.Count() )
221  {
222  m_sel_col_start = cols[0];
223  m_sel_col_count = cols.Count();
224  m_sel_row_start = 0;
225  m_sel_row_count = m_grid->GetNumberRows();
226  }
227  else if( rows.Count() )
228  {
229  m_sel_col_start = 0;
230  m_sel_col_count = m_grid->GetNumberCols();
231  m_sel_row_start = rows[0];
232  m_sel_row_count = rows.Count();
233  }
234  else
235  {
236  m_sel_row_start = m_grid->GetGridCursorRow();
237  m_sel_col_start = m_grid->GetGridCursorCol();
238  m_sel_row_count = m_sel_row_start >= 0 ? 1 : 0;
239  m_sel_col_count = m_sel_col_start >= 0 ? 1 : 0;
240  }
241 }
242 
243 
245 {
246  wxMenu menu;
247 
248  showPopupMenu( menu );
249 }
250 
251 
252 void GRID_TRICKS::onGridLabelLeftClick( wxGridEvent& aEvent )
253 {
255 
256  aEvent.Skip();
257 }
258 
259 
261 {
262  wxMenu menu;
263 
264  for( int i = 0; i < m_grid->GetNumberCols(); ++i )
265  {
266  int id = GRIDTRICKS_FIRST_SHOWHIDE + i;
267  menu.AppendCheckItem( id, m_grid->GetColLabelValue( i ) );
268  menu.Check( id, m_grid->IsColShown( i ) );
269  }
270 
271  m_grid->PopupMenu( &menu );
272 }
273 
274 
275 void GRID_TRICKS::showPopupMenu( wxMenu& menu )
276 {
277  menu.Append( GRIDTRICKS_ID_CUT, _( "Cut" ) + "\tCtrl+X",
278  _( "Clear selected cells placing original contents on clipboard" ) );
279  menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C",
280  _( "Copy selected cells to clipboard" ) );
281  menu.Append( GRIDTRICKS_ID_PASTE, _( "Paste" ) + "\tCtrl+V",
282  _( "Paste clipboard cells to matrix at current cell" ) );
283  menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel", _( "Delete selected cells" ) );
284  menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A", _( "Select all cells" ) );
285 
286  getSelectedArea();
287 
288  // if nothing is selected, disable cut, copy and delete.
290  {
291  menu.Enable( GRIDTRICKS_ID_CUT, false );
292  menu.Enable( GRIDTRICKS_ID_COPY, false );
293  menu.Enable( GRIDTRICKS_ID_DELETE, false );
294  }
295 
296  menu.Enable( GRIDTRICKS_ID_PASTE, false );
297 
298  wxLogNull doNotLog; // disable logging of failed clipboard actions
299 
300  if( wxTheClipboard->Open() )
301  {
302  if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
303  menu.Enable( GRIDTRICKS_ID_PASTE, true );
304 
305  wxTheClipboard->Close();
306  }
307 
308  m_grid->PopupMenu( &menu );
309 }
310 
311 
312 void GRID_TRICKS::onPopupSelection( wxCommandEvent& event )
313 {
314  doPopupSelection( event );
315 }
316 
317 
318 void GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
319 {
320  int menu_id = event.GetId();
321 
322  // assume getSelectedArea() was called by rightClickPopupMenu() and there's
323  // no way to have gotten here without that having been called.
324 
325  switch( menu_id )
326  {
327  case GRIDTRICKS_ID_CUT:
328  cutcopy( true, true );
329  break;
330 
331  case GRIDTRICKS_ID_COPY:
332  cutcopy( true, false );
333  break;
334 
336  cutcopy( false, true );
337  break;
338 
339  case GRIDTRICKS_ID_PASTE:
340  paste_clipboard();
341  break;
342 
344  m_grid->SelectAll();
345  break;
346 
347  default:
348  if( menu_id >= GRIDTRICKS_FIRST_SHOWHIDE )
349  {
350  int col = menu_id - GRIDTRICKS_FIRST_SHOWHIDE;
351 
352  if( m_grid->IsColShown( col ) )
353  m_grid->HideCol( col );
354  else
355  m_grid->ShowCol( col );
356  }
357  }
358 }
359 
360 
361 void GRID_TRICKS::onKeyDown( wxKeyEvent& ev )
362 {
363  if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'A' )
364  {
365  m_grid->SelectAll();
366  return;
367  }
368  else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'C' )
369  {
370  getSelectedArea();
371  cutcopy( true, false );
372  return;
373  }
374  else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' )
375  {
376  getSelectedArea();
377  paste_clipboard();
378  return;
379  }
380  else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'X' )
381  {
382  getSelectedArea();
383  cutcopy( true, true );
384  return;
385  }
386  else if( !ev.GetModifiers() && ev.GetKeyCode() == WXK_DELETE )
387  {
388  getSelectedArea();
389  cutcopy( false, true );
390  return;
391  }
392 
393  // space-bar toggling of checkboxes
394  if( ev.GetKeyCode() == ' ' )
395  {
396  bool retVal = false;
397 
398  // If only rows can be selected, only toggle the first cell in a row
399  if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
400  {
401  wxArrayInt rowSel = m_grid->GetSelectedRows();
402 
403  for( unsigned int rowInd = 0; rowInd < rowSel.GetCount(); rowInd++ )
404  {
405  retVal |= toggleCell( rowSel[rowInd], 0, true );
406  }
407  }
408 
409  // If only columns can be selected, only toggle the first cell in a column
410  else if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectColumns )
411  {
412  wxArrayInt colSel = m_grid->GetSelectedCols();
413 
414  for( unsigned int colInd = 0; colInd < colSel.GetCount(); colInd++ )
415  {
416  retVal |= toggleCell( 0, colSel[colInd], true );
417  }
418  }
419 
420  // If the user can select the individual cells, toggle each cell selected
421  else if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectCells )
422  {
423  wxArrayInt rowSel = m_grid->GetSelectedRows();
424  wxArrayInt colSel = m_grid->GetSelectedCols();
425  wxGridCellCoordsArray cellSel = m_grid->GetSelectedCells();
426  wxGridCellCoordsArray topLeft = m_grid->GetSelectionBlockTopLeft();
427  wxGridCellCoordsArray botRight = m_grid->GetSelectionBlockBottomRight();
428 
429  // Iterate over every individually selected cell and try to toggle it
430  for( unsigned int cellInd = 0; cellInd < cellSel.GetCount(); cellInd++ )
431  {
432  retVal |= toggleCell( cellSel[cellInd].GetRow(), cellSel[cellInd].GetCol(), true );
433  }
434 
435  // Iterate over every column and try to toggle each cell in it
436  for( unsigned int colInd = 0; colInd < colSel.GetCount(); colInd++ )
437  {
438  for( int row = 0; row < m_grid->GetNumberRows(); row++ )
439  {
440  retVal |= toggleCell( row, colSel[colInd], true );
441  }
442  }
443 
444  // Iterate over every row and try to toggle each cell in it
445  for( unsigned int rowInd = 0; rowInd < rowSel.GetCount(); rowInd++ )
446  {
447  for( int col = 0; col < m_grid->GetNumberCols(); col++ )
448  {
449  retVal |= toggleCell( rowSel[rowInd], col, true );
450  }
451  }
452 
453  // Iterate over the selection blocks
454  for( unsigned int blockInd = 0; blockInd < topLeft.GetCount(); blockInd++ )
455  {
456  wxGridCellCoords start = topLeft[blockInd];
457  wxGridCellCoords end = botRight[blockInd];
458 
459  for( int row = start.GetRow(); row <= end.GetRow(); row++ )
460  {
461  for( int col = start.GetCol(); col <= end.GetCol(); col++ )
462  {
463  retVal |= toggleCell( row, col, true );
464  }
465  }
466  }
467  }
468  else
469  {
470  }
471 
472  // Return if there were any cells toggled
473  if( retVal )
474  return;
475  }
476 
477  // ctrl-tab for exit grid
478 #ifdef __APPLE__
479  bool ctrl = ev.RawControlDown();
480 #else
481  bool ctrl = ev.ControlDown();
482 #endif
483 
484  if( ctrl && ev.GetKeyCode() == WXK_TAB )
485  {
486  wxWindow* test = m_grid->GetNextSibling();
487 
488  if( !test )
489  test = m_grid->GetParent()->GetNextSibling();
490 
491  while( test && !test->IsTopLevel() )
492  {
493  test->SetFocus();
494 
495  if( test->HasFocus() )
496  break;
497 
498  if( !test->GetChildren().empty() )
499  {
500  test = test->GetChildren().front();
501  }
502  else if( test->GetNextSibling() )
503  {
504  test = test->GetNextSibling();
505  }
506  else
507  {
508  while( test )
509  {
510  test = test->GetParent();
511 
512  if( test && test->IsTopLevel() )
513  {
514  break;
515  }
516  else if( test && test->GetNextSibling() )
517  {
518  test = test->GetNextSibling();
519  break;
520  }
521  }
522  }
523  }
524 
525  return;
526  }
527 
528  ev.Skip( true );
529 }
530 
531 
533 {
534  wxLogNull doNotLog; // disable logging of failed clipboard actions
535 
536  if( wxTheClipboard->Open() )
537  {
538  if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
539  {
540  wxTextDataObject data;
541 
542  wxTheClipboard->GetData( data );
543 
544  paste_text( data.GetText() );
545  }
546 
547  wxTheClipboard->Close();
548  m_grid->ForceRefresh();
549  }
550 }
551 
552 
553 void GRID_TRICKS::paste_text( const wxString& cb_text )
554 {
555  wxGridTableBase* tbl = m_grid->GetTable();
556 
557  const int cur_row = m_grid->GetGridCursorRow();
558  const int cur_col = m_grid->GetGridCursorCol();
559  int start_row;
560  int end_row;
561  int start_col;
562  int end_col;
563  bool is_selection = false;
564 
565  if( cur_row < 0 || cur_col < 0 )
566  {
567  wxBell();
568  return;
569  }
570 
571  if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
572  {
573  if( m_sel_row_count > 1 )
574  is_selection = true;
575  }
576  else
577  {
578  if( m_grid->IsSelection() )
579  is_selection = true;
580  }
581 
582  wxStringTokenizer rows( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY );
583 
584  // If selection of cells is present
585  // then a clipboard pastes to selected cells only.
586  if( is_selection )
587  {
588  start_row = m_sel_row_start;
589  end_row = m_sel_row_start + m_sel_row_count;
590  start_col = m_sel_col_start;
591  end_col = m_sel_col_start + m_sel_col_count;
592  }
593  // Otherwise, paste whole clipboard
594  // starting from cell with cursor.
595  else
596  {
597  start_row = cur_row;
598  end_row = cur_row + rows.CountTokens();
599 
600  if( end_row > tbl->GetNumberRows() )
601  end_row = tbl->GetNumberRows();
602 
603  start_col = cur_col;
604  end_col = start_col; // end_col actual value calculates later
605  }
606 
607  for( int row = start_row; row < end_row; ++row )
608  {
609  // If number of selected rows bigger than count of rows in
610  // the clipboard, paste from the clipboard again and again
611  // while end of the selection is reached.
612  if( !rows.HasMoreTokens() )
613  rows.SetString( cb_text, ROW_SEP, wxTOKEN_RET_EMPTY );
614 
615  wxString rowTxt = rows.GetNextToken();
616 
617  wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY );
618 
619  if( !is_selection )
620  {
621  end_col = cur_col + cols.CountTokens();
622 
623  if( end_col > tbl->GetNumberCols() )
624  end_col = tbl->GetNumberCols();
625  }
626 
627  for( int col = start_col; col < end_col; ++col )
628  {
629  // If number of selected columns bigger than count of columns in
630  // the clipboard, paste from the clipboard again and again while
631  // end of the selection is reached.
632  if( !cols.HasMoreTokens() )
633  cols.SetString( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY );
634 
635  wxString cellTxt = cols.GetNextToken();
636 
637  if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_STRING ) )
638  {
639  tbl->SetValue( row, col, cellTxt );
640 
641  wxGridEvent evt( m_grid->GetId(), wxEVT_GRID_CELL_CHANGED, m_grid, row, col );
642  m_grid->GetEventHandler()->ProcessEvent( evt );
643  }
644  }
645  }
646 }
647 
648 
649 void GRID_TRICKS::cutcopy( bool doCopy, bool doDelete )
650 {
651  wxLogNull doNotLog; // disable logging of failed clipboard actions
652 
653  if( doCopy && !wxTheClipboard->Open() )
654  return;
655 
656  wxGridTableBase* tbl = m_grid->GetTable();
657  wxString txt;
658 
659  // fill txt with a format that is compatible with most spreadsheets
660  for( int row = m_sel_row_start; row < m_sel_row_start + m_sel_row_count; ++row )
661  {
662  for( int col = m_sel_col_start; col < m_sel_col_start + m_sel_col_count; ++col )
663  {
664  txt += tbl->GetValue( row, col );
665 
666  if( col < m_sel_col_start + m_sel_col_count - 1 ) // that was not last column
667  txt += COL_SEP;
668 
669  if( doDelete )
670  {
671  if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_STRING ) )
672  tbl->SetValue( row, col, wxEmptyString );
673  }
674  }
675 
676  txt += ROW_SEP;
677  }
678 
679  if( doCopy )
680  {
681  wxTheClipboard->SetData( new wxTextDataObject( txt ) );
682  wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
683  wxTheClipboard->Close();
684  }
685 
686  if( doDelete )
687  m_grid->ForceRefresh();
688 }
689 
690 
691 void GRID_TRICKS::onUpdateUI( wxUpdateUIEvent& event )
692 {
693  // Respect ROW selectionMode when moving cursor
694 
695  if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
696  {
697  int cursorRow = m_grid->GetGridCursorRow();
698  bool cursorInSelectedRow = false;
699 
700  for( int row : m_grid->GetSelectedRows() )
701  {
702  if( row == cursorRow )
703  {
704  cursorInSelectedRow = true;
705  break;
706  }
707  }
708 
709  if( !cursorInSelectedRow && cursorRow >= 0 )
710  m_grid->SelectRow( cursorRow );
711  }
712 }
void onGridLabelLeftClick(wxGridEvent &event)
void getSelectedArea()
Puts the selected area into a sensible rectangle of m_sel_{row,col}_{start,count} above.
int m_sel_row_count
Definition: grid_tricks.h:115
void onGridCellLeftClick(wxGridEvent &event)
void onGridCellRightClick(wxGridEvent &event)
virtual bool handleDoubleClick(wxGridEvent &aEvent)
std::bitset< GRIDTRICKS_MAX_COL > m_tooltipEnabled
Definition: grid_tricks.h:118
int m_sel_col_start
Definition: grid_tricks.h:114
GRID_TRICKS(WX_GRID *aGrid)
Definition: grid_tricks.cpp:40
void onGridCellLeftDClick(wxGridEvent &event)
WX_GRID * m_grid
I don't own the grid, but he owns me.
Definition: grid_tricks.h:109
virtual void paste_text(const wxString &cb_text)
void onPopupSelection(wxCommandEvent &event)
int m_sel_col_count
Definition: grid_tricks.h:116
bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false)
Definition: grid_tricks.cpp:70
bool showEditor(int aRow, int aCol)
virtual void cutcopy(bool doCopy, bool doDelete)
void onGridMotion(wxMouseEvent &event)
#define _(s)
int m_sel_row_start
Definition: grid_tricks.h:113
virtual void paste_clipboard()
void onUpdateUI(wxUpdateUIEvent &event)
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:190
void onGridLabelRightClick(wxGridEvent &event)
#define ROW_SEP
Definition: grid_tricks.cpp:37
virtual void doPopupSelection(wxCommandEvent &event)
virtual void showPopupMenu(wxMenu &menu)
#define COL_SEP
Definition: grid_tricks.cpp:36
void onKeyDown(wxKeyEvent &ev)
void ShowEditorOnMouseUp()
WxWidgets has a bunch of bugs in its handling of wxGrid mouse events which close cell editors right a...
Definition: wx_grid.h:99