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 m_scintillaTricks = nullptr;
149
150 if( m_helpWindow )
151 m_helpWindow->Destroy();
152}
153
154
156{
157 if( !wxDialog::TransferDataToWindow() )
158 return false;
159
160 bool firstCell = true;
163 int textThickness = 0;
164 int effectivePenWidth = 0;
165
166 for( PCB_TABLECELL* cell : m_cells )
167 {
168 if( firstCell )
169 {
170 m_cellTextCtrl->SetValue( cell->GetText() );
171
172 m_fontCtrl->SetFontSelection( cell->GetFont() );
173 m_textWidth.SetValue( cell->GetTextWidth() );
174 m_textHeight.SetValue( cell->GetTextHeight() );
175 textThickness = cell->GetTextThickness();
176 effectivePenWidth = cell->GetEffectiveTextPenWidth();
177
178 hAlign = cell->GetHorizJustify();
179 vAlign = cell->GetVertJustify();
180
181 m_marginLeft.SetValue( cell->GetMarginLeft() );
182 m_marginTop.SetValue( cell->GetMarginTop() );
183 m_marginRight.SetValue( cell->GetMarginRight() );
184 m_marginBottom.SetValue( cell->GetMarginBottom() );
185
186 // wxCheckBoxState bold = cell->IsBold() ? wxCHK_CHECKED : wxCHK_UNCHECKED;
187 m_bold->Check( cell->IsBold() );
188
189 // wxCheckBoxState italic = cell->IsItalic() ? wxCHK_CHECKED : wxCHK_UNCHECKED;
190 m_italic->Check( cell->IsItalic() );
191
192 firstCell = false;
193 }
194 else
195 {
196 if( cell->GetText() != m_cellTextCtrl->GetValue() )
198
199 if( cell->GetFont() != m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) )
200 m_fontCtrl->SetSelection( -1 );
201
202 if( cell->GetTextWidth() != m_textWidth.GetValue() )
204
205 if( cell->GetTextHeight() != m_textHeight.GetValue() )
207
208 if( cell->GetTextThickness() != textThickness )
209 textThickness = -1;
210
211 if( cell->GetEffectiveTextPenWidth() != effectivePenWidth )
212 effectivePenWidth = -1;
213
214 if( cell->GetHorizJustify() != hAlign )
216
217 if( cell->GetVertJustify() != vAlign )
219
220 if( cell->GetMarginLeft() != m_marginLeft.GetIntValue() )
222
223 if( cell->GetMarginTop() != m_marginTop.GetIntValue() )
225
226 if( cell->GetMarginRight() != m_marginRight.GetIntValue() )
228
229 if( cell->GetMarginBottom() != m_marginBottom.GetIntValue() )
231 }
232
233 switch( hAlign )
234 {
235 case GR_TEXT_H_ALIGN_LEFT: m_hAlignLeft->Check(); break;
236 case GR_TEXT_H_ALIGN_CENTER: m_hAlignCenter->Check(); break;
237 case GR_TEXT_H_ALIGN_RIGHT: m_hAlignRight->Check(); break;
239 }
240
241 switch( vAlign )
242 {
243 case GR_TEXT_V_ALIGN_TOP: m_vAlignTop->Check(); break;
244 case GR_TEXT_V_ALIGN_CENTER: m_vAlignCenter->Check(); break;
245 case GR_TEXT_V_ALIGN_BOTTOM: m_vAlignBottom->Check(); break;
247 }
248 }
249
251 m_autoTextThickness->Check( false );
252
253 if( textThickness == 0 )
254 {
255 if( effectivePenWidth > 0 )
256 m_textThickness.SetValue( effectivePenWidth );
257
258 m_autoTextThickness->Check( true );
259 m_textThickness.Enable( false );
260 }
261 else if( textThickness > 0 )
262 {
263 m_textThickness.SetValue( textThickness );
264 }
265
266 return true;
267}
268
269void DIALOG_TABLECELL_PROPERTIES::onBoldToggle( wxCommandEvent& aEvent )
270{
271 int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
272
273 if( aEvent.IsChecked() )
274 m_textThickness.ChangeValue( GetPenSizeForBold( textSize ) );
275 else
276 m_textThickness.ChangeValue( GetPenSizeForNormal( textSize ) );
277
278 aEvent.Skip();
279}
280
281void DIALOG_TABLECELL_PROPERTIES::onTextSize( wxCommandEvent& aEvent )
282{
283 if( m_autoTextThickness->IsChecked() )
284 {
285 int textSize = std::min( m_textWidth.GetValue(), m_textHeight.GetValue() );
286 int thickness;
287
288 // Calculate the "best" thickness from text size and bold option:
289 if( m_bold->IsChecked() )
290 thickness = GetPenSizeForBold( textSize );
291 else
292 thickness = GetPenSizeForNormal( textSize );
293
294 m_textThickness.SetValue( thickness );
295 }
296}
297
298
300{
301 if( aEvent.IsChecked() )
302 {
303 m_autoTextThickness->Check( true );
304
305 if( !m_textWidth.IsIndeterminate() && !m_textHeight.IsIndeterminate() )
306 {
307 wxCommandEvent dummy;
308 onTextSize( dummy );
309 }
310
311 m_textThickness.Enable( false );
312 }
313 else
314 {
315 m_textThickness.Enable( true );
316 }
317}
318
319
320void DIALOG_TABLECELL_PROPERTIES::onHAlignButton( wxCommandEvent& aEvent )
321{
323 {
324 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
325 btn->Check( false );
326 }
327}
328
329
330void DIALOG_TABLECELL_PROPERTIES::onVAlignButton( wxCommandEvent& aEvent )
331{
332 for( BITMAP_BUTTON* btn : { m_vAlignTop, m_vAlignCenter, m_vAlignBottom } )
333 {
334 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
335 btn->Check( false );
336 }
337}
338
339
341{
342 if( !wxDialog::TransferDataFromWindow() )
343 return false;
344
345 BOARD_COMMIT commit( m_frame );
346 commit.Modify( m_table );
347
348 // If no other command in progress, prepare undo command
349 // (for a command in progress, will be made later, at the completion of command)
350 bool pushCommit = ( m_table->GetEditFlags() == 0 );
351
352 // Set IN_EDIT flag to force undo/redo/abort proper operation and avoid new calls to
353 // SaveCopyInUndoList for the same text if is moved, and then rotated, edited, etc....
354 if( !pushCommit )
355 m_table->SetFlags( IN_EDIT );
356
357 for( PCB_TABLECELL* cell : m_cells )
358 {
359 if( m_cellTextCtrl->GetValue() != INDETERMINATE_STATE )
360 {
361 wxString txt = m_cellTextCtrl->GetValue();
362
363#ifdef __WXMAC__
364 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting.
365 // Replace it now.
366 txt.Replace( "\r", "\n" );
367#elif defined( __WINDOWS__ )
368 // On Windows, a new line is coded as \r\n. We use only \n in kicad files and in
369 // drawing routines so strip the \r char.
370 txt.Replace( "\r", "" );
371#endif
372
373 cell->SetText( txt );
374 }
375
376 cell->SetBold( m_bold->IsChecked() );
377 cell->SetItalic( m_italic->IsChecked() );
378
379 if( m_fontCtrl->HaveFontSelection() )
380 cell->SetFont( m_fontCtrl->GetFontSelection( cell->IsBold(), cell->IsItalic() ) );
381
382 if( !m_textWidth.IsIndeterminate() )
383 cell->SetTextWidth( m_textWidth.GetIntValue() );
384
385 if( !m_textHeight.IsIndeterminate() )
386 cell->SetTextHeight( m_textHeight.GetIntValue() );
387
388 if( m_autoTextThickness->IsChecked() )
389 cell->SetAutoThickness( true );
390 else if( !m_textThickness.IsIndeterminate() )
391 cell->SetTextThickness( m_textThickness.GetIntValue() );
392
393 if( m_hAlignLeft->IsChecked() )
394 cell->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
395 else if( m_hAlignRight->IsChecked() )
396 cell->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
397 else if( m_hAlignCenter->IsChecked() )
398 cell->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
399
400 if( m_vAlignTop->IsChecked() )
401 cell->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
402 else if( m_vAlignBottom->IsChecked() )
403 cell->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
404 else if( m_vAlignCenter->IsChecked() )
405 cell->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
406
407 if( !m_marginLeft.IsIndeterminate() )
408 cell->SetMarginLeft( m_marginLeft.GetIntValue() );
409
410 if( !m_marginTop.IsIndeterminate() )
411 cell->SetMarginTop( m_marginTop.GetIntValue() );
412
413 if( !m_marginRight.IsIndeterminate() )
414 cell->SetMarginRight( m_marginRight.GetIntValue() );
415
416 if( !m_marginBottom.IsIndeterminate() )
417 cell->SetMarginBottom( m_marginBottom.GetIntValue() );
418 }
419
420 if( !commit.Empty() )
421 commit.Push( _( "Edit Table Cell Properties" ), SKIP_CONNECTIVITY );
422
424 return true;
425}
426
427
428void DIALOG_TABLECELL_PROPERTIES::onEditTable( wxCommandEvent& aEvent )
429{
431 {
433 Close();
434 }
435}
436
437
438void DIALOG_TABLECELL_PROPERTIES::onSyntaxHelp( wxHyperlinkEvent& aEvent )
439{
440 if( m_helpWindow )
441 {
442 m_helpWindow->Raise();
443 m_helpWindow->Show( true );
444 return;
445 }
446
448}
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