21#include <wx/tokenzr.h>
23#include <wx/settings.h>
25#include <wx/textentry.h>
44 wxGridCellAttr::wxAttrKind aKind )
46 wxGridCellAttr* attr = aInputAttr;
48 if( wxGridCellAttrProvider* provider = GetAttrProvider() )
50 wxGridCellAttr* providerAttr = provider->GetAttr( aRow, aCol, aKind );
54 attr =
new wxGridCellAttr;
55 attr->SetKind( wxGridCellAttr::Merged );
59 attr->MergeWith( aInputAttr );
63 attr->MergeWith( providerAttr );
64 providerAttr->DecRef();
72#define MIN_GRIDCELL_MARGIN FromDIP( 2 )
78 aEntry->SetMargins( 0, 0 );
84#if defined( __WXMSW__ ) || defined( __WXGTK__ )
92 KIGFX::COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK );
93 KIGFX::COLOR4D fg = wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER );
104 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
107 rect.SetTop( rect.GetTop() + 1 );
108 rect.SetLeft( rect.GetLeft() + 1 );
109 rect.SetBottom( rect.GetBottom() - 1 );
110 rect.SetRight( rect.GetRight() - 1 );
111 dc.DrawRectangle( rect );
121 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
124 rect.SetTop( rect.GetTop() + 1 );
125 rect.SetLeft( rect.GetLeft() );
126 rect.SetBottom( rect.GetBottom() - 1 );
127 rect.SetRight( rect.GetRight() - 1 );
128 dc.DrawRectangle( rect );
138 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
141 rect.SetTop( rect.GetTop() + 1 );
142 rect.SetLeft( rect.GetLeft() + 1 );
143 rect.SetBottom( rect.GetBottom() - 1 );
144 rect.SetRight( rect.GetRight() );
145 dc.DrawRectangle( rect );
158 wxGridCellAttrProvider(),
172 wxGridCellAttr*
GetAttr(
int row,
int col, wxGridCellAttr::wxAttrKind kind )
const override
174 wxGridCellAttrPtr cellAttr( wxGridCellAttrProvider::GetAttr( row, col, kind ) );
179 return cellAttr.release();
187 if( !cellAttr->HasBackgroundColour() )
189 cellAttr = cellAttr->Clone();
190 cellAttr->SetBackgroundColour(
m_attrEven->GetBackgroundColour() );
194 return cellAttr.release();
202WX_GRID::WX_GRID( wxWindow *parent, wxWindowID
id,
const wxPoint& pos,
const wxSize& size,
long style,
203 const wxString&
name ) :
204 wxGrid( parent, id, pos, size, style,
name ),
208 SetDefaultRowSize( GetDefaultRowSize() + FromDIP( 4 ) );
210 SetDefaultCellOverflow(
false );
245 std::vector<int> hiddenCols;
247 for(
int col = 0; col < GetNumberCols(); ++col )
249 if( !IsColShown( col ) )
250 hiddenCols.push_back( col );
255 if( !hiddenCols.empty() )
260 for(
int col : hiddenCols )
273 wxGrid::SetColLabelSize( wxGRID_AUTOSIZE );
280 if( aHeight == 0 || aHeight == wxGRID_AUTOSIZE )
282 wxGrid::SetColLabelSize( aHeight );
289 wxGrid::SetColLabelSize( std::max( aHeight, minHeight ) );
303 int numberCols = GetNumberCols();
304 int* formBuilderColWidths =
new int[numberCols];
306 for(
int i = 0; i < numberCols; ++i )
307 formBuilderColWidths[ i ] = GetColSize( i );
309 wxGrid::SetTable( aTable );
313 numberCols = std::min( numberCols, GetNumberCols() );
315 for(
int i = 0; i < numberCols; ++i )
320 SetColSize( i, std::max( formBuilderColWidths[ i ], headingWidth ) );
323 delete[] formBuilderColWidths;
336 wxGridTableBase*
table = wxGrid::GetTable();
338 wxCHECK_MSG(
table, ,
"Tried to enable alternate row colors without a table assigned to the grid" );
342 wxColor color = wxGrid::GetDefaultCellBackgroundColour();
347 table->SetAttrProvider(
nullptr );
357 int row = aEvent.GetRow();
358 int col = aEvent.GetCol();
360 if( row >= 0 && row < GetNumberRows() && col >= 0 && col < GetNumberCols() )
362 if( GetSelectionMode() == wxGrid::wxGridSelectCells )
364 SelectBlock( row, col, row, col,
false );
366 else if( GetSelectionMode() == wxGrid::wxGridSelectRows
367 || GetSelectionMode() == wxGrid::wxGridSelectRowsOrColumns )
369 SelectBlock( row, 0, row, GetNumberCols() - 1,
false );
371 else if( GetSelectionMode() == wxGrid::wxGridSelectColumns )
373 SelectBlock( 0, col, GetNumberRows() - 1, col,
false );
380 if( !m_firstSelectionRefreshDone )
382 m_firstSelectionRefreshDone =
true;
383 CallAfter( [
this]() { ForceRefresh(); } );
394 int row = aEvent.GetRow();
395 int col = aEvent.GetCol();
397 const std::pair<wxString, wxString>& beforeAfter =
m_evalBeforeAfter[ { row, col } ];
399 if( GetCellValue( row, col ) == beforeAfter.second )
400 SetCellValue( row, col, beforeAfter.first );
407 const int col = aEvent.GetCol();
414 EDA_UNITS cellUnits = cellUnitsData.first;
417 m_eval->SetDefaultUnits( cellUnits );
419 const int row = aEvent.GetRow();
422 bool isNullable =
false;
423 wxGridCellEditor* cellEditor = GetCellEditor( row, col );
429 isNullable = nullable->IsNullable();
431 cellEditor->DecRef();
435 [
this, row, col, isNullable, unitsProvider, cellDataType]()
439 if( row >= GetNumberRows() || col >= GetNumberCols() )
442 wxString stringValue = GetCellValue( row, col );
443 bool processedOk =
true;
446 processedOk =
m_eval->Process( stringValue );
454 std::optional<int> val;
474 if( stringValue != evalValue )
476 SetCellValue( row, col, evalValue );
496 wxGrid::SetTable(
nullptr );
503 wxString shownColumns;
505 for(
int i = 0; i < GetNumberCols(); ++i )
507 if( IsColShown( i ) )
509 if( shownColumns.Length() )
510 shownColumns << wxT(
" " );
522 std::bitset<64> shownColumns;
524 for(
int ii = 0; ii < GetNumberCols(); ++ii )
525 shownColumns[ii] = IsColShown( ii );
533 for(
int i = 0; i < GetNumberCols(); ++i )
536 wxStringTokenizer shownTokens( shownColumns,
" \t\r\n", wxTOKEN_STRTOK );
538 while( shownTokens.HasMoreTokens() )
541 shownTokens.GetNextToken().ToLong( &colNumber );
543 if( colNumber >= 0 && colNumber < GetNumberCols() )
544 ShowCol( (
int) colNumber );
551 if( m_nativeColumnLabels )
552 wxGrid::DrawCornerLabel( dc );
554 wxRect rect( wxSize( m_rowLabelWidth, m_colLabelHeight ) );
560 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
561 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
562 dc.DrawRectangle( rect.Inflate( 1 ) );
571 if( m_nativeColumnLabels )
572 wxGrid::DrawColLabel( dc, col );
574 if( GetColWidth( col ) <= 0 || m_colLabelHeight <= 0 )
577 wxRect rect( GetColLeft( col ), 0, GetColWidth( col ), m_colLabelHeight );
583 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
584 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
585 dc.DrawRectangle( rect.Inflate( 1 ) );
591 dc.SetFont( GetLabelFont() );
594 GetColLabelAlignment( &hAlign, &vAlign );
595 const int orient = GetColLabelTextOrientation();
598 hAlign = wxALIGN_LEFT;
600 if( hAlign == wxALIGN_LEFT )
603 rend.DrawLabel( *
this, dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
609 if( GetRowHeight( row ) <= 0 || m_rowLabelWidth <= 0 )
612 wxRect rect( 0, GetRowTop( row ), m_rowLabelWidth, GetRowHeight( row ) );
618 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
619 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
620 dc.DrawRectangle( rect.Inflate( 1 ) );
626 dc.SetFont( GetLabelFont() );
629 GetRowLabelAlignment(&hAlign, &vAlign);
631 if( hAlign == wxALIGN_LEFT )
634 rend.DrawLabel( *
this, dc, GetRowLabelValue( row ), rect, hAlign, vAlign, wxHORIZONTAL );
640 if( !IsCellEditControlEnabled() )
643 HideCellEditControl();
646 m_cellEditCtrlEnabled =
false;
648 int row = m_currentCellCoords.GetRow();
649 int col = m_currentCellCoords.GetCol();
651 wxString oldval = GetCellValue( row, col );
654 wxGridCellAttr* attr = GetCellAttr( row, col );
655 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
657 editor->EndEdit( row, col,
this, oldval, &newval );
668 if( !IsCellEditControlEnabled() )
671 if( !aQuietMode && SendEvent( wxEVT_GRID_EDITOR_HIDDEN ) == -1 )
674 HideCellEditControl();
677 m_cellEditCtrlEnabled =
false;
679 int row = m_currentCellCoords.GetRow();
680 int col = m_currentCellCoords.GetCol();
682 wxString oldval = GetCellValue( row, col );
685 wxGridCellAttr* attr = GetCellAttr( row, col );
686 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
688 bool changed =
editor->EndEdit( row, col,
this, oldval, &newval );
695 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGING, newval ) == -1 )
698 editor->ApplyEdit( row, col,
this );
703 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGED, oldval ) == -1 )
706 SetCellValue( row, col, oldval );
723 auto [row, editCol] = aAdder();
727 MakeCellVisible( row, std::max( editCol, 0 ) );
728 SetGridCursor( row, std::max( editCol, 0 ) );
732 EnableCellEditControl(
true );
733 ShowCellEditControl();
750 const std::function<
void(
int row )>& aDeleter )
752 wxArrayInt selectedRows = GetSelectedRows();
754 auto addSelectedRow = [&](
int row )
756 for(
size_t i = 0; i < selectedRows.size(); ++i )
758 if( selectedRows[i] == row )
762 selectedRows.push_back( row );
765 wxGridCellCoordsArray topLeft = GetSelectionBlockTopLeft();
766 wxGridCellCoordsArray botRight = GetSelectionBlockBottomRight();
768 for(
size_t i = 0; i < std::min( topLeft.Count(), botRight.Count() ); ++i )
770 for(
int row = topLeft[i].GetRow(); row <= botRight[i].GetRow(); ++row )
771 addSelectedRow( row );
774 wxGridCellCoordsArray cells = GetSelectedCells();
776 for(
size_t i = 0; i < cells.Count(); ++i )
777 addSelectedRow( cells[i].GetRow() );
779 if( selectedRows.empty() && GetGridCursorRow() >= 0 )
780 selectedRows.push_back( GetGridCursorRow() );
782 if( selectedRows.empty() )
785 for(
int row : selectedRows )
787 if( !aFilter( row ) )
796 [](
int* first,
int* second )
798 return *second - *first;
801 int nextSelRow = selectedRows.back() - 1;
803 if( nextSelRow >= 0 )
805 GoToCell( nextSelRow, GetGridCursorCol() );
806 SetGridCursor( nextSelRow, GetGridCursorCol() );
809 for(
int row : selectedRows )
816 for(
int col = 0; col < GetNumberCols(); ++col )
818 wxString temp = GetCellValue( aRowA, col );
819 SetCellValue( aRowA, col, GetCellValue( aRowB, col ) );
820 SetCellValue( aRowB, col, temp );
837 const std::function<
void(
int row )>& aMover )
842 int i = GetGridCursorRow();
844 if( i > 0 && aFilter( i ) )
848 SetGridCursor( i - 1, GetGridCursorCol() );
849 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
870 const std::function<
void(
int row )>& aMover )
875 int i = GetGridCursorRow();
877 if( i + 1 < GetNumberRows() && aFilter( i ) )
881 SetGridCursor( i + 1, GetGridCursorCol() );
882 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
915 wxString stringValue = GetCellValue( aRow, aCol );
921 m_eval->SetDefaultUnits( cellUnits );
923 if(
m_eval->Process( stringValue ) )
924 stringValue =
m_eval->Result();
933 wxString stringValue = GetCellValue( aRow, aCol );
939 m_eval->SetDefaultUnits( cellUnits );
942 stringValue =
m_eval->Result();
958 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromValue( aValue,
true, cellDataType ) );
971 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromOptionalValue( aValue,
true, cellDataType ) );
989 size = GetRowLabelSize();
991 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
992 size = std::max( size,
int( GetTextExtent( GetRowLabelValue( row ) + wxS(
"M" ) ).x ) );
997 size = GetColSize( aCol );
1005 size = std::max( size,
int( GetTextExtent( GetColLabelValue( aCol ) + wxS(
"M" ) ).x ) );
1008 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
1011 if( GetTable()->CanGetValueAs( row, aCol, wxGRID_VALUE_STRING ) )
1012 size = std::max( size, GetTextExtent( GetCellValue( row, aCol ) + wxS(
"M" ) ).x );
1014 size = std::max( size, GetTextExtent(
"MM" ).x );
1024 int line_height = int( GetTextExtent(
"Mj" ).y ) + 3;
1025 int row_height = GetColLabelSize();
1026 int initial_row_height = row_height;
1031 for(
int col = 0; col < GetNumberCols(); col++ )
1033 int nl_count = GetColLabelValue( col ).Freq(
'\n' );
1038 if( row_height < line_height * ( nl_count+1 ) )
1039 row_height += line_height * nl_count;
1045 if( initial_row_height != row_height )
1062 const int colCount = GetNumberCols();
1064 for(
int ii = 0; ii < GetNumberCols(); ++ii )
1069 wxASSERT_MSG(
m_flexibleCol < colCount,
"Flexible column index does not exist in grid" );
1071 Bind( wxEVT_UPDATE_UI,
1072 [
this]( wxUpdateUIEvent& aEvent )
1079 [
this]( wxSizeEvent& aEvent )
1086 Bind( wxEVT_GRID_CELL_CHANGED,
1087 [
this]( wxGridEvent& aEvent )
1099 const int width = GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
1101 std::optional<int> flexibleMinWidth;
1105 if( GetColSize( colIndex ) != 0 )
1107 AutoSizeColumn( colIndex );
1108 const int colSize = GetColSize( colIndex );
1110 int minWidthScaled = FromDIP( minWidth );
1111 SetColSize( colIndex, std::max( minWidthScaled, colSize ) );
1114 flexibleMinWidth = minWidthScaled;
1119 int nonFlexibleWidth = 0;
1121 for(
int i = 0; i < GetNumberCols(); ++i )
1124 nonFlexibleWidth += GetColSize( i );
1128 SetColSize(
m_flexibleCol, std::max( flexibleMinWidth.value_or( 0 ), width - nonFlexibleWidth ) );
1139 const int width = aEvent.GetSize().GetX();
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
A color representation with 4 components: red, green, blue, alpha.
wxColour ToColour() const
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
Icon provider for the "standard" row indicators, for example in layer selection lists.
static const wxString NullUiString
The string that is used in the UI to represent a null value.
std::optional< int > OptionalValueFromString(const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aTextValue in aUnits to internal units used by the frame.
wxString StringFromOptionalValue(std::optional< int > aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts an optional aValue in internal units into a united string.
EDA_UNITS GetUserUnits() const
static EDA_DATA_TYPE GetTypeFromUnits(const EDA_UNITS aUnits)
Gets the inferred type from the given units.
wxString StringFromValue(double aValue, bool aAddUnitLabel=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aValue in internal units into a united string.
int ValueFromString(const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
Converts aTextValue in aUnits to internal units used by the frame.
Attribute provider that provides attributes (or modifies the existing attribute) to alternate a row c...
WX_GRID_ALT_ROW_COLOR_PROVIDER(const wxColor &aBaseColor)
wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) const override
wxGridCellAttrPtr m_attrEven
void UpdateColors(const wxColor &aBaseColor)
void DrawBorder(const wxGrid &grid, wxDC &dc, wxRect &rect) const override
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
int GetVisibleWidth(int aCol, bool aHeader=true, bool aContents=true, bool aKeep=false)
Calculate the specified column based on the actual size of the text on screen.
void onGridCellSelect(wxGridEvent &aEvent)
std::map< int, int > m_autosizedCols
void SetLabelFont(const wxFont &aFont)
Hide wxGrid's SetLabelFont() because for some reason on MSW it's a one-shot and subsequent calls to i...
void onDPIChanged(wxDPIChangedEvent &event)
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
void OnMoveRowUp(const std::function< void(int row)> &aMover)
std::map< int, UNITS_PROVIDER * > m_unitsProviders
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
void DestroyTable(wxGridTableBase *aTable)
Work-around for a bug in wxGrid which crashes when deleting the table if the cell edit control was no...
std::unordered_map< int, std::pair< EDA_UNITS, EDA_DATA_TYPE > > m_autoEvalColsUnits
void SetAutoEvalColUnits(int col, EDA_UNITS aUnit, EDA_DATA_TYPE aUnitType)
Set the unit and unit data type to use for a given column.
bool CancelPendingChanges()
void SetColLabelSize(int aHeight)
Hide wxGrid's SetColLabelSize() method with one which makes sure the size is tall enough for the syst...
void SwapRows(int aRowA, int aRowB)
These aren't that tricky, but might as well share code.
std::pair< EDA_UNITS, EDA_DATA_TYPE > getColumnUnits(int aCol) const
Returns the units and data type associated with a given column.
void SetUnitValue(int aRow, int aCol, int aValue)
Set a unitized cell's value.
WX_GRID(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxWANTS_CHARS, const wxString &name=wxGridNameStr)
int GetUnitValue(int aRow, int aCol)
Apply standard KiCad unit and eval services to a numeric cell.
std::vector< int > m_autoEvalCols
UNITS_PROVIDER * getUnitsProvider(int aCol) const
std::map< std::pair< int, int >, std::pair< wxString, wxString > > m_evalBeforeAfter
void DrawCornerLabel(wxDC &dc) override
A re-implementation of wxGrid::DrawCornerLabel which draws flat borders.
ROW_ICON_PROVIDER * m_rowIconProvider
void onCellEditorHidden(wxGridEvent &aEvent)
void SetupColumnAutosizer(int aFlexibleCol)
Set autosize behaviour using wxFormBuilder column widths as minimums, with a single specified growabl...
void RecomputeGridWidths()
void OnMoveRowDown(const std::function< void(int row)> &aMover)
void onGridColMove(wxGridEvent &aEvent)
void SetOptionalUnitValue(int aRow, int aCol, std::optional< int > aValue)
Set a unitized cell's optional value.
void onSizeEvent(wxSizeEvent &aEvent)
void onCellEditorShown(wxGridEvent &aEvent)
void EnsureColLabelsVisible()
Ensure the height of the row displaying the column labels is enough, even if labels are multiline tex...
void OnDeleteRows(const std::function< void(int row)> &aDeleter)
Handles a row deletion event.
wxString GetShownColumnsAsString()
Get a tokenized string containing the shown column indexes.
void OnAddRow(const std::function< std::pair< int, int >()> &aAdder)
void DrawRowLabel(wxDC &dc, int row) override
A re-implementation of wxGrid::DrawRowLabel which draws flat borders.
std::bitset< 64 > GetShownColumns()
static void CellEditorSetMargins(wxTextEntryBase *aEntry)
A helper function to set OS-specific margins for text-based cell editors.
std::optional< int > GetOptionalUnitValue(int aRow, int aCol)
Apply standard KiCad unit and eval services to a numeric cell.
void EnableAlternateRowColors(bool aEnable=true)
Enable alternate row highlighting, where every odd row has a different background color than the even...
void SetUnitsProvider(UNITS_PROVIDER *aProvider, int aCol=0)
Set a EUNITS_PROVIDER to enable use of unit- and eval-based Getters.
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
std::unique_ptr< NUMERIC_EVALUATOR > m_eval
void DrawColLabel(wxDC &dc, int col) override
A re-implementation of wxGrid::DrawColLabel which left-aligns the first column and draws flat borders...
static void CellEditorTransformSizeRect(wxRect &aRect)
A helper function to tweak sizes of text-based cell editors depending on OS.
EDA_DATA_TYPE
The type of unit.
KICOMMON_API wxFont GetControlFont(wxWindow *aWindow)
const int c_IndicatorSizeDIP
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
PGM_BASE & Pgm()
The global program "get" accessor.
std::vector< std::vector< std::string > > table
Functions to provide common constants and other functions to assist in making a consistent UI.
wxColour getBorderColour()
#define MIN_GRIDCELL_MARGIN