KiCad PCB EDA Suite
footprint_editor_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 Jon Evans <[email protected]>
5  * Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <common.h>
23 #include <layer_ids.h>
24 #include <pgm_base.h>
27 #include <settings/parameters.h>
29 #include <wx/config.h>
30 #include <base_units.h>
31 #include <widgets/ui_common.h>
32 #include <wx/log.h>
33 #include <pcbnew.h>
34 
35 
37 const int fpEditSchemaVersion = 1;
38 
39 
42  m_DesignSettings( nullptr, "fpedit.settings" ),
43  m_MagneticItems(),
44  m_Display(),
45  m_UserGrid(),
46  m_PolarCoords( false ),
47  m_Use45Limit( true ),
48  m_LibWidth( 250 ),
49  m_LastImportExportPath(),
50  m_FootprintTextShownColumns()
51 {
55 
59 
60  m_params.emplace_back( new PARAM<int>( "window.lib_width",
61  &m_LibWidth, 250 ) );
62 
63  m_params.emplace_back( new PARAM<bool>( "aui.show_layer_manager",
65 
66  m_params.emplace_back( new PARAM<int>( "aui.right_panel_width",
68 
69  m_params.emplace_back( new PARAM<int>( "aui.appearance_panel_tab",
70  &m_AuiPanels.appearance_panel_tab, 0, 0, 2 ) );
71 
72  m_params.emplace_back( new PARAM<wxString>( "system.last_import_export_path",
73  &m_LastImportExportPath, "" ) );
74 
75  m_params.emplace_back( new PARAM<wxString>( "window.footprint_text_shown_columns",
76  &m_FootprintTextShownColumns, "0 1 2 3 4 5 6" ) );
77 
78  m_params.emplace_back( new PARAM<int>( "editing.magnetic_pads",
79  reinterpret_cast<int*>( &m_MagneticItems.pads ),
80  static_cast<int>( MAGNETIC_OPTIONS::CAPTURE_ALWAYS ) ) );
81 
82  m_params.emplace_back( new PARAM<bool>( "editing.magnetic_graphics",
83  &m_MagneticItems.graphics, true ) );
84 
85  m_params.emplace_back( new PARAM<bool>( "editing.polar_coords", &m_PolarCoords, false ) );
86 
87  m_params.emplace_back( new PARAM<bool>( "editing.use_45_degree_limit",
88  &m_Use45Limit, false ) );
89 
90  m_params.emplace_back( new PARAM<bool>( "pcb_display.text_fill",
91  &m_Display.m_DisplayTextFill, true ) );
92 
93  m_params.emplace_back( new PARAM<bool>( "pcb_display.graphic_items_fill",
95 
96  m_params.emplace_back( new PARAM<bool>( "pcb_display.pad_fill",
97  &m_Display.m_DisplayPadFill, true ) );
98 
99  m_params.emplace_back( new PARAM_LAYER_PRESET( "pcb_display.layer_presets", &m_LayerPresets ) );
100 
101  m_params.emplace_back( new PARAM<wxString>( "pcb_display.active_layer_preset",
102  &m_ActiveLayerPreset, "" ) );
103 
104  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>(
105  "design_settings.default_footprint_text_items",
106  [&] () -> nlohmann::json
107  {
108  nlohmann::json js = nlohmann::json::array();
109 
111  {
112  js.push_back( nlohmann::json( { item.m_Text.ToUTF8(),
113  item.m_Visible,
114  item.m_Layer } ) );
115  }
116 
117  return js;
118  },
119  [&] ( const nlohmann::json& aObj )
120  {
122 
123  if( !aObj.is_array() )
124  return;
125 
126  for( const nlohmann::json& entry : aObj )
127  {
128  if( entry.empty() || !entry.is_array() )
129  continue;
130 
131  TEXT_ITEM_INFO textInfo( wxEmptyString, true, F_SilkS );
132 
133  textInfo.m_Text = entry.at(0).get<wxString>();
134  textInfo.m_Visible = entry.at(1).get<bool>();
135  textInfo.m_Layer = entry.at(2).get<int>();
136 
137  m_DesignSettings.m_DefaultFPTextItems.push_back( std::move( textInfo ) );
138  }
139  },
140  nlohmann::json::array( {
141  { "REF**", true, F_SilkS },
142  { "", true, F_Fab },
143  { "${REFERENCE}", true, F_Fab }
144  } ) ) );
145 
146  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_line_width",
149  MM_PER_IU ) );
150 
151  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_text_size_h",
154 
155  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_text_size_v",
158 
159  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.silk_text_thickness",
162 
163  m_params.emplace_back( new PARAM<bool>( "design_settings.silk_text_italic",
165 
166  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_line_width",
169  MM_PER_IU ) );
170 
171  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_text_size_h",
174  MM_PER_IU ) );
175 
176  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_text_size_v",
179  MM_PER_IU ) );
180 
181  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.copper_text_thickness",
184  MM_PER_IU ) );
185 
186  m_params.emplace_back( new PARAM<bool>( "design_settings.copper_text_italic",
188 
189  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.edge_line_width",
192  MM_PER_IU ) );
193 
194  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.courtyard_line_width",
197  MM_PER_IU ) );
198 
199  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_line_width",
202  MM_PER_IU ) );
203 
204  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_text_size_h",
207 
208  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_text_size_v",
211 
212  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.fab_text_thickness",
214  Millimeter2iu( DEFAULT_TEXT_WIDTH ), 1, TEXTS_MAX_WIDTH, MM_PER_IU ) );
215 
216  m_params.emplace_back( new PARAM<bool>( "design_settings.fab_text_italic",
218 
219  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_line_width",
222  MM_PER_IU ) );
223 
224  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_text_size_h",
227 
228  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_text_size_v",
231 
232  m_params.emplace_back( new PARAM_SCALED<int>( "design_settings.others_text_thickness",
234  Millimeter2iu( DEFAULT_TEXT_WIDTH ), 1, TEXTS_MAX_WIDTH, MM_PER_IU ) );
235 
236  m_params.emplace_back( new PARAM<bool>( "design_settings.others_text_italic",
238 
239  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "editing.selection_filter",
240  [&]() -> nlohmann::json
241  {
242  nlohmann::json ret;
243 
244  ret["lockedItems"] = m_SelectionFilter.lockedItems;
245  ret["footprints"] = m_SelectionFilter.footprints;
246  ret["text"] = m_SelectionFilter.text;
247  ret["tracks"] = m_SelectionFilter.tracks;
248  ret["vias"] = m_SelectionFilter.vias;
249  ret["pads"] = m_SelectionFilter.pads;
250  ret["graphics"] = m_SelectionFilter.graphics;
251  ret["zones"] = m_SelectionFilter.zones;
252  ret["keepouts"] = m_SelectionFilter.keepouts;
253  ret["dimensions"] = m_SelectionFilter.dimensions;
254  ret["otherItems"] = m_SelectionFilter.otherItems;
255 
256  return ret;
257  },
258  [&]( const nlohmann::json& aVal )
259  {
260  if( aVal.empty() || !aVal.is_object() )
261  return;
262 
263  SetIfPresent( aVal, "lockedItems", m_SelectionFilter.lockedItems );
264  SetIfPresent( aVal, "footprints", m_SelectionFilter.footprints );
265  SetIfPresent( aVal, "text", m_SelectionFilter.text );
266  SetIfPresent( aVal, "tracks", m_SelectionFilter.tracks );
267  SetIfPresent( aVal, "vias", m_SelectionFilter.vias );
268  SetIfPresent( aVal, "pads", m_SelectionFilter.pads );
269  SetIfPresent( aVal, "graphics", m_SelectionFilter.graphics );
270  SetIfPresent( aVal, "zones", m_SelectionFilter.zones );
271  SetIfPresent( aVal, "keepouts", m_SelectionFilter.keepouts );
272  SetIfPresent( aVal, "dimensions", m_SelectionFilter.dimensions );
273  SetIfPresent( aVal, "otherItems", m_SelectionFilter.otherItems );
274  },
275  {
276  { "lockedItems", true },
277  { "footprints", true },
278  { "text", true },
279  { "tracks", true },
280  { "vias", true },
281  { "pads", true },
282  { "graphics", true },
283  { "zones", true },
284  { "keepouts", true },
285  { "dimensions", true },
286  { "otherItems", true }
287  } ) );
288 
290 }
291 
292 
294 {
295  bool ret = APP_SETTINGS_BASE::MigrateFromLegacy( aCfg );
296 
297  //
298  // NOTE: there's no value in line-wrapping these; it just makes the table unreadable.
299  //
300  ret &= fromLegacy<int>( aCfg, "ModeditLibWidth", "window.lib_width" );
301  ret &= fromLegacyString( aCfg, "import_last_path", "system.last_import_export_path" );
302  ret &= fromLegacyString( aCfg, "LibFootprintTextShownColumns", "window.footprint_text_shown_columns" );
303 
304  ret &= fromLegacy<int>( aCfg, "FpEditorMagneticPads", "editing.magnetic_pads" );
305  ret &= fromLegacy<bool>( aCfg, "FpEditorDisplayPolarCoords", "editing.polar_coords" );
306  ret &= fromLegacy<int>( aCfg, "FpEditorUse45DegreeGraphicSegments", "editing.use_45_degree_graphic_segments" );
307 
308  ret &= fromLegacy<bool>( aCfg, "FpEditorGraphicLinesDisplayMode", "pcb_display.graphic_items_fill" );
309  ret &= fromLegacy<bool>( aCfg, "FpEditorPadDisplayMode", "pcb_display.pad_fill" );
310  ret &= fromLegacy<bool>( aCfg, "FpEditorTextsDisplayMode", "pcb_display.footprint_text" );
311 
312  ret &= fromLegacy<double>( aCfg, "FpEditorSilkLineWidth", "design_settings.silk_line_width" );
313  ret &= fromLegacy<double>( aCfg, "FpEditorSilkTextSizeH", "design_settings.silk_text_size_h" );
314  ret &= fromLegacy<double>( aCfg, "FpEditorSilkTextSizeV", "design_settings.silk_text_size_v" );
315  ret &= fromLegacy<double>( aCfg, "FpEditorSilkTextThickness", "design_settings.silk_text_thickness" );
316  ret &= fromLegacy<bool>( aCfg, "FpEditorSilkTextItalic", "design_settings.silk_text_italic" );
317  ret &= fromLegacy<double>( aCfg, "FpEditorCopperLineWidth", "design_settings.copper_line_width" );
318  ret &= fromLegacy<double>( aCfg, "FpEditorCopperTextSizeH", "design_settings.copper_text_size_h" );
319  ret &= fromLegacy<double>( aCfg, "FpEditorCopperTextSizeV", "design_settings.copper_text_size_v" );
320  ret &= fromLegacy<double>( aCfg, "FpEditorCopperTextThickness", "design_settings.copper_text_thickness" );
321  ret &= fromLegacy<bool>( aCfg, "FpEditorCopperTextItalic", "design_settings.copper_text_italic" );
322  ret &= fromLegacy<double>( aCfg, "FpEditorEdgeCutLineWidth", "design_settings.edge_line_width" );
323  ret &= fromLegacy<double>( aCfg, "FpEditorCourtyardLineWidth", "design_settings.courtyard_line_width" );
324  ret &= fromLegacy<double>( aCfg, "FpEditorOthersLineWidth", "design_settings.others_line_width" );
325  ret &= fromLegacy<double>( aCfg, "FpEditorOthersTextSizeH", "design_settings.others_text_size_h" );
326  ret &= fromLegacy<double>( aCfg, "FpEditorOthersTextSizeV", "design_settings.others_text_size_v" );
327  ret &= fromLegacy<double>( aCfg, "FpEditorOthersTextThickness", "design_settings.others_text_thickness" );
328  ret &= fromLegacy<bool>( aCfg, "FpEditorOthersTextItalic", "design_settings.others_text_italic" );
329 
330  nlohmann::json textItems = nlohmann::json::array( {
331  { "REF**", true, F_SilkS },
332  { "", true, F_Fab }
333  } );
334 
335  Set( "design_settings.default_footprint_text_items", textItems );
336 
337  ret &= fromLegacyString( aCfg, "FpEditorRefDefaultText", "design_settings.default_footprint_text_items.0.0" );
338  ret &= fromLegacy<bool>( aCfg, "FpEditorRefDefaultVisibility", "design_settings.default_footprint_text_items.0.1" );
339  ret &= fromLegacy<int>( aCfg, "FpEditorRefDefaultLayer", "design_settings.default_footprint_text_items.0.2" );
340  ret &= fromLegacyString( aCfg, "FpEditorValueDefaultText", "design_settings.default_footprint_text_items.1.0" );
341  ret &= fromLegacy<bool>( aCfg, "FpEditorValueDefaultVisibility", "design_settings.default_footprint_text_items.1.1" );
342  ret &= fromLegacy<int>( aCfg, "FpEditorValueDefaultLayer", "design_settings.default_footprint_text_items.1.2" );
343 
344 
345  std::string f = "ModEdit";
346 
347  // Migrate color settings that were stored in the pcbnew config file
348  // We create a copy of the user scheme for the footprint editor context
349 
350  SETTINGS_MANAGER& manager = Pgm().GetSettingsManager();
351  COLOR_SETTINGS* cs = manager.AddNewColorSettings( "user_footprints" );
352 
353  cs->SetName( wxT( "User (Footprints)" ) );
354  manager.Save( cs );
355 
356  auto migrateLegacyColor = [&] ( const std::string& aKey, int aLayerId )
357  {
358  wxString str;
359 
360  if( aCfg->Read( aKey, &str ) )
361  cs->SetColor( aLayerId, COLOR4D( str ) );
362  };
363 
364  for( int i = 0; i < PCB_LAYER_ID_COUNT; ++i )
365  {
366  wxString layer = LSET::Name( PCB_LAYER_ID( i ) );
367  migrateLegacyColor( f + "Color4DPCBLayer_" + layer.ToStdString(), PCB_LAYER_ID( i ) );
368  }
369 
370  migrateLegacyColor( f + "Color4DAnchorEx", LAYER_ANCHOR );
371  migrateLegacyColor( f + "Color4DAuxItems", LAYER_AUX_ITEMS );
372  migrateLegacyColor( f + "Color4DGrid", LAYER_GRID );
373  migrateLegacyColor( f + "Color4DNoNetPadMarker", LAYER_NO_CONNECTS );
374  migrateLegacyColor( f + "Color4DNonPlatedEx", LAYER_NON_PLATEDHOLES );
375  migrateLegacyColor( f + "Color4DPadThruHoleEx", LAYER_PADS_TH );
376  migrateLegacyColor( f + "Color4DPCBBackground", LAYER_PCB_BACKGROUND );
377  migrateLegacyColor( f + "Color4DPCBCursor", LAYER_CURSOR );
378  migrateLegacyColor( f + "Color4DRatsEx", LAYER_RATSNEST );
379  migrateLegacyColor( f + "Color4DTxtInvisEx", LAYER_MOD_TEXT_INVISIBLE );
380  migrateLegacyColor( f + "Color4DViaBBlindEx", LAYER_VIA_BBLIND );
381  migrateLegacyColor( f + "Color4DViaMicroEx", LAYER_VIA_MICROVIA );
382  migrateLegacyColor( f + "Color4DViaThruEx", LAYER_VIA_THROUGH );
383  migrateLegacyColor( f + "Color4DWorksheet", LAYER_DRAWINGSHEET );
384 
385  manager.SaveColorSettings( cs, "board" );
386 
387  ( *m_internals )[m_internals->PointerFromString( "appearance.color_theme" )] = "user_footprints";
388 
389  double x, y;
390  f = "ModEditFrame";
391 
392  if( aCfg->Read( f + "PcbUserGrid_X", &x ) && aCfg->Read( f + "PcbUserGrid_Y", &y ) )
393  {
394  EDA_UNITS u = static_cast<EDA_UNITS>( aCfg->ReadLong( f + "PcbUserGrid_Unit",
395  static_cast<long>( EDA_UNITS::INCHES ) ) );
396 
397  // Convert to internal units
398  x = From_User_Unit( u, x );
399  y = From_User_Unit( u, y );
400 
401  Set( "window.grid.user_grid_x", StringFromValue( u, x ) );
402  Set( "window.grid.user_grid_y", StringFromValue( u, y ) );
403  }
404 
405  return ret;
406 }
407 
408 
410 {
418  if( !m_manager )
419  {
420  wxLogTrace( traceSettings,
421  wxT( "Error: FOOTPRINT_EDITOR_SETTINGS migration cannot run unmanaged!" ) );
422  return false;
423  }
424 
425  std::string theme_ptr( "appearance.color_theme" );
426 
427  if( !Count( theme_ptr ) )
428  return true;
429 
430  wxString selected = At( theme_ptr ).get<wxString>();
431  wxString search = selected + wxT( "_footprints" );
432 
433  for( COLOR_SETTINGS* settings : Pgm().GetSettingsManager().GetColorSettingsList() )
434  {
435  if( settings->GetFilename() == search )
436  {
437  wxLogTrace( traceSettings, wxT( "Updating footprint editor theme from %s to %s" ),
438  selected, search );
439  Set( theme_ptr, search );
440  return true;
441  }
442  }
443 
444  return true;
445 }
#define DEFAULT_SILK_TEXT_WIDTH
to draw micro vias
Definition: layer_ids.h:201
#define DEFAULT_COURTYARD_WIDTH
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:229
void Set(const std::string &aPath, ValueType aVal)
Stores a value into the JSON document Will throw an exception if ValueType isn't something that the l...
bool otherItems
Anything not fitting one of the above categories.
std::vector< TEXT_ITEM_INFO > m_DefaultFPTextItems
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
#define TEXTS_MAX_WIDTH
Maximum text width in internal units (10 inches)
Definition: pcbnew.h:33
Implementation of conversion functions that require both schematic and board internal units.
PCB cursor.
Definition: layer_ids.h:228
virtual bool MigrateFromLegacy(wxConfigBase *aCfg) override
Migrates from wxConfig to JSON-based configuration.
#define DEFAULT_LINE_WIDTH
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:208
#define DEFAULT_COPPER_LINE_WIDTH
void SetColor(int aLayer, const COLOR4D &aColor)
COLOR_SETTINGS * AddNewColorSettings(const wxString &aFilename)
Registers a new color settings object with the given filename.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
nlohmann::json json
Definition: gerbview.cpp:41
nlohmann::json & At(const std::string &aPath)
Wrappers for the underlying JSON API so that most consumers don't need json.hpp All of these function...
to draw usual through hole vias
Definition: layer_ids.h:203
#define DEFAULT_TEXT_WIDTH
wxSize m_TextSize[LAYER_CLASS_COUNT]
const int fpEditSchemaVersion
! Update the schema version whenever a migration is required
#define DEFAULT_SILK_TEXT_SIZE
int m_TextThickness[LAYER_CLASS_COUNT]
#define DEFAULT_SILK_LINE_WIDTH
handle color for not plated holes (holes, not pads)
Definition: layer_ids.h:204
bool text
Text (free or attached to a footprint)
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:99
bool dimensions
Dimension items.
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:82
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
bool graphics
Graphic lines, shapes, polygons.
static bool SetIfPresent(const nlohmann::json &aObj, const std::string &aPath, wxString &aTarget)
Sets the given string if the given key/path is present.
text marked as invisible
Definition: layer_ids.h:207
bool m_TextItalic[LAYER_CLASS_COUNT]
Represents a parameter that has a scaling factor between the value in the file and the value used int...
Definition: parameters.h:333
Functions to provide common constants and other functions to assist in making a consistent UI.
SELECTION_FILTER_OPTIONS m_SelectionFilter
void SetName(const wxString &aName)
drawingsheet frame and titleblock
Definition: layer_ids.h:224
#define TEXTS_MAX_SIZE
Maximum text size in internal units (10 inches)
Definition: pcbnew.h:32
SETTINGS_MANAGER * GetSettingsManager()
bool footprints
Allow selecting entire footprints.
int m_LineThickness[LAYER_CLASS_COUNT]
#define TEXTS_MIN_SIZE
Minimum text size in internal units (1 mil)
Definition: pcbnew.h:31
show a marker on pads with no nets
Definition: layer_ids.h:214
EDA_UNITS
Definition: eda_units.h:38
bool fromLegacyString(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig string value to a given JSON pointer value.
bool lockedItems
Allow selecting locked items.
see class PGM_BASE
multilayer pads, usually with holes
Definition: layer_ids.h:220
to draw blind/buried vias
Definition: layer_ids.h:202
void registerMigration(int aOldSchemaVersion, int aNewSchemaVersion, std::function< bool(void)> aMigrator)
Registers a migration from one schema version to another.
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
std::vector< LAYER_PRESET > m_LayerPresets
MAGNETIC_OPTIONS pads
void SaveColorSettings(COLOR_SETTINGS *aSettings, const std::string &aNamespace="")
Safely saves a COLOR_SETTINGS to disk, preserving any changes outside the given namespace.
The common library.
#define DEFAULT_COPPER_TEXT_WIDTH
PCB background color.
Definition: layer_ids.h:227
virtual bool MigrateFromLegacy(wxConfigBase *aLegacyConfig) override
Migrates from wxConfig to JSON-based configuration.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:204
Color settings are a bit different than most of the settings objects in that there can be more than o...
#define DEFAULT_TEXT_SIZE
Ratio of the font height to the baseline of the text above the wire.
const wxChar *const traceSettings
Flag to enable debug output of settings operations and management.
#define DEFAULT_COPPER_TEXT_SIZE
BOARD_DESIGN_SETTINGS m_DesignSettings
Only some of these settings are actually used for footprint editing.
SETTINGS_MANAGER * m_manager
A pointer to the settings manager managing this file (may be null)
static constexpr int Millimeter2iu(double mm)
double From_User_Unit(EDA_UNITS aUnits, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: base_units.cpp:282
MAGNETIC_OPTIONS tracks
size_t Count(const std::string &aPath) const
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103