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 );
390 isNullable = nullable->IsNullable();
392 cellEditor->DecRef();
396 [
this, row, col, isNullable, unitsProvider, cellDataType]()
400 if( row >= GetNumberRows() || col >= GetNumberCols() )
403 wxString stringValue = GetCellValue( row, col );
404 bool processedOk =
true;
407 processedOk =
m_eval->Process( stringValue );
415 std::optional<int> val;
435 if( stringValue != evalValue )
437 SetCellValue( row, col, evalValue );
457 wxGrid::SetTable(
nullptr );
464 wxString shownColumns;
466 for(
int i = 0; i < GetNumberCols(); ++i )
468 if( IsColShown( i ) )
470 if( shownColumns.Length() )
471 shownColumns << wxT(
" " );
483 std::bitset<64> shownColumns;
485 for(
int ii = 0; ii < GetNumberCols(); ++ii )
486 shownColumns[ii] = IsColShown( ii );
494 for(
int i = 0; i < GetNumberCols(); ++i )
497 wxStringTokenizer shownTokens( shownColumns,
" \t\r\n", wxTOKEN_STRTOK );
499 while( shownTokens.HasMoreTokens() )
502 shownTokens.GetNextToken().ToLong( &colNumber );
504 if( colNumber >= 0 && colNumber < GetNumberCols() )
505 ShowCol( (
int) colNumber );
512 if( m_nativeColumnLabels )
513 wxGrid::DrawCornerLabel( dc );
515 wxRect rect( wxSize( m_rowLabelWidth, m_colLabelHeight ) );
521 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
522 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
523 dc.DrawRectangle( rect.Inflate( 1 ) );
532 if( m_nativeColumnLabels )
533 wxGrid::DrawColLabel( dc, col );
535 if( GetColWidth( col ) <= 0 || m_colLabelHeight <= 0 )
538 wxRect rect( GetColLeft( col ), 0, GetColWidth( col ), m_colLabelHeight );
544 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
545 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
546 dc.DrawRectangle( rect.Inflate( 1 ) );
552 dc.SetFont( GetLabelFont() );
555 GetColLabelAlignment( &hAlign, &vAlign );
556 const int orient = GetColLabelTextOrientation();
559 hAlign = wxALIGN_LEFT;
561 if( hAlign == wxALIGN_LEFT )
564 rend.DrawLabel( *
this, dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
570 if( GetRowHeight( row ) <= 0 || m_rowLabelWidth <= 0 )
573 wxRect rect( 0, GetRowTop( row ), m_rowLabelWidth, GetRowHeight( row ) );
579 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
580 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
581 dc.DrawRectangle( rect.Inflate( 1 ) );
587 dc.SetFont( GetLabelFont() );
590 GetRowLabelAlignment(&hAlign, &vAlign);
592 if( hAlign == wxALIGN_LEFT )
595 rend.DrawLabel( *
this, dc, GetRowLabelValue( row ), rect, hAlign, vAlign, wxHORIZONTAL );
601 if( !IsCellEditControlEnabled() )
604 HideCellEditControl();
607 m_cellEditCtrlEnabled =
false;
609 int row = m_currentCellCoords.GetRow();
610 int col = m_currentCellCoords.GetCol();
612 wxString oldval = GetCellValue( row, col );
615 wxGridCellAttr* attr = GetCellAttr( row, col );
616 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
618 editor->EndEdit( row, col,
this, oldval, &newval );
629 if( !IsCellEditControlEnabled() )
632 if( !aQuietMode && SendEvent( wxEVT_GRID_EDITOR_HIDDEN ) == -1 )
635 HideCellEditControl();
638 m_cellEditCtrlEnabled =
false;
640 int row = m_currentCellCoords.GetRow();
641 int col = m_currentCellCoords.GetCol();
643 wxString oldval = GetCellValue( row, col );
646 wxGridCellAttr* attr = GetCellAttr( row, col );
647 wxGridCellEditor*
editor = attr->GetEditor(
this, row, col );
649 bool changed =
editor->EndEdit( row, col,
this, oldval, &newval );
656 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGING, newval ) == -1 )
659 editor->ApplyEdit( row, col,
this );
664 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGED, oldval ) == -1 )
667 SetCellValue( row, col, oldval );
684 auto [row, editCol] = aAdder();
688 MakeCellVisible( row, std::max( editCol, 0 ) );
689 SetGridCursor( row, std::max( editCol, 0 ) );
693 EnableCellEditControl(
true );
694 ShowCellEditControl();
711 const std::function<
void(
int row )>& aDeleter )
713 wxArrayInt selectedRows = GetSelectedRows();
715 if( selectedRows.empty() && GetGridCursorRow() >= 0 )
716 selectedRows.push_back( GetGridCursorRow() );
718 if( selectedRows.empty() )
721 for(
int row : selectedRows )
723 if( !aFilter( row ) )
732 [](
int* first,
int* second )
734 return *second - *first;
737 int nextSelRow = selectedRows.back() - 1;
739 if( nextSelRow >= 0 )
741 GoToCell( nextSelRow, GetGridCursorCol() );
742 SetGridCursor( nextSelRow, GetGridCursorCol() );
745 for(
int row : selectedRows )
752 for(
int col = 0; col < GetNumberCols(); ++col )
754 wxString temp = GetCellValue( aRowA, col );
755 SetCellValue( aRowA, col, GetCellValue( aRowB, col ) );
756 SetCellValue( aRowB, col, temp );
773 const std::function<
void(
int row )>& aMover )
778 int i = GetGridCursorRow();
780 if( i > 0 && aFilter( i ) )
784 SetGridCursor( i - 1, GetGridCursorCol() );
785 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
806 const std::function<
void(
int row )>& aMover )
811 int i = GetGridCursorRow();
813 if( i + 1 < GetNumberRows() && aFilter( i ) )
817 SetGridCursor( i + 1, GetGridCursorCol() );
818 MakeCellVisible( GetGridCursorRow(), GetGridCursorCol() );
851 wxString stringValue = GetCellValue( aRow, aCol );
857 m_eval->SetDefaultUnits( cellUnits );
859 if(
m_eval->Process( stringValue ) )
860 stringValue =
m_eval->Result();
869 wxString stringValue = GetCellValue( aRow, aCol );
875 m_eval->SetDefaultUnits( cellUnits );
878 stringValue =
m_eval->Result();
894 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromValue( aValue,
true, cellDataType ) );
900 SetCellValue( aRow, aCol,
getUnitsProvider( aCol )->StringFromOptionalValue( aValue,
true ) );
918 size = GetRowLabelSize();
920 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
921 size = std::max( size,
int( GetTextExtent( GetRowLabelValue( row ) + wxS(
"M" ) ).x ) );
926 size = GetColSize( aCol );
934 size = std::max( size,
int( GetTextExtent( GetColLabelValue( aCol ) + wxS(
"M" ) ).x ) );
937 for(
int row = 0; aContents && row < GetNumberRows(); row++ )
940 if( GetTable()->CanGetValueAs( row, aCol, wxGRID_VALUE_STRING ) )
941 size = std::max( size, GetTextExtent( GetCellValue( row, aCol ) + wxS(
"M" ) ).x );
943 size = std::max( size, GetTextExtent(
"MM" ).x );
953 int line_height = int( GetTextExtent(
"Mj" ).y ) + 3;
954 int row_height = GetColLabelSize();
955 int initial_row_height = row_height;
960 for(
int col = 0; col < GetNumberCols(); col++ )
962 int nl_count = GetColLabelValue( col ).Freq(
'\n' );
967 if( row_height < line_height * ( nl_count+1 ) )
968 row_height += line_height * nl_count;
974 if( initial_row_height != row_height )
991 const int colCount = GetNumberCols();
993 for(
int ii = 0; ii < GetNumberCols(); ++ii )
998 wxASSERT_MSG(
m_flexibleCol < colCount,
"Flexible column index does not exist in grid" );
1000 Bind( wxEVT_UPDATE_UI,
1001 [
this]( wxUpdateUIEvent& aEvent )
1008 [
this]( wxSizeEvent& aEvent )
1015 Bind( wxEVT_GRID_CELL_CHANGED,
1016 [
this]( wxGridEvent& aEvent )
1028 const int width = GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
1030 std::optional<int> flexibleMinWidth;
1034 if( GetColSize( colIndex ) != 0 )
1036 AutoSizeColumn( colIndex );
1037 const int colSize = GetColSize( colIndex );
1039 int minWidthScaled = FromDIP( minWidth );
1040 SetColSize( colIndex, std::max( minWidthScaled, colSize ) );
1043 flexibleMinWidth = minWidthScaled;
1048 int nonFlexibleWidth = 0;
1050 for(
int i = 0; i < GetNumberCols(); ++i )
1053 nonFlexibleWidth += GetColSize( i );
1057 SetColSize(
m_flexibleCol, std::max( flexibleMinWidth.value_or( 0 ), width - nonFlexibleWidth ) );
1068 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