KiCad PCB EDA Suite
Loading...
Searching...
No Matches
net_settings.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) 2020 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Jon Evans <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <algorithm>
23#include <limits>
24
25#include <json_common.h>
26
28#include <settings/parameters.h>
30#include <string_utils.h>
31#include <base_units.h>
32#include <unordered_set>
33
34
35// const int netSettingsSchemaVersion = 0;
36// const int netSettingsSchemaVersion = 1; // new overbar syntax
37// const int netSettingsSchemaVersion = 2; // exclude buses from netclass members
38// const int netSettingsSchemaVersion = 3; // netclass assignment patterns
39// const int netSettingsSchemaVersion = 4; // netclass ordering
40const int netSettingsSchemaVersion = 5; // Tuning profile names
41
42
43static std::optional<int> getInPcbUnits( const nlohmann::json& aObj, const std::string& aKey,
44 std::optional<int> aDefault = std::optional<int>() )
45{
46 if( aObj.contains( aKey ) && aObj[aKey].is_number() )
47 return pcbIUScale.mmToIU( aObj[aKey].get<double>() );
48 else
49 return aDefault;
50};
51
52
53static std::optional<int> getInSchUnits( const nlohmann::json& aObj, const std::string& aKey,
54 std::optional<int> aDefault = std::optional<int>() )
55{
56 if( aObj.contains( aKey ) && aObj[aKey].is_number() )
57 return schIUScale.MilsToIU( aObj[aKey].get<double>() );
58 else
59 return aDefault;
60};
61
62
63NET_SETTINGS::NET_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
64 NESTED_SETTINGS( "net_settings", netSettingsSchemaVersion, aParent, aPath, false )
65{
66 m_defaultNetClass = std::make_shared<NETCLASS>( NETCLASS::Default, true );
67 m_defaultNetClass->SetDescription( _( "This is the default net class." ) );
68 m_defaultNetClass->SetPriority( std::numeric_limits<int>::max() );
69
70 auto saveNetclass =
71 []( nlohmann::json& json_array, const std::shared_ptr<NETCLASS>& nc )
72 {
73 // Note: we're in common/, but we do happen to know which of these
74 // fields are used in which units system.
75 nlohmann::json nc_json = { { "name", nc->GetName().ToUTF8() },
76 { "priority", nc->GetPriority() },
77 { "schematic_color", nc->GetSchematicColor( true ) },
78 { "pcb_color", nc->GetPcbColor( true ) },
79 { "tuning_profile", nc->GetTuningProfile() } };
80
81 auto saveInPcbUnits =
82 []( nlohmann::json& json, const std::string& aKey, int aValue )
83 {
84 json.push_back( { aKey, pcbIUScale.IUTomm( aValue ) } );
85 };
86
87 if( nc->HasWireWidth() )
88 nc_json.push_back(
89 { "wire_width", schIUScale.IUToMils( nc->GetWireWidth() ) } );
90
91 if( nc->HasBusWidth() )
92 nc_json.push_back( { "bus_width", schIUScale.IUToMils( nc->GetBusWidth() ) } );
93
94 if( nc->HasLineStyle() )
95 nc_json.push_back( { "line_style", nc->GetLineStyle() } );
96
97 if( nc->HasClearance() )
98 saveInPcbUnits( nc_json, "clearance", nc->GetClearance() );
99
100 if( nc->HasTrackWidth() )
101 saveInPcbUnits( nc_json, "track_width", nc->GetTrackWidth() );
102
103 if( nc->HasViaDiameter() )
104 saveInPcbUnits( nc_json, "via_diameter", nc->GetViaDiameter() );
105
106 if( nc->HasViaDrill() )
107 saveInPcbUnits( nc_json, "via_drill", nc->GetViaDrill() );
108
109 if( nc->HasuViaDiameter() )
110 saveInPcbUnits( nc_json, "microvia_diameter", nc->GetuViaDiameter() );
111
112 if( nc->HasuViaDrill() )
113 saveInPcbUnits( nc_json, "microvia_drill", nc->GetuViaDrill() );
114
115 if( nc->HasDiffPairWidth() )
116 saveInPcbUnits( nc_json, "diff_pair_width", nc->GetDiffPairWidth() );
117
118 if( nc->HasDiffPairGap() )
119 saveInPcbUnits( nc_json, "diff_pair_gap", nc->GetDiffPairGap() );
120
121 if( nc->HasDiffPairViaGap() )
122 saveInPcbUnits( nc_json, "diff_pair_via_gap", nc->GetDiffPairViaGap() );
123
124 json_array.push_back( nc_json );
125 };
126
127 auto readNetClass =
128 []( const nlohmann::json& entry )
129 {
130 wxString name = entry["name"];
131
132 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( name, false );
133
134 int priority = entry["priority"];
135 nc->SetPriority( priority );
136
137 nc->SetTuningProfile( entry["tuning_profile"] );
138
139 if( auto value = getInPcbUnits( entry, "clearance" ) )
140 nc->SetClearance( *value );
141
142 if( auto value = getInPcbUnits( entry, "track_width" ) )
143 nc->SetTrackWidth( *value );
144
145 if( auto value = getInPcbUnits( entry, "via_diameter" ) )
146 nc->SetViaDiameter( *value );
147
148 if( auto value = getInPcbUnits( entry, "via_drill" ) )
149 nc->SetViaDrill( *value );
150
151 if( auto value = getInPcbUnits( entry, "microvia_diameter" ) )
152 nc->SetuViaDiameter( *value );
153
154 if( auto value = getInPcbUnits( entry, "microvia_drill" ) )
155 nc->SetuViaDrill( *value );
156
157 if( auto value = getInPcbUnits( entry, "diff_pair_width" ) )
158 nc->SetDiffPairWidth( *value );
159
160 if( auto value = getInPcbUnits( entry, "diff_pair_gap" ) )
161 nc->SetDiffPairGap( *value );
162
163 if( auto value = getInPcbUnits( entry, "diff_pair_via_gap" ) )
164 nc->SetDiffPairViaGap( *value );
165
166 if( auto value = getInSchUnits( entry, "wire_width" ) )
167 nc->SetWireWidth( *value );
168
169 if( auto value = getInSchUnits( entry, "bus_width" ) )
170 nc->SetBusWidth( *value );
171
172 if( entry.contains( "line_style" ) && entry["line_style"].is_number() )
173 nc->SetLineStyle( entry["line_style"].get<int>() );
174
175 if( entry.contains( "pcb_color" ) && entry["pcb_color"].is_string() )
176 nc->SetPcbColor( entry["pcb_color"].get<KIGFX::COLOR4D>() );
177
178 if( entry.contains( "schematic_color" )
179 && entry["schematic_color"].is_string() )
180 {
181 nc->SetSchematicColor( entry["schematic_color"].get<KIGFX::COLOR4D>() );
182 }
183
184 return nc;
185 };
186
187 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "classes",
188 [&]() -> nlohmann::json
189 {
190 nlohmann::json ret = nlohmann::json::array();
191
193 saveNetclass( ret, m_defaultNetClass );
194
195 for( const auto& [name, netclass] : m_netClasses )
196 saveNetclass( ret, netclass );
197
198 return ret;
199 },
200 [&]( const nlohmann::json& aJson )
201 {
202 if( !aJson.is_array() )
203 return;
204
205 m_netClasses.clear();
206
207 for( const nlohmann::json& entry : aJson )
208 {
209 if( !entry.is_object() || !entry.contains( "name" ) )
210 continue;
211
212 std::shared_ptr<NETCLASS> nc = readNetClass( entry );
213
214 if( nc->IsDefault() )
216 else
217 m_netClasses[nc->GetName()] = nc;
218 }
219 },
220 {} ) );
221
222 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "net_colors",
223 [&]() -> nlohmann::json
224 {
225 nlohmann::json ret = {};
226
227 for( const auto& [netname, color] : m_netColorAssignments )
228 {
229 std::string key( netname.ToUTF8() );
230 ret[ std::move( key ) ] = color;
231 }
232
233 return ret;
234 },
235 [&]( const nlohmann::json& aJson )
236 {
237 if( !aJson.is_object() )
238 return;
239
240 m_netColorAssignments.clear();
241
242 for( const auto& pair : aJson.items() )
243 {
244 wxString key( pair.key().c_str(), wxConvUTF8 );
245 m_netColorAssignments[std::move( key )] = pair.value().get<KIGFX::COLOR4D>();
246 }
247 },
248 {} ) );
249
250 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "netclass_assignments",
251 [&]() -> nlohmann::json
252 {
253 nlohmann::json ret = {};
254
255 for( const auto& [netname, netclassNames] : m_netClassLabelAssignments )
256 {
257 nlohmann::json netclassesJson = nlohmann::json::array();
258
259 for( const auto& netclass : netclassNames )
260 {
261 std::string netclassStr( netclass.ToUTF8() );
262 netclassesJson.push_back( std::move( netclassStr ) );
263 }
264
265 std::string key( netname.ToUTF8() );
266 ret[std::move( key )] = netclassesJson;
267 }
268
269 return ret;
270 },
271 [&]( const nlohmann::json& aJson )
272 {
273 if( !aJson.is_object() )
274 return;
275
277
278 for( const auto& pair : aJson.items() )
279 {
280 wxString key( pair.key().c_str(), wxConvUTF8 );
281
282 for( const auto& netclassName : pair.value() )
283 m_netClassLabelAssignments[key].insert( netclassName.get<wxString>() );
284 }
285 },
286 {} ) );
287
288 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "netclass_patterns",
289 [&]() -> nlohmann::json
290 {
291 nlohmann::json ret = nlohmann::json::array();
292
293 for( const auto& [matcher, netclassName] : m_netClassPatternAssignments )
294 {
295 nlohmann::json pattern_json = {
296 { "pattern", matcher->GetPattern().ToUTF8() },
297 { "netclass", netclassName.ToUTF8() }
298 };
299
300 ret.push_back( std::move( pattern_json ) );
301 }
302
303 return ret;
304 },
305 [&]( const nlohmann::json& aJson )
306 {
307 if( !aJson.is_array() )
308 return;
309
311
312 for( const nlohmann::json& entry : aJson )
313 {
314 if( !entry.is_object() )
315 continue;
316
317 if( entry.contains( "pattern" ) && entry["pattern"].is_string()
318 && entry.contains( "netclass" ) && entry["netclass"].is_string() )
319 {
320 wxString pattern = entry["pattern"].get<wxString>();
321 wxString netclass = entry["netclass"].get<wxString>();
322
324 { std::make_unique<EDA_COMBINED_MATCHER>( pattern, CTX_NETCLASS ),
325 netclass } );
326 }
327 }
328 },
329 {} ) );
330
331 registerMigration( 0, 1, std::bind( &NET_SETTINGS::migrateSchema0to1, this ) );
332 registerMigration( 1, 2, std::bind( &NET_SETTINGS::migrateSchema1to2, this ) );
333 registerMigration( 2, 3, std::bind( &NET_SETTINGS::migrateSchema2to3, this ) );
334 registerMigration( 3, 4, std::bind( &NET_SETTINGS::migrateSchema3to4, this ) );
335 registerMigration( 4, 5, std::bind( &NET_SETTINGS::migrateSchema4to5, this ) );
336}
337
338
340{
341 // Release early before destroying members
342 if( m_parent )
343 {
344 m_parent->ReleaseNestedSettings( this );
345 m_parent = nullptr;
346 }
347}
348
349
350bool NET_SETTINGS::operator==( const NET_SETTINGS& aOther ) const
351{
352 if( !std::equal( std::begin( m_netClasses ), std::end( m_netClasses ),
353 std::begin( aOther.m_netClasses ) ) )
354 return false;
355
356 if( !std::equal( std::begin( m_netClassPatternAssignments ),
358 std::begin( aOther.m_netClassPatternAssignments ) ) )
359 return false;
360
361 if( !std::equal( std::begin( m_netClassLabelAssignments ),
362 std::end( m_netClassLabelAssignments ),
363 std::begin( aOther.m_netClassLabelAssignments ) ) )
364 return false;
365
366
367 if( !std::equal( std::begin( m_netColorAssignments ), std::end( m_netColorAssignments ),
368 std::begin( aOther.m_netColorAssignments ) ) )
369 return false;
370
371 return true;
372}
373
374
376{
377 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
378 {
379 for( auto& netClass : m_internals->At( "classes" ).items() )
380 {
381 if( netClass.value().contains( "nets" ) && netClass.value()["nets"].is_array() )
382 {
383 nlohmann::json migrated = nlohmann::json::array();
384
385 for( auto& net : netClass.value()["nets"].items() )
386 migrated.push_back( ConvertToNewOverbarNotation( net.value().get<wxString>() ) );
387
388 netClass.value()["nets"] = migrated;
389 }
390 }
391 }
392
393 return true;
394}
395
396
398{
399 return true;
400}
401
402
404{
405 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
406 {
407 nlohmann::json patterns = nlohmann::json::array();
408
409 for( auto& netClass : m_internals->At( "classes" ).items() )
410 {
411 if( netClass.value().contains( "name" )
412 && netClass.value().contains( "nets" )
413 && netClass.value()["nets"].is_array() )
414 {
415 wxString netClassName = netClass.value()["name"].get<wxString>();
416
417 for( auto& net : netClass.value()["nets"].items() )
418 {
419 nlohmann::json pattern_json = {
420 { "pattern", net.value().get<wxString>() },
421 { "netclass", netClassName }
422 };
423
424 patterns.push_back( pattern_json );
425 }
426 }
427 }
428
429 m_internals->SetFromString( "netclass_patterns", patterns );
430 }
431
432 return true;
433}
434
435
437{
438 // Add priority field to netclasses
439 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
440 {
441 int priority = 0;
442
443 for( auto& netClass : m_internals->At( "classes" ).items() )
444 {
445 if( netClass.value()["name"].get<wxString>() == NETCLASS::Default )
446 netClass.value()["priority"] = std::numeric_limits<int>::max();
447 else
448 netClass.value()["priority"] = priority++;
449 }
450 }
451
452 // Move netclass assignments to a list
453 if( m_internals->contains( "netclass_assignments" )
454 && m_internals->At( "netclass_assignments" ).is_object() )
455 {
456 nlohmann::json migrated = {};
457
458 for( const auto& pair : m_internals->At( "netclass_assignments" ).items() )
459 {
460 nlohmann::json netclassesJson = nlohmann::json::array();
461
462 if( pair.value().get<wxString>() != wxEmptyString )
463 netclassesJson.push_back( pair.value() );
464
465 migrated[pair.key()] = netclassesJson;
466 }
467
468 m_internals->SetFromString( "netclass_assignments", migrated );
469 }
470
471 return true;
472}
473
474
476{
477 // Add tuning profile name field to netclasses
478 if( m_internals->contains( "classes" ) && m_internals->At( "classes" ).is_array() )
479 {
480 const wxString emptyStr = "";
481
482 for( auto& netClass : m_internals->At( "classes" ).items() )
483 netClass.value()["tuning_profile"] = emptyStr.ToUTF8();
484 }
485
486 return true;
487}
488
489
490void NET_SETTINGS::SetDefaultNetclass( std::shared_ptr<NETCLASS> netclass )
491{
492 m_defaultNetClass = netclass;
493}
494
495
496std::shared_ptr<NETCLASS> NET_SETTINGS::GetDefaultNetclass()
497{
498 return m_defaultNetClass;
499}
500
501
502bool NET_SETTINGS::HasNetclass( const wxString& netclassName ) const
503{
504 return m_netClasses.find( netclassName ) != m_netClasses.end();
505}
506
507
508void NET_SETTINGS::SetNetclass( const wxString& netclassName, std::shared_ptr<NETCLASS>& netclass )
509{
510 m_netClasses[netclassName] = netclass;
511}
512
513
514void NET_SETTINGS::SetNetclasses( const std::map<wxString, std::shared_ptr<NETCLASS>>& netclasses )
515{
516 m_netClasses = netclasses;
518}
519
520
521const std::map<wxString, std::shared_ptr<NETCLASS>>& NET_SETTINGS::GetNetclasses() const
522{
523 return m_netClasses;
524}
525
526
527const std::map<wxString, std::shared_ptr<NETCLASS>>& NET_SETTINGS::GetCompositeNetclasses() const
528{
530}
531
532
534{
535 m_netClasses.clear();
536 m_impicitNetClasses.clear();
538}
539
540
541const std::map<wxString, std::set<wxString>>& NET_SETTINGS::GetNetclassLabelAssignments() const
542{
544}
545
546
551
552
553void NET_SETTINGS::ClearNetclassLabelAssignment( const wxString& netName )
554{
555 m_netClassLabelAssignments.erase( netName );
556}
557
558
559void NET_SETTINGS::SetNetclassLabelAssignment( const wxString& netName,
560 const std::set<wxString>& netclasses )
561{
562 m_netClassLabelAssignments[netName] = netclasses;
563}
564
565
567 const std::set<wxString>& netclasses )
568{
569 m_netClassLabelAssignments[netName].insert( netclasses.begin(), netclasses.end() );
570}
571
572
573bool NET_SETTINGS::HasNetclassLabelAssignment( const wxString& netName ) const
574{
575 return m_netClassLabelAssignments.find( netName ) != m_netClassLabelAssignments.end();
576}
577
578
579void NET_SETTINGS::SetNetclassPatternAssignment( const wxString& pattern, const wxString& netclass )
580{
581 // Avoid exact duplicates - these shouldn't cause problems, due to later de-duplication
582 // but they are unnecessary.
583 for( auto& assignment : m_netClassPatternAssignments )
584 {
585 if( assignment.first->GetPattern() == pattern && assignment.second == netclass )
586 return;
587 }
588
589 // No assignment, add a new one
591 { std::make_unique<EDA_COMBINED_MATCHER>( pattern, CTX_NETCLASS ), netclass } );
592
594}
595
596
598 std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&& netclassPatterns )
599{
600 m_netClassPatternAssignments = std::move( netclassPatterns );
602}
603
604
605std::vector<std::pair<std::unique_ptr<EDA_COMBINED_MATCHER>, wxString>>&
610
611
616
617
618void NET_SETTINGS::ClearCacheForNet( const wxString& netName )
619{
620 if( m_effectiveNetclassCache.count( netName ) )
621 {
622 wxString compositeNetclassName = m_effectiveNetclassCache[netName]->GetName();
623 m_compositeNetClasses.erase( compositeNetclassName );
624 m_effectiveNetclassCache.erase( netName );
625 }
626}
627
628
634
635
636void NET_SETTINGS::SetNetColorAssignment( const wxString& netName, const KIGFX::COLOR4D& color )
637{
638 m_netColorAssignments[netName] = color;
639}
640
641
642const std::map<wxString, KIGFX::COLOR4D>& NET_SETTINGS::GetNetColorAssignments() const
643{
645}
646
647
652
653
654bool NET_SETTINGS::HasEffectiveNetClass( const wxString& aNetName ) const
655{
656 return m_effectiveNetclassCache.count( aNetName ) > 0;
657}
658
659
660std::shared_ptr<NETCLASS> NET_SETTINGS::GetCachedEffectiveNetClass( const wxString& aNetName ) const
661{
662 return m_effectiveNetclassCache.at( aNetName );
663}
664
665
666std::shared_ptr<NETCLASS> NET_SETTINGS::GetEffectiveNetClass( const wxString& aNetName )
667{
668 // Lambda to fetch an explicit netclass. Returns a nullptr if not found
669 auto getExplicitNetclass =
670 [this]( const wxString& netclass ) -> std::shared_ptr<NETCLASS>
671 {
672 if( netclass == NETCLASS::Default )
673 return m_defaultNetClass;
674
675 auto ii = m_netClasses.find( netclass );
676
677 if( ii == m_netClasses.end() )
678 return {};
679 else
680 return ii->second;
681 };
682
683 // Lambda to fetch or create an implicit netclass (defined with a label, but not configured)
684 // These are needed as while they do not provide any netclass parameters, they do now appear in
685 // DRC matching strings as an assigned netclass.
686 auto getOrAddImplicitNetcless =
687 [this]( const wxString& netclass ) -> std::shared_ptr<NETCLASS>
688 {
689 auto ii = m_impicitNetClasses.find( netclass );
690
691 if( ii == m_impicitNetClasses.end() )
692 {
693 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( netclass, false );
694 nc->SetPriority( std::numeric_limits<int>::max() - 1 ); // Priority > default netclass
695 m_impicitNetClasses[netclass] = nc;
696 return nc;
697 }
698 else
699 {
700 return ii->second;
701 }
702 };
703
704 // <no net> is forced to be part of the default netclass.
705 if( aNetName.IsEmpty() )
706 return m_defaultNetClass;
707
708 // First check if we have a cached resolved netclass
709 auto cacheItr = m_effectiveNetclassCache.find( aNetName );
710
711 if( cacheItr != m_effectiveNetclassCache.end() )
712 return cacheItr->second;
713
714 // No cache found - build a vector of all netclasses assigned to or matching this net
715 std::unordered_set<std::shared_ptr<NETCLASS>> resolvedNetclasses;
716
717 // First find explicit netclass assignments
718 auto it = m_netClassLabelAssignments.find( aNetName );
719
720 if( it != m_netClassLabelAssignments.end() && it->second.size() > 0 )
721 {
722 for( const wxString& netclassName : it->second )
723 {
724 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
725
726 if( netclass )
727 {
728 resolvedNetclasses.insert( std::move( netclass ) );
729 }
730 else
731 {
732 resolvedNetclasses.insert( getOrAddImplicitNetcless( netclassName ) );
733 }
734 }
735 }
736
737 // Now find any pattern-matched netclass assignments
738 for( const auto& [matcher, netclassName] : m_netClassPatternAssignments )
739 {
740 if( matcher->StartsWith( aNetName ) )
741 {
742 std::shared_ptr<NETCLASS> netclass = getExplicitNetclass( netclassName );
743
744 if( netclass )
745 {
746 resolvedNetclasses.insert( std::move( netclass ) );
747 }
748 else
749 {
750 resolvedNetclasses.insert( getOrAddImplicitNetcless( netclassName ) );
751 }
752 }
753 }
754
755 // Handle zero resolved netclasses
756 if( resolvedNetclasses.size() == 0 )
757 {
759
760 return m_defaultNetClass;
761 }
762
763 // Make and cache the effective netclass. Note that makeEffectiveNetclass will add the default
764 // netclass to resolvedNetclasses if it is needed to complete the netclass paramters set. It
765 // will also sort resolvedNetclasses by priority order.
766 std::vector<NETCLASS*> netclassPtrs;
767
768 for( const std::shared_ptr<NETCLASS>& nc : resolvedNetclasses )
769 netclassPtrs.push_back( nc.get() );
770
771 wxString name;
772 name.Printf( "Effective for net: %s", aNetName );
773 std::shared_ptr<NETCLASS> effectiveNetclass = std::make_shared<NETCLASS>( name, false );
774 makeEffectiveNetclass( effectiveNetclass, netclassPtrs );
775
776 if( netclassPtrs.size() == 1 )
777 {
778 // No defaults were added - just return the primary netclass
779 m_effectiveNetclassCache[aNetName] = *resolvedNetclasses.begin();
780 return *resolvedNetclasses.begin();
781 }
782 else
783 {
784 effectiveNetclass->SetConstituentNetclasses( std::move( netclassPtrs ) );
785
786 m_compositeNetClasses[effectiveNetclass->GetName()] = effectiveNetclass;
787 m_effectiveNetclassCache[aNetName] = effectiveNetclass;
788
789 return effectiveNetclass;
790 }
791}
792
793
795{
796 for( auto& [ncName, nc] : m_compositeNetClasses )
797 {
798 // Note this needs to be a copy in case we now need to add the default netclass
799 std::vector<NETCLASS*> constituents = nc->GetConstituentNetclasses();
800
801 wxASSERT( constituents.size() > 0 );
802
803 // If the last netclass is Default, remove it (it will be re-added if still needed)
804 if( ( *constituents.rbegin() )->GetName() == NETCLASS::Default )
805 {
806 constituents.pop_back();
807 }
808
809 // Remake the netclass from original constituents
810 nc->ResetParameters();
811 makeEffectiveNetclass( nc, constituents );
812 nc->SetConstituentNetclasses( std::move( constituents ) );
813 }
814}
815
816
817void NET_SETTINGS::makeEffectiveNetclass( std::shared_ptr<NETCLASS>& effectiveNetclass,
818 std::vector<NETCLASS*>& constituentNetclasses ) const
819{
820 // Sort the resolved netclasses by priority (highest first), with same-priority netclasses
821 // ordered alphabetically
822 std::sort( constituentNetclasses.begin(), constituentNetclasses.end(),
823 []( NETCLASS* nc1, NETCLASS* nc2 )
824 {
825 int p1 = nc1->GetPriority();
826 int p2 = nc2->GetPriority();
827
828 if( p1 < p2 )
829 return true;
830
831 if (p1 == p2)
832 return nc1->GetName().Cmp( nc2->GetName() ) < 0;
833
834 return false;
835 } );
836
837 // Iterate from lowest priority netclass and fill effective netclass parameters
838 for( auto itr = constituentNetclasses.rbegin(); itr != constituentNetclasses.rend(); ++itr )
839 {
840 NETCLASS* nc = *itr;
841
842 if( nc->HasClearance() )
843 {
844 effectiveNetclass->SetClearance( nc->GetClearance() );
845 effectiveNetclass->SetClearanceParent( nc );
846 }
847
848 if( nc->HasTrackWidth() )
849 {
850 effectiveNetclass->SetTrackWidth( nc->GetTrackWidth() );
851 effectiveNetclass->SetTrackWidthParent( nc );
852 }
853
854 if( nc->HasViaDiameter() )
855 {
856 effectiveNetclass->SetViaDiameter( nc->GetViaDiameter() );
857 effectiveNetclass->SetViaDiameterParent( nc );
858 }
859
860 if( nc->HasViaDrill() )
861 {
862 effectiveNetclass->SetViaDrill( nc->GetViaDrill() );
863 effectiveNetclass->SetViaDrillParent( nc );
864 }
865
866 if( nc->HasuViaDiameter() )
867 {
868 effectiveNetclass->SetuViaDiameter( nc->GetuViaDiameter() );
869 effectiveNetclass->SetuViaDiameterParent( nc );
870 }
871
872 if( nc->HasuViaDrill() )
873 {
874 effectiveNetclass->SetuViaDrill( nc->GetuViaDrill() );
875 effectiveNetclass->SetuViaDrillParent( nc );
876 }
877
878 if( nc->HasDiffPairWidth() )
879 {
880 effectiveNetclass->SetDiffPairWidth( nc->GetDiffPairWidth() );
881 effectiveNetclass->SetDiffPairWidthParent( nc );
882 }
883
884 if( nc->HasDiffPairGap() )
885 {
886 effectiveNetclass->SetDiffPairGap( nc->GetDiffPairGap() );
887 effectiveNetclass->SetDiffPairGapParent( nc );
888 }
889
890 if( nc->HasDiffPairViaGap() )
891 {
892 effectiveNetclass->SetDiffPairViaGap( nc->GetDiffPairViaGap() );
893 effectiveNetclass->SetDiffPairViaGapParent( nc );
894 }
895
896 if( nc->HasWireWidth() )
897 {
898 effectiveNetclass->SetWireWidth( nc->GetWireWidth() );
899 effectiveNetclass->SetWireWidthParent( nc );
900 }
901
902 if( nc->HasBusWidth() )
903 {
904 effectiveNetclass->SetBusWidth( nc->GetBusWidth() );
905 effectiveNetclass->SetBusWidthParent( nc );
906 }
907
908 if( nc->HasLineStyle() )
909 {
910 effectiveNetclass->SetLineStyle( nc->GetLineStyle() );
911 effectiveNetclass->SetLineStyleParent( nc );
912 }
913
914 COLOR4D pcbColor = nc->GetPcbColor();
915
916 if( pcbColor != COLOR4D::UNSPECIFIED )
917 {
918 effectiveNetclass->SetPcbColor( pcbColor );
919 effectiveNetclass->SetPcbColorParent( nc );
920 }
921
922 COLOR4D schColor = nc->GetSchematicColor();
923
924 if( schColor != COLOR4D::UNSPECIFIED )
925 {
926 effectiveNetclass->SetSchematicColor( schColor );
927 effectiveNetclass->SetSchematicColorParent( nc );
928 }
929
930 if( nc->HasTuningProfile() )
931 {
932 effectiveNetclass->SetTuningProfile( nc->GetTuningProfile() );
933 effectiveNetclass->SetTuningProfileParent( nc );
934 }
935 }
936
937 // Fill in any required defaults
938 if( addMissingDefaults( effectiveNetclass.get() ) )
939 constituentNetclasses.push_back( m_defaultNetClass.get() );
940}
941
942
944{
945 bool addedDefault = false;
946
947 if( !nc->HasClearance() )
948 {
949 addedDefault = true;
950 nc->SetClearance( m_defaultNetClass->GetClearance() );
952 }
953
954 if( !nc->HasTrackWidth() )
955 {
956 addedDefault = true;
957 nc->SetTrackWidth( m_defaultNetClass->GetTrackWidth() );
959 }
960
961 if( !nc->HasViaDiameter() )
962 {
963 addedDefault = true;
964 nc->SetViaDiameter( m_defaultNetClass->GetViaDiameter() );
966 }
967
968 if( !nc->HasViaDrill() )
969 {
970 addedDefault = true;
971 nc->SetViaDrill( m_defaultNetClass->GetViaDrill() );
973 }
974
975 if( !nc->HasuViaDiameter() )
976 {
977 addedDefault = true;
978 nc->SetuViaDiameter( m_defaultNetClass->GetuViaDiameter() );
980 }
981
982 if( !nc->HasuViaDrill() )
983 {
984 addedDefault = true;
985 nc->SetuViaDrill( m_defaultNetClass->GetuViaDrill() );
987 }
988
989 if( !nc->HasDiffPairWidth() )
990 {
991 addedDefault = true;
992 nc->SetDiffPairWidth( m_defaultNetClass->GetDiffPairWidth() );
994 }
995
996 if( !nc->HasDiffPairGap() )
997 {
998 addedDefault = true;
999 nc->SetDiffPairGap( m_defaultNetClass->GetDiffPairGap() );
1001 }
1002
1003 // Currently this is only on the default netclass, and not editable in the setup panel
1004 // if( !nc->HasDiffPairViaGap() )
1005 // {
1006 // addedDefault = true;
1007 // nc->SetDiffPairViaGap( m_defaultNetClass->GetDiffPairViaGap() );
1008 // nc->SetDiffPairViaGapParent( m_defaultNetClass.get() );
1009 // }
1010
1011 if( !nc->HasWireWidth() )
1012 {
1013 addedDefault = true;
1014 nc->SetWireWidth( m_defaultNetClass->GetWireWidth() );
1016 }
1017
1018 if( !nc->HasBusWidth() )
1019 {
1020 addedDefault = true;
1021 nc->SetBusWidth( m_defaultNetClass->GetBusWidth() );
1023 }
1024
1025 // The tuning profile can be empty - only fill if a default tuning profile is set
1026 if( !nc->HasTuningProfile() && m_defaultNetClass->HasTuningProfile() )
1027 {
1028 addedDefault = true;
1029 nc->SetTuningProfile( m_defaultNetClass->GetTuningProfile() );
1031 }
1032
1033 return addedDefault;
1034}
1035
1036
1037std::shared_ptr<NETCLASS> NET_SETTINGS::GetNetClassByName( const wxString& aNetClassName ) const
1038{
1039 auto ii = m_netClasses.find( aNetClassName );
1040
1041 if( ii == m_netClasses.end() )
1042 return m_defaultNetClass;
1043 else
1044 return ii->second;
1045}
1046
1047
1048static bool isSuperSubOverbar( wxChar c )
1049{
1050 return c == '_' || c == '^' || c == '~';
1051}
1052
1053
1054bool NET_SETTINGS::ParseBusVector( const wxString& aBus, wxString* aName,
1055 std::vector<wxString>* aMemberList )
1056{
1057 auto isDigit =
1058 []( wxChar c )
1059 {
1060 static wxString digits( wxT( "0123456789" ) );
1061 return digits.Contains( c );
1062 };
1063
1064 size_t busLen = aBus.length();
1065 size_t i = 0;
1066 wxString prefix;
1067 wxString suffix;
1068 wxString tmp;
1069 long begin = 0;
1070 long end = 0;
1071 int braceNesting = 0;
1072
1073 prefix.reserve( busLen );
1074
1075 // Parse prefix
1076 //
1077 for( ; i < busLen; ++i )
1078 {
1079 if( aBus[i] == '{' )
1080 {
1081 if( i > 0 && isSuperSubOverbar( aBus[i-1] ) )
1082 braceNesting++;
1083 else
1084 return false;
1085 }
1086 else if( aBus[i] == '}' )
1087 {
1088 braceNesting--;
1089 }
1090
1091 if( aBus[i] == ' ' || aBus[i] == ']' )
1092 return false;
1093
1094 if( aBus[i] == '[' )
1095 break;
1096
1097 prefix += aBus[i];
1098 }
1099
1100 // Parse start number
1101 //
1102 i++; // '[' character
1103
1104 if( i >= busLen )
1105 return false;
1106
1107 for( ; i < busLen; ++i )
1108 {
1109 if( aBus[i] == '.' && i + 1 < busLen && aBus[i+1] == '.' )
1110 {
1111 tmp.ToLong( &begin );
1112 i += 2;
1113 break;
1114 }
1115
1116 if( !isDigit( aBus[i] ) )
1117 return false;
1118
1119 tmp += aBus[i];
1120 }
1121
1122 // Parse end number
1123 //
1124 tmp = wxEmptyString;
1125
1126 if( i >= busLen )
1127 return false;
1128
1129 for( ; i < busLen; ++i )
1130 {
1131 if( aBus[i] == ']' )
1132 {
1133 tmp.ToLong( &end );
1134 ++i;
1135 break;
1136 }
1137
1138 if( !isDigit( aBus[i] ) )
1139 return false;
1140
1141 tmp += aBus[i];
1142 }
1143
1144 // Parse suffix
1145 //
1146 for( ; i < busLen; ++i )
1147 {
1148 if( aBus[i] == '}' )
1149 {
1150 braceNesting--;
1151 }
1152 else if( aBus[i] == '+' || aBus[i] == '-' || aBus[i] == 'P' || aBus[i] == 'N' )
1153 {
1154 suffix += aBus[i];
1155 }
1156 else
1157 {
1158 return false;
1159 }
1160 }
1161
1162 if( braceNesting != 0 )
1163 return false;
1164
1165 if( begin == end )
1166 return false;
1167 else if( begin > end )
1168 std::swap( begin, end );
1169
1170 if( aName )
1171 *aName = prefix;
1172
1173 if( aMemberList )
1174 {
1175 for( long idx = begin; idx <= end; ++idx )
1176 {
1177 wxString str = prefix;
1178 str << idx;
1179 str << suffix;
1180
1181 aMemberList->emplace_back( str );
1182 }
1183 }
1184
1185 return true;
1186}
1187
1188
1189bool NET_SETTINGS::ParseBusGroup( const wxString& aGroup, wxString* aName,
1190 std::vector<wxString>* aMemberList )
1191{
1192 size_t groupLen = aGroup.length();
1193 size_t i = 0;
1194 wxString prefix;
1195 wxString tmp;
1196 int braceNesting = 0;
1197
1198 prefix.reserve( groupLen );
1199
1200 // Parse prefix
1201 //
1202 for( ; i < groupLen; ++i )
1203 {
1204 if( aGroup[i] == '{' )
1205 {
1206 if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
1207 braceNesting++;
1208 else
1209 break;
1210 }
1211 else if( aGroup[i] == '}' )
1212 {
1213 braceNesting--;
1214 }
1215
1216 if( aGroup[i] == ' ' || aGroup[i] == '[' || aGroup[i] == ']' )
1217 return false;
1218
1219 prefix += aGroup[i];
1220 }
1221
1222 if( braceNesting != 0 )
1223 return false;
1224
1225 if( aName )
1226 *aName = prefix;
1227
1228 // Parse members
1229 //
1230 i++; // '{' character
1231
1232 if( i >= groupLen )
1233 return false;
1234
1235 for( ; i < groupLen; ++i )
1236 {
1237 if( aGroup[i] == '{' )
1238 {
1239 if( i > 0 && isSuperSubOverbar( aGroup[i-1] ) )
1240 braceNesting++;
1241 else
1242 return false;
1243 }
1244 else if( aGroup[i] == '}' )
1245 {
1246 if( braceNesting )
1247 {
1248 braceNesting--;
1249 }
1250 else
1251 {
1252 if( aMemberList && !tmp.IsEmpty() )
1253 aMemberList->push_back( EscapeString( tmp, CTX_NETNAME ) );
1254
1255 return true;
1256 }
1257 }
1258
1259 // Commas aren't strictly legal, but we can be pretty sure what the author had in mind.
1260 if( aGroup[i] == ' ' || aGroup[i] == ',' )
1261 {
1262 if( aMemberList && !tmp.IsEmpty() )
1263 aMemberList->push_back( EscapeString( tmp, CTX_NETNAME ) );
1264
1265 tmp.Clear();
1266 continue;
1267 }
1268
1269 tmp += aGroup[i];
1270 }
1271
1272 return false;
1273}
int color
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:398
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
void registerMigration(int aOldSchemaVersion, int aNewSchemaVersion, std::function< bool(void)> aMigrator)
Registers a migration from one schema version to another.
JSON_SETTINGS(const wxString &aFilename, SETTINGS_LOC aLocation, int aSchemaVersion)
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
NESTED_SETTINGS(const std::string &aName, int aSchemaVersion, JSON_SETTINGS *aParent, const std::string &aPath, bool aLoadFromFile=true)
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
void SetViaDiameter(int aDia)
Definition netclass.h:135
void SetViaDrill(int aSize)
Definition netclass.h:143
bool HasLineStyle() const
Definition netclass.h:233
int GetViaDiameter() const
Definition netclass.h:133
int GetViaDrill() const
Definition netclass.h:141
void SetWireWidthParent(NETCLASS *parent)
Definition netclass.h:208
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:47
void SetuViaDrillParent(NETCLASS *parent)
Definition netclass.h:161
bool HasBusWidth() const
Definition netclass.h:211
bool HasuViaDrill() const
Definition netclass.h:156
void SetDiffPairWidthParent(NETCLASS *parent)
Definition netclass.h:169
void SetuViaDiameter(int aSize)
Definition netclass.h:151
void SetDiffPairWidth(int aSize)
Definition netclass.h:167
int HasViaDrill() const
Definition netclass.h:140
int GetDiffPairViaGap() const
Definition netclass.h:181
void SetViaDrillParent(NETCLASS *parent)
Definition netclass.h:145
wxString GetTuningProfile() const
Definition netclass.h:246
void SetDiffPairGapParent(NETCLASS *parent)
Definition netclass.h:177
void SetTuningProfileParent(NETCLASS *aParent)
Definition netclass.h:247
int GetDiffPairGap() const
Definition netclass.h:173
int GetuViaDrill() const
Definition netclass.h:157
bool HasViaDiameter() const
Definition netclass.h:132
int GetLineStyle() const
Definition netclass.h:234
bool HasDiffPairWidth() const
Definition netclass.h:164
bool HasuViaDiameter() const
Definition netclass.h:148
void SetTrackWidthParent(NETCLASS *parent)
Definition netclass.h:129
int GetuViaDiameter() const
Definition netclass.h:149
bool HasTrackWidth() const
Definition netclass.h:124
void SetViaDiameterParent(NETCLASS *parent)
Definition netclass.h:137
int GetDiffPairWidth() const
Definition netclass.h:165
void SetuViaDrill(int aSize)
Definition netclass.h:159
int GetWireWidth() const
Definition netclass.h:204
void SetDiffPairGap(int aSize)
Definition netclass.h:175
void SetBusWidthParent(NETCLASS *parent)
Definition netclass.h:216
void SetClearance(int aClearance)
Definition netclass.h:119
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition netclass.h:189
bool HasDiffPairGap() const
Definition netclass.h:172
COLOR4D GetSchematicColor(bool aIsForSave=false) const
Definition netclass.h:219
void SetBusWidth(int aWidth)
Definition netclass.h:214
void SetClearanceParent(NETCLASS *parent)
Definition netclass.h:121
int GetTrackWidth() const
Definition netclass.h:125
void SetWireWidth(int aWidth)
Definition netclass.h:206
void SetTuningProfile(const wxString &aTuningProfile)
Definition netclass.h:245
bool HasTuningProfile() const
Definition netclass.h:244
bool HasWireWidth() const
Definition netclass.h:203
int GetClearance() const
Definition netclass.h:117
void SetuViaDiameterParent(NETCLASS *parent)
Definition netclass.h:153
void SetTrackWidth(int aWidth)
Definition netclass.h:127
bool HasDiffPairViaGap() const
Definition netclass.h:180
int GetBusWidth() const
Definition netclass.h:212
bool HasClearance() const
Definition netclass.h:116
void ClearAllCaches()
Clears the effective netclass cache for all nets.
std::map< wxString, std::shared_ptr< NETCLASS > > m_compositeNetClasses
Map of netclass names to netclass definitions for.
bool addMissingDefaults(NETCLASS *nc) const
Adds any missing fields to the given netclass from the default netclass.
void ClearNetColorAssignments()
Clears all net name to color assignments Calling user is responsible for resetting the effective netc...
bool operator==(const NET_SETTINGS &aOther) const
void ClearCacheForNet(const wxString &netName)
Clears effective netclass cache for the given net.
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const wxString &aNetName)
Fetches the effective (may be aggregate) netclass for the given net name.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
void ClearNetclassLabelAssignments()
Clears all net name to netclasses assignments Calling user is responsible for resetting the effective...
void ClearNetclassLabelAssignment(const wxString &netName)
Clears a specific net name to netclass assignment Calling user is responsible for resetting the effec...
void ClearNetclassPatternAssignments()
Clears all netclass pattern assignments.
std::map< wxString, KIGFX::COLOR4D > m_netColorAssignments
A map of fully-qualified net names to colors used in the board context.
void SetNetclasses(const std::map< wxString, std::shared_ptr< NETCLASS > > &netclasses)
Sets all netclass Calling this method will reset the effective netclass calculation caches.
bool HasNetclassLabelAssignment(const wxString &netName) const
Determines if a given net name has netclasses assigned.
void SetNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Sets a net name to netclasses assignment Calling user is responsible for resetting the effective netc...
std::shared_ptr< NETCLASS > m_defaultNetClass
The default netclass.
virtual ~NET_SETTINGS()
static bool ParseBusGroup(const wxString &aGroup, wxString *name, std::vector< wxString > *aMemberList)
Parse a bus group label into the name and a list of components.
void ClearNetclasses()
Clears all netclasses Calling this method will reset the effective netclass calculation caches.
std::map< wxString, std::shared_ptr< NETCLASS > > m_impicitNetClasses
Map of netclass names to netclass definitions for implicit netclasses.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetCompositeNetclasses() const
Gets all composite (multiple assignment / missing defaults) netclasses.
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > m_netClassPatternAssignments
List of net class pattern assignments.
bool migrateSchema3to4()
bool migrateSchema0to1()
std::map< wxString, std::shared_ptr< NETCLASS > > m_effectiveNetclassCache
Cache of nets to pattern-matched netclasses.
void SetNetclassPatternAssignments(std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > &&netclassPatterns)
Sets all netclass pattern assignments Calling user is responsible for resetting the effective netclas...
void SetNetclassPatternAssignment(const wxString &pattern, const wxString &netclass)
Sets a netclass pattern assignment Calling this method will reset the effective netclass calculation ...
bool migrateSchema2to3()
std::map< wxString, std::shared_ptr< NETCLASS > > m_netClasses
Map of netclass names to netclass definitions.
const std::map< wxString, std::set< wxString > > & GetNetclassLabelAssignments() const
Gets all current net name to netclasses assignments.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetNetclasses() const
Gets all netclasses.
std::shared_ptr< NETCLASS > GetDefaultNetclass()
Gets the default netclass for the project.
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parse a bus vector (e.g.
const std::map< wxString, KIGFX::COLOR4D > & GetNetColorAssignments() const
Gets all net name to color assignments.
bool migrateSchema1to2()
std::vector< std::pair< std::unique_ptr< EDA_COMBINED_MATCHER >, wxString > > & GetNetclassPatternAssignments()
Gets the netclass pattern assignments.
void RecomputeEffectiveNetclasses()
Recomputes the internal values of all aggregate effective netclasses Called when a value of a user-de...
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
bool migrateSchema4to5()
std::map< wxString, std::set< wxString > > m_netClassLabelAssignments
Map of net names to resolved netclasses.
void SetNetclass(const wxString &netclassName, std::shared_ptr< NETCLASS > &netclass)
Sets the given netclass Calling user is responsible for resetting the effective netclass calculation ...
void makeEffectiveNetclass(std::shared_ptr< NETCLASS > &effectiveNetclass, std::vector< NETCLASS * > &netclasses) const
Creates an effective aggregate netclass from the given constituent netclasses.
void AppendNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Apppends to a net name to netclasses assignment Calling user is responsible for resetting the effecti...
void SetDefaultNetclass(std::shared_ptr< NETCLASS > netclass)
Sets the default netclass for the project Calling user is responsible for resetting the effective net...
std::shared_ptr< NETCLASS > GetNetClassByName(const wxString &aNetName) const
Get a NETCLASS object from a given Netclass name string.
void SetNetColorAssignment(const wxString &netName, const KIGFX::COLOR4D &color)
Sets a net to color assignment Calling user is responsible for resetting the effective netclass calcu...
NET_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
bool HasNetclass(const wxString &netclassName) const
Determines if the given netclass exists.
Like a normal param, but with custom getter and setter functions.
Definition parameters.h:296
bool isDigit(char cc)
Definition dsnlexer.cpp:469
#define _(s)
@ CTX_NETCLASS
nlohmann::json json
Definition gerbview.cpp:50
static bool isSuperSubOverbar(wxChar c)
const int netSettingsSchemaVersion
static std::optional< int > getInSchUnits(const nlohmann::json &aObj, const std::string &aKey, std::optional< int > aDefault=std::optional< int >())
static std::optional< int > getInPcbUnits(const nlohmann::json &aObj, const std::string &aKey, std::optional< int > aDefault=std::optional< int >())
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
VECTOR2I end