28#include <wx/tokenzr.h>
29#include <wx/clipbrd.h>
31#include <wx/stc/stc.h>
37#define COL_SEP wxT( '\t' )
38#define ROW_SEP wxT( '\n' )
39#define ROW_SEP_R wxT( '\r' )
44 m_addHandler( []( wxCommandEvent& ) {} ),
45 m_enableSingleClickEdit(
true ),
46 m_multiCellEditEnabled(
true )
54 m_addHandler( aAddHandler ),
55 m_enableSingleClickEdit( true ),
56 m_multiCellEditEnabled( true )
69 m_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK,
71 m_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK,
73 m_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK,
75 m_grid->Connect( wxEVT_GRID_LABEL_RIGHT_CLICK,
77 m_grid->Connect( wxEVT_GRID_LABEL_LEFT_CLICK,
81 m_grid->Connect( wxEVT_CHAR_HOOK,
83 m_grid->Connect( wxEVT_KEY_DOWN,
85 m_grid->Connect( wxEVT_UPDATE_UI,
89 m_grid->GetGridWindow()->Connect( wxEVT_MOTION,
97 wxGridCellEditor*
editor =
m_grid->GetCellEditor( aRow, aCol );
98 bool retval = (
dynamic_cast<wxTextEntry*
>(
editor )
108 wxGridCellRenderer* renderer =
m_grid->GetCellRenderer( aRow, aCol );
109 bool retval = (
dynamic_cast<wxGridCellBoolRenderer*
>( renderer ) );
118 return !
m_grid->IsEditable() ||
m_grid->IsReadOnly( aRow, aCol );
126 if( !aPreserveSelection )
129 m_grid->SetGridCursor( aRow, aCol );
132 wxGridTableBase* model =
m_grid->GetTable();
134 if( model->CanGetValueAs( aRow, aCol, wxGRID_VALUE_BOOL )
135 && model->CanSetValueAs( aRow, aCol, wxGRID_VALUE_BOOL ) )
137 model->SetValueAsBool( aRow, aCol, !model->GetValueAsBool( aRow, aCol ) );
141 if( model->GetValue( aRow, aCol ) == wxT(
"1" ) )
142 model->SetValue( aRow, aCol, wxT(
"0" ) );
144 model->SetValue( aRow, aCol, wxT(
"1" ) );
151 wxGridEvent event(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, aRow, aCol );
152 event.SetString( model->GetValue( aRow, aCol ) );
153 m_grid->GetEventHandler()->ProcessEvent( event );
164 if(
m_grid->GetGridCursorRow() != aRow ||
m_grid->GetGridCursorCol() != aCol )
165 m_grid->SetGridCursor( aRow, aCol );
176 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
178 wxArrayInt rows =
m_grid->GetSelectedRows();
180 if( rows.size() != 1 || rows.Item( 0 ) != aRow )
181 m_grid->SelectRow( aRow );
204 int row = aEvent.GetRow();
205 int col = aEvent.GetCol();
208 if( !aEvent.GetModifiers() )
210 bool toggled =
false;
233 wxString newVal =
m_grid->GetCellValue( row, col );
237 if( affectedRow == row )
240 m_grid->SetCellValue( affectedRow, col, newVal );
261 wxPoint pt = aEvent.GetPosition();
262 wxPoint pos =
m_grid->CalcScrolledPosition( wxPoint( pt.x, pt.y ) );
264 int col =
m_grid->XToCol( pos.x );
265 int row =
m_grid->YToRow( pos.y );
268 if( ( col == wxNOT_FOUND ) || ( row == wxNOT_FOUND ) || !
m_tooltipEnabled[col] )
270 m_grid->GetGridWindow()->SetToolTip( wxS(
"" ) );
275 m_grid->GetGridWindow()->SetToolTip(
m_grid->GetCellValue( row, col ) );
288 wxGridCellCoordsArray topLeft =
m_grid->GetSelectionBlockTopLeft();
289 wxGridCellCoordsArray botRight =
m_grid->GetSelectionBlockBottomRight();
291 wxArrayInt cols =
m_grid->GetSelectedCols();
292 wxArrayInt rows =
m_grid->GetSelectedRows();
294 if( topLeft.Count() && botRight.Count() )
302 else if( cols.Count() )
309 else if( rows.Count() )
346 for(
int i = 0; i <
m_grid->GetNumberCols(); ++i )
349 menu.AppendCheckItem(
id,
m_grid->GetColLabelValue( i ) );
350 menu.Check(
id,
m_grid->IsColShown( i ) );
353 m_grid->PopupMenu( &menu );
360 _(
"Clear selected cells placing original contents on clipboard" ) );
362 _(
"Copy selected cells to clipboard" ) );
367 _(
"Paste clipboard cells to matrix at current cell" ) );
369 _(
"Clear contents of selected cells" ) );
373 _(
"Select all cells" ) );
381 auto anyCellsWritable =
396 if( anyCellsWritable() )
406 if( wxTheClipboard->Open() )
408 if( wxTheClipboard->IsSupported( wxDF_TEXT )
409 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
411 if(
m_grid->IsEditable() )
415 wxTheClipboard->Close();
418 m_grid->PopupMenu( &menu );
430 int menu_id =
event.GetId();
462 if(
m_grid->IsColShown( col ) )
473 bool handled =
false;
475 if( ( ev.GetKeyCode() == WXK_RETURN || ev.GetKeyCode() == WXK_NUMPAD_ENTER )
476 && ev.GetModifiers() == wxMOD_NONE
477 &&
m_grid->GetGridCursorRow() ==
m_grid->GetNumberRows() - 1 )
479 if(
m_grid->IsCellEditControlShown() )
486 wxCommandEvent
dummy;
491 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'V' )
493 if(
m_grid->IsCellEditControlShown() && wxTheClipboard->Open() )
495 if( wxTheClipboard->IsSupported( wxDF_TEXT )
496 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
498 wxTextDataObject data;
499 wxTheClipboard->GetData( data );
501 if( data.GetText().Contains(
COL_SEP ) || data.GetText().Contains(
ROW_SEP ) )
503 wxString stripped( data.GetText() );
504 stripped.Replace(
ROW_SEP,
" " );
506 stripped.Replace(
COL_SEP,
" " );
509 if( wxTextEntry* te =
dynamic_cast<wxTextEntry*
>( ev.GetEventObject() ) )
510 te->WriteText( stripped );
518 wxTheClipboard->Close();
522 else if( ev.GetKeyCode() == WXK_ESCAPE )
524 if(
m_grid->IsCellEditControlShown() )
538 if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'A' )
543 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'C' )
549 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'V' )
555 else if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() ==
'X' )
561 else if( !ev.GetModifiers() && ev.GetKeyCode() == WXK_DELETE )
569 if(
m_grid->IsEditable() && ev.GetKeyCode() ==
' ' )
574 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
576 wxArrayInt rowSel =
m_grid->GetSelectedRows();
578 for(
unsigned int rowInd = 0; rowInd < rowSel.GetCount(); rowInd++ )
579 retVal |=
toggleCell( rowSel[rowInd], 0,
true );
583 else if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectColumns )
585 wxArrayInt colSel =
m_grid->GetSelectedCols();
587 for(
unsigned int colInd = 0; colInd < colSel.GetCount(); colInd++ )
588 retVal |=
toggleCell( 0, colSel[colInd],
true );
592 else if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectCells )
594 wxArrayInt rowSel =
m_grid->GetSelectedRows();
595 wxArrayInt colSel =
m_grid->GetSelectedCols();
596 wxGridCellCoordsArray cellSel =
m_grid->GetSelectedCells();
597 wxGridCellCoordsArray topLeft =
m_grid->GetSelectionBlockTopLeft();
598 wxGridCellCoordsArray botRight =
m_grid->GetSelectionBlockBottomRight();
601 for(
unsigned int cellInd = 0; cellInd < cellSel.GetCount(); cellInd++ )
603 retVal |=
toggleCell( cellSel[cellInd].GetRow(), cellSel[cellInd].GetCol(),
true );
607 for(
unsigned int colInd = 0; colInd < colSel.GetCount(); colInd++ )
609 for(
int row = 0; row <
m_grid->GetNumberRows(); row++ )
610 retVal |=
toggleCell( row, colSel[colInd],
true );
614 for(
unsigned int rowInd = 0; rowInd < rowSel.GetCount(); rowInd++ )
616 for(
int col = 0; col <
m_grid->GetNumberCols(); col++ )
617 retVal |=
toggleCell( rowSel[rowInd], col,
true );
621 for(
unsigned int blockInd = 0; blockInd < topLeft.GetCount(); blockInd++ )
623 wxGridCellCoords start = topLeft[blockInd];
624 wxGridCellCoords end = botRight[blockInd];
626 for(
int row = start.GetRow(); row <= end.GetRow(); row++ )
628 for(
int col = start.GetCol(); col <= end.GetCol(); col++ )
641 bool ctrl = ev.RawControlDown();
643 bool ctrl = ev.ControlDown();
646 if( ctrl && ev.GetKeyCode() == WXK_TAB )
653 while(
test && !
test->IsTopLevel() )
657 if(
test->HasFocus() )
660 if( !
test->GetChildren().empty() )
664 else if(
test->GetNextSibling() )
678 else if(
test &&
test->GetNextSibling() )
698 if(
m_grid->IsEditable() && wxTheClipboard->Open() )
700 if( wxTheClipboard->IsSupported( wxDF_TEXT )
701 || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
703 wxTextDataObject data;
705 wxTheClipboard->GetData( data );
707 wxString
text = data.GetText();
711 text.Replace(
"\n\n",
"\n" );
717 wxTheClipboard->Close();
728 wxGridTableBase* tbl =
m_grid->GetTable();
730 const int cur_row =
m_grid->GetGridCursorRow();
731 const int cur_col =
m_grid->GetGridCursorCol();
736 bool is_selection =
false;
738 if( cur_row < 0 || cur_col < 0 )
744 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
754 wxStringTokenizer rows( cb_text,
ROW_SEP, wxTOKEN_RET_EMPTY );
770 end_row = cur_row + rows.CountTokens();
772 if( end_row > tbl->GetNumberRows() )
776 for(
int ii = end_row - tbl->GetNumberRows(); ii > 0; --ii )
778 wxCommandEvent
dummy;
783 end_row = tbl->GetNumberRows();
790 for(
int row = start_row; row < end_row; ++row )
794 if( !rows.HasMoreTokens() )
795 rows.SetString( cb_text,
ROW_SEP, wxTOKEN_RET_EMPTY );
797 wxString rowTxt = rows.GetNextToken();
799 wxStringTokenizer cols( rowTxt,
COL_SEP, wxTOKEN_RET_EMPTY );
802 end_col = cur_col + cols.CountTokens();
804 for(
int col = start_col; col < end_col && col < tbl->GetNumberCols(); ++col )
807 if( !
m_grid->IsColShown( col ) )
815 if( !cols.HasMoreTokens() )
816 cols.SetString( rowTxt,
COL_SEP, wxTOKEN_RET_EMPTY );
818 wxString cellTxt = cols.GetNextToken();
822 if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_STRING ) && !
isReadOnly( row, col ) )
824 tbl->SetValue( row, col, cellTxt );
826 wxGridEvent evt(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, row, col );
827 m_grid->GetEventHandler()->ProcessEvent( evt );
830 else if( tbl->CanSetValueAs( row, col, wxGRID_VALUE_BOOL ) )
832 tbl->SetValueAsBool( row, col, cellTxt == wxT(
"1" ) );
834 wxGridEvent evt(
m_grid->GetId(), wxEVT_GRID_CELL_CHANGED,
m_grid, row, col );
835 m_grid->GetEventHandler()->ProcessEvent( evt );
846 if( doCopy && !wxTheClipboard->Open() )
849 wxGridTableBase* tbl =
m_grid->GetTable();
857 if( !
m_grid->IsColShown( col ) )
860 txt += tbl->GetValue( row, col );
870 tbl->SetValue( row, col, wxEmptyString );
879 wxTheClipboard->SetData(
new wxTextDataObject( txt ) );
880 wxTheClipboard->Flush();
881 wxTheClipboard->Close();
893 if(
m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
895 int cursorRow =
m_grid->GetGridCursorRow();
896 bool cursorInSelectedRow =
false;
898 for(
int row :
m_grid->GetSelectedRows() )
900 if( row == cursorRow )
902 cursorInSelectedRow =
true;
907 if( !cursorInSelectedRow && cursorRow >= 0 )
908 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)
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)
WX_GRID * m_grid
I don't own the grid, but he owns me.
bool isTextEntry(int aRow, int aCol)
void onGridCellLeftDClick(wxGridEvent &event)
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)
bool CancelPendingChanges()
void ShowEditorOnMouseUp()
WxWidgets has a bunch of bugs in its handling of wxGrid mouse events which close cell editors right a...
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
@ GRIDTRICKS_FIRST_SHOWHIDE
std::vector< FAB_LAYER_COLOR > dummy