OpenCPN Partial API docs
navutil.cpp
1 /***************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose: Navigation Utility Functions
5  * Author: David Register
6  *
7  ***************************************************************************
8  * Copyright (C) 2010 by David S. Register *
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License *
21  * along with this program; if not, write to the *
22  * Free Software Foundation, Inc., *
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24  **************************************************************************/
25 
26 #include <wx/wxprec.h>
27 
28 #ifdef __MINGW32__
29 #undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
30 #include <windows.h>
31 #endif
32 
33 #include <stdlib.h>
34 #include <time.h>
35 #include <locale>
36 #include <list>
37 
38 
39 #ifndef WX_PRECOMP
40 #include <wx/wx.h>
41 #endif // precompiled headers
42 
43 #include <wx/bmpcbox.h>
44 #include <wx/dir.h>
45 #include <wx/filename.h>
46 #include <wx/graphics.h>
47 #include <wx/image.h>
48 #include <wx/listbook.h>
49 #include <wx/listimpl.cpp>
50 #include <wx/progdlg.h>
51 #include <wx/sstream.h>
52 #include <wx/tglbtn.h>
53 #include <wx/timectrl.h>
54 #include <wx/tokenzr.h>
55 
56 #include "model/ais_decoder.h"
57 #include "model/ais_state_vars.h"
58 #include "model/cmdline.h"
59 #include "model/config_vars.h"
60 #include "model/conn_params.h"
61 #include "model/cutil.h"
62 #include "model/geodesic.h"
63 #include "model/georef.h"
64 #include "model/idents.h"
65 #include "model/multiplexer.h"
66 #include "model/nav_object_database.h"
67 #include "model/navutil_base.h"
68 #include "model/own_ship.h"
69 #include "model/route.h"
70 #include "model/routeman.h"
71 #include "model/select.h"
72 #include "model/track.h"
73 
74 #include "ais.h"
75 #include "CanvasConfig.h"
76 #include "chartbase.h"
77 #include "chartdb.h"
78 #include "chcanv.h"
79 #include "cm93.h"
80 #include "config.h"
81 #include "ConfigMgr.h"
82 #include "displays.h"
83 #include "dychart.h"
84 #include "FontMgr.h"
85 #include "Layer.h"
86 #include "navutil.h"
87 #include "nmea0183.h"
88 #include "NMEALogWindow.h"
89 #include "observable_globvar.h"
90 #include "ocpndc.h"
91 #include "ocpn_frame.h"
92 #include "OCPNPlatform.h"
93 #include "OCPN_Sound.h"
94 #include "s52plib.h"
95 #include "s52utils.h"
96 #include "snd_config.h"
97 #include "styles.h"
98 
99 #ifdef ocpnUSE_GL
100 #include "glChartCanvas.h"
101 #endif
102 
103 #ifdef __ANDROID__
104 #include "androidUTIL.h"
105 #endif
106 
107 // Statics
108 
109 extern OCPNPlatform *g_Platform;
110 extern MyFrame *gFrame;
111 
112 extern double g_ChartNotRenderScaleFactor;
113 extern int g_restore_stackindex;
114 extern int g_restore_dbindex;
115 extern RouteList *pRouteList;
116 extern std::vector<Track*> g_TrackList;
117 extern LayerList *pLayerList;
118 extern MyConfig *pConfig;
119 extern double vLat, vLon;
120 extern double kLat, kLon;
121 extern ColorScheme global_color_scheme;
122 extern int g_nbrightness;
123 extern bool g_bShowStatusBar;
124 extern bool g_bUIexpert;
125 extern bool g_bFullscreen;
126 
127 extern wxString g_SENCPrefix;
128 extern wxString g_UserPresLibData;
129 
130 extern wxString *pInit_Chart_Dir;
131 extern wxString gWorldMapLocation;
132 extern wxString gWorldShapefileLocation;
133 
134 extern bool s_bSetSystemTime;
135 extern bool g_bDisplayGrid; // Flag indicating if grid is to be displayed
136 extern bool g_bPlayShipsBells;
137 extern int g_iSoundDeviceIndex;
138 extern bool g_bFullscreenToolbar;
139 extern bool g_bShowLayers;
140 extern bool g_bTransparentToolbar;
141 extern bool g_bPermanentMOBIcon;
142 
143 extern bool g_bShowDepthUnits;
144 extern bool g_bAutoAnchorMark;
145 extern bool g_bskew_comp;
146 extern bool g_bopengl;
147 extern bool g_bSoftwareGL;
148 extern bool g_bsmoothpanzoom;
149 extern bool g_fog_overzoom;
150 extern double g_overzoom_emphasis_base;
151 extern bool g_oz_vector_scale;
152 extern double g_plus_minus_zoom_factor;
153 extern bool g_bShowOutlines;
154 extern bool g_bShowActiveRouteHighway;
155 extern bool g_bShowRouteTotal;
156 extern int g_nAWDefault;
157 extern int g_nAWMax;
158 
159 extern int g_nframewin_x;
160 extern int g_nframewin_y;
161 extern int g_nframewin_posx;
162 extern int g_nframewin_posy;
163 extern bool g_bframemax;
164 
165 extern wxString g_VisibleLayers;
166 extern wxString g_InvisibleLayers;
167 extern wxString g_VisiNameinLayers;
168 extern wxString g_InVisiNameinLayers;
169 
170 extern wxArrayString *pMessageOnceArray;
171 
172 // LIVE ETA OPTION
173 extern bool g_bShowLiveETA;
174 extern double g_defaultBoatSpeed;
175 extern double g_defaultBoatSpeedUserUnit;
176 
177 extern bool g_bUseOnlyConfirmedAISName;
178 extern int g_ScaledNumWeightSOG;
179 
180 extern int g_S57_dialog_sx, g_S57_dialog_sy;
181 int g_S57_extradialog_sx, g_S57_extradialog_sy;
182 
183 extern int g_iNavAidRadarRingsNumberVisible;
184 extern bool g_bNavAidRadarRingsShown;
185 extern float g_fNavAidRadarRingsStep;
186 extern int g_pNavAidRadarRingsStepUnits;
187 extern bool g_bWayPointPreventDragging;
188 extern bool g_bConfirmObjectDelete;
189 extern wxColour g_colourOwnshipRangeRingsColour;
190 
191 extern bool g_bEnableZoomToCursor;
192 extern wxString g_toolbarConfig;
193 extern double g_TrackIntervalSeconds;
194 
195 extern int g_nCacheLimit;
196 extern int g_memCacheLimit;
197 
198 extern bool g_bGDAL_Debug;
199 extern bool g_bDebugCM93;
200 extern bool g_bDebugS57;
201 
202 extern double g_ownship_predictor_minutes;
203 extern int g_cog_predictor_style;
204 extern wxString g_cog_predictor_color;
205 extern int g_cog_predictor_endmarker;
206 extern int g_cog_predictor_width;
207 extern int g_ownship_HDTpredictor_style;
208 extern wxString g_ownship_HDTpredictor_color;
209 extern int g_ownship_HDTpredictor_endmarker;
210 extern int g_ownship_HDTpredictor_width;
211 extern double g_ownship_HDTpredictor_miles;
212 
213 extern bool g_own_ship_sog_cog_calc;
214 extern int g_own_ship_sog_cog_calc_damp_sec;
215 
216 extern bool g_bShowMenuBar;
217 extern bool g_bShowCompassWin;
218 
219 extern s52plib *ps52plib;
220 
221 extern int g_cm93_zoom_factor;
222 extern bool g_b_legacy_input_filter_behaviour;
223 extern bool g_bShowDetailSlider;
224 extern int g_detailslider_dialog_x, g_detailslider_dialog_y;
225 
226 extern bool g_bUseGreenShip;
227 
228 extern int g_OwnShipIconType;
229 extern double g_n_ownship_length_meters;
230 extern double g_n_ownship_beam_meters;
231 extern double g_n_gps_antenna_offset_y;
232 extern double g_n_gps_antenna_offset_x;
233 extern int g_n_ownship_min_mm;
234 extern int g_maxzoomin;
235 
236 extern bool g_bShowShipToActive;
237 extern int g_shipToActiveStyle;
238 extern int g_shipToActiveColor;
239 
240 extern bool g_bPreserveScaleOnX;
241 extern bool g_bsimplifiedScalebar;
242 
243 extern bool g_bUseGLL;
244 
245 extern wxString g_locale;
246 extern wxString g_localeOverride;
247 
248 extern bool g_bCourseUp;
249 extern bool g_bLookAhead;
250 extern int g_COGAvgSec;
251 extern bool g_bShowChartBar;
252 
253 extern int g_MemFootMB;
254 
255 extern wxString g_AW1GUID;
256 extern wxString g_AW2GUID;
257 extern int g_BSBImgDebug;
258 
259 extern int n_NavMessageShown;
260 extern wxString g_config_version_string;
261 
262 extern wxString g_CmdSoundString;
263 
264 extern bool g_bDebugGPSD;
265 
266 extern bool g_bfilter_cogsog;
267 extern int g_COGFilterSec;
268 extern int g_SOGFilterSec;
269 
270 int g_navobjbackups;
271 
272 extern bool g_bQuiltEnable;
273 extern bool g_bFullScreenQuilt;
274 extern bool g_bQuiltStart;
275 
276 extern int g_SkewCompUpdatePeriod;
277 
278 extern int g_maintoolbar_x;
279 extern int g_maintoolbar_y;
280 extern long g_maintoolbar_orient;
281 
282 extern int g_lastClientRectx;
283 extern int g_lastClientRecty;
284 extern int g_lastClientRectw;
285 extern int g_lastClientRecth;
286 
287 extern bool g_bHighliteTracks;
288 extern int g_cog_predictor_width;
289 extern int g_ais_cog_predictor_width;
290 
291 extern wxColour g_colourTrackLineColour;
292 extern wxString g_default_wp_icon;
293 
294 extern ChartGroupArray *g_pGroupArray;
295 
296 extern bool g_bDebugOGL;
297 extern int g_tcwin_scale;
298 extern wxString g_uploadConnection;
299 
300 extern ocpnStyle::StyleManager *g_StyleManager;
301 extern std::vector<std::string> TideCurrentDataSet;
302 extern wxString g_TCData_Dir;
303 
304 extern bool g_bresponsive;
305 
306 extern bool g_bGLexpert;
307 
308 extern int g_SENC_LOD_pixels;
309 extern ArrayOfMmsiProperties g_MMSI_Props_Array;
310 
311 extern int g_chart_zoom_modifier_raster;
312 extern int g_chart_zoom_modifier_vector;
313 
314 extern bool g_bShowTrackPointTime;
315 
316 extern bool g_bAdvanceRouteWaypointOnArrivalOnly;
317 extern double g_display_size_mm;
318 extern std::vector<size_t> g_config_display_size_mm;
319 extern bool g_config_display_size_manual;
320 
321 extern bool g_benable_rotate;
322 extern bool g_bEmailCrashReport;
323 
324 extern int g_default_font_size;
325 extern wxString g_default_font_facename;
326 
327 extern bool g_bAutoHideToolbar;
328 extern int g_nAutoHideToolbar;
329 extern int g_GUIScaleFactor;
330 extern int g_ChartScaleFactor;
331 extern float g_MarkScaleFactorExp;
332 
333 extern int g_ShipScaleFactor;
334 extern float g_ShipScaleFactorExp;
335 extern int g_ENCSoundingScaleFactor;
336 extern int g_ENCTextScaleFactor;
337 
338 extern int g_iENCToolbarPosX;
339 extern int g_iENCToolbarPosY;
340 extern bool g_bRollover;
341 
342 extern bool g_bSpaceDropMark;
343 
344 extern bool g_bShowTide;
345 extern bool g_bShowCurrent;
346 
347 extern wxString g_uiStyle;
348 extern bool g_btrackContinuous;
349 extern bool g_useMUI;
350 
351 int g_nCPUCount;
352 
353 extern unsigned int g_canvasConfig;
354 extern wxString g_lastAppliedTemplateGUID;
355 
356 extern int g_route_prop_x, g_route_prop_y;
357 extern int g_route_prop_sx, g_route_prop_sy;
358 extern int g_AndroidVersionCode;
359 
360 extern wxString g_ObjQFileExt;
361 
362 wxString g_gpx_path;
363 bool g_bLayersLoaded;
364 bool g_bShowMuiZoomButtons = true;
365 
366 double g_mouse_zoom_sensitivity;
367 int g_mouse_zoom_sensitivity_ui;
368 
369 #ifdef ocpnUSE_GL
370 extern ocpnGLOptions g_GLOptions;
371 #endif
372 
373 #if !defined(NAN)
374 static const long long lNaN = 0xfff8000000000000;
375 #define NAN (*(double *)&lNaN)
376 #endif
377 
378 // Layer helper function
379 
380 wxString GetLayerName(int id) {
381  wxString name(_T("unknown layer"));
382  if (id <= 0) return (name);
383  LayerList::iterator it;
384  int index = 0;
385  for (it = (*pLayerList).begin(); it != (*pLayerList).end(); ++it, ++index) {
386  Layer *lay = (Layer *)(*it);
387  if (lay->m_LayerID == id) return (lay->m_LayerName);
388  }
389  return (name);
390 }
391 
392 // Helper conditional file name dir slash
393 void appendOSDirSlash(wxString *pString);
394 
395 //-----------------------------------------------------------------------------
396 // MyConfig Implementation
397 //-----------------------------------------------------------------------------
398 //
399 
400 MyConfig::MyConfig(const wxString &LocalFileName)
401  : wxFileConfig(_T (""), _T (""), LocalFileName, _T (""),
402  wxCONFIG_USE_LOCAL_FILE) {
403  // Create the default NavObjectCollection FileName
404  wxFileName config_file(LocalFileName);
405  m_sNavObjSetFile =
406  config_file.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
407  m_sNavObjSetFile += _T ( "navobj.xml" );
408  m_sNavObjSetChangesFile = m_sNavObjSetFile + _T ( ".changes" );
409 
410  m_pNavObjectInputSet = NULL;
411  m_pNavObjectChangesSet = NavObjectChanges::getInstance();
412 }
413 
414 MyConfig::~MyConfig() {
415 }
416 
417 void MyConfig::CreateRotatingNavObjBackup() {
418  // Avoid nonsense log errors...
419 #ifdef __ANDROID__
420  wxLogNull logNo;
421 #endif
422  // Monthly backup, keep max 3
423  if(wxFileExists(m_sNavObjSetFile)) {
424  int month = wxDateTime::Now().GetMonth() + 1;
425  wxString fn = wxString::Format(_T("%s.m%d"), m_sNavObjSetFile.c_str(), month);
426  if (!wxFileExists(fn)) {
427  wxCopyFile(m_sNavObjSetFile, fn);
428  }
429  if (month > 3) {
430  for (wxDateTime::wxDateTime_t i = 1; i <= month - 3; i++) {
431  fn = wxString::Format(_T("%s.m%d"), m_sNavObjSetFile.c_str(), i);
432  if (wxFileExists(fn)) {
433  wxRemoveFile(fn);
434  }
435  }
436  for (wxDateTime::wxDateTime_t i = month + 1; i <= 12; i++) {
437  fn = wxString::Format(_T("%s.m%d"), m_sNavObjSetFile.c_str(), i);
438  if (wxFileExists(fn)) {
439  wxRemoveFile(fn);
440  }
441  }
442  } else {
443  for (wxDateTime::wxDateTime_t i = month + 1; i <= 12 - month; i++) {
444  fn = wxString::Format(_T("%s.m%d"), m_sNavObjSetFile.c_str(), i);
445  if (wxFileExists(fn)) {
446  wxRemoveFile(fn);
447  }
448  }
449  }
450  // Weekly backup, we want to keep max 4
451  wxDateTime::wxDateTime_t week = wxDateTime::Now().GetWeekOfYear();
452  fn = wxString::Format(_T("%s.w%u"), m_sNavObjSetFile.c_str(), week);
453  if (!wxFileExists(fn)) {
454  wxCopyFile(m_sNavObjSetFile, fn);
455  }
456  if (week > 4) {
457  for (wxDateTime::wxDateTime_t i = 1; i <= week - 4; i++) {
458  fn = wxString::Format(_T("%s.w%u"), m_sNavObjSetFile.c_str(), i);
459  if (wxFileExists(fn)) {
460  wxRemoveFile(fn);
461  }
462  }
463  for (wxDateTime::wxDateTime_t i = week + 1; i <= 53; i++) {
464  fn = wxString::Format(_T("%s.w%u"), m_sNavObjSetFile.c_str(), i);
465  if (wxFileExists(fn)) {
466  wxRemoveFile(fn);
467  }
468  }
469  } else {
470  for (wxDateTime::wxDateTime_t i = week + 1; i <= 53 - week; i++) {
471  fn = wxString::Format(_T("%s.w%u"), m_sNavObjSetFile.c_str(), i);
472  if (wxFileExists(fn)) {
473  wxRemoveFile(fn);
474  }
475  }
476  }
477  }
478 
479  // Rotate navobj backups, but just in case there are some changes in the
480  // current version to prevent the user trying to "fix" the problem by
481  // continuously starting the application to overwrite all of his good
482  // backups...
483  if (g_navobjbackups > 0) {
484  wxFile f;
485  wxString oldname = m_sNavObjSetFile;
486  wxString newname = wxString::Format(_T("%s.1"), m_sNavObjSetFile.c_str());
487 
488  wxFileOffset s_diff = 1;
489  if (::wxFileExists(newname)) {
490  if (f.Open(oldname)) {
491  s_diff = f.Length();
492  f.Close();
493  }
494 
495  if (f.Open(newname)) {
496  s_diff -= f.Length();
497  f.Close();
498  }
499  }
500 
501  if (s_diff != 0) {
502  for (int i = g_navobjbackups - 1; i >= 1; i--) {
503  oldname = wxString::Format(_T("%s.%d"), m_sNavObjSetFile.c_str(), i);
504  newname =
505  wxString::Format(_T("%s.%d"), m_sNavObjSetFile.c_str(), i + 1);
506  if (wxFile::Exists(oldname)) wxCopyFile(oldname, newname);
507  }
508 
509  wxULongLong size = wxFileName::GetSize(m_sNavObjSetFile);
510  if (wxFile::Exists(m_sNavObjSetFile) && size > 0) {
511  newname = wxString::Format(_T("%s.1"), m_sNavObjSetFile.c_str());
512  wxCopyFile(m_sNavObjSetFile, newname);
513  }
514  }
515  }
516  // try to clean the backups the user doesn't want - breaks if he deleted some
517  // by hand as it tries to be effective...
518  for (int i = g_navobjbackups + 1; i <= 99; i++)
519  if (wxFile::Exists(
520  wxString::Format(_T("%s.%d"), m_sNavObjSetFile.c_str(), i)))
521  wxRemoveFile(wxString::Format(_T("%s.%d"), m_sNavObjSetFile.c_str(), i));
522  else
523  break;
524 }
525 
526 int MyConfig::LoadMyConfig() {
527  int display_width, display_height;
528  display_width = g_monitor_info[g_current_monitor].width;
529  display_height = g_monitor_info[g_current_monitor].height;
530 
531  // Set up any defaults not set elsewhere
532  g_useMUI = true;
533  g_TalkerIdText = _T("EC");
534  g_maxWPNameLength = 6;
535  g_NMEAAPBPrecision = 3;
536 
537 #ifdef ocpnUSE_GL
538  g_GLOptions.m_bUseAcceleratedPanning = true;
539  g_GLOptions.m_GLPolygonSmoothing = true;
540  g_GLOptions.m_GLLineSmoothing = true;
541  g_GLOptions.m_iTextureDimension = 512;
542  g_GLOptions.m_iTextureMemorySize = 128;
543  if (!g_bGLexpert) {
544  g_GLOptions.m_iTextureMemorySize =
545  wxMax(128, g_GLOptions.m_iTextureMemorySize);
546  g_GLOptions.m_bTextureCompressionCaching =
547  g_GLOptions.m_bTextureCompression;
548  }
549 #endif
550 
551  g_maintoolbar_orient = wxTB_HORIZONTAL;
552  g_iENCToolbarPosX = -1;
553  g_iENCToolbarPosY = -1;
554  g_restore_dbindex = -1;
555  g_ChartNotRenderScaleFactor = 1.5;
556  g_detailslider_dialog_x = 200L;
557  g_detailslider_dialog_y = 200L;
558  g_SENC_LOD_pixels = 2;
559  g_SkewCompUpdatePeriod = 10;
560 
561  g_bShowStatusBar = 1;
562  g_bShowCompassWin = 1;
563  g_iSoundDeviceIndex = -1;
564  g_bFullscreenToolbar = 1;
565  g_bTransparentToolbar = 0;
566  g_bShowLayers = 1;
567  g_bShowDepthUnits = 1;
568  g_bShowActiveRouteHighway = 1;
569  g_bShowChartBar = 1;
570  g_defaultBoatSpeed = 6.0;
571  g_ownship_predictor_minutes = 5;
572  g_cog_predictor_style = 105;
573  g_cog_predictor_color = _T("rgb(255,0,0)" );
574  g_cog_predictor_endmarker = 1;
575  g_ownship_HDTpredictor_style = 105;
576  g_ownship_HDTpredictor_color = _T("rgb(255,0,0)" );
577  g_ownship_HDTpredictor_endmarker = 1;
578  g_ownship_HDTpredictor_width = 0;
579  g_cog_predictor_width = 3;
580  g_ownship_HDTpredictor_miles = 1;
581  g_n_ownship_min_mm = 2;
582  g_own_ship_sog_cog_calc_damp_sec = 1;
583  g_bFullScreenQuilt = 1;
584  g_track_rotate_time_type = TIME_TYPE_COMPUTER;
585  g_bHighliteTracks = 1;
586  g_bPreserveScaleOnX = 1;
587  g_navobjbackups = 5;
588  g_benableAISNameCache = true;
589  g_n_arrival_circle_radius = 0.05;
590  g_plus_minus_zoom_factor = 2.0;
591  g_mouse_zoom_sensitivity = 1.5;
592 
593  g_AISShowTracks_Mins = 20;
594  g_AISShowTracks_Limit = 300.0;
595  g_ShowScaled_Num = 10;
596  g_ScaledNumWeightSOG = 50;
597  g_ScaledNumWeightCPA = 60;
598  g_ScaledNumWeightTCPA = 25;
599  g_ScaledSizeMinimal = 50;
600  g_ScaledNumWeightRange = 75;
601  g_ScaledNumWeightSizeOfT = 25;
602  g_Show_Target_Name_Scale = 250000;
603  g_bWplUsePosition = 0;
604  g_WplAction = 0;
605  g_ais_cog_predictor_width = 3;
606  g_ais_alert_dialog_sx = 200;
607  g_ais_alert_dialog_sy = 200;
608  g_ais_alert_dialog_x = 200;
609  g_ais_alert_dialog_y = 200;
610  g_ais_query_dialog_x = 200;
611  g_ais_query_dialog_y = 200;
612  g_AisTargetList_range = 40;
613  g_AisTargetList_sortColumn = 2; // Column #2 is MMSI
614  g_S57_dialog_sx = 400;
615  g_S57_dialog_sy = 400;
616  g_S57_extradialog_sx = 400;
617  g_S57_extradialog_sy = 400;
618 
619  // Reasonable starting point
620  vLat = START_LAT; // display viewpoint
621  vLon = START_LON;
622  gLat = START_LAT; // GPS position, as default
623  gLon = START_LON;
624  g_maxzoomin = 800;
625 
626  g_iNavAidRadarRingsNumberVisible = 0;
627  g_bNavAidRadarRingsShown = false;
628  g_fNavAidRadarRingsStep = 1.0;
629  g_pNavAidRadarRingsStepUnits = 0;
630  g_colourOwnshipRangeRingsColour = *wxRED;
631  g_iWaypointRangeRingsNumber = 0;
632  g_fWaypointRangeRingsStep = 1.0;
633  g_iWaypointRangeRingsStepUnits = 0;
634  g_colourWaypointRangeRingsColour = wxColour(*wxRED);
635  g_bConfirmObjectDelete = true;
636 
637  g_TrackIntervalSeconds = 60.0;
638  g_TrackDeltaDistance = 0.10;
639  g_route_line_width = 2;
640  g_track_line_width = 2;
641  g_colourTrackLineColour = wxColour(243, 229, 47); // Yellow
642 
643  g_tcwin_scale = 100;
644  g_default_wp_icon = _T("triangle");
645  g_default_routepoint_icon = _T("diamond");
646 
647  g_nAWDefault = 50;
648  g_nAWMax = 1852;
649  g_ObjQFileExt = _T("txt,rtf,png,html,gif,tif");
650 
651  // Load the raw value, with no defaults, and no processing
652  int ret_Val = LoadMyConfigRaw();
653 
654  // Perform any required post processing and validation
655  if (!ret_Val) {
656  g_ChartScaleFactorExp =
657  g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
658  g_ShipScaleFactorExp =
659  g_Platform->GetChartScaleFactorExp(g_ShipScaleFactor);
660  g_MarkScaleFactorExp =
661  g_Platform->GetMarkScaleFactorExp(g_ChartScaleFactor);
662 
663  g_COGFilterSec = wxMin(g_COGFilterSec, MAX_COGSOG_FILTER_SECONDS);
664  g_COGFilterSec = wxMax(g_COGFilterSec, 1);
665  g_SOGFilterSec = g_COGFilterSec;
666 
667  if (!g_bShowTrue && !g_bShowMag) g_bShowTrue = true;
668  g_COGAvgSec =
669  wxMin(g_COGAvgSec, MAX_COG_AVERAGE_SECONDS); // Bound the array size
670 
671  if (g_bInlandEcdis) g_bLookAhead = 1;
672 
673  if (g_bdisable_opengl) g_bopengl = false;
674 
675 #ifdef ocpnUSE_GL
676  if (!g_bGLexpert) {
677  g_GLOptions.m_iTextureMemorySize =
678  wxMax(128, g_GLOptions.m_iTextureMemorySize);
679  g_GLOptions.m_bTextureCompressionCaching =
680  g_GLOptions.m_bTextureCompression;
681  }
682 #endif
683 
684  g_chart_zoom_modifier_raster = wxMin(g_chart_zoom_modifier_raster, 5);
685  g_chart_zoom_modifier_raster = wxMax(g_chart_zoom_modifier_raster, -5);
686  g_chart_zoom_modifier_vector = wxMin(g_chart_zoom_modifier_vector, 5);
687  g_chart_zoom_modifier_vector = wxMax(g_chart_zoom_modifier_vector, -5);
688  g_cm93_zoom_factor = wxMin(g_cm93_zoom_factor, CM93_ZOOM_FACTOR_MAX_RANGE);
689  g_cm93_zoom_factor =
690  wxMax(g_cm93_zoom_factor, (-CM93_ZOOM_FACTOR_MAX_RANGE));
691 
692  if ((g_detailslider_dialog_x < 0) ||
693  (g_detailslider_dialog_x > display_width))
694  g_detailslider_dialog_x = 5;
695  if ((g_detailslider_dialog_y < 0) ||
696  (g_detailslider_dialog_y > display_height))
697  g_detailslider_dialog_y = 5;
698 
699  g_defaultBoatSpeedUserUnit = toUsrSpeed(g_defaultBoatSpeed, -1);
700  g_n_ownship_min_mm = wxMax(g_n_ownship_min_mm, 2);
701 
702  if (g_navobjbackups > 99) g_navobjbackups = 99;
703  if (g_navobjbackups < 0) g_navobjbackups = 0;
704  g_n_arrival_circle_radius = wxClip(g_n_arrival_circle_radius, 0.001, 0.6);
705 
706  g_selection_radius_mm = wxMax(g_selection_radius_mm, 0.5);
707  g_selection_radius_touch_mm = wxMax(g_selection_radius_touch_mm, 1.0);
708 
709  g_Show_Target_Name_Scale = wxMax(5000, g_Show_Target_Name_Scale);
710 
711  if ((g_ais_alert_dialog_x < 0) || (g_ais_alert_dialog_x > display_width))
712  g_ais_alert_dialog_x = 5;
713  if ((g_ais_alert_dialog_y < 0) || (g_ais_alert_dialog_y > display_height))
714  g_ais_alert_dialog_y = 5;
715  if ((g_ais_query_dialog_x < 0) || (g_ais_query_dialog_x > display_width))
716  g_ais_query_dialog_x = 5;
717  if ((g_ais_query_dialog_y < 0) || (g_ais_query_dialog_y > display_height))
718  g_ais_query_dialog_y = 5;
719 
720  SwitchInlandEcdisMode(g_bInlandEcdis);
721  if (g_bInlandEcdis)
722  global_color_scheme =
723  GLOBAL_COLOR_SCHEME_DUSK; // startup in duskmode if inlandEcdis
724 
725  // Multicanvas Settings
726  LoadCanvasConfigs();
727  }
728 
729  return ret_Val;
730 }
731 
732 int MyConfig::LoadMyConfigRaw(bool bAsTemplate) {
733  int read_int;
734  wxString val;
735 
736  int display_width, display_height;
737  display_width = g_monitor_info[g_current_monitor].width;
738  display_height = g_monitor_info[g_current_monitor].height;
739 
740  // Global options and settings
741  SetPath(_T ( "/Settings" ));
742  Read("ActiveRoute", &g_active_route);
743  Read("PersistActiveRoute", &g_persist_active_route);
744  Read(_T ( "LastAppliedTemplate" ), &g_lastAppliedTemplateGUID);
745  Read(_T ( "CompatOS" ), &g_compatOS);
746  Read(_T ( "CompatOsVersion" ), &g_compatOsVersion);
747 
748  // Some undocumented values
749  Read(_T ( "ConfigVersionString" ), &g_config_version_string);
750  Read(_T("CmdSoundString"), &g_CmdSoundString, wxString(OCPN_SOUND_CMD));
751  if (wxIsEmpty(g_CmdSoundString))
752  g_CmdSoundString = wxString(OCPN_SOUND_CMD);
753  Read(_T ( "NavMessageShown" ), &n_NavMessageShown);
754 
755  Read(_T ( "AndroidVersionCode" ), &g_AndroidVersionCode);
756 
757  Read(_T ( "UIexpert" ), &g_bUIexpert);
758 
759  Read(_T ( "UIStyle" ), &g_uiStyle);
760 
761  Read(_T ( "NCacheLimit" ), &g_nCacheLimit);
762 
763  Read(_T ( "InlandEcdis" ),
764  &g_bInlandEcdis); // First read if in iENC mode as this will override
765  // some config settings
766 
767  Read(_T( "SpaceDropMark" ), &g_bSpaceDropMark);
768 
769  int mem_limit = 0;
770  Read(_T ( "MEMCacheLimit" ), &mem_limit);
771  if (mem_limit > 0)
772  g_memCacheLimit = mem_limit * 1024; // convert from MBytes to kBytes
773 
774  Read(_T ( "UseModernUI5" ), &g_useMUI);
775 
776  Read(_T( "NCPUCount" ), &g_nCPUCount);
777 
778  Read(_T ( "DebugGDAL" ), &g_bGDAL_Debug);
779  Read(_T ( "DebugNMEA" ), &g_nNMEADebug);
780  Read(_T ( "AnchorWatchDefault" ), &g_nAWDefault);
781  Read(_T ( "AnchorWatchMax" ), &g_nAWMax);
782  Read(_T ( "GPSDogTimeout" ), &gps_watchdog_timeout_ticks);
783  Read(_T ( "DebugCM93" ), &g_bDebugCM93);
784  Read(_T ( "DebugS57" ),
785  &g_bDebugS57); // Show LUP and Feature info in object query
786  Read(_T ( "DebugBSBImg" ), &g_BSBImgDebug);
787  Read(_T ( "DebugGPSD" ), &g_bDebugGPSD);
788  Read(_T ( "MaxZoomScale" ), &g_maxzoomin);
789  g_maxzoomin = wxMax(g_maxzoomin, 50);
790 
791  Read(_T ( "DefaultFontSize"), &g_default_font_size);
792  Read(_T ( "DefaultFontFacename"), &g_default_font_facename);
793 
794  Read(_T ( "UseGreenShipIcon" ), &g_bUseGreenShip);
795 
796  Read(_T ( "AutoHideToolbar" ), &g_bAutoHideToolbar);
797  Read(_T ( "AutoHideToolbarSecs" ), &g_nAutoHideToolbar);
798 
799  Read(_T ( "UseSimplifiedScalebar" ), &g_bsimplifiedScalebar);
800  Read(_T ( "ShowTide" ), &g_bShowTide);
801  Read(_T ( "ShowCurrent" ), &g_bShowCurrent);
802 
803  wxString size_mm;
804  Read(_T ( "DisplaySizeMM" ), &size_mm);
805 
806  Read(_T ( "SelectionRadiusMM" ), &g_selection_radius_mm);
807  Read(_T ( "SelectionRadiusTouchMM" ), &g_selection_radius_touch_mm);
808 
809  if (!bAsTemplate) {
810  g_config_display_size_mm.clear();
811  wxStringTokenizer tokenizer(size_mm, ",");
812  while ( tokenizer.HasMoreTokens() )
813  {
814  wxString token = tokenizer.GetNextToken();
815  int size;
816  try {
817  size = std::stoi(token.ToStdString());
818  } catch (std::invalid_argument &e) {
819  size = 0;
820  }
821  if (size > 100 && size < 2000) {
822  g_config_display_size_mm.push_back(size);
823  } else {
824  g_config_display_size_mm.push_back(0);
825  }
826  }
827  Read(_T ( "DisplaySizeManual" ), &g_config_display_size_manual);
828  }
829 
830  Read(_T ( "GUIScaleFactor" ), &g_GUIScaleFactor);
831 
832  Read(_T ( "ChartObjectScaleFactor" ), &g_ChartScaleFactor);
833  Read(_T ( "ShipScaleFactor" ), &g_ShipScaleFactor);
834  Read(_T ( "ENCSoundingScaleFactor" ), &g_ENCSoundingScaleFactor);
835  Read(_T ( "ENCTextScaleFactor" ), &g_ENCTextScaleFactor);
836  Read(_T ( "ObjQueryAppendFilesExt" ), &g_ObjQFileExt);
837 
838  // Plugin catalog handler persistent variables.
839  Read("CatalogCustomURL", &g_catalog_custom_url);
840  Read("CatalogChannel", &g_catalog_channel);
841 
842  // NMEA connection options.
843  if (!bAsTemplate) {
844  Read(_T ( "FilterNMEA_Avg" ), &g_bfilter_cogsog);
845  Read(_T ( "FilterNMEA_Sec" ), &g_COGFilterSec);
846  Read(_T ( "GPSIdent" ), &g_GPS_Ident);
847  Read(_T ( "UseGarminHostUpload" ), &g_bGarminHostUpload);
848  Read(_T ( "UseNMEA_GLL" ), &g_bUseGLL);
849  Read(_T ( "UseMagAPB" ), &g_bMagneticAPB);
850  Read(_T ( "TrackContinuous" ), &g_btrackContinuous, false);
851  Read(_T ( "FilterTrackDropLargeJump" ), &g_trackFilterMax, 1000);
852  }
853 
854  Read(_T ( "ShowTrue" ), &g_bShowTrue);
855  Read(_T ( "ShowMag" ), &g_bShowMag);
856 
857  wxString umv;
858  Read(_T ( "UserMagVariation" ), &umv);
859  if (umv.Len()) umv.ToDouble(&g_UserVar);
860 
861  Read(_T ( "ScreenBrightness" ), &g_nbrightness);
862 
863  Read(_T ( "MemFootprintTargetMB" ), &g_MemFootMB);
864 
865  Read(_T ( "WindowsComPortMax" ), &g_nCOMPortCheck);
866 
867  Read(_T ( "ChartQuilting" ), &g_bQuiltEnable);
868  Read(_T ( "ChartQuiltingInitial" ), &g_bQuiltStart);
869 
870  Read(_T ( "CourseUpMode" ), &g_bCourseUp);
871  Read(_T ( "COGUPAvgSeconds" ), &g_COGAvgSec);
872  Read(_T ( "LookAheadMode" ), &g_bLookAhead);
873  Read(_T ( "SkewToNorthUp" ), &g_bskew_comp);
874 
875  Read(_T( "NMEAAPBPrecision" ), &g_NMEAAPBPrecision);
876 
877  Read(_T( "TalkerIdText" ), &g_TalkerIdText);
878  Read(_T( "MaxWaypointNameLength" ), &g_maxWPNameLength);
879  Read(_T( "MbtilesMaxLayers" ), &g_mbtilesMaxLayers);
880 
881  Read(_T( "ShowTrackPointTime" ), &g_bShowTrackPointTime, true);
882  /* opengl options */
883 #ifdef ocpnUSE_GL
884  if (!bAsTemplate) {
885  Read(_T ( "OpenGLExpert" ), &g_bGLexpert, false);
886  Read(_T ( "UseAcceleratedPanning" ), &g_GLOptions.m_bUseAcceleratedPanning,
887  true);
888  Read(_T ( "GPUTextureCompression" ), &g_GLOptions.m_bTextureCompression);
889  Read(_T ( "GPUTextureCompressionCaching" ),
890  &g_GLOptions.m_bTextureCompressionCaching);
891  Read(_T ( "PolygonSmoothing" ), &g_GLOptions.m_GLPolygonSmoothing);
892  Read(_T ( "LineSmoothing" ), &g_GLOptions.m_GLLineSmoothing);
893  Read(_T ( "GPUTextureDimension" ), &g_GLOptions.m_iTextureDimension);
894  Read(_T ( "GPUTextureMemSize" ), &g_GLOptions.m_iTextureMemorySize);
895  Read(_T ( "DebugOpenGL" ), &g_bDebugOGL);
896  Read(_T ( "OpenGL" ), &g_bopengl);
897  Read(_T ( "SoftwareGL" ), &g_bSoftwareGL);
898  }
899 #endif
900 
901  Read(_T ( "SmoothPanZoom" ), &g_bsmoothpanzoom);
902 
903  Read(_T ( "ToolbarX"), &g_maintoolbar_x);
904  Read(_T ( "ToolbarY" ), &g_maintoolbar_y);
905  Read(_T ( "ToolbarOrient" ), &g_maintoolbar_orient);
906  Read(_T ( "GlobalToolbarConfig" ), &g_toolbarConfig);
907 
908  Read(_T ( "iENCToolbarX"), &g_iENCToolbarPosX);
909  Read(_T ( "iENCToolbarY"), &g_iENCToolbarPosY);
910 
911  Read(_T ( "AnchorWatch1GUID" ), &g_AW1GUID);
912  Read(_T ( "AnchorWatch2GUID" ), &g_AW2GUID);
913 
914  Read(_T ( "InitialStackIndex" ), &g_restore_stackindex);
915  Read(_T ( "InitialdBIndex" ), &g_restore_dbindex);
916 
917  Read(_T ( "ChartNotRenderScaleFactor" ), &g_ChartNotRenderScaleFactor);
918 
919  Read(_T ( "MobileTouch" ), &g_btouch);
920 
921 // "Responsive graphics" option deprecated in O58+
922 // Read(_T ( "ResponsiveGraphics" ), &g_bresponsive);
923 #ifdef __ANDROID__
924  g_bresponsive = true;
925 #else
926  g_bresponsive = false;
927 #endif
928 
929  Read(_T ( "EnableRolloverBlock" ), &g_bRollover);
930 
931  Read(_T ( "ZoomDetailFactor" ), &g_chart_zoom_modifier_raster);
932  Read(_T ( "ZoomDetailFactorVector" ), &g_chart_zoom_modifier_vector);
933  Read(_T ( "PlusMinusZoomFactor" ), &g_plus_minus_zoom_factor, 2.0);
934  Read("MouseZoomSensitivity", &g_mouse_zoom_sensitivity, 1.3);
935  g_mouse_zoom_sensitivity_ui =
936  MouseZoom::config_to_ui(g_mouse_zoom_sensitivity);
937  Read(_T ( "CM93DetailFactor" ), &g_cm93_zoom_factor);
938 
939  Read(_T ( "CM93DetailZoomPosX" ), &g_detailslider_dialog_x);
940  Read(_T ( "CM93DetailZoomPosY" ), &g_detailslider_dialog_y);
941  Read(_T ( "ShowCM93DetailSlider" ), &g_bShowDetailSlider);
942 
943  Read(_T ( "SENC_LOD_Pixels" ), &g_SENC_LOD_pixels);
944 
945  Read(_T ( "SkewCompUpdatePeriod" ), &g_SkewCompUpdatePeriod);
946 
947  Read(_T ( "SetSystemTime" ), &s_bSetSystemTime);
948  Read(_T ( "ShowStatusBar" ), &g_bShowStatusBar);
949 #ifndef __WXOSX__
950  Read(_T ( "ShowMenuBar" ), &g_bShowMenuBar);
951 #endif
952  Read(_T ( "Fullscreen" ), &g_bFullscreen);
953  Read(_T ( "ShowCompassWindow" ), &g_bShowCompassWin);
954  Read(_T ( "ShowGrid" ), &g_bDisplayGrid);
955  Read(_T ( "PlayShipsBells" ), &g_bPlayShipsBells);
956  Read(_T ( "SoundDeviceIndex" ), &g_iSoundDeviceIndex);
957  Read(_T ( "FullscreenToolbar" ), &g_bFullscreenToolbar);
958  Read(_T ( "PermanentMOBIcon" ), &g_bPermanentMOBIcon);
959  Read(_T ( "ShowLayers" ), &g_bShowLayers);
960  Read(_T ( "ShowDepthUnits" ), &g_bShowDepthUnits);
961  Read(_T ( "AutoAnchorDrop" ), &g_bAutoAnchorMark);
962  Read(_T ( "ShowChartOutlines" ), &g_bShowOutlines);
963  Read(_T ( "ShowActiveRouteHighway" ), &g_bShowActiveRouteHighway);
964  Read(_T ( "ShowActiveRouteTotal" ), &g_bShowRouteTotal);
965  Read(_T ( "MostRecentGPSUploadConnection" ), &g_uploadConnection);
966  Read(_T ( "ShowChartBar" ), &g_bShowChartBar);
967  Read(_T ( "SDMMFormat" ),
968  &g_iSDMMFormat); // 0 = "Degrees, Decimal minutes"), 1 = "Decimal
969  // degrees", 2 = "Degrees,Minutes, Seconds"
970 
971  Read(_T ( "DistanceFormat" ),
972  &g_iDistanceFormat); // 0 = "Nautical miles"), 1 = "Statute miles", 2 =
973  // "Kilometers", 3 = "Meters"
974  Read(_T ( "SpeedFormat" ),
975  &g_iSpeedFormat); // 0 = "kts"), 1 = "mph", 2 = "km/h", 3 = "m/s"
976  Read(_T ( "WindSpeedFormat" ),
977  &g_iWindSpeedFormat); // 0 = "knots"), 1 = "m/s", 2 = "Mph", 3 = "km/h"
978  Read(_T ("TemperatureFormat"), &g_iTempFormat); // 0 = C, 1 = F, 2 = K
979 
980  // LIVE ETA OPTION
981  Read(_T ( "LiveETA" ), &g_bShowLiveETA);
982  Read(_T ( "DefaultBoatSpeed" ), &g_defaultBoatSpeed);
983 
984  Read(_T ( "OwnshipCOGPredictorMinutes" ), &g_ownship_predictor_minutes);
985  Read(_T ( "OwnshipCOGPredictorStyle" ), &g_cog_predictor_style);
986  Read(_T ( "OwnshipCOGPredictorColor" ), &g_cog_predictor_color);
987  Read(_T ( "OwnshipCOGPredictorEndmarker" ), &g_cog_predictor_endmarker);
988  Read(_T ( "OwnshipCOGPredictorWidth" ), &g_cog_predictor_width);
989  Read(_T ( "OwnshipHDTPredictorStyle" ), &g_ownship_HDTpredictor_style);
990  Read(_T ( "OwnshipHDTPredictorColor" ), &g_ownship_HDTpredictor_color);
991  Read(_T ( "OwnshipHDTPredictorEndmarker" ), &g_ownship_HDTpredictor_endmarker);
992  Read(_T ( "OwnshipHDTPredictorWidth" ), &g_ownship_HDTpredictor_width);
993  Read(_T ( "OwnshipHDTPredictorMiles" ), &g_ownship_HDTpredictor_miles);
994 
995  Read(_T ( "OwnShipIconType" ), &g_OwnShipIconType);
996  Read(_T ( "OwnShipLength" ), &g_n_ownship_length_meters);
997  Read(_T ( "OwnShipWidth" ), &g_n_ownship_beam_meters);
998  Read(_T ( "OwnShipGPSOffsetX" ), &g_n_gps_antenna_offset_x);
999  Read(_T ( "OwnShipGPSOffsetY" ), &g_n_gps_antenna_offset_y);
1000  Read(_T ( "OwnShipMinSize" ), &g_n_ownship_min_mm);
1001  Read(_T ( "OwnShipSogCogCalc" ), &g_own_ship_sog_cog_calc);
1002  Read(_T ( "OwnShipSogCogCalcDampSec"), &g_own_ship_sog_cog_calc_damp_sec);
1003  Read(_T ( "ShowDirectRouteLine"), &g_bShowShipToActive);
1004  Read(_T ( "DirectRouteLineStyle"), &g_shipToActiveStyle);
1005  Read(_T( "DirectRouteLineColor" ), &g_shipToActiveColor);
1006 
1007  wxString racr;
1008  Read(_T ( "RouteArrivalCircleRadius" ), &racr);
1009  if (racr.Len()) racr.ToDouble(&g_n_arrival_circle_radius);
1010 
1011  Read(_T ( "FullScreenQuilt" ), &g_bFullScreenQuilt);
1012 
1013  Read(_T ( "StartWithTrackActive" ), &g_bTrackCarryOver);
1014  Read(_T ( "AutomaticDailyTracks" ), &g_bTrackDaily);
1015  Read(_T ( "TrackRotateAt" ), &g_track_rotate_time);
1016  Read(_T ( "TrackRotateTimeType" ), &g_track_rotate_time_type);
1017  Read(_T ( "HighlightTracks" ), &g_bHighliteTracks);
1018 
1019  wxString stps;
1020  Read(_T ( "PlanSpeed" ), &stps);
1021  if (!stps.IsEmpty()) stps.ToDouble(&g_PlanSpeed);
1022 
1023  Read(_T ( "VisibleLayers" ), &g_VisibleLayers);
1024  Read(_T ( "InvisibleLayers" ), &g_InvisibleLayers);
1025  Read(_T ( "VisNameInLayers" ), &g_VisiNameinLayers);
1026  Read(_T ( "InvisNameInLayers" ), &g_InVisiNameinLayers);
1027 
1028  Read(_T ( "PreserveScaleOnX" ), &g_bPreserveScaleOnX);
1029 
1030  Read(_T ( "ShowMUIZoomButtons" ), &g_bShowMuiZoomButtons);
1031 
1032  Read(_T ( "Locale" ), &g_locale);
1033  Read(_T ( "LocaleOverride" ), &g_localeOverride);
1034 
1035  // We allow 0-99 backups ov navobj.xml
1036  Read(_T ( "KeepNavobjBackups" ), &g_navobjbackups);
1037 
1038  NMEALogWindow::GetInstance().SetSize(Read(_T("NMEALogWindowSizeX"), 600L),
1039  Read(_T("NMEALogWindowSizeY"), 400L));
1040  NMEALogWindow::GetInstance().SetPos(Read(_T("NMEALogWindowPosX"), 10L),
1041  Read(_T("NMEALogWindowPosY"), 10L));
1042  NMEALogWindow::GetInstance().CheckPos(display_width, display_height);
1043 
1044  // Boolean to cater for legacy Input COM Port filer behaviour, i.e. show msg
1045  // filtered but put msg on bus.
1046  Read(_T ( "LegacyInputCOMPortFilterBehaviour" ),
1047  &g_b_legacy_input_filter_behaviour);
1048 
1049  // Boolean to cater for sailing when not approaching waypoint
1050  Read(_T( "AdvanceRouteWaypointOnArrivalOnly" ),
1051  &g_bAdvanceRouteWaypointOnArrivalOnly);
1052 
1053  Read(_T ( "EnableRotateKeys" ), &g_benable_rotate);
1054  Read(_T ( "EmailCrashReport" ), &g_bEmailCrashReport);
1055 
1056  g_benableAISNameCache = true;
1057  Read(_T ( "EnableAISNameCache" ), &g_benableAISNameCache);
1058 
1059  Read(_T ( "EnableUDPNullHeader" ), &g_benableUDPNullHeader);
1060 
1061  SetPath(_T ( "/Settings/GlobalState" ));
1062 
1063  Read(_T ( "FrameWinX" ), &g_nframewin_x);
1064  Read(_T ( "FrameWinY" ), &g_nframewin_y);
1065  Read(_T ( "FrameWinPosX" ), &g_nframewin_posx);
1066  Read(_T ( "FrameWinPosY" ), &g_nframewin_posy);
1067  Read(_T ( "FrameMax" ), &g_bframemax);
1068 
1069  Read(_T ( "ClientPosX" ), &g_lastClientRectx);
1070  Read(_T ( "ClientPosY" ), &g_lastClientRecty);
1071  Read(_T ( "ClientSzX" ), &g_lastClientRectw);
1072  Read(_T ( "ClientSzY" ), &g_lastClientRecth);
1073 
1074  Read(_T( "RoutePropSizeX" ), &g_route_prop_sx);
1075  Read(_T( "RoutePropSizeY" ), &g_route_prop_sy);
1076  Read(_T( "RoutePropPosX" ), &g_route_prop_x);
1077  Read(_T( "RoutePropPosY" ), &g_route_prop_y);
1078 
1079  read_int = -1;
1080  Read(_T ( "S52_DEPTH_UNIT_SHOW" ), &read_int); // default is metres
1081  if (read_int >= 0) {
1082  read_int = wxMax(read_int, 0); // qualify value
1083  read_int = wxMin(read_int, 2);
1084  g_nDepthUnitDisplay = read_int;
1085  }
1086 
1087  // Sounds
1088  SetPath(_T ( "/Settings/Audio" ));
1089 
1090  // Set reasonable defaults
1091  wxString sound_dir = g_Platform->GetSharedDataDir();
1092  sound_dir.Append(_T("sounds"));
1093  sound_dir.Append(wxFileName::GetPathSeparator());
1094 
1095  g_AIS_sound_file = sound_dir + _T("beep_ssl.wav");
1096  g_DSC_sound_file = sound_dir + _T("phonering1.wav");
1097  g_SART_sound_file = sound_dir + _T("beep3.wav");
1098  g_anchorwatch_sound_file = sound_dir + _T("beep1.wav");
1099 
1100  Read(_T ( "AISAlertSoundFile" ), &g_AIS_sound_file);
1101  Read(_T ( "DSCAlertSoundFile" ), &g_DSC_sound_file);
1102  Read(_T ( "SARTAlertSoundFile" ), &g_SART_sound_file);
1103  Read(_T ( "AnchorAlarmSoundFile" ), &g_anchorwatch_sound_file);
1104 
1105  Read(_T ( "bAIS_GCPA_AlertAudio" ), &g_bAIS_GCPA_Alert_Audio);
1106  Read(_T ( "bAIS_SART_AlertAudio" ), &g_bAIS_SART_Alert_Audio);
1107  Read(_T ( "bAIS_DSC_AlertAudio" ), &g_bAIS_DSC_Alert_Audio);
1108  Read(_T ( "bAnchorAlertAudio" ), &g_bAnchor_Alert_Audio);
1109 
1110  // AIS
1111  wxString s;
1112  SetPath(_T ( "/Settings/AIS" ));
1113 
1114  g_bUseOnlyConfirmedAISName = false;
1115  Read(_T ( "UseOnlyConfirmedAISName" ), &g_bUseOnlyConfirmedAISName);
1116 
1117  Read(_T ( "bNoCPAMax" ), &g_bCPAMax);
1118 
1119  Read(_T ( "NoCPAMaxNMi" ), &s);
1120  s.ToDouble(&g_CPAMax_NM);
1121 
1122  Read(_T ( "bCPAWarn" ), &g_bCPAWarn);
1123 
1124  Read(_T ( "CPAWarnNMi" ), &s);
1125  s.ToDouble(&g_CPAWarn_NM);
1126 
1127  Read(_T ( "bTCPAMax" ), &g_bTCPA_Max);
1128 
1129  Read(_T ( "TCPAMaxMinutes" ), &s);
1130  s.ToDouble(&g_TCPA_Max);
1131 
1132  Read(_T ( "bMarkLostTargets" ), &g_bMarkLost);
1133 
1134  Read(_T ( "MarkLost_Minutes" ), &s);
1135  s.ToDouble(&g_MarkLost_Mins);
1136 
1137  Read(_T ( "bRemoveLostTargets" ), &g_bRemoveLost);
1138 
1139  Read(_T ( "RemoveLost_Minutes" ), &s);
1140  s.ToDouble(&g_RemoveLost_Mins);
1141 
1142  Read(_T ( "bShowCOGArrows" ), &g_bShowCOG);
1143 
1144  Read(_T ("bSyncCogPredictors"), &g_bSyncCogPredictors);
1145 
1146  Read(_T ( "CogArrowMinutes" ), &s);
1147  s.ToDouble(&g_ShowCOG_Mins);
1148 
1149  Read(_T ( "bShowTargetTracks" ), &g_bAISShowTracks);
1150 
1151  if (Read(_T ( "TargetTracksLimit" ), &s)) {
1152  s.ToDouble(&g_AISShowTracks_Limit);
1153  g_AISShowTracks_Limit = wxMax(300.0, g_AISShowTracks_Limit);
1154  }
1155  if (Read(_T ( "TargetTracksMinutes" ), &s)) {
1156  s.ToDouble(&g_AISShowTracks_Mins);
1157  g_AISShowTracks_Mins = wxMax(1.0, g_AISShowTracks_Mins);
1158  g_AISShowTracks_Mins = wxMin(g_AISShowTracks_Limit, g_AISShowTracks_Mins);
1159  }
1160 
1161  Read(_T ( "bHideMooredTargets" ), &g_bHideMoored);
1162  if (Read(_T ( "MooredTargetMaxSpeedKnots" ), &s))
1163  s.ToDouble(&g_ShowMoored_Kts);
1164 
1165  g_SOGminCOG_kts = 0.2;
1166  if (Read(_T ( "SOGMinimumForCOGDisplay" ), &s))
1167  s.ToDouble(&g_SOGminCOG_kts);
1168 
1169  Read(_T ("bShowScaledTargets"), &g_bAllowShowScaled);
1170  Read(_T ( "AISScaledNumber" ), &g_ShowScaled_Num);
1171  Read(_T ( "AISScaledNumberWeightSOG" ), &g_ScaledNumWeightSOG);
1172  Read(_T ( "AISScaledNumberWeightCPA" ), &g_ScaledNumWeightCPA);
1173  Read(_T ( "AISScaledNumberWeightTCPA" ), &g_ScaledNumWeightTCPA);
1174  Read(_T ( "AISScaledNumberWeightRange" ), &g_ScaledNumWeightRange);
1175  Read(_T ( "AISScaledNumberWeightSizeOfTarget" ), &g_ScaledNumWeightSizeOfT);
1176  Read(_T ( "AISScaledSizeMinimal" ), &g_ScaledSizeMinimal);
1177  Read(_T("AISShowScaled"), &g_bShowScaled);
1178 
1179  Read(_T ( "bShowAreaNotices" ), &g_bShowAreaNotices);
1180  Read(_T ( "bDrawAISSize" ), &g_bDrawAISSize);
1181  Read(_T ( "bDrawAISRealtime" ), &g_bDrawAISRealtime);
1182  Read(_T ( "bShowAISName" ), &g_bShowAISName);
1183  Read(_T ( "AISRealtimeMinSpeedKnots" ), &g_AIS_RealtPred_Kts, 0.7);
1184  Read(_T ( "bAISAlertDialog" ), &g_bAIS_CPA_Alert);
1185  Read(_T ( "ShowAISTargetNameScale" ), &g_Show_Target_Name_Scale);
1186  Read(_T ( "bWplIsAprsPositionReport" ), &g_bWplUsePosition);
1187  Read(_T ( "WplSelAction"), &g_WplAction);
1188  Read(_T ( "AISCOGPredictorWidth" ), &g_ais_cog_predictor_width);
1189 
1190  Read(_T ( "bAISAlertAudio" ), &g_bAIS_CPA_Alert_Audio);
1191  Read(_T ( "AISAlertAudioFile" ), &g_sAIS_Alert_Sound_File);
1192  Read(_T ( "bAISAlertSuppressMoored" ), &g_bAIS_CPA_Alert_Suppress_Moored);
1193 
1194  Read(_T ( "bAISAlertAckTimeout" ), &g_bAIS_ACK_Timeout);
1195  if (Read(_T ( "AlertAckTimeoutMinutes" ), &s)) s.ToDouble(&g_AckTimeout_Mins);
1196 
1197  Read(_T ( "AlertDialogSizeX" ), &g_ais_alert_dialog_sx);
1198  Read(_T ( "AlertDialogSizeY" ), &g_ais_alert_dialog_sy);
1199  Read(_T ( "AlertDialogPosX" ), &g_ais_alert_dialog_x);
1200  Read(_T ( "AlertDialogPosY" ), &g_ais_alert_dialog_y);
1201  Read(_T ( "QueryDialogPosX" ), &g_ais_query_dialog_x);
1202  Read(_T ( "QueryDialogPosY" ), &g_ais_query_dialog_y);
1203 
1204  Read(_T ( "AISTargetListPerspective" ), &g_AisTargetList_perspective);
1205  Read(_T ( "AISTargetListRange" ), &g_AisTargetList_range);
1206  Read(_T ( "AISTargetListSortColumn" ), &g_AisTargetList_sortColumn);
1207  Read(_T ( "bAISTargetListSortReverse" ), &g_bAisTargetList_sortReverse);
1208  Read(_T ( "AISTargetListColumnSpec" ), &g_AisTargetList_column_spec);
1209  Read(_T ("AISTargetListColumnOrder"), &g_AisTargetList_column_order);
1210 
1211  Read(_T ( "bAISRolloverShowClass" ), &g_bAISRolloverShowClass);
1212  Read(_T ( "bAISRolloverShowCOG" ), &g_bAISRolloverShowCOG);
1213  Read(_T ( "bAISRolloverShowCPA" ), &g_bAISRolloverShowCPA);
1214 
1215  Read(_T ( "S57QueryDialogSizeX" ), &g_S57_dialog_sx);
1216  Read(_T ( "S57QueryDialogSizeY" ), &g_S57_dialog_sy);
1217  Read(_T ( "S57QueryExtraDialogSizeX" ), &g_S57_extradialog_sx);
1218  Read(_T ( "S57QueryExtraDialogSizeY" ), &g_S57_extradialog_sy);
1219 
1220  wxString strpres(_T ( "PresentationLibraryData" ));
1221  wxString valpres;
1222  SetPath(_T ( "/Directories" ));
1223  Read(strpres, &valpres); // Get the File name
1224  if (!valpres.IsEmpty()) g_UserPresLibData = valpres;
1225 
1226  wxString strs(_T ( "SENCFileLocation" ));
1227  SetPath(_T ( "/Directories" ));
1228  wxString vals;
1229  Read(strs, &vals); // Get the Directory name
1230  if (!vals.IsEmpty()) g_SENCPrefix = vals;
1231 
1232  SetPath(_T ( "/Directories" ));
1233  wxString vald;
1234  Read(_T ( "InitChartDir" ), &vald); // Get the Directory name
1235 
1236  wxString dirnamed(vald);
1237  if (!dirnamed.IsEmpty()) {
1238  if (pInit_Chart_Dir->IsEmpty()) // on second pass, don't overwrite
1239  {
1240  pInit_Chart_Dir->Clear();
1241  pInit_Chart_Dir->Append(vald);
1242  }
1243  }
1244 
1245  Read(_T ( "GPXIODir" ), &g_gpx_path); // Get the Directory name
1246  Read(_T ( "TCDataDir" ), &g_TCData_Dir); // Get the Directory name
1247  Read(_T ( "BasemapDir"), &gWorldMapLocation);
1248  Read(_T ( "BaseShapefileDir"), &gWorldShapefileLocation);
1249  Read(_T ( "pluginInstallDir"), &g_winPluginDir);
1250  wxLogMessage("winPluginDir, read from ini file: %s",
1251  g_winPluginDir.mb_str().data());
1252 
1253  SetPath(_T ( "/Settings/GlobalState" ));
1254 
1255  if (Read(_T ( "nColorScheme" ), &read_int))
1256  global_color_scheme = (ColorScheme)read_int;
1257 
1258  if (!bAsTemplate) {
1259  SetPath(_T ( "/Settings/NMEADataSource" ));
1260 
1261  wxString connectionconfigs;
1262  Read(_T( "DataConnections" ), &connectionconfigs);
1263  if (!connectionconfigs.IsEmpty()) {
1264  wxArrayString confs = wxStringTokenize(connectionconfigs, _T("|"));
1265  TheConnectionParams()->Clear();
1266  for (size_t i = 0; i < confs.Count(); i++) {
1267  ConnectionParams *prm = new ConnectionParams(confs[i]);
1268  if (!prm->Valid) {
1269  wxLogMessage(_T( "Skipped invalid DataStream config"));
1270  delete prm;
1271  continue;
1272  }
1273  TheConnectionParams()->Add(prm);
1274  }
1275  }
1276  }
1277 
1278  SetPath(_T ( "/Settings/GlobalState" ));
1279  wxString st;
1280 
1281  double st_lat, st_lon;
1282  if (Read(_T ( "VPLatLon" ), &st)) {
1283  sscanf(st.mb_str(wxConvUTF8), "%lf,%lf", &st_lat, &st_lon);
1284 
1285  // Sanity check the lat/lon...both have to be reasonable.
1286  if (fabs(st_lon) < 360.) {
1287  while (st_lon < -180.) st_lon += 360.;
1288 
1289  while (st_lon > 180.) st_lon -= 360.;
1290 
1291  vLon = st_lon;
1292  }
1293 
1294  if (fabs(st_lat) < 90.0) vLat = st_lat;
1295 
1296  s.Printf(_T ( "Setting Viewpoint Lat/Lon %g, %g" ), vLat, vLon);
1297  wxLogMessage(s);
1298  }
1299 
1300  double st_view_scale, st_rotation;
1301  if (Read(wxString(_T ( "VPScale" )), &st)) {
1302  sscanf(st.mb_str(wxConvUTF8), "%lf", &st_view_scale);
1303  // Sanity check the scale
1304  st_view_scale = fmax(st_view_scale, .001 / 32);
1305  st_view_scale = fmin(st_view_scale, 4);
1306  }
1307 
1308  if (Read(wxString(_T ( "VPRotation" )), &st)) {
1309  sscanf(st.mb_str(wxConvUTF8), "%lf", &st_rotation);
1310  // Sanity check the rotation
1311  st_rotation = fmin(st_rotation, 360);
1312  st_rotation = fmax(st_rotation, 0);
1313  }
1314 
1315  wxString sll;
1316  double lat, lon;
1317  if (Read(_T ( "OwnShipLatLon" ), &sll)) {
1318  sscanf(sll.mb_str(wxConvUTF8), "%lf,%lf", &lat, &lon);
1319 
1320  // Sanity check the lat/lon...both have to be reasonable.
1321  if (fabs(lon) < 360.) {
1322  while (lon < -180.) lon += 360.;
1323 
1324  while (lon > 180.) lon -= 360.;
1325 
1326  gLon = lon;
1327  }
1328 
1329  if (fabs(lat) < 90.0) gLat = lat;
1330 
1331  s.Printf(_T ( "Setting Ownship Lat/Lon %g, %g" ), gLat, gLon);
1332  wxLogMessage(s);
1333  }
1334 
1335  // Fonts
1336 
1337  // Load the persistent Auxiliary Font descriptor Keys
1338  SetPath(_T ( "/Settings/AuxFontKeys" ));
1339 
1340  wxString strk;
1341  long dummyk;
1342  wxString kval;
1343  bool bContk = GetFirstEntry(strk, dummyk);
1344  bool bNewKey = false;
1345  while (bContk) {
1346  Read(strk, &kval);
1347  bNewKey = FontMgr::Get().AddAuxKey(kval);
1348  if (!bAsTemplate && !bNewKey) {
1349  DeleteEntry(strk);
1350  dummyk--;
1351  }
1352  bContk = GetNextEntry(strk, dummyk);
1353  }
1354 
1355 #ifdef __WXX11__
1356  SetPath(_T ( "/Settings/X11Fonts" ));
1357 #endif
1358 
1359 #ifdef __WXGTK__
1360  SetPath(_T ( "/Settings/GTKFonts" ));
1361 #endif
1362 
1363 #ifdef __WXMSW__
1364  SetPath(_T ( "/Settings/MSWFonts" ));
1365 #endif
1366 
1367 #ifdef __WXMAC__
1368  SetPath(_T ( "/Settings/MacFonts" ));
1369 #endif
1370 
1371 #ifdef __WXQT__
1372  SetPath(_T ( "/Settings/QTFonts" ));
1373 #endif
1374 
1375  wxString str;
1376  long dummy;
1377  wxString pval;
1378  wxArrayString deleteList;
1379 
1380  bool bCont = GetFirstEntry(str, dummy);
1381  while (bCont) {
1382  pval = Read(str);
1383 
1384  if (str.StartsWith(_T("Font"))) {
1385  // Convert pre 3.1 setting. Can't delete old entries from inside the
1386  // GetNextEntry() loop, so we need to save those and delete outside.
1387  deleteList.Add(str);
1388  wxString oldKey = pval.BeforeFirst(_T(':'));
1389  str = FontMgr::GetFontConfigKey(oldKey);
1390  }
1391 
1392  if (pval.IsEmpty() || pval.StartsWith(_T(":"))) {
1393  deleteList.Add(str);
1394  } else
1395  FontMgr::Get().LoadFontNative(&str, &pval);
1396 
1397  bCont = GetNextEntry(str, dummy);
1398  }
1399 
1400  for (unsigned int i = 0; i < deleteList.Count(); i++) {
1401  DeleteEntry(deleteList[i]);
1402  }
1403  deleteList.Clear();
1404 
1405  // Tide/Current Data Sources
1406  SetPath(_T ( "/TideCurrentDataSources" ));
1407  if (GetNumberOfEntries()) {
1408  TideCurrentDataSet.clear();
1409  wxString str, val;
1410  long dummy;
1411  bool bCont = GetFirstEntry(str, dummy);
1412  while (bCont) {
1413  Read(str, &val); // Get a file name and add it to the list just in case it is not repeated
1414  // We have seen duplication of dataset entries in https://github.com/OpenCPN/OpenCPN/issues/3042, this
1415  // effectively gets rid of them.
1416  if (std::find(TideCurrentDataSet.begin(), TideCurrentDataSet.end(), val.ToStdString()) == TideCurrentDataSet.end()) {
1417  TideCurrentDataSet.push_back(val.ToStdString());
1418  }
1419  bCont = GetNextEntry(str, dummy);
1420  }
1421  }
1422 
1423  // Groups
1424  LoadConfigGroups(g_pGroupArray);
1425 
1426  // // Multicanvas Settings
1427  // LoadCanvasConfigs();
1428 
1429  SetPath(_T ( "/Settings/Others" ));
1430 
1431  // Radar rings
1432  Read(_T ( "RadarRingsNumberVisible" ), &val);
1433  if (val.Length() > 0) g_iNavAidRadarRingsNumberVisible = atoi(val.mb_str());
1434  g_bNavAidRadarRingsShown = g_iNavAidRadarRingsNumberVisible > 0;
1435 
1436  Read(_T ( "RadarRingsStep" ), &val);
1437  if (val.Length() > 0) g_fNavAidRadarRingsStep = atof(val.mb_str());
1438 
1439  Read(_T ( "RadarRingsStepUnits" ), &g_pNavAidRadarRingsStepUnits);
1440 
1441  wxString l_wxsOwnshipRangeRingsColour;
1442  Read(_T ( "RadarRingsColour" ), &l_wxsOwnshipRangeRingsColour);
1443  if (l_wxsOwnshipRangeRingsColour.Length())
1444  g_colourOwnshipRangeRingsColour.Set(l_wxsOwnshipRangeRingsColour);
1445 
1446  // Waypoint Radar rings
1447  Read(_T ( "WaypointRangeRingsNumber" ), &val);
1448  if (val.Length() > 0) g_iWaypointRangeRingsNumber = atoi(val.mb_str());
1449 
1450  Read(_T ( "WaypointRangeRingsStep" ), &val);
1451  if (val.Length() > 0) g_fWaypointRangeRingsStep = atof(val.mb_str());
1452 
1453  Read(_T ( "WaypointRangeRingsStepUnits" ), &g_iWaypointRangeRingsStepUnits);
1454 
1455  wxString l_wxsWaypointRangeRingsColour;
1456  Read(_T( "WaypointRangeRingsColour" ), &l_wxsWaypointRangeRingsColour);
1457  g_colourWaypointRangeRingsColour.Set(l_wxsWaypointRangeRingsColour);
1458 
1459  if (!Read(_T("WaypointUseScaMin"), &g_bUseWptScaMin)) g_bUseWptScaMin = false;
1460  if (!Read(_T("WaypointScaMinValue"), &g_iWpt_ScaMin))
1461  g_iWpt_ScaMin = 2147483646;
1462  if (!Read(_T("WaypointUseScaMinOverrule"), &g_bOverruleScaMin))
1463  g_bOverruleScaMin = false;
1464  if (!Read(_T("WaypointsShowName"), &g_bShowWptName)) g_bShowWptName = true;
1465  if (!Read(_T("UserIconsFirst"), &g_bUserIconsFirst)) g_bUserIconsFirst = true;
1466 
1467  // Support Version 3.0 and prior config setting for Radar Rings
1468  bool b300RadarRings = true;
1469  if (Read(_T ( "ShowRadarRings" ), &b300RadarRings)) {
1470  if (!b300RadarRings) g_iNavAidRadarRingsNumberVisible = 0;
1471  }
1472 
1473  Read(_T ( "ConfirmObjectDeletion" ), &g_bConfirmObjectDelete);
1474 
1475  // Waypoint dragging with mouse
1476  g_bWayPointPreventDragging = false;
1477  Read(_T ( "WaypointPreventDragging" ), &g_bWayPointPreventDragging);
1478 
1479  g_bEnableZoomToCursor = false;
1480  Read(_T ( "EnableZoomToCursor" ), &g_bEnableZoomToCursor);
1481 
1482  val.Clear();
1483  Read(_T ( "TrackIntervalSeconds" ), &val);
1484  if (val.Length() > 0) {
1485  double tval = atof(val.mb_str());
1486  if (tval >= 2.) g_TrackIntervalSeconds = tval;
1487  }
1488 
1489  val.Clear();
1490  Read(_T ( "TrackDeltaDistance" ), &val);
1491  if (val.Length() > 0) {
1492  double tval = atof(val.mb_str());
1493  if (tval >= 0.05) g_TrackDeltaDistance = tval;
1494  }
1495 
1496  Read(_T ( "TrackPrecision" ), &g_nTrackPrecision);
1497 
1498  Read(_T ( "NavObjectFileName" ), m_sNavObjSetFile);
1499 
1500  Read(_T ( "RouteLineWidth" ), &g_route_line_width);
1501  Read(_T ( "TrackLineWidth" ), &g_track_line_width);
1502 
1503  wxString l_wxsTrackLineColour;
1504  if (Read(_T( "TrackLineColour" ), &l_wxsTrackLineColour))
1505  g_colourTrackLineColour.Set(l_wxsTrackLineColour);
1506 
1507  Read(_T ( "TideCurrentWindowScale" ), &g_tcwin_scale);
1508  Read(_T ( "DefaultWPIcon" ), &g_default_wp_icon);
1509  Read(_T ( "DefaultRPIcon" ), &g_default_routepoint_icon);
1510 
1511  SetPath(_T ( "/MmsiProperties" ));
1512  int iPMax = GetNumberOfEntries();
1513  if (iPMax) {
1514  g_MMSI_Props_Array.Empty();
1515  wxString str, val;
1516  long dummy;
1517  bool bCont = pConfig->GetFirstEntry(str, dummy);
1518  while (bCont) {
1519  pConfig->Read(str, &val); // Get an entry
1520 
1521  MmsiProperties *pProps = new MmsiProperties(val);
1522  g_MMSI_Props_Array.Add(pProps);
1523 
1524  bCont = pConfig->GetNextEntry(str, dummy);
1525  }
1526  }
1527 
1528  return (0);
1529 }
1530 
1531 void MyConfig::LoadS57Config() {
1532  if (!ps52plib) return;
1533 
1534  int read_int;
1535  double dval;
1536  SetPath(_T ( "/Settings/GlobalState" ));
1537 
1538  Read(_T ( "bShowS57Text" ), &read_int, 1);
1539  ps52plib->SetShowS57Text(!(read_int == 0));
1540 
1541  Read(_T ( "bShowS57ImportantTextOnly" ), &read_int, 0);
1542  ps52plib->SetShowS57ImportantTextOnly(!(read_int == 0));
1543 
1544  Read(_T ( "bShowLightDescription" ), &read_int, 0);
1545  ps52plib->SetShowLdisText(!(read_int == 0));
1546 
1547  Read(_T ( "bExtendLightSectors" ), &read_int, 0);
1548  ps52plib->SetExtendLightSectors(!(read_int == 0));
1549 
1550  Read(_T ( "nDisplayCategory" ), &read_int, (enum _DisCat)STANDARD);
1551  ps52plib->SetDisplayCategory((enum _DisCat)read_int);
1552 
1553  Read(_T ( "nSymbolStyle" ), &read_int, (enum _LUPname)PAPER_CHART);
1554  ps52plib->m_nSymbolStyle = (LUPname)read_int;
1555 
1556  Read(_T ( "nBoundaryStyle" ), &read_int, PLAIN_BOUNDARIES);
1557  ps52plib->m_nBoundaryStyle = (LUPname)read_int;
1558 
1559  Read(_T ( "bShowSoundg" ), &read_int, 1);
1560  ps52plib->m_bShowSoundg = !(read_int == 0);
1561 
1562  Read(_T ( "bShowMeta" ), &read_int, 0);
1563  ps52plib->m_bShowMeta = !(read_int == 0);
1564 
1565  Read(_T ( "bUseSCAMIN" ), &read_int, 1);
1566  ps52plib->m_bUseSCAMIN = !(read_int == 0);
1567 
1568  Read(_T ( "bUseSUPER_SCAMIN" ), &read_int, 0);
1569  ps52plib->m_bUseSUPER_SCAMIN = !(read_int == 0);
1570 
1571  Read(_T ( "bShowAtonText" ), &read_int, 1);
1572  ps52plib->m_bShowAtonText = !(read_int == 0);
1573 
1574  Read(_T ( "bDeClutterText" ), &read_int, 0);
1575  ps52plib->m_bDeClutterText = !(read_int == 0);
1576 
1577  Read(_T ( "bShowNationalText" ), &read_int, 0);
1578  ps52plib->m_bShowNationalTexts = !(read_int == 0);
1579 
1580  Read(_T ( "ENCSoundingScaleFactor" ), &read_int, 0);
1581  ps52plib->m_nSoundingFactor = read_int;
1582 
1583  Read(_T ( "ENCTextScaleFactor" ), &read_int, 0);
1584  ps52plib->m_nTextFactor = read_int;
1585 
1586  if (Read(_T ( "S52_MAR_SAFETY_CONTOUR" ), &dval, 3.0)) {
1587  S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, dval);
1588  S52_setMarinerParam(S52_MAR_SAFETY_DEPTH,
1589  dval); // Set safety_contour and safety_depth the same
1590  }
1591 
1592  if (Read(_T ( "S52_MAR_SHALLOW_CONTOUR" ), &dval, 2.0))
1593  S52_setMarinerParam(S52_MAR_SHALLOW_CONTOUR, dval);
1594 
1595  if (Read(_T ( "S52_MAR_DEEP_CONTOUR" ), &dval, 6.0))
1596  S52_setMarinerParam(S52_MAR_DEEP_CONTOUR, dval);
1597 
1598  if (Read(_T ( "S52_MAR_TWO_SHADES" ), &dval, 0.0))
1599  S52_setMarinerParam(S52_MAR_TWO_SHADES, dval);
1600 
1601  ps52plib->UpdateMarinerParams();
1602 
1603  SetPath(_T ( "/Settings/GlobalState" ));
1604  Read(_T ( "S52_DEPTH_UNIT_SHOW" ), &read_int, 1); // default is metres
1605  read_int = wxMax(read_int, 0); // qualify value
1606  read_int = wxMin(read_int, 2);
1607  ps52plib->m_nDepthUnitDisplay = read_int;
1608  g_nDepthUnitDisplay = read_int;
1609 
1610  // S57 Object Class Visibility
1611 
1612  OBJLElement *pOLE;
1613 
1614  SetPath(_T ( "/Settings/ObjectFilter" ));
1615 
1616  int iOBJMax = GetNumberOfEntries();
1617  if (iOBJMax) {
1618  wxString str;
1619  long val;
1620  long dummy;
1621 
1622  wxString sObj;
1623 
1624  bool bCont = pConfig->GetFirstEntry(str, dummy);
1625  while (bCont) {
1626  pConfig->Read(str, &val); // Get an Object Viz
1627 
1628  bool bNeedNew = true;
1629 
1630  if (str.StartsWith(_T ( "viz" ), &sObj)) {
1631  for (unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount();
1632  iPtr++) {
1633  pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
1634  if (!strncmp(pOLE->OBJLName, sObj.mb_str(), 6)) {
1635  pOLE->nViz = val;
1636  bNeedNew = false;
1637  break;
1638  }
1639  }
1640 
1641  if (bNeedNew) {
1642  pOLE = (OBJLElement *)calloc(sizeof(OBJLElement), 1);
1643  memcpy(pOLE->OBJLName, sObj.mb_str(), OBJL_NAME_LEN);
1644  pOLE->nViz = 1;
1645 
1646  ps52plib->pOBJLArray->Add((void *)pOLE);
1647  }
1648  }
1649  bCont = pConfig->GetNextEntry(str, dummy);
1650  }
1651  }
1652 }
1653 
1655 static bool ReloadPendingChanges(const wxString& changes_path) {
1656  wxULongLong size = wxFileName::GetSize(changes_path);
1657 
1658  // We crashed last time :(
1659  // That's why this file still exists...
1660  // Let's reconstruct the unsaved changes
1661  auto pNavObjectChangesSet = NavObjectChanges::getTempInstance();
1662  pNavObjectChangesSet->Init(changes_path);
1663  auto res = pNavObjectChangesSet->load_file(changes_path.fn_str());
1664 
1665  // Remove the file before applying the changes,
1666  // just in case the changes file itself causes a fault.
1667  // If it does fault, at least the next restart will proceed without fault.
1668  if (::wxFileExists(changes_path))
1669  ::wxRemoveFile(changes_path);
1670 
1671  if (size == 0 || res.status != pugi::xml_parse_status::status_ok) {
1672  wxLogMessage(changes_path + " seems corrupted, not applying it.");
1673  pNavObjectChangesSet->reset();
1674  return false;
1675  }
1676 
1677  wxLogMessage(_T("Applying NavObjChanges"));
1678  pNavObjectChangesSet->ApplyChanges();
1679  return true;
1680 }
1681 
1682 wxString MyConfig::FindNewestUsableBackup() const {
1683  wxString newest_backup;
1684  pugi::xml_document doc;
1685  for (int i = 1; i <= g_navobjbackups; i++) {
1686  wxString backup = m_sNavObjSetFile + "." + wxString::Format("%d", i);
1687  if (wxFileExists(backup) && wxFileName::GetSize(backup) > 461 && doc.load_file(backup.fn_str()).status == pugi::xml_parse_status::status_ok) {
1688  newest_backup = backup;
1689  break;
1690  }
1691  }
1692  return newest_backup;
1693 }
1694 
1695 void MyConfig::LoadNavObjects() {
1696  // next thing to do is read tracks, etc from the NavObject XML file,
1697  wxLogMessage(_T("Loading navobjects from navobj.xml"));
1698 
1699  if (NULL == m_pNavObjectInputSet)
1700  m_pNavObjectInputSet = new NavObjectCollection1();
1701 
1702  int wpt_dups = 0;
1703  wxString newest_backup;
1704  if (::wxFileExists(m_sNavObjSetFile)) {
1705  if (wxFileName::GetSize(m_sNavObjSetFile) < 461) { // Empty navobj.xml file with just the gpx tag is 461 bytes, so anything smaller is obvious sign of a fatal crash while saving it last time, replace it with latest backup if available
1706  wxLogMessage("Navobjects file exists, but seems truncated!");
1707  newest_backup = FindNewestUsableBackup();
1708  if (wxFileExists(newest_backup)) {
1709  wxLogMessage("We do have a backup " + newest_backup + " that looks healthy and will use it.");
1710  wxCopyFile(newest_backup, m_sNavObjSetFile, true);
1711  }
1712  }
1713  } else { //File does not exist, try to recover from a backup
1714  newest_backup = FindNewestUsableBackup();
1715  if (wxFileExists(newest_backup)) {
1716  wxLogMessage("We do have a backup " + newest_backup + " that looks healthy and will use it.");
1717  wxCopyFile(newest_backup, m_sNavObjSetFile, true);
1718  } else {
1719  wxLogMessage("No navobjects.xml file or usable backup exist, will create a new one.");
1720  }
1721  }
1722  bool success = false;
1723  // We did all we could to have an usable navobj.xml file in scenarios where it did not exist or was clearly corrupted, let's try to load it
1724  if(::wxFileExists(m_sNavObjSetFile) && m_pNavObjectInputSet->load_file(m_sNavObjSetFile.fn_str()).status == pugi::xml_parse_status::status_ok) {
1725  CreateRotatingNavObjBackup(); // We only create backups when data is good, there is no point in saving something we can't even load
1726  success = m_pNavObjectInputSet->LoadAllGPXObjects(false, wpt_dups);
1727  } else {
1728  // It was still not valid after all our efforts and did not load as XML, let's rename it to a corrupted file and try to recover from a backup on last time
1729  wxString corrupted_file = m_sNavObjSetFile + wxDateTime::Now().Format(".corrupted.%Y-%m-%d-%H-%M-%S");
1730  wxRenameFile(m_sNavObjSetFile, corrupted_file, true);
1731  wxLogMessage("Error while loading navobjects from " + m_sNavObjSetFile + ", the corrupted file was renamed to " + corrupted_file);
1732  // If we got here with existing navobj.xml file, but it's corrupted, we can still try to recover from a backup
1733  if (newest_backup.IsEmpty()) { // If we got here with empty newest_backup, navobj.xml probably did exist, but was corrupted XML-wise, so we need to find a new backup
1734  newest_backup = FindNewestUsableBackup();
1735  }
1736  m_pNavObjectInputSet->reset();
1737  if (wxFileExists(newest_backup) && m_pNavObjectInputSet->load_file(newest_backup.fn_str()).status == pugi::xml_parse_status::status_ok) {
1738  success = m_pNavObjectInputSet->LoadAllGPXObjects(false, wpt_dups);
1739  wxLogMessage("We do have a healthy backup " + newest_backup + " and did load it.");
1740  } else {
1741  wxLogMessage("No usable backup found, a new navobj.xml file will be created.");
1742  m_pNavObjectInputSet->reset();
1743  }
1744  }
1745  if (success) {
1746  wxLogMessage(_T("Done loading navobjects, %d duplicate waypoints ignored"),
1747  wpt_dups);
1748  } else {
1749  wxLogMessage(_T("Failed to load navobjects, creating a new navobj.xml file."));
1750  }
1751  delete m_pNavObjectInputSet;
1752 
1753  if (::wxFileExists(m_sNavObjSetChangesFile)) {
1754  if (ReloadPendingChanges(m_sNavObjSetChangesFile)) {
1755  UpdateNavObj();
1756  }
1757  }
1758  m_pNavObjectChangesSet->Init(m_sNavObjSetChangesFile);
1759  // Signal to listeners to g_active_route that it's possible to look up guid.
1760  GlobalVar<wxString> active_route(&g_active_route);
1761  active_route.Notify();
1762 }
1763 
1764 bool MyConfig::LoadLayers(wxString &path) {
1765  wxArrayString file_array;
1766  wxDir dir;
1767  Layer *l;
1768  dir.Open(path);
1769  if (dir.IsOpened()) {
1770  wxString filename;
1771  bool cont = dir.GetFirst(&filename);
1772  while (cont) {
1773  file_array.Clear();
1774  filename.Prepend(wxFileName::GetPathSeparator());
1775  filename.Prepend(path);
1776  wxFileName f(filename);
1777  size_t nfiles = 0;
1778  if (f.GetExt().IsSameAs(wxT("gpx")))
1779  file_array.Add(filename); // single-gpx-file layer
1780  else {
1781  if (wxDir::Exists(filename)) {
1782  wxDir dir(filename);
1783  if (dir.IsOpened()) {
1784  nfiles = dir.GetAllFiles(filename, &file_array,
1785  wxT("*.gpx")); // layers subdirectory set
1786  }
1787  }
1788  }
1789 
1790  if (file_array.GetCount()) {
1791  l = new Layer();
1792  l->m_LayerID = ++g_LayerIdx;
1793  l->m_LayerFileName = file_array[0];
1794  if (file_array.GetCount() <= 1)
1795  wxFileName::SplitPath(file_array[0], NULL, NULL, &(l->m_LayerName),
1796  NULL, NULL);
1797  else
1798  wxFileName::SplitPath(filename, NULL, NULL, &(l->m_LayerName), NULL,
1799  NULL);
1800 
1801  bool bLayerViz = g_bShowLayers;
1802 
1803  if (g_VisibleLayers.Contains(l->m_LayerName)) bLayerViz = true;
1804  if (g_InvisibleLayers.Contains(l->m_LayerName)) bLayerViz = false;
1805 
1806  l->m_bHasVisibleNames = wxCHK_UNDETERMINED;
1807  if (g_VisiNameinLayers.Contains(l->m_LayerName))
1808  l->m_bHasVisibleNames = wxCHK_CHECKED;
1809  if (g_InVisiNameinLayers.Contains(l->m_LayerName))
1810  l->m_bHasVisibleNames = wxCHK_UNCHECKED;
1811 
1812  l->m_bIsVisibleOnChart = bLayerViz;
1813 
1814  wxString laymsg;
1815  laymsg.Printf(wxT("New layer %d: %s"), l->m_LayerID,
1816  l->m_LayerName.c_str());
1817  wxLogMessage(laymsg);
1818 
1819  pLayerList->Insert(l);
1820 
1821  // Load the entire file array as a single layer
1822 
1823  for (unsigned int i = 0; i < file_array.GetCount(); i++) {
1824  wxString file_path = file_array[i];
1825 
1826  if (::wxFileExists(file_path)) {
1828  if (pSet->load_file(file_path.fn_str()).status != pugi::xml_parse_status::status_ok) {
1829  wxLogMessage("Error loading GPX file " + file_path);
1830  pSet->reset();
1831  }
1832  long nItems = pSet->LoadAllGPXObjectsAsLayer(
1833  l->m_LayerID, bLayerViz, l->m_bHasVisibleNames);
1834  l->m_NoOfItems += nItems;
1835  l->m_LayerType = _("Persistent");
1836 
1837  wxString objmsg;
1838  objmsg.Printf(wxT("Loaded GPX file %s with %ld items."),
1839  file_path.c_str(), nItems);
1840  wxLogMessage(objmsg);
1841 
1842  delete pSet;
1843  }
1844  }
1845  }
1846 
1847  cont = dir.GetNext(&filename);
1848  }
1849  }
1850  g_bLayersLoaded = true;
1851 
1852  return true;
1853 }
1854 
1855 bool MyConfig::LoadChartDirArray(ArrayOfCDI &ChartDirArray) {
1856  // Chart Directories
1857  SetPath(_T ( "/ChartDirectories" ));
1858  int iDirMax = GetNumberOfEntries();
1859  if (iDirMax) {
1860  ChartDirArray.Empty();
1861  wxString str, val;
1862  long dummy;
1863  int nAdjustChartDirs = 0;
1864  int iDir = 0;
1865  bool bCont = pConfig->GetFirstEntry(str, dummy);
1866  while (bCont) {
1867  pConfig->Read(str, &val); // Get a Directory name
1868 
1869  wxString dirname(val);
1870  if (!dirname.IsEmpty()) {
1871  /* Special case for first time run after Windows install with sample
1872  chart data... We desire that the sample configuration file opencpn.ini
1873  should not contain any installation dependencies, so... Detect and
1874  update the sample [ChartDirectories] entries to point to the Shared
1875  Data directory For instance, if the (sample) opencpn.ini file should
1876  contain shortcut coded entries like:
1877 
1878  [ChartDirectories]
1879  ChartDir1=SampleCharts\\MaptechRegion7
1880 
1881  then this entry will be updated to be something like:
1882  ChartDir1=c:\Program Files\opencpn\SampleCharts\\MaptechRegion7
1883 
1884  */
1885  if (dirname.Find(_T ( "SampleCharts" )) ==
1886  0) // only update entries starting with "SampleCharts"
1887  {
1888  nAdjustChartDirs++;
1889 
1890  pConfig->DeleteEntry(str);
1891  wxString new_dir = dirname.Mid(dirname.Find(_T ( "SampleCharts" )));
1892  new_dir.Prepend(g_Platform->GetSharedDataDir());
1893  dirname = new_dir;
1894  }
1895 
1896  ChartDirInfo cdi;
1897  cdi.fullpath = dirname.BeforeFirst('^');
1898  cdi.magic_number = dirname.AfterFirst('^');
1899 
1900  ChartDirArray.Add(cdi);
1901  iDir++;
1902  }
1903 
1904  bCont = pConfig->GetNextEntry(str, dummy);
1905  }
1906 
1907  if (nAdjustChartDirs) pConfig->UpdateChartDirs(ChartDirArray);
1908  }
1909 
1910  return true;
1911 }
1912 
1913 void MyConfig::AddNewRoute(Route *r) {
1914  m_pNavObjectChangesSet->AddNewRoute(r);
1915 }
1916 
1917 void MyConfig::UpdateRoute(Route *r) {
1918  m_pNavObjectChangesSet->UpdateRoute(r);
1919 }
1920 
1921 void MyConfig::DeleteConfigRoute(Route *pr) {
1922  m_pNavObjectChangesSet->DeleteConfigRoute(pr);
1923 }
1924 
1925 void MyConfig::AddNewTrack(Track *pt) {
1926  m_pNavObjectChangesSet->AddNewTrack(pt);
1927 }
1928 
1929 void MyConfig::UpdateTrack(Track *pt) {
1930  m_pNavObjectChangesSet->UpdateTrack(pt);
1931 }
1932 
1933 void MyConfig::DeleteConfigTrack(Track *pt) {
1934  m_pNavObjectChangesSet->DeleteConfigTrack(pt);
1935 }
1936 
1937 void MyConfig::AddNewWayPoint(RoutePoint *pWP, int crm) {
1938  m_pNavObjectChangesSet->AddNewWayPoint(pWP);
1939 }
1940 
1941 void MyConfig::UpdateWayPoint(RoutePoint *pWP) {
1942  m_pNavObjectChangesSet->UpdateWayPoint(pWP);
1943 }
1944 
1945 void MyConfig::DeleteWayPoint(RoutePoint *pWP) {
1946  m_pNavObjectChangesSet->DeleteWayPoint(pWP);
1947 }
1948 
1949 void MyConfig::AddNewTrackPoint(TrackPoint *pWP,
1950  const wxString &parent_GUID) {
1951  m_pNavObjectChangesSet->AddNewTrackPoint(pWP, parent_GUID);
1952 }
1953 
1954 bool MyConfig::UpdateChartDirs(ArrayOfCDI &dir_array) {
1955  wxString key, dir;
1956  wxString str_buf;
1957 
1958  SetPath(_T ( "/ChartDirectories" ));
1959  int iDirMax = GetNumberOfEntries();
1960  if (iDirMax) {
1961  long dummy;
1962 
1963  for (int i = 0; i < iDirMax; i++) {
1964  GetFirstEntry(key, dummy);
1965  DeleteEntry(key, false);
1966  }
1967  }
1968 
1969  iDirMax = dir_array.GetCount();
1970 
1971  for (int iDir = 0; iDir < iDirMax; iDir++) {
1972  ChartDirInfo cdi = dir_array[iDir];
1973 
1974  wxString dirn = cdi.fullpath;
1975  dirn.Append(_T("^"));
1976  dirn.Append(cdi.magic_number);
1977 
1978  str_buf.Printf(_T ( "ChartDir%d" ), iDir + 1);
1979 
1980  Write(str_buf, dirn);
1981  }
1982 
1983 // Avoid nonsense log errors...
1984 #ifdef __ANDROID__
1985  wxLogNull logNo;
1986 #endif
1987 
1988  Flush();
1989  return true;
1990 }
1991 
1992 void MyConfig::CreateConfigGroups(ChartGroupArray *pGroupArray) {
1993  if (!pGroupArray) return;
1994 
1995  SetPath(_T ( "/Groups" ));
1996  Write(_T ( "GroupCount" ), (int)pGroupArray->GetCount());
1997 
1998  for (unsigned int i = 0; i < pGroupArray->GetCount(); i++) {
1999  ChartGroup *pGroup = pGroupArray->Item(i);
2000  wxString s;
2001  s.Printf(_T("Group%d"), i + 1);
2002  s.Prepend(_T ( "/Groups/" ));
2003  SetPath(s);
2004 
2005  Write(_T ( "GroupName" ), pGroup->m_group_name);
2006  Write(_T ( "GroupItemCount" ), (int)pGroup->m_element_array.size());
2007 
2008  for (unsigned int j = 0; j < pGroup->m_element_array.size(); j++) {
2009  wxString sg;
2010  sg.Printf(_T("Group%d/Item%d"), i + 1, j);
2011  sg.Prepend(_T ( "/Groups/" ));
2012  SetPath(sg);
2013  Write(_T ( "IncludeItem" ), pGroup->m_element_array[j].m_element_name);
2014 
2015  wxString t;
2016  wxArrayString u = pGroup->m_element_array[j].m_missing_name_array;
2017  if (u.GetCount()) {
2018  for (unsigned int k = 0; k < u.GetCount(); k++) {
2019  t += u[k];
2020  t += _T(";");
2021  }
2022  Write(_T ( "ExcludeItems" ), t);
2023  }
2024  }
2025  }
2026 }
2027 
2028 void MyConfig::DestroyConfigGroups(void) {
2029  DeleteGroup(_T ( "/Groups" )); // zap
2030 }
2031 
2032 void MyConfig::LoadConfigGroups(ChartGroupArray *pGroupArray) {
2033  SetPath(_T ( "/Groups" ));
2034  unsigned int group_count;
2035  Read(_T ( "GroupCount" ), (int *)&group_count, 0);
2036 
2037  for (unsigned int i = 0; i < group_count; i++) {
2038  ChartGroup *pGroup = new ChartGroup;
2039  wxString s;
2040  s.Printf(_T("Group%d"), i + 1);
2041  s.Prepend(_T ( "/Groups/" ));
2042  SetPath(s);
2043 
2044  wxString t;
2045  Read(_T ( "GroupName" ), &t);
2046  pGroup->m_group_name = t;
2047 
2048  unsigned int item_count;
2049  Read(_T ( "GroupItemCount" ), (int *)&item_count);
2050  for (unsigned int j = 0; j < item_count; j++) {
2051  wxString sg;
2052  sg.Printf(_T("Group%d/Item%d"), i + 1, j);
2053  sg.Prepend(_T ( "/Groups/" ));
2054  SetPath(sg);
2055 
2056  wxString v;
2057  Read(_T ( "IncludeItem" ), &v);
2058 
2059  ChartGroupElement pelement{v};
2060  wxString u;
2061  if (Read(_T ( "ExcludeItems" ), &u)) {
2062  if (!u.IsEmpty()) {
2063  wxStringTokenizer tk(u, _T(";"));
2064  while (tk.HasMoreTokens()) {
2065  wxString token = tk.GetNextToken();
2066  pelement.m_missing_name_array.Add(token);
2067  }
2068  }
2069  }
2070  pGroup->m_element_array.push_back(std::move(pelement));
2071  }
2072  pGroupArray->Add(pGroup);
2073  }
2074 }
2075 
2076 void MyConfig::LoadCanvasConfigs(bool bApplyAsTemplate) {
2077  wxString s;
2078  canvasConfig *pcc;
2079  auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
2080 
2081  SetPath(_T ( "/Canvas" ));
2082 
2083  // If the canvas config has never been set/persisted, use the global settings
2084  if (!HasEntry(_T ( "CanvasConfig" ))) {
2085  pcc = new canvasConfig(0);
2086  pcc->LoadFromLegacyConfig(this);
2087  config_array.Add(pcc);
2088 
2089  return;
2090  }
2091 
2092  Read(_T ( "CanvasConfig" ), (int *)&g_canvasConfig, 0);
2093 
2094 
2095  // Do not recreate canvasConfigs when applying config dynamically
2096  if (config_array.GetCount() == 0) { // This is initial load from startup
2097  s.Printf(_T("/Canvas/CanvasConfig%d"), 1);
2098  SetPath(s);
2099  canvasConfig *pcca = new canvasConfig(0);
2100  LoadConfigCanvas(pcca, bApplyAsTemplate);
2101  config_array.Add(pcca);
2102 
2103  s.Printf(_T("/Canvas/CanvasConfig%d"), 2);
2104  SetPath(s);
2105  pcca = new canvasConfig(1);
2106  LoadConfigCanvas(pcca, bApplyAsTemplate);
2107  config_array.Add(pcca);
2108  } else { // This is a dynamic (i.e. Template) load
2109  canvasConfig *pcca = config_array[0];
2110  s.Printf(_T("/Canvas/CanvasConfig%d"), 1);
2111  SetPath(s);
2112  LoadConfigCanvas(pcca, bApplyAsTemplate);
2113 
2114  if (config_array.GetCount() > 1) {
2115  canvasConfig *pcca = config_array[1];
2116  s.Printf(_T("/Canvas/CanvasConfig%d"), 2);
2117  SetPath(s);
2118  LoadConfigCanvas(pcca, bApplyAsTemplate);
2119  } else {
2120  s.Printf(_T("/Canvas/CanvasConfig%d"), 2);
2121  SetPath(s);
2122  pcca = new canvasConfig(1);
2123  LoadConfigCanvas(pcca, bApplyAsTemplate);
2124  config_array.Add(pcca);
2125  }
2126  }
2127 }
2128 
2129 void MyConfig::LoadConfigCanvas(canvasConfig *cConfig, bool bApplyAsTemplate) {
2130  wxString st;
2131  double st_lat, st_lon;
2132 
2133  if (!bApplyAsTemplate) {
2134  // Reasonable starting point
2135  cConfig->iLat = START_LAT; // display viewpoint
2136  cConfig->iLon = START_LON;
2137 
2138  if (Read(_T ( "canvasVPLatLon" ), &st)) {
2139  sscanf(st.mb_str(wxConvUTF8), "%lf,%lf", &st_lat, &st_lon);
2140 
2141  // Sanity check the lat/lon...both have to be reasonable.
2142  if (fabs(st_lon) < 360.) {
2143  while (st_lon < -180.) st_lon += 360.;
2144 
2145  while (st_lon > 180.) st_lon -= 360.;
2146 
2147  cConfig->iLon = st_lon;
2148  }
2149 
2150  if (fabs(st_lat) < 90.0) cConfig->iLat = st_lat;
2151  }
2152 
2153  cConfig->iScale = .0003; // decent initial value
2154  cConfig->iRotation = 0;
2155 
2156  double st_view_scale;
2157  if (Read(wxString(_T ( "canvasVPScale" )), &st)) {
2158  sscanf(st.mb_str(wxConvUTF8), "%lf", &st_view_scale);
2159  // Sanity check the scale
2160  st_view_scale = fmax(st_view_scale, .001 / 32);
2161  st_view_scale = fmin(st_view_scale, 4);
2162  cConfig->iScale = st_view_scale;
2163  }
2164 
2165  double st_rotation;
2166  if (Read(wxString(_T ( "canvasVPRotation" )), &st)) {
2167  sscanf(st.mb_str(wxConvUTF8), "%lf", &st_rotation);
2168  // Sanity check the rotation
2169  st_rotation = fmin(st_rotation, 360);
2170  st_rotation = fmax(st_rotation, 0);
2171  cConfig->iRotation = st_rotation * PI / 180.;
2172  }
2173 
2174  Read(_T ( "canvasInitialdBIndex" ), &cConfig->DBindex, 0);
2175  Read(_T ( "canvasbFollow" ), &cConfig->bFollow, 0);
2176 
2177  Read(_T ( "canvasCourseUp" ), &cConfig->bCourseUp, 0);
2178  Read(_T ( "canvasHeadUp" ), &cConfig->bHeadUp, 0);
2179  Read(_T ( "canvasLookahead" ), &cConfig->bLookahead, 0);
2180  }
2181 
2182  Read(_T ( "ActiveChartGroup" ), &cConfig->GroupID, 0);
2183 
2184  // Special check for group selection when applied as template
2185  if (cConfig->GroupID && bApplyAsTemplate) {
2186  if (cConfig->GroupID > (int)g_pGroupArray->GetCount()) cConfig->GroupID = 0;
2187  }
2188 
2189  Read(_T ( "canvasShowTides" ), &cConfig->bShowTides, 0);
2190  Read(_T ( "canvasShowCurrents" ), &cConfig->bShowCurrents, 0);
2191 
2192  Read(_T ( "canvasQuilt" ), &cConfig->bQuilt, 1);
2193  Read(_T ( "canvasShowGrid" ), &cConfig->bShowGrid, 0);
2194  Read(_T ( "canvasShowOutlines" ), &cConfig->bShowOutlines, 0);
2195  Read(_T ( "canvasShowDepthUnits" ), &cConfig->bShowDepthUnits, 0);
2196 
2197  Read(_T ( "canvasShowAIS" ), &cConfig->bShowAIS, 1);
2198  Read(_T ( "canvasAttenAIS" ), &cConfig->bAttenAIS, 0);
2199 
2200  // ENC options
2201  Read(_T ( "canvasShowENCText" ), &cConfig->bShowENCText, 1);
2202  Read(_T ( "canvasENCDisplayCategory" ), &cConfig->nENCDisplayCategory,
2203  STANDARD);
2204  Read(_T ( "canvasENCShowDepths" ), &cConfig->bShowENCDepths, 1);
2205  Read(_T ( "canvasENCShowBuoyLabels" ), &cConfig->bShowENCBuoyLabels, 1);
2206  Read(_T ( "canvasENCShowLightDescriptions" ),
2207  &cConfig->bShowENCLightDescriptions, 1);
2208  Read(_T ( "canvasENCShowLights" ), &cConfig->bShowENCLights, 1);
2209  Read(_T ( "canvasENCShowVisibleSectorLights" ),
2210  &cConfig->bShowENCVisibleSectorLights, 0);
2211  Read(_T ( "canvasENCShowAnchorInfo" ), &cConfig->bShowENCAnchorInfo, 0);
2212  Read(_T ( "canvasENCShowDataQuality" ), &cConfig->bShowENCDataQuality, 0);
2213 
2214  int sx, sy;
2215  Read(_T ( "canvasSizeX" ), &sx, 0);
2216  Read(_T ( "canvasSizeY" ), &sy, 0);
2217  cConfig->canvasSize = wxSize(sx, sy);
2218 }
2219 
2220 void MyConfig::SaveCanvasConfigs() {
2221  auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
2222 
2223  SetPath(_T ( "/Canvas" ));
2224  Write(_T ( "CanvasConfig" ), (int)g_canvasConfig);
2225 
2226  wxString s;
2227  canvasConfig *pcc;
2228 
2229  switch (g_canvasConfig) {
2230  case 0:
2231  default:
2232 
2233  s.Printf(_T("/Canvas/CanvasConfig%d"), 1);
2234  SetPath(s);
2235 
2236  if (config_array.GetCount() > 0) {
2237  pcc = config_array.Item(0);
2238  if (pcc) {
2239  SaveConfigCanvas(pcc);
2240  }
2241  }
2242  break;
2243 
2244  case 1:
2245 
2246  if (config_array.GetCount() > 1) {
2247  s.Printf(_T("/Canvas/CanvasConfig%d"), 1);
2248  SetPath(s);
2249  pcc = config_array.Item(0);
2250  if (pcc) {
2251  SaveConfigCanvas(pcc);
2252  }
2253 
2254  s.Printf(_T("/Canvas/CanvasConfig%d"), 2);
2255  SetPath(s);
2256  pcc = config_array.Item(1);
2257  if (pcc) {
2258  SaveConfigCanvas(pcc);
2259  }
2260  }
2261  break;
2262  }
2263 }
2264 
2265 void MyConfig::SaveConfigCanvas(canvasConfig *cConfig) {
2266  wxString st1;
2267 
2268  if (cConfig->canvas) {
2269  ViewPort vp = cConfig->canvas->GetVP();
2270 
2271  if (vp.IsValid()) {
2272  st1.Printf(_T ( "%10.4f,%10.4f" ), vp.clat, vp.clon);
2273  Write(_T ( "canvasVPLatLon" ), st1);
2274  st1.Printf(_T ( "%g" ), vp.view_scale_ppm);
2275  Write(_T ( "canvasVPScale" ), st1);
2276  st1.Printf(_T ( "%i" ), ((int)(vp.rotation * 180 / PI)) % 360);
2277  Write(_T ( "canvasVPRotation" ), st1);
2278  }
2279 
2280  int restore_dbindex = 0;
2281  ChartStack *pcs = cConfig->canvas->GetpCurrentStack();
2282  if (pcs) restore_dbindex = pcs->GetCurrentEntrydbIndex();
2283  if (cConfig->canvas->GetQuiltMode())
2284  restore_dbindex = cConfig->canvas->GetQuiltReferenceChartIndex();
2285  Write(_T ( "canvasInitialdBIndex" ), restore_dbindex);
2286 
2287  Write(_T ( "canvasbFollow" ), cConfig->canvas->m_bFollow);
2288  Write(_T ( "ActiveChartGroup" ), cConfig->canvas->m_groupIndex);
2289 
2290  Write(_T ( "canvasQuilt" ), cConfig->canvas->GetQuiltMode());
2291  Write(_T ( "canvasShowGrid" ), cConfig->canvas->GetShowGrid());
2292  Write(_T ( "canvasShowOutlines" ), cConfig->canvas->GetShowOutlines());
2293  Write(_T ( "canvasShowDepthUnits" ), cConfig->canvas->GetShowDepthUnits());
2294 
2295  Write(_T ( "canvasShowAIS" ), cConfig->canvas->GetShowAIS());
2296  Write(_T ( "canvasAttenAIS" ), cConfig->canvas->GetAttenAIS());
2297 
2298  Write(_T ( "canvasShowTides" ), cConfig->canvas->GetbShowTide());
2299  Write(_T ( "canvasShowCurrents" ), cConfig->canvas->GetbShowCurrent());
2300 
2301  // ENC options
2302  Write(_T ( "canvasShowENCText" ), cConfig->canvas->GetShowENCText());
2303  Write(_T ( "canvasENCDisplayCategory" ),
2304  cConfig->canvas->GetENCDisplayCategory());
2305  Write(_T ( "canvasENCShowDepths" ), cConfig->canvas->GetShowENCDepth());
2306  Write(_T ( "canvasENCShowBuoyLabels" ),
2307  cConfig->canvas->GetShowENCBuoyLabels());
2308  Write(_T ( "canvasENCShowLightDescriptions" ),
2309  cConfig->canvas->GetShowENCLightDesc());
2310  Write(_T ( "canvasENCShowLights" ), cConfig->canvas->GetShowENCLights());
2311  Write(_T ( "canvasENCShowVisibleSectorLights" ),
2312  cConfig->canvas->GetShowVisibleSectors());
2313  Write(_T ( "canvasENCShowAnchorInfo" ),
2314  cConfig->canvas->GetShowENCAnchor());
2315  Write(_T ( "canvasENCShowDataQuality" ),
2316  cConfig->canvas->GetShowENCDataQual());
2317  Write(_T ( "canvasCourseUp" ),
2318  cConfig->canvas->GetUpMode() == COURSE_UP_MODE);
2319  Write(_T ( "canvasHeadUp" ), cConfig->canvas->GetUpMode() == HEAD_UP_MODE);
2320  Write(_T ( "canvasLookahead" ), cConfig->canvas->GetLookahead());
2321 
2322  int width = cConfig->canvas->GetSize().x;
2323  // if(cConfig->canvas->IsPrimaryCanvas()){
2324  // width = wxMax(width, gFrame->GetClientSize().x / 10);
2325  // }
2326  // else{
2327  // width = wxMin(width, gFrame->GetClientSize().x * 9 / 10);
2328  // }
2329 
2330  Write(_T ( "canvasSizeX" ), width);
2331  Write(_T ( "canvasSizeY" ), cConfig->canvas->GetSize().y);
2332  }
2333 }
2334 
2335 void MyConfig::UpdateSettings() {
2336  // Temporarily suppress logging of trivial non-fatal wxLogSysError() messages
2337  // provoked by Android security...
2338 #ifdef __ANDROID__
2339  wxLogNull logNo;
2340 #endif
2341 
2342  // Global options and settings
2343  SetPath(_T ( "/Settings" ));
2344 
2345  Write(_T ( "LastAppliedTemplate" ), g_lastAppliedTemplateGUID);
2346  Write(_T ( "CompatOS" ), g_compatOS);
2347  Write(_T ( "CompatOsVersion" ), g_compatOsVersion);
2348  Write(_T ( "ConfigVersionString" ), g_config_version_string);
2349  if (wxIsEmpty(g_CmdSoundString))
2350  g_CmdSoundString = wxString(OCPN_SOUND_CMD);
2351  Write(_T( "CmdSoundString" ), g_CmdSoundString);
2352  Write(_T ( "NavMessageShown" ), n_NavMessageShown);
2353  Write(_T ( "InlandEcdis" ), g_bInlandEcdis);
2354 
2355  Write(_T ( "AndroidVersionCode" ), g_AndroidVersionCode);
2356 
2357  Write(_T ( "UIexpert" ), g_bUIexpert);
2358  Write(_T( "SpaceDropMark" ), g_bSpaceDropMark);
2359  // Write( _T ( "UIStyle" ), g_StyleManager->GetStyleNextInvocation() );
2360  // //Not desired for O5 MUI
2361 
2362  Write(_T ( "ShowStatusBar" ), g_bShowStatusBar);
2363 #ifndef __WXOSX__
2364  Write(_T ( "ShowMenuBar" ), g_bShowMenuBar);
2365 #endif
2366  Write(_T ( "DefaultFontSize" ), g_default_font_size);
2367  Write(_T ( "DefaultFontFacename" ), g_default_font_facename);
2368 
2369  Write(_T ( "Fullscreen" ), g_bFullscreen);
2370  Write(_T ( "ShowCompassWindow" ), g_bShowCompassWin);
2371  Write(_T ( "SetSystemTime" ), s_bSetSystemTime);
2372  Write(_T ( "ShowGrid" ), g_bDisplayGrid);
2373  Write(_T ( "PlayShipsBells" ), g_bPlayShipsBells);
2374  Write(_T ( "SoundDeviceIndex" ), g_iSoundDeviceIndex);
2375  Write(_T ( "FullscreenToolbar" ), g_bFullscreenToolbar);
2376  Write(_T ( "TransparentToolbar" ), g_bTransparentToolbar);
2377  Write(_T ( "PermanentMOBIcon" ), g_bPermanentMOBIcon);
2378  Write(_T ( "ShowLayers" ), g_bShowLayers);
2379  Write(_T ( "AutoAnchorDrop" ), g_bAutoAnchorMark);
2380  Write(_T ( "ShowChartOutlines" ), g_bShowOutlines);
2381  Write(_T ( "ShowActiveRouteTotal" ), g_bShowRouteTotal);
2382  Write(_T ( "ShowActiveRouteHighway" ), g_bShowActiveRouteHighway);
2383  Write(_T ( "SDMMFormat" ), g_iSDMMFormat);
2384  Write(_T ( "MostRecentGPSUploadConnection" ), g_uploadConnection);
2385  Write(_T ( "ShowChartBar" ), g_bShowChartBar);
2386 
2387  Write(_T ( "GUIScaleFactor" ), g_GUIScaleFactor);
2388  Write(_T ( "ChartObjectScaleFactor" ), g_ChartScaleFactor);
2389  Write(_T ( "ShipScaleFactor" ), g_ShipScaleFactor);
2390  Write(_T ( "ENCSoundingScaleFactor" ), g_ENCSoundingScaleFactor);
2391  Write(_T ( "ENCTextScaleFactor" ), g_ENCTextScaleFactor);
2392  Write(_T ( "ObjQueryAppendFilesExt" ), g_ObjQFileExt);
2393 
2394  // Plugin catalog persistent values.
2395  Write(_T( "CatalogCustomURL"), g_catalog_custom_url);
2396  Write(_T( "CatalogChannel"), g_catalog_channel);
2397 
2398  Write(_T ( "FilterNMEA_Avg" ), g_bfilter_cogsog);
2399  Write(_T ( "FilterNMEA_Sec" ), g_COGFilterSec);
2400 
2401  Write(_T ( "TrackContinuous" ), g_btrackContinuous);
2402 
2403  Write(_T ( "ShowTrue" ), g_bShowTrue);
2404  Write(_T ( "ShowMag" ), g_bShowMag);
2405  Write(_T ( "UserMagVariation" ), wxString::Format(_T("%.2f"), g_UserVar));
2406 
2407  Write(_T ( "CM93DetailFactor" ), g_cm93_zoom_factor);
2408  Write(_T ( "CM93DetailZoomPosX" ), g_detailslider_dialog_x);
2409  Write(_T ( "CM93DetailZoomPosY" ), g_detailslider_dialog_y);
2410  Write(_T ( "ShowCM93DetailSlider" ), g_bShowDetailSlider);
2411 
2412  Write(_T ( "SkewToNorthUp" ), g_bskew_comp);
2413  if (!g_bdisable_opengl) { // Only modify the saved value if OpenGL is not force-disabled from the command line
2414  Write(_T ( "OpenGL" ), g_bopengl);
2415  }
2416  Write(_T ( "SoftwareGL" ), g_bSoftwareGL);
2417 
2418  Write(_T ( "ZoomDetailFactor" ), g_chart_zoom_modifier_raster);
2419  Write(_T ( "ZoomDetailFactorVector" ), g_chart_zoom_modifier_vector);
2420 
2421  Write(_T ( "FogOnOverzoom" ), g_fog_overzoom);
2422  Write(_T ( "OverzoomVectorScale" ), g_oz_vector_scale);
2423  Write(_T ( "OverzoomEmphasisBase" ), g_overzoom_emphasis_base);
2424  Write(_T ( "PlusMinusZoomFactor" ), g_plus_minus_zoom_factor);
2425  Write("MouseZoomSensitivity",
2426  MouseZoom::ui_to_config(g_mouse_zoom_sensitivity_ui));
2427  Write(_T ( "ShowMUIZoomButtons" ), g_bShowMuiZoomButtons);
2428 
2429 #ifdef ocpnUSE_GL
2430  /* opengl options */
2431  Write(_T ( "UseAcceleratedPanning" ), g_GLOptions.m_bUseAcceleratedPanning);
2432 
2433  Write(_T ( "GPUTextureCompression" ), g_GLOptions.m_bTextureCompression);
2434  Write(_T ( "GPUTextureCompressionCaching" ),
2435  g_GLOptions.m_bTextureCompressionCaching);
2436  Write(_T ( "GPUTextureDimension" ), g_GLOptions.m_iTextureDimension);
2437  Write(_T ( "GPUTextureMemSize" ), g_GLOptions.m_iTextureMemorySize);
2438  Write(_T ( "PolygonSmoothing" ), g_GLOptions.m_GLPolygonSmoothing);
2439  Write(_T ( "LineSmoothing" ), g_GLOptions.m_GLLineSmoothing);
2440 #endif
2441  Write(_T ( "SmoothPanZoom" ), g_bsmoothpanzoom);
2442 
2443  Write(_T ( "CourseUpMode" ), g_bCourseUp);
2444  if (!g_bInlandEcdis) Write(_T ( "LookAheadMode" ), g_bLookAhead);
2445  Write(_T ( "COGUPAvgSeconds" ), g_COGAvgSec);
2446  Write(_T ( "UseMagAPB" ), g_bMagneticAPB);
2447 
2448  Write(_T ( "OwnshipCOGPredictorMinutes" ), g_ownship_predictor_minutes);
2449  Write(_T ( "OwnshipCOGPredictorStyle" ), g_cog_predictor_style);
2450  Write(_T ( "OwnshipCOGPredictorColor" ), g_cog_predictor_color);
2451  Write(_T ( "OwnshipCOGPredictorEndmarker" ), g_cog_predictor_endmarker);
2452  Write(_T ( "OwnshipCOGPredictorWidth" ), g_cog_predictor_width);
2453  Write(_T ( "OwnshipHDTPredictorStyle" ), g_ownship_HDTpredictor_style);
2454  Write(_T ( "OwnshipHDTPredictorColor" ), g_ownship_HDTpredictor_color);
2455  Write(_T ( "OwnshipHDTPredictorEndmarker" ), g_ownship_HDTpredictor_endmarker);
2456  Write(_T ( "OwnshipHDTPredictorWidth" ), g_ownship_HDTpredictor_width);
2457  Write(_T ( "OwnshipHDTPredictorMiles" ), g_ownship_HDTpredictor_miles);
2458 
2459  Write(_T ( "OwnShipIconType" ), g_OwnShipIconType);
2460  Write(_T ( "OwnShipLength" ), g_n_ownship_length_meters);
2461  Write(_T ( "OwnShipWidth" ), g_n_ownship_beam_meters);
2462  Write(_T ( "OwnShipGPSOffsetX" ), g_n_gps_antenna_offset_x);
2463  Write(_T ( "OwnShipGPSOffsetY" ), g_n_gps_antenna_offset_y);
2464  Write(_T ( "OwnShipMinSize" ), g_n_ownship_min_mm);
2465  Write(_T ( "OwnShipSogCogCalc" ), g_own_ship_sog_cog_calc);
2466  Write(_T ( "OwnShipSogCogCalcDampSec"), g_own_ship_sog_cog_calc_damp_sec);
2467  Write(_T ( "ShowDirectRouteLine"), g_bShowShipToActive);
2468  Write(_T ( "DirectRouteLineStyle"), g_shipToActiveStyle);
2469  Write(_T ( "DirectRouteLineColor" ), g_shipToActiveColor);
2470 
2471  wxString racr;
2472  // racr.Printf( _T ( "%g" ), g_n_arrival_circle_radius );
2473  // Write( _T ( "RouteArrivalCircleRadius" ), racr );
2474  Write(_T ( "RouteArrivalCircleRadius" ),
2475  wxString::Format(_T("%.2f"), g_n_arrival_circle_radius));
2476 
2477  Write(_T ( "ChartQuilting" ), g_bQuiltEnable);
2478 
2479  Write(_T ( "NMEALogWindowSizeX" ), NMEALogWindow::GetInstance().GetSizeW());
2480  Write(_T ( "NMEALogWindowSizeY" ), NMEALogWindow::GetInstance().GetSizeH());
2481  Write(_T ( "NMEALogWindowPosX" ), NMEALogWindow::GetInstance().GetPosX());
2482  Write(_T ( "NMEALogWindowPosY" ), NMEALogWindow::GetInstance().GetPosY());
2483 
2484  Write(_T ( "PreserveScaleOnX" ), g_bPreserveScaleOnX);
2485 
2486  Write(_T ( "StartWithTrackActive" ), g_bTrackCarryOver);
2487  Write(_T ( "AutomaticDailyTracks" ), g_bTrackDaily);
2488  Write(_T ( "TrackRotateAt" ), g_track_rotate_time);
2489  Write(_T ( "TrackRotateTimeType" ), g_track_rotate_time_type);
2490  Write(_T ( "HighlightTracks" ), g_bHighliteTracks);
2491 
2492  Write(_T ( "InitialStackIndex" ), g_restore_stackindex);
2493  Write(_T ( "InitialdBIndex" ), g_restore_dbindex);
2494 
2495  Write(_T( "NMEAAPBPrecision" ), g_NMEAAPBPrecision);
2496 
2497  Write(_T("TalkerIdText"), g_TalkerIdText);
2498  Write(_T("ShowTrackPointTime"), g_bShowTrackPointTime);
2499 
2500  Write(_T ( "AnchorWatch1GUID" ), g_AW1GUID);
2501  Write(_T ( "AnchorWatch2GUID" ), g_AW2GUID);
2502 
2503  Write(_T ( "ToolbarX" ), g_maintoolbar_x);
2504  Write(_T ( "ToolbarY" ), g_maintoolbar_y);
2505  // Write( _T ( "ToolbarOrient" ), g_maintoolbar_orient );
2506 
2507  Write(_T ( "iENCToolbarX" ), g_iENCToolbarPosX);
2508  Write(_T ( "iENCToolbarY" ), g_iENCToolbarPosY);
2509 
2510  if (!g_bInlandEcdis) {
2511  Write(_T ( "GlobalToolbarConfig" ), g_toolbarConfig);
2512  Write(_T ( "DistanceFormat" ), g_iDistanceFormat);
2513  Write(_T ( "SpeedFormat" ), g_iSpeedFormat);
2514  Write(_T ( "WindSpeedFormat" ), g_iWindSpeedFormat);
2515  Write(_T ( "ShowDepthUnits" ), g_bShowDepthUnits);
2516  Write(_T ( "TemperatureFormat" ), g_iTempFormat);
2517  }
2518  Write(_T ( "GPSIdent" ), g_GPS_Ident);
2519  Write("ActiveRoute" , g_active_route);
2520  Write("PersistActiveRoute", g_persist_active_route);
2521  Write(_T ( "UseGarminHostUpload" ), g_bGarminHostUpload);
2522 
2523  Write(_T ( "MobileTouch" ), g_btouch);
2524  Write(_T ( "ResponsiveGraphics" ), g_bresponsive);
2525  Write(_T ( "EnableRolloverBlock" ), g_bRollover);
2526 
2527  Write(_T ( "AutoHideToolbar" ), g_bAutoHideToolbar);
2528  Write(_T ( "AutoHideToolbarSecs" ), g_nAutoHideToolbar);
2529 
2530  wxString st0;
2531  for (const auto &mm : g_config_display_size_mm) {
2532  st0.Append(wxString::Format(_T ( "%zu," ), mm));
2533  }
2534  st0.RemoveLast(); //Strip last comma
2535  Write(_T ( "DisplaySizeMM" ), st0);
2536  Write(_T ( "DisplaySizeManual" ), g_config_display_size_manual);
2537 
2538  Write(_T ( "SelectionRadiusMM" ), g_selection_radius_mm);
2539  Write(_T ( "SelectionRadiusTouchMM" ), g_selection_radius_touch_mm);
2540 
2541  st0.Printf(_T ( "%g" ), g_PlanSpeed);
2542  Write(_T ( "PlanSpeed" ), st0);
2543 
2544  if (g_bLayersLoaded) {
2545  wxString vis, invis, visnames, invisnames;
2546  LayerList::iterator it;
2547  int index = 0;
2548  for (it = (*pLayerList).begin(); it != (*pLayerList).end(); ++it, ++index) {
2549  Layer *lay = (Layer *)(*it);
2550  if (lay->IsVisibleOnChart())
2551  vis += (lay->m_LayerName) + _T(";");
2552  else
2553  invis += (lay->m_LayerName) + _T(";");
2554 
2555  if (lay->HasVisibleNames() == wxCHK_CHECKED) {
2556  visnames += (lay->m_LayerName) + _T(";");
2557  } else if (lay->HasVisibleNames() == wxCHK_UNCHECKED) {
2558  invisnames += (lay->m_LayerName) + _T(";");
2559  }
2560  }
2561  Write(_T ( "VisibleLayers" ), vis);
2562  Write(_T ( "InvisibleLayers" ), invis);
2563  Write(_T ( "VisNameInLayers" ), visnames);
2564  Write(_T ( "InvisNameInLayers" ), invisnames);
2565  }
2566  Write(_T ( "Locale" ), g_locale);
2567  Write(_T ( "LocaleOverride" ), g_localeOverride);
2568 
2569  Write(_T ( "KeepNavobjBackups" ), g_navobjbackups);
2570  Write(_T ( "LegacyInputCOMPortFilterBehaviour" ),
2571  g_b_legacy_input_filter_behaviour);
2572  Write(_T( "AdvanceRouteWaypointOnArrivalOnly" ),
2573  g_bAdvanceRouteWaypointOnArrivalOnly);
2574 
2575  // LIVE ETA OPTION
2576  Write(_T( "LiveETA" ), g_bShowLiveETA);
2577  Write(_T( "DefaultBoatSpeed" ), g_defaultBoatSpeed);
2578 
2579  // S57 Object Filter Settings
2580 
2581  SetPath(_T ( "/Settings/ObjectFilter" ));
2582 
2583  if (ps52plib) {
2584  for (unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount();
2585  iPtr++) {
2586  OBJLElement *pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
2587 
2588  wxString st1(_T ( "viz" ));
2589  char name[7];
2590  strncpy(name, pOLE->OBJLName, 6);
2591  name[6] = 0;
2592  st1.Append(wxString(name, wxConvUTF8));
2593  Write(st1, pOLE->nViz);
2594  }
2595  }
2596 
2597  // Global State
2598 
2599  SetPath(_T ( "/Settings/GlobalState" ));
2600 
2601  wxString st1;
2602 
2603  // if( cc1 ) {
2604  // ViewPort vp = cc1->GetVP();
2605  //
2606  // if( vp.IsValid() ) {
2607  // st1.Printf( _T ( "%10.4f,%10.4f" ), vp.clat, vp.clon );
2608  // Write( _T ( "VPLatLon" ), st1 );
2609  // st1.Printf( _T ( "%g" ), vp.view_scale_ppm );
2610  // Write( _T ( "VPScale" ), st1 );
2611  // st1.Printf( _T ( "%i" ), ((int)(vp.rotation * 180 / PI)) % 360
2612  // ); Write( _T ( "VPRotation" ), st1 );
2613  // }
2614  // }
2615 
2616  st1.Printf(_T ( "%10.4f, %10.4f" ), gLat, gLon);
2617  Write(_T ( "OwnShipLatLon" ), st1);
2618 
2619  // Various Options
2620  SetPath(_T ( "/Settings/GlobalState" ));
2621  if (!g_bInlandEcdis)
2622  Write(_T ( "nColorScheme" ), (int)gFrame->GetColorScheme());
2623 
2624  Write(_T ( "FrameWinX" ), g_nframewin_x);
2625  Write(_T ( "FrameWinY" ), g_nframewin_y);
2626  Write(_T ( "FrameWinPosX" ), g_nframewin_posx);
2627  Write(_T ( "FrameWinPosY" ), g_nframewin_posy);
2628  Write(_T ( "FrameMax" ), g_bframemax);
2629 
2630  Write(_T ( "ClientPosX" ), g_lastClientRectx);
2631  Write(_T ( "ClientPosY" ), g_lastClientRecty);
2632  Write(_T ( "ClientSzX" ), g_lastClientRectw);
2633  Write(_T ( "ClientSzY" ), g_lastClientRecth);
2634 
2635  Write(_T ( "S52_DEPTH_UNIT_SHOW" ), g_nDepthUnitDisplay);
2636 
2637  Write(_T( "RoutePropSizeX" ), g_route_prop_sx);
2638  Write(_T( "RoutePropSizeY" ), g_route_prop_sy);
2639  Write(_T( "RoutePropPosX" ), g_route_prop_x);
2640  Write(_T( "RoutePropPosY" ), g_route_prop_y);
2641 
2642  // Sounds
2643  SetPath(_T ( "/Settings/Audio" ));
2644  Write(_T ( "AISAlertSoundFile" ), g_AIS_sound_file);
2645  Write(_T ( "DSCAlertSoundFile" ), g_DSC_sound_file);
2646  Write(_T ( "SARTAlertSoundFile" ), g_SART_sound_file);
2647  Write(_T ( "AnchorAlarmSoundFile" ), g_anchorwatch_sound_file);
2648 
2649  Write(_T ( "bAIS_GCPA_AlertAudio" ), g_bAIS_GCPA_Alert_Audio);
2650  Write(_T ( "bAIS_SART_AlertAudio" ), g_bAIS_SART_Alert_Audio);
2651  Write(_T ( "bAIS_DSC_AlertAudio" ), g_bAIS_DSC_Alert_Audio);
2652  Write(_T ( "bAnchorAlertAudio" ), g_bAnchor_Alert_Audio);
2653 
2654  // AIS
2655  SetPath(_T ( "/Settings/AIS" ));
2656 
2657  Write(_T ( "bNoCPAMax" ), g_bCPAMax);
2658  Write(_T ( "NoCPAMaxNMi" ), g_CPAMax_NM);
2659  Write(_T ( "bCPAWarn" ), g_bCPAWarn);
2660  Write(_T ( "CPAWarnNMi" ), g_CPAWarn_NM);
2661  Write(_T ( "bTCPAMax" ), g_bTCPA_Max);
2662  Write(_T ( "TCPAMaxMinutes" ), g_TCPA_Max);
2663  Write(_T ( "bMarkLostTargets" ), g_bMarkLost);
2664  Write(_T ( "MarkLost_Minutes" ), g_MarkLost_Mins);
2665  Write(_T ( "bRemoveLostTargets" ), g_bRemoveLost);
2666  Write(_T ( "RemoveLost_Minutes" ), g_RemoveLost_Mins);
2667  Write(_T ( "bShowCOGArrows" ), g_bShowCOG);
2668  Write(_T ( "bSyncCogPredictors" ), g_bSyncCogPredictors);
2669  Write(_T ( "CogArrowMinutes" ), g_ShowCOG_Mins);
2670  Write(_T ( "bShowTargetTracks" ), g_bAISShowTracks);
2671  Write(_T ( "TargetTracksMinutes" ), g_AISShowTracks_Mins);
2672 
2673  Write(_T ( "bHideMooredTargets" ), g_bHideMoored);
2674  Write(_T ( "MooredTargetMaxSpeedKnots" ), g_ShowMoored_Kts);
2675 
2676  Write(_T ( "bAISAlertDialog" ), g_bAIS_CPA_Alert);
2677  Write(_T ( "bAISAlertAudio" ), g_bAIS_CPA_Alert_Audio);
2678 
2679  Write(_T ( "AISAlertAudioFile" ), g_sAIS_Alert_Sound_File);
2680  Write(_T ( "bAISAlertSuppressMoored" ), g_bAIS_CPA_Alert_Suppress_Moored);
2681  Write(_T ( "bShowAreaNotices" ), g_bShowAreaNotices);
2682  Write(_T ( "bDrawAISSize" ), g_bDrawAISSize);
2683  Write(_T ( "bDrawAISRealtime" ), g_bDrawAISRealtime);
2684  Write(_T ( "AISRealtimeMinSpeedKnots" ), g_AIS_RealtPred_Kts);
2685  Write(_T ( "bShowAISName" ), g_bShowAISName);
2686  Write(_T ( "ShowAISTargetNameScale" ), g_Show_Target_Name_Scale);
2687  Write(_T ( "bWplIsAprsPositionReport" ), g_bWplUsePosition);
2688  Write(_T ( "WplSelAction" ), g_WplAction);
2689  Write(_T ( "AISCOGPredictorWidth" ), g_ais_cog_predictor_width);
2690  Write(_T ( "bShowScaledTargets" ), g_bAllowShowScaled);
2691  Write(_T ( "AISScaledNumber" ), g_ShowScaled_Num);
2692  Write(_T ( "AISScaledNumberWeightSOG" ), g_ScaledNumWeightSOG);
2693  Write(_T ( "AISScaledNumberWeightCPA" ), g_ScaledNumWeightCPA);
2694  Write(_T ( "AISScaledNumberWeightTCPA" ), g_ScaledNumWeightTCPA);
2695  Write(_T ( "AISScaledNumberWeightRange" ), g_ScaledNumWeightRange);
2696  Write(_T ( "AISScaledNumberWeightSizeOfTarget" ), g_ScaledNumWeightSizeOfT);
2697  Write(_T ( "AISScaledSizeMinimal" ), g_ScaledSizeMinimal);
2698  Write(_T ( "AISShowScaled"), g_bShowScaled);
2699 
2700  Write(_T ( "AlertDialogSizeX" ), g_ais_alert_dialog_sx);
2701  Write(_T ( "AlertDialogSizeY" ), g_ais_alert_dialog_sy);
2702  Write(_T ( "AlertDialogPosX" ), g_ais_alert_dialog_x);
2703  Write(_T ( "AlertDialogPosY" ), g_ais_alert_dialog_y);
2704  Write(_T ( "QueryDialogPosX" ), g_ais_query_dialog_x);
2705  Write(_T ( "QueryDialogPosY" ), g_ais_query_dialog_y);
2706  Write(_T ( "AISTargetListPerspective" ), g_AisTargetList_perspective);
2707  Write(_T ( "AISTargetListRange" ), g_AisTargetList_range);
2708  Write(_T ( "AISTargetListSortColumn" ), g_AisTargetList_sortColumn);
2709  Write(_T ( "bAISTargetListSortReverse" ), g_bAisTargetList_sortReverse);
2710  Write(_T ( "AISTargetListColumnSpec" ), g_AisTargetList_column_spec);
2711  Write(_T ("AISTargetListColumnOrder"), g_AisTargetList_column_order);
2712 
2713  Write(_T ( "S57QueryDialogSizeX" ), g_S57_dialog_sx);
2714  Write(_T ( "S57QueryDialogSizeY" ), g_S57_dialog_sy);
2715  Write(_T ( "S57QueryExtraDialogSizeX" ), g_S57_extradialog_sx);
2716  Write(_T ( "S57QueryExtraDialogSizeY" ), g_S57_extradialog_sy);
2717 
2718  Write(_T ( "bAISRolloverShowClass" ), g_bAISRolloverShowClass);
2719  Write(_T ( "bAISRolloverShowCOG" ), g_bAISRolloverShowCOG);
2720  Write(_T ( "bAISRolloverShowCPA" ), g_bAISRolloverShowCPA);
2721 
2722  Write(_T ( "bAISAlertAckTimeout" ), g_bAIS_ACK_Timeout);
2723  Write(_T ( "AlertAckTimeoutMinutes" ), g_AckTimeout_Mins);
2724 
2725  SetPath(_T ( "/Settings/GlobalState" ));
2726  if (ps52plib) {
2727  Write(_T ( "bShowS57Text" ), ps52plib->GetShowS57Text());
2728  Write(_T ( "bShowS57ImportantTextOnly" ),
2729  ps52plib->GetShowS57ImportantTextOnly());
2730  if (!g_bInlandEcdis)
2731  Write(_T ( "nDisplayCategory" ), (long)ps52plib->GetDisplayCategory());
2732  Write(_T ( "nSymbolStyle" ), (int)ps52plib->m_nSymbolStyle);
2733  Write(_T ( "nBoundaryStyle" ), (int)ps52plib->m_nBoundaryStyle);
2734 
2735  Write(_T ( "bShowSoundg" ), ps52plib->m_bShowSoundg);
2736  Write(_T ( "bShowMeta" ), ps52plib->m_bShowMeta);
2737  Write(_T ( "bUseSCAMIN" ), ps52plib->m_bUseSCAMIN);
2738  Write(_T ( "bUseSUPER_SCAMIN" ), ps52plib->m_bUseSUPER_SCAMIN);
2739  Write(_T ( "bShowAtonText" ), ps52plib->m_bShowAtonText);
2740  Write(_T ( "bShowLightDescription" ), ps52plib->m_bShowLdisText);
2741  Write(_T ( "bExtendLightSectors" ), ps52plib->m_bExtendLightSectors);
2742  Write(_T ( "bDeClutterText" ), ps52plib->m_bDeClutterText);
2743  Write(_T ( "bShowNationalText" ), ps52plib->m_bShowNationalTexts);
2744 
2745  Write(_T ( "S52_MAR_SAFETY_CONTOUR" ),
2746  S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR));
2747  Write(_T ( "S52_MAR_SHALLOW_CONTOUR" ),
2748  S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR));
2749  Write(_T ( "S52_MAR_DEEP_CONTOUR" ),
2750  S52_getMarinerParam(S52_MAR_DEEP_CONTOUR));
2751  Write(_T ( "S52_MAR_TWO_SHADES" ), S52_getMarinerParam(S52_MAR_TWO_SHADES));
2752  Write(_T ( "S52_DEPTH_UNIT_SHOW" ), ps52plib->m_nDepthUnitDisplay);
2753  Write(_T ( "ENCSoundingScaleFactor" ), g_ENCSoundingScaleFactor);
2754  Write(_T ( "ENCTextScaleFactor" ), g_ENCTextScaleFactor);
2755  }
2756  SetPath(_T ( "/Directories" ));
2757  Write(_T ( "S57DataLocation" ), _T(""));
2758  // Write( _T ( "SENCFileLocation" ), _T("") );
2759 
2760  SetPath(_T ( "/Directories" ));
2761  Write(_T ( "InitChartDir" ), *pInit_Chart_Dir);
2762  Write(_T ( "GPXIODir" ), g_gpx_path);
2763  Write(_T ( "TCDataDir" ), g_TCData_Dir);
2764  Write(_T ( "BasemapDir" ), g_Platform->NormalizePath(gWorldMapLocation));
2765  Write(_T ( "BaseShapefileDir" ), g_Platform->NormalizePath(gWorldShapefileLocation));
2766  Write(_T ( "pluginInstallDir" ), g_Platform->NormalizePath(g_winPluginDir));
2767 
2768  SetPath(_T ( "/Settings/NMEADataSource" ));
2769  wxString connectionconfigs;
2770  for (size_t i = 0; i < TheConnectionParams()->Count(); i++) {
2771  if (i > 0) connectionconfigs.Append(_T("|"));
2772  connectionconfigs.Append(TheConnectionParams()->Item(i)->Serialize());
2773  }
2774  Write(_T ( "DataConnections" ), connectionconfigs);
2775 
2776  // Fonts
2777 
2778  // Store the persistent Auxiliary Font descriptor Keys
2779  SetPath(_T ( "/Settings/AuxFontKeys" ));
2780 
2781  wxArrayString keyArray = FontMgr::Get().GetAuxKeyArray();
2782  for (unsigned int i = 0; i < keyArray.GetCount(); i++) {
2783  wxString key;
2784  key.Printf(_T("Key%i"), i);
2785  wxString keyval = keyArray[i];
2786  Write(key, keyval);
2787  }
2788 
2789  wxString font_path;
2790 #ifdef __WXX11__
2791  font_path = (_T ( "/Settings/X11Fonts" ));
2792 #endif
2793 
2794 #ifdef __WXGTK__
2795  font_path = (_T ( "/Settings/GTKFonts" ));
2796 #endif
2797 
2798 #ifdef __WXMSW__
2799  font_path = (_T ( "/Settings/MSWFonts" ));
2800 #endif
2801 
2802 #ifdef __WXMAC__
2803  font_path = (_T ( "/Settings/MacFonts" ));
2804 #endif
2805 
2806 #ifdef __WXQT__
2807  font_path = (_T ( "/Settings/QTFonts" ));
2808 #endif
2809 
2810  DeleteGroup(font_path);
2811 
2812  SetPath(font_path);
2813 
2814  int nFonts = FontMgr::Get().GetNumFonts();
2815 
2816  for (int i = 0; i < nFonts; i++) {
2817  wxString cfstring(FontMgr::Get().GetConfigString(i));
2818  wxString valstring = FontMgr::Get().GetFullConfigDesc(i);
2819  Write(cfstring, valstring);
2820  }
2821 
2822  // Tide/Current Data Sources
2823  DeleteGroup(_T ( "/TideCurrentDataSources" ));
2824  SetPath(_T ( "/TideCurrentDataSources" ));
2825  unsigned int id = 0;
2826  for (auto val : TideCurrentDataSet) {
2827  wxString key;
2828  key.Printf(_T("tcds%d"), id);
2829  Write(key, wxString(val));
2830  ++id;
2831  }
2832 
2833  SetPath(_T ( "/Settings/Others" ));
2834 
2835  // Radar rings
2836  Write(_T ( "ShowRadarRings" ),
2837  (bool)(g_iNavAidRadarRingsNumberVisible > 0)); // 3.0.0 config support
2838  Write(_T ( "RadarRingsNumberVisible" ), g_iNavAidRadarRingsNumberVisible);
2839  Write(_T ( "RadarRingsStep" ), g_fNavAidRadarRingsStep);
2840  Write(_T ( "RadarRingsStepUnits" ), g_pNavAidRadarRingsStepUnits);
2841  Write(_T ( "RadarRingsColour" ),
2842  g_colourOwnshipRangeRingsColour.GetAsString(wxC2S_HTML_SYNTAX));
2843  Write(_T( "WaypointUseScaMin" ), g_bUseWptScaMin);
2844  Write(_T( "WaypointScaMinValue" ), g_iWpt_ScaMin);
2845  Write(_T( "WaypointUseScaMinOverrule" ), g_bOverruleScaMin);
2846  Write(_T("WaypointsShowName"), g_bShowWptName);
2847  Write(_T("UserIconsFirst"), g_bUserIconsFirst);
2848 
2849  // Waypoint Radar rings
2850  Write(_T ( "WaypointRangeRingsNumber" ), g_iWaypointRangeRingsNumber);
2851  Write(_T ( "WaypointRangeRingsStep" ), g_fWaypointRangeRingsStep);
2852  Write(_T ( "WaypointRangeRingsStepUnits" ), g_iWaypointRangeRingsStepUnits);
2853  Write(_T ( "WaypointRangeRingsColour" ),
2854  g_colourWaypointRangeRingsColour.GetAsString(wxC2S_HTML_SYNTAX));
2855 
2856  Write(_T ( "ConfirmObjectDeletion" ), g_bConfirmObjectDelete);
2857 
2858  // Waypoint dragging with mouse; toh, 2009.02.24
2859  Write(_T ( "WaypointPreventDragging" ), g_bWayPointPreventDragging);
2860 
2861  Write(_T ( "EnableZoomToCursor" ), g_bEnableZoomToCursor);
2862 
2863  Write(_T ( "TrackIntervalSeconds" ), g_TrackIntervalSeconds);
2864  Write(_T ( "TrackDeltaDistance" ), g_TrackDeltaDistance);
2865  Write(_T ( "TrackPrecision" ), g_nTrackPrecision);
2866 
2867  Write(_T ( "RouteLineWidth" ), g_route_line_width);
2868  Write(_T ( "TrackLineWidth" ), g_track_line_width);
2869  Write(_T ( "TrackLineColour" ),
2870  g_colourTrackLineColour.GetAsString(wxC2S_HTML_SYNTAX));
2871  Write(_T ( "DefaultWPIcon" ), g_default_wp_icon);
2872  Write(_T ( "DefaultRPIcon" ), g_default_routepoint_icon);
2873 
2874  DeleteGroup(_T ( "/MmsiProperties" ));
2875  SetPath(_T ( "/MmsiProperties" ));
2876  for (unsigned int i = 0; i < g_MMSI_Props_Array.GetCount(); i++) {
2877  wxString p;
2878  p.Printf(_T("Props%d"), i);
2879  Write(p, g_MMSI_Props_Array[i]->Serialize());
2880  }
2881 
2882  SaveCanvasConfigs();
2883 
2884  Flush();
2885 }
2886 
2887 void MyConfig::UpdateNavObjOnly() {
2888  // Create the NavObjectCollection, and save to specified file
2889  NavObjectCollection1 *pNavObjectSet = new NavObjectCollection1();
2890 
2891  pNavObjectSet->CreateAllGPXObjects();
2892  pNavObjectSet->SaveFile(m_sNavObjSetFile);
2893 
2894  delete pNavObjectSet;
2895 }
2896 
2897 void MyConfig::UpdateNavObj(bool bRecreate) {
2898  // Create the NavObjectCollection, and save to specified file
2899  NavObjectCollection1 *pNavObjectSet = new NavObjectCollection1();
2900 
2901  pNavObjectSet->CreateAllGPXObjects();
2902  pNavObjectSet->SaveFile(m_sNavObjSetFile);
2903 
2904  delete pNavObjectSet;
2905 
2906  if (m_pNavObjectChangesSet->m_changes_file)
2907  fclose(m_pNavObjectChangesSet->m_changes_file);
2908 
2909  if (::wxFileExists(m_sNavObjSetChangesFile)) {
2910  wxLogNull logNo; // avoid silly log error message.
2911  wxRemoveFile(m_sNavObjSetChangesFile);
2912  }
2913 
2914  if (bRecreate) {
2915  m_pNavObjectChangesSet->Init(m_sNavObjSetChangesFile);
2916 
2917  m_pNavObjectChangesSet->reset();
2918  if (m_pNavObjectChangesSet->load_file(m_sNavObjSetChangesFile.fn_str()).status != pugi::xml_parse_status::status_ok) {
2919  wxLogMessage("Error while loading " + m_sNavObjSetChangesFile + ", ignoring contents of the file.");
2920  m_pNavObjectChangesSet->reset();
2921  }
2922  }
2923 }
2924 
2925 static wxFileName exportFileName(wxWindow *parent,
2926  const wxString suggestedName) {
2927  wxFileName ret;
2928  wxString path;
2929  wxString validName{suggestedName};
2930  // replace common date characters invalid in filename
2931  // MS-DOS file systems have many more
2932  validName.Replace(_T("/"), _T("-"));
2933  validName.Replace(_T(":"), _T("_"));
2934  int response = g_Platform->DoFileSelectorDialog(
2935  parent, &path, _("Export GPX file"), g_gpx_path, validName, wxT("*.gpx"));
2936 
2937  if (response == wxID_OK) {
2938  wxFileName fn(path);
2939  g_gpx_path = fn.GetPath();
2940  fn.SetExt(_T("gpx"));
2941 
2942 #ifndef __WXMAC__
2943  if (wxFileExists(fn.GetFullPath())) {
2944  int answer =
2945  OCPNMessageBox(NULL, _("Overwrite existing file?"), _T("Confirm"),
2946  wxICON_QUESTION | wxYES_NO | wxCANCEL);
2947  if (answer != wxID_YES) return ret;
2948  }
2949 #endif
2950  ret = fn;
2951  }
2952  return ret;
2953 }
2954 
2955 bool MyConfig::IsChangesFileDirty() {
2956  return m_pNavObjectChangesSet->IsDirty();
2957 }
2958 
2959 bool ExportGPXRoutes(wxWindow *parent, RouteList *pRoutes,
2960  const wxString suggestedName) {
2961  wxFileName fn = exportFileName(parent, suggestedName);
2962  if (fn.IsOk()) {
2964  pgpx->AddGPXRoutesList(pRoutes);
2965 
2966 #ifdef __ANDROID__
2967  wxString fns = androidGetCacheDir() + wxFileName::GetPathSeparator() +
2968  fn.GetFullName();
2969  pgpx->SaveFile(fns);
2970  AndroidSecureCopyFile(fns, fn.GetFullPath());
2971 #else
2972  pgpx->SaveFile(fn.GetFullPath());
2973 
2974 #endif
2975 
2976  delete pgpx;
2977 
2978  return true;
2979  }
2980  return false;
2981 }
2982 
2983 bool ExportGPXTracks(wxWindow *parent, std::vector<Track*> *pTracks,
2984  const wxString suggestedName) {
2985  wxFileName fn = exportFileName(parent, suggestedName);
2986  if (fn.IsOk()) {
2988  pgpx->AddGPXTracksList(pTracks);
2989 #ifdef __ANDROID__
2990  wxString fns = androidGetCacheDir() + wxFileName::GetPathSeparator() +
2991  fn.GetFullName();
2992  pgpx->SaveFile(fns);
2993  AndroidSecureCopyFile(fns, fn.GetFullPath());
2994 #else
2995  pgpx->SaveFile(fn.GetFullPath());
2996 #endif
2997  delete pgpx;
2998 
2999  return true;
3000  }
3001  return false;
3002 }
3003 
3004 bool ExportGPXWaypoints(wxWindow *parent, RoutePointList *pRoutePoints,
3005  const wxString suggestedName) {
3006  wxFileName fn = exportFileName(parent, suggestedName);
3007  if (fn.IsOk()) {
3009  pgpx->AddGPXPointsList(pRoutePoints);
3010 
3011 #ifdef __ANDROID__
3012  wxString fns = androidGetCacheDir() + wxFileName::GetPathSeparator() +
3013  fn.GetFullName();
3014  pgpx->SaveFile(fns);
3015  AndroidSecureCopyFile(fns, fn.GetFullPath());
3016 #else
3017  pgpx->SaveFile(fn.GetFullPath());
3018 #endif
3019 
3020  delete pgpx;
3021 
3022  return true;
3023  }
3024  return false;
3025 }
3026 
3027 void ExportGPX(wxWindow *parent, bool bviz_only, bool blayer) {
3028  wxFileName fn = exportFileName(parent, _T("userobjects.gpx"));
3029  if (fn.IsOk()) {
3030  ::wxBeginBusyCursor();
3031 
3033 
3034  wxGenericProgressDialog *pprog = nullptr;
3035  int count = pWayPointMan->GetWaypointList()->GetCount();
3036  int progStep = count / 32;
3037  if (count > 200) {
3038  pprog = new wxGenericProgressDialog(
3039  _("Export GPX file"), _T("0/0"), count, NULL,
3040  wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
3041  wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);
3042  pprog->SetSize(400, wxDefaultCoord);
3043  pprog->Centre();
3044  }
3045 
3046  // WPTs
3047  int ic = 1;
3048 
3049  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
3050  RoutePoint *pr;
3051  while (node) {
3052  if (pprog && !(ic % progStep)) {
3053  wxString msg;
3054  msg.Printf(_T("%d/%d"), ic, count);
3055  pprog->Update(ic, msg);
3056  }
3057  ic++;
3058 
3059  pr = node->GetData();
3060 
3061  bool b_add = true;
3062 
3063  if (bviz_only && !pr->m_bIsVisible) b_add = false;
3064 
3065  if (pr->m_bIsInLayer && !blayer) b_add = false;
3066  if (b_add) {
3067  if (pr->IsShared() || !WptIsInRouteList(pr)) pgpx->AddGPXWaypoint(pr);
3068  }
3069 
3070  node = node->GetNext();
3071  }
3072  // RTEs and TRKs
3073  wxRouteListNode *node1 = pRouteList->GetFirst();
3074  while (node1) {
3075  Route *pRoute = node1->GetData();
3076 
3077  bool b_add = true;
3078 
3079  if (bviz_only && !pRoute->IsVisible()) b_add = false;
3080 
3081  if (pRoute->m_bIsInLayer && !blayer) b_add = false;
3082 
3083  if (b_add) pgpx->AddGPXRoute(pRoute);
3084 
3085  node1 = node1->GetNext();
3086  }
3087 
3088  for (Track* pTrack : g_TrackList) {
3089  bool b_add = true;
3090 
3091  if (bviz_only && !pTrack->IsVisible()) b_add = false;
3092 
3093  if (pTrack->m_bIsInLayer && !blayer) b_add = false;
3094 
3095  if (b_add) pgpx->AddGPXTrack(pTrack);
3096  }
3097 
3098  // Android 5+ requires special handling to support native app file writes to
3099  // SDCard We need to use a two step copy process using a guaranteed
3100  // accessible location for the first step.
3101 #ifdef __ANDROID__
3102  wxString fns = androidGetCacheDir() + wxFileName::GetPathSeparator() +
3103  fn.GetFullName();
3104  pgpx->SaveFile(fns);
3105  AndroidSecureCopyFile(fns, fn.GetFullPath());
3106 #else
3107  pgpx->SaveFile(fn.GetFullPath());
3108 #endif
3109 
3110  delete pgpx;
3111  ::wxEndBusyCursor();
3112 
3113  delete pprog;
3114  }
3115 }
3116 
3117 void UI_ImportGPX(wxWindow *parent, bool islayer, wxString dirpath,
3118  bool isdirectory, bool isPersistent) {
3119  int response = wxID_CANCEL;
3120  wxArrayString file_array;
3121  Layer *l = NULL;
3122 
3123  if (!islayer || dirpath.IsSameAs(_T(""))) {
3124  // Platform DoFileSelectorDialog method does not properly handle multiple
3125  // selections So use native method if not Android, which means Android gets
3126  // single selection only.
3127 #ifndef __ANDROID__
3128  wxFileDialog *popenDialog =
3129  new wxFileDialog(NULL, _("Import GPX file"), g_gpx_path, wxT(""),
3130  wxT("GPX files (*.gpx)|*.gpx|All files (*.*)|*.*"),
3131  wxFD_OPEN | wxFD_MULTIPLE);
3132 
3133  if (g_bresponsive && parent)
3134  popenDialog = g_Platform->AdjustFileDialogFont(parent, popenDialog);
3135 
3136  popenDialog->Centre();
3137 
3138 #ifdef __WXOSX__
3139  if (parent) parent->HideWithEffect(wxSHOW_EFFECT_BLEND);
3140 #endif
3141 
3142  response = popenDialog->ShowModal();
3143 
3144 #ifdef __WXOSX__
3145  if (parent) parent->ShowWithEffect(wxSHOW_EFFECT_BLEND);
3146 #endif
3147 
3148  if (response == wxID_OK) {
3149  popenDialog->GetPaths(file_array);
3150 
3151  // Record the currently selected directory for later use
3152  if (file_array.GetCount()) {
3153  wxFileName fn(file_array[0]);
3154  g_gpx_path = fn.GetPath();
3155  }
3156  }
3157  delete popenDialog;
3158 #else
3159  wxString path;
3160  response = g_Platform->DoFileSelectorDialog(
3161  NULL, &path, _("Import GPX file"), g_gpx_path, _T(""), wxT("*.gpx"));
3162 
3163  file_array.Add(path);
3164  wxFileName fn(path);
3165  g_gpx_path = fn.GetPath();
3166 
3167 #endif
3168 
3169  } else {
3170  if (isdirectory) {
3171  if (wxDir::GetAllFiles(dirpath, &file_array, wxT("*.gpx")))
3172  response = wxID_OK;
3173  } else {
3174  file_array.Add(dirpath);
3175  response = wxID_OK;
3176  }
3177  }
3178 
3179  if (response == wxID_OK) {
3180  if (islayer) {
3181  l = new Layer();
3182  l->m_LayerID = ++g_LayerIdx;
3183  l->m_LayerFileName = file_array[0];
3184  if (file_array.GetCount() <= 1)
3185  wxFileName::SplitPath(file_array[0], NULL, NULL, &(l->m_LayerName),
3186  NULL, NULL);
3187  else {
3188  if (dirpath.IsSameAs(_T("")))
3189  wxFileName::SplitPath(g_gpx_path, NULL, NULL, &(l->m_LayerName), NULL,
3190  NULL);
3191  else
3192  wxFileName::SplitPath(dirpath, NULL, NULL, &(l->m_LayerName), NULL,
3193  NULL);
3194  }
3195 
3196  bool bLayerViz = g_bShowLayers;
3197  if (g_VisibleLayers.Contains(l->m_LayerName)) bLayerViz = true;
3198  if (g_InvisibleLayers.Contains(l->m_LayerName)) bLayerViz = false;
3199  l->m_bIsVisibleOnChart = bLayerViz;
3200 
3201  // Default for new layers is "Names visible"
3202  l->m_bHasVisibleNames = wxCHK_CHECKED;
3203 
3204  wxString laymsg;
3205  laymsg.Printf(wxT("New layer %d: %s"), l->m_LayerID,
3206  l->m_LayerName.c_str());
3207  wxLogMessage(laymsg);
3208 
3209  pLayerList->Insert(l);
3210  }
3211 
3212  for (unsigned int i = 0; i < file_array.GetCount(); i++) {
3213  wxString path = file_array[i];
3214 
3215  if (::wxFileExists(path)) {
3217  if (pSet->load_file(path.fn_str()).status != pugi::xml_parse_status::status_ok) {
3218  wxLogMessage("Error loading GPX file " + path);
3219  pSet->reset();
3220  delete pSet;
3221  continue;
3222  }
3223 
3224  if (islayer) {
3225  l->m_NoOfItems = pSet->LoadAllGPXObjectsAsLayer(
3226  l->m_LayerID, l->m_bIsVisibleOnChart, l->m_bHasVisibleNames);
3227  l->m_LayerType = isPersistent ? _("Persistent") : _("Temporary");
3228 
3229  if (isPersistent) {
3230  // If this is a persistent layer also copy the file to config file
3231  // dir /layers
3232  wxString destf, f, name, ext;
3233  f = l->m_LayerFileName;
3234  wxFileName::SplitPath(f, NULL, NULL, &name, &ext);
3235  destf = g_Platform->GetPrivateDataDir();
3236  appendOSDirSlash(&destf);
3237  destf.Append(_T("layers"));
3238  appendOSDirSlash(&destf);
3239  if (!wxDirExists(destf)) {
3240  if (!wxMkdir(destf, wxS_DIR_DEFAULT))
3241  wxLogMessage(_T("Error creating layer directory"));
3242  }
3243 
3244  destf << name << _T(".") << ext;
3245  wxString msg;
3246  if (wxCopyFile(f, destf, true))
3247  msg.Printf(_T("File: %s.%s also added to persistent layers"),
3248  name, ext);
3249  else
3250  msg.Printf(_T("Failed adding %s.%s to persistent layers"), name,
3251  ext);
3252  wxLogMessage(msg);
3253  }
3254  } else {
3255  int wpt_dups;
3256  pSet->LoadAllGPXObjects(
3257  !pSet->IsOpenCPN(),
3258  wpt_dups); // Import with full visibility of names and objects
3259  if (wpt_dups > 0) {
3260  OCPNMessageBox(
3261  parent,
3262  wxString::Format(_T("%d ") + _("duplicate waypoints detected "
3263  "during import and ignored."),
3264  wpt_dups),
3265  _("OpenCPN Info"), wxICON_INFORMATION | wxOK, 10);
3266  }
3267  }
3268  delete pSet;
3269  }
3270  }
3271  }
3272 }
3273 
3274 //-------------------------------------------------------------------------
3275 // Static Routine Switch to Inland Ecdis Mode
3276 //-------------------------------------------------------------------------
3277 void SwitchInlandEcdisMode(bool Switch) {
3278  if (Switch) {
3279  wxLogMessage(_T("Switch InlandEcdis mode On"));
3280  LoadS57();
3281  // Overule some sewttings to comply with InlandEcdis
3282  // g_toolbarConfig = _T ( ".....XXXX.X...XX.XXXXXXXXXXXX" );
3283  g_iDistanceFormat = 2; // 0 = "Nautical miles"), 1 = "Statute miles", 2 =
3284  // "Kilometers", 3 = "Meters"
3285  g_iSpeedFormat = 2; // 0 = "kts"), 1 = "mph", 2 = "km/h", 3 = "m/s"
3286  if (ps52plib) ps52plib->SetDisplayCategory(STANDARD);
3287  g_bDrawAISSize = false;
3288  if (gFrame) gFrame->RequestNewToolbars(true);
3289  } else {
3290  wxLogMessage(_T("Switch InlandEcdis mode Off"));
3291  // reread the settings overruled by inlandEcdis
3292  if (pConfig) {
3293  pConfig->SetPath(_T ( "/Settings" ));
3294  pConfig->Read(_T ( "GlobalToolbarConfig" ), &g_toolbarConfig);
3295  pConfig->Read(_T ( "DistanceFormat" ), &g_iDistanceFormat);
3296  pConfig->Read(_T ( "SpeedFormat" ), &g_iSpeedFormat);
3297  pConfig->Read(_T ( "ShowDepthUnits" ), &g_bShowDepthUnits, 1);
3298  int read_int;
3299  pConfig->Read(_T ( "nDisplayCategory" ), &read_int,
3300  (enum _DisCat)STANDARD);
3301  if (ps52plib) ps52plib->SetDisplayCategory((enum _DisCat)read_int);
3302  pConfig->SetPath(_T ( "/Settings/AIS" ));
3303  pConfig->Read(_T ( "bDrawAISSize" ), &g_bDrawAISSize);
3304  pConfig->Read(_T ( "bDrawAISRealtime" ), &g_bDrawAISRealtime);
3305  }
3306  if (gFrame) gFrame->RequestNewToolbars(true);
3307  }
3308 }
3309 
3310 //-------------------------------------------------------------------------
3311 //
3312 // Static GPX Support Routines
3313 //
3314 //-------------------------------------------------------------------------
3315 // This function formats the input date/time into a valid GPX ISO 8601
3316 // time string specified in the UTC time zone.
3317 
3318 wxString FormatGPXDateTime(wxDateTime dt) {
3319  // return dt.Format(wxT("%Y-%m-%dT%TZ"), wxDateTime::GMT0);
3320  return dt.Format(wxT("%Y-%m-%dT%H:%M:%SZ"));
3321 }
3322 
3323 /**************************************************************************/
3324 /* LogMessageOnce */
3325 /**************************************************************************/
3326 
3327 bool LogMessageOnce(const wxString &msg) {
3328  // Search the array for a match
3329 
3330  for (unsigned int i = 0; i < pMessageOnceArray->GetCount(); i++) {
3331  if (msg.IsSameAs(pMessageOnceArray->Item(i))) return false;
3332  }
3333 
3334  // Not found, so add to the array
3335  pMessageOnceArray->Add(msg);
3336 
3337  // And print it
3338  wxLogMessage(msg);
3339  return true;
3340 }
3341 
3342 /**************************************************************************/
3343 /* Some assorted utilities */
3344 /**************************************************************************/
3345 
3346 /**************************************************************************/
3347 /* Converts the distance from the units selected by user to NMi */
3348 /**************************************************************************/
3349 double fromUsrDistance(double usr_distance, int unit) {
3350  double ret = NAN;
3351  if (unit == -1) unit = g_iDistanceFormat;
3352  switch (unit) {
3353  case DISTANCE_NMI: // Nautical miles
3354  ret = usr_distance;
3355  break;
3356  case DISTANCE_MI: // Statute miles
3357  ret = usr_distance / 1.15078;
3358  break;
3359  case DISTANCE_KM:
3360  ret = usr_distance / 1.852;
3361  break;
3362  case DISTANCE_M:
3363  ret = usr_distance / 1852;
3364  break;
3365  case DISTANCE_FT:
3366  ret = usr_distance / 6076.12;
3367  break;
3368  }
3369  return ret;
3370 }
3371 /**************************************************************************/
3372 /* Converts the speed from the units selected by user to knots */
3373 /**************************************************************************/
3374 double fromUsrSpeed(double usr_speed, int unit) {
3375  double ret = NAN;
3376  if (unit == -1) unit = g_iSpeedFormat;
3377  switch (unit) {
3378  case SPEED_KTS: // kts
3379  ret = usr_speed;
3380  break;
3381  case SPEED_MPH: // mph
3382  ret = usr_speed / 1.15078;
3383  break;
3384  case SPEED_KMH: // km/h
3385  ret = usr_speed / 1.852;
3386  break;
3387  case SPEED_MS: // m/s
3388  ret = usr_speed / 0.514444444;
3389  break;
3390  }
3391  return ret;
3392 }
3393 /**************************************************************************/
3394 /* Converts the wind speed from the units selected by user to knots */
3395 /**************************************************************************/
3396 double fromUsrWindSpeed(double usr_wspeed, int unit) {
3397  double ret = NAN;
3398  if (unit == -1) unit = g_iWindSpeedFormat;
3399  switch (unit) {
3400  case WSPEED_KTS: // kts
3401  ret = usr_wspeed;
3402  break;
3403  case WSPEED_MS: // m/s
3404  ret = usr_wspeed / 0.514444444;
3405  break;
3406  case WSPEED_MPH: // mph
3407  ret = usr_wspeed / 1.15078;
3408  break;
3409  case WSPEED_KMH: // km/h
3410  ret = usr_wspeed / 1.852;
3411  break;
3412  }
3413  return ret;
3414 }
3415 
3416 
3417 /**************************************************************************/
3418 /* Converts the temperature from the units selected by user to Celsius */
3419 /**************************************************************************/
3420 double fromUsrTemp(double usr_temp, int unit) {
3421  double ret = NAN;
3422  if (unit == -1) unit = g_iTempFormat;
3423  switch (unit) {
3424  case TEMPERATURE_C: // C
3425  ret = usr_temp;
3426  break;
3427  case TEMPERATURE_F: // F
3428  ret = (usr_temp - 32) * 5.0 / 9.0;
3429  break;
3430  case TEMPERATURE_K: // K
3431  ret = usr_temp - 273.15;
3432  break;
3433  }
3434  return ret;
3435 }
3436 
3437 wxString formatAngle(double angle) {
3438  wxString out;
3439  if (g_bShowMag && g_bShowTrue) {
3440  out.Printf(wxT("%03.0f %cT (%.0f %cM)"), angle, 0x00B0,
3441  toMagnetic(angle), 0x00B0);
3442  } else if (g_bShowTrue) {
3443  out.Printf(wxT("%03.0f %cT"), angle, 0x00B0);
3444  } else {
3445  out.Printf(wxT("%03.0f %cM"), toMagnetic(angle), 0x00B0);
3446  }
3447  return out;
3448 }
3449 
3450 /* render a rectangle at a given color and transparency */
3451 void AlphaBlending(ocpnDC &dc, int x, int y, int size_x, int size_y,
3452  float radius, wxColour color, unsigned char transparency) {
3453  wxDC *pdc = dc.GetDC();
3454  if (pdc) {
3455  // Get wxImage of area of interest
3456  wxBitmap obm(size_x, size_y);
3457  wxMemoryDC mdc1;
3458  mdc1.SelectObject(obm);
3459  mdc1.Blit(0, 0, size_x, size_y, pdc, x, y);
3460  mdc1.SelectObject(wxNullBitmap);
3461  wxImage oim = obm.ConvertToImage();
3462 
3463  // Create destination image
3464  wxBitmap olbm(size_x, size_y);
3465  wxMemoryDC oldc(olbm);
3466  if (!oldc.IsOk()) return;
3467 
3468  oldc.SetBackground(*wxBLACK_BRUSH);
3469  oldc.SetBrush(*wxWHITE_BRUSH);
3470  oldc.Clear();
3471 
3472  if (radius > 0.0) oldc.DrawRoundedRectangle(0, 0, size_x, size_y, radius);
3473 
3474  wxImage dest = olbm.ConvertToImage();
3475  unsigned char *dest_data =
3476  (unsigned char *)malloc(size_x * size_y * 3 * sizeof(unsigned char));
3477  unsigned char *bg = oim.GetData();
3478  unsigned char *box = dest.GetData();
3479  unsigned char *d = dest_data;
3480 
3481  // Sometimes, on Windows, the destination image is corrupt...
3482  if (NULL == box) {
3483  free(d);
3484  return;
3485  }
3486  float alpha = 1.0 - (float)transparency / 255.0;
3487  int sb = size_x * size_y;
3488  for (int i = 0; i < sb; i++) {
3489  float a = alpha;
3490  if (*box == 0 && radius > 0.0) a = 1.0;
3491  int r = ((*bg++) * a) + (1.0 - a) * color.Red();
3492  *d++ = r;
3493  box++;
3494  int g = ((*bg++) * a) + (1.0 - a) * color.Green();
3495  *d++ = g;
3496  box++;
3497  int b = ((*bg++) * a) + (1.0 - a) * color.Blue();
3498  *d++ = b;
3499  box++;
3500  }
3501 
3502  dest.SetData(dest_data);
3503 
3504  // Convert destination to bitmap and draw it
3505  wxBitmap dbm(dest);
3506  dc.DrawBitmap(dbm, x, y, false);
3507 
3508  // on MSW, the dc Bounding box is not updated on DrawBitmap() method.
3509  // Do it explicitely here for all platforms.
3510  dc.CalcBoundingBox(x, y);
3511  dc.CalcBoundingBox(x + size_x, y + size_y);
3512  } else {
3513 #ifdef ocpnUSE_GL
3514  glEnable(GL_BLEND);
3515 
3516  float radMod = wxMax(radius, 2.0);
3517  wxColour c(color.Red(), color.Green(), color.Blue(), transparency);
3518  dc.SetBrush(wxBrush(c));
3519  dc.SetPen(wxPen(c, 1));
3520  dc.DrawRoundedRectangle(x, y, size_x, size_y, radMod);
3521 
3522  glDisable(GL_BLEND);
3523 
3524 #endif
3525  }
3526 }
3527 
3528 void GpxDocument::SeedRandom() {
3529  /* Fill with random. Miliseconds hopefully good enough for our usage, reading
3530  * /dev/random would be much better on linux and system guid function on
3531  * Windows as well */
3532  wxDateTime x = wxDateTime::UNow();
3533  long seed = x.GetMillisecond();
3534  seed *= x.GetTicks();
3535  srand(seed);
3536 }
3537 
3538 void DimeControl(wxWindow *ctrl) {
3539 #ifdef __WXOSX__
3540  // On macOS 10.14+, we use the native colours in both light mode and dark
3541  // mode, and do not need to do anything else. Dark mode is toggled at the
3542  // application level in `SetAndApplyColorScheme`, and is also respected if it
3543  // is enabled system-wide.
3544  if (wxPlatformInfo::Get().CheckOSVersion(10, 14)) {
3545  return;
3546  }
3547 #endif
3548 #ifdef __WXQT__
3549  return; // this is seriously broken on wxqt
3550 #endif
3551 
3552  if(wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOW).Red() < 128) {
3553  // Dark system color themes usually do better job than we do on diming UI controls, do not fight with them
3554  return;
3555  }
3556 
3557  if (NULL == ctrl) return;
3558 
3559  wxColour col, window_back_color, gridline, uitext, udkrd, ctrl_back_color,
3560  text_color;
3561  col = GetGlobalColor(_T("DILG0")); // Dialog Background white
3562  window_back_color = GetGlobalColor(_T("DILG1")); // Dialog Background
3563  ctrl_back_color = GetGlobalColor(_T("DILG1")); // Control Background
3564  text_color = GetGlobalColor(_T("DILG3")); // Text
3565  uitext = GetGlobalColor(_T("UITX1")); // Menu Text, derived from UINFF
3566  udkrd = GetGlobalColor(_T("UDKRD"));
3567  gridline = GetGlobalColor(_T("GREY2"));
3568 
3569  DimeControl(ctrl, col, window_back_color, ctrl_back_color, text_color, uitext,
3570  udkrd, gridline);
3571 }
3572 
3573 void DimeControl(wxWindow *ctrl, wxColour col, wxColour window_back_color,
3574  wxColour ctrl_back_color, wxColour text_color, wxColour uitext,
3575  wxColour udkrd, wxColour gridline) {
3576 #ifdef __WXOSX__
3577  // On macOS 10.14+, we use the native colours in both light mode and dark
3578  // mode, and do not need to do anything else. Dark mode is toggled at the
3579  // application level in `SetAndApplyColorScheme`, and is also respected if it
3580  // is enabled system-wide.
3581  if (wxPlatformInfo::Get().CheckOSVersion(10, 14)) {
3582  return;
3583  }
3584 #endif
3585 
3586  ColorScheme cs = global_color_scheme;
3587 
3588  // Are we in dusk or night mode? (Used below in several places.)
3589  bool darkMode =
3590  (cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT);
3591 
3592  static int depth = 0; // recursion count
3593  if (depth == 0) { // only for the window root, not for every child
3594  // If the color scheme is DAY or RGB, use the default platform native colour
3595  // for backgrounds
3596  if (!darkMode) {
3597 #ifdef _WIN32
3598  window_back_color = wxNullColour;
3599 #else
3600  window_back_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
3601 #endif
3602  col = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
3603  uitext = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
3604  }
3605 
3606  ctrl->SetBackgroundColour(window_back_color);
3607  if (darkMode) ctrl->SetForegroundColour(text_color);
3608  }
3609 
3610  wxWindowList kids = ctrl->GetChildren();
3611  for (unsigned int i = 0; i < kids.GetCount(); i++) {
3612  wxWindowListNode *node = kids.Item(i);
3613  wxWindow *win = node->GetData();
3614 
3615  if (win->IsKindOf(CLASSINFO(wxListBox)) ||
3616  win->IsKindOf(CLASSINFO(wxListCtrl)) ||
3617  win->IsKindOf(CLASSINFO(wxTextCtrl))
3618  || win->IsKindOf(CLASSINFO(wxTimePickerCtrl))
3619  ) {
3620  win->SetBackgroundColour(col);
3621  } else if (win->IsKindOf(CLASSINFO(wxStaticText)) ||
3622  win->IsKindOf(CLASSINFO(wxCheckBox)) ||
3623  win->IsKindOf(CLASSINFO(wxRadioButton))) {
3624  win->SetForegroundColour(uitext);
3625  }
3626 #ifndef __WXOSX__
3627  // On macOS most controls can't be styled, and trying to do so only creates
3628  // weird coloured boxes around them. Fortunately, however, many of them
3629  // inherit a colour or tint from the background of their parent.
3630 
3631  else if (win->IsKindOf(CLASSINFO(wxBitmapComboBox)) ||
3632  win->IsKindOf(CLASSINFO(wxChoice)) ||
3633  win->IsKindOf(CLASSINFO(wxComboBox)) ||
3634  win->IsKindOf(CLASSINFO(wxTreeCtrl))) {
3635  win->SetBackgroundColour(col);
3636  }
3637 
3638  else if (win->IsKindOf(CLASSINFO(wxScrolledWindow)) ||
3639  win->IsKindOf(CLASSINFO(wxGenericDirCtrl)) ||
3640  win->IsKindOf(CLASSINFO(wxListbook)) ||
3641  win->IsKindOf(CLASSINFO(wxButton)) ||
3642  win->IsKindOf(CLASSINFO(wxToggleButton))) {
3643  win->SetBackgroundColour(window_back_color);
3644  }
3645 
3646  else if (win->IsKindOf(CLASSINFO(wxNotebook))) {
3647  ((wxNotebook *)win)->SetBackgroundColour(window_back_color);
3648  ((wxNotebook *)win)->SetForegroundColour(text_color);
3649  }
3650 #endif
3651 
3652  else if (win->IsKindOf(CLASSINFO(wxHtmlWindow))) {
3653  if (cs != GLOBAL_COLOR_SCHEME_DAY && cs != GLOBAL_COLOR_SCHEME_RGB)
3654  ((wxPanel *)win)->SetBackgroundColour(ctrl_back_color);
3655  else
3656  ((wxPanel *)win)->SetBackgroundColour(wxNullColour);
3657  }
3658 
3659  else if (win->IsKindOf(CLASSINFO(wxGrid))) {
3660  ((wxGrid *)win)->SetDefaultCellBackgroundColour(window_back_color);
3661  ((wxGrid *)win)->SetDefaultCellTextColour(uitext);
3662  ((wxGrid *)win)->SetLabelBackgroundColour(col);
3663  ((wxGrid *)win)->SetLabelTextColour(uitext);
3664 #if !wxCHECK_VERSION(3, 0, 0)
3665  ((wxGrid *)win)->SetDividerPen(wxPen(col));
3666 #endif
3667  ((wxGrid *)win)->SetGridLineColour(gridline);
3668  }
3669 
3670  if (win->GetChildren().GetCount() > 0) {
3671  depth++;
3672  wxWindow *w = win;
3673  DimeControl(w, col, window_back_color, ctrl_back_color, text_color,
3674  uitext, udkrd, gridline);
3675  depth--;
3676  }
3677  }
3678 }
3679 
3680 #define LUMIMOSITY_NIGHT (-0.8)
3681 #define LUMIMOSITY_DUSK (-0.5)
3682 
3683 wxColor GetDimedColor(const wxColor& c)
3684 {
3685  switch (global_color_scheme) {
3686  case ColorScheme::GLOBAL_COLOR_SCHEME_NIGHT:
3687  return (
3688  wxColor(wxMax(0, wxMin(c.Red() + c.Red() * LUMIMOSITY_NIGHT, 255)),
3689  wxMax(0, wxMin(c.Green() + c.Green() * LUMIMOSITY_NIGHT, 255)),
3690  wxMax(0, wxMin(c.Blue() + c.Blue() * LUMIMOSITY_NIGHT, 255))));
3691  case ColorScheme::GLOBAL_COLOR_SCHEME_DUSK:
3692  return (
3693  wxColor(wxMax(0, wxMin(c.Red() + c.Red() * LUMIMOSITY_DUSK, 255)),
3694  wxMax(0, wxMin(c.Green() + c.Green() * LUMIMOSITY_DUSK, 255)),
3695  wxMax(0, wxMin(c.Blue() + c.Blue() * LUMIMOSITY_DUSK, 255))));
3696  default:
3697  return c;
3698  }
3699 }
Global state for AIS decoder.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
Wrapper for global variable, supports notification events when value changes.
Definition: Layer.h:32
static int config_to_ui(double value)
Convert configuration 1.02..3.0 value to slider scale 1..100.
Definition: navutil.h:129
static double ui_to_config(int slider_pos)
Convert a slider scale 1-100 value to configuration value 1.02..3.0.
Definition: navutil.h:124
Definition: route.h:75
Definition: track.h:78
Definition: ocpndc.h:58
Global variables reflecting command line options and arguments.