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, see <https://www.gnu.org/licenses/>.
20 */
21
23#include <widgets/font_choice.h>
28#include <sch_edit_frame.h>
29#include <tool/tool_manager.h>
30#include <gr_text.h>
31#include <confirm.h>
32#include <schematic.h>
35#include <string_utils.h>
36#include <kiface_base.h>
37#include <sch_label.h>
38#include <sch_commit.h>
39
40
43 m_Parent( aParent ),
44 m_currentLabel( aLabel ),
45 m_activeTextEntry( nullptr ),
46 m_netNameValidator( true ),
47 m_fields( nullptr ),
49 m_helpWindow( nullptr ),
50 m_labelList( nullptr )
51{
52 COLOR_SETTINGS* colorSettings = m_Parent->GetColorSettings();
53 COLOR4D schematicBackground = colorSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
54
55 m_fields = new FIELDS_GRID_TABLE( this, aParent, m_grid, m_currentLabel );
58
59 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
60 {
62 SetInitialFocus( m_valueCombo->GetTextCtrl() );
63
64 m_labelSingleLine->Show( false );
65 m_valueSingleLine->Show( false );
66 }
67 else if( m_currentLabel->Type() == SCH_HIER_LABEL_T )
68 {
71
72 m_labelCombo->Show( false );
73 m_valueCombo->Show( false );
74 }
75 else if( m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
76 {
79
80 m_labelSingleLine->Show( false );
81 m_valueSingleLine->Show( false );
82 m_labelCombo->Show( false );
83 m_valueCombo->Show( false );
84 m_syntaxHelp->Show( false );
85 m_textEntrySizer->Show( false );
86 m_labelCombo->Show( false );
87 m_valueCombo->Show( false );
88 m_cbMultiLine->Show( false );
89
90 m_textSizeLabel->SetLabel( _( "Pin length:" ) );
91 }
92
93 if( !aNew )
94 m_cbMultiLine->Show( false );
95
96 // multiline set of labels can be used only to create new labels
97 m_multilineAllowed = aNew && m_cbMultiLine->IsShown();
98
99 switch( m_currentLabel->Type() )
100 {
101 case SCH_GLOBAL_LABEL_T: SetTitle( _( "Global Label Properties" ) ); break;
102 case SCH_HIER_LABEL_T: SetTitle( _( "Hierarchical Label Properties" ) ); break;
103 case SCH_LABEL_T: SetTitle( _( "Label Properties" ) ); break;
104 case SCH_DIRECTIVE_LABEL_T: SetTitle( _( "Directive Label Properties" ) ); break;
105 case SCH_SHEET_PIN_T: SetTitle( _( "Hierarchical Sheet Pin Properties" ) ); break;
106 default: UNIMPLEMENTED_FOR( m_currentLabel->GetClass() ); break;
107 }
108
109 m_grid->SetTable( m_fields );
110 m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this, {},
111 [&]( wxCommandEvent& aEvent )
112 {
113 OnAddField( aEvent );
114 } ) );
115 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
116 m_grid->ShowHideColumns( "0 1 2 3 4 5 6 7" );
117 m_shownColumns = m_grid->GetShownColumns();
118
119 // Configure button logos
124
125 m_separator1->SetIsSeparator();
126
127 m_bold->SetIsCheckButton();
129 m_italic->SetIsCheckButton();
131
132 m_separator2->SetIsSeparator();
133
134 m_spin0->SetIsRadioButton();
135 m_spin1->SetIsRadioButton();
136 m_spin2->SetIsRadioButton();
137 m_spin3->SetIsRadioButton();
138
139 m_separator3->SetIsSeparator();
140
141 m_textColorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
142 m_textColorSwatch->SetSwatchBackground( schematicBackground );
143
144 // Show/hide relevant controls
146 {
147 m_dot->Hide();
148 m_circle->Hide();
149 m_diamond->Hide();
150 m_rectangle->Hide();
151
156 }
157 else if( m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
158 {
159 m_input->Hide();
160 m_output->Hide();
161 m_bidirectional->Hide();
162 m_triState->Hide();
163 m_passive->Hide();
164
165 m_fontLabel->SetLabel( _( "Orientation:" ) );
166 m_fontCtrl->Hide();
167 m_separator1->Hide();
168 m_bold->Hide();
169 m_italic->Hide();
170 m_separator2->Hide();
175 m_separator3->Hide();
176
177 m_formattingGB->Detach( m_fontCtrl );
178 m_formattingGB->Detach( m_iconBar );
179 m_formattingGB->Add( m_iconBar, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxEXPAND | wxRIGHT, 5 );
180 }
181 else
182 {
183 m_shapeSizer->Show( false );
184
189 }
190
191 if( !m_currentLabel->AutoRotateOnPlacementSupported() )
192 {
193 m_autoRotate->Hide();
194 wxSizer* parentSizer = m_autoRotate->GetContainingSizer();
195 parentSizer->Detach( m_autoRotate );
196 parentSizer->Layout();
197 }
198
200
201 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient because the
202 // various versions have different controls so we want to store sizes for each version.
203 m_hash_key = TO_UTF8( GetTitle() );
204
205 m_spin0->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
206 m_spin1->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
207 m_spin2->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
208 m_spin3->Bind( wxEVT_BUTTON, &DIALOG_LABEL_PROPERTIES::onSpinButton, this );
209
210 // wxFormBuilder doesn't include this event...
211 m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
212 wxGridEventHandler( DIALOG_LABEL_PROPERTIES::OnGridCellChanging ), nullptr,
213 this );
214
215 // Now all widgets have the size fixed, call FinishDialogSettings
217}
218
219
221{
222 // Prevents crash bug in wxGrid's d'tor
223 m_grid->DestroyTable( m_fields );
224
225 m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
226 wxGridEventHandler( DIALOG_LABEL_PROPERTIES::OnGridCellChanging ), nullptr,
227 this );
228
229 // Delete the GRID_TRICKS.
230 m_grid->PopEventHandler( true );
231
232 if( m_helpWindow )
233 m_helpWindow->Destroy();
234}
235
236
238{
239 if( !wxDialog::TransferDataToWindow() )
240 return false;
241
242 // Respond to previously-saved state of multilable checkbox
243 wxCommandEvent dummy;
245
246 wxString text;
247
249 {
250 // show control characters in a human-readable format
251 text = UnescapeString( m_currentLabel->GetText() );
252
253 // show text variable cross-references in a human-readable format
254 text = m_currentLabel->Schematic()->ConvertKIIDsToRefs( text );
255 }
256
257 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
258 {
259 // Load the combobox with the existing labels of the same type
260 std::set<wxString> existingLabels;
261 SCH_SCREENS allScreens( m_Parent->Schematic().Root() );
262
263 for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
264 {
265 for( SCH_ITEM* item : screen->Items().OfType( m_currentLabel->Type() ) )
266 {
267 const SCH_LABEL_BASE* label = static_cast<const SCH_LABEL_BASE*>( item );
268 existingLabels.insert( UnescapeString( label->GetText() ) );
269 }
270
271 // Add global power labels from power symbols
272 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T )
273 {
274 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_LOCATE_POWER_T ) )
275 {
276 const SCH_SYMBOL* power = static_cast<const SCH_SYMBOL*>( item );
277
278 // Ensure the symbol has the Power (i.e. equivalent to a global label
279 // before adding its value in list
280 if( power->IsSymbolLikePowerGlobalLabel() )
281 {
282 const SCH_FIELD* valueField = power->GetField( FIELD_T::VALUE );
283 existingLabels.insert( UnescapeString( valueField->GetText() ) );
284 }
285 }
286 }
287
288 // Add local power labels from power symbols
289 if( m_currentLabel->Type() == SCH_LABEL_T )
290 {
291 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_LOCATE_POWER_T ) )
292 {
293 const SCH_SYMBOL* power = static_cast<const SCH_SYMBOL*>( item );
294
295 // Ensure the symbol has the Power (i.e. equivalent to a local label
296 // before adding its value in list
297 if( power->IsSymbolLikePowerLocalLabel() )
298 {
299 const SCH_FIELD* valueField = power->GetField( FIELD_T::VALUE );
300 existingLabels.insert( UnescapeString( valueField->GetText() ) );
301 }
302 }
303 }
304 }
305
306 // Add bus aliases to label list
307 for( const std::shared_ptr<BUS_ALIAS>& busAlias : m_Parent->Schematic().GetAllBusAliases() )
308 existingLabels.insert( wxT( "{" ) + busAlias->GetName() + wxT( "}" ) );
309
310 for( const wxString& label : existingLabels )
311 m_existingLabelArray.push_back( label );
312
313 m_valueCombo->SetStringList( m_existingLabelArray );
314 m_valueCombo->SetSelectedString( text );
315 }
316 else if( m_activeTextEntry )
317 {
318 m_activeTextEntry->SetValue( text );
319 }
320
321 // Push a copy of each field into m_updateFields
322 for( SCH_FIELD& field : m_currentLabel->GetFields() )
323 {
324 SCH_FIELD field_copy( field );
325
326 // change offset to be symbol-relative
327 field_copy.Offset( -m_currentLabel->GetPosition() );
328
329 m_fields->push_back( field_copy );
330 }
331
332 // notify the grid
333 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (int) m_fields->size() );
334 m_grid->ProcessTableMessage( msg );
335
336 if( m_shapeSizer->AreAnyItemsShown() )
337 {
338 switch( m_currentLabel->GetShape() )
339 {
340 case LABEL_FLAG_SHAPE::L_INPUT: m_input->SetValue( true ); break;
341 case LABEL_FLAG_SHAPE::L_OUTPUT: m_output->SetValue( true ); break;
342 case LABEL_FLAG_SHAPE::L_BIDI: m_bidirectional->SetValue( true ); break;
343 case LABEL_FLAG_SHAPE::L_TRISTATE: m_triState->SetValue( true ); break;
344 case LABEL_FLAG_SHAPE::L_UNSPECIFIED: m_passive->SetValue( true ); break;
345 case LABEL_FLAG_SHAPE::F_DOT: m_dot->SetValue( true ); break;
346 case LABEL_FLAG_SHAPE::F_ROUND: m_circle->SetValue( true ); break;
347 case LABEL_FLAG_SHAPE::F_DIAMOND: m_diamond->SetValue( true ); break;
348 case LABEL_FLAG_SHAPE::F_RECTANGLE: m_rectangle->SetValue( true ); break;
349 }
350 }
351
352 m_fontCtrl->SetFontSelection( m_currentLabel->GetFont() );
353
355 m_textSize.SetValue( static_cast<SCH_DIRECTIVE_LABEL*>( m_currentLabel )->GetPinLength() );
356 else
357 m_textSize.SetValue( m_currentLabel->GetTextWidth() );
358
359 m_bold->Check( m_currentLabel->IsBold() );
360 m_italic->Check( m_currentLabel->IsItalic() );
361 m_textColorSwatch->SetSwatchColor( m_currentLabel->GetTextColor(), false );
362
363 switch( m_currentLabel->GetSpinStyle() )
364 {
365 case SPIN_STYLE::RIGHT: m_spin0->Check( true ); break;
366 case SPIN_STYLE::LEFT: m_spin1->Check( true ); break;
367 case SPIN_STYLE::UP: m_spin2->Check( true ); break;
368 case SPIN_STYLE::BOTTOM: m_spin3->Check( true ); break;
369 }
370
371 if( m_currentLabel->AutoRotateOnPlacementSupported() )
372 m_autoRotate->SetValue( m_currentLabel->AutoRotateOnPlacement() );
373
374 // Recalculate layout after grid population
375 m_grid->Layout();
376 Layout();
377 GetSizer()->SetSizeHints( this );
378
379 wxSize minSize = GetMinSize();
380 wxSize curSize = GetSize();
381
382 if( curSize.x < minSize.x || curSize.y < minSize.y )
383 SetSize( wxSize( std::max( curSize.x, minSize.x ), std::max( curSize.y, minSize.y ) ) );
384
385 SendSizeEvent( wxSEND_EVENT_POST );
386
387 return true;
388}
389
390
391void DIALOG_LABEL_PROPERTIES::OnEnterKey( wxCommandEvent& aEvent )
392{
393 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
394}
395
396
398{
399 // If the key is WXK_RETURN/WXK_NUMPAD_ENTER because m_valueCombo is the source event, we do not skip
400 // the key event because the default action is to show the m_valueCombo dropdown list,
401 // and we only want to accept the entered string.
402 if(( aEvent.GetKeyCode() == WXK_RETURN ) || (aEvent.GetKeyCode() == WXK_NUMPAD_ENTER))
403 {
404 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
405 }
406 else if( aEvent.GetKeyCode() == WXK_SPACE )
407 {
408 // our FILTER_COMBOBOX uses the space as special command, not wanted here,
409 // to open the dropdown list of labels.
410 // So just add the space char to the current text, at current insertion point,
411 // and do not skip this event
412 m_activeTextEntry->WriteText( wxT(" " ) );
413 }
414 else
415 {
416 aEvent.Skip();
417 }
418}
419
420
422{
423 if( aEvent.GetKeyCode() == WXK_TAB )
424 {
425 if( aEvent.ShiftDown() )
426 {
427 m_textSizeCtrl->SetFocusFromKbd();
428 }
429 else if( !m_fields->empty() )
430 {
431 m_grid->SetFocusFromKbd();
432 m_grid->MakeCellVisible( 0, 0 );
433 m_grid->SetGridCursor( 0, 0 );
434 }
435 else
436 {
437 m_textSizeCtrl->SetFocusFromKbd();
438 }
439 }
440 else
441 {
442 aEvent.Skip();
443 }
444}
445
446
447static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
448{
449 return a.GetPosition() != b.GetPosition()
450 || a.GetHorizJustify() != b.GetHorizJustify()
451 || a.GetVertJustify() != b.GetVertJustify()
452 || a.GetTextAngle() != b.GetTextAngle();
453}
454
455
456static bool positioningChanged( FIELDS_GRID_TABLE* a, std::vector<SCH_FIELD>& b )
457{
458 for( size_t i = 0; i < a->size() && i < b.size(); ++i )
459 {
460 if( positioningChanged( a->at( i ), b.at( i ) ) )
461 return true;
462 }
463
464 return false;
465}
466
467
469{
470 if( !m_grid->CommitPendingChanges() )
471 return false;
472
473 if( !wxDialog::TransferDataFromWindow() )
474 return false;
475
476 // Don't allow text to disappear; it can be difficult to correct if you can't select it
477 if( !m_textSize.Validate( 0.01, 1000.0, EDA_UNITS::MM ) )
478 return false;
479
480 SCH_COMMIT commit( m_Parent );
481 wxString text;
482
483 /* save old text in undo list if not already in edit */
484 if( m_currentLabel->GetEditFlags() == 0 )
485 commit.Modify( m_currentLabel, m_Parent->GetScreen() );
486
487 m_Parent->GetCanvas()->Refresh();
488
490 {
491 // labels need escaping
493
494 // convert any text variable cross-references to their UUIDs
495 text = m_currentLabel->Schematic()->ConvertRefsToKIIDs( text );
496
497#ifdef __WXMAC__
498 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
499 text.Replace( wxS( "\r" ), wxS( "\n" ) );
500#endif
501
502 if( text.IsEmpty() && !m_currentLabel->IsNew() )
503 {
504 DisplayError( this, _( "Label can not be empty." ) );
505 return false;
506 }
507
508 m_currentLabel->SetText( text );
509 }
510
511 // change all field positions from relative to absolute
512 for( SCH_FIELD& field : *m_fields )
513 {
514 field.Offset( m_currentLabel->GetPosition() );
515
516 if( field.GetCanonicalName() == wxT( "Netclass" ) )
517 {
518 field.SetLayer( LAYER_NETCLASS_REFS );
519 }
520 else if( field.GetId() == FIELD_T::INTERSHEET_REFS )
521 {
522 if( field.IsVisible() != m_Parent->Schematic().Settings().m_IntersheetRefsShow )
523 {
524 DisplayInfoMessage( this, _( "Intersheet reference visibility is controlled globally from "
525 "Schematic Setup > General > Formatting" ) );
526 }
527
528 field.SetLayer( LAYER_INTERSHEET_REFS );
529 }
530 else
531 {
532 field.SetLayer( LAYER_FIELDS );
533 }
534 }
535
536 if( positioningChanged( m_fields, m_currentLabel->GetFields() ) )
537 m_currentLabel->SetFieldsAutoplaced( AUTOPLACE_NONE );
538
539 for( int ii = m_fields->GetNumberRows() - 1; ii >= 0; ii-- )
540 {
541 SCH_FIELD& field = m_fields->at( ii );
542 const wxString& fieldName = field.GetCanonicalName();
543 const wxString& fieldText = field.GetText();
544
545 if( fieldName.IsEmpty() && fieldText.IsEmpty() )
546 {
547 // delete empty, unnamed fields
548 m_fields->erase( m_fields->begin() + ii );
549 }
550 else if( fieldName == wxT( "Netclass" ) && fieldText.IsEmpty() )
551 {
552 // delete empty Netclass fields if there are other Netclass fields present
553 int netclassFieldCount = 0;
554
555 for( int jj = 0; jj < m_fields->GetNumberRows(); ++jj )
556 {
557 if( m_fields->at( jj ).GetCanonicalName() == wxT( "Netclass" ) )
558 netclassFieldCount++;
559 }
560
561 if( netclassFieldCount > 1 )
562 m_fields->erase( m_fields->begin() + ii );
563 }
564 else if( fieldName.IsEmpty() )
565 {
566 // give non-empty, unnamed fields a name
567 field.SetName( _( "untitled" ) );
568 }
569 }
570
571 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T ids.
572
573 for( SCH_FIELD& field : *m_fields )
574 {
575 if( !field.IsMandatory() )
576 field.SetOrdinal( ordinal++ );
577 }
578
579 m_currentLabel->SetFields( *m_fields );
580
581 if( m_shapeSizer->AreAnyItemsShown() )
582 {
583 if( m_bidirectional->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
584 else if( m_input->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
585 else if( m_output->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
586 else if( m_triState->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_TRISTATE );
587 else if( m_passive->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::L_UNSPECIFIED );
588 else if( m_dot->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_DOT );
589 else if( m_circle->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_ROUND );
590 else if( m_diamond->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_DIAMOND );
591 else if( m_rectangle->GetValue() ) m_currentLabel->SetShape( LABEL_FLAG_SHAPE::F_RECTANGLE );
592 }
593
594 if( m_fontCtrl->HaveFontSelection() )
595 m_currentLabel->SetFont( m_fontCtrl->GetFontSelection( m_bold->IsChecked(), m_italic->IsChecked() ) );
596
598 static_cast<SCH_DIRECTIVE_LABEL*>( m_currentLabel )->SetPinLength( m_textSize.GetIntValue() );
599 else if( m_currentLabel->GetTextWidth() != m_textSize.GetIntValue() )
600 m_currentLabel->SetTextSize( VECTOR2I( m_textSize.GetIntValue(), m_textSize.GetIntValue() ) );
601
602 // Must come after SetTextSize()
603 m_currentLabel->SetBold( m_bold->IsChecked() );
604 m_currentLabel->SetItalic( m_italic->IsChecked() );
605
606 m_currentLabel->SetTextColor( m_textColorSwatch->GetSwatchColor() );
607
608 SPIN_STYLE selectedSpinStyle= SPIN_STYLE::LEFT;
609
610 if( m_spin0->IsChecked() ) selectedSpinStyle = SPIN_STYLE::RIGHT;
611 else if( m_spin1->IsChecked() ) selectedSpinStyle = SPIN_STYLE::LEFT;
612 else if( m_spin2->IsChecked() ) selectedSpinStyle = SPIN_STYLE::UP;
613 else if( m_spin3->IsChecked() ) selectedSpinStyle = SPIN_STYLE::BOTTOM;
614
615 if( m_currentLabel->AutoRotateOnPlacementSupported() )
616 {
617 SCH_EDIT_FRAME* frame = static_cast<SCH_EDIT_FRAME*>( m_parentFrame );
618 m_currentLabel->SetAutoRotateOnPlacement( m_autoRotate->IsChecked() );
619 frame->AutoRotateItem( frame->GetScreen(), m_currentLabel );
620 }
621 else
622 {
623 m_currentLabel->SetAutoRotateOnPlacement( false );
624 }
625
626 if( !m_currentLabel->AutoRotateOnPlacement() && m_currentLabel->GetSpinStyle() != selectedSpinStyle )
627 m_currentLabel->SetSpinStyle( selectedSpinStyle );
628
629 AUTOPLACE_ALGO fieldsAutoplaced = m_currentLabel->GetFieldsAutoplaced();
630
631 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
632 m_currentLabel->AutoplaceFields( m_Parent->GetScreen(), fieldsAutoplaced );
633
634 if( !commit.Empty() )
635 {
636 commit.Push( _( "Edit Label Properties" ) );
637 }
638 else if( m_activeTextEntry && m_labelList )
639 {
640 text = m_activeTextEntry->GetValue();
641 // On macOS CTRL+Enter produces '\r' instead of '\n' regardless of EOL setting
642 text.Replace( wxS( "\r" ), wxS( "\n" ) );
643 wxArrayString lines = wxSplit( text, '\n' );
644
645 for( const wxString& line : lines )
646 {
647 text = EscapeString( line, CTX_NETNAME );
648 text.Trim( false ).Trim( true );
649
650 if( text.empty() )
651 continue;
652
653 // convert any text variable cross-references to their UUIDs
654 text = m_currentLabel->Schematic()->ConvertRefsToKIIDs( text );
655
656 switch ( m_currentLabel->Type() )
657 {
659 {
660 SCH_GLOBALLABEL* label = new SCH_GLOBALLABEL( *static_cast<SCH_GLOBALLABEL*>( m_currentLabel ) );
661 const_cast<KIID&>( label->m_Uuid ) = KIID(); // Gives a new UUID to the copy
662 label->SetText( text );
663 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
664 break;
665 }
666 case SCH_HIER_LABEL_T:
667 {
668 SCH_HIERLABEL* label = new SCH_HIERLABEL( *static_cast<SCH_HIERLABEL*>( m_currentLabel ) );
669 const_cast<KIID&>( label->m_Uuid ) = KIID();
670 label->SetText( text );
671 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
672 break;
673 }
674 case SCH_LABEL_T:
675 {
676 SCH_LABEL* label = new SCH_LABEL( *static_cast<SCH_LABEL*>( m_currentLabel ) );
677 const_cast<KIID&>( label->m_Uuid ) = KIID();
678 label->SetText( text );
679 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
680 break;
681 }
682 default:
683 break;
684 }
685 }
686 }
687 else if( m_labelList && m_currentLabel->Type() == SCH_DIRECTIVE_LABEL_T )
688 {
690 m_labelList->push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
691 }
692
693 return true;
694}
695
696
697void DIALOG_LABEL_PROPERTIES::onSpinButton( wxCommandEvent& aEvent )
698{
699 for( BITMAP_BUTTON* btn : { m_spin0, m_spin1, m_spin2, m_spin3 } )
700 {
701 if( btn->IsChecked() && btn != aEvent.GetEventObject() )
702 btn->Check( false );
703 }
704}
705
706
707void DIALOG_LABEL_PROPERTIES::OnFormattingHelp( wxHyperlinkEvent& aEvent )
708{
710}
711
712
714{
715 wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
716 wxControl* control = editor->GetControl();
717
718 if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
719 {
720 event.Veto();
721 m_delayedFocusRow = event.GetRow();
722 m_delayedFocusColumn = event.GetCol();
723 }
724 else if( event.GetCol() == FDC_NAME )
725 {
726 wxString newName = event.GetString();
727
728 for( int i = 0; i < m_grid->GetNumberRows(); ++i )
729 {
730 if( i == event.GetRow() )
731 continue;
732
733 if( newName.CmpNoCase( m_grid->GetCellValue( i, FDC_NAME ) ) == 0 )
734 {
735 DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
736 newName ) );
737 event.Veto();
738 m_delayedFocusRow = event.GetRow();
739 m_delayedFocusColumn = event.GetCol();
740 break;
741 }
742 }
743 }
744
745 editor->DecRef();
746}
747
748
749void DIALOG_LABEL_PROPERTIES::OnAddField( wxCommandEvent& event )
750{
751 m_grid->OnAddRow(
752 [&]() -> std::pair<int, int>
753 {
754 wxString fieldName = wxT( "Netclass" );
755
756 for( SCH_FIELD& field : *m_fields )
757 {
758 if( field.GetId() != FIELD_T::INTERSHEET_REFS && field.GetName() != wxT( "Netclass" ) )
759 {
760 fieldName = wxEmptyString;
761 break;
762 }
763 }
764
765 fieldName = SCH_LABEL_BASE::GetDefaultFieldName( fieldName, true );
766
767 SCH_FIELD newField( m_currentLabel, FIELD_T::USER, fieldName );
768
769 if( m_fields->size() > 0 )
770 {
771 // SetAttributes() also covers text angle, size, italic and bold
772 newField.SetAttributes( m_fields->at( m_fields->size() - 1 ) );
773 newField.SetVisible( m_fields->at( m_fields->size() - 1 ).IsVisible() );
774 }
775 else
776 {
777 newField.SetVisible( true );
778 newField.SetItalic( true );
779 }
780
781 m_fields->push_back( newField );
782
783 // notify the grid
784 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
785 m_grid->ProcessTableMessage( msg );
786 return { m_fields->size() - 1, FDC_NAME };
787 } );
788}
789
790
791void DIALOG_LABEL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
792{
793 m_grid->OnDeleteRows(
794 [&]( int row )
795 {
796 if( row < m_currentLabel->GetMandatoryFieldCount() )
797 {
798 DisplayError( this, _( "The first field is mandatory." ) );
799 return false;
800 }
801
802 return true;
803 },
804 [&]( int row )
805 {
806 m_fields->erase( m_fields->begin() + row );
807
808 // notify the grid
809 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
810 m_grid->ProcessTableMessage( msg );
811 } );
812}
813
814
815void DIALOG_LABEL_PROPERTIES::OnMoveUp( wxCommandEvent& event )
816{
817 m_grid->OnMoveRowUp(
818 [&]( int row )
819 {
820 return row > m_currentLabel->GetMandatoryFieldCount();
821 },
822 [&]( int row )
823 {
824 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row - 1 ) );
825 m_grid->ForceRefresh();
826 } );
827}
828
829
830void DIALOG_LABEL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
831{
832 m_grid->OnMoveRowUp(
833 [&]( int row )
834 {
835 return row >= m_currentLabel->GetMandatoryFieldCount();
836 },
837 [&]( int row )
838 {
839 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row + 1 ) );
840 m_grid->ForceRefresh();
841 } );
842}
843
844
845void DIALOG_LABEL_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
846{
847 std::bitset<64> shownColumns = m_grid->GetShownColumns();
848
849 if( shownColumns != m_shownColumns )
850 {
851 m_shownColumns = shownColumns;
852
853 if( !m_grid->IsCellEditControlShown() )
854 m_grid->SetGridWidthsDirty();
855 }
856
857 // Handle a delayed focus
858 if( m_delayedFocusRow >= 0 && m_delayedFocusRow < m_grid->GetNumberRows() )
859 {
860 m_grid->SetFocus();
861 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
863 }
864
867}
868
869
871{
872 bool multiLine = m_multilineAllowed && m_cbMultiLine->IsChecked();
873
874 if( m_currentLabel->Type() == SCH_GLOBAL_LABEL_T || m_currentLabel->Type() == SCH_LABEL_T )
875 {
876 m_labelCombo->Show( !multiLine );
877 m_valueCombo->Show( !multiLine );
878 m_labelMultiLine->Show( multiLine );
879 m_valueMultiLine->Show( multiLine );
880
881 if( multiLine )
882 {
883 m_valueMultiLine->SetValue( m_valueCombo->GetValue() );
886 }
887 else
888 {
889 wxString multiText = m_valueMultiLine->GetValue();
890 m_valueCombo->SetValue( multiText.BeforeFirst( '\n' ) );
892 SetInitialFocus( m_valueCombo->GetTextCtrl() );
893 }
894 }
895 else if( m_currentLabel->Type() == SCH_HIER_LABEL_T )
896 {
897 m_labelSingleLine->Show( !multiLine );
898 m_valueSingleLine->Show( !multiLine );
899 m_labelMultiLine->Show( multiLine );
900 m_valueMultiLine->Show( multiLine );
901
902 if( multiLine )
903 {
904 m_valueMultiLine->SetValue( m_valueSingleLine->GetValue() );
907 }
908 else
909 {
910 wxString multiText = m_valueMultiLine->GetValue();
911 m_valueSingleLine->SetValue( multiText.BeforeFirst( '\n' ) );
914 }
915 }
916
917 Layout();
918}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
@ text_align_right
@ label_align_bottom
@ text_align_left
@ label_align_right
@ label_align_top
@ pinorient_right
@ label_align_left
@ text_align_bottom
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:134
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:102
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 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 OnGridCellChanging(wxGridEvent &event)
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:79
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
EDA_BASE_FRAME * m_parentFrame
const KIID m_Uuid
Definition eda_item.h:531
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:428
virtual void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:595
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:221
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:168
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:224
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:302
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
Definition kiid.h:44
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
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
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:162
static const wxString GetDefaultFieldName(const wxString &aName, bool aUseDefaultName)
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:746
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
Schematic symbol object.
Definition sch_symbol.h:69
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:245
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
@ FDC_NAME
@ FDC_VALUE
@ LAYER_FIELDS
Definition layer_ids.h:460
@ LAYER_NETCLASS_REFS
Definition layer_ids.h:462
@ LAYER_SCHEMATIC_BACKGROUND
Definition layer_ids.h:486
@ LAYER_INTERSHEET_REFS
Definition layer_ids.h:461
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
AUTOPLACE_ALGO
Definition sch_item.h:65
@ AUTOPLACE_MANUAL
Definition sch_item.h:68
@ AUTOPLACE_NONE
Definition sch_item.h:66
@ AUTOPLACE_AUTO
Definition sch_item.h:67
@ L_BIDI
Definition sch_label.h:100
@ L_TRISTATE
Definition sch_label.h:101
@ L_UNSPECIFIED
Definition sch_label.h:102
@ F_DOT
Definition sch_label.h:105
@ F_ROUND
Definition sch_label.h:106
@ L_OUTPUT
Definition sch_label.h:99
@ F_DIAMOND
Definition sch_label.h:107
@ L_INPUT
Definition sch_label.h:98
@ F_RECTANGLE
Definition sch_label.h:108
std::vector< FAB_LAYER_COLOR > dummy
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:168
@ SCH_LABEL_T
Definition typeinfo.h:164
@ SCH_HIER_LABEL_T
Definition typeinfo.h:166
@ SCH_SHEET_PIN_T
Definition typeinfo.h:171
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:193
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:165
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683