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