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