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 if( selectedRows.empty() && GetGridCursorRow() >= 0 )
759 selectedRows.push_back( GetGridCursorRow() );
761 if( selectedRows.empty() )
764 for(
int row : selectedRows )
766 if( !aFilter( row ) )
775 [](
int* first,
int* second )
777 return *second - *first;
780 int nextSelRow = selectedRows.back() - 1;
782 if( nextSelRow >= 0 )
784 GoToCell( nextSelRow, GetGridCursorCol() );
785 SetGridCursor( nextSelRow, GetGridCursorCol() );
788 for(
int row : selectedRows )
795 for(
int col = 0; col < GetNumberCols(); ++col )
797 wxString temp = GetCellValue( aRowA, col );
798 SetCellValue( aRowA, col, GetCellValue( aRowB, col ) );
799 SetCellValue( aRowB, col, temp );
816 const std::function<
void(
int row )>& aMover )
821 int i = GetGridCursorRow();
823 if( i > 0 && aFilter( i ) )
827 SetGridCursor( i - 1, GetGridCursorCol() );
828 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
849 const std::function<
void(
int row )>& aMover )
854 int i = GetGridCursorRow();
856 if( i + 1 < GetNumberRows() && aFilter( i ) )
860 SetGridCursor( i + 1, GetGridCursorCol() );
861 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
894 wxString stringValue = GetCellValue( aRow, aCol );
900 m_eval->SetDefaultUnits( cellUnits );
902 if(
m_eval->Process( stringValue ) )
903 stringValue =
m_eval->Result();
912 wxString stringValue = GetCellValue( aRow, aCol );
918 m_eval->SetDefaultUnits( cellUnits );
921 stringValue =
m_eval->Result();
937 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromValue( aValue,
true, cellDataType ) );
950 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromOptionalValue( aValue,
true, cellDataType ) );
968 size = GetRowLabelSize();
970 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
971 size = std::max( size,
int( GetTextExtent( GetRowLabelValue( row ) + wxS(
"M" ) ).x ) );
976 size = GetColSize( aCol );
984 size = std::max( size,
int( GetTextExtent( GetColLabelValue( aCol ) + wxS(
"M" ) ).x ) );
987 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
990 if( GetTable()->CanGetValueAs( row, aCol, wxGRID_VALUE_STRING ) )
991 size = std::max( size, GetTextExtent( GetCellValue( row, aCol ) + wxS(
"M" ) ).x );
993 size = std::max( size, GetTextExtent(
"MM" ).x );
1003 int line_height = int( GetTextExtent(
"Mj" ).y ) + 3;
1004 int row_height = GetColLabelSize();
1005 int initial_row_height = row_height;
1010 for(
int col = 0; col < GetNumberCols(); col++ )
1012 int nl_count = GetColLabelValue( col ).Freq(
'\n' );
1017 if( row_height < line_height * ( nl_count+1 ) )
1018 row_height += line_height * nl_count;
1024 if( initial_row_height != row_height )
1041 const int colCount = GetNumberCols();
1043 for(
int ii = 0; ii < GetNumberCols(); ++ii )
1048 wxASSERT_MSG(
m_flexibleCol < colCount,
"Flexible column index does not exist in grid" );
1050 Bind( wxEVT_UPDATE_UI,
1051 [
this]( wxUpdateUIEvent& aEvent )
1058 [
this]( wxSizeEvent& aEvent )
1065 Bind( wxEVT_GRID_CELL_CHANGED,
1066 [
this]( wxGridEvent& aEvent )
1078 const int width = GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
1080 std::optional<int> flexibleMinWidth;
1084 if( GetColSize( colIndex ) != 0 )
1086 AutoSizeColumn( colIndex );
1087 const int colSize = GetColSize( colIndex );
1089 int minWidthScaled = FromDIP( minWidth );
1090 SetColSize( colIndex, std::max( minWidthScaled, colSize ) );
1093 flexibleMinWidth = minWidthScaled;
1098 int nonFlexibleWidth = 0;
1100 for(
int i = 0; i < GetNumberCols(); ++i )
1103 nonFlexibleWidth += GetColSize( i );
1107 SetColSize(
m_flexibleCol, std::max( flexibleMinWidth.value_or( 0 ), width - nonFlexibleWidth ) );
1118 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.
Functions to provide common constants and other functions to assist in making a consistent UI.
wxColour getBorderColour()
#define MIN_GRIDCELL_MARGIN