24#include <wx/tokenzr.h>
25#include <wx/clipbrd.h>
27#include <wx/stc/stc.h>
36#define COL_SEP wxT( '\t' )
37#define ROW_SEP wxT( '\n' )
38#define ROW_SEP_R wxT( '\r' )
44 m_enableSingleClickEdit(
true ),
45 m_multiCellEditEnabled(
true )
68 m_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK,
70 m_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK,
72 m_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK,
74 m_grid->Connect( wxEVT_GRID_LABEL_RIGHT_CLICK,
76 m_grid->Connect( wxEVT_GRID_LABEL_LEFT_CLICK,
80 m_grid->Connect( wxEVT_CHAR_HOOK,
82 m_grid->Connect( wxEVT_KEY_DOWN,
84 m_grid->Connect( wxEVT_UPDATE_UI,
88 m_grid->GetGridWindow()->Connect( wxEVT_MOTION,
96 wxGridCellEditor*
editor =
m_grid->GetCellEditor( aRow, aCol );
97 bool retval = (
dynamic_cast<wxGridCellTextEditor*
>(
editor )
108 wxGridCellEditor*
editor =
m_grid->GetCellEditor( aRow, aCol );
109 bool retval = (
dynamic_cast<wxGridCellChoiceEditor*
>(
editor )
120 wxGridCellRenderer* renderer =
m_grid->GetCellRenderer( aRow, aCol );
121 bool retval = (
dynamic_cast<wxGridCellBoolRenderer*
>( renderer ) );
130 return !
m_grid->IsEditable() ||
m_grid->IsReadOnly( aRow, aCol );
138 if( !aPreserveSelection )
141 m_grid->SetGridCursor( aRow, aCol );
146 if(
model->CanGetValueAs( aRow, aCol, wxGRID_VALUE_BOOL )
147 &&
model->CanSetValueAs( aRow, aCol, wxGRID_VALUE_BOOL ) )
149 model->SetValueAsBool( aRow, aCol, !
model->GetValueAsBool( aRow, aCol ) );
153 if(
model->GetValue( aRow, aCol ) == wxT(
"1" ) )
154 model->SetValue( aRow, aCol, wxT(
"0" ) );
156 model->SetValue( aRow, aCol, wxT(
"1" ) );
163 wxGridEvent event(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, aRow, aCol );
164 event.SetString(
model->GetValue( aRow, aCol ) );
165 m_grid->GetEventHandler()->ProcessEvent( event );
176 if(
m_grid->GetGridCursorRow() != aRow ||
m_grid->GetGridCursorCol() != aCol )
177 m_grid->SetGridCursor( aRow, aCol );
188 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
190 wxArrayInt rows =
m_grid->GetSelectedRows();
192 if( rows.size() != 1 || rows.Item( 0 ) != aRow )
193 m_grid->SelectRow( aRow );
205 m_grid->ShowEditorOnMouseUp();
216 int row = aEvent.GetRow();
217 int col = aEvent.GetCol();
220 if( !aEvent.GetModifiers() )
222 bool toggled =
false;
245 wxString newVal =
m_grid->GetCellValue( row, col );
249 if( otherRow == row )
252 m_grid->SetCellValue( otherRow, col, newVal );
275 wxPoint pt = aEvent.GetPosition();
276 wxPoint pos =
m_grid->CalcScrolledPosition( wxPoint( pt.x, pt.y ) );
278 int col =
m_grid->XToCol( pos.x );
279 int row =
m_grid->YToRow( pos.y );
282 if( ( col == wxNOT_FOUND ) || ( row == wxNOT_FOUND ) || !
m_tooltipEnabled[col] )
284 m_grid->GetGridWindow()->SetToolTip( wxS(
"" ) );
289 m_grid->GetGridWindow()->SetToolTip(
m_grid->GetCellValue( row, col ) );
302 wxGridCellCoordsArray topLeft =
m_grid->GetSelectionBlockTopLeft();
303 wxGridCellCoordsArray botRight =
m_grid->GetSelectionBlockBottomRight();
305 wxArrayInt cols =
m_grid->GetSelectedCols();
306 wxArrayInt rows =
m_grid->GetSelectedRows();
308 if( topLeft.Count() && botRight.Count() )
316 else if( cols.Count() )
323 else if( rows.Count() )
342 m_grid->CommitPendingChanges(
true );
345 int row = aEvent.GetRow();
347 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
349 wxArrayInt selectedRows =
m_grid->GetSelectedRows();
351 if( selectedRows.Index( row ) == wxNOT_FOUND )
356 if( !
m_grid->IsInSelection( row, aEvent.GetCol() ) )
357 m_grid->SetGridCursor( row, aEvent.GetCol() );
368 m_grid->CommitPendingChanges();
378 for(
int i = 0; i <
m_grid->GetNumberCols(); ++i )
381 menu.AppendCheckItem(
id,
m_grid->GetColLabelValue( i ) );
382 menu.Check(
id,
m_grid->IsColShown( i ) );
385 m_grid->PopupMenu( &menu );
392 _(
"Clear selected cells placing original contents on clipboard" ) );
394 _(
"Copy selected cells to clipboard" ) );
399 _(
"Paste clipboard cells to matrix at current cell" ) );
401 _(
"Clear contents of selected cells" ) );
405 _(
"Select all cells" ) );
413 auto anyCellsWritable =
431 if( anyCellsWritable() )
441 if( wxTheClipboard->Open() )
443 if( wxTheClipboard->IsSupported( wxDF_TEXT )
444 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
446 if(
m_grid->IsEditable() )
450 wxTheClipboard->Close();
454 m_grid->PopupMenu( &menu );
466 int menu_id =
event.GetId();
498 if(
m_grid->IsColShown( col ) )
509 bool handled =
false;
511 if( ( ev.GetKeyCode() == WXK_RETURN || ev.GetKeyCode() == WXK_NUMPAD_ENTER )
512 && ev.GetModifiers() == wxMOD_NONE
513 &&
m_grid->GetGridCursorRow() ==
m_grid->GetNumberRows() - 1 )
515 if(
m_grid->IsCellEditControlShown() )
517 if(
m_grid->CommitPendingChanges() )
522 wxCommandEvent
dummy;
527 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'C' )
529 if(
m_grid->IsCellEditControlShown() )
531 wxTextEntry* te =
dynamic_cast<wxTextEntry*
>( ev.GetEventObject() );
535 wxString selectedText = te->GetStringSelection();
537 if( !selectedText.IsEmpty() )
541 if( wxTheClipboard->Open() )
543 wxTheClipboard->SetData(
new wxTextDataObject( selectedText ) );
544 wxTheClipboard->Flush();
545 wxTheClipboard->Close();
553 m_grid->CancelPendingChanges();
560 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'V' )
562 if(
m_grid->IsCellEditControlShown() )
566 if( wxTheClipboard->Open() )
568 if( wxTheClipboard->IsSupported( wxDF_TEXT )
569 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
571 wxTextDataObject data;
572 wxTheClipboard->GetData( data );
573 wxString
text = data.GetText();
577 if( hasMultipleCells )
584 wxTextEntry* te =
dynamic_cast<wxTextEntry*
>( ev.GetEventObject() );
586 if( te && te->IsEditable() )
588 te->WriteText(
text );
593 m_grid->CancelPendingChanges();
600 wxTheClipboard->Close();
605 else if( ev.GetKeyCode() == WXK_ESCAPE )
607 if(
m_grid->IsCellEditControlShown() )
609 m_grid->CancelPendingChanges();
621 if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'A' )
626 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'C' )
632 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'V' )
638 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'X' )
644 else if( !ev.GetModifiers() && ev.GetKeyCode() == WXK_DELETE )
652 if(
m_grid->IsEditable() && ev.GetKeyCode() ==
' ' )
657 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
659 wxArrayInt rowSel =
m_grid->GetSelectedRows();
661 for(
unsigned int rowInd = 0; rowInd < rowSel.GetCount(); rowInd++ )
662 retVal |=
toggleCell( rowSel[rowInd], 0,
true );
666 else if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectColumns )
668 wxArrayInt colSel =
m_grid->GetSelectedCols();
670 for(
unsigned int colInd = 0; colInd < colSel.GetCount(); colInd++ )
671 retVal |=
toggleCell( 0, colSel[colInd],
true );
675 else if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectCells )
677 wxArrayInt rowSel =
m_grid->GetSelectedRows();
678 wxArrayInt colSel =
m_grid->GetSelectedCols();
679 wxGridCellCoordsArray cellSel =
m_grid->GetSelectedCells();
680 wxGridCellCoordsArray topLeft =
m_grid->GetSelectionBlockTopLeft();
681 wxGridCellCoordsArray botRight =
m_grid->GetSelectionBlockBottomRight();
684 for(
unsigned int cellInd = 0; cellInd < cellSel.GetCount(); cellInd++ )
686 retVal |=
toggleCell( cellSel[cellInd].GetRow(), cellSel[cellInd].GetCol(),
true );
690 for(
unsigned int colInd = 0; colInd < colSel.GetCount(); colInd++ )
692 for(
int row = 0; row <
m_grid->GetNumberRows(); row++ )
693 retVal |=
toggleCell( row, colSel[colInd],
true );
697 for(
unsigned int rowInd = 0; rowInd < rowSel.GetCount(); rowInd++ )
699 for(
int col = 0; col <
m_grid->GetNumberCols(); col++ )
700 retVal |=
toggleCell( rowSel[rowInd], col,
true );
704 for(
unsigned int blockInd = 0; blockInd < topLeft.GetCount(); blockInd++ )
706 wxGridCellCoords start = topLeft[blockInd];
707 wxGridCellCoords
end = botRight[blockInd];
709 for(
int row = start.GetRow(); row <=
end.GetRow(); row++ )
711 for(
int col = start.GetCol(); col <=
end.GetCol(); col++ )
724 bool ctrl = ev.RawControlDown();
726 bool ctrl = ev.ControlDown();
729 if( ctrl && ev.GetKeyCode() == WXK_TAB )
736 while(
test && !
test->IsTopLevel() )
740 if(
test->HasFocus() )
743 if( !
test->GetChildren().empty() )
747 else if(
test->GetNextSibling() )
761 else if(
test &&
test->GetNextSibling() )
781 if(
m_grid->IsEditable() && ( wxTheClipboard->IsOpened() || wxTheClipboard->Open() ) )
783 if( wxTheClipboard->IsSupported( wxDF_TEXT )
784 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
786 wxTextDataObject data;
788 wxTheClipboard->GetData( data );
790 wxString
text = data.GetText();
794 text.Replace(
"\n\n",
"\n" );
796 m_grid->CommitPendingChanges(
true );
800 wxTheClipboard->Close();
811 wxGridTableBase* tbl =
m_grid->GetTable();
813 const int cur_row =
m_grid->GetGridCursorRow();
814 const int cur_col =
m_grid->GetGridCursorCol();
819 bool is_selection =
false;
821 if( cur_row < 0 || cur_col < 0 )
827 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
837 wxStringTokenizer rows( cb_text,
ROW_SEP, wxTOKEN_RET_EMPTY );
853 end_row = cur_row + rows.CountTokens();
855 if( end_row > tbl->GetNumberRows() )
859 for(
int ii = end_row - tbl->GetNumberRows(); ii > 0; --ii )
861 wxCommandEvent
dummy;
866 end_row = tbl->GetNumberRows();
873 for(
int row = start_row; row < end_row; ++row )
877 if( !rows.HasMoreTokens() )
878 rows.SetString( cb_text,
ROW_SEP, wxTOKEN_RET_EMPTY );
880 wxString rowTxt = rows.GetNextToken();
882 wxStringTokenizer cols( rowTxt,
COL_SEP, wxTOKEN_RET_EMPTY );
885 end_col = cur_col + cols.CountTokens();
887 for(
int col = start_col; col < end_col && col < tbl->GetNumberCols(); ++col )
890 if( !
m_grid->IsColShown( col ) )
898 if( !cols.HasMoreTokens() )
899 cols.SetString( rowTxt,
COL_SEP, wxTOKEN_RET_EMPTY );
901 wxString cellTxt = cols.GetNextToken();
905 if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_STRING ) && !
isReadOnly( row, col ) )
907 tbl->SetValue( row, col, cellTxt );
909 wxGridEvent evt(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, row, col );
910 m_grid->GetEventHandler()->ProcessEvent( evt );
913 else if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_BOOL ) )
915 tbl->SetValueAsBool( row, col, cellTxt == wxT(
"1" ) );
917 wxGridEvent evt(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, row, col );
918 m_grid->GetEventHandler()->ProcessEvent( evt );
929 if( doCopy && !wxTheClipboard->Open() )
932 wxGridTableBase* tbl =
m_grid->GetTable();
943 if( !
m_grid->IsColShown( col ) )
946 txt += tbl->GetValue( row, col );
957 bool hadContent = !tbl->GetValue( row, col ).IsEmpty();
959 tbl->SetValue( row, col, wxEmptyString );
963 wxGridEvent evt(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, row, col );
964 m_grid->GetEventHandler()->ProcessEvent( evt );
973 wxTheClipboard->SetData(
new wxTextDataObject( txt ) );
974 wxTheClipboard->Flush();
975 wxTheClipboard->Close();
987 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
989 int cursorRow =
m_grid->GetGridCursorRow();
990 bool cursorInSelectedRow =
false;
992 for(
int row :
m_grid->GetSelectedRows() )
994 if( row == cursorRow )
996 cursorInSelectedRow =
true;
1001 if( !cursorInSelectedRow && cursorRow >= 0 )
1002 m_grid->SelectRow( cursorRow );
bool isReadOnly(int aRow, int aCol)
void onGridMotion(wxMouseEvent &event)
void onGridLabelLeftClick(wxGridEvent &event)
virtual void paste_text(const wxString &cb_text)
void init()
Shared initialization for various ctors.
void getSelectedArea()
Puts the selected area into a sensible rectangle of m_sel_{row,col}_{start,count} above.
bool m_multiCellEditEnabled
GRID_TRICKS(WX_GRID *aGrid)
bool isChoiceEditor(int aRow, int aCol)
void onKeyDown(wxKeyEvent &event)
void onPopupSelection(wxCommandEvent &event)
virtual void cutcopy(bool doCopy, bool doDelete)
bool m_enableSingleClickEdit
virtual void doPopupSelection(wxCommandEvent &event)
bool isCheckbox(int aRow, int aCol)
std::function< void(wxCommandEvent &)> m_addHandler
virtual void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent)
std::bitset< GRIDTRICKS_MAX_COL > m_tooltipEnabled
void onUpdateUI(wxUpdateUIEvent &event)
void onGridCellRightClick(wxGridEvent &event)
virtual void appendPopupMenuItems(wxMenu &aMenu)
WX_GRID * m_grid
I don't own the grid, but he owns me.
bool isTextEntry(int aRow, int aCol)
void onGridCellLeftDClick(wxGridEvent &event)
virtual void onGridCellLeftClick(wxGridEvent &event)
virtual bool handleDoubleClick(wxGridEvent &aEvent)
void onCharHook(wxKeyEvent &event)
virtual void paste_clipboard()
bool showEditor(int aRow, int aCol)
void onGridLabelRightClick(wxGridEvent &event)
virtual bool toggleCell(int aRow, int aCol, bool aPreserveSelection=false)
@ GRIDTRICKS_FIRST_SHOWHIDE
std::vector< FAB_LAYER_COLOR > dummy