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, 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#include <widgets/font_choice.h>
26#include <confirm.h>
27#include <board_commit.h>
29#include <board.h>
30#include <footprint.h>
31#include <pcb_textbox.h>
32#include <pcb_tablecell.h>
33#include <pcb_table.h>
34#include <project.h>
35#include <pcb_edit_frame.h>
37#include <tool/tool_manager.h>
38#include <tools/pcb_actions.h>
39#include <scintilla_tricks.h>
41
43 std::vector<PCB_TABLECELL*> aCells ) :
45 m_frame( aFrame ),
46 m_table( nullptr ),
47 m_cells( std::move( aCells ) ),
48 m_textHeight( aFrame, m_SizeYLabel, m_SizeYCtrl, m_SizeYUnits ),
49 m_textWidth( aFrame, m_SizeXLabel, m_SizeXCtrl, m_SizeXUnits ),
50 m_textThickness( aFrame, m_ThicknessLabel, m_ThicknessCtrl, m_ThicknessUnits ),
51 m_marginLeft( aFrame, nullptr, m_marginLeftCtrl, nullptr ),
52 m_marginTop( aFrame, nullptr, m_marginTopCtrl, m_marginTopUnits ),
53 m_marginRight( aFrame, nullptr, m_marginRightCtrl, nullptr ),
54 m_marginBottom( aFrame, nullptr, m_marginBottomCtrl, nullptr ),
55 m_cellText( m_cellTextCtrl ),
56 m_returnValue( TABLECELL_PROPS_CANCEL )
57{
58 wxASSERT( m_cells.size() > 0 && m_cells[0] );
59
60 m_cellText->SetEOLMode( wxSTC_EOL_LF );
61
62#ifdef _WIN32
63 // Without this setting, on Windows, some esoteric unicode chars create display issue
64 // in a wxStyledTextCtrl.
65 // for SetTechnology() info, see https://www.scintilla.org/ScintillaDoc.html#SCI_SETTECHNOLOGY
66 m_cellText->SetTechnology(wxSTC_TECHNOLOGY_DIRECTWRITE);
67#endif
68
69 m_scintillaTricks = new SCINTILLA_TRICKS( m_cellText, wxT( "{}" ), false,
70 // onAcceptFn
71 [this]( wxKeyEvent& aEvent )
72 {
73 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
74 },
75 // onCharFn
76 [this]( wxStyledTextEvent& aEvent )
77 {
79 // getTokensFn
80 [this]( const wxString& xRef, wxArrayString* tokens )
81 {
82 m_frame->GetContextualTextVars( m_table, xRef, tokens );
83 } );
84 } );
85
86 // A hack which causes Scintilla to auto-size the text editor canvas
87 // See: https://github.com/jacobslusser/ScintillaNET/issues/216
88 m_cellText->SetScrollWidth( 1 );
89 m_cellText->SetScrollWidthTracking( true );
90
92
93 m_table = static_cast<PCB_TABLE*>( m_cells[0]->GetParent() );
94
96 m_hAlignLeft->SetBitmap( KiBitmapBundle( BITMAPS::text_align_left ) );
98 m_hAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_align_center ) );
100 m_hAlignRight->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) );
101
103
105 m_vAlignTop->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_top ) );
107 m_vAlignCenter->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_center ) );
109 m_vAlignBottom->SetBitmap( KiBitmapBundle( BITMAPS::text_valign_bottom ) );
110
112
113 m_bold->SetIsCheckButton();
114 m_bold->SetBitmap( KiBitmapBundle( BITMAPS::text_bold ) );
115 m_italic->SetIsCheckButton();
116 m_italic->SetBitmap( KiBitmapBundle( BITMAPS::text_italic ) );
117
119 m_autoTextThickness->SetBitmap( KiBitmapBundle( BITMAPS::edit_cmp_symb_links ) );
120
122 Layout();
123
124 Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TABLECELL_PROPERTIES::OnCharHook ),
125 nullptr, this );
126
127 m_hAlignLeft->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onHAlignButton, this );
130 m_vAlignTop->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onVAlignButton, this );
133
134 // Now all widgets have the size fixed, call FinishDialogSettings
136}
137
139{
140 Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TABLECELL_PROPERTIES::OnCharHook ),
141 nullptr, this );
142
143 delete m_scintillaTricks;
144}
145
146
148{
149 if( !wxDialog::TransferDataToWindow() )
150 return false;
151
152 bool firstCell = true;
155 int textThickness = 0;
156 int effectivePenWidth = 0;
157
158 for( PCB_TABLECELL* cell : m_cells )
159 {
160 if( firstCell )
161 {
162 m_cellTextCtrl->SetValue( cell->GetText() );
163
164 m_fontCtrl->SetFontSelection( cell->GetFont() );
165 m_textWidth.SetValue( cell->GetTextWidth() );
166 m_textHeight.SetValue( cell->GetTextHeight() );
167 textThickness = cell->GetTextThickness();
168 effectivePenWidth = cell->GetEffectiveTextPenWidth();
169
170 hAlign = cell->GetHorizJustify();
171 vAlign = cell->GetVertJustify();
172
173 m_marginLeft.SetValue( cell->GetMarginLeft() );
174 m_marginTop.SetValue( cell->GetMarginTop() );
175 m_marginRight.SetValue( cell->GetMarginRight() );
176 m_marginBottom.SetValue( cell->GetMarginBottom() );
177
178 // wxCheckBoxState bold = cell->IsBold() ? wxCHK_CHECKED : wxCHK_UNCHECKED;
179 m_bold->Check( cell->IsBold() );
180
181 // wxCheckBoxState italic = cell->IsItalic() ? wxCHK_CHECKED : wxCHK_UNCHECKED;
182 m_italic->Check( cell->IsItalic() );
183
184 firstCell = false;
185 }
186 else
187 {
188 if( cell->GetText() != m_cellTextCtrl->GetValue() )
190
191 if( cell->GetFont() != m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) )
192 m_fontCtrl->SetSelection( -1 );
193
194 if( cell->GetTextWidth() != m_textWidth.GetValue() )
196
197 if( cell->GetTextHeight() != m_textHeight.GetValue() )
199
200 if( cell->GetTextThickness() != textThickness )
201 textThickness = -1;
202
203 if( cell->GetEffectiveTextPenWidth() != effectivePenWidth )
204 effectivePenWidth = -1;
205
206 if( cell->GetHorizJustify() != hAlign )
208
209 if( cell->GetVertJustify() != vAlign )
211
212 if( cell->GetMarginLeft() != m_marginLeft.GetIntValue() )
214
215 if( cell->GetMarginTop() != m_marginTop.GetIntValue() )
217
218 if( cell->GetMarginRight() != m_marginRight.GetIntValue() )
220
221 if( cell->GetMarginBottom() != m_marginBottom.GetIntValue() )
223 }
224
225 switch( hAlign )
226 {
231 }
232
233 switch( vAlign )
234 {
235 case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check(); break;
239 }
240 }
241
243 m_autoTextThickness->Check( false );
244
245 if( textThickness == 0 )
246 {
247 if( effectivePenWidth > 0 )
248 m_textThickness.SetValue( effectivePenWidth );
249
250 m_autoTextThickness->Check( true );
251 m_textThickness.Enable( false );
252 }
253 else if( textThickness > 0 )
254 {
255 m_textThickness.SetValue( textThickness );
256 }
257
258 return true;
259}
260
261void DIALOG_TABLECELL_PROPERTIES::onBoldToggle( wxCommandEvent& aEvent )
262{
263 int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
264
265 if( aEvent.IsChecked() )
267 else
269
270 aEvent.Skip();
271}
272
273void DIALOG_TABLECELL_PROPERTIES::onTextSize( wxCommandEvent& aEvent )
274{
276 {
277 int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
278 int thickness;
279
280 // Calculate the "best" thickness from text size and bold option:
281 if( m_bold->IsChecked() )
282 thickness = GetPenSizeForBold( textSize );
283 else
284 thickness = GetPenSizeForNormal( textSize );
285
286 m_textThickness.SetValue( thickness );
287 }
288}
289
290
292{
293 if( aEvent.IsChecked() )
294 {
295 m_autoTextThickness->Check( true );
296
298 {
299 wxCommandEvent dummy;
300 onTextSize( dummy );
301 }
302
303 m_textThickness.Enable( false );
304 }
305 else
306 {
307 m_textThickness.Enable( true );
308 }
309}
310
311
312void DIALOG_TABLECELL_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
313{
315 {
316 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
317 btn->Check( false );
318 }
319}
320
321
322void DIALOG_TABLECELL_PROPERTIES::onVAlignButton( wxCommandEvent& aEvent )
323{
325 {
326 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
327 btn->Check( false );
328 }
329}
330
331
333{
334 if( !wxDialog::TransferDataFromWindow() )
335 return false;
336
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 )
348
349 for( PCB_TABLECELL* cell : m_cells )
350 {
351 if( m_cellTextCtrl->GetValue() != INDETERMINATE_STATE )
352 {
353 wxString txt = m_cellTextCtrl->GetValue();
354
355#ifdef __WXMAC__
356 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
357 // Replace it now.
358 txt.Replace( "\r", "\n" );
359#elif defined( __WINDOWS__ )
360 // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
361 // drawing routines so strip the \r char.
362 txt.Replace( "\r", "" );
363#endif
364
365 cell->SetText( txt );
366 }
367
368 cell->SetBold( m_bold->IsChecked() );
369 cell->SetItalic( m_italic->IsChecked() );
370
372 cell->SetFont( m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) );
373
375 cell->SetTextWidth( m_textWidth.GetIntValue() );
376
378 cell->SetTextHeight( m_textHeight.GetIntValue() );
379
381 cell->SetAutoThickness( true );
382 else if( !m_textThickness.IsIndeterminate() )
383 cell->SetTextThickness( m_textThickness.GetIntValue() );
384
385 if( m_hAlignLeft->IsChecked() )
386 cell->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
387 else if( m_hAlignRight->IsChecked() )
388 cell->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
389 else if( m_hAlignCenter->IsChecked() )
390 cell->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
391
392 if( m_vAlignTop->IsChecked() )
393 cell->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
394 else if( m_vAlignBottom->IsChecked() )
395 cell->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
396 else if( m_vAlignCenter->IsChecked() )
397 cell->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
398
400 cell->SetMarginLeft( m_marginLeft.GetIntValue() );
401
403 cell->SetMarginTop( m_marginTop.GetIntValue() );
404
406 cell->SetMarginRight( m_marginRight.GetIntValue() );
407
409 cell->SetMarginBottom( m_marginBottom.GetIntValue() );
410 }
411
412 if( !commit.Empty() )
413 commit.Push( _( "Edit Table Cell Properties" ), SKIP_CONNECTIVITY );
414
416 return true;
417}
418
419
420void DIALOG_TABLECELL_PROPERTIES::onEditTable( wxCommandEvent& aEvent )
421{
423 {
425 Close();
426 }
427}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition: bitmap.cpp:110
#define SKIP_CONNECTIVITY
Definition: board_commit.h:44
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
Definition: bitmap_button.h:42
void SetIsRadioButton()
bool IsChecked() const
void Check(bool aCheck=true)
Check the control.
void SetIsSeparator()
Render button as a toolbar separator.
void SetIsCheckButton()
Setup the control as a two-state button (checked or unchecked).
void SetBitmap(const wxBitmapBundle &aBmp)
Set the bitmap shown when the button is enabled.
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:66
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)
void onBoldToggle(wxCommandEvent &aEvent) override
void onTextSize(wxCommandEvent &aEvent) override
void onAutoTextThickness(wxCommandEvent &aEvent) override
DIALOG_TABLECELL_PROPERTIES(SCH_EDIT_FRAME *aParentFrame, std::vector< SCH_TABLECELL * > aCells)
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:144
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:138
void SetFontSelection(KIFONT::FONT *aFont, bool aSilentMode=false)
Set the selection in wxChoice widget.
Definition: font_choice.cpp:73
KIFONT::FONT * GetFontSelection(bool aBold, bool aItalic, bool aForDrawingSheet=false) const
bool HaveFontSelection() const
Definition: font_choice.cpp:95
Common, abstract interface for edit frames.
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)
int GetIntValue()
Definition: unit_binder.h:129
virtual long long int GetValue()
Return the current value in Internal Units.
void Enable(bool aEnable)
Enable/disable the label, widget and units label.
bool IsIndeterminate() const
Return true if the control holds the indeterminate value (for instance, if it represents a multiple s...
virtual void ChangeValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
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.
int GetPenSizeForBold(int aTextSize)
Definition: gr_text.cpp:36
int GetPenSizeForNormal(int aTextSize)
Definition: gr_text.cpp:60
STL namespace.
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:46