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 ) ),
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 ),
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 {
78 m_scintillaTricks->DoTextVarAutocomplete(
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
95 m_hAlignLeft->SetIsRadioButton();
97 m_hAlignCenter->SetIsRadioButton();
99 m_hAlignRight->SetIsRadioButton();
101
102 m_separator0->SetIsSeparator();
103
104 m_vAlignTop->SetIsRadioButton();
106 m_vAlignCenter->SetIsRadioButton();
108 m_vAlignBottom->SetIsRadioButton();
110
111 m_separator1->SetIsSeparator();
112
113 m_bold->SetIsCheckButton();
115 m_italic->SetIsCheckButton();
117
118 m_autoTextThickness->SetIsCheckButton();
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 {
227 case GR_TEXT_H_ALIGN_LEFT: m_hAlignLeft->Check(); break;
228 case GR_TEXT_H_ALIGN_CENTER: m_hAlignCenter->Check(); break;
229 case GR_TEXT_H_ALIGN_RIGHT: m_hAlignRight->Check(); break;
231 }
232
233 switch( vAlign )
234 {
235 case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check(); break;
236 case GR_TEXT_V_ALIGN_CENTER: m_vAlignCenter->Check(); break;
237 case GR_TEXT_V_ALIGN_BOTTOM: m_vAlignBottom->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() )
266 m_textThickness.ChangeValue( GetPenSizeForBold( textSize ) );
267 else
268 m_textThickness.ChangeValue( GetPenSizeForNormal( textSize ) );
269
270 aEvent.Skip();
271}
272
273void DIALOG_TABLECELL_PROPERTIES::onTextSize( wxCommandEvent& aEvent )
274{
275 if( m_autoTextThickness->IsChecked() )
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
297 if( !m_textWidth.IsIndeterminate() && !m_textHeight.IsIndeterminate() )
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{
324 for( BITMAP_BUTTON* btn : { m_vAlignTop, m_vAlignCenter, m_vAlignBottom } )
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 )
347 m_table->SetFlags( IN_EDIT );
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
371 if( m_fontCtrl->HaveFontSelection() )
372 cell->SetFont( m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) );
373
374 if( !m_textWidth.IsIndeterminate() )
375 cell->SetTextWidth( m_textWidth.GetIntValue() );
376
377 if( !m_textHeight.IsIndeterminate() )
378 cell->SetTextHeight( m_textHeight.GetIntValue() );
379
380 if( m_autoTextThickness->IsChecked() )
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
399 if( !m_marginLeft.IsIndeterminate() )
400 cell->SetMarginLeft( m_marginLeft.GetIntValue() );
401
402 if( !m_marginTop.IsIndeterminate() )
403 cell->SetMarginTop( m_marginTop.GetIntValue() );
404
405 if( !m_marginRight.IsIndeterminate() )
406 cell->SetMarginRight( m_marginRight.GetIntValue() );
407
408 if( !m_marginBottom.IsIndeterminate() )
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
@ text_align_right
@ text_valign_top
@ text_align_left
@ text_valign_center
@ text_align_center
@ text_valign_bottom
@ edit_cmp_symb_links
#define SKIP_CONNECTIVITY
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:82
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)
void onBoldToggle(wxCommandEvent &aEvent) override
void onAutoTextThickness(wxCommandEvent &aEvent) override
DIALOG_TABLECELL_PROPERTIES(SCH_EDIT_FRAME *aParentFrame, std::vector< SCH_TABLECELL * > aCells)
Common, abstract interface for edit frames.
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 GetPenSizeForBold(int aTextSize)
Definition gr_text.cpp:37
int GetPenSizeForNormal(int aTextSize)
Definition gr_text.cpp:61
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