KiCad PCB EDA Suite
Loading...
Searching...
No Matches
wx_grid.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <wx/colour.h>
25#include <wx/tokenzr.h>
26#include <wx/dc.h>
27#include <wx/settings.h>
28#include <wx/event.h> // Needed for textentry.h on MSW
29#include <wx/textentry.h>
30
32#include <widgets/wx_grid.h>
33#include <widgets/ui_common.h>
34#include <algorithm>
35#include <core/kicad_algo.h>
36#include <gal/color4d.h>
37#include <kiplatform/ui.h>
38#include <utility>
39
40#include <pgm_base.h>
42#include <dialog_shim.h>
43
44
45wxGridCellAttr* WX_GRID_TABLE_BASE::enhanceAttr( wxGridCellAttr* aInputAttr, int aRow, int aCol,
46 wxGridCellAttr::wxAttrKind aKind )
47{
48 wxGridCellAttr* attr = aInputAttr;
49
50 if( wxGridCellAttrProvider* provider = GetAttrProvider() )
51 {
52 wxGridCellAttr* providerAttr = provider->GetAttr( aRow, aCol, aKind );
53
54 if( providerAttr )
55 {
56 attr = new wxGridCellAttr;
57 attr->SetKind( wxGridCellAttr::Merged );
58
59 if( aInputAttr )
60 {
61 attr->MergeWith( aInputAttr );
62 aInputAttr->DecRef();
63 }
64
65 attr->MergeWith( providerAttr );
66 providerAttr->DecRef();
67 }
68 }
69
70 return attr;
71}
72
73
74#define MIN_GRIDCELL_MARGIN FromDIP( 2 )
75
76
77void WX_GRID::CellEditorSetMargins( wxTextEntryBase* aEntry )
78{
79 // This is consistent with wxGridCellTextEditor. But works differently across platforms or course.
80 aEntry->SetMargins( 0, 0 );
81}
82
83
85{
86#if defined( __WXMSW__ ) || defined( __WXGTK__ )
87 aRect.Deflate( 2 );
88#endif
89}
90
91
93{
94 KIGFX::COLOR4D bg = wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK );
95 KIGFX::COLOR4D fg = wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER );
96 KIGFX::COLOR4D border = fg.Mix( bg, 0.50 );
97 return border.ToColour();
98}
99
100
101class WX_GRID_CORNER_HEADER_RENDERER : public wxGridCornerHeaderRendererDefault
102{
103public:
104 void DrawBorder( const wxGrid& grid, wxDC& dc, wxRect& rect ) const override
105 {
106 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
107 wxDCPenChanger SetPen( dc, wxPen( getBorderColour(), 1 ) );
108
109 rect.SetTop( rect.GetTop() + 1 );
110 rect.SetLeft( rect.GetLeft() + 1 );
111 rect.SetBottom( rect.GetBottom() - 1 );
112 rect.SetRight( rect.GetRight() - 1 );
113 dc.DrawRectangle( rect );
114 }
115};
116
117
118class WX_GRID_COLUMN_HEADER_RENDERER : public wxGridColumnHeaderRendererDefault
119{
120public:
121 void DrawBorder( const wxGrid& grid, wxDC& dc, wxRect& rect ) const override
122 {
123 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
124 wxDCPenChanger SetPen( dc, wxPen( getBorderColour(), 1 ) );
125
126 rect.SetTop( rect.GetTop() + 1 );
127 rect.SetLeft( rect.GetLeft() );
128 rect.SetBottom( rect.GetBottom() - 1 );
129 rect.SetRight( rect.GetRight() - 1 );
130 dc.DrawRectangle( rect );
131 }
132};
133
134
135class WX_GRID_ROW_HEADER_RENDERER : public wxGridRowHeaderRendererDefault
136{
137public:
138 void DrawBorder( const wxGrid& grid, wxDC& dc, wxRect& rect ) const override
139 {
140 wxDCBrushChanger SetBrush( dc, *wxTRANSPARENT_BRUSH );
141 wxDCPenChanger SetPen( dc, wxPen( getBorderColour(), 1 ) );
142
143 rect.SetTop( rect.GetTop() + 1 );
144 rect.SetLeft( rect.GetLeft() + 1 );
145 rect.SetBottom( rect.GetBottom() - 1 );
146 rect.SetRight( rect.GetRight() );
147 dc.DrawRectangle( rect );
148 }
149};
150
151
156class WX_GRID_ALT_ROW_COLOR_PROVIDER : public wxGridCellAttrProvider
157{
158public:
159 WX_GRID_ALT_ROW_COLOR_PROVIDER( const wxColor& aBaseColor ) : wxGridCellAttrProvider(),
160 m_attrEven( new wxGridCellAttr() )
161 {
162 UpdateColors( aBaseColor );
163 }
164
165
166 void UpdateColors( const wxColor& aBaseColor )
167 {
168 // Choose the default color, taking into account if the dark mode theme is enabled
169 wxColor rowColor = aBaseColor.ChangeLightness( KIPLATFORM::UI::IsDarkTheme() ? 105 : 95 );
170
171 m_attrEven->SetBackgroundColour( rowColor );
172 }
173
174
175 wxGridCellAttr* GetAttr( int row, int col,
176 wxGridCellAttr::wxAttrKind kind ) const override
177 {
178 wxGridCellAttrPtr cellAttr( wxGridCellAttrProvider::GetAttr( row, col, kind ) );
179
180 // Just pass through the cell attribute on odd rows (start normal to allow for the header row)
181 if( !( row % 2 ) )
182 return cellAttr.release();
183
184 if( !cellAttr )
185 {
186 cellAttr = m_attrEven;
187 }
188 else
189 {
190 if( !cellAttr->HasBackgroundColour() )
191 {
192 cellAttr = cellAttr->Clone();
193 cellAttr->SetBackgroundColour( m_attrEven->GetBackgroundColour() );
194 }
195 }
196
197 return cellAttr.release();
198 }
199
200private:
201 wxGridCellAttrPtr m_attrEven;
202};
203
204
205WX_GRID::WX_GRID( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
206 long style, const wxString& name ) :
207 wxGrid( parent, id, pos, size, style, name ),
208 m_weOwnTable( false )
209{
210 SetDefaultCellOverflow( false );
211
212 // Make sure the GUI font scales properly
213 SetDefaultCellFont( KIUI::GetControlFont( this ) );
215
216 Connect( wxEVT_DPI_CHANGED, wxDPIChangedEventHandler( WX_GRID::onDPIChanged ), nullptr, this );
217 Connect( wxEVT_GRID_EDITOR_SHOWN, wxGridEventHandler( WX_GRID::onCellEditorShown ), nullptr, this );
218 Connect( wxEVT_GRID_EDITOR_HIDDEN, wxGridEventHandler( WX_GRID::onCellEditorHidden ), nullptr, this );
219}
220
221
223{
224 if( m_weOwnTable )
225 DestroyTable( GetTable() );
226
227 Disconnect( wxEVT_GRID_EDITOR_SHOWN, wxGridEventHandler( WX_GRID::onCellEditorShown ), nullptr, this );
228 Disconnect( wxEVT_GRID_EDITOR_HIDDEN, wxGridEventHandler( WX_GRID::onCellEditorHidden ), nullptr, this );
229 Disconnect( wxEVT_DPI_CHANGED, wxDPIChangedEventHandler( WX_GRID::onDPIChanged ), nullptr, this );
230}
231
232
233void WX_GRID::onDPIChanged(wxDPIChangedEvent& aEvt)
234{
235 CallAfter(
236 [&]()
237 {
238 wxGrid::SetColLabelSize( wxGRID_AUTOSIZE );
239 } );
240
243#ifndef __WXMAC__
244 aEvt.Skip();
245#endif
246}
247
248
249void WX_GRID::SetColLabelSize( int aHeight )
250{
251 if( aHeight == 0 || aHeight == wxGRID_AUTOSIZE )
252 {
253 wxGrid::SetColLabelSize( aHeight );
254 return;
255 }
256
257 // Correct wxFormBuilder height for large fonts
258 int minHeight = GetCharHeight() + 2 * MIN_GRIDCELL_MARGIN;
259
260 wxGrid::SetColLabelSize( std::max( aHeight, minHeight ) );
261}
262
263
264void WX_GRID::SetLabelFont( const wxFont& aFont )
265{
266 wxGrid::SetLabelFont( KIUI::GetControlFont( this ) );
267}
268
269
270void WX_GRID::SetTable( wxGridTableBase* aTable, bool aTakeOwnership )
271{
272 // wxGrid::SetTable() messes up the column widths from wxFormBuilder so we have to save
273 // and restore them.
274 int numberCols = GetNumberCols();
275 int* formBuilderColWidths = new int[numberCols];
276
277 for( int i = 0; i < numberCols; ++i )
278 formBuilderColWidths[ i ] = GetColSize( i );
279
280 wxGrid::SetTable( aTable );
281
282 // wxGrid::SetTable() may change the number of columns, so prevent out-of-bounds access
283 // to formBuilderColWidths
284 numberCols = std::min( numberCols, GetNumberCols() );
285
286 for( int i = 0; i < numberCols; ++i )
287 {
288 // correct wxFormBuilder width for large fonts and/or long translations
289 int headingWidth = GetTextExtent( GetColLabelValue( i ) ).x + 2 * MIN_GRIDCELL_MARGIN;
290
291 SetColSize( i, std::max( formBuilderColWidths[ i ], headingWidth ) );
292 }
293
294 delete[] formBuilderColWidths;
295
296 EnableAlternateRowColors( Pgm().GetCommonSettings()->m_Appearance.grid_striping );
297
298 Connect( wxEVT_GRID_COL_MOVE, wxGridEventHandler( WX_GRID::onGridColMove ), nullptr, this );
299 Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( WX_GRID::onGridCellSelect ), nullptr, this );
300
301 m_weOwnTable = aTakeOwnership;
302}
303
304
306{
307 wxGridTableBase* table = wxGrid::GetTable();
308
309 wxCHECK_MSG( table, /* void */,
310 "Tried to enable alternate row colors without a table assigned to the grid" );
311
312 if( aEnable )
313 {
314 wxColor color = wxGrid::GetDefaultCellBackgroundColour();
315 table->SetAttrProvider( new WX_GRID_ALT_ROW_COLOR_PROVIDER( color ) );
316 }
317 else
318 {
319 table->SetAttrProvider( nullptr );
320 }
321}
322
323
324void WX_GRID::onGridCellSelect( wxGridEvent& aEvent )
325{
326 // Highlight the selected cell.
327 // Calling SelectBlock() allows a visual effect when cells are selected by tab or arrow keys.
328 // Otherwise, one cannot really know what actual cell is selected.
329 int row = aEvent.GetRow();
330 int col = aEvent.GetCol();
331
332 if( row >= 0 && row < GetNumberRows() && col >= 0 && col < GetNumberCols() )
333 {
334 if( GetSelectionMode() == wxGrid::wxGridSelectCells )
335 {
336 SelectBlock( row, col, row, col, false );
337 }
338 else if( GetSelectionMode() == wxGrid::wxGridSelectRows
339 || GetSelectionMode() == wxGrid::wxGridSelectRowsOrColumns )
340 {
341 SelectBlock( row, 0, row, GetNumberCols() - 1, false );
342 }
343 else if( GetSelectionMode() == wxGrid::wxGridSelectColumns )
344 {
345 SelectBlock( 0, col, GetNumberRows() - 1, col, false );
346 }
347 }
348}
349
350
351void WX_GRID::onCellEditorShown( wxGridEvent& aEvent )
352{
353 if( alg::contains( m_autoEvalCols, aEvent.GetCol() ) )
354 {
355 int row = aEvent.GetRow();
356 int col = aEvent.GetCol();
357
358 const std::pair<wxString, wxString>& beforeAfter = m_evalBeforeAfter[ { row, col } ];
359
360 if( GetCellValue( row, col ) == beforeAfter.second )
361 SetCellValue( row, col, beforeAfter.first );
362 }
363}
364
365
366void WX_GRID::onCellEditorHidden( wxGridEvent& aEvent )
367{
368 if( alg::contains( m_autoEvalCols, aEvent.GetCol() ) )
369 {
370 UNITS_PROVIDER* unitsProvider = m_unitsProviders[ aEvent.GetCol() ];
371
372 if( !unitsProvider )
373 unitsProvider = m_unitsProviders.begin()->second;
374
375 m_eval->SetDefaultUnits( unitsProvider->GetUserUnits() );
376
377 int row = aEvent.GetRow();
378 int col = aEvent.GetCol();
379
380 // Determine if this cell is marked as holding nullable values
381 bool isNullable = false;
382 wxGridCellEditor* cellEditor = GetCellEditor( row, col );
383
384 if( cellEditor )
385 {
386 GRID_CELL_MARK_AS_NULLABLE* nullableCell =
387 dynamic_cast<GRID_CELL_MARK_AS_NULLABLE*>( cellEditor );
388
389 if( nullableCell )
390 isNullable = nullableCell->IsNullable();
391
392 cellEditor->DecRef();
393 }
394
395 CallAfter(
396 [this, row, col, isNullable, unitsProvider]()
397 {
398 wxString stringValue = GetCellValue( row, col );
399 bool processedOk = true;
400
401 if( stringValue != UNITS_PROVIDER::NullUiString )
402 processedOk = m_eval->Process( stringValue );
403
404 if( processedOk )
405 {
406 wxString evalValue;
407
408 if( isNullable )
409 {
410 std::optional<int> val;
411
412 if( stringValue == UNITS_PROVIDER::NullUiString )
413 {
414 val = unitsProvider->OptionalValueFromString(
416 }
417 else
418 {
419 val = unitsProvider->OptionalValueFromString( m_eval->Result() );
420 }
421
422 evalValue = unitsProvider->StringFromOptionalValue( val, true );
423 }
424 else
425 {
426 int val = unitsProvider->ValueFromString( m_eval->Result() );
427 evalValue = unitsProvider->StringFromValue( val, true );
428 }
429
430 if( stringValue != evalValue )
431 {
432 SetCellValue( row, col, evalValue );
433 m_evalBeforeAfter[{ row, col }] = { stringValue, evalValue };
434 }
435 }
436 } );
437 }
438
439 aEvent.Skip();
440}
441
442
443void WX_GRID::DestroyTable( wxGridTableBase* aTable )
444{
445 // wxGrid's destructor will crash trying to look up the cell attr if the edit control
446 // is left open. Normally it's closed in Validate(), but not if the user hit Cancel.
447 CommitPendingChanges( true /* quiet mode */ );
448
449 Disconnect( wxEVT_GRID_COL_MOVE, wxGridEventHandler( WX_GRID::onGridColMove ), nullptr, this );
450 Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( WX_GRID::onGridCellSelect ), nullptr, this );
451
452 wxGrid::SetTable( nullptr );
453 delete aTable;
454}
455
456
458{
459 wxString shownColumns;
460
461 for( int i = 0; i < GetNumberCols(); ++i )
462 {
463 if( IsColShown( i ) )
464 {
465 if( shownColumns.Length() )
466 shownColumns << wxT( " " );
467
468 shownColumns << i;
469 }
470 }
471
472 return shownColumns;
473}
474
475
477{
478 std::bitset<64> shownColumns;
479
480 for( int ii = 0; ii < GetNumberCols(); ++ii )
481 shownColumns[ii] = IsColShown( ii );
482
483 return shownColumns;
484}
485
486
487void WX_GRID::ShowHideColumns( const wxString& shownColumns )
488{
489 for( int i = 0; i < GetNumberCols(); ++i )
490 HideCol( i );
491
492 wxStringTokenizer shownTokens( shownColumns );
493
494 while( shownTokens.HasMoreTokens() )
495 {
496 long colNumber;
497 shownTokens.GetNextToken().ToLong( &colNumber );
498
499 if( colNumber >= 0 && colNumber < GetNumberCols() )
500 ShowCol( (int) colNumber );
501 }
502}
503
504
505void WX_GRID::ShowHideColumns( const std::bitset<64>& aShownColumns )
506{
507 for( int ii = 0; ii < GetNumberCols(); ++ ii )
508 {
509 if( aShownColumns[ii] )
510 ShowCol( ii );
511 else
512 HideCol( ii );
513 }
514}
515
516
518{
519 if( m_nativeColumnLabels )
520 wxGrid::DrawCornerLabel( dc );
521
522 wxRect rect( wxSize( m_rowLabelWidth, m_colLabelHeight ) );
523
525
526 // It is reported that we need to erase the background to avoid display
527 // artifacts, see #12055.
528 {
529 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
530 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
531 dc.DrawRectangle( rect.Inflate( 1 ) );
532 }
533
534 rend.DrawBorder( *this, dc, rect );
535}
536
537
538void WX_GRID::DrawColLabel( wxDC& dc, int col )
539{
540 if( m_nativeColumnLabels )
541 wxGrid::DrawColLabel( dc, col );
542
543 if( GetColWidth( col ) <= 0 || m_colLabelHeight <= 0 )
544 return;
545
546 wxRect rect( GetColLeft( col ), 0, GetColWidth( col ), m_colLabelHeight );
547
549
550 // It is reported that we need to erase the background to avoid display
551 // artifacts, see #12055.
552 {
553 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
554 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
555 dc.DrawRectangle( rect.Inflate( 1 ) );
556 }
557
558 rend.DrawBorder( *this, dc, rect );
559
560 // Make sure fonts get scaled correctly on GTK HiDPI monitors
561 dc.SetFont( GetLabelFont() );
562
563 int hAlign, vAlign;
564 GetColLabelAlignment( &hAlign, &vAlign );
565 const int orient = GetColLabelTextOrientation();
566
567 if( col == 0 )
568 hAlign = wxALIGN_LEFT;
569
570 if( hAlign == wxALIGN_LEFT )
571 rect.SetLeft( rect.GetLeft() + MIN_GRIDCELL_MARGIN );
572
573 rend.DrawLabel( *this, dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
574}
575
576
577void WX_GRID::DrawRowLabel( wxDC& dc, int row )
578{
579 if ( GetRowHeight( row ) <= 0 || m_rowLabelWidth <= 0 )
580 return;
581
582 wxRect rect( 0, GetRowTop( row ), m_rowLabelWidth, GetRowHeight( row ) );
583
584 static WX_GRID_ROW_HEADER_RENDERER rend;
585
586 // It is reported that we need to erase the background to avoid display
587 // artifacts, see #12055.
588 {
589 wxDCBrushChanger setBrush( dc, m_colLabelWin->GetBackgroundColour() );
590 wxDCPenChanger setPen( dc, m_colLabelWin->GetBackgroundColour() );
591 dc.DrawRectangle( rect.Inflate( 1 ) );
592 }
593
594 rend.DrawBorder( *this, dc, rect );
595
596 // Make sure fonts get scaled correctly on GTK HiDPI monitors
597 dc.SetFont( GetLabelFont() );
598
599 int hAlign, vAlign;
600 GetRowLabelAlignment(&hAlign, &vAlign);
601
602 if( hAlign == wxALIGN_LEFT )
603 rect.SetLeft( rect.GetLeft() + MIN_GRIDCELL_MARGIN );
604
605 rend.DrawLabel( *this, dc, GetRowLabelValue( row ), rect, hAlign, vAlign, wxHORIZONTAL );
606}
607
608
610{
611 if( !IsCellEditControlEnabled() )
612 return true;
613
614 HideCellEditControl();
615
616 // do it after HideCellEditControl()
617 m_cellEditCtrlEnabled = false;
618
619 int row = m_currentCellCoords.GetRow();
620 int col = m_currentCellCoords.GetCol();
621
622 wxString oldval = GetCellValue( row, col );
623 wxString newval;
624
625 wxGridCellAttr* attr = GetCellAttr( row, col );
626 wxGridCellEditor* editor = attr->GetEditor( this, row, col );
627
628 editor->EndEdit( row, col, this, oldval, &newval );
629
630 editor->DecRef();
631 attr->DecRef();
632
633 return true;
634}
635
636
637bool WX_GRID::CommitPendingChanges( bool aQuietMode )
638{
639 if( !IsCellEditControlEnabled() )
640 return true;
641
642 if( !aQuietMode && SendEvent( wxEVT_GRID_EDITOR_HIDDEN ) == -1 )
643 return false;
644
645 HideCellEditControl();
646
647 // do it after HideCellEditControl()
648 m_cellEditCtrlEnabled = false;
649
650 int row = m_currentCellCoords.GetRow();
651 int col = m_currentCellCoords.GetCol();
652
653 wxString oldval = GetCellValue( row, col );
654 wxString newval;
655
656 wxGridCellAttr* attr = GetCellAttr( row, col );
657 wxGridCellEditor* editor = attr->GetEditor( this, row, col );
658
659 bool changed = editor->EndEdit( row, col, this, oldval, &newval );
660
661 editor->DecRef();
662 attr->DecRef();
663
664 if( changed )
665 {
666 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGING, newval ) == -1 )
667 return false;
668
669 editor->ApplyEdit( row, col, this );
670
671 // for compatibility reasons dating back to wx 2.8 when this event
672 // was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING
673 // didn't exist we allow vetoing this one too
674 if( !aQuietMode && SendEvent( wxEVT_GRID_CELL_CHANGED, oldval ) == -1 )
675 {
676 // Event has been vetoed, set the data back.
677 SetCellValue( row, col, oldval );
678 return false;
679 }
680
681 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( wxGetTopLevelParent( this ) ) )
682 dlg->OnModify();
683 }
684
685 return true;
686}
687
688
689void WX_GRID::SetUnitsProvider( UNITS_PROVIDER* aProvider, int aCol )
690{
691 m_unitsProviders[ aCol ] = aProvider;
692
693 if( !m_eval )
694 m_eval = std::make_unique<NUMERIC_EVALUATOR>( aProvider->GetUserUnits() );
695}
696
697
698int WX_GRID::GetUnitValue( int aRow, int aCol )
699{
700 UNITS_PROVIDER* unitsProvider = m_unitsProviders[ aCol ];
701
702 if( !unitsProvider )
703 unitsProvider = m_unitsProviders.begin()->second;
704
705 wxString stringValue = GetCellValue( aRow, aCol );
706
707 if( alg::contains( m_autoEvalCols, aCol ) )
708 {
709 m_eval->SetDefaultUnits( unitsProvider->GetUserUnits() );
710
711 if( m_eval->Process( stringValue ) )
712 stringValue = m_eval->Result();
713 }
714
715 return unitsProvider->ValueFromString( stringValue );
716}
717
718
719std::optional<int> WX_GRID::GetOptionalUnitValue( int aRow, int aCol )
720{
721 UNITS_PROVIDER* unitsProvider = m_unitsProviders[aCol];
722
723 if( !unitsProvider )
724 unitsProvider = m_unitsProviders.begin()->second;
725
726 wxString stringValue = GetCellValue( aRow, aCol );
727
728 if( alg::contains( m_autoEvalCols, aCol ) )
729 {
730 m_eval->SetDefaultUnits( unitsProvider->GetUserUnits() );
731
732 if( stringValue != UNITS_PROVIDER::NullUiString && m_eval->Process( stringValue ) )
733 stringValue = m_eval->Result();
734 }
735
736 return unitsProvider->OptionalValueFromString( stringValue );
737}
738
739
740void WX_GRID::SetUnitValue( int aRow, int aCol, int aValue )
741{
742 UNITS_PROVIDER* unitsProvider = m_unitsProviders[ aCol ];
743
744 if( !unitsProvider )
745 unitsProvider = m_unitsProviders.begin()->second;
746
747 SetCellValue( aRow, aCol, unitsProvider->StringFromValue( aValue, true ) );
748}
749
750
751void WX_GRID::SetOptionalUnitValue( int aRow, int aCol, std::optional<int> aValue )
752{
753 UNITS_PROVIDER* unitsProvider = m_unitsProviders[aCol];
754
755 if( !unitsProvider )
756 unitsProvider = m_unitsProviders.begin()->second;
757
758 SetCellValue( aRow, aCol, unitsProvider->StringFromOptionalValue( aValue, true ) );
759}
760
761
762void WX_GRID::onGridColMove( wxGridEvent& aEvent )
763{
764 // wxWidgets won't move an open editor, so better just to close it
765 CommitPendingChanges( true );
766}
767
768
769int WX_GRID::GetVisibleWidth( int aCol, bool aHeader, bool aContents, bool aKeep )
770{
771 int size = 0;
772
773 if( aCol < 0 )
774 {
775 if( aKeep )
776 size = GetRowLabelSize();
777
778 for( int row = 0; aContents && row < GetNumberRows(); row++ )
779 size = std::max( size, int( GetTextExtent( GetRowLabelValue( row ) + wxS( "M" ) ).x ) );
780 }
781 else
782 {
783 if( aKeep )
784 size = GetColSize( aCol );
785
786 // 'M' is generally the widest character, so we buffer the column width by default to
787 // ensure we don't write a continuous line of text at the column header
788 if( aHeader )
789 {
791
792 size = std::max( size, int( GetTextExtent( GetColLabelValue( aCol ) + wxS( "M" ) ).x ) );
793 }
794
795 for( int row = 0; aContents && row < GetNumberRows(); row++ )
796 {
797 // If we have text, get the size. Otherwise, use a placeholder for the checkbox
798 if( GetTable()->CanGetValueAs( row, aCol, wxGRID_VALUE_STRING ) )
799 size = std::max( size, GetTextExtent( GetCellValue( row, aCol ) + wxS( "M" ) ).x );
800 else
801 size = std::max( size, GetTextExtent( "MM" ).x );
802 }
803 }
804
805 return size;
806}
807
808
810{
811 int line_height = int( GetTextExtent( "Mj" ).y ) + 3;
812 int row_height = GetColLabelSize();
813 int initial_row_height = row_height;
814
815 // Headers can be multiline. Fix the Column Label Height to show the full header
816 // However GetTextExtent does not work on multiline strings,
817 // and do not return the full text height (only the height of one line)
818 for( int col = 0; col < GetNumberCols(); col++ )
819 {
820 int nl_count = GetColLabelValue( col ).Freq( '\n' );
821
822 if( nl_count )
823 {
824 // Col Label height must be able to show nl_count+1 lines
825 if( row_height < line_height * ( nl_count+1 ) )
826 row_height += line_height * nl_count;
827 }
828 }
829
830 // Update the column label size, but only if needed, to avoid generating useless
831 // and perhaps annoying UI events when the size does not change
832 if( initial_row_height != row_height )
833 SetColLabelSize( row_height );
834}
int color
Definition: DXF_plotter.cpp:58
const char * name
Definition: DXF_plotter.cpp:57
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:88
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
wxColour ToColour() const
Definition: color4d.cpp:220
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
Definition: color4d.h:295
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
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...
Definition: wx_grid.cpp:157
WX_GRID_ALT_ROW_COLOR_PROVIDER(const wxColor &aBaseColor)
Definition: wx_grid.cpp:159
wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) const override
Definition: wx_grid.cpp:175
wxGridCellAttrPtr m_attrEven
Definition: wx_grid.cpp:201
void UpdateColors(const wxColor &aBaseColor)
Definition: wx_grid.cpp:166
void DrawBorder(const wxGrid &grid, wxDC &dc, wxRect &rect) const override
Definition: wx_grid.cpp:121
void DrawBorder(const wxGrid &grid, wxDC &dc, wxRect &rect) const override
Definition: wx_grid.cpp:104
void DrawBorder(const wxGrid &grid, wxDC &dc, wxRect &rect) const override
Definition: wx_grid.cpp:138
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
Definition: wx_grid.cpp:45
int GetVisibleWidth(int aCol, bool aHeader=true, bool aContents=true, bool aKeep=false)
Calculates the specified column based on the actual size of the text on screen.
Definition: wx_grid.cpp:769
void onGridCellSelect(wxGridEvent &aEvent)
Definition: wx_grid.cpp:324
~WX_GRID() override
Definition: wx_grid.cpp:222
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...
Definition: wx_grid.cpp:264
bool m_weOwnTable
Definition: wx_grid.h:225
void onDPIChanged(wxDPIChangedEvent &event)
Definition: wx_grid.cpp:233
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:487
std::map< int, UNITS_PROVIDER * > m_unitsProviders
Definition: wx_grid.h:227
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...
Definition: wx_grid.cpp:270
void DestroyTable(wxGridTableBase *aTable)
Work-around for a bug in wxGrid which crashes when deleting the table if the cell edit control was no...
Definition: wx_grid.cpp:443
bool CancelPendingChanges()
Definition: wx_grid.cpp:609
void SetColLabelSize(int aHeight)
Hide wxGrid's SetColLabelSize() method with one which makes sure the size is tall enough for the syst...
Definition: wx_grid.cpp:249
void SetUnitValue(int aRow, int aCol, int aValue)
Set a unitized cell's value.
Definition: wx_grid.cpp:740
WX_GRID(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxWANTS_CHARS, const wxString &name=wxGridNameStr)
Definition: wx_grid.cpp:205
int GetUnitValue(int aRow, int aCol)
Apply standard KiCad unit and eval services to a numeric cell.
Definition: wx_grid.cpp:698
std::vector< int > m_autoEvalCols
Definition: wx_grid.h:229
std::map< std::pair< int, int >, std::pair< wxString, wxString > > m_evalBeforeAfter
Definition: wx_grid.h:231
void DrawCornerLabel(wxDC &dc) override
A re-implementation of wxGrid::DrawCornerLabel which draws flat borders.
Definition: wx_grid.cpp:517
void onCellEditorHidden(wxGridEvent &aEvent)
Definition: wx_grid.cpp:366
void onGridColMove(wxGridEvent &aEvent)
Definition: wx_grid.cpp:762
void SetOptionalUnitValue(int aRow, int aCol, std::optional< int > aValue)
Set a unitized cell's optional value.
Definition: wx_grid.cpp:751
void onCellEditorShown(wxGridEvent &aEvent)
Definition: wx_grid.cpp:351
void EnsureColLabelsVisible()
Ensure the height of the row displaying the column labels is enough, even if labels are multiline tex...
Definition: wx_grid.cpp:809
wxString GetShownColumnsAsString()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:457
void DrawRowLabel(wxDC &dc, int row) override
A re-implementation of wxGrid::DrawRowLabel which draws flat borders.
Definition: wx_grid.cpp:577
std::bitset< 64 > GetShownColumns()
Definition: wx_grid.cpp:476
static void CellEditorSetMargins(wxTextEntryBase *aEntry)
A helper function to set OS-specific margins for text-based cell editors.
Definition: wx_grid.cpp:77
std::optional< int > GetOptionalUnitValue(int aRow, int aCol)
Apply standard KiCad unit and eval services to a numeric cell.
Definition: wx_grid.cpp:719
void EnableAlternateRowColors(bool aEnable=true)
Enable alternate row highlighting, where every odd row has a different background color than the even...
Definition: wx_grid.cpp:305
void SetUnitsProvider(UNITS_PROVIDER *aProvider, int aCol=0)
Set a UNITS_PROVIDER to enable use of unit- and eval-based Getters.
Definition: wx_grid.cpp:689
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:637
std::unique_ptr< NUMERIC_EVALUATOR > m_eval
Definition: wx_grid.h:228
void DrawColLabel(wxDC &dc, int col) override
A re-implementation of wxGrid::DrawColLabel which left-aligns the first column and draws flat borders...
Definition: wx_grid.cpp:538
static void CellEditorTransformSizeRect(wxRect &aRect)
A helper function to tweak sizes of text-based cell editors depending on OS.
Definition: wx_grid.cpp:84
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition: wxgtk/ui.cpp:48
KICOMMON_API wxFont GetControlFont(wxWindow *aWindow)
Definition: ui_common.cpp:160
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
see class PGM_BASE
Functions to provide common constants and other functions to assist in making a consistent UI.
wxColour getBorderColour()
Definition: wx_grid.cpp:92
#define MIN_GRIDCELL_MARGIN
Definition: wx_grid.cpp:74