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
24#include <wx/hyperlink.h>
25
27#include <widgets/font_choice.h>
29#include <confirm.h>
30#include <board_commit.h>
32#include <board.h>
33#include <footprint.h>
34#include <pcb_textbox.h>
35#include <pcb_tablecell.h>
36#include <pcb_table.h>
37#include <project.h>
38#include <pcb_edit_frame.h>
40#include <tool/tool_manager.h>
41#include <tools/pcb_actions.h>
42#include <scintilla_tricks.h>
44
46 std::vector<PCB_TABLECELL*> aCells ) :
48 m_frame( aFrame ),
49 m_table( nullptr ),
50 m_cells( std::move( aCells ) ),
54 m_marginLeft( aFrame, nullptr, m_marginLeftCtrl, nullptr ),
55 m_marginTop( aFrame, nullptr, m_marginTopCtrl, m_marginTopUnits ),
56 m_marginRight( aFrame, nullptr, m_marginRightCtrl, nullptr ),
57 m_marginBottom( aFrame, nullptr, m_marginBottomCtrl, nullptr ),
60{
61 wxASSERT( m_cells.size() > 0 && m_cells[0] );
62
63 m_cellText->SetEOLMode( wxSTC_EOL_LF );
64
65#ifdef _WIN32
66 // Without this setting, on Windows, some esoteric unicode chars create display issue
67 // in a wxStyledTextCtrl.
68 // for SetTechnology() info, see https://www.scintilla.org/ScintillaDoc.html#SCI_SETTECHNOLOGY
69 m_cellText->SetTechnology( wxSTC_TECHNOLOGY_DIRECTWRITE );
70#endif
71
73 m_cellText, wxT( "{}" ), false,
74 // onAcceptFn
75 [this]( wxKeyEvent& aEvent )
76 {
77 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
78 },
79 // onCharFn
80 [this]( wxStyledTextEvent& aEvent )
81 {
82 m_scintillaTricks->DoTextVarAutocomplete(
83 // getTokensFn
84 [this]( const wxString& xRef, wxArrayString* tokens )
85 {
86 m_frame->GetContextualTextVars( m_table, xRef, tokens );
87 } );
88 } );
89
90 // A hack which causes Scintilla to auto-size the text editor canvas
91 // See: https://github.com/jacobslusser/ScintillaNET/issues/216
92 m_cellText->SetScrollWidth( 1 );
93 m_cellText->SetScrollWidthTracking( true );
94
96
97 m_table = static_cast<PCB_TABLE*>( m_cells[0]->GetParent() );
98
99 m_hAlignLeft->SetIsRadioButton();
101 m_hAlignCenter->SetIsRadioButton();
103 m_hAlignRight->SetIsRadioButton();
105
106 m_separator0->SetIsSeparator();
107
108 m_vAlignTop->SetIsRadioButton();
110 m_vAlignCenter->SetIsRadioButton();
112 m_vAlignBottom->SetIsRadioButton();
114
115 m_separator1->SetIsSeparator();
116
117 m_bold->SetIsCheckButton();
119 m_italic->SetIsCheckButton();
121
122 m_autoTextThickness->SetIsCheckButton();
124
126 Layout();
127
128 m_helpWindow = nullptr;
129
130 Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TABLECELL_PROPERTIES::OnCharHook ), nullptr, this );
131
132 m_hAlignLeft->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onHAlignButton, this );
135 m_vAlignTop->Bind( wxEVT_BUTTON, &DIALOG_TABLECELL_PROPERTIES::onVAlignButton, this );
138
139 // Now all widgets have the size fixed, call FinishDialogSettings
141}
142
144{
145 Disconnect( wxEVT_CHAR_HOOK, wxKeyEventHandler( DIALOG_TABLECELL_PROPERTIES::OnCharHook ), nullptr, this );
146
147 delete m_scintillaTricks;
148
149 if( m_helpWindow )
150 m_helpWindow->Destroy();
151}
152
153
155{
156 if( !wxDialog::TransferDataToWindow() )
157 return false;
158
159 bool firstCell = true;
162 int textThickness = 0;
163 int effectivePenWidth = 0;
164
165 for( PCB_TABLECELL* cell : m_cells )
166 {
167 if( firstCell )
168 {
169 m_cellTextCtrl->SetValue( cell->GetText() );
170
171 m_fontCtrl->SetFontSelection( cell->GetFont() );
172 m_textWidth.SetValue( cell->GetTextWidth() );
173 m_textHeight.SetValue( cell->GetTextHeight() );
174 textThickness = cell->GetTextThickness();
175 effectivePenWidth = cell->GetEffectiveTextPenWidth();
176
177 hAlign = cell->GetHorizJustify();
178 vAlign = cell->GetVertJustify();
179
180 m_marginLeft.SetValue( cell->GetMarginLeft() );
181 m_marginTop.SetValue( cell->GetMarginTop() );
182 m_marginRight.SetValue( cell->GetMarginRight() );
183 m_marginBottom.SetValue( cell->GetMarginBottom() );
184
185 // wxCheckBoxState bold = cell->IsBold() ? wxCHK_CHECKED : wxCHK_UNCHECKED;
186 m_bold->Check( cell->IsBold() );
187
188 // wxCheckBoxState italic = cell->IsItalic() ? wxCHK_CHECKED : wxCHK_UNCHECKED;
189 m_italic->Check( cell->IsItalic() );
190
191 firstCell = false;
192 }
193 else
194 {
195 if( cell->GetText() != m_cellTextCtrl->GetValue() )
197
198 if( cell->GetFont() != m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) )
199 m_fontCtrl->SetSelection( -1 );
200
201 if( cell->GetTextWidth() != m_textWidth.GetValue() )
203
204 if( cell->GetTextHeight() != m_textHeight.GetValue() )
206
207 if( cell->GetTextThickness() != textThickness )
208 textThickness = -1;
209
210 if( cell->GetEffectiveTextPenWidth() != effectivePenWidth )
211 effectivePenWidth = -1;
212
213 if( cell->GetHorizJustify() != hAlign )
215
216 if( cell->GetVertJustify() != vAlign )
218
219 if( cell->GetMarginLeft() != m_marginLeft.GetIntValue() )
221
222 if( cell->GetMarginTop() != m_marginTop.GetIntValue() )
224
225 if( cell->GetMarginRight() != m_marginRight.GetIntValue() )
227
228 if( cell->GetMarginBottom() != m_marginBottom.GetIntValue() )
230 }
231
232 switch( hAlign )
233 {
234 case GR_TEXT_H_ALIGN_LEFT: m_hAlignLeft->Check(); break;
235 case GR_TEXT_H_ALIGN_CENTER: m_hAlignCenter->Check(); break;
236 case GR_TEXT_H_ALIGN_RIGHT: m_hAlignRight->Check(); break;
238 }
239
240 switch( vAlign )
241 {
242 case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check(); break;
243 case GR_TEXT_V_ALIGN_CENTER: m_vAlignCenter->Check(); break;
244 case GR_TEXT_V_ALIGN_BOTTOM: m_vAlignBottom->Check(); break;
246 }
247 }
248
250 m_autoTextThickness->Check( false );
251
252 if( textThickness == 0 )
253 {
254 if( effectivePenWidth > 0 )
255 m_textThickness.SetValue( effectivePenWidth );
256
257 m_autoTextThickness->Check( true );
258 m_textThickness.Enable( false );
259 }
260 else if( textThickness > 0 )
261 {
262 m_textThickness.SetValue( textThickness );
263 }
264
265 return true;
266}
267
268void DIALOG_TABLECELL_PROPERTIES::onBoldToggle( wxCommandEvent& aEvent )
269{
270 int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
271
272 if( aEvent.IsChecked() )
273 m_textThickness.ChangeValue( GetPenSizeForBold( textSize ) );
274 else
275 m_textThickness.ChangeValue( GetPenSizeForNormal( textSize ) );
276
277 aEvent.Skip();
278}
279
280void DIALOG_TABLECELL_PROPERTIES::onTextSize( wxCommandEvent& aEvent )
281{
282 if( m_autoTextThickness->IsChecked() )
283 {
284 int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
285 int thickness;
286
287 // Calculate the "best" thickness from text size and bold option:
288 if( m_bold->IsChecked() )
289 thickness = GetPenSizeForBold( textSize );
290 else
291 thickness = GetPenSizeForNormal( textSize );
292
293 m_textThickness.SetValue( thickness );
294 }
295}
296
297
299{
300 if( aEvent.IsChecked() )
301 {
302 m_autoTextThickness->Check( true );
303
304 if( !m_textWidth.IsIndeterminate() && !m_textHeight.IsIndeterminate() )
305 {
306 wxCommandEvent dummy;
307 onTextSize( dummy );
308 }
309
310 m_textThickness.Enable( false );
311 }
312 else
313 {
314 m_textThickness.Enable( true );
315 }
316}
317
318
319void DIALOG_TABLECELL_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
320{
322 {
323 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
324 btn->Check( false );
325 }
326}
327
328
329void DIALOG_TABLECELL_PROPERTIES::onVAlignButton( wxCommandEvent& aEvent )
330{
331 for( BITMAP_BUTTON* btn : { m_vAlignTop, m_vAlignCenter, m_vAlignBottom } )
332 {
333 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
334 btn->Check( false );
335 }
336}
337
338
340{
341 if( !wxDialog::TransferDataFromWindow() )
342 return false;
343
344 BOARD_COMMIT commit( m_frame );
345 commit.Modify( m_table );
346
347 // If no other command in progress, prepare undo command
348 // (for a command in progress, will be made later, at the completion of command)
349 bool pushCommit = ( m_table->GetEditFlags() == 0 );
350
351 // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
352 // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
353 if( !pushCommit )
354 m_table->SetFlags( IN_EDIT );
355
356 for( PCB_TABLECELL* cell : m_cells )
357 {
358 if( m_cellTextCtrl->GetValue() != INDETERMINATE_STATE )
359 {
360 wxString txt = m_cellTextCtrl->GetValue();
361
362#ifdef __WXMAC__
363 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
364 // Replace it now.
365 txt.Replace( "\r", "\n" );
366#elif defined( __WINDOWS__ )
367 // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
368 // drawing routines so strip the \r char.
369 txt.Replace( "\r", "" );
370#endif
371
372 cell->SetText( txt );
373 }
374
375 cell->SetBold( m_bold->IsChecked() );
376 cell->SetItalic( m_italic->IsChecked() );
377
378 if( m_fontCtrl->HaveFontSelection() )
379 cell->SetFont( m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) );
380
381 if( !m_textWidth.IsIndeterminate() )
382 cell->SetTextWidth( m_textWidth.GetIntValue() );
383
384 if( !m_textHeight.IsIndeterminate() )
385 cell->SetTextHeight( m_textHeight.GetIntValue() );
386
387 if( m_autoTextThickness->IsChecked() )
388 cell->SetAutoThickness( true );
389 else if( !m_textThickness.IsIndeterminate() )
390 cell->SetTextThickness( m_textThickness.GetIntValue() );
391
392 if( m_hAlignLeft->IsChecked() )
393 cell->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
394 else if( m_hAlignRight->IsChecked() )
395 cell->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
396 else if( m_hAlignCenter->IsChecked() )
397 cell->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
398
399 if( m_vAlignTop->IsChecked() )
400 cell->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
401 else if( m_vAlignBottom->IsChecked() )
402 cell->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
403 else if( m_vAlignCenter->IsChecked() )
404 cell->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
405
406 if( !m_marginLeft.IsIndeterminate() )
407 cell->SetMarginLeft( m_marginLeft.GetIntValue() );
408
409 if( !m_marginTop.IsIndeterminate() )
410 cell->SetMarginTop( m_marginTop.GetIntValue() );
411
412 if( !m_marginRight.IsIndeterminate() )
413 cell->SetMarginRight( m_marginRight.GetIntValue() );
414
415 if( !m_marginBottom.IsIndeterminate() )
416 cell->SetMarginBottom( m_marginBottom.GetIntValue() );
417 }
418
419 if( !commit.Empty() )
420 commit.Push( _( "Edit Table Cell Properties" ), SKIP_CONNECTIVITY );
421
423 return true;
424}
425
426
427void DIALOG_TABLECELL_PROPERTIES::onEditTable( wxCommandEvent& aEvent )
428{
430 {
432 Close();
433 }
434}
435
436
437void DIALOG_TABLECELL_PROPERTIES::onSyntaxHelp( wxHyperlinkEvent& aEvent )
438{
439 if( m_helpWindow )
440 {
441 m_helpWindow->Raise();
442 m_helpWindow->Show( true );
443 return;
444 }
445
447}
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)
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:670
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