KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_label_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 (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27#include <widgets/font_choice.h>
32#include <sch_edit_frame.h>
33#include <tool/tool_manager.h>
34#include <gr_text.h>
35#include <confirm.h>
36#include <schematic.h>
39#include <string_utils.h>
40#include <kiface_base.h>
41#include <sch_label.h>
42#include <sch_commit.h>
43
44
47 m_Parent( aParent ),
48 m_currentLabel( aLabel ),
49 m_activeTextEntry( nullptr ),
50 m_netNameValidator( true ),
51 m_fields( nullptr ),
53 m_helpWindow( nullptr ),
54 m_labelList( nullptr )
55{
56 COLOR_SETTINGS* colorSettings = m_Parent->GetColorSettings();
57 COLOR4D schematicBackground = colorSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
58 bool multiLine = false;
59
60 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
61 multiLine = cfg->m_Appearance.edit_label_multiple;
62
63 m_cbMultiLine->SetValue( multiLine );
64
65 m_fields = new FIELDS_GRID_TABLE( this, aParent, m_grid, m_currentLabel );
66 m_width = 100; // Will be later set to a better value
69
70 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
71 {
72 m_activeTextEntry = m_valueCombo;
73 SetInitialFocus( m_valueCombo->GetTextCtrl() );
74
75 m_labelSingleLine->Show( false );
76 m_valueSingleLine->Show( false );
77
78 if( multiLine && aNew )
79 {
80 m_activeTextEntry = m_valueMultiLine;
81 SetInitialFocus( m_valueMultiLine );
82 m_labelCombo->Show( false );
83 m_valueCombo->Show( false );
84 }
85 else
86 {
87 m_labelMultiLine->Show( false );
88 m_valueMultiLine->Show( false );
89 m_valueCombo->SetValidator( m_netNameValidator );
90 }
91 }
92 else if( m_currentLabel->Type() == SCH_HIER_LABEL_T )
93 {
94 m_activeTextEntry = m_valueSingleLine;
95 SetInitialFocus( m_valueSingleLine );
96
97 m_labelCombo->Show( false );
98 m_valueCombo->Show( false );
99
100 if( multiLine && aNew )
101 {
102 m_activeTextEntry = m_valueMultiLine;
103 SetInitialFocus( m_valueMultiLine );
104 m_labelSingleLine->Show( false );
105 m_valueSingleLine->Show( false );
106 }
107 else
108 {
109 m_labelMultiLine->Show( false );
110 m_valueMultiLine->Show( false );
111 m_valueSingleLine->SetValidator( m_netNameValidator );
112 }
113 }
114 else if( m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
115 {
116 SetInitialFocus( m_grid );
117 m_delayedFocusRow = 0;
118
119 m_labelSingleLine->Show( false );
120 m_valueSingleLine->Show( false );
121 m_labelCombo->Show( false );
122 m_valueCombo->Show( false );
123 m_syntaxHelp->Show( false );
124 m_textEntrySizer->Show( false );
125 m_labelCombo->Show( false );
126 m_valueCombo->Show( false );
127 m_cbMultiLine->Show( false );
128
129 m_textSizeLabel->SetLabel( _( "Pin length:" ) );
130 }
131
132 if( !aNew )
133 m_cbMultiLine->Show( false );
134
135 switch( m_currentLabel->Type() )
136 {
137 case SCH_GLOBAL_LABEL_T: SetTitle( _( "Global Label Properties" ) ); break;
138 case SCH_HIER_LABEL_T: SetTitle( _( "Hierarchical Label Properties" ) ); break;
139 case SCH_LABEL_T: SetTitle( _( "Label Properties" ) ); break;
140 case SCH_DIRECTIVE_LABEL_T: SetTitle( _( "Directive Label Properties" ) ); break;
141 case SCH_SHEET_PIN_T: SetTitle( _( "Hierarchical Sheet Pin Properties" ) ); break;
142 default: UNIMPLEMENTED_FOR( m_currentLabel->GetClass() ); break;
143 }
144
145 m_grid->SetTable( m_fields );
146 m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this, {},
147 [&]( wxCommandEvent& aEvent )
148 {
149 OnAddField( aEvent );
150 } ) );
151 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
152
153 // Show/hide columns according to user's preference
154 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
155 {
156 m_grid->ShowHideColumns( cfg->m_Appearance.edit_label_visible_columns );
157 m_shownColumns = m_grid->GetShownColumns();
158 }
159
160 // Configure button logos
161 m_bpAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
162 m_bpDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
163 m_bpMoveUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
164 m_bpMoveDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
165
166 m_separator1->SetIsSeparator();
167
168 m_bold->SetIsCheckButton();
169 m_bold->SetBitmap( KiBitmapBundle( BITMAPS::text_bold ) );
170 m_italic->SetIsCheckButton();
171 m_italic->SetBitmap( KiBitmapBundle( BITMAPS::text_italic ) );
172
173 m_separator2->SetIsSeparator();
174
175 m_spin0->SetIsRadioButton();
176 m_spin1->SetIsRadioButton();
177 m_spin2->SetIsRadioButton();
178 m_spin3->SetIsRadioButton();
179
180 m_separator3->SetIsSeparator();
181
182 m_textColorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
183 m_textColorSwatch->SetSwatchBackground( schematicBackground );
184
185 // Show/hide relevant controls
186 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_HIER_LABEL_T )
187 {
188 m_dot->Hide();
189 m_circle->Hide();
190 m_diamond->Hide();
191 m_rectangle->Hide();
192
193 m_spin0->SetBitmap( KiBitmapBundle( BITMAPS::label_align_left ) );
194 m_spin1->SetBitmap( KiBitmapBundle( BITMAPS::label_align_right ) );
195 m_spin2->SetBitmap( KiBitmapBundle( BITMAPS::label_align_bottom ) );
196 m_spin3->SetBitmap( KiBitmapBundle( BITMAPS::label_align_top ) );
197 }
198 else if( m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
199 {
200 m_input->Hide();
201 m_output->Hide();
202 m_bidirectional->Hide();
203 m_triState->Hide();
204 m_passive->Hide();
205
206 m_fontLabel->SetLabel( _( "Orientation:" ) );
207 m_fontCtrl->Hide();
208 m_separator1->Hide();
209 m_bold->Hide();
210 m_italic->Hide();
211 m_separator2->Hide();
212 m_spin0->SetBitmap( KiBitmapBundle( BITMAPS::pinorient_down ) );
213 m_spin1->SetBitmap( KiBitmapBundle( BITMAPS::pinorient_up ) );
214 m_spin2->SetBitmap( KiBitmapBundle( BITMAPS::pinorient_right ) );
215 m_spin3->SetBitmap( KiBitmapBundle( BITMAPS::pinorient_left ) );
216 m_separator3->Hide();
217
218 m_formattingGB->Detach( m_fontCtrl );
219 m_formattingGB->Detach( m_iconBar );
220 m_formattingGB->Add( m_iconBar, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxEXPAND | wxRIGHT, 5 );
221 }
222 else
223 {
224 m_shapeSizer->Show( false );
225
226 m_spin0->SetBitmap( KiBitmapBundle( BITMAPS::text_align_left ) );
227 m_spin1->SetBitmap( KiBitmapBundle( BITMAPS::text_align_right ) );
228 m_spin2->SetBitmap( KiBitmapBundle( BITMAPS::text_align_bottom ) );
229 m_spin3->SetBitmap( KiBitmapBundle( BITMAPS::text_align_top ) );
230 }
231
232 if( !m_currentLabel->AutoRotateOnPlacementSupported() )
233 {
234 m_autoRotate->Hide();
235 wxSizer* parentSizer = m_autoRotate->GetContainingSizer();
236 parentSizer->Detach( m_autoRotate );
237 parentSizer->Layout();
238 }
239
240 SetupStandardButtons();
241
242 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient because the
243 // various versions have different controls so we want to store sizes for each version.
244 m_hash_key = TO_UTF8( GetTitle() );
245
246 m_spin0->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
247 m_spin1->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
248 m_spin2->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
249 m_spin3->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
250
251 // Now all widgets have the size fixed, call FinishDialogSettings
252 finishDialogSettings();
253
254 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
255 {
256 if( cfg->m_Appearance.edit_label_width > 0 && cfg->m_Appearance.edit_label_height > 0 )
257 SetSize( cfg->m_Appearance.edit_label_width, cfg->m_Appearance.edit_label_height );
258 }
259}
260
261
263{
264 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
265 {
266 cfg->m_Appearance.edit_label_visible_columns = m_grid->GetShownColumnsAsString();
267 cfg->m_Appearance.edit_label_width = GetSize().x;
268 cfg->m_Appearance.edit_label_height = GetSize().y;
269 cfg->m_Appearance.edit_label_multiple = m_cbMultiLine->IsChecked();
270 }
271
272 // Prevents crash bug in wxGrid's d'tor
273 m_grid->DestroyTable( m_fields );
274
275 // Delete the GRID_TRICKS.
276 m_grid->PopEventHandler( true );
277
278 if( m_helpWindow )
279 m_helpWindow->Destroy();
280}
281
282
284{
285 if( !wxDialog::TransferDataToWindow() )
286 return false;
287
288 wxString text;
289
291 {
292 // show control characters in a human-readable format
293 text = UnescapeString( m_currentLabel->GetText() );
294
295 // show text variable cross-references in a human-readable format
296 text = m_currentLabel->Schematic()->ConvertKIIDsToRefs( text );
297 }
298
299 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
300 {
301 // Load the combobox with the existing labels of the same type
302 std::set<wxString> existingLabels;
303 std::vector<std::shared_ptr<BUS_ALIAS>> busAliases;
304 SCH_SCREENS allScreens( m_Parent->Schematic().Root() );
305
306 for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
307 {
308 for( SCH_ITEM* item : screen->Items().OfType( m_currentLabel->Type() ) )
309 {
310 const SCH_LABEL_BASE* label = static_cast<const SCH_LABEL_BASE*>( item );
311 existingLabels.insert( UnescapeString( label->GetText() ) );
312 }
313
314 // Add global power labels from power symbols
315 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T )
316 {
317 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_LOCATE_POWER_T ) )
318 {
319 const SCH_SYMBOL* power = static_cast<const SCH_SYMBOL*>( item );
320
321 // Ensure the symbol has the Power (i.e. equivalent to a global label
322 // before adding its value in list
323 if( power->IsSymbolLikePowerGlobalLabel() )
324 {
325 const SCH_FIELD* valueField = power->GetField( FIELD_T::VALUE );
326 existingLabels.insert( UnescapeString( valueField->GetText() ) );
327 }
328 }
329 }
330
331 // Add local power labels from power symbols
332 if( m_currentLabel->Type() == SCH_LABEL_T )
333 {
334 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_LOCATE_POWER_T ) )
335 {
336 const SCH_SYMBOL* power = static_cast<const SCH_SYMBOL*>( item );
337
338 // Ensure the symbol has the Power (i.e. equivalent to a local label
339 // before adding its value in list
340 if( power->IsSymbolLikePowerLocalLabel() )
341 {
342 const SCH_FIELD* valueField = power->GetField( FIELD_T::VALUE );
343 existingLabels.insert( UnescapeString( valueField->GetText() ) );
344 }
345 }
346 }
347 // Add bus aliases from the current screen
348
349 auto& sheetAliases = screen->GetBusAliases();
350 busAliases.insert( busAliases.end(), sheetAliases.begin(), sheetAliases.end() );
351 }
352
353 // Add bus aliases to label list
354 for( const std::shared_ptr<BUS_ALIAS>& busAlias : busAliases )
355 existingLabels.insert( wxT( "{" ) + busAlias->GetName() + wxT( "}" ) );
356
357 for( const wxString& label : existingLabels )
358 m_existingLabelArray.push_back( label );
359
360 m_valueCombo->SetStringList( m_existingLabelArray );
361 m_valueCombo->SetSelectedString( text );
362 }
363 else if( m_activeTextEntry )
364 {
365 m_activeTextEntry->SetValue( text );
366 }
367
368 // Push a copy of each field into m_updateFields
369 for( SCH_FIELD& field : m_currentLabel->GetFields() )
370 {
371 SCH_FIELD field_copy( field );
372
373 // change offset to be symbol-relative
374 field_copy.Offset( -m_currentLabel->GetPosition() );
375
376 m_fields->push_back( field_copy );
377 }
378
379 // notify the grid
380 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (int) m_fields->size() );
381 m_grid->ProcessTableMessage( msg );
382 AdjustGridColumns( m_grid->GetRect().GetWidth() );
383
384 if( m_shapeSizer->AreAnyItemsShown() )
385 {
386 switch( m_currentLabel->GetShape() )
387 {
388 case LABEL_FLAG_SHAPE::L_INPUT: m_input->SetValue( true ); break;
389 case LABEL_FLAG_SHAPE::L_OUTPUT: m_output->SetValue( true ); break;
390 case LABEL_FLAG_SHAPE::L_BIDI: m_bidirectional->SetValue( true ); break;
391 case LABEL_FLAG_SHAPE::L_TRISTATE: m_triState->SetValue( true ); break;
392 case LABEL_FLAG_SHAPE::L_UNSPECIFIED: m_passive->SetValue( true ); break;
393 case LABEL_FLAG_SHAPE::F_DOT: m_dot->SetValue( true ); break;
394 case LABEL_FLAG_SHAPE::F_ROUND: m_circle->SetValue( true ); break;
395 case LABEL_FLAG_SHAPE::F_DIAMOND: m_diamond->SetValue( true ); break;
396 case LABEL_FLAG_SHAPE::F_RECTANGLE: m_rectangle->SetValue( true ); break;
397 }
398 }
399
400 m_fontCtrl->SetFontSelection( m_currentLabel->GetFont() );
401
403 m_textSize.SetValue( static_cast<SCH_DIRECTIVE_LABEL*>( m_currentLabel )->GetPinLength() );
404 else
405 m_textSize.SetValue( m_currentLabel->GetTextWidth() );
406
407 m_bold->Check( m_currentLabel->IsBold() );
408 m_italic->Check( m_currentLabel->IsItalic() );
409 m_textColorSwatch->SetSwatchColor( m_currentLabel->GetTextColor(), false );
410
411 switch( m_currentLabel->GetSpinStyle() )
412 {
413 case SPIN_STYLE::RIGHT: m_spin0->Check( true ); break;
414 case SPIN_STYLE::LEFT: m_spin1->Check( true ); break;
415 case SPIN_STYLE::UP: m_spin2->Check( true ); break;
416 case SPIN_STYLE::BOTTOM: m_spin3->Check( true ); break;
417 }
418
419 if( m_currentLabel->AutoRotateOnPlacementSupported() )
420 m_autoRotate->SetValue( m_currentLabel->AutoRotateOnPlacement() );
421
422 return true;
423}
424
425
426void DIALOG_LABEL_PROPERTIES::OnEnterKey( wxCommandEvent& aEvent )
427{
428 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
429}
430
431
433{
434 // If the key is WXK_RETURN/WXK_NUMPAD_ENTER because m_valueCombo is the source event, we do not skip
435 // the key event because the default action is to show the m_valueCombo dropdown list,
436 // and we only want to accept the entered string.
437 if(( aEvent.GetKeyCode() == WXK_RETURN ) || (aEvent.GetKeyCode() == WXK_NUMPAD_ENTER))
438 {
439 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
440 }
441 else if( aEvent.GetKeyCode() == WXK_SPACE )
442 {
443 // our FILTER_COMBOBOX uses the space as special command, not wanted here,
444 // to open the dropdown list of labels.
445 // So just add the space char to the current text, at current insertion point,
446 // and do not skip this event
447 m_activeTextEntry->WriteText( wxT(" " ) );
448 }
449 else
450 {
451 aEvent.Skip();
452 }
453}
454
455
457{
458 if( aEvent.GetKeyCode() == WXK_TAB )
459 {
460 if( aEvent.ShiftDown() )
461 {
462 m_textSizeCtrl->SetFocusFromKbd();
463 }
464 else if( !m_fields->empty() )
465 {
466 m_grid->SetFocusFromKbd();
467 m_grid->MakeCellVisible( 0, 0 );
468 m_grid->SetGridCursor( 0, 0 );
469 }
470 else
471 {
472 m_textSizeCtrl->SetFocusFromKbd();
473 }
474 }
475 else
476 {
477 aEvent.Skip();
478 }
479}
480
481
482static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
483{
484 return a.GetPosition() != b.GetPosition()
485 || a.GetHorizJustify() != b.GetHorizJustify()
486 || a.GetVertJustify() != b.GetVertJustify()
487 || a.GetTextAngle() != b.GetTextAngle();
488}
489
490
491static bool positioningChanged( FIELDS_GRID_TABLE* a, std::vector<SCH_FIELD>& b )
492{
493 for( size_t i = 0; i < a->size() && i < b.size(); ++i )
494 {
495 if( positioningChanged( a->at( i ), b.at( i ) ) )
496 return true;
497 }
498
499 return false;
500}
501
502
504{
505 if( !m_grid->CommitPendingChanges() )
506 return false;
507
508 if( !wxDialog::TransferDataFromWindow() )
509 return false;
510
511 // Don't allow text to disappear; it can be difficult to correct if you can't select it
512 if( !m_textSize.Validate( 0.01, 1000.0, EDA_UNITS::MM ) )
513 return false;
514
515 SCH_COMMIT commit( m_Parent );
516 wxString text;
517
518 /* save old text in undo list if not already in edit */
519 if( m_currentLabel->GetEditFlags() == 0 )
520 commit.Modify( m_currentLabel, m_Parent->GetScreen() );
521
522 m_Parent->GetCanvas()->Refresh();
523
525 {
526 // labels need escaping
528
529 // convert any text variable cross-references to their UUIDs
530 text = m_currentLabel->Schematic()->ConvertRefsToKIIDs( text );
531
532#ifdef __WXMAC__
533 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
534 text.Replace( wxS( "\r" ), wxS( "\n" ) );
535#endif
536
537 if( text.IsEmpty() && !m_currentLabel->IsNew() )
538 {
539 DisplayError( this, _( "Label can not be empty." ) );
540 return false;
541 }
542
543 m_currentLabel->SetText( text );
544 }
545
546 // change all field positions from relative to absolute
547 for( SCH_FIELD& field : *m_fields )
548 {
549 field.Offset( m_currentLabel->GetPosition() );
550
551 if( field.GetCanonicalName() == wxT( "Netclass" ) )
552 {
553 field.SetLayer( LAYER_NETCLASS_REFS );
554 }
555 else if( field.GetId() == FIELD_T::INTERSHEET_REFS )
556 {
557 if( field.IsVisible() != m_Parent->Schematic().Settings().m_IntersheetRefsShow )
558 {
559 DisplayInfoMessage( this, _( "Intersheet reference visibility is controlled globally from "
560 "Schematic Setup > General > Formatting" ) );
561 }
562
563 field.SetLayer( LAYER_INTERSHEET_REFS );
564 }
565 else
566 {
567 field.SetLayer( LAYER_FIELDS );
568 }
569 }
570
571 if( positioningChanged( m_fields, m_currentLabel->GetFields() ) )
572 m_currentLabel->SetFieldsAutoplaced( AUTOPLACE_NONE );
573
574 for( int ii = m_fields->GetNumberRows() - 1; ii >= 0; ii-- )
575 {
576 SCH_FIELD& field = m_fields->at( ii );
577 const wxString& fieldName = field.GetCanonicalName();
578 const wxString& fieldText = field.GetText();
579
580 if( fieldName.IsEmpty() && fieldText.IsEmpty() )
581 {
582 // delete empty, unnamed fields
583 m_fields->erase( m_fields->begin() + ii );
584 }
585 else if( fieldName == wxT( "Netclass" ) && fieldText.IsEmpty() )
586 {
587 // delete empty Netclass fields if there are other Netclass fields present
588 int netclassFieldCount = 0;
589
590 for( int jj = 0; jj < m_fields->GetNumberRows(); ++jj )
591 {
592 if( m_fields->at( jj ).GetCanonicalName() == wxT( "Netclass" ) )
593 netclassFieldCount++;
594 }
595
596 if( netclassFieldCount > 1 )
597 m_fields->erase( m_fields->begin() + ii );
598 }
599 else if( fieldName.IsEmpty() )
600 {
601 // give non-empty, unnamed fields a name
602 field.SetName( _( "untitled" ) );
603 }
604 }
605
606 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T ids.
607
608 for( SCH_FIELD& field : *m_fields )
609 {
610 if( !field.IsMandatory() )
611 field.SetOrdinal( ordinal++ );
612 }
613
614 m_currentLabel->SetFields( *m_fields );
615
616 if( m_shapeSizer->AreAnyItemsShown() )
617 {
618 if( m_bidirectional->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
619 else if( m_input->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
620 else if( m_output->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
621 else if( m_triState->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_TRISTATE );
622 else if( m_passive->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
623 else if( m_dot->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_DOT );
624 else if( m_circle->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_ROUND );
625 else if( m_diamond->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_DIAMOND );
626 else if( m_rectangle->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_RECTANGLE );
627 }
628
629 if( m_fontCtrl->HaveFontSelection() )
630 m_currentLabel->SetFont( m_fontCtrl->GetFontSelection( m_bold->IsChecked(), m_italic->IsChecked() ) );
631
633 static_cast<SCH_DIRECTIVE_LABEL*>( m_currentLabel )->SetPinLength( m_textSize.GetIntValue() );
634 else if( m_currentLabel->GetTextWidth() != m_textSize.GetIntValue() )
635 m_currentLabel->SetTextSize( VECTOR2I( m_textSize.GetIntValue(), m_textSize.GetIntValue() ) );
636
637 // Must come after SetTextSize()
638 m_currentLabel->SetBold( m_bold->IsChecked() );
639 m_currentLabel->SetItalic( m_italic->IsChecked() );
640
641 m_currentLabel->SetTextColor( m_textColorSwatch->GetSwatchColor() );
642
643 SPIN_STYLE selectedSpinStyle= SPIN_STYLE::LEFT;
644
645 if( m_spin0->IsChecked() ) selectedSpinStyle = SPIN_STYLE::RIGHT;
646 else if( m_spin1->IsChecked() ) selectedSpinStyle = SPIN_STYLE::LEFT;
647 else if( m_spin2->IsChecked() ) selectedSpinStyle = SPIN_STYLE::UP;
648 else if( m_spin3->IsChecked() ) selectedSpinStyle = SPIN_STYLE::BOTTOM;
649
650 if( m_currentLabel->AutoRotateOnPlacementSupported() )
651 {
652 SCH_EDIT_FRAME* frame = static_cast<SCH_EDIT_FRAME*>( m_parentFrame );
653 m_currentLabel->SetAutoRotateOnPlacement( m_autoRotate->IsChecked() );
654 frame->AutoRotateItem( frame->GetScreen(), m_currentLabel );
655 }
656 else
657 {
658 m_currentLabel->SetAutoRotateOnPlacement( false );
659 }
660
661 if( !m_currentLabel->AutoRotateOnPlacement() && m_currentLabel->GetSpinStyle() != selectedSpinStyle )
662 m_currentLabel->SetSpinStyle( selectedSpinStyle );
663
664 AUTOPLACE_ALGO fieldsAutoplaced = m_currentLabel->GetFieldsAutoplaced();
665
666 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
667 m_currentLabel->AutoplaceFields( m_Parent->GetScreen(), fieldsAutoplaced );
668
669 if( !commit.Empty() )
670 {
671 commit.Push( _( "Edit Label Properties" ) );
672 }
673 else if( m_activeTextEntry && m_labelList )
674 {
675 text = m_activeTextEntry->GetValue();
676 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
677 text.Replace( wxS( "\r" ), wxS( "\n" ) );
678 wxArrayString lines = wxSplit( text, '\n' );
679
680 for( const wxString& line : lines )
681 {
682 text = EscapeString( line, CTX_NETNAME );
683 text.Trim( false ).Trim( true );
684
685 if( text.empty() )
686 continue;
687
688 // convert any text variable cross-references to their UUIDs
689 text = m_currentLabel->Schematic()->ConvertRefsToKIIDs( text );
690
691 switch ( m_currentLabel->Type() )
692 {
694 {
695 SCH_GLOBALLABEL* label = new SCH_GLOBALLABEL( *static_cast<SCH_GLOBALLABEL*>( m_currentLabel ) );
696 label->SetText( text );
697 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
698 break;
699 }
700 case SCH_HIER_LABEL_T:
701 {
702 SCH_HIERLABEL* label = new SCH_HIERLABEL( *static_cast<SCH_HIERLABEL*>( m_currentLabel ) );
703 label->SetText( text );
704 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
705 break;
706 }
707 case SCH_LABEL_T:
708 {
709 SCH_LABEL* label = new SCH_LABEL( *static_cast<SCH_LABEL*>( m_currentLabel ) );
710 label->SetText( text );
711 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
712 break;
713 }
714 default:
715 break;
716 }
717 }
718 }
719 else if( m_labelList && m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
720 {
722 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
723 }
724
725 return true;
726}
727
728
729void DIALOG_LABEL_PROPERTIES::onSpinButton( wxCommandEvent& aEvent )
730{
731 for( BITMAP_BUTTON* btn : { m_spin0, m_spin1, m_spin2, m_spin3 } )
732 {
733 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
734 btn->Check( false );
735 }
736}
737
738
739void DIALOG_LABEL_PROPERTIES::OnFormattingHelp( wxHyperlinkEvent& aEvent )
740{
742}
743
744
745void DIALOG_LABEL_PROPERTIES::OnAddField( wxCommandEvent& event )
746{
747 m_grid->OnAddRow(
748 [&]() -> std::pair<int, int>
749 {
750 wxString fieldName = wxT( "Netclass" );
751
752 for( SCH_FIELD& field : *m_fields )
753 {
754 if( field.GetId() != FIELD_T::INTERSHEET_REFS && field.GetName() != wxT( "Netclass" ) )
755 {
756 fieldName = wxEmptyString;
757 break;
758 }
759 }
760
761 fieldName = SCH_LABEL_BASE::GetDefaultFieldName( fieldName, true );
762
763 SCH_FIELD newField( m_currentLabel, FIELD_T::USER, fieldName );
764
765 if( m_fields->size() > 0 )
766 {
767 // SetAttributes() also covers text angle, size, italic and bold
768 newField.SetAttributes( m_fields->at( m_fields->size() - 1 ) );
769 newField.SetVisible( m_fields->at( m_fields->size() - 1 ).IsVisible() );
770 }
771 else
772 {
773 newField.SetVisible( true );
774 newField.SetItalic( true );
775 }
776
777 m_fields->push_back( newField );
778
779 // notify the grid
780 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
781 m_grid->ProcessTableMessage( msg );
782 return { m_fields->size() - 1, FDC_NAME };
783 } );
784}
785
786
787void DIALOG_LABEL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
788{
789 m_grid->OnDeleteRows(
790 [&]( int row )
791 {
792 if( row < m_currentLabel->GetMandatoryFieldCount() )
793 {
794 DisplayError( this, _( "The first field is mandatory." ) );
795 return false;
796 }
797
798 return true;
799 },
800 [&]( int row )
801 {
802 m_fields->erase( m_fields->begin() + row );
803
804 // notify the grid
805 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
806 m_grid->ProcessTableMessage( msg );
807 } );
808}
809
810
811void DIALOG_LABEL_PROPERTIES::OnMoveUp( wxCommandEvent& event )
812{
813 m_grid->OnMoveRowUp(
814 [&]( int row )
815 {
816 return row > m_currentLabel->GetMandatoryFieldCount();
817 },
818 [&]( int row )
819 {
820 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row - 1 ) );
821 m_grid->ForceRefresh();
822 } );
823}
824
825
826void DIALOG_LABEL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
827{
828 m_grid->OnMoveRowUp(
829 [&]( int row )
830 {
831 return row >= m_currentLabel->GetMandatoryFieldCount();
832 },
833 [&]( int row )
834 {
835 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row + 1 ) );
836 m_grid->ForceRefresh();
837 } );
838}
839
840
842{
843 m_width = aWidth;
844 // Account for scroll bars
845 aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
846
847 m_grid->AutoSizeColumn( 0 );
848 m_grid->SetColSize( 0, std::max( 72, m_grid->GetColSize( 0 ) ) );
849
850 int fixedColsWidth = m_grid->GetColSize( 0 );
851
852 for( int i = 2; i < m_grid->GetNumberCols(); i++ )
853 fixedColsWidth += m_grid->GetColSize( i );
854
855 m_grid->SetColSize( 1, std::max( 120, aWidth - fixedColsWidth ) );
856}
857
858
859void DIALOG_LABEL_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
860{
861 std::bitset<64> shownColumns = m_grid->GetShownColumns();
862
863 if( shownColumns != m_shownColumns )
864 {
865 m_shownColumns = shownColumns;
866
867 if( !m_grid->IsCellEditControlShown() )
868 AdjustGridColumns( m_grid->GetRect().GetWidth() );
869 }
870
871 // Handle a delayed focus
872 if( m_delayedFocusRow >= 0 && m_delayedFocusRow < m_grid->GetNumberRows() )
873 {
874 m_grid->SetFocus();
875 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
877 }
878
881}
882
883
884void DIALOG_LABEL_PROPERTIES::OnSizeGrid( wxSizeEvent& event )
885{
886 int new_size = event.GetSize().GetX();
887
888 if( m_width != new_size )
889 AdjustGridColumns( new_size );
890
891 // Always propagate for a grid repaint (needed if the height changes, as well as width)
892 event.Skip();
893}
894
895
897{
898 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
899 {
900 m_labelCombo->Show( !m_cbMultiLine->IsChecked() );
901 m_valueCombo->Show( !m_cbMultiLine->IsChecked() );
902 m_labelMultiLine->Show( m_cbMultiLine->IsChecked() );
903 m_valueMultiLine->Show( m_cbMultiLine->IsChecked() );
904
905 if( m_cbMultiLine->IsChecked() )
906 {
907 m_valueMultiLine->SetValue( m_valueCombo->GetValue() );
910 }
911 else
912 {
913 wxString multiText = m_valueMultiLine->GetValue();
914 m_valueCombo->SetValue( multiText.BeforeFirst( '\n' ) );
917 }
918 }
919 else if( m_currentLabel->Type() == SCH_HIER_LABEL_T )
920 {
921 m_labelSingleLine->Show( !m_cbMultiLine->IsChecked() );
922 m_valueSingleLine->Show( !m_cbMultiLine->IsChecked() );
923 m_labelMultiLine->Show( m_cbMultiLine->IsChecked() );
924 m_valueMultiLine->Show( m_cbMultiLine->IsChecked() );
925
926 if( m_cbMultiLine->IsChecked() )
927 {
928 m_valueMultiLine->SetValue( m_valueSingleLine->GetValue() );
931 }
932 else
933 {
934 wxString multiText = m_valueMultiLine->GetValue();
935 m_valueSingleLine->SetValue( multiText.BeforeFirst( '\n' ) );
938 }
939 }
940
941 Layout();
942}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
A bitmap button widget that behaves like an AUI toolbar item's button when it is drawn.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:398
Color settings are a bit different than most of the settings objects in that there can be more than o...
COLOR4D GetColor(int aLayer) const
bool Empty() const
Definition commit.h:137
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
DIALOG_LABEL_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Label Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
std::list< std::unique_ptr< SCH_LABEL_BASE > > * m_labelList
void OnSizeGrid(wxSizeEvent &event) override
void OnMoveUp(wxCommandEvent &event) override
void OnMoveDown(wxCommandEvent &event) override
DIALOG_LABEL_PROPERTIES(SCH_EDIT_FRAME *parent, SCH_LABEL_BASE *aLabel, bool aNew)
void OnEnterKey(wxCommandEvent &aEvent) override
wxEVT_COMMAND_ENTER event handler for single-line control.
void OnAddField(wxCommandEvent &event) override
SCH_NETNAME_VALIDATOR m_netNameValidator
void OnFormattingHelp(wxHyperlinkEvent &aEvent) override
void OnCBValueCharHook(wxKeyEvent &aEvent) override
void OnUpdateUI(wxUpdateUIEvent &event) override
void onSpinButton(wxCommandEvent &aEvent)
void onMultiLabelCheck(wxCommandEvent &aEvent) override
void OnDeleteField(wxCommandEvent &event) override
void OnValueCharHook(wxKeyEvent &aEvent) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:82
EDA_BASE_FRAME * m_parentFrame
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:146
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:434
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:597
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:199
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:387
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:202
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:271
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:308
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Schematic editor (Eeschema) main window.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void AutoRotateItem(SCH_SCREEN *aScreen, SCH_ITEM *aItem)
Automatically set the rotation of an item (if the item supports it).
VECTOR2I GetPosition() const override
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
void SetName(const wxString &aName)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
static const wxString GetDefaultFieldName(const wxString &aName, bool aUseDefaultName)
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:758
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
Schematic symbol object.
Definition sch_symbol.h:75
bool IsSymbolLikePowerGlobalLabel() const
bool IsSymbolLikePowerLocalLabel() const
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
static HTML_MESSAGE_BOX * ShowSyntaxHelp(wxWindow *aParentWindow)
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:222
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:169
This file is part of the common library.
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
#define _(s)
@ FDC_NAME
@ FDC_VALUE
@ LAYER_FIELDS
Definition layer_ids.h:461
@ LAYER_NETCLASS_REFS
Definition layer_ids.h:463
@ LAYER_SCHEMATIC_BACKGROUND
Definition layer_ids.h:487
@ LAYER_INTERSHEET_REFS
Definition layer_ids.h:462
AUTOPLACE_ALGO
Definition sch_item.h:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_NONE
Definition sch_item.h:69
@ AUTOPLACE_AUTO
Definition sch_item.h:70
@ L_BIDI
Definition sch_label.h:102
@ L_TRISTATE
Definition sch_label.h:103
@ L_UNSPECIFIED
Definition sch_label.h:104
@ F_DOT
Definition sch_label.h:107
@ F_ROUND
Definition sch_label.h:108
@ L_OUTPUT
Definition sch_label.h:101
@ F_DIAMOND
Definition sch_label.h:109
@ L_INPUT
Definition sch_label.h:100
@ F_RECTANGLE
Definition sch_label.h:110
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ CTX_NETNAME
@ USER
The field ID hasn't been set yet; field is invalid.
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ VALUE
Field Value of part, i.e. "3.3K".
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:173
@ SCH_LABEL_T
Definition typeinfo.h:169
@ SCH_HIER_LABEL_T
Definition typeinfo.h:171
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:198
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:170
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695