25#include <wx/tokenzr.h>
27#include <wx/settings.h>
29#include <wx/textentry.h>
47 wxGridCellAttr::wxAttrKind aKind )
49 wxGridCellAttr* attr = aInputAttr;
51 if( wxGridCellAttrProvider* provider = GetAttrProvider() )
53 wxGridCellAttr* providerAttr = provider->GetAttr( aRow, aCol, aKind );
57 attr =
new wxGridCellAttr;
58 attr->SetKind( wxGridCellAttr::Merged );
62 attr->MergeWith( aInputAttr );
66 attr->MergeWith( providerAttr );
67 providerAttr->DecRef();
75#define MIN_GRIDCELL_MARGIN FromDIP( 2 )
81 aEntry->SetMargins( 0, 0 );
87#if defined( __WXMSW__ ) || defined( __WXGTK__ )
95 KIGFX::COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK );
96 KIGFX::COLOR4D fg = wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER );
107 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
110 rect.SetTop( rect.GetTop() + 1 );
111 rect.SetLeft( rect.GetLeft() + 1 );
112 rect.SetBottom( rect.GetBottom() - 1 );
113 rect.SetRight( rect.GetRight() - 1 );
114 dc.DrawRectangle( rect );
124 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
127 rect.SetTop( rect.GetTop() + 1 );
128 rect.SetLeft( rect.GetLeft() );
129 rect.SetBottom( rect.GetBottom() - 1 );
130 rect.SetRight( rect.GetRight() - 1 );
131 dc.DrawRectangle( rect );
141 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
144 rect.SetTop( rect.GetTop() + 1 );
145 rect.SetLeft( rect.GetLeft() + 1 );
146 rect.SetBottom( rect.GetBottom() - 1 );
147 rect.SetRight( rect.GetRight() );
148 dc.DrawRectangle( rect );
161 wxGridCellAttrProvider(),
175 wxGridCellAttr*
GetAttr(
int row,
int col, wxGridCellAttr::wxAttrKind kind )
const override
177 wxGridCellAttrPtr cellAttr( wxGridCellAttrProvider::GetAttr( row, col, kind ) );
182 return cellAttr.release();
190 if( !cellAttr->HasBackgroundColour() )
192 cellAttr = cellAttr->Clone();
193 cellAttr->SetBackgroundColour(
m_attrEven->GetBackgroundColour() );
197 return cellAttr.release();
205WX_GRID::WX_GRID( wxWindow *parent, wxWindowID
id,
const wxPoint& pos,
const wxSize& size,
long style,
206 const wxString&
name ) :
207 wxGrid( parent, id, pos, size, style,
name ),
211 SetDefaultRowSize( GetDefaultRowSize() + FromDIP( 4 ) );
213 SetDefaultCellOverflow(
false );
244 wxGrid::SetColLabelSize( wxGRID_AUTOSIZE );
253 if( aHeight == 0 || aHeight == wxGRID_AUTOSIZE )
255 wxGrid::SetColLabelSize( aHeight );
262 wxGrid::SetColLabelSize( std::max( aHeight, minHeight ) );
276 int numberCols = GetNumberCols();
277 int* formBuilderColWidths =
new int[numberCols];
279 for(
int i = 0; i < numberCols; ++i )
280 formBuilderColWidths[ i ] = GetColSize( i );
282 wxGrid::SetTable( aTable );
286 numberCols = std::min( numberCols, GetNumberCols() );
288 for(
int i = 0; i < numberCols; ++i )
293 SetColSize( i, std::max( formBuilderColWidths[ i ], headingWidth ) );
296 delete[] formBuilderColWidths;
309 wxGridTableBase*
table = wxGrid::GetTable();
311 wxCHECK_MSG(
table, ,
"Tried to enable alternate row colors without a table assigned to the grid" );
315 wxColor
color = wxGrid::GetDefaultCellBackgroundColour();
320 table->SetAttrProvider(
nullptr );
330 int row = aEvent.GetRow();
331 int col = aEvent.GetCol();
333 if( row >= 0 && row < GetNumberRows() && col >= 0 && col < GetNumberCols() )
335 if( GetSelectionMode() == wxGrid::wxGridSelectCells )
337 SelectBlock( row, col, row, col,
false );
339 else if( GetSelectionMode() == wxGrid::wxGridSelectRows
340 || GetSelectionMode() == wxGrid::wxGridSelectRowsOrColumns )
342 SelectBlock( row, 0, row, GetNumberCols() - 1,
false );
344 else if( GetSelectionMode() == wxGrid::wxGridSelectColumns )
346 SelectBlock( 0, col, GetNumberRows() - 1, col,
false );
356 int row = aEvent.GetRow();
357 int col = aEvent.GetCol();
359 const std::pair<wxString, wxString>& beforeAfter =
m_evalBeforeAfter[ { row, col } ];
361 if( GetCellValue( row, col ) == beforeAfter.second )
362 SetCellValue( row, col, beforeAfter.first );
369 const int col = aEvent.GetCol();
376 EDA_UNITS cellUnits = cellUnitsData.first;
379 m_eval->SetDefaultUnits( cellUnits );
381 const int row = aEvent.GetRow();
384 bool isNullable =
false;
385 wxGridCellEditor* cellEditor = GetCellEditor( row, col );
391 isNullable = nullable->IsNullable();
393 cellEditor->DecRef();
397 [
this, row, col, isNullable, unitsProvider, cellDataType]()
401 if( row >= GetNumberRows() || col >= GetNumberCols() )
404 wxString stringValue = GetCellValue( row, col );
405 bool processedOk =
true;
408 processedOk =
m_eval->Process( stringValue );
416 std::optional<int> val;
436 if( stringValue != evalValue )
438 SetCellValue( row, col, evalValue );
458 wxGrid::SetTable(
nullptr );
465 wxString shownColumns;
467 for(
int i = 0; i < GetNumberCols(); ++i )
469 if( IsColShown( i ) )
471 if( shownColumns.Length() )
472 shownColumns << wxT(
" " );
484 std::bitset<64> shownColumns;
486 for(
int ii = 0; ii < GetNumberCols(); ++ii )
487 shownColumns[ii] = IsColShown( ii );
495 for(
int i = 0; i < GetNumberCols(); ++i )
498 wxStringTokenizer shownTokens( shownColumns,
" \t\r\n", wxTOKEN_STRTOK );
500 while( shownTokens.HasMoreTokens() )
503 shownTokens.GetNextToken().ToLong( &colNumber );
505 if( colNumber >= 0 && colNumber < GetNumberCols() )
506 ShowCol( (
int) colNumber );
513 if( m_nativeColumnLabels )
514 wxGrid::DrawCornerLabel( dc );
516 wxRect rect( wxSize( m_rowLabelWidth, m_colLabelHeight ) );
522 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
523 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
524 dc.DrawRectangle( rect.Inflate( 1 ) );
533 if( m_nativeColumnLabels )
534 wxGrid::DrawColLabel( dc, col );
536 if( GetColWidth( col ) <= 0 || m_colLabelHeight <= 0 )
539 wxRect rect( GetColLeft( col ), 0, GetColWidth( col ), m_colLabelHeight );
545 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
546 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
547 dc.DrawRectangle( rect.Inflate( 1 ) );
553 dc.SetFont( GetLabelFont() );
556 GetColLabelAlignment( &hAlign, &vAlign );
557 const int orient = GetColLabelTextOrientation();
560 hAlign = wxALIGN_LEFT;
562 if( hAlign == wxALIGN_LEFT )
565 rend.DrawLabel( *
this, dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
571 if( GetRowHeight( row ) <= 0 || m_rowLabelWidth <= 0 )
574 wxRect rect( 0, GetRowTop( row ), m_rowLabelWidth, GetRowHeight( row ) );
580 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
581 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
582 dc.DrawRectangle( rect.Inflate( 1 ) );
588 dc.SetFont( GetLabelFont() );
591 GetRowLabelAlignment(&hAlign, &vAlign);
593 if( hAlign == wxALIGN_LEFT )
596 rend.DrawLabel( *
this, dc, GetRowLabelValue( row ), rect, hAlign, vAlign, wxHORIZONTAL );
602 if( !IsCellEditControlEnabled() )
605 HideCellEditControl();
608 m_cellEditCtrlEnabled =
false;
610 int row = m_currentCellCoords.GetRow();
611 int col = m_currentCellCoords.GetCol();
613 wxString oldval = GetCellValue( row, col );
616 wxGridCellAttr* attr = GetCellAttr( row, col );
617 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
619 editor->EndEdit( row, col,
this, oldval, &newval );
630 if( !IsCellEditControlEnabled() )
633 if( !aQuietMode && SendEvent( wxEVT_GRID_EDITOR_HIDDEN ) == -1 )
636 HideCellEditControl();
639 m_cellEditCtrlEnabled =
false;
641 int row = m_currentCellCoords.GetRow();
642 int col = m_currentCellCoords.GetCol();
644 wxString oldval = GetCellValue( row, col );
647 wxGridCellAttr* attr = GetCellAttr( row, col );
648 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
650 bool changed =
editor->EndEdit( row, col,
this, oldval, &newval );
657 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGING, newval ) == -1 )
660 editor->ApplyEdit( row, col,
this );
665 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGED, oldval ) == -1 )
668 SetCellValue( row, col, oldval );
685 auto [row, editCol] = aAdder();
689 MakeCellVisible( row, std::max( editCol, 0 ) );
690 SetGridCursor( row, std::max( editCol, 0 ) );
694 EnableCellEditControl(
true );
695 ShowCellEditControl();
712 const std::function<
void(
int row )>& aDeleter )
714 wxArrayInt selectedRows = GetSelectedRows();
716 if( selectedRows.empty() && GetGridCursorRow() >= 0 )
717 selectedRows.push_back( GetGridCursorRow() );
719 if( selectedRows.empty() )
722 for(
int row : selectedRows )
724 if( !aFilter( row ) )
733 [](
int* first,
int* second )
735 return *second - *first;
738 int nextSelRow = selectedRows.back() - 1;
740 if( nextSelRow >= 0 )
742 GoToCell( nextSelRow, GetGridCursorCol() );
743 SetGridCursor( nextSelRow, GetGridCursorCol() );
746 for(
int row : selectedRows )
753 for(
int col = 0; col < GetNumberCols(); ++col )
755 wxString temp = GetCellValue( aRowA, col );
756 SetCellValue( aRowA, col, GetCellValue( aRowB, col ) );
757 SetCellValue( aRowB, col, temp );
774 const std::function<
void(
int row )>& aMover )
779 int i = GetGridCursorRow();
781 if( i > 0 && aFilter( i ) )
785 SetGridCursor( i - 1, GetGridCursorCol() );
786 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
807 const std::function<
void(
int row )>& aMover )
812 int i = GetGridCursorRow();
814 if( i + 1 < GetNumberRows() && aFilter( i ) )
818 SetGridCursor( i + 1, GetGridCursorCol() );
819 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
852 wxString stringValue = GetCellValue( aRow, aCol );
858 m_eval->SetDefaultUnits( cellUnits );
860 if(
m_eval->Process( stringValue ) )
861 stringValue =
m_eval->Result();
870 wxString stringValue = GetCellValue( aRow, aCol );
876 m_eval->SetDefaultUnits( cellUnits );
879 stringValue =
m_eval->Result();
895 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromValue( aValue,
true, cellDataType ) );
908 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromOptionalValue( aValue,
true, cellDataType ) );
926 size = GetRowLabelSize();
928 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
929 size = std::max( size,
int( GetTextExtent( GetRowLabelValue( row ) + wxS(
"M" ) ).x ) );
934 size = GetColSize( aCol );
942 size = std::max( size,
int( GetTextExtent( GetColLabelValue( aCol ) + wxS(
"M" ) ).x ) );
945 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
948 if( GetTable()->CanGetValueAs( row, aCol, wxGRID_VALUE_STRING ) )
949 size = std::max( size, GetTextExtent( GetCellValue( row, aCol ) + wxS(
"M" ) ).x );
951 size = std::max( size, GetTextExtent(
"MM" ).x );
961 int line_height = int( GetTextExtent(
"Mj" ).y ) + 3;
962 int row_height = GetColLabelSize();
963 int initial_row_height = row_height;
968 for(
int col = 0; col < GetNumberCols(); col++ )
970 int nl_count = GetColLabelValue( col ).Freq(
'\n' );
975 if( row_height < line_height * ( nl_count+1 ) )
976 row_height += line_height * nl_count;
982 if( initial_row_height != row_height )
999 const int colCount = GetNumberCols();
1001 for(
int ii = 0; ii < GetNumberCols(); ++ii )
1006 wxASSERT_MSG(
m_flexibleCol < colCount,
"Flexible column index does not exist in grid" );
1008 Bind( wxEVT_UPDATE_UI,
1009 [
this]( wxUpdateUIEvent& aEvent )
1016 [
this]( wxSizeEvent& aEvent )
1023 Bind( wxEVT_GRID_CELL_CHANGED,
1024 [
this]( wxGridEvent& aEvent )
1036 const int width = GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
1038 std::optional<int> flexibleMinWidth;
1042 if( GetColSize( colIndex ) != 0 )
1044 AutoSizeColumn( colIndex );
1045 const int colSize = GetColSize( colIndex );
1047 int minWidthScaled = FromDIP( minWidth );
1048 SetColSize( colIndex, std::max( minWidthScaled, colSize ) );
1051 flexibleMinWidth = minWidthScaled;
1056 int nonFlexibleWidth = 0;
1058 for(
int i = 0; i < GetNumberCols(); ++i )
1061 nonFlexibleWidth += GetColSize( i );
1065 SetColSize(
m_flexibleCol, std::max( flexibleMinWidth.value_or( 0 ), width - nonFlexibleWidth ) );
1076 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 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 recomputeGridWidths()
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