KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/dialogs/dialog_tablecell_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>
26#include <widgets/font_choice.h>
28#include <confirm.h>
29#include <board_commit.h>
31#include <board.h>
32#include <footprint.h>
33#include <pcb_textbox.h>
34#include <pcb_tablecell.h>
35#include <pcb_table.h>
36#include <project.h>
37#include <pcb_edit_frame.h>
39#include <tool/tool_manager.h>
40#include <tools/pcb_actions.h>
41#include <scintilla_tricks.h>
42
43
45 std::vector<PCB_TABLECELL*> aCells ) :
47 m_frame( aFrame ),
48 m_table( nullptr ),
49 m_cells( std::move( aCells ) ),
53 m_marginLeft( aFrame, nullptr, m_marginLeftCtrl, nullptr ),
54 m_marginTop( aFrame, nullptr, m_marginTopCtrl, m_marginTopUnits ),
55 m_marginRight( aFrame, nullptr, m_marginRightCtrl, nullptr ),
56 m_marginBottom( aFrame, nullptr, m_marginBottomCtrl, nullptr ),
58 m_cellTextIsGenerated( false ),
60{
61 wxASSERT( m_cells.size() > 0 && m_cells[0] );
62
63 m_cellText->SetEOLMode( wxSTC_EOL_LF );
64
65 // Wrapping is display-only and does not insert newlines into the stored text.
66 m_cellText->SetWrapMode( wxSTC_WRAP_WORD );
67 m_cellText->SetWrapVisualFlags( wxSTC_WRAPVISUALFLAG_END );
68 m_cellText->SetWrapIndentMode( wxSTC_WRAPINDENT_INDENT );
69
70#ifdef _WIN32
71 // Without this setting, on Windows, some esoteric unicode chars create display issue
72 // in a wxStyledTextCtrl.
73 // for SetTechnology() info, see https://www.scintilla.org/ScintillaDoc.html#SCI_SETTECHNOLOGY
74 m_cellText->SetTechnology( wxSTC_TECHNOLOGY_DIRECTWRITE );
75#endif
76
78 m_cellText, wxT( "{}" ), false,
79 // onAcceptFn
80 [this]( wxKeyEvent& aEvent )
81 {
82 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
83 },
84 // onCharFn
85 [this]( wxStyledTextEvent& aEvent )
86 {
87 m_scintillaTricks->DoTextVarAutocomplete(
88 // getTokensFn
89 [this]( const wxString& xRef, wxArrayString* tokens )
90 {
91 m_frame->GetContextualTextVars( m_table, xRef, tokens );
92 } );
93 } );
94
95 // A hack which causes Scintilla to auto-size the text editor canvas
96 // See: https://github.com/jacobslusser/ScintillaNET/issues/216
97 m_cellText->SetScrollWidth( 1 );
98 m_cellText->SetScrollWidthTracking( true );
99
101
102 m_table = static_cast<PCB_TABLE*>( m_cells[0]->GetParent() );
103
104 // A generated table reports the board. Its text is generated, so only the formatting on
105 // this page is the user's to change
106 if( m_table->IsGenerated() )
107 {
109 m_cellText->SetReadOnly( true );
111 }
112
113 m_hAlignLeft->SetIsRadioButton();
115 m_hAlignCenter->SetIsRadioButton();
117 m_hAlignRight->SetIsRadioButton();
119
120 m_separator0->SetIsSeparator();
121
122 m_vAlignTop->SetIsRadioButton();
124 m_vAlignCenter->SetIsRadioButton();
126 m_vAlignBottom->SetIsRadioButton();
128
129 m_separator1->SetIsSeparator();
130
131 m_bold->SetIsCheckButton();
133 m_italic->SetIsCheckButton();
135
136 m_autoTextThickness->SetIsCheckButton();
138
140 Layout();
141
142 m_helpWindow = nullptr;
143
144 Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TABLECELL_PROPERTIES::OnCharHook ), nullptr, this );
145
146 m_hAlignLeft->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onHAlignButton, this );
149 m_vAlignTop->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onVAlignButton, this );
152
153 // Now all widgets have the size fixed, call FinishDialogSettings
155}
156
158{
159 Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TABLECELL_PROPERTIES::OnCharHook ), nullptr, this );
160
161 delete m_scintillaTricks;
162 m_scintillaTricks = nullptr;
163
164 if( m_helpWindow )
165 m_helpWindow->Destroy();
166}
167
168
170{
171 if( !wxDialog::TransferDataToWindow() )
172 return false;
173
174 // Scintilla drops every write while it is read-only, so generated text would arrive here
175 // as an empty control and be written back over the cell on OK
176 m_cellText->SetReadOnly( false );
177
178 bool firstCell = true;
181 int textThickness = 0;
182 int basePenWidth = 0;
183
184 for( PCB_TABLECELL* cell : m_cells )
185 {
186 if( firstCell )
187 {
188 wxString text = cell->GetText();
189
190 // show text variable cross-references in a human-readable format
191 if( BOARD* board = cell->GetBoard() )
192 text = board->ConvertKIIDsToCrossReferences( text );
193
194 m_cellTextCtrl->SetValue( text );
195
196 m_fontCtrl->SetFontSelection( cell->GetFont() );
197 m_textWidth.SetValue( cell->GetTextWidth() );
198 m_textHeight.SetValue( cell->GetTextHeight() );
199 textThickness = cell->GetTextThickness();
200 basePenWidth = GetPenSizeForNormal( cell->GetTextWidth() );
201
202 hAlign = cell->GetHorizJustify();
203 vAlign = cell->GetVertJustify();
204
205 m_marginLeft.SetValue( cell->GetMarginLeft() );
206 m_marginTop.SetValue( cell->GetMarginTop() );
207 m_marginRight.SetValue( cell->GetMarginRight() );
208 m_marginBottom.SetValue( cell->GetMarginBottom() );
209
210 m_bold->Check( cell->IsBold() );
211 m_mixedBoldSetting = false;
212
213 m_italic->Check( cell->IsItalic() );
214 m_mixedItalicSetting = false;
215
216 m_cbKnockout->SetValue( cell->IsKnockout() );
217
218 firstCell = false;
219 }
220 else
221 {
222 wxString text = cell->GetText();
223
224 // show text variable cross-references in a human-readable format
225 if( BOARD* board = cell->GetBoard() )
226 text = board->ConvertKIIDsToCrossReferences( text );
227
228 if( text != m_cellTextCtrl->GetValue() )
230
231 if( cell->GetFont() != m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) )
232 m_fontCtrl->SetSelection( -1 );
233
234 if( cell->GetTextWidth() != m_textWidth.GetValue() )
236
237 if( cell->GetTextHeight() != m_textHeight.GetValue() )
239
240 if( cell->GetTextThickness() != textThickness )
241 textThickness = -1;
242
243 if( GetPenSizeForNormal( cell->GetTextWidth() ) != basePenWidth )
244 basePenWidth = -1;
245
246 if( cell->IsBold() != m_bold->IsChecked() )
247 {
248 m_mixedBoldSetting = true;
249 m_bold->Check( false );
250 }
251
252 if( cell->IsItalic() != m_italic->IsChecked() )
253 {
255 m_italic->Check( false );
256 }
257
258 if( cell->GetHorizJustify() != hAlign )
260
261 if( cell->GetVertJustify() != vAlign )
263
264 if( cell->GetMarginLeft() != m_marginLeft.GetIntValue() )
266
267 if( cell->GetMarginTop() != m_marginTop.GetIntValue() )
269
270 if( cell->GetMarginRight() != m_marginRight.GetIntValue() )
272
273 if( cell->GetMarginBottom() != m_marginBottom.GetIntValue() )
275
276 if( cell->IsKnockout() != m_cbKnockout->GetValue() )
277 m_cbKnockout->Set3StateValue( wxCHK_UNDETERMINED );
278 }
279
280 m_hAlignLeft->Check( false );
281 m_hAlignCenter->Check( false );
282 m_hAlignRight->Check( false );
283
284 switch( hAlign )
285 {
286 case GR_TEXT_H_ALIGN_LEFT: m_hAlignLeft->Check(); break;
287 case GR_TEXT_H_ALIGN_CENTER: m_hAlignCenter->Check(); break;
288 case GR_TEXT_H_ALIGN_RIGHT: m_hAlignRight->Check(); break;
290 }
291
292 m_vAlignTop->Check( false );
293 m_vAlignCenter->Check( false );
294 m_vAlignBottom->Check( false );
295
296 switch( vAlign )
297 {
298 case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check(); break;
299 case GR_TEXT_V_ALIGN_CENTER: m_vAlignCenter->Check(); break;
300 case GR_TEXT_V_ALIGN_BOTTOM: m_vAlignBottom->Check(); break;
302 }
303 }
304
306 m_autoTextThickness->Check( false );
307
308 if( textThickness == 0 )
309 {
310 // Show the base width (frozen if auto is unchecked); Bold scales it at render time.
311 if( basePenWidth > 0 )
312 m_textThickness.SetValue( basePenWidth );
313
314 m_autoTextThickness->Check( true );
315 m_textThickness.Enable( false );
316 }
317 else if( textThickness > 0 )
318 {
319 m_textThickness.SetValue( textThickness );
320 }
321
322 m_cellText->SetReadOnly( m_cellTextIsGenerated );
323
324 return true;
325}
326
327void DIALOG_TABLECELL_PROPERTIES::onTextSize( wxCommandEvent& aEvent )
328{
329 if( m_autoTextThickness->IsChecked() )
330 m_textThickness.SetValue( GetPenSizeForNormal( m_textWidth.GetIntValue() ) );
331}
332
333
335{
336 if( aEvent.IsChecked() )
337 {
338 m_autoTextThickness->Check( true );
339
340 if( !m_textWidth.IsIndeterminate() && !m_textHeight.IsIndeterminate() )
341 {
342 wxCommandEvent dummy;
343 onTextSize( dummy );
344 }
345
346 m_textThickness.Enable( false );
347 }
348 else
349 {
350 m_textThickness.Enable( true );
351 }
352}
353
354
355void DIALOG_TABLECELL_PROPERTIES::onBold(wxCommandEvent& aEvent)
356{
357 m_mixedBoldSetting = false;
358 aEvent.Skip();
359}
360
361
362void DIALOG_TABLECELL_PROPERTIES::onItalic(wxCommandEvent& aEvent)
363{
364 m_mixedItalicSetting = false;
365 aEvent.Skip();
366}
367
368
369void DIALOG_TABLECELL_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
370{
372 {
373 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
374 btn->Check( false );
375 }
376}
377
378
379void DIALOG_TABLECELL_PROPERTIES::onVAlignButton( wxCommandEvent& aEvent )
380{
381 for( BITMAP_BUTTON* btn : { m_vAlignTop, m_vAlignCenter, m_vAlignBottom } )
382 {
383 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
384 btn->Check( false );
385 }
386}
387
388
390{
391 if( !wxDialog::TransferDataFromWindow() )
392 return false;
393
394 BOARD_COMMIT commit( m_frame );
395 commit.Modify( m_table );
396
397 // If no other command in progress, prepare undo command
398 // (for a command in progress, will be made later, at the completion of command)
399 bool pushCommit = ( m_table->GetEditFlags() == 0 );
400
401 // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
402 // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
403 if( !pushCommit )
404 m_table->SetFlags( IN_EDIT );
405
406 for( PCB_TABLECELL* cell : m_cells )
407 {
409 {
410 wxString txt = m_cellTextCtrl->GetValue();
411
412 // convert any text variable cross-references to their UUIDs
413 if( BOARD* board = cell->GetBoard() )
414 txt = board->ConvertCrossReferencesToKIIDs( txt );
415
416#ifdef __WXMAC__
417 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
418 // Replace it now.
419 txt.Replace( "\r", "\n" );
420#elif defined( __WINDOWS__ )
421 // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
422 // drawing routines so strip the \r char.
423 txt.Replace( "\r", "" );
424#endif
425
426 cell->SetText( txt );
427 }
428
429 if( !m_mixedBoldSetting )
430 cell->SetBold( m_bold->IsChecked() );
431
433 cell->SetItalic( m_italic->IsChecked() );
434
435 if( m_cbKnockout->Get3StateValue() == wxCHK_CHECKED )
436 cell->SetIsKnockout( true );
437 else if( m_cbKnockout->Get3StateValue() == wxCHK_UNCHECKED )
438 cell->SetIsKnockout( false );
439
440 if( m_fontCtrl->HaveFontSelection() )
441 cell->SetFont( m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) );
442
443 if( !m_textWidth.IsIndeterminate() )
444 cell->SetTextWidth( m_textWidth.GetIntValue() );
445
446 if( !m_textHeight.IsIndeterminate() )
447 cell->SetTextHeight( m_textHeight.GetIntValue() );
448
449 if( m_autoTextThickness->IsChecked() )
450 cell->SetAutoThickness( true );
451 else if( !m_textThickness.IsIndeterminate() )
452 cell->SetTextThickness( m_textThickness.GetIntValue() );
453
454 if( m_hAlignLeft->IsChecked() )
455 cell->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
456 else if( m_hAlignRight->IsChecked() )
457 cell->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
458 else if( m_hAlignCenter->IsChecked() )
459 cell->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
460
461 if( m_vAlignTop->IsChecked() )
462 cell->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
463 else if( m_vAlignBottom->IsChecked() )
464 cell->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
465 else if( m_vAlignCenter->IsChecked() )
466 cell->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
467
468 if( !m_marginLeft.IsIndeterminate() )
469 cell->SetMarginLeft( m_marginLeft.GetIntValue() );
470
471 if( !m_marginTop.IsIndeterminate() )
472 cell->SetMarginTop( m_marginTop.GetIntValue() );
473
474 if( !m_marginRight.IsIndeterminate() )
475 cell->SetMarginRight( m_marginRight.GetIntValue() );
476
477 if( !m_marginBottom.IsIndeterminate() )
478 cell->SetMarginBottom( m_marginBottom.GetIntValue() );
479 }
480
481 if( !commit.Empty() )
482 commit.Push( _( "Edit Table Cell Properties" ), SKIP_CONNECTIVITY );
483
485 return true;
486}
487
488
489void DIALOG_TABLECELL_PROPERTIES::onEditTable( wxCommandEvent& aEvent )
490{
492 {
494 Close();
495 }
496}
497
498
499void DIALOG_TABLECELL_PROPERTIES::onSyntaxHelp( wxHyperlinkEvent& aEvent )
500{
501 if( m_helpWindow )
502 {
503 m_helpWindow->Raise();
504 m_helpWindow->Show( true );
505 return;
506 }
507
509}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
@ text_align_right
@ text_valign_top
@ text_align_left
@ text_valign_center
@ text_align_center
@ text_valign_bottom
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
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...
virtual void OnCharHook(wxKeyEvent &aEvt)
DIALOG_TABLECELL_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Table Cell Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
bool m_cellTextIsGenerated
Generated cell text, shown so the user can read it but not theirs to change.
void onAutoTextThickness(wxCommandEvent &aEvent) override
DIALOG_TABLECELL_PROPERTIES(SCH_EDIT_FRAME *aParentFrame, std::vector< SCH_TABLECELL * > aCells)
void onSyntaxHelp(wxHyperlinkEvent &aEvent) override
Common, abstract interface for edit frames.
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.
This file is part of the common library.
#define _(s)
#define IN_EDIT
Item currently edited.
int GetPenSizeForNormal(int aTextSize)
Definition gr_text.cpp:58
STL namespace.
#define SKIP_CONNECTIVITY
Definition sch_commit.h:41
std::vector< FAB_LAYER_COLOR > dummy
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_H_ALIGN_INDETERMINATE
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:47