KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/dialogs/dialog_table_properties.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 The 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 2
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, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <wx/hyperlink.h>
23
24#include <kiplatform/ui.h>
25#include <widgets/font_choice.h>
27#include <widgets/wx_grid.h>
31#include <grid_tricks.h>
32#include <scintilla_tricks.h>
33#include <string_utils.h>
34#include <confirm.h>
35#include <board.h>
36#include <board_commit.h>
38#include <footprint.h>
39#include <pcb_textbox.h>
40#include <pcb_tablecell.h>
41#include <pcb_table.h>
42#include <project.h>
43#include <pcb_edit_frame.h>
45#include <tool/tool_manager.h>
46#include <tools/pcb_actions.h>
47
48
51 m_frame( aFrame ),
52 m_table( aTable ),
55{
56 m_grid = new WX_GRID( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
57
58 m_grid->CreateGrid( m_table->GetRowCount(), m_table->GetColCount() );
59 m_grid->EnableEditing( true );
60 m_grid->EnableGridLines( true );
61 m_grid->EnableDragGridSize( false );
62 m_grid->SetMargins( 0, 0 );
63 m_grid->SetCellHighlightROPenWidth( 0 );
64
65 m_grid->EnableDragColMove( false );
66 m_grid->EnableDragColSize( false );
67 m_grid->SetColLabelSize( 0 );
68 m_grid->EnableDragRowMove( false );
69 m_grid->EnableDragRowSize( false );
70 m_grid->SetRowLabelSize( 0 );
71 m_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
72
73 m_gridSizer->Add( m_grid, 1, wxEXPAND, 5 );
74 m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
75
76 for( int row = 0; row < m_table->GetRowCount(); ++row )
77 {
78 for( int col = 0; col < m_table->GetColCount(); ++col )
79 {
80 PCB_TABLECELL* cell = m_table->GetCell( row, col );
81 wxGridCellAttr* attr = new wxGridCellAttr;
82
83 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
84 {
85 attr->SetRenderer( new GRID_CELL_COLOR_RENDERER( this ) );
86 attr->SetReadOnly();
87 }
88 else
89 {
90 attr->SetRenderer( new wxGridCellAutoWrapStringRenderer );
91 attr->SetEditor( new GRID_CELL_STC_EDITOR(
92 true, false,
93 [this, cell]( wxStyledTextEvent& aEvent, SCINTILLA_TRICKS* aScintillaTricks )
94 {
95 aScintillaTricks->DoTextVarAutocomplete(
96 // getTokensFn
97 [this, cell]( const wxString& xRef, wxArrayString* tokens )
98 {
99 m_frame->GetContextualTextVars( cell, xRef, tokens );
100 } );
101 } ) );
102 }
103
104 m_grid->SetAttr( row, col, attr );
105 }
106 }
107
108 if( m_table->GetParentFootprint() )
109 {
110 // Do not allow locking items in the footprint editor
111 m_cbLocked->Show( false );
112 }
113
114 // Configure the layers list selector. Note that footprints are built outside the current
115 // board and so we may need to show all layers if the text is on an unactivated layer.
116 if( !m_frame->GetBoard()->IsLayerEnabled( m_table->GetLayer() ) )
117 m_LayerSelectionCtrl->ShowNonActivatedLayers( true );
118
119 m_LayerSelectionCtrl->SetLayersHotkeys( false );
120 m_LayerSelectionCtrl->SetBoardFrame( m_frame );
121 m_LayerSelectionCtrl->Resync();
122
123 for( const auto& [lineStyle, lineStyleDesc] : lineTypeNames )
124 {
125 m_borderStyleCombo->Append( lineStyleDesc.name, KiBitmap( lineStyleDesc.bitmap ) );
126 m_separatorsStyleCombo->Append( lineStyleDesc.name, KiBitmap( lineStyleDesc.bitmap ) );
127 }
128
130 Layout();
131
132 // Add syntax help hyperlink
133 m_syntaxHelp = new wxHyperlinkCtrl( this, wxID_ANY, _( "Syntax help" ), wxEmptyString, wxDefaultPosition,
134 wxDefaultSize, wxHL_DEFAULT_STYLE );
135 m_syntaxHelp->SetToolTip( _( "Show syntax help window" ) );
136 m_gridSizer->Add( m_syntaxHelp, 0, wxTOP | wxBOTTOM | wxRIGHT | wxLEFT, 3 );
137
138 m_syntaxHelp->Bind( wxEVT_HYPERLINK, &DIALOG_TABLE_PROPERTIES::onSyntaxHelp, this );
139
140 m_helpWindow = nullptr;
141
142 // Now all widgets have the size fixed, call FinishDialogSettings
144}
145
146
148{
149 // Delete the GRID_TRICKS.
150 m_grid->PopEventHandler( true );
151
152 if( m_helpWindow )
153 m_helpWindow->Destroy();
154}
155
156
158{
159 BOARD* board = m_frame->GetBoard();
160
161 if( !wxDialog::TransferDataToWindow() )
162 return false;
163
164 //
165 // Cell Contents
166 //
167
168 wxColour coveredColor = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
169
171 coveredColor = coveredColor.ChangeLightness( 140 );
172 else
173 coveredColor = coveredColor.ChangeLightness( 100 );
174
175 for( int row = 0; row < m_table->GetRowCount(); ++row )
176 {
177 for( int col = 0; col < m_table->GetColCount(); ++col )
178 {
179 PCB_TABLECELL* tableCell;
180
181 if( IsBackLayer( m_table->GetLayer() ) )
182 tableCell = m_table->GetCell( row, m_table->GetColCount() - 1 - col );
183 else
184 tableCell = m_table->GetCell( row, col );
185
186 if( tableCell->GetColSpan() == 0 || tableCell->GetRowSpan() == 0 )
187 {
188 m_grid->SetCellValue( row, col, coveredColor.GetAsString() );
189 continue;
190 }
191
192 wxString text = tableCell->GetText();
193
194 // show text variable cross-references in a human-readable format
196
197 m_grid->SetCellValue( row, col, text );
198 }
199 }
200
201 CallAfter(
202 [this]()
203 {
204 for( int row = 0; row < m_table->GetRowCount(); ++row )
205 {
206 for( int col = 0; col < m_table->GetColCount(); ++col )
207 {
208 PCB_TABLECELL* tableCell = m_table->GetCell( row, col );
209
210 if( tableCell->IsSelected() )
211 {
212 m_grid->SetGridCursor( row, col );
213 m_grid->EnableCellEditControl();
214 m_grid->ShowCellEditControl();
215 return;
216 }
217 }
218 }
219 } );
220
222
223 //
224 // Table Properties
225 //
226
227 m_LayerSelectionCtrl->SetLayerSelection( m_table->GetLayer() );
228 m_cbLocked->SetValue( m_table->IsLocked() );
229
230 m_borderCheckbox->SetValue( m_table->StrokeExternal() );
231 m_headerBorder->SetValue( m_table->StrokeHeaderSeparator() );
232
233 if( m_table->GetBorderStroke().GetWidth() >= 0 )
234 m_borderWidth.SetValue( m_table->GetBorderStroke().GetWidth() );
235
236 int style = static_cast<int>( m_table->GetBorderStroke().GetLineStyle() );
237
238 if( style >= 0 && style < (int) lineTypeNames.size() )
239 m_borderStyleCombo->SetSelection( style );
240 else
241 m_borderStyleCombo->SetSelection( 0 );
242
243 m_borderWidth.Enable( m_table->StrokeExternal() || m_table->StrokeHeaderSeparator() );
244 m_borderStyleLabel->Enable( m_table->StrokeExternal() || m_table->StrokeHeaderSeparator() );
245 m_borderStyleCombo->Enable( m_table->StrokeExternal() || m_table->StrokeHeaderSeparator() );
246
247 bool rows = m_table->StrokeRows() && m_table->GetSeparatorsStroke().GetWidth() >= 0;
248 bool cols = m_table->StrokeColumns() && m_table->GetSeparatorsStroke().GetWidth() >= 0;
249
250 m_rowSeparators->SetValue( rows );
251 m_colSeparators->SetValue( cols );
252
253 if( m_table->GetSeparatorsStroke().GetWidth() >= 0 )
254 m_separatorsWidth.SetValue( m_table->GetSeparatorsStroke().GetWidth() );
255
256 style = static_cast<int>( m_table->GetSeparatorsStroke().GetLineStyle() );
257
258 if( style >= 0 && style < (int) lineTypeNames.size() )
259 m_separatorsStyleCombo->SetSelection( style );
260 else
261 m_separatorsStyleCombo->SetSelection( 0 );
262
263 m_separatorsWidth.Enable( rows || cols );
264 m_separatorsStyleLabel->Enable( rows || cols );
265 m_separatorsStyleCombo->Enable( rows || cols );
266
267 return true;
268}
269
270void DIALOG_TABLE_PROPERTIES::onHeaderChecked( wxCommandEvent& aEvent )
271{
272 BOARD_DESIGN_SETTINGS& bds = m_frame->GetDesignSettings();
273 PCB_LAYER_ID currentLayer = ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() );
274 int defaultLineThickness = bds.GetLineThickness( currentLayer );
275
276 bool border = m_borderCheckbox->GetValue();
277 bool header = m_headerBorder->GetValue();
278
279 if( ( border || header ) && m_borderWidth.GetValue() < 0 )
280 m_borderWidth.SetValue( defaultLineThickness );
281
282 m_borderWidth.Enable( border || header );
283 m_borderStyleLabel->Enable( border || header );
284 m_borderStyleCombo->Enable( border || header );
285
286 bool row = m_rowSeparators->GetValue();
287 bool col = m_colSeparators->GetValue();
288
289 if( ( row || col ) && m_separatorsWidth.GetValue() < 0 )
290 m_separatorsWidth.SetValue( defaultLineThickness );
291
292 m_separatorsWidth.Enable( row || col );
293 m_separatorsStyleLabel->Enable( row || col );
294 m_separatorsStyleCombo->Enable( row || col );
295}
296
297void DIALOG_TABLE_PROPERTIES::onBorderChecked( wxCommandEvent& aEvent )
298{
299 BOARD_DESIGN_SETTINGS& bds = m_frame->GetDesignSettings();
301 int defaultLineThickness = bds.GetLineThickness( currentLayer );
302
303 bool border = m_borderCheckbox->GetValue();
304 bool header = m_headerBorder->GetValue();
305
306 if( ( border || header ) && m_borderWidth.GetValue() < 0 )
307 m_borderWidth.SetValue( defaultLineThickness );
308
309 m_borderWidth.Enable( border || header );
310 m_borderStyleLabel->Enable( border || header );
311 m_borderStyleCombo->Enable( border || header );
312
313 bool row = m_rowSeparators->GetValue();
314 bool col = m_colSeparators->GetValue();
315
316 if( ( row || col ) && m_separatorsWidth.GetValue() < 0 )
317 m_separatorsWidth.SetValue( defaultLineThickness );
318
319 m_separatorsWidth.Enable( row || col );
320 m_separatorsStyleLabel->Enable( row || col );
321 m_separatorsStyleCombo->Enable( row || col );
322}
323
324
326{
327 if( !m_grid->CommitPendingChanges() )
328 return false;
329
330 if( !wxDialog::TransferDataFromWindow() )
331 return false;
332
333 BOARD* board = m_frame->GetBoard();
334 BOARD_COMMIT commit( m_frame );
335 commit.Modify( m_table );
336
337 // If no other command in progress, prepare undo command
338 // (for a command in progress, will be made later, at the completion of command)
339 bool pushCommit = ( m_table->GetEditFlags() == 0 );
340
341 // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
342 // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
343 if( !pushCommit )
344 m_table->SetFlags( IN_EDIT );
345
346 for( int row = 0; row < m_table->GetRowCount(); ++row )
347 {
348 for( int col = 0; col < m_table->GetColCount(); ++col )
349 {
350 PCB_TABLECELL* tableCell;
351
352 if( IsBackLayer( m_table->GetLayer() ) )
353 tableCell = m_table->GetCell( row, m_table->GetColCount() - 1 - col );
354 else
355 tableCell = m_table->GetCell( row, col );
356
357 wxString txt = m_grid->GetCellValue( row, col );
358
359 // Don't insert grey colour value back in to table cell
360 if( tableCell->GetColSpan() == 0 || tableCell->GetRowSpan() == 0 )
361 txt = wxEmptyString;
362
363 // convert any text variable cross-references to their UUIDs
364 txt = board->ConvertCrossReferencesToKIIDs( txt );
365
366#ifdef __WXMAC__
367 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
368 // Replace it now.
369 txt.Replace( "\r", "\n" );
370#elif defined( __WINDOWS__ )
371 // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
372 // drawing routines so strip the \r char.
373 txt.Replace( "\r", "" );
374#endif
375
376 tableCell->SetText( txt );
377 tableCell->SetLayer( ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() ) );
378 }
379 }
380
381 m_table->SetLayer( ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() ) );
382 m_table->SetLocked( m_cbLocked->GetValue() );
383
384 m_table->SetStrokeExternal( m_borderCheckbox->GetValue() );
385 m_table->SetStrokeHeaderSeparator( m_headerBorder->GetValue() );
386 {
387 STROKE_PARAMS stroke = m_table->GetBorderStroke();
388
389 if( m_borderCheckbox->GetValue() || m_headerBorder->GetValue() )
390 stroke.SetWidth( std::max( 0, m_borderWidth.GetIntValue() ) );
391 else
392 stroke.SetWidth( -1 );
393
394 auto it = lineTypeNames.begin();
395 std::advance( it, m_borderStyleCombo->GetSelection() );
396
397 if( it == lineTypeNames.end() )
399 else
400 stroke.SetLineStyle( it->first );
401
402 m_table->SetBorderStroke( stroke );
403 }
404
405 m_table->SetStrokeRows( m_rowSeparators->GetValue() );
406 m_table->SetStrokeColumns( m_colSeparators->GetValue() );
407 {
408 STROKE_PARAMS stroke = m_table->GetSeparatorsStroke();
409
410 if( m_rowSeparators->GetValue() || m_colSeparators->GetValue() )
411 stroke.SetWidth( std::max( 0, m_separatorsWidth.GetIntValue() ) );
412 else
413 stroke.SetWidth( -1 );
414
415 auto it = lineTypeNames.begin();
416 std::advance( it, m_separatorsStyleCombo->GetSelection() );
417
418 if( it == lineTypeNames.end() )
420 else
421 stroke.SetLineStyle( it->first );
422
423 m_table->SetSeparatorsStroke( stroke );
424 }
425
426 if( pushCommit )
427 commit.Push( _( "Edit Table" ), SKIP_CONNECTIVITY );
428
429 return true;
430}
431
432
434{
435 Layout(); // Make sure we get the current client size for the grid
436
437 wxSize availableGridSize = m_grid->GetClientSize();
438
439 if( availableGridSize.x == 0 || availableGridSize.y == 0 )
440 return;
441
442 BOX2I tableBBox = m_table->GetBoundingBox();
443 double scalerX = static_cast<double>( availableGridSize.x ) / tableBBox.GetWidth();
444 double scalerY = static_cast<double>( availableGridSize.y ) / tableBBox.GetHeight();
445
446 for( int row = 0; row < m_table->GetRowCount(); ++row )
447 m_grid->SetRowSize( row, std::floor( m_table->GetRowHeight( row ) * scalerY ) );
448
449 for( int col = 0; col < m_table->GetColCount(); ++col )
450 m_grid->SetColSize( col, std::floor( m_table->GetColWidth( col ) * scalerX ) );
451}
452
453
454void DIALOG_TABLE_PROPERTIES::onSize( wxSizeEvent& aEvent )
455{
456 if( m_table )
458
459 aEvent.Skip();
460}
461
462
463void DIALOG_TABLE_PROPERTIES::onSyntaxHelp( wxHyperlinkEvent& aEvent )
464{
466}
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:100
#define SKIP_CONNECTIVITY
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
Container for design settings for a BOARD object.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
wxString ConvertCrossReferencesToKIIDs(const wxString &aSource) const
Convert cross-references back and forth between ${refDes:field} and ${kiid:field}.
Definition board.cpp:2229
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition board.cpp:2309
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr size_type GetHeight() const
Definition box2.h:211
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
DIALOG_TABLE_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Table Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
DIALOG_TABLE_PROPERTIES(SCH_EDIT_FRAME *aParentFrame, SCH_TABLE *aTable)
void onBorderChecked(wxCommandEvent &aEvent) override
void onHeaderChecked(wxCommandEvent &aEvent) override
bool IsSelected() const
Definition eda_item.h:132
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:57
Common, abstract interface for edit frames.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
int GetRowSpan() const
int GetColSpan() const
static HTML_MESSAGE_BOX * ShowSyntaxHelp(wxWindow *aParentWindow)
Display a syntax help window for text variables and expressions.
Definition pcb_text.cpp:873
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
void DoTextVarAutocomplete(const std::function< void(const wxString &xRef, wxArrayString *tokens)> &getTokensFn)
void SetLineStyle(LINE_STYLE aLineStyle)
void SetWidth(int aWidth)
void Enable(bool aEnable)
Enable/disable the label, widget and units label.
virtual long long int GetValue() const
Return the current value in Internal Units.
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
This file is part of the common library.
#define _(s)
#define IN_EDIT
Item currently edited.
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
Definition layer_ids.h:801
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition wxgtk/ui.cpp:50
const std::map< LINE_STYLE, struct LINE_STYLE_DESC > lineTypeNames
Conversion map between LINE_STYLE values and style names displayed.
std::vector< std::string > header