25#include <wx/tokenzr.h>
27#include <wx/settings.h>
29#include <wx/textentry.h>
48 wxGridCellAttr::wxAttrKind aKind )
50 wxGridCellAttr* attr = aInputAttr;
52 if( wxGridCellAttrProvider* provider = GetAttrProvider() )
54 wxGridCellAttr* providerAttr = provider->GetAttr( aRow, aCol, aKind );
58 attr =
new wxGridCellAttr;
59 attr->SetKind( wxGridCellAttr::Merged );
63 attr->MergeWith( aInputAttr );
67 attr->MergeWith( providerAttr );
68 providerAttr->DecRef();
76#define MIN_GRIDCELL_MARGIN FromDIP( 2 )
82 aEntry->SetMargins( 0, 0 );
88#if defined( __WXMSW__ ) || defined( __WXGTK__ )
96 KIGFX::COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK );
97 KIGFX::COLOR4D fg = wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER );
108 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
111 rect.SetTop( rect.GetTop() + 1 );
112 rect.SetLeft( rect.GetLeft() + 1 );
113 rect.SetBottom( rect.GetBottom() - 1 );
114 rect.SetRight( rect.GetRight() - 1 );
115 dc.DrawRectangle( rect );
125 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
128 rect.SetTop( rect.GetTop() + 1 );
129 rect.SetLeft( rect.GetLeft() );
130 rect.SetBottom( rect.GetBottom() - 1 );
131 rect.SetRight( rect.GetRight() - 1 );
132 dc.DrawRectangle( rect );
142 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
145 rect.SetTop( rect.GetTop() + 1 );
146 rect.SetLeft( rect.GetLeft() + 1 );
147 rect.SetBottom( rect.GetBottom() - 1 );
148 rect.SetRight( rect.GetRight() );
149 dc.DrawRectangle( rect );
162 wxGridCellAttrProvider(),
176 wxGridCellAttr*
GetAttr(
int row,
int col, wxGridCellAttr::wxAttrKind kind )
const override
178 wxGridCellAttrPtr cellAttr( wxGridCellAttrProvider::GetAttr( row, col, kind ) );
183 return cellAttr.release();
191 if( !cellAttr->HasBackgroundColour() )
193 cellAttr = cellAttr->Clone();
194 cellAttr->SetBackgroundColour(
m_attrEven->GetBackgroundColour() );
198 return cellAttr.release();
206WX_GRID::WX_GRID( wxWindow *parent, wxWindowID
id,
const wxPoint& pos,
const wxSize& size,
long style,
207 const wxString&
name ) :
208 wxGrid( parent, id, pos, size, style,
name ),
212 SetDefaultRowSize( GetDefaultRowSize() + FromDIP( 4 ) );
214 SetDefaultCellOverflow(
false );
249 std::vector<int> hiddenCols;
251 for(
int col = 0; col < GetNumberCols(); ++col )
253 if( !IsColShown( col ) )
254 hiddenCols.push_back( col );
259 if( !hiddenCols.empty() )
264 for(
int col : hiddenCols )
277 wxGrid::SetColLabelSize( wxGRID_AUTOSIZE );
284 if( aHeight == 0 || aHeight == wxGRID_AUTOSIZE )
286 wxGrid::SetColLabelSize( aHeight );
293 wxGrid::SetColLabelSize( std::max( aHeight, minHeight ) );
307 int numberCols = GetNumberCols();
308 int* formBuilderColWidths =
new int[numberCols];
310 for(
int i = 0; i < numberCols; ++i )
311 formBuilderColWidths[ i ] = GetColSize( i );
313 wxGrid::SetTable( aTable );
317 numberCols = std::min( numberCols, GetNumberCols() );
319 for(
int i = 0; i < numberCols; ++i )
324 SetColSize( i, std::max( formBuilderColWidths[ i ], headingWidth ) );
327 delete[] formBuilderColWidths;
340 wxGridTableBase*
table = wxGrid::GetTable();
342 wxCHECK_MSG(
table, ,
"Tried to enable alternate row colors without a table assigned to the grid" );
346 wxColor color = wxGrid::GetDefaultCellBackgroundColour();
351 table->SetAttrProvider(
nullptr );
361 int row = aEvent.GetRow();
362 int col = aEvent.GetCol();
364 if( row >= 0 && row < GetNumberRows() && col >= 0 && col < GetNumberCols() )
366 if( GetSelectionMode() == wxGrid::wxGridSelectCells )
368 SelectBlock( row, col, row, col,
false );
370 else if( GetSelectionMode() == wxGrid::wxGridSelectRows
371 || GetSelectionMode() == wxGrid::wxGridSelectRowsOrColumns )
373 SelectBlock( row, 0, row, GetNumberCols() - 1,
false );
375 else if( GetSelectionMode() == wxGrid::wxGridSelectColumns )
377 SelectBlock( 0, col, GetNumberRows() - 1, col,
false );
384 if( !m_firstSelectionRefreshDone )
386 m_firstSelectionRefreshDone =
true;
387 CallAfter( [
this]() { ForceRefresh(); } );
398 int row = aEvent.GetRow();
399 int col = aEvent.GetCol();
401 const std::pair<wxString, wxString>& beforeAfter =
m_evalBeforeAfter[ { row, col } ];
403 if( GetCellValue( row, col ) == beforeAfter.second )
404 SetCellValue( row, col, beforeAfter.first );
411 const int col = aEvent.GetCol();
418 EDA_UNITS cellUnits = cellUnitsData.first;
421 m_eval->SetDefaultUnits( cellUnits );
423 const int row = aEvent.GetRow();
426 bool isNullable =
false;
427 wxGridCellEditor* cellEditor = GetCellEditor( row, col );
433 isNullable = nullable->IsNullable();
435 cellEditor->DecRef();
439 [
this, row, col, isNullable, unitsProvider, cellDataType]()
443 if( row >= GetNumberRows() || col >= GetNumberCols() )
446 wxString stringValue = GetCellValue( row, col );
447 bool processedOk =
true;
450 processedOk =
m_eval->Process( stringValue );
458 std::optional<int> val;
478 if( stringValue != evalValue )
480 SetCellValue( row, col, evalValue );
500 wxGrid::SetTable(
nullptr );
507 wxString shownColumns;
509 for(
int i = 0; i < GetNumberCols(); ++i )
511 if( IsColShown( i ) )
513 if( shownColumns.Length() )
514 shownColumns << wxT(
" " );
526 std::bitset<64> shownColumns;
528 for(
int ii = 0; ii < GetNumberCols(); ++ii )
529 shownColumns[ii] = IsColShown( ii );
537 for(
int i = 0; i < GetNumberCols(); ++i )
540 wxStringTokenizer shownTokens( shownColumns,
" \t\r\n", wxTOKEN_STRTOK );
542 while( shownTokens.HasMoreTokens() )
545 shownTokens.GetNextToken().ToLong( &colNumber );
547 if( colNumber >= 0 && colNumber < GetNumberCols() )
548 ShowCol( (
int) colNumber );
555 if( m_nativeColumnLabels )
556 wxGrid::DrawCornerLabel( dc );
558 wxRect rect( wxSize( m_rowLabelWidth, m_colLabelHeight ) );
564 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
565 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
566 dc.DrawRectangle( rect.Inflate( 1 ) );
575 if( m_nativeColumnLabels )
576 wxGrid::DrawColLabel( dc, col );
578 if( GetColWidth( col ) <= 0 || m_colLabelHeight <= 0 )
581 wxRect rect( GetColLeft( col ), 0, GetColWidth( col ), m_colLabelHeight );
587 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
588 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
589 dc.DrawRectangle( rect.Inflate( 1 ) );
595 dc.SetFont( GetLabelFont() );
598 GetColLabelAlignment( &hAlign, &vAlign );
599 const int orient = GetColLabelTextOrientation();
602 hAlign = wxALIGN_LEFT;
604 if( hAlign == wxALIGN_LEFT )
607 rend.DrawLabel( *
this, dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
613 if( GetRowHeight( row ) <= 0 || m_rowLabelWidth <= 0 )
616 wxRect rect( 0, GetRowTop( row ), m_rowLabelWidth, GetRowHeight( row ) );
622 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
623 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
624 dc.DrawRectangle( rect.Inflate( 1 ) );
630 dc.SetFont( GetLabelFont() );
633 GetRowLabelAlignment(&hAlign, &vAlign);
635 if( hAlign == wxALIGN_LEFT )
638 rend.DrawLabel( *
this, dc, GetRowLabelValue( row ), rect, hAlign, vAlign, wxHORIZONTAL );
644 if( !IsCellEditControlEnabled() )
647 HideCellEditControl();
650 m_cellEditCtrlEnabled =
false;
652 int row = m_currentCellCoords.GetRow();
653 int col = m_currentCellCoords.GetCol();
655 wxString oldval = GetCellValue( row, col );
658 wxGridCellAttr* attr = GetCellAttr( row, col );
659 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
661 editor->EndEdit( row, col,
this, oldval, &newval );
672 if( !IsCellEditControlEnabled() )
675 if( !aQuietMode && SendEvent( wxEVT_GRID_EDITOR_HIDDEN ) == -1 )
678 HideCellEditControl();
681 m_cellEditCtrlEnabled =
false;
683 int row = m_currentCellCoords.GetRow();
684 int col = m_currentCellCoords.GetCol();
686 wxString oldval = GetCellValue( row, col );
689 wxGridCellAttr* attr = GetCellAttr( row, col );
690 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
692 bool changed =
editor->EndEdit( row, col,
this, oldval, &newval );
699 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGING, newval ) == -1 )
702 editor->ApplyEdit( row, col,
this );
707 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGED, oldval ) == -1 )
710 SetCellValue( row, col, oldval );
727 auto [row, editCol] = aAdder();
731 MakeCellVisible( row, std::max( editCol, 0 ) );
732 SetGridCursor( row, std::max( editCol, 0 ) );
736 EnableCellEditControl(
true );
737 ShowCellEditControl();
754 const std::function<
void(
int row )>& aDeleter )
756 wxArrayInt selectedRows = GetSelectedRows();
758 auto addSelectedRow = [&](
int row )
760 for(
size_t i = 0; i < selectedRows.size(); ++i )
762 if( selectedRows[i] == row )
766 selectedRows.push_back( row );
769 wxGridCellCoordsArray topLeft = GetSelectionBlockTopLeft();
770 wxGridCellCoordsArray botRight = GetSelectionBlockBottomRight();
772 for(
size_t i = 0; i < std::min( topLeft.Count(), botRight.Count() ); ++i )
774 for(
int row = topLeft[i].GetRow(); row <= botRight[i].GetRow(); ++row )
775 addSelectedRow( row );
778 wxGridCellCoordsArray cells = GetSelectedCells();
780 for(
size_t i = 0; i < cells.Count(); ++i )
781 addSelectedRow( cells[i].GetRow() );
783 if( selectedRows.empty() && GetGridCursorRow() >= 0 )
784 selectedRows.push_back( GetGridCursorRow() );
786 if( selectedRows.empty() )
789 for(
int row : selectedRows )
791 if( !aFilter( row ) )
800 [](
int* first,
int* second )
802 return *second - *first;
805 int nextSelRow = selectedRows.back() - 1;
807 if( nextSelRow >= 0 )
809 GoToCell( nextSelRow, GetGridCursorCol() );
810 SetGridCursor( nextSelRow, GetGridCursorCol() );
813 for(
int row : selectedRows )
820 for(
int col = 0; col < GetNumberCols(); ++col )
822 wxString temp = GetCellValue( aRowA, col );
823 SetCellValue( aRowA, col, GetCellValue( aRowB, col ) );
824 SetCellValue( aRowB, col, temp );
841 const std::function<
void(
int row )>& aMover )
846 int i = GetGridCursorRow();
848 if( i > 0 && aFilter( i ) )
852 SetGridCursor( i - 1, GetGridCursorCol() );
853 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
874 const std::function<
void(
int row )>& aMover )
879 int i = GetGridCursorRow();
881 if( i + 1 < GetNumberRows() && aFilter( i ) )
885 SetGridCursor( i + 1, GetGridCursorCol() );
886 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
919 wxString stringValue = GetCellValue( aRow, aCol );
925 m_eval->SetDefaultUnits( cellUnits );
927 if(
m_eval->Process( stringValue ) )
928 stringValue =
m_eval->Result();
937 wxString stringValue = GetCellValue( aRow, aCol );
943 m_eval->SetDefaultUnits( cellUnits );
946 stringValue =
m_eval->Result();
962 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromValue( aValue,
true, cellDataType ) );
975 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromOptionalValue( aValue,
true, cellDataType ) );
993 size = GetRowLabelSize();
995 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
996 size = std::max( size,
int( GetTextExtent( GetRowLabelValue( row ) + wxS(
"M" ) ).x ) );
1001 size = GetColSize( aCol );
1009 size = std::max( size,
int( GetTextExtent( GetColLabelValue( aCol ) + wxS(
"M" ) ).x ) );
1012 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
1015 if( GetTable()->CanGetValueAs( row, aCol, wxGRID_VALUE_STRING ) )
1016 size = std::max( size, GetTextExtent( GetCellValue( row, aCol ) + wxS(
"M" ) ).x );
1018 size = std::max( size, GetTextExtent(
"MM" ).x );
1028 int line_height = int( GetTextExtent(
"Mj" ).y ) + 3;
1029 int row_height = GetColLabelSize();
1030 int initial_row_height = row_height;
1035 for(
int col = 0; col < GetNumberCols(); col++ )
1037 int nl_count = GetColLabelValue( col ).Freq(
'\n' );
1042 if( row_height < line_height * ( nl_count+1 ) )
1043 row_height += line_height * nl_count;
1049 if( initial_row_height != row_height )
1066 const int colCount = GetNumberCols();
1068 for(
int ii = 0; ii < GetNumberCols(); ++ii )
1073 wxASSERT_MSG(
m_flexibleCol < colCount,
"Flexible column index does not exist in grid" );
1075 Bind( wxEVT_UPDATE_UI,
1076 [
this]( wxUpdateUIEvent& aEvent )
1083 [
this]( wxSizeEvent& aEvent )
1090 Bind( wxEVT_GRID_CELL_CHANGED,
1091 [
this]( wxGridEvent& aEvent )
1103 const int width = GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
1105 std::optional<int> flexibleMinWidth;
1109 if( GetColSize( colIndex ) != 0 )
1111 AutoSizeColumn( colIndex );
1112 const int colSize = GetColSize( colIndex );
1114 int minWidthScaled = FromDIP( minWidth );
1115 SetColSize( colIndex, std::max( minWidthScaled, colSize ) );
1118 flexibleMinWidth = minWidthScaled;
1123 int nonFlexibleWidth = 0;
1125 for(
int i = 0; i < GetNumberCols(); ++i )
1128 nonFlexibleWidth += GetColSize( i );
1132 SetColSize(
m_flexibleCol, std::max( flexibleMinWidth.value_or( 0 ), width - nonFlexibleWidth ) );
1143 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