1 /***************************************************************************
2  *
3  * Project:  OpenCPN
4  * Purpose:  Options Dialog
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 #include <memory>
26 
27 #ifdef __linux__
28 #include <unistd.h>
29 #endif
30 
31 #ifdef __MINGW32__
32 #undef IPV6STRICT    // mingw FTBS fix:  missing struct ip_mreq
33 #include <windows.h>
34 #endif
35 
36 // For compilers that support precompilation, includes "wx/wx.h".
37 #include "wx/wxprec.h"
38 
39 #ifndef WX_PRECOMP
40 #include <wx/wx.h>
41 #endif
42 
43 #include <wx/progdlg.h>
44 #include <wx/radiobox.h>
45 #include <wx/listbox.h>
46 #include <wx/imaglist.h>
47 #include <wx/display.h>
48 #include <wx/choice.h>
49 #include <wx/dirdlg.h>
50 #include <wx/clrpicker.h>
51 #include <wx/stdpaths.h>
52 #include "wx/tokenzr.h"
53 #include <wx/mediactrl.h>
54 #include "wx/dir.h"
55 #include "wx/odcombo.h"
56 #include <wx/statline.h>
57 #include "SignalKDataStream.h"
58 
59 #if wxCHECK_VERSION(2, 9, \
60                     4) /* does this work in 2.8 too.. do we need a test? */
61 #include <wx/renderer.h>
62 #endif
63 #if defined(__WXGTK__) || defined(__WXQT__)
64 #include <wx/colordlg.h>
65 #endif
66 
67 #ifdef ocpnUSE_SVG
68 #include <wxSVG/svg.h>
69 #endif // ocpnUSE_SVG
70 
71 #include "config.h"
72 
73 #include "dychart.h"
74 #include "chart1.h"
75 
76 #ifdef ocpnUSE_GL
77 #include "glChartCanvas.h"
78 extern GLuint g_raster_format;
79 #endif
80 
81 #include "chartdbs.h"
82 #include "options.h"
83 #include "styles.h"
84 #include "datastream.h"
85 #include "multiplexer.h"
86 #include "FontMgr.h"
87 #include "OCPN_Sound.h"
88 #include "SoundFactory.h"
89 
90 #ifndef __OCPN__ANDROID__
91 #include "SystemCmdSound.h"
92 #endif
93 
94 #include "NMEALogWindow.h"
95 #include "wx28compat.h"
96 #include "routeman.h"
97 #include "chcanv.h"
98 #include "MarkInfo.h"
99 
100 #include "ais.h"
101 #include "AIS_Decoder.h"
102 #include "AIS_Target_Data.h"
103 
104 #include "navutil.h"
105 
106 #include "s52plib.h"
107 #include "s52utils.h"
108 #include "cm93.h"
109 
110 #ifdef __OCPN__ANDROID__
111 #include "androidUTIL.h"
112 #endif
113 
114 #ifdef __OCPN__ANDROID__
115 #include <QtWidgets/QScroller>
116 #endif
117 
118 #ifdef __WXOSX__
119 #include "DarkMode.h"
120 #endif
121 
122 #include "OCPNPlatform.h"
123 #include "ConfigMgr.h"
124 
125 #include "SignalKDataStream.h"
126 
127 #if !defined(__WXOSX__)
128 #define SLIDER_STYLE  wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS
129 #else
130 #define SLIDER_STYLE  wxSL_HORIZONTAL | wxSL_AUTOTICKS
131 #endif
132 
133 wxString GetOCPNKnownLanguage(const wxString lang_canonical,
134                               wxString& lang_dir);
135 wxString GetOCPNKnownLanguage(const wxString lang_canonical);
136 
137 extern OCPNPlatform* g_Platform;
138 
139 extern MyFrame* gFrame;
140 extern WayPointman *pWayPointMan;
141 extern bool g_bSoftwareGL;
142 extern bool g_bShowFPS;
143 
144 extern bool g_bShowOutlines;
145 extern bool g_bShowChartBar;
146 extern bool g_bShowDepthUnits;
147 extern bool g_bskew_comp;
148 extern bool g_bopengl;
149 extern bool g_bsmoothpanzoom;
150 extern bool g_bShowTrue, g_bShowMag;
151 extern double g_UserVar;
152 extern double gVar;
153 extern int g_chart_zoom_modifier;
154 extern int g_chart_zoom_modifier_vector;
155 extern int g_NMEAAPBPrecision;
156 extern wxString g_TalkerIdText;
157 extern int g_nDepthUnitDisplay;
158 extern bool g_bUIexpert;
159 
160 extern wxString* pInit_Chart_Dir;
161 extern wxArrayOfConnPrm* g_pConnectionParams;
162 extern Multiplexer* g_pMUX;
163 extern bool g_bfilter_cogsog;
164 extern int g_COGFilterSec;
165 extern int g_SOGFilterSec;
166 
167 extern PlugInManager* g_pi_manager;
168 extern ocpnStyle::StyleManager* g_StyleManager;
169 
170 extern bool g_bDisplayGrid;
171 
172 // LIVE ETA OPTION
173 extern bool     g_bShowLiveETA;
174 extern double   g_defaultBoatSpeed;
175 extern double   g_defaultBoatSpeedUserUnit;
176 
177 //    AIS Global configuration
178 extern bool g_bCPAMax;
179 extern double g_CPAMax_NM;
180 extern bool g_bCPAWarn;
181 extern double g_CPAWarn_NM;
182 extern bool g_bTCPA_Max;
183 extern double g_TCPA_Max;
184 extern bool g_bMarkLost;
185 extern double g_MarkLost_Mins;
186 extern bool g_bRemoveLost;
187 extern double g_RemoveLost_Mins;
188 extern bool g_bShowCOG;
189 extern double g_ShowCOG_Mins;
190 extern bool g_bAISShowTracks;
191 extern double g_AISShowTracks_Mins;
192 extern double g_ShowMoored_Kts;
193 extern bool g_bHideMoored;
194 extern bool g_bAllowShowScaled;
195 extern int  g_ShowScaled_Num;
196 extern bool g_bAIS_CPA_Alert;
197 extern bool g_bAIS_CPA_Alert_Audio;
198 extern wxString g_sAIS_Alert_Sound_File;
199 extern bool g_bAIS_CPA_Alert_Suppress_Moored;
200 extern bool g_bShowAreaNotices;
201 extern bool g_bDrawAISSize;
202 extern bool g_bDrawAISRealtime;
203 extern double g_AIS_RealtPred_Kts;
204 extern bool g_bShowAISName;
205 extern int g_Show_Target_Name_Scale;
206 extern bool g_bWplIsAprsPosition;
207 
208 extern int g_iNavAidRadarRingsNumberVisible;
209 extern float g_fNavAidRadarRingsStep;
210 extern int g_pNavAidRadarRingsStepUnits;
211 extern int g_iWaypointRangeRingsNumber;
212 extern float g_fWaypointRangeRingsStep;
213 extern int g_iWaypointRangeRingsStepUnits;
214 extern wxColour g_colourWaypointRangeRingsColour;
215 extern bool g_bWayPointPreventDragging;
216 extern wxColour g_colourOwnshipRangeRingsColour;
217 
218 extern bool g_own_ship_sog_cog_calc;
219 extern int g_own_ship_sog_cog_calc_damp_sec;
220 
221 extern bool g_bPreserveScaleOnX;
222 extern bool g_bPlayShipsBells;
223 
224 extern wxString g_CmdSoundString;
225 
226 extern int g_iSoundDeviceIndex;
227 extern bool g_bFullscreenToolbar;
228 extern bool g_bTransparentToolbar;
229 extern bool g_bTransparentToolbarInOpenGLOK;
230 
231 extern int g_OwnShipIconType;
232 extern double g_n_ownship_length_meters;
233 extern double g_n_ownship_beam_meters;
234 extern double g_n_gps_antenna_offset_y;
235 extern double g_n_gps_antenna_offset_x;
236 extern int g_n_ownship_min_mm;
237 extern double g_n_arrival_circle_radius;
238 
239 extern bool g_bEnableZoomToCursor;
240 extern bool g_bTrackDaily;
241 extern int g_track_rotate_time;
242 extern int g_track_rotate_time_type;
243 extern bool g_bHighliteTracks;
244 extern double g_TrackDeltaDistance;
245 extern double g_TrackDeltaDistance;
246 extern int g_nTrackPrecision;
247 extern wxColour g_colourTrackLineColour;
248 
249 extern int g_iSDMMFormat;
250 extern int g_iDistanceFormat;
251 extern int g_iSpeedFormat;
252 
253 extern bool g_bAdvanceRouteWaypointOnArrivalOnly;
254 
255 extern int g_cm93_zoom_factor;
256 
257 extern int g_COGAvgSec;
258 
259 extern bool g_bCourseUp;
260 extern bool g_bLookAhead;
261 
262 extern double g_ownship_predictor_minutes;
263 extern double g_ownship_HDTpredictor_miles;
264 
265 extern bool g_bAISRolloverShowClass;
266 extern bool g_bAISRolloverShowCOG;
267 extern bool g_bAISRolloverShowCPA;
268 
269 extern bool g_bAIS_ACK_Timeout;
270 extern double g_AckTimeout_Mins;
271 
272 extern bool g_bQuiltEnable;
273 extern bool g_bFullScreenQuilt;
274 extern bool g_bConfirmObjectDelete;
275 extern wxString g_GPS_Ident;
276 extern bool g_bGarminHostUpload;
277 
278 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
279 extern wxLocale* plocale_def_lang;
280 #endif
281 
282 extern OcpnSound* g_anchorwatch_sound;
283 extern bool g_bMagneticAPB;
284 
285 extern bool g_fog_overzoom;
286 extern bool g_oz_vector_scale;
287 extern bool g_bShowStatusBar;
288 
289 extern s52plib* ps52plib;
290 
291 extern wxString g_locale;
292 extern bool g_bportable;
293 extern bool g_bdisable_opengl;
294 
295 extern ChartGroupArray* g_pGroupArray;
296 extern ocpnStyle::StyleManager* g_StyleManager;
297 
298 #ifdef ocpnUSE_GL
299 extern ocpnGLOptions g_GLOptions;
300 #endif
301 
302 extern bool g_bGLexpert;
303 //    Some constants
304 #define ID_CHOICE_NMEA wxID_HIGHEST + 1
305 
306 extern wxArrayString* EnumerateSerialPorts(void);  // in chart1.cpp
307 
308 extern wxArrayString TideCurrentDataSet;
309 extern wxString g_TCData_Dir;
310 
311 extern AIS_Decoder* g_pAIS;
312 extern bool g_bserial_access_checked;
313 
314 options* g_pOptions;
315 
316 extern bool g_bShowMenuBar;
317 extern bool g_bShowCompassWin;
318 
319 extern bool g_btouch;
320 extern bool g_bresponsive;
321 extern bool g_bAutoHideToolbar;
322 extern int g_nAutoHideToolbar;
323 extern int g_GUIScaleFactor;
324 extern int g_ChartScaleFactor;
325 extern float g_ChartScaleFactorExp;
326 extern bool g_bRollover;
327 extern int g_ShipScaleFactor;
328 extern float g_ShipScaleFactorExp;
329 extern int g_ENCSoundingScaleFactor;
330 extern bool  g_bShowMuiZoomButtons;
331 
332 extern double g_config_display_size_mm;
333 extern bool g_config_display_size_manual;
334 extern bool g_bInlandEcdis;
335 extern bool g_bDarkDecorations;
336 extern unsigned int g_canvasConfig;
337 extern bool g_useMUI;
338 extern wxString g_lastAppliedTemplateGUID;
339 extern wxString g_default_wp_icon;
340 extern wxString g_default_routepoint_icon;
341 extern int      g_iWpt_ScaMin;
342 extern bool     g_bUseWptScaMin;
343 bool            g_bOverruleScaMin;
344 extern int      osMajor, osMinor;
345 extern bool     g_bShowMuiZoomButtons;
346 
347 extern "C" bool CheckSerialAccess(void);
348 extern  wxString GetShipNameFromFile(int);
349 
350 WX_DEFINE_ARRAY_PTR(ChartCanvas*, arrayofCanvasPtr);
351 extern arrayofCanvasPtr   g_canvasArray;
352 
353 
354 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
355 static int lang_list[] = {
356     wxLANGUAGE_DEFAULT, wxLANGUAGE_ABKHAZIAN, wxLANGUAGE_AFAR,
357     wxLANGUAGE_AFRIKAANS, wxLANGUAGE_ALBANIAN, wxLANGUAGE_AMHARIC,
358     wxLANGUAGE_ARABIC, wxLANGUAGE_ARABIC_ALGERIA, wxLANGUAGE_ARABIC_BAHRAIN,
359     wxLANGUAGE_ARABIC_EGYPT, wxLANGUAGE_ARABIC_IRAQ, wxLANGUAGE_ARABIC_JORDAN,
360     wxLANGUAGE_ARABIC_KUWAIT, wxLANGUAGE_ARABIC_LEBANON,
361     wxLANGUAGE_ARABIC_LIBYA, wxLANGUAGE_ARABIC_MOROCCO, wxLANGUAGE_ARABIC_OMAN,
362     wxLANGUAGE_ARABIC_QATAR, wxLANGUAGE_ARABIC_SAUDI_ARABIA,
363     wxLANGUAGE_ARABIC_SUDAN, wxLANGUAGE_ARABIC_SYRIA, wxLANGUAGE_ARABIC_TUNISIA,
364     //    wxLANGUAGE_ARABIC_UAE,
365     wxLANGUAGE_ARABIC_YEMEN, wxLANGUAGE_ARMENIAN, wxLANGUAGE_ASSAMESE,
366     wxLANGUAGE_AYMARA, wxLANGUAGE_AZERI, wxLANGUAGE_AZERI_CYRILLIC,
367     wxLANGUAGE_AZERI_LATIN, wxLANGUAGE_BASHKIR, wxLANGUAGE_BASQUE,
368     wxLANGUAGE_BELARUSIAN, wxLANGUAGE_BENGALI, wxLANGUAGE_BHUTANI,
369     wxLANGUAGE_BIHARI, wxLANGUAGE_BISLAMA, wxLANGUAGE_BRETON,
370     wxLANGUAGE_BULGARIAN, wxLANGUAGE_BURMESE, wxLANGUAGE_CAMBODIAN,
371     wxLANGUAGE_CATALAN,
372     //    wxLANGUAGE_CHINESE,
373     //    wxLANGUAGE_CHINESE_SIMPLIFIED,
374     //    wxLANGUAGE_CHINESE_TRADITIONAL,
375     //    wxLANGUAGE_CHINESE_HONGKONG,
376     //    wxLANGUAGE_CHINESE_MACAU,
377     //    wxLANGUAGE_CHINESE_SINGAPORE,
378     wxLANGUAGE_CHINESE_TAIWAN, wxLANGUAGE_CORSICAN, wxLANGUAGE_CROATIAN,
379     wxLANGUAGE_CZECH, wxLANGUAGE_DANISH, wxLANGUAGE_DUTCH,
380     wxLANGUAGE_DUTCH_BELGIAN, wxLANGUAGE_ENGLISH, wxLANGUAGE_ENGLISH_UK,
381     wxLANGUAGE_ENGLISH_US, wxLANGUAGE_ENGLISH_AUSTRALIA,
382     wxLANGUAGE_ENGLISH_BELIZE, wxLANGUAGE_ENGLISH_BOTSWANA,
383     wxLANGUAGE_ENGLISH_CANADA, wxLANGUAGE_ENGLISH_CARIBBEAN,
384     wxLANGUAGE_ENGLISH_DENMARK, wxLANGUAGE_ENGLISH_EIRE,
385     wxLANGUAGE_ENGLISH_JAMAICA, wxLANGUAGE_ENGLISH_NEW_ZEALAND,
386     wxLANGUAGE_ENGLISH_PHILIPPINES, wxLANGUAGE_ENGLISH_SOUTH_AFRICA,
387     wxLANGUAGE_ENGLISH_TRINIDAD, wxLANGUAGE_ENGLISH_ZIMBABWE,
388     wxLANGUAGE_ESPERANTO, wxLANGUAGE_ESTONIAN, wxLANGUAGE_FAEROESE,
389     wxLANGUAGE_FARSI, wxLANGUAGE_FIJI, wxLANGUAGE_FINNISH, wxLANGUAGE_FRENCH,
390     wxLANGUAGE_FRENCH_BELGIAN, wxLANGUAGE_FRENCH_CANADIAN,
391     wxLANGUAGE_FRENCH_LUXEMBOURG, wxLANGUAGE_FRENCH_MONACO,
392     wxLANGUAGE_FRENCH_SWISS, wxLANGUAGE_FRISIAN, wxLANGUAGE_GALICIAN,
393     wxLANGUAGE_GEORGIAN, wxLANGUAGE_GERMAN, wxLANGUAGE_GERMAN_AUSTRIAN,
394     wxLANGUAGE_GERMAN_BELGIUM, wxLANGUAGE_GERMAN_LIECHTENSTEIN,
395     wxLANGUAGE_GERMAN_LUXEMBOURG, wxLANGUAGE_GERMAN_SWISS, wxLANGUAGE_GREEK,
396     wxLANGUAGE_GREENLANDIC, wxLANGUAGE_GUARANI, wxLANGUAGE_GUJARATI,
397     wxLANGUAGE_HAUSA, wxLANGUAGE_HEBREW, wxLANGUAGE_HINDI, wxLANGUAGE_HUNGARIAN,
398     wxLANGUAGE_ICELANDIC, wxLANGUAGE_INDONESIAN, wxLANGUAGE_INTERLINGUA,
399     wxLANGUAGE_INTERLINGUE, wxLANGUAGE_INUKTITUT, wxLANGUAGE_INUPIAK,
400     wxLANGUAGE_IRISH, wxLANGUAGE_ITALIAN, wxLANGUAGE_ITALIAN_SWISS,
401     wxLANGUAGE_JAPANESE, wxLANGUAGE_JAVANESE, wxLANGUAGE_KANNADA,
402     wxLANGUAGE_KASHMIRI, wxLANGUAGE_KASHMIRI_INDIA, wxLANGUAGE_KAZAKH,
403     wxLANGUAGE_KERNEWEK, wxLANGUAGE_KINYARWANDA, wxLANGUAGE_KIRGHIZ,
404     wxLANGUAGE_KIRUNDI,
405     //    wxLANGUAGE_KONKANI,
406     wxLANGUAGE_KOREAN, wxLANGUAGE_KURDISH, wxLANGUAGE_LAOTHIAN,
407     wxLANGUAGE_LATIN, wxLANGUAGE_LATVIAN, wxLANGUAGE_LINGALA,
408     wxLANGUAGE_LITHUANIAN, wxLANGUAGE_MACEDONIAN, wxLANGUAGE_MALAGASY,
409     wxLANGUAGE_MALAY, wxLANGUAGE_MALAYALAM, wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM,
410     wxLANGUAGE_MALAY_MALAYSIA, wxLANGUAGE_MALTESE,
411     //    wxLANGUAGE_MANIPURI,
412     wxLANGUAGE_MAORI, wxLANGUAGE_MARATHI, wxLANGUAGE_MOLDAVIAN,
413     wxLANGUAGE_MONGOLIAN, wxLANGUAGE_NAURU, wxLANGUAGE_NEPALI,
414     wxLANGUAGE_NEPALI_INDIA, wxLANGUAGE_NORWEGIAN_BOKMAL,
415     wxLANGUAGE_NORWEGIAN_NYNORSK, wxLANGUAGE_OCCITAN, wxLANGUAGE_ORIYA,
416     wxLANGUAGE_OROMO, wxLANGUAGE_PASHTO, wxLANGUAGE_POLISH,
417     wxLANGUAGE_PORTUGUESE, wxLANGUAGE_PORTUGUESE_BRAZILIAN, wxLANGUAGE_PUNJABI,
418     wxLANGUAGE_QUECHUA, wxLANGUAGE_RHAETO_ROMANCE, wxLANGUAGE_ROMANIAN,
419     wxLANGUAGE_RUSSIAN, wxLANGUAGE_RUSSIAN_UKRAINE, wxLANGUAGE_SAMOAN,
420     wxLANGUAGE_SANGHO, wxLANGUAGE_SANSKRIT, wxLANGUAGE_SCOTS_GAELIC,
421     wxLANGUAGE_SERBIAN, wxLANGUAGE_SERBIAN_CYRILLIC, wxLANGUAGE_SERBIAN_LATIN,
422     wxLANGUAGE_SERBO_CROATIAN, wxLANGUAGE_SESOTHO, wxLANGUAGE_SETSWANA,
423     wxLANGUAGE_SHONA, wxLANGUAGE_SINDHI, wxLANGUAGE_SINHALESE,
424     wxLANGUAGE_SISWATI, wxLANGUAGE_SLOVAK, wxLANGUAGE_SLOVENIAN,
425     wxLANGUAGE_SOMALI, wxLANGUAGE_SPANISH, wxLANGUAGE_SPANISH_ARGENTINA,
426     wxLANGUAGE_SPANISH_BOLIVIA, wxLANGUAGE_SPANISH_CHILE,
427     wxLANGUAGE_SPANISH_COLOMBIA, wxLANGUAGE_SPANISH_COSTA_RICA,
428     wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, wxLANGUAGE_SPANISH_ECUADOR,
429     wxLANGUAGE_SPANISH_EL_SALVADOR, wxLANGUAGE_SPANISH_GUATEMALA,
430     wxLANGUAGE_SPANISH_HONDURAS, wxLANGUAGE_SPANISH_MEXICAN,
431     //    wxLANGUAGE_SPANISH_MODERN,
432     wxLANGUAGE_SPANISH_NICARAGUA, wxLANGUAGE_SPANISH_PANAMA,
433     wxLANGUAGE_SPANISH_PARAGUAY, wxLANGUAGE_SPANISH_PERU,
434     wxLANGUAGE_SPANISH_PUERTO_RICO, wxLANGUAGE_SPANISH_URUGUAY,
435     wxLANGUAGE_SPANISH_US, wxLANGUAGE_SPANISH_VENEZUELA, wxLANGUAGE_SUNDANESE,
436     wxLANGUAGE_SWAHILI, wxLANGUAGE_SWEDISH, wxLANGUAGE_SWEDISH_FINLAND,
437     wxLANGUAGE_TAGALOG, wxLANGUAGE_TAJIK, wxLANGUAGE_TAMIL, wxLANGUAGE_TATAR,
438     wxLANGUAGE_TELUGU, wxLANGUAGE_THAI, wxLANGUAGE_TIBETAN, wxLANGUAGE_TIGRINYA,
439     wxLANGUAGE_TONGA, wxLANGUAGE_TSONGA, wxLANGUAGE_TURKISH, wxLANGUAGE_TURKMEN,
440     wxLANGUAGE_TWI, wxLANGUAGE_UIGHUR, wxLANGUAGE_UKRAINIAN, wxLANGUAGE_URDU,
441     wxLANGUAGE_URDU_INDIA, wxLANGUAGE_URDU_PAKISTAN, wxLANGUAGE_UZBEK,
442     wxLANGUAGE_UZBEK_CYRILLIC, wxLANGUAGE_UZBEK_LATIN, wxLANGUAGE_VIETNAMESE,
443     wxLANGUAGE_VOLAPUK, wxLANGUAGE_WELSH, wxLANGUAGE_WOLOF, wxLANGUAGE_XHOSA,
444     wxLANGUAGE_YIDDISH, wxLANGUAGE_YORUBA, wxLANGUAGE_ZHUANG, wxLANGUAGE_ZULU};
445 #endif
446 
447 
448 //  Helper utilities
LoadSVG(const wxString filename,unsigned int width,unsigned int height)449 static wxBitmap LoadSVG( const wxString filename, unsigned int width, unsigned int height )
450 {
451     #ifdef ocpnUSE_SVG
452 #ifdef __OCPN__ANDROID__
453     return loadAndroidSVG( filename, width, height );
454 #else
455     wxSVGDocument svgDoc;
456     if( svgDoc.Load(filename) )
457         return wxBitmap( svgDoc.Render( width, height, NULL, true, true ) );
458     else
459         return wxBitmap(width, height);
460 #endif
461     #else
462         return wxBitmap(width, height);
463         #endif // ocpnUSE_SVG
464 }
465 
466 
467 #ifdef __OCPN__ANDROID__
prepareSlider(wxSlider * slider)468 void prepareSlider(wxSlider *slider)
469 {
470     slider->GetHandle()->setStyleSheet(prepareAndroidSliderStyleSheet(slider->GetSize().x));
471     slider->GetHandle()->setAttribute(Qt::WA_AcceptTouchEvents);
472     slider->GetHandle()->grabGesture(Qt::PanGesture);
473     slider->GetHandle()->grabGesture(Qt::SwipeGesture);
474 }
475 #endif
476 
477 
478 // sort callback for Connections list  Sort by priority.
479 #if wxCHECK_VERSION(2, 9, 0)
SortConnectionOnPriority(wxIntPtr item1,wxIntPtr item2,wxIntPtr list)480 int wxCALLBACK SortConnectionOnPriority(wxIntPtr  item1, wxIntPtr item2, wxIntPtr list)
481 #else
482 int wxCALLBACK SortConnectionOnPriority(long item1, long item2, long list)
483 #endif
484 {
485   wxListCtrl* lc = reinterpret_cast<wxListCtrl*>(list);
486 
487   wxListItem it1, it2;
488   it1.SetId(lc->FindItem(-1, item1));
489   it1.SetColumn(3);
490   it1.SetMask(it1.GetMask() | wxLIST_MASK_TEXT);
491 
492   it2.SetId(lc->FindItem(-1, item2));
493   it2.SetColumn(3);
494   it2.SetMask(it2.GetMask() | wxLIST_MASK_TEXT);
495 
496   lc->GetItem(it1);
497   lc->GetItem(it2);
498 
499 #ifdef __WXOSX__
500   return it1.GetText().CmpNoCase(it2.GetText());
501 #else
502   return it2.GetText().CmpNoCase(it1.GetText());
503 #endif
504 }
505 
506 WX_DECLARE_LIST(wxCheckBox, CBList);
507 
508 class OCPNCheckedListCtrl : public wxScrolledWindow {
509  public:
OCPNCheckedListCtrl()510   OCPNCheckedListCtrl() {}
511 
OCPNCheckedListCtrl(wxWindow * parent,wxWindowID id=-1,const wxPoint & pt=wxDefaultPosition,const wxSize & sz=wxDefaultSize,long style=wxHSCROLL|wxVSCROLL,const wxString & name=_T ("scrolledWindow"))512   OCPNCheckedListCtrl(wxWindow* parent, wxWindowID id = -1,
513                       const wxPoint& pt = wxDefaultPosition,
514                       const wxSize& sz = wxDefaultSize,
515                       long style = wxHSCROLL | wxVSCROLL,
516                       const wxString& name = _T("scrolledWindow")) {
517     Create(parent, id, pt, sz, style, name);
518   }
519 
520   bool Create(wxWindow* parent, wxWindowID id = -1,
521               const wxPoint& pt = wxDefaultPosition,
522               const wxSize& sz = wxDefaultSize,
523               long style = wxHSCROLL | wxVSCROLL,
524               const wxString& name = _T("scrolledWindow"));
525 
~OCPNCheckedListCtrl()526   virtual ~OCPNCheckedListCtrl() {}
527 
528   unsigned int Append(wxString& label, bool benable = true);
GetCount()529   unsigned int GetCount() { return m_list.GetCount(); }
530 
531   void Clear();
532   void Check(int index, bool val);
533   bool IsChecked(int index);
534 
535  private:
536   wxBoxSizer* m_sizer;
537 
538   CBList m_list;
539 };
540 
541 #include <wx/listimpl.cpp>
542 WX_DEFINE_LIST(CBList);
543 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pt,const wxSize & sz,long style,const wxString & name)544 bool OCPNCheckedListCtrl::Create(wxWindow* parent, wxWindowID id,
545                                  const wxPoint& pt, const wxSize& sz,
546                                  long style, const wxString& name) {
547   if (!wxScrolledWindow::Create(parent, id, pt, sz, style, name)) return FALSE;
548 
549 #ifdef __OCPN__ANDROID__
550   GetHandle()->setObjectName("OCPNCheckedListCtrl");
551   GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
552 #endif
553 
554   SetScrollRate(0, 2);
555   m_sizer = new wxBoxSizer(wxVERTICAL);
556   SetSizer(m_sizer);
557 
558   return TRUE;
559 }
560 
Append(wxString & label,bool benable)561 unsigned int OCPNCheckedListCtrl::Append(wxString& label, bool benable) {
562   wxCheckBox* cb = new wxCheckBox(this, wxID_ANY, label);
563   cb->Enable(benable);
564   cb->SetValue(!benable);
565   m_sizer->Add(cb);
566   m_sizer->Layout();
567 
568   m_list.Append(cb);
569 
570   return m_list.GetCount() - 1;
571 }
572 
Check(int index,bool val)573 void OCPNCheckedListCtrl::Check(int index, bool val) {
574   CBList::Node* node = m_list.Item(index);
575   wxCheckBox* cb = node->GetData();
576 
577   if (cb) cb->SetValue(val);
578 }
579 
IsChecked(int index)580 bool OCPNCheckedListCtrl::IsChecked(int index) {
581   CBList::Node* node = m_list.Item(index);
582   wxCheckBox* cb = node->GetData();
583 
584   if (cb)
585     return cb->GetValue();
586   else
587     return false;
588 }
589 
Clear()590 void OCPNCheckedListCtrl::Clear() {
591   for(unsigned int i=0 ; i < m_list.GetCount() ; i++){
592       wxCheckBox* cb = m_list[i];
593       delete cb;
594   }
595   m_list.Clear();
596   Scroll(0,0);
597 }
598 
599 //Helper for conditional file name separator
600 void appendOSDirSlash(wxString* pString);
601 
602 extern ArrayOfMMSIProperties g_MMSI_Props_Array;
603 
604 ///////////////////////////////////////////////////////////////////////////////
605 /// Class ConfigCreateDialog
606 ///////////////////////////////////////////////////////////////////////////////
607 
BEGIN_EVENT_TABLE(ConfigCreateDialog,wxDialog)608 BEGIN_EVENT_TABLE(ConfigCreateDialog, wxDialog)
609  EVT_BUTTON(ID_CONFIGEDIT_CANCEL, ConfigCreateDialog::OnConfigEditCancelClick)
610  EVT_BUTTON(ID_CONFIGEDIT_OK, ConfigCreateDialog::OnConfigEditOKClick)
611 END_EVENT_TABLE()
612 
613 ConfigCreateDialog::ConfigCreateDialog(wxWindow* parent,
614                                wxWindowID id, const wxString& caption,
615                                const wxPoint& pos, const wxSize& size,
616                                long style)
617 : wxDialog(parent, id, caption, pos, size,
618            wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
619 {
620     CreateControls();
621     GetSizer()->SetSizeHints(this);
622     Centre();
623 }
624 
~ConfigCreateDialog(void)625 ConfigCreateDialog::~ConfigCreateDialog(void)
626 {
627 }
628 
CreateControls(void)629 void ConfigCreateDialog::CreateControls(void)
630 {
631     wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
632     SetSizer(mainSizer);
633 
634     mainSizer->Add(new wxStaticText(this, wxID_STATIC, _("Title")), 0,  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
635 
636     m_TitleCtl = new wxTextCtrl(this, wxID_ANY, wxEmptyString,  wxDefaultPosition, wxSize(40 * GetCharHeight(), -1), 0);
637     mainSizer->Add(m_TitleCtl, 0,  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
638 
639     mainSizer->AddSpacer(2 * GetCharHeight());
640 
641     mainSizer->Add(new wxStaticText(this, wxID_STATIC, _("Description")), 0,  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
642 
643     m_DescriptionCtl = new wxTextCtrl(this, wxID_ANY, wxEmptyString,  wxDefaultPosition, wxSize(-1, 6 * GetCharHeight()), wxTE_MULTILINE);
644     mainSizer->Add(m_DescriptionCtl, 0,  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
645 
646     mainSizer->AddSpacer(2 * GetCharHeight());
647 
648     mainSizer->Add(new wxStaticText(this, wxID_STATIC,
649                                     _("Create a private configuration template based on current settings.\n\
650 This template will be saved, and may be selected for further use at any time.\n\
651                ")),
652                0,  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
653 
654     mainSizer->AddSpacer(2 * GetCharHeight());
655 
656     wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
657     mainSizer->Add(btnSizer, 0, wxALIGN_RIGHT | wxALL, 5);
658 
659     m_CancelButton = new wxButton(this, ID_CONFIGEDIT_CANCEL, _("Cancel"));
660     btnSizer->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
661 
662     m_OKButton = new wxButton(this, ID_CONFIGEDIT_OK, _("OK"));
663     btnSizer->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
664     m_OKButton->SetDefault();
665 
666 }
667 
OnConfigEditCancelClick(wxCommandEvent & event)668 void ConfigCreateDialog::OnConfigEditCancelClick(wxCommandEvent& event)
669 {
670     EndModal(wxID_CANCEL);
671 }
672 
OnConfigEditOKClick(wxCommandEvent & event)673 void ConfigCreateDialog::OnConfigEditOKClick(wxCommandEvent& event)
674 {
675     const wxString &title = m_TitleCtl->GetValue();
676     const wxString &desc = m_DescriptionCtl->GetValue();
677     m_createdTemplateGUID = ConfigMgr::Get().CreateNamedConfig(title, desc, _T(""));
678     EndModal(wxID_OK);
679 
680 }
681 
682 
683 
684 
685 ///////////////////////////////////////////////////////////////////////////////
686 /// Class MMSIEditDialog
687 ///////////////////////////////////////////////////////////////////////////////
688 
BEGIN_EVENT_TABLE(MMSIEditDialog,wxDialog)689 BEGIN_EVENT_TABLE(MMSIEditDialog, wxDialog)
690 EVT_BUTTON(ID_MMSIEDIT_CANCEL, MMSIEditDialog::OnMMSIEditCancelClick)
691 EVT_BUTTON(ID_MMSIEDIT_OK, MMSIEditDialog::OnMMSIEditOKClick)
692 END_EVENT_TABLE()
693 
694 MMSIEditDialog::MMSIEditDialog(MMSIProperties* props, wxWindow* parent,
695                                wxWindowID id, const wxString& caption,
696                                const wxPoint& pos, const wxSize& size,
697                                long style)
698     : wxDialog(parent, id, caption, pos, size,
699                wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
700       m_props(props) {
701   CreateControls();
702   GetSizer()->SetSizeHints(this);
703   Centre();
704 }
705 
~MMSIEditDialog(void)706 MMSIEditDialog::~MMSIEditDialog(void) { delete m_MMSICtl; }
707 
CreateControls(void)708 void MMSIEditDialog::CreateControls(void) {
709   wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
710   SetSizer(mainSizer);
711 
712   wxStaticBox* mmsiBox =
713       new wxStaticBox(this, wxID_ANY, _("MMSI Extended Properties"));
714 
715   wxStaticBoxSizer* mmsiSizer = new wxStaticBoxSizer(mmsiBox, wxVERTICAL);
716   mainSizer->Add(mmsiSizer, 0, wxEXPAND | wxALL, 5);
717 
718   mmsiSizer->Add(new wxStaticText(this, wxID_STATIC, _("MMSI")), 0,
719                  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
720 
721   m_MMSICtl = new wxTextCtrl(this, ID_MMSI_CTL, wxEmptyString,
722                              wxDefaultPosition, wxSize(180, -1), 0);
723   mmsiSizer->Add(m_MMSICtl, 0,
724                  wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
725 
726   wxStaticBoxSizer* trackSizer = new wxStaticBoxSizer(
727       new wxStaticBox(this, wxID_ANY, _("Tracking")), wxVERTICAL);
728 
729   wxGridSizer* gridSizer = new wxGridSizer(0, 3, 0, 0);
730 
731   m_rbTypeTrackDefault =
732       new wxRadioButton(this, wxID_ANY, _("Default tracking"),
733                         wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
734   m_rbTypeTrackDefault->SetValue(TRUE);
735   gridSizer->Add(m_rbTypeTrackDefault, 0, wxALL, 5);
736 
737   m_rbTypeTrackAlways = new wxRadioButton(this, wxID_ANY, _("Always track"));
738   gridSizer->Add(m_rbTypeTrackAlways, 0, wxALL, 5);
739 
740   m_rbTypeTrackNever = new wxRadioButton(this, wxID_ANY, _(" Never track"));
741   gridSizer->Add(m_rbTypeTrackNever, 0, wxALL, 5);
742 
743   m_cbTrackPersist = new wxCheckBox(this, wxID_ANY, _("Persistent"));
744   gridSizer->Add(m_cbTrackPersist, 0, wxALL, 5);
745 
746   trackSizer->Add(gridSizer, 0, wxEXPAND, 0);
747   mmsiSizer->Add(trackSizer, 0, wxEXPAND, 0);
748 
749   m_IgnoreButton = new wxCheckBox(this, wxID_ANY, _("Ignore this MMSI"));
750   mmsiSizer->Add(m_IgnoreButton, 0, wxEXPAND, 5);
751 
752   m_MOBButton = new wxCheckBox(this, wxID_ANY,
753                                _("Handle this MMSI as SART/PLB(AIS) MOB."));
754   mmsiSizer->Add(m_MOBButton, 0, wxEXPAND, 5);
755 
756   m_VDMButton = new wxCheckBox(this, wxID_ANY, _("Convert AIVDM to AIVDO for this MMSI"));
757   mmsiSizer->Add(m_VDMButton, 0, wxEXPAND, 5);
758 
759   m_FollowerButton = new wxCheckBox(this, wxID_ANY, _("This MMSI is my Follower - No CPA Alert"));
760   mmsiSizer->Add(m_FollowerButton, 0, wxEXPAND, 5);
761 
762   wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
763   mainSizer->Add(btnSizer, 0, wxALIGN_RIGHT | wxALL, 5);
764 
765   m_CancelButton = new wxButton(this, ID_MMSIEDIT_CANCEL, _("Cancel"));
766   btnSizer->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
767 
768   m_OKButton = new wxButton(this, ID_MMSIEDIT_OK, _("OK"));
769   btnSizer->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
770   m_OKButton->SetDefault();
771 
772   //  Set initial values...
773   wxString sMMSI;
774   if (m_props->MMSI > 0)
775     sMMSI.Printf(_T("%d"), m_props->MMSI);
776   else
777     sMMSI = _T("");
778   m_MMSICtl->AppendText(sMMSI);
779 
780   switch (m_props->TrackType) {
781     case TRACKTYPE_ALWAYS:
782       m_rbTypeTrackAlways->SetValue(TRUE);
783       break;
784     case TRACKTYPE_NEVER:
785       m_rbTypeTrackNever->SetValue(TRUE);
786       break;
787     default:
788       break;
789   }
790 
791   m_cbTrackPersist->SetValue(m_props->m_bPersistentTrack);
792   m_IgnoreButton->SetValue(m_props->m_bignore);
793   m_MOBButton->SetValue(m_props->m_bMOB);
794   m_VDMButton->SetValue(m_props->m_bVDM);
795   m_FollowerButton->SetValue(m_props->m_bFollower);
796 
797   SetColorScheme(GLOBAL_COLOR_SCHEME_RGB);
798 }
799 
SetColorScheme(ColorScheme cs)800 void MMSIEditDialog::SetColorScheme(ColorScheme cs) { DimeControl(this); }
801 
OnMMSIEditCancelClick(wxCommandEvent & event)802 void MMSIEditDialog::OnMMSIEditCancelClick(wxCommandEvent& event) {
803   EndModal(wxID_CANCEL);
804 }
805 
Persist()806 void MMSIEditDialog::Persist() {
807   if (m_props) {
808 
809     if (m_rbTypeTrackDefault->GetValue())
810         m_props->TrackType = TRACKTYPE_DEFAULT;
811     else if (m_rbTypeTrackAlways->GetValue())
812         m_props->TrackType = TRACKTYPE_ALWAYS;
813     else
814         m_props->TrackType = TRACKTYPE_NEVER;
815 
816     m_props->m_bignore = m_IgnoreButton->GetValue();
817     m_props->m_bMOB = m_MOBButton->GetValue();
818     m_props->m_bVDM = m_VDMButton->GetValue();
819     m_props->m_bFollower = m_FollowerButton->GetValue();
820     m_props->m_bPersistentTrack = m_cbTrackPersist->GetValue();
821     if (m_props->m_ShipName == wxEmptyString) {
822         AIS_Target_Data *proptarget = g_pAIS->Get_Target_Data_From_MMSI(m_props->MMSI);
823         if (proptarget) {
824             wxString s = proptarget->GetFullName();
825             m_props->m_ShipName = s;
826         }
827         else {
828             wxString GetShipNameFromFile(int);
829             m_props->m_ShipName = GetShipNameFromFile(m_props->MMSI);
830         }
831     }
832   }
833 }
834 
OnMMSIEditOKClick(wxCommandEvent & event)835 void MMSIEditDialog::OnMMSIEditOKClick(wxCommandEvent& event) {
836   // Update the MMSIProperties by the passed pointer
837   if (m_props) {
838     long nmmsi;
839     m_MMSICtl->GetValue().ToLong(&nmmsi);
840     m_props->MMSI = nmmsi;
841     Persist();
842 
843 
844     if (m_MMSICtl->GetValue().Length() != 9)
845     {
846         OCPNMessageDialog* dlg = new OCPNMessageDialog(this,
847             _("An MMSI Id is generally a number of nine digits.\nPlease check your entries and cancel if necessary."), _("OpenCPN Info"), wxOK | wxCANCEL);
848 
849         dlg->ShowWindowModalThenDo([this,dlg](int retcode){
850             if ( retcode == wxID_OK ) {
851                 Persist();
852             }
853             EndModal(retcode);
854         });
855     } else {
856         EndModal(wxID_OK);
857     }
858   }
859 }
860 
OnCtlUpdated(wxCommandEvent & event)861 void MMSIEditDialog::OnCtlUpdated(wxCommandEvent& event) {}
862 
BEGIN_EVENT_TABLE(MMSIListCtrl,wxListCtrl)863 BEGIN_EVENT_TABLE(MMSIListCtrl, wxListCtrl)
864 EVT_LIST_ITEM_SELECTED(ID_MMSI_PROPS_LIST, MMSIListCtrl::OnListItemClick)
865 EVT_LIST_ITEM_ACTIVATED(ID_MMSI_PROPS_LIST, MMSIListCtrl::OnListItemActivated)
866 EVT_LIST_ITEM_RIGHT_CLICK(ID_MMSI_PROPS_LIST,
867                           MMSIListCtrl::OnListItemRightClick)
868 EVT_MENU(ID_DEF_MENU_MMSI_EDIT, MMSIListCtrl::PopupMenuHandler)
869 EVT_MENU(ID_DEF_MENU_MMSI_DELETE, MMSIListCtrl::PopupMenuHandler)
870 END_EVENT_TABLE()
871 
872 MMSIListCtrl::MMSIListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
873                            const wxSize& size, long style)
874     : wxListCtrl(parent, id, pos, size, style) {
875   m_parent = parent;
876 }
877 
~MMSIListCtrl(void)878 MMSIListCtrl::~MMSIListCtrl(void) {}
879 
OnGetItemText(long item,long column) const880 wxString MMSIListCtrl::OnGetItemText(long item, long column) const {
881   wxString ret;
882   MMSIProperties* props = g_MMSI_Props_Array[item];
883 
884   if (!props) return ret;
885   switch (column) {
886     case mlMMSI:
887       if (props->MMSI > 0) ret = wxString::Format(_T( "%d" ), props->MMSI);
888       break;
889     case mlTrackMode:
890       switch (props->TrackType) {
891         case TRACKTYPE_DEFAULT:
892           ret = _("Default");
893           break;
894         case TRACKTYPE_ALWAYS:
895           ret = _("Always");
896           break;
897         case TRACKTYPE_NEVER:
898           ret = _("Never");
899           break;
900         default:
901           ret = _T( "???" );
902       }
903       if (props->m_bPersistentTrack)
904         ret.Append(_T( ", " )).Append(_("Persistent"));
905       break;
906     case mlIgnore:
907       if (props->m_bignore) ret = _T( "X" );
908       break;
909     case mlMOB:
910       if (props->m_bMOB) ret = _T( "X" );
911       break;
912     case mlVDM:
913       if (props->m_bVDM) ret = _T( "X" );
914       break;
915     case mlFollower:
916       if (props->m_bFollower) ret = _T("X");
917       break;
918     case mlShipName:
919         ret = props->m_ShipName;
920         break;
921     default:
922       ret = _T( "??" );
923       break;
924   }
925   return ret;
926 }
927 
OnListItemClick(wxListEvent & event)928 void MMSIListCtrl::OnListItemClick(wxListEvent& event) {}
929 
OnListItemActivated(wxListEvent & event)930 void MMSIListCtrl::OnListItemActivated(wxListEvent& event) {
931   MMSIProperties* props = g_MMSI_Props_Array.Item(event.GetIndex());
932   MMSIProperties* props_new = new MMSIProperties(*props);
933 
934   MMSIEditDialog* pd =
935       new MMSIEditDialog(props_new, m_parent, -1, _("Edit MMSI Properties"),
936                          wxDefaultPosition, wxSize(200, 200));
937 
938   if (pd->ShowModal() == wxID_OK) {
939     g_MMSI_Props_Array.RemoveAt(event.GetIndex());
940     delete props;
941     g_MMSI_Props_Array.Insert(props_new, event.GetIndex());
942   }
943   else
944     delete props_new;
945 
946   pd->Destroy();
947 }
948 
OnListItemRightClick(wxListEvent & event)949 void MMSIListCtrl::OnListItemRightClick(wxListEvent& event) {
950   m_context_item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
951   if (m_context_item == wxNOT_FOUND) return;
952   wxMenu* menu = new wxMenu(_("MMSI Properties"));
953   wxMenuItem* item_edit =
954       new wxMenuItem(menu, ID_DEF_MENU_MMSI_EDIT, _("Edit") + _T("..."));
955   menu->Append(item_edit);
956   wxMenuItem* item_delete =
957       new wxMenuItem(menu, ID_DEF_MENU_MMSI_DELETE, _("Delete"));
958   menu->Append(item_delete);
959 
960 #ifdef __WXMSW__
961   wxFont* qFont = GetOCPNScaledFont(_("Menu"));
962   item_edit->SetFont(*qFont);
963   item_delete->SetFont(*qFont);
964 #endif
965 
966   wxPoint p = ScreenToClient(wxGetMousePosition());
967   PopupMenu(menu, p.x, p.y);
968 
969   SetItemCount(g_MMSI_Props_Array.GetCount());
970   Refresh(TRUE);
971 }
972 
PopupMenuHandler(wxCommandEvent & event)973 void MMSIListCtrl::PopupMenuHandler(wxCommandEvent& event) {
974   int context_item = m_context_item;
975   MMSIProperties* props = g_MMSI_Props_Array[context_item];
976 
977   if (!props)
978       return;
979 
980   switch (event.GetId()) {
981     case ID_DEF_MENU_MMSI_EDIT: {
982       MMSIProperties* props_new = new MMSIProperties(*props);
983       MMSIEditDialog* pd = new MMSIEditDialog(props_new, m_parent, -1, _("Edit MMSI Properties"),
984                              wxDefaultPosition, wxSize(200, 200));
985 
986       if (pd->ShowModal() == wxID_OK) {
987         g_MMSI_Props_Array.RemoveAt(context_item);
988         delete props;
989         props_new->m_ShipName = GetShipNameFromFile(props_new->MMSI);
990         g_MMSI_Props_Array.Insert(props_new, context_item);
991       }
992       else {
993         delete props_new;
994       }
995       pd->Destroy();
996       break;
997     }
998     case ID_DEF_MENU_MMSI_DELETE:
999       g_MMSI_Props_Array.RemoveAt(context_item);
1000       delete props;
1001       break;
1002   }
1003 }
1004 
MMSI_Props_Panel(wxWindow * parent)1005 MMSI_Props_Panel::MMSI_Props_Panel(wxWindow* parent)
1006     : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1007               wxBORDER_NONE) {
1008   m_pparent = parent;
1009 
1010   wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
1011   SetFont(*qFont);
1012 
1013   wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
1014   SetSizer(topSizer);
1015 
1016   wxString MMSI_props_column_spec = _T("120;120;100;100;100;100;100;100");
1017   //  Parse the global column width string as read from config file
1018   wxStringTokenizer tkz(MMSI_props_column_spec, _T(";"));
1019   wxString s_width = tkz.GetNextToken();
1020   int width;
1021   long lwidth;
1022 
1023   m_pListCtrlMMSI = new MMSIListCtrl(
1024       this, ID_MMSI_PROPS_LIST, wxDefaultPosition, wxSize(-1, -1),
1025       wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES |
1026           wxBORDER_SUNKEN | wxLC_VIRTUAL);
1027   //wxImageList* imglist = new wxImageList(16, 16, TRUE, 2);
1028 
1029   ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
1030   //imglist->Add(style->GetIcon(_T( "sort_asc" )));
1031   //imglist->Add(style->GetIcon(_T( "sort_desc" )));
1032 
1033   // m_pListCtrlMMSI->AssignImageList( imglist, wxIMAGE_LIST_SMALL );
1034   int dx = GetCharWidth();
1035 
1036   width = dx * 5;
1037   if (s_width.ToLong(&lwidth)) {
1038     width = wxMax(dx * 2, lwidth);
1039     width = wxMin(width, dx * 13);
1040   }
1041   m_pListCtrlMMSI->InsertColumn(tlMMSI, _("MMSI"), wxLIST_FORMAT_LEFT, width);
1042 
1043   s_width = tkz.GetNextToken();
1044   width = dx * 12;
1045   if (s_width.ToLong(&lwidth)) {
1046     width = wxMax(dx * 2, lwidth);
1047     width = wxMin(width, dx * 25);
1048   }
1049   m_pListCtrlMMSI->InsertColumn(tlCLASS, _("Track Mode"), wxLIST_FORMAT_CENTER, width);
1050 
1051   s_width = tkz.GetNextToken();
1052   width = dx * 8;
1053   if (s_width.ToLong(&lwidth)) {
1054     width = wxMax(dx * 2, lwidth);
1055     width = wxMin(width, dx * 10);
1056   }
1057   m_pListCtrlMMSI->InsertColumn(tlTYPE, _("Ignore"), wxLIST_FORMAT_CENTER,
1058                                 width);
1059 
1060   s_width = tkz.GetNextToken();
1061   width = dx * 8;
1062   if (s_width.ToLong(&lwidth)) {
1063     width = wxMax(dx * 2, lwidth);
1064     width = wxMin(width, dx * 10);
1065   }
1066   m_pListCtrlMMSI->InsertColumn(tlTYPE, _("MOB"), wxLIST_FORMAT_CENTER, width);
1067 
1068   s_width = tkz.GetNextToken();
1069   width = dx * 8;
1070   if (s_width.ToLong(&lwidth)) {
1071     width = wxMax(dx * 2, lwidth);
1072     width = wxMin(width, dx * 15);
1073   }
1074   m_pListCtrlMMSI->InsertColumn(tlTYPE, _("VDM->VDO"), wxLIST_FORMAT_CENTER, width);
1075 
1076   s_width = tkz.GetNextToken();
1077   width = dx * 8;
1078   if (s_width.ToLong(&lwidth)) {
1079     width = wxMax(dx * 2, lwidth);
1080     width = wxMin(width, dx * 30);
1081   }
1082   m_pListCtrlMMSI->InsertColumn(tlTYPE, _("Ship name"), wxLIST_FORMAT_CENTER, width);
1083 
1084   s_width = tkz.GetNextToken();
1085   width = dx * 8;
1086   if (s_width.ToLong(&lwidth)) {
1087       width = wxMax(dx * 2, lwidth);
1088       width = wxMin(width, dx * 10);
1089   }
1090   m_pListCtrlMMSI->InsertColumn(tlTYPE, _("Follower"), wxLIST_FORMAT_CENTER, width);  //Has
1091 
1092   topSizer->Add(m_pListCtrlMMSI, 1, wxEXPAND | wxALL, 0);
1093 
1094   m_pButtonNew = new wxButton(this, wxID_ANY, _("New..."), wxDefaultPosition,
1095                               wxSize(200, -1));
1096   m_pButtonNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
1097                         wxCommandEventHandler(MMSI_Props_Panel::OnNewButton),
1098                         NULL, this);
1099   topSizer->Add(m_pButtonNew, 0, wxALIGN_RIGHT | wxALL, 0);
1100 
1101   topSizer->Layout();
1102 
1103   //  This is silly, but seems to be required for __WXMSW__ build
1104   //  If not done, the SECOND invocation of the panel fails to expand the list
1105   //  to the full wxSizer size....
1106   SetSize(GetSize().x, GetSize().y - 1);
1107 
1108   SetColorScheme(GLOBAL_COLOR_SCHEME_RGB);
1109 }
1110 
~MMSI_Props_Panel(void)1111 MMSI_Props_Panel::~MMSI_Props_Panel(void) {}
1112 
OnNewButton(wxCommandEvent & event)1113 void MMSI_Props_Panel::OnNewButton(wxCommandEvent& event) {
1114   MMSIProperties* props = new MMSIProperties(-1);
1115 
1116   MMSIEditDialog* pd =
1117       new MMSIEditDialog(props, m_parent, -1, _("Add MMSI Properties"),
1118                          wxDefaultPosition, wxSize(200, 200));
1119 
1120   DimeControl( pd );
1121   pd->ShowWindowModalThenDo([this, pd, props](int retcode){
1122         if ( retcode == wxID_OK ) {
1123             g_MMSI_Props_Array.Add(props);
1124         }
1125         else {
1126             delete props;
1127         }
1128         UpdateMMSIList();
1129     });
1130 }
1131 
UpdateMMSIList(void)1132 void MMSI_Props_Panel::UpdateMMSIList(void) {
1133   // Capture the MMSI of the curently selected list item
1134   long selItemID = wxNOT_FOUND;
1135   m_pListCtrlMMSI->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1136                                wxLIST_STATE_SELECTED);
1137 
1138   int selMMSI = wxNOT_FOUND;
1139   if (selItemID != wxNOT_FOUND)
1140     selMMSI = g_MMSI_Props_Array[selItemID]->MMSI;
1141 
1142   m_pListCtrlMMSI->SetItemCount(g_MMSI_Props_Array.GetCount());
1143 
1144   // Restore selected item
1145   long item_sel = wxNOT_FOUND;
1146   if (selItemID != wxNOT_FOUND && selMMSI != wxNOT_FOUND) {
1147     for (unsigned int i = 0; i < g_MMSI_Props_Array.GetCount(); i++) {
1148       if (g_MMSI_Props_Array[i]->MMSI == selMMSI) {
1149         item_sel = i;
1150         break;
1151       }
1152     }
1153   }
1154 
1155   if (g_MMSI_Props_Array.GetCount() > 0)
1156     m_pListCtrlMMSI->SetItemState(item_sel,
1157                                   wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1158                                   wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1159 
1160 #ifdef __WXMSW__
1161   m_pListCtrlMMSI->Refresh(FALSE);
1162 #endif
1163 }
1164 
SetColorScheme(ColorScheme cs)1165 void MMSI_Props_Panel::SetColorScheme(ColorScheme cs) { DimeControl(this); }
1166 
1167 
1168 //WX_DECLARE_OBJARRAY(wxBitmap,      ArrayOfBitmaps);
1169 //#include <wx/arrimpl.cpp>
1170 //WX_DEFINE_OBJARRAY(ArrayOfBitmaps);
1171 
1172 class  OCPNFatCombo : public wxOwnerDrawnComboBox
1173 {
1174 public:
1175 
1176     OCPNFatCombo();
1177 
1178     OCPNFatCombo(wxWindow* parent, wxWindowID id, const wxString& value = _T(""),
1179                   const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
1180                   int n = 0, const wxString choices[] = NULL,
1181                   long style = 0, const wxValidator& validator = wxDefaultValidator, const wxString& name = _T("OCPNFatCombo") );
1182 
1183 
1184 
1185     ~OCPNFatCombo ();
1186 
1187     void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const;
1188     wxCoord OnMeasureItem(size_t item) const;
1189     wxCoord OnMeasureItemWidth(size_t item) const;
1190     bool SetFont(const wxFont& font);
1191 
1192     int Append(const wxString& item, wxBitmap bmp);
1193     void Clear( void );
1194 
1195     const wxFont *dfont;
1196 
1197 private:
1198     int         itemHeight;
1199     ArrayOfBitmaps  bmpArray;
1200 
1201 };
1202 
OCPNFatCombo()1203 OCPNFatCombo::OCPNFatCombo()
1204     :wxOwnerDrawnComboBox(){}
1205 
OCPNFatCombo(wxWindow * parent,wxWindowID id,const wxString & value,const wxPoint & pos,const wxSize & size,int n,const wxString choices[],long style,const wxValidator & validator,const wxString & name)1206 OCPNFatCombo::OCPNFatCombo (wxWindow* parent, wxWindowID id, const wxString& value,
1207                                   const wxPoint& pos, const wxSize& size, int n, const wxString choices[],
1208                                   long style, const wxValidator& validator, const wxString& name)
1209                         :wxOwnerDrawnComboBox(parent, id, value, pos, size, n, choices, style, validator, name)
1210 {
1211     double fontHeight = GetFont().GetPointSize() / g_Platform->getFontPointsperPixel();
1212     itemHeight = (int)wxRound(fontHeight);
1213     SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
1214 }
1215 
~OCPNFatCombo()1216 OCPNFatCombo::~OCPNFatCombo ()
1217 {
1218 }
1219 
SetFont(const wxFont & font)1220 bool OCPNFatCombo::SetFont(const wxFont& font)
1221 {
1222     dfont = &font;
1223     return true;
1224 }
1225 
OnDrawItem(wxDC & dc,const wxRect & rect,int item,int flags) const1226 void OCPNFatCombo::OnDrawItem( wxDC& dc,
1227                                        const wxRect& rect,
1228                                        int item,
1229                                        int flags ) const
1230 {
1231 
1232     int offset_x =  10;
1233 //    dc.DrawBitmap(bmpArray.Item(item), rect.x, rect.y + (rect.height - bmpHeight)/2, true);
1234     dc.SetFont(*dfont);
1235 
1236     wxColor bg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
1237     wxBrush br = wxBrush(bg);
1238     wxBrush sv = dc.GetBrush();
1239     dc.SetBrush(br);
1240     dc.DrawRectangle(0, 0, rect.width, rect.height);
1241     dc.SetBrush(sv);
1242     dc.SetTextForeground(wxColour(0, 0, 0));
1243 
1244     if ( flags & wxODCB_PAINTING_CONTROL )
1245     {
1246         wxString text = GetValue();
1247         int margin_x = 2;
1248         dc.DrawText( text, rect.x + margin_x + offset_x, (rect.height-dc.GetCharHeight())/2 + rect.y );
1249     }
1250     else
1251     {
1252         dc.SetBackground(wxBrush(br));
1253         dc.Clear();
1254         dc.DrawText( GetVListBoxComboPopup()->GetString(item), rect.x + 2 + offset_x, (rect.height-dc.GetCharHeight())/2 + rect.y );
1255     }
1256 }
1257 
1258 
1259 
OnMeasureItem(size_t item) const1260 wxCoord OCPNFatCombo::OnMeasureItem( size_t item ) const
1261 {
1262     if(item < bmpArray.GetCount())
1263         return wxMax(itemHeight, bmpArray.Item(item).GetHeight());
1264 
1265     return itemHeight * 12 /10;
1266 }
1267 
OnMeasureItemWidth(size_t item) const1268 wxCoord OCPNFatCombo::OnMeasureItemWidth( size_t item ) const
1269 {
1270     return -1;
1271 }
1272 
Append(const wxString & item,wxBitmap bmp)1273 int OCPNFatCombo::Append(const wxString& item, wxBitmap bmp)
1274 {
1275     bmpArray.Add(bmp);
1276     int idx = wxOwnerDrawnComboBox::Append(item);
1277 
1278     return idx;
1279 }
1280 
Clear(void)1281 void OCPNFatCombo::Clear( void )
1282 {
1283     wxOwnerDrawnComboBox::Clear();
1284     bmpArray.Clear();
1285 }
1286 
1287 
1288 
1289 
1290 
1291 
1292 
1293 
BEGIN_EVENT_TABLE(options,wxDialog)1294 BEGIN_EVENT_TABLE(options, wxDialog)
1295 EVT_CHECKBOX(ID_DEBUGCHECKBOX1, options::OnDebugcheckbox1Click)
1296 EVT_BUTTON(ID_BUTTONADD, options::OnButtonaddClick)
1297 EVT_BUTTON(ID_BUTTONDELETE, options::OnButtondeleteClick)
1298 EVT_BUTTON(ID_PARSEENCBUTTON, options::OnButtonParseENC)
1299 EVT_BUTTON(ID_BUTTONCOMPRESS, options::OnButtoncompressClick)
1300 EVT_BUTTON(ID_TCDATAADD, options::OnInsertTideDataLocation)
1301 EVT_BUTTON(ID_TCDATADEL, options::OnRemoveTideDataLocation)
1302 EVT_BUTTON(ID_APPLY, options::OnApplyClick)
1303 EVT_BUTTON(xID_OK, options::OnXidOkClick)
1304 EVT_BUTTON(wxID_CANCEL, options::OnCancelClick)
1305 EVT_BUTTON(ID_BUTTONFONTCHOOSE, options::OnChooseFont)
1306 EVT_CHOICE(ID_CHOICE_FONTELEMENT, options::OnFontChoice)
1307 EVT_CLOSE(options::OnClose)
1308 
1309 #if defined(__WXGTK__) || defined(__WXQT__)
1310 EVT_BUTTON(ID_BUTTONFONTCOLOR, options::OnChooseFontColor)
1311 #endif
1312 #ifdef ocpnUSE_GL
1313 EVT_BUTTON(ID_OPENGLOPTIONS, options::OnOpenGLOptions)
1314 #endif
1315 EVT_CHOICE(ID_RADARDISTUNIT, options::OnDisplayCategoryRadioButton)
1316 EVT_CHOICE(ID_DEPTHUNITSCHOICE, options::OnUnitsChoice)
1317 EVT_BUTTON(ID_CLEARLIST, options::OnButtonClearClick)
1318 EVT_BUTTON(ID_SELECTLIST, options::OnButtonSelectClick)
1319 EVT_BUTTON(ID_SETSTDLIST, options::OnButtonSetStd)
1320 EVT_BUTTON(ID_AISALERTSELECTSOUND, options::OnButtonSelectSound)
1321 EVT_BUTTON(ID_AISALERTTESTSOUND, options::OnButtonTestSound)
1322 EVT_CHECKBOX(ID_SHOWGPSWINDOW, options::OnShowGpsWindowCheckboxClick)
1323 EVT_CHOICE(ID_SHIPICONTYPE, options::OnShipTypeSelect)
1324 EVT_CHOICE(ID_RADARRINGS, options::OnRadarringSelect)
1325 EVT_CHOICE(ID_OPWAYPOINTRANGERINGS, options::OnWaypointRangeRingSelect)
1326 EVT_CHAR_HOOK(options::OnCharHook)
1327 EVT_TIMER(ID_BT_SCANTIMER, options::onBTScanTimer)
1328 END_EVENT_TABLE()
1329 
1330 
1331 
1332 options::options(MyFrame* parent, wxWindowID id, const wxString& caption,
1333                  const wxPoint& pos, const wxSize& size, long style) {
1334   Init();
1335 
1336   pParent = parent;
1337 
1338   long wstyle = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER;
1339   SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
1340 
1341   wxDialog::Create(parent, id, caption, pos, size, wstyle);
1342   SetFont(*dialogFont);
1343 
1344   CreateControls();
1345   RecalculateSize();
1346 
1347   Center();
1348 }
1349 
~options(void)1350 options::~options(void) {
1351 
1352   wxNotebook* nb = dynamic_cast<wxNotebook*>(m_pListbook->GetPage(m_pageCharts));
1353     if (nb)
1354         nb->Disconnect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
1355                                     wxListbookEventHandler(options::OnChartsPageChange),
1356                                     NULL, this);
1357 
1358   groupsPanel->EmptyChartGroupArray(m_pGroupArray);
1359   delete groupsPanel;
1360 
1361   delete m_pSerialArray;
1362   delete m_pGroupArray;
1363   delete m_topImgList;
1364 
1365   // Take care of the plugin manager...
1366 
1367   delete m_pPlugInCtrl;
1368   if(g_pi_manager)
1369     g_pi_manager->SetListPanelPtr( NULL );
1370 #ifndef __OCPN__ANDROID__
1371   delete m_PluginCatalogMgrPanel;
1372 #endif
1373 
1374 }
1375 
1376 // with AIS it's called very often
1377 #if wxCHECK_VERSION(3,0,0)
SendIdleEvents(wxIdleEvent & event)1378 bool options::SendIdleEvents(wxIdleEvent &event )  {
1379     if (IsShown())
1380        return wxDialog::SendIdleEvents(event);
1381    return false;
1382 }
1383 #endif
1384 
RecalculateSize(void)1385 void options::RecalculateSize(void) {
1386   if (!g_bresponsive) {
1387     wxSize canvas_size = gFrame->GetSize();
1388     wxSize fitted_size = GetSize();
1389 
1390     fitted_size.x = wxMin(fitted_size.x, canvas_size.x);
1391     fitted_size.y = wxMin(fitted_size.y, canvas_size.y);
1392 
1393     SetSize(fitted_size);
1394 
1395     Fit();
1396     m_nCharWidthMax = GetSize().x / GetCharWidth();
1397 
1398     return;
1399   }
1400 
1401   wxSize esize;
1402   esize.x = GetCharWidth() * 110;
1403   esize.y = GetCharHeight() * 40;
1404 
1405   wxSize dsize = GetParent()->GetSize();  // GetClientSize();
1406   esize.y = wxMin(esize.y, dsize.y - 0 /*(2 * GetCharHeight())*/);
1407   esize.x = wxMin(esize.x, dsize.x - 0 /*(2 * GetCharHeight())*/);
1408   SetSize(esize);
1409 
1410   wxSize fsize = GetSize();
1411   wxSize canvas_size = GetParent()->GetSize();
1412   wxPoint screen_pos = GetParent()->GetScreenPosition();
1413   int xp = (canvas_size.x - fsize.x) / 2;
1414   int yp = (canvas_size.y - fsize.y) / 2;
1415   Move(screen_pos.x + xp, screen_pos.y + yp);
1416 
1417   m_nCharWidthMax = GetSize().x / GetCharWidth();
1418 }
1419 
Init(void)1420 void options::Init(void) {
1421   m_pWorkDirList = NULL;
1422 
1423   pShowStatusBar = NULL;
1424   pShowMenuBar = NULL;
1425   pShowCompassWin = NULL;
1426   pSelCtl = NULL;
1427   pActiveChartsList = NULL;
1428   ps57CtlListBox = NULL;
1429   pDispCat = NULL;
1430   m_pSerialArray = NULL;
1431   pUpdateCheckBox = NULL;
1432   pParseENCButton = NULL;
1433   k_charts = 0;
1434   k_vectorcharts = 0;
1435   k_plugins = 0;
1436   k_tides = 0;
1437   m_pConfig = NULL;
1438 
1439   pSoundDeviceIndex = NULL;
1440 
1441   pCBNorthUp = NULL;
1442   pCBCourseUp = NULL;
1443   pCBLookAhead = NULL;
1444   pCDOQuilting = NULL;
1445   pPreserveScale = NULL;
1446   pSmoothPanZoom = NULL;
1447   pEnableZoomToCursor = NULL;
1448   pSDisplayGrid = NULL;
1449   pCDOOutlines = NULL;
1450   pSDepthUnits = NULL;
1451   pSLiveETA = NULL;
1452   pSDefaultBoatSpeed = NULL;
1453 
1454   activeSizer = NULL;
1455   itemActiveChartStaticBox = NULL;
1456 
1457   pCheck_SOUNDG = NULL;
1458   pCheck_META = NULL;
1459   pCheck_SHOWIMPTEXT = NULL;
1460   pCheck_SCAMIN = NULL;
1461   pCheck_ATONTEXT = NULL;
1462   pCheck_LDISTEXT = NULL;
1463   pCheck_XLSECTTEXT = NULL;
1464 
1465   m_bVisitLang = FALSE;
1466   m_itemFontElementListBox = NULL;
1467   m_textSample = NULL;
1468   m_topImgList = NULL;
1469 
1470   m_pListbook = NULL;
1471   m_pGroupArray = NULL;
1472   m_groups_changed = 0;
1473 
1474   m_pageDisplay = -1;
1475   m_pageConnections = -1;
1476   m_pageCharts = -1;
1477   m_pageShips = -1;
1478   m_pageUI = -1;
1479   m_pagePlugins = -1;
1480   m_pageConnections = -1;
1481 
1482   m_buttonScanBT = 0;
1483   m_stBTPairs = 0;
1484   m_choiceBTDataSources = 0;
1485 
1486   b_haveWMM = g_pi_manager && g_pi_manager->IsPlugInAvailable(_T("WMM"));
1487   b_oldhaveWMM = b_haveWMM;
1488 
1489   lastPage = 0;
1490   m_bneedNew =false;
1491 
1492   m_cs = (ColorScheme) 0;
1493 
1494   // for deferred loading
1495   m_pPlugInCtrl = NULL;
1496   m_PluginCatalogMgrPanel = NULL;
1497   m_pNMEAForm = NULL;
1498   mSelectedConnection = NULL;
1499 
1500 #ifdef __OCPN__ANDROID__
1501   m_scrollRate = 1;
1502 #else
1503   m_scrollRate = 15;
1504 #endif
1505 
1506   m_BTScanTimer.SetOwner(this, ID_BT_SCANTIMER);
1507   m_BTscanning = 0;
1508 
1509   dialogFont = GetOCPNScaledFont(_("Dialog"));
1510 
1511   dialogFontPlus =  new wxFont(*dialogFont);  // we can't use Smaller() because wx2.8 doesn't support it
1512   dialogFontPlus->SetPointSize((dialogFontPlus->GetPointSize() * 1.2) +  0.5);  // + 0.5 to round instead of truncate
1513   dialogFontPlus->SetWeight(wxFONTWEIGHT_BOLD);
1514 
1515 
1516   m_bVectorInit = false;
1517 
1518   // This variable is used by plugin callback function AddOptionsPage
1519   g_pOptions = this;
1520 
1521   m_bcompact = false;
1522 
1523 #ifdef __OCPN__ANDROID__
1524   m_bcompact = true;
1525 #endif
1526   pCmdSoundString = NULL;
1527 
1528   m_sconfigSelect_single = NULL;
1529   m_sconfigSelect_twovertical = NULL;
1530 
1531   wxScreenDC dc;
1532   dc.SetFont(*dialogFont);
1533   int width, height;
1534   dc.GetTextExtent(_T("H"), &width, &height, NULL, NULL, dialogFont);
1535 
1536   m_colourPickerDefaultSize = wxSize(4 * height, height * 2);
1537 
1538 }
1539 
1540 #if defined(__GNUC__) && __GNUC__ < 8
1541 // Handle old gcc C++-11 bugs, remove when builders updated to gcc >= 8.1.1.
1542 
1543 static const wxString BAD_ACCESS_MSG = _(  \
1544 "The device selected is not accessible; opencpn will likely not be able\n"\
1545 "to use this device as-is. You might want to exit OpenCPN, reboot and\n"\
1546 "retry after creating a file called /etc/udev/rules.d/70-opencpn.rules\n"\
1547 "with the following contents:\n\n"\
1548 "            KERNEL==\"ttyUSB*\", MODE=\"0666\"\n"\
1549 "            KERNEL==\"ttyACM*\", MODE=\"0666\"\n"\
1550 "            KERNEL==\"ttyS*\", MODE=\"0666\"\n\n"\
1551 "For more info, see the file LINUX_DEVICES.md in the distribution docs.\n"\
1552 );
1553 
1554 #else
1555 
1556 static const wxString BAD_ACCESS_MSG = _( R"(
1557 The device selected is not accessible; opencpn will likely not be able
1558 to use this device as-is. You might want to exit OpenCPN, reboot and
1559 retry after creating a file called /etc/udev/rules.d/70-opencpn.rules
1560 with the following contents:
1561 
1562             KERNEL=="ttyUSB*", MODE="0666"
1563             KERNEL=="ttyACM*", MODE="0666"
1564             KERNEL=="ttyS*", MODE="0666"
1565 
1566 For more info, see the file LINUX_DEVICES.md in the distribution docs.
1567 )" );
1568 
1569 #endif  // defined(__GNUC__) && __GNUC__ < 8
1570 
CheckDeviceAccess(wxString & path)1571 void options::CheckDeviceAccess( /*[[maybe_unused]]*/ wxString &path) {
1572    // Microsoft compiler 19.14.26433 requires rightfully std=c++-17 for this.
1573 
1574 #ifdef __OCPN__ANDROID__
1575    return;
1576 #endif
1577 
1578 #ifndef __linux__
1579    return;
1580 #else
1581    if(path.IsEmpty())
1582        return;
1583    int r = access(path.mb_str(), R_OK | W_OK);
1584    if (r == 0)
1585       return;
1586   OCPNMessageBox (this, BAD_ACCESS_MSG, wxString( _("OpenCPN Warning") ),
1587 		  wxICON_WARNING | wxOK, 60 );
1588 #endif
1589 
1590 }
1591 
CreatePanel(const wxString & title)1592 size_t options::CreatePanel(const wxString& title) {
1593   size_t id = m_pListbook->GetPageCount();
1594   /* This is the default empty content for any top tab.
1595      It'll be replaced when we call AddPage */
1596   wxPanel* panel = new wxPanel(m_pListbook, wxID_ANY, wxDefaultPosition,
1597                                wxDefaultSize, wxTAB_TRAVERSAL, title);
1598   m_pListbook->AddPage(panel, title, FALSE, id);
1599   return id;
1600 }
1601 
AddPage(size_t parent,const wxString & title)1602 wxScrolledWindow* options::AddPage(size_t parent, const wxString& title) {
1603   if (parent > m_pListbook->GetPageCount() - 1) {
1604     wxLogMessage(
1605         wxString::Format(
1606             _T("Warning: invalid parent in options::AddPage( %d, "), parent) +
1607         title + _T(" )"));
1608     return NULL;
1609   }
1610   wxNotebookPage* page = m_pListbook->GetPage(parent);
1611   wxNotebook* nb;
1612   wxScrolledWindow* sw;
1613 
1614   int style = wxVSCROLL | wxTAB_TRAVERSAL;
1615   if ((nb = dynamic_cast<wxNotebook*>(page))) {
1616     sw = new wxScrolledWindow(page, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1617                               style);
1618     sw->SetScrollRate(m_scrollRate, m_scrollRate);
1619     nb->AddPage(sw, title);
1620   } else if ((sw = dynamic_cast<wxScrolledWindow*>(page))) {
1621     wxString toptitle = m_pListbook->GetPageText(parent);
1622     wxNotebook* nb = new wxNotebook(m_pListbook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
1623     /* Only remove the tab from listbook, we still have original content in
1624      * {page} */
1625     m_pListbook->InsertPage(parent, nb, toptitle, FALSE, parent);
1626     m_pListbook->RemovePage(parent + 1);
1627     wxString previoustitle = page->GetName();
1628     page->Reparent(nb);
1629     nb->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler(options::OnSubNBPageChange), NULL,  this);
1630 
1631     nb->AddPage(page, previoustitle);
1632     /* wxNotebookPage is hidden under wxGTK after RemovePage/Reparent
1633      * we must explicitely Show() it */
1634     page->Show();
1635     sw = new wxScrolledWindow(nb, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1636                               style);
1637     sw->SetScrollRate(m_scrollRate, m_scrollRate);
1638     nb->AddPage(sw, title);
1639     nb->ChangeSelection(0);
1640   } else {  // This is the default content, we can replace it now
1641     sw = new wxScrolledWindow(m_pListbook, wxID_ANY, wxDefaultPosition,
1642                               wxDefaultSize, style, title);
1643     sw->SetScrollRate(m_scrollRate, m_scrollRate);
1644     wxString toptitle = m_pListbook->GetPageText(parent);
1645     m_pListbook->InsertPage(parent, sw, toptitle, FALSE, parent);
1646     m_pListbook->DeletePage(parent + 1);
1647   }
1648 
1649 #ifdef __OCPN__ANDROID__
1650     sw->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
1651 #endif
1652 
1653   return sw;
1654 }
1655 
DeletePluginPage(wxScrolledWindow * page)1656 bool options::DeletePluginPage(wxScrolledWindow* page) {
1657   for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
1658     wxNotebookPage* pg = m_pListbook->GetPage(i);
1659     wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
1660 
1661     if (nb) {
1662       for (size_t j = 0; j < nb->GetPageCount(); j++) {
1663         wxNotebookPage* spg = nb->GetPage(j);
1664         if (spg == page){
1665             nb->DeletePage(j);
1666             if (nb->GetPageCount() != 1)
1667                 return TRUE;
1668             /* There's only one page, remove inner notebook */
1669             spg = nb->GetPage(0);
1670             spg->Reparent(m_pListbook);
1671             nb->RemovePage(0);
1672             wxString toptitle = m_pListbook->GetPageText(i);
1673             m_pListbook->DeletePage(i);
1674             m_pListbook->InsertPage(i, spg, toptitle, FALSE, i);
1675             return TRUE;
1676         }
1677       }
1678     } else if (pg == page) {
1679       /* There's only one page, replace it with empty panel */
1680       m_pListbook->DeletePage(i);
1681       wxPanel* panel = new wxPanel(m_pListbook);
1682       wxString toptitle = m_pListbook->GetPageText(i);
1683       m_pListbook->InsertPage(i, panel, toptitle, FALSE, i);
1684       return TRUE;
1685     }
1686   }
1687   return FALSE;
1688 }
1689 
CreatePanel_NMEA_Compact(size_t parent,int border_size,int group_item_spacing)1690 void options::CreatePanel_NMEA_Compact(size_t parent, int border_size,
1691                                        int group_item_spacing) {
1692   m_pNMEAForm = AddPage(parent, _("NMEA"));
1693 
1694   wxBoxSizer* bSizer4 = new wxBoxSizer(wxVERTICAL);
1695   m_pNMEAForm->SetSizer(bSizer4);
1696   m_pNMEAForm->SetSizeHints(wxDefaultSize, wxDefaultSize);
1697 
1698   wxBoxSizer* bSizerOuterContainer = new wxBoxSizer(wxVERTICAL);
1699 
1700   wxStaticBoxSizer* sbSizerGeneral;
1701   sbSizerGeneral = new wxStaticBoxSizer(
1702       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("General")), wxVERTICAL);
1703 
1704   wxBoxSizer* bSizer151;
1705   bSizer151 = new wxBoxSizer(wxVERTICAL);
1706 
1707   wxBoxSizer* bSizer161;
1708   bSizer161 = new wxBoxSizer(wxVERTICAL);
1709 
1710   m_cbFilterSogCog =
1711       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Filter NMEA COG/SOG"),
1712                      wxDefaultPosition, wxDefaultSize, 0);
1713   m_cbFilterSogCog->SetValue(g_bfilter_cogsog);
1714   bSizer161->Add(m_cbFilterSogCog, 0, wxALL, 5);
1715 
1716   wxFlexGridSizer* bSizer171 = new wxFlexGridSizer(0, 2, 0, 0);
1717   bSizer171->SetFlexibleDirection(wxBOTH);
1718   bSizer171->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
1719 
1720   m_stFilterSec =
1721       new wxStaticText(m_pNMEAForm, wxID_ANY, _("Filter period (sec)"),
1722                        wxDefaultPosition, wxDefaultSize, 0);
1723   // m_stFilterSec->Wrap( -1 );
1724 
1725   int nspace = 5;
1726 #ifdef __WXGTK__
1727   nspace = 9;
1728 #endif
1729   bSizer171->Add(m_stFilterSec, 1, wxALL, nspace);
1730 
1731   m_tFilterSec = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
1732                                 wxDefaultPosition, wxSize(100, -1), 0);
1733   wxString sfilt;
1734   sfilt.Printf(_T( "%d" ), g_COGFilterSec);
1735   m_tFilterSec->SetValue(sfilt);
1736   bSizer171->Add(m_tFilterSec, 1, wxALL, 4);
1737 
1738   bSizer161->Add(bSizer171, 1, wxEXPAND, 5);
1739 
1740   int cb_space = 2;
1741   m_cbNMEADebug =
1742       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Show NMEA Debug Window"),
1743                      wxDefaultPosition, wxDefaultSize, 0);
1744   m_cbNMEADebug->SetValue(NMEALogWindow::Get().Active());
1745   bSizer161->Add(m_cbNMEADebug, 0, wxALL, cb_space);
1746 
1747   m_cbFurunoGP3X =
1748       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Use Furuno GP3X for uploads"),
1749                      wxDefaultPosition, wxDefaultSize, 0);
1750   m_cbFurunoGP3X->SetValue(g_GPS_Ident == _T( "FurunoGP3X" ));
1751   bSizer161->Add(m_cbFurunoGP3X, 0, wxALL, cb_space);
1752 
1753   m_cbGarminUploadHost =
1754       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Use GRMN for uploads"),
1755                      wxDefaultPosition, wxDefaultSize, 0);
1756   m_cbGarminUploadHost->SetValue(g_bGarminHostUpload);
1757   bSizer161->Add(m_cbGarminUploadHost, 0, wxALL, cb_space);
1758 
1759   m_cbAPBMagnetic =
1760       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Use magnetic bearings in output sentence ECAPB"),
1761                      wxDefaultPosition, wxDefaultSize, 0);
1762   m_cbAPBMagnetic->SetValue(g_bMagneticAPB);
1763   bSizer161->Add(m_cbAPBMagnetic, 0, wxALL, cb_space);
1764 
1765   bSizer151->Add(bSizer161, 1, wxEXPAND, 5);
1766   sbSizerGeneral->Add(bSizer151, 1, wxEXPAND, 5);
1767   bSizerOuterContainer->Add(sbSizerGeneral, 0, wxALL | wxEXPAND, 5);
1768 
1769   //  Connections listbox, etc
1770   wxStaticBoxSizer* sbSizerLB = new wxStaticBoxSizer(
1771       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Data Connections")),
1772       wxVERTICAL);
1773 
1774   wxBoxSizer* bSizer17;
1775   bSizer17 = new wxBoxSizer(wxVERTICAL);
1776 
1777   //m_lcSources = new wxListCtrl(m_pNMEAForm, wxID_ANY, wxDefaultPosition,
1778   //                             wxSize(300, m_fontHeight * 2), wxLC_REPORT | wxLC_SINGLE_SEL);
1779   //bSizer17->Add(m_lcSources, 1, wxALL | wxEXPAND, 5);
1780 
1781   wxBoxSizer* bSizer18;
1782   bSizer18 = new wxBoxSizer(wxHORIZONTAL);
1783   bSizer17->Add(bSizer18, 0, wxEXPAND, 5);
1784 
1785   m_buttonAdd = new wxButton(m_pNMEAForm, wxID_ANY, _("Add") + _T("..."),
1786                              wxDefaultPosition, wxDefaultSize, 0);
1787   bSizer18->Add(m_buttonAdd, 0, wxALL, 5);
1788 
1789   m_buttonRemove = new wxButton(m_pNMEAForm, wxID_ANY, _("Remove"),
1790                                 wxDefaultPosition, wxDefaultSize, 0);
1791   m_buttonRemove->Enable(FALSE);
1792   bSizer18->Add(m_buttonRemove, 0, wxALL, 5);
1793 
1794   sbSizerLB->Add(bSizer17, 1, wxEXPAND, 5);
1795   bSizerOuterContainer->Add(sbSizerLB, 0, wxEXPAND, 5);
1796 
1797   //  Connections Properties
1798   sbSizerConnectionProps = new wxStaticBoxSizer(
1799       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Properties")), wxVERTICAL);
1800 
1801   wxFlexGridSizer* bSizer15 = new wxFlexGridSizer(0, 2, 0, 0);
1802   bSizer15->SetFlexibleDirection(wxBOTH);
1803   bSizer15->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
1804 
1805   sbSizerConnectionProps->Add(bSizer15, 0, wxEXPAND, 0);
1806 
1807   m_rbTypeSerial =
1808       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Serial"), wxDefaultPosition,
1809                         wxDefaultSize, wxRB_GROUP);
1810   m_rbTypeSerial->SetValue(TRUE);
1811   bSizer15->Add(m_rbTypeSerial, 0, wxALL, 5);
1812 
1813   m_rbTypeNet = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Network"),
1814                                   wxDefaultPosition, wxDefaultSize, 0);
1815   bSizer15->Add(m_rbTypeNet, 0, wxALL, 5);
1816 
1817   if (OCPNPlatform::hasInternalGPS()) {
1818     m_rbTypeInternalGPS =
1819         new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Built-in GPS"),
1820                           wxDefaultPosition, wxDefaultSize, 0);
1821     bSizer15->Add(m_rbTypeInternalGPS, 0, wxALL, 5);
1822   } else
1823     m_rbTypeInternalGPS = NULL;
1824 
1825   // has built-in Bluetooth
1826   if (OCPNPlatform::hasInternalBT()) {
1827     m_rbTypeInternalBT =
1828         new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Built-in Bluetooth"),
1829                           wxDefaultPosition, wxDefaultSize, 0);
1830     bSizer15->Add(m_rbTypeInternalBT, 0, wxALL, 5);
1831 
1832     m_buttonScanBT = new wxButton(m_pNMEAForm, wxID_ANY, _("BT Scan") + _T("..."),
1833                                   wxDefaultPosition, wxDefaultSize);
1834     m_buttonScanBT->Hide();
1835     sbSizerConnectionProps->Add(m_buttonScanBT, 0, wxALL, 5);
1836 
1837     wxBoxSizer* bSizer15a = new wxBoxSizer(wxHORIZONTAL);
1838     sbSizerConnectionProps->Add(bSizer15a, 0, wxEXPAND, 5);
1839 
1840     m_stBTPairs = new wxStaticText(m_pNMEAForm, wxID_ANY, _("BT Sources"),
1841                                    wxDefaultPosition, wxDefaultSize, 0);
1842     // m_stBTPairs->Wrap( -1 );
1843     // m_stBTPairs->Hide();
1844     bSizer15a->Add(m_stBTPairs, 0, wxALL, 5);
1845 
1846     wxArrayString mt;
1847     mt.Add(_T( "unscanned" ));
1848     m_choiceBTDataSources = new wxChoice(m_pNMEAForm, wxID_ANY,
1849                                          wxDefaultPosition, wxDefaultSize, mt);
1850     bSizer15a->Add(m_choiceBTDataSources, 1, wxEXPAND | wxTOP, 5);
1851 
1852 #if 0
1853         m_BTscan_results.Clear();
1854         m_BTscan_results.Add(_T("None"));
1855 
1856         m_BTscan_results = g_Platform->getBluetoothScanResults();
1857         m_choiceBTDataSources->Clear();
1858         m_choiceBTDataSources->Append(m_BTscan_results[0]);  // scan status
1859 
1860         unsigned int i=1;
1861         while( (i+1) < m_BTscan_results.GetCount()){
1862             wxString item1 = m_BTscan_results[i] + _T(";");
1863             wxString item2 = m_BTscan_results.Item(i+1);
1864             m_choiceBTDataSources->Append(item1 + item2);
1865 
1866             i += 2;
1867         }
1868 
1869         if( m_BTscan_results.GetCount() > 1){
1870             m_choiceBTDataSources->SetSelection( 1 );
1871         }
1872 #endif
1873 
1874     m_choiceBTDataSources->Hide();
1875     m_buttonScanBT->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
1876                             wxCommandEventHandler(options::OnScanBTClick), NULL,
1877                             this);
1878   } else
1879     m_rbTypeInternalBT = NULL;
1880 
1881   wxBoxSizer* gSizerNetPropsV = new wxBoxSizer(wxVERTICAL);
1882   sbSizerConnectionProps->Add(gSizerNetPropsV, 0, wxEXPAND, 5);
1883 
1884   m_stNetProto = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Protocol"),
1885                                   wxDefaultPosition, wxDefaultSize, 0);
1886   // m_stNetProto->Wrap( -1 );
1887   gSizerNetPropsV->Add(m_stNetProto, 0, wxALL, 5);
1888 
1889   wxBoxSizer* bSizer16;
1890   bSizer16 = new wxBoxSizer(wxHORIZONTAL);
1891   gSizerNetPropsV->Add(bSizer16, 1, wxEXPAND, 5);
1892 
1893   m_rbNetProtoTCP =
1894       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("TCP"), wxDefaultPosition,
1895                         wxDefaultSize, wxRB_GROUP);
1896   m_rbNetProtoTCP->Enable(TRUE);
1897 
1898   bSizer16->Add(m_rbNetProtoTCP, 0, wxALL, 5);
1899 
1900   m_rbNetProtoUDP = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("UDP"),
1901                                       wxDefaultPosition, wxDefaultSize, 0);
1902   m_rbNetProtoUDP->Enable(TRUE);
1903 
1904   bSizer16->Add(m_rbNetProtoUDP, 0, wxALL, 5);
1905 
1906   m_rbNetProtoGPSD = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("GPSD"),
1907                                        wxDefaultPosition, wxDefaultSize, 0);
1908   m_rbNetProtoGPSD->SetValue(TRUE);
1909   bSizer16->Add(m_rbNetProtoGPSD, 0, wxALL, 5);
1910 
1911   m_rbNetProtoSignalK = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Signal K"),
1912                                        wxDefaultPosition, wxDefaultSize, 0);
1913   m_rbNetProtoSignalK->Enable(TRUE);
1914   bSizer16->Add(m_rbNetProtoSignalK, 0, wxALL, 5);
1915 
1916   wxFlexGridSizer* fgSizer1a = new wxFlexGridSizer(0, 2, 0, 0);
1917   fgSizer1a->SetFlexibleDirection(wxBOTH);
1918   fgSizer1a->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
1919   gSizerNetPropsV->Add(fgSizer1a, 0, wxEXPAND, 5);
1920 
1921   m_stNetAddr = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Address"),
1922                                  wxDefaultPosition, wxDefaultSize, 0);
1923   fgSizer1a->Add(m_stNetAddr, 0, wxALL, 5);
1924 
1925   m_tNetAddress = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
1926                                  wxDefaultPosition, wxSize(m_fontHeight * 4, -1), 0);
1927   fgSizer1a->Add(m_tNetAddress, 1, wxTOP | wxALIGN_RIGHT, 5);
1928 
1929   m_stNetPort = new wxStaticText(m_pNMEAForm, wxID_ANY, _("DataPort"),
1930                                  wxDefaultPosition, wxDefaultSize, 0);
1931   fgSizer1a->Add(m_stNetPort, 1, wxALL, 5);
1932 
1933   m_tNetPort = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
1934                               wxDefaultPosition, wxSize(200, -1), 0);
1935   fgSizer1a->Add(m_tNetPort, 1, wxTOP | wxALIGN_RIGHT, 5);
1936 
1937   gSizerSerProps = new wxGridSizer(0, 1, 0, 0);
1938 
1939   wxFlexGridSizer* fgSizer1 = new wxFlexGridSizer(0, 2, 0, 0);
1940   fgSizer1->SetFlexibleDirection(wxBOTH);
1941   fgSizer1->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
1942   gSizerSerProps->Add(fgSizer1, 0, wxEXPAND, 5);
1943 
1944   m_stSerPort = new wxStaticText(m_pNMEAForm, wxID_ANY, _("DataPort"),
1945                                  wxDefaultPosition, wxDefaultSize, 0);
1946   // m_stSerPort->Wrap( -1 );
1947   fgSizer1->Add(m_stSerPort, 0, wxALL, 5);
1948 
1949   m_comboPort = new wxComboBox(m_pNMEAForm, wxID_ANY, wxEmptyString,
1950                                wxDefaultPosition, wxDefaultSize, 0, NULL, 0);
1951   fgSizer1->Add(m_comboPort, 0, wxEXPAND | wxTOP, 5);
1952 
1953   m_stSerBaudrate = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Baudrate"),
1954                                      wxDefaultPosition, wxDefaultSize, 0);
1955   // m_stSerBaudrate->Wrap( -1 );
1956   fgSizer1->Add(m_stSerBaudrate, 0, wxALL, 5);
1957 
1958   wxString m_choiceBaudRateChoices[] = {
1959       _("150"),    _("300"),    _("600"),    _("1200"),  _("2400"),
1960       _("4800"),   _("9600"),   _("19200"),  _("38400"), _("57600"),
1961       _("115200"), _("230400"), _("460800"), _("921600")};
1962   int m_choiceBaudRateNChoices =
1963       sizeof(m_choiceBaudRateChoices) / sizeof(wxString);
1964   m_choiceBaudRate =
1965       new wxChoice(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1966                    m_choiceBaudRateNChoices, m_choiceBaudRateChoices, 0);
1967   m_choiceBaudRate->SetSelection(0);
1968   fgSizer1->Add(m_choiceBaudRate, 1, wxEXPAND | wxTOP, 5);
1969 
1970   m_stSerProtocol = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Protocol"),
1971                                      wxDefaultPosition, wxDefaultSize, 0);
1972   // m_stSerProtocol->Wrap( -1 );
1973   fgSizer1->Add(m_stSerProtocol, 0, wxALL, 5);
1974 
1975   wxString m_choiceSerialProtocolChoices[] = {_("NMEA 0183"), _("NMEA 2000"),
1976                                               _("Seatalk")};
1977   int m_choiceSerialProtocolNChoices =
1978       sizeof(m_choiceSerialProtocolChoices) / sizeof(wxString);
1979   m_choiceSerialProtocol = new wxChoice(
1980       m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1981       m_choiceSerialProtocolNChoices, m_choiceSerialProtocolChoices, 0);
1982   m_choiceSerialProtocol->SetSelection(0);
1983   m_choiceSerialProtocol->Enable(FALSE);
1984 
1985   fgSizer1->Add(m_choiceSerialProtocol, 1, wxEXPAND | wxTOP, 5);
1986   m_stPriority = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Priority"),
1987                                   wxDefaultPosition, wxDefaultSize, 0);
1988   // m_stPriority->Wrap( -1 );
1989   fgSizer1->Add(m_stPriority, 0, wxALL, 5);
1990 
1991   wxString m_choicePriorityChoices[] = {_("0"), _("1"), _("2"), _("3"), _("4"),
1992                                         _("5"), _("6"), _("7"), _("8"), _("9")};
1993   int m_choicePriorityNChoices =
1994       sizeof(m_choicePriorityChoices) / sizeof(wxString);
1995   m_choicePriority =
1996       new wxChoice(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1997                    m_choicePriorityNChoices, m_choicePriorityChoices, 0);
1998   m_choicePriority->SetSelection(9);
1999   fgSizer1->Add(m_choicePriority, 0, wxEXPAND | wxTOP, 5);
2000 
2001   wxBoxSizer* fgSizer5 = new wxBoxSizer(wxVERTICAL);
2002 
2003   m_cbCheckCRC = new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Control checksum"),
2004                                 wxDefaultPosition, wxDefaultSize, 0);
2005   m_cbCheckCRC->SetValue(TRUE);
2006   m_cbCheckCRC->SetToolTip(
2007       _("If checked, only the sentences with a valid checksum are passed through"));
2008   fgSizer5->Add(m_cbCheckCRC, 0, wxALL, 5);
2009 
2010   m_cbGarminHost =
2011       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Use GRMN mode for input"),
2012                      wxDefaultPosition, wxDefaultSize, 0);
2013   m_cbGarminHost->SetValue(FALSE);
2014   fgSizer5->Add(m_cbGarminHost, 0, wxALL, 5);
2015 #ifndef USE_GARMINHOST
2016 // m_cbGarminHost->Hide();
2017 #endif
2018 
2019   m_cbInput =
2020       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Receive Input on this Port"),
2021                      wxDefaultPosition, wxDefaultSize, 0);
2022   fgSizer5->Add(m_cbInput, 0, wxALL, 5);
2023 
2024   m_cbOutput = new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Output on this port"),
2025                               wxDefaultPosition, wxDefaultSize, 0);
2026   fgSizer5->Add(m_cbOutput, 0, wxALL, 5);
2027 
2028   wxFlexGridSizer* fgSizer5a = new wxFlexGridSizer(0, 2, 0, 0);
2029   fgSizer5a->SetFlexibleDirection(wxBOTH);
2030   fgSizer5a->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
2031 
2032   m_stTalkerIdText = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Talker ID"),
2033                                       wxDefaultPosition, wxDefaultSize, 0);
2034   // m_stTalkerIdText->Wrap( -1 );
2035   fgSizer5a->Add(m_stTalkerIdText, 0, wxALL, 5);
2036 
2037   m_TalkerIdText = new wxTextCtrl(m_pNMEAForm, ID_OPTEXTCTRL, _T(""),
2038                                   wxDefaultPosition, wxSize(50, -1), 0);
2039   m_TalkerIdText->SetMaxLength(2);
2040   fgSizer5a->Add(m_TalkerIdText, 0, wxALIGN_LEFT | wxALL, group_item_spacing);
2041 
2042   m_stPrecision =
2043       new wxStaticText(m_pNMEAForm, wxID_ANY, _("APB bearing precision"),
2044                        wxDefaultPosition, wxDefaultSize, 0);
2045 
2046   // m_stPrecision->Wrap( -1 );
2047   fgSizer5a->Add(m_stPrecision, 0, wxALL, 5);
2048 
2049   wxString m_choicePrecisionChoices[] = {_T("x"), _T("x.x"), _T("x.xx"),
2050                                          _T("x.xxx"), _T("x.xxxx")};
2051   int m_choicePrecisionNChoices =
2052       sizeof(m_choicePrecisionChoices) / sizeof(wxString);
2053   m_choicePrecision =
2054       new wxChoice(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2055                    m_choicePrecisionNChoices, m_choicePrecisionChoices, 0);
2056   m_choicePrecision->SetSelection(g_NMEAAPBPrecision);
2057   fgSizer5a->Add(m_choicePrecision, 0, wxALL, 5);
2058 
2059   sbSizerConnectionProps->Add(gSizerSerProps, 0, wxEXPAND, 5);
2060   sbSizerConnectionProps->Add(fgSizer5, 0, wxEXPAND, 5);
2061   sbSizerConnectionProps->Add(fgSizer5a, 0, wxEXPAND, 5);
2062 
2063   sbSizerInFilter = new wxStaticBoxSizer(
2064       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Input filtering")), wxVERTICAL);
2065 
2066   wxBoxSizer* bSizer9;
2067   bSizer9 = new wxBoxSizer(wxVERTICAL);
2068 
2069   m_rbIAccept =
2070       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Accept only sentences"),
2071                         wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
2072   bSizer9->Add(m_rbIAccept, 0, wxALL, 5);
2073 
2074   m_rbIIgnore = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Ignore sentences"),
2075                                   wxDefaultPosition, wxDefaultSize, 0);
2076   bSizer9->Add(m_rbIIgnore, 0, wxALL, 5);
2077 
2078   sbSizerInFilter->Add(bSizer9, 0, wxEXPAND, 5);
2079 
2080   wxBoxSizer* bSizer11;
2081   bSizer11 = new wxBoxSizer(wxHORIZONTAL);
2082 
2083   m_tcInputStc =
2084       new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString, wxDefaultPosition,
2085                      wxSize(-1, -1), wxTE_READONLY);
2086   bSizer11->Add(m_tcInputStc, 1, wxALL, 5);
2087 
2088   m_btnInputStcList =
2089       new wxButton(m_pNMEAForm, wxID_ANY, _T("..."), wxDefaultPosition,
2090                    wxDefaultSize, wxBU_EXACTFIT);
2091   bSizer11->Add(m_btnInputStcList, 0, wxALL, 5);
2092 
2093   sbSizerInFilter->Add(bSizer11, 0, wxEXPAND, 5);
2094   sbSizerConnectionProps->Add(sbSizerInFilter, 0, wxEXPAND, 5);
2095 
2096   sbSizerOutFilter = new wxStaticBoxSizer(
2097       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Output filtering")),
2098       wxVERTICAL);
2099 
2100   wxBoxSizer* bSizer10;
2101   bSizer10 = new wxBoxSizer(wxVERTICAL);
2102 
2103   m_rbOAccept =
2104       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Transmit sentences"),
2105                         wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
2106   bSizer10->Add(m_rbOAccept, 0, wxALL, 5);
2107 
2108   m_rbOIgnore = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Drop sentences"),
2109                                   wxDefaultPosition, wxDefaultSize, 0);
2110   bSizer10->Add(m_rbOIgnore, 0, wxALL, 5);
2111 
2112   sbSizerOutFilter->Add(bSizer10, 0, wxEXPAND, 5);
2113 
2114   wxBoxSizer* bSizer12;
2115   bSizer12 = new wxBoxSizer(wxHORIZONTAL);
2116 
2117   m_tcOutputStc =
2118       new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString, wxDefaultPosition,
2119                      wxSize(-1, -1), wxTE_READONLY);
2120   bSizer12->Add(m_tcOutputStc, 1, wxALL, 5);
2121 
2122   m_btnOutputStcList =
2123       new wxButton(m_pNMEAForm, wxID_ANY, _T("..."), wxDefaultPosition,
2124                    wxDefaultSize, wxBU_EXACTFIT);
2125   bSizer12->Add(m_btnOutputStcList, 0, wxALL, 5);
2126 
2127   sbSizerOutFilter->Add(bSizer12, 0, wxEXPAND, 5);
2128   sbSizerConnectionProps->Add(sbSizerOutFilter, 0, wxEXPAND, 5);
2129 
2130   bSizerOuterContainer->Add(sbSizerConnectionProps, 1, wxALL | wxEXPAND, 5);
2131 
2132   bSizer4->Add(bSizerOuterContainer, 1, wxEXPAND, 5);
2133 
2134   // Connect Events
2135 //   m_lcSources->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED,
2136 //                        wxListEventHandler(options::OnSelectDatasource), NULL,
2137 //                        this);
2138   m_buttonAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2139                        wxCommandEventHandler(options::OnAddDatasourceClick),
2140                        NULL, this);
2141   m_buttonRemove->Connect(
2142       wxEVT_COMMAND_BUTTON_CLICKED,
2143       wxCommandEventHandler(options::OnRemoveDatasourceClick), NULL, this);
2144 
2145   m_rbTypeSerial->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2146                           wxCommandEventHandler(options::OnTypeSerialSelected),
2147                           NULL, this);
2148   m_rbTypeNet->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2149                        wxCommandEventHandler(options::OnTypeNetSelected), NULL,
2150                        this);
2151 
2152   if (m_rbTypeInternalGPS)
2153     m_rbTypeInternalGPS->Connect(
2154         wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2155         wxCommandEventHandler(options::OnTypeGPSSelected), NULL, this);
2156   if (m_rbTypeInternalBT)
2157     m_rbTypeInternalBT->Connect(
2158         wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2159         wxCommandEventHandler(options::OnTypeBTSelected), NULL, this);
2160 
2161   m_rbNetProtoTCP->Connect(
2162       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2163       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2164   m_rbNetProtoUDP->Connect(
2165       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2166       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2167   m_rbNetProtoGPSD->Connect(
2168       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2169       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2170   m_rbNetProtoSignalK->Connect(
2171       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2172       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2173   m_tNetAddress->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2174                          wxCommandEventHandler(options::OnConnValChange), NULL,
2175                          this);
2176   m_tNetPort->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2177                       wxCommandEventHandler(options::OnConnValChange), NULL,
2178                       this);
2179   m_comboPort->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
2180                        wxCommandEventHandler(options::OnConnValChange), NULL,
2181                        this);
2182   m_comboPort->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2183                        wxCommandEventHandler(options::OnConnValChange), NULL,
2184                        this);
2185   m_choiceBaudRate->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
2186                             wxCommandEventHandler(options::OnBaudrateChoice),
2187                             NULL, this);
2188   m_choiceSerialProtocol->Connect(
2189       wxEVT_COMMAND_CHOICE_SELECTED,
2190       wxCommandEventHandler(options::OnProtocolChoice), NULL, this);
2191   m_choicePriority->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
2192                             wxCommandEventHandler(options::OnConnValChange),
2193                             NULL, this);
2194   m_cbCheckCRC->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2195                         wxCommandEventHandler(options::OnCrcCheck), NULL, this);
2196   m_cbGarminHost->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2197                           wxCommandEventHandler(options::OnUploadFormatChange),
2198                           NULL, this);
2199   m_cbGarminUploadHost->Connect(
2200       wxEVT_COMMAND_CHECKBOX_CLICKED,
2201       wxCommandEventHandler(options::OnUploadFormatChange), NULL, this);
2202   m_cbFurunoGP3X->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2203                           wxCommandEventHandler(options::OnUploadFormatChange),
2204                           NULL, this);
2205   m_rbIAccept->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2206                        wxCommandEventHandler(options::OnRbAcceptInput), NULL,
2207                        this);
2208   m_rbIIgnore->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2209                        wxCommandEventHandler(options::OnRbIgnoreInput), NULL,
2210                        this);
2211   m_tcInputStc->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2212                         wxCommandEventHandler(options::OnConnValChange), NULL,
2213                         this);
2214   m_btnInputStcList->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2215                              wxCommandEventHandler(options::OnBtnIStcs), NULL,
2216                              this);
2217   m_cbInput->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2218                      wxCommandEventHandler(options::OnCbInput), NULL, this);
2219   m_cbOutput->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2220                       wxCommandEventHandler(options::OnCbOutput), NULL, this);
2221   m_rbOAccept->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2222                        wxCommandEventHandler(options::OnRbOutput), NULL, this);
2223   m_rbOIgnore->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2224                        wxCommandEventHandler(options::OnRbOutput), NULL, this);
2225   m_tcOutputStc->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2226                          wxCommandEventHandler(options::OnConnValChange), NULL,
2227                          this);
2228   m_btnOutputStcList->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2229                               wxCommandEventHandler(options::OnBtnOStcs), NULL,
2230                               this);
2231   m_cbCheckCRC->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2232                       wxCommandEventHandler(options::OnConnValChange), NULL, this);
2233   pOpenGL->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2234                    wxCommandEventHandler(options::OnGLClicked), NULL, this);
2235 
2236   m_cbNMEADebug->Connect(
2237       wxEVT_COMMAND_CHECKBOX_CLICKED,
2238       wxCommandEventHandler(options::OnShowGpsWindowCheckboxClick), NULL, this);
2239   m_cbFilterSogCog->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2240                             wxCommandEventHandler(options::OnValChange), NULL,
2241                             this);
2242   m_tFilterSec->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2243                         wxCommandEventHandler(options::OnValChange), NULL,
2244                         this);
2245   m_cbAPBMagnetic->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2246                            wxCommandEventHandler(options::OnValChange), NULL,
2247                            this);
2248 
2249 #if 0
2250   m_lcSources->Connect(wxEVT_LEFT_DOWN,
2251                        wxMouseEventHandler(options::OnConnectionToggleEnableMouse),
2252                        NULL, this);
2253 #if wxCHECK_VERSION(2, 9, 0)
2254     m_lcSources->Connect(wxEVT_LIST_ITEM_ACTIVATED,
2255                        wxListEventHandler(options::OnConnectionToggleEnable),
2256                        NULL, this);
2257 #endif
2258 
2259   wxString columns[] = {_("On"),   _("Type"), _("Data Port"),   _("Prio"),
2260                         _("Parm"), _("I/O"),  _("Filters")};
2261   for (int i = 0; i < 7; ++i) {
2262     wxListItem col;
2263     col.SetId(i);
2264     col.SetText(columns[i]);
2265     m_lcSources->InsertColumn(i, col);
2266   }
2267 
2268   //  Build the image list
2269   wxImageList* imglist = new wxImageList(16, 16, TRUE, 1);
2270   wxBitmap unchecked_bmp(16, 16), checked_bmp(16, 16);
2271   wxMemoryDC renderer_dc;
2272 
2273   // Unchecked
2274   renderer_dc.SelectObject(unchecked_bmp);
2275   renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(
2276       GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
2277   renderer_dc.Clear();
2278   wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, 16, 16),
2279                                        0);
2280 
2281   // Checked
2282   renderer_dc.SelectObject(checked_bmp);
2283   renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(
2284       GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
2285   renderer_dc.Clear();
2286   wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, 16, 16),
2287                                        wxCONTROL_CHECKED);
2288 
2289   // Deselect the renderer Object
2290   renderer_dc.SelectObject(wxNullBitmap);
2291 
2292   imglist->Add(unchecked_bmp);
2293   imglist->Add(checked_bmp);
2294   m_lcSources->AssignImageList(imglist, wxIMAGE_LIST_SMALL);
2295 
2296   m_lcSources->Refresh();
2297 #endif
2298   FillSourceList();
2299 
2300   ShowNMEACommon(FALSE);
2301   ShowNMEASerial(FALSE);
2302   ShowNMEANet(FALSE);
2303   connectionsaved = TRUE;
2304 }
2305 
CreatePanel_NMEA(size_t parent,int border_size,int group_item_spacing)2306 void options::CreatePanel_NMEA(size_t parent, int border_size,
2307                                int group_item_spacing) {
2308   m_pNMEAForm = AddPage(parent, _("NMEA"));
2309 
2310   wxBoxSizer* bSizer4 = new wxBoxSizer(wxVERTICAL);
2311   m_pNMEAForm->SetSizer(bSizer4);
2312   m_pNMEAForm->SetSizeHints(wxDefaultSize, wxDefaultSize);
2313 
2314   wxBoxSizer* bSizerOuterContainer = new wxBoxSizer(wxVERTICAL);
2315 
2316   wxStaticBoxSizer* sbSizerGeneral;
2317   sbSizerGeneral = new wxStaticBoxSizer(
2318       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("General")), wxVERTICAL);
2319 
2320   wxBoxSizer* bSizer151;
2321   bSizer151 = new wxBoxSizer(wxVERTICAL);
2322 
2323   wxBoxSizer* bSizer161;
2324   bSizer161 = new wxBoxSizer(wxVERTICAL);
2325 
2326   wxBoxSizer* bSizer171;
2327   bSizer171 = new wxBoxSizer(wxHORIZONTAL);
2328 
2329   m_cbFilterSogCog = new wxCheckBox(m_pNMEAForm, wxID_ANY,
2330                                     _("Filter NMEA Course and Speed data"),
2331                                     wxDefaultPosition, wxDefaultSize, 0);
2332   m_cbFilterSogCog->SetValue(g_bfilter_cogsog);
2333   bSizer171->Add(m_cbFilterSogCog, 0, wxALL, 5);
2334 
2335   m_stFilterSec =
2336       new wxStaticText(m_pNMEAForm, wxID_ANY, _("Filter period (sec)"),
2337                        wxDefaultPosition, wxDefaultSize, 0);
2338   m_stFilterSec->Wrap(-1);
2339 
2340   int nspace = 5;
2341 #ifdef __WXGTK__
2342   nspace = 9;
2343 #endif
2344   bSizer171->Add(m_stFilterSec, 0, wxALL, nspace);
2345 
2346   m_tFilterSec = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
2347                                 wxDefaultPosition, wxDefaultSize, 0);
2348   wxString sfilt;
2349   sfilt.Printf(_T("%d"), g_COGFilterSec);
2350   m_tFilterSec->SetValue(sfilt);
2351   bSizer171->Add(m_tFilterSec, 0, wxALL, 4);
2352   bSizer161->Add(bSizer171, 1, wxEXPAND, 5);
2353 
2354   int cb_space = 2;
2355   m_cbNMEADebug =
2356       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Show NMEA Debug Window"),
2357                      wxDefaultPosition, wxDefaultSize, 0);
2358   m_cbNMEADebug->SetValue(NMEALogWindow::Get().Active());
2359   bSizer161->Add(m_cbNMEADebug, 0, wxALL, cb_space);
2360 
2361   m_cbFurunoGP3X =
2362       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Format uploads for Furuno GP3X"),
2363                      wxDefaultPosition, wxDefaultSize, 0);
2364   m_cbFurunoGP3X->SetValue(g_GPS_Ident == _T( "FurunoGP3X" ));
2365   bSizer161->Add(m_cbFurunoGP3X, 0, wxALL, cb_space);
2366 
2367   m_cbGarminUploadHost = new wxCheckBox(
2368       m_pNMEAForm, wxID_ANY, _("Use Garmin GRMN (Host) mode for uploads"),
2369       wxDefaultPosition, wxDefaultSize, 0);
2370   m_cbGarminUploadHost->SetValue(g_bGarminHostUpload);
2371   bSizer161->Add(m_cbGarminUploadHost, 0, wxALL, cb_space);
2372 
2373   m_cbAPBMagnetic =
2374       new wxCheckBox(m_pNMEAForm, wxID_ANY,
2375                      _("Use magnetic bearings in output sentence ECAPB"),
2376                      wxDefaultPosition, wxDefaultSize, 0);
2377   m_cbAPBMagnetic->SetValue(g_bMagneticAPB);
2378   bSizer161->Add(m_cbAPBMagnetic, 0, wxALL, cb_space);
2379 
2380   bSizer151->Add(bSizer161, 1, wxEXPAND, 5);
2381   sbSizerGeneral->Add(bSizer151, 1, wxEXPAND, 5);
2382   bSizerOuterContainer->Add(sbSizerGeneral, 0, wxALL | wxEXPAND, 5);
2383 
2384   //  Connections listbox, etc
2385   wxStaticBoxSizer* sbSizerLB = new wxStaticBoxSizer(
2386       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Data Connections")),
2387       wxVERTICAL);
2388 
2389 
2390 
2391 /*
2392   wxBoxSizer* bSizer17;
2393   bSizer17 = new wxBoxSizer(wxVERTICAL);
2394 
2395   m_lcSources = new wxListCtrl(m_pNMEAForm, wxID_ANY, wxDefaultPosition,
2396                                wxSize(-1, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
2397   bSizer17->Add(m_lcSources, 1, wxALL | wxEXPAND, 5);
2398 */
2399 
2400   wxPanel *cPanel = new wxPanel(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1,-1)), wxBG_STYLE_ERASE );
2401   sbSizerLB->Add(cPanel, 0, wxALL|wxEXPAND, 5);
2402 
2403   wxBoxSizer *boxSizercPanel = new wxBoxSizer(wxVERTICAL);
2404   cPanel->SetSizer(boxSizercPanel);
2405 
2406   m_scrollWinConnections = new wxScrolledWindow(cPanel, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1,80)), wxBORDER_RAISED | wxVSCROLL | wxBG_STYLE_ERASE );
2407   m_scrollWinConnections->SetScrollRate(5, 5);
2408   boxSizercPanel->Add(m_scrollWinConnections, 0, wxALL|wxEXPAND, 5);
2409 
2410   boxSizerConnections = new wxBoxSizer(wxVERTICAL);
2411   m_scrollWinConnections->SetSizer(boxSizerConnections);
2412 
2413 
2414   bSizerOuterContainer->Add(sbSizerLB, 0, wxEXPAND, 5);
2415 
2416 
2417   wxBoxSizer* bSizer18;
2418   bSizer18 = new wxBoxSizer(wxHORIZONTAL);
2419   sbSizerLB->Add(bSizer18, 1, wxEXPAND, 5);
2420 
2421   m_buttonAdd = new wxButton(m_pNMEAForm, wxID_ANY, _("Add Connection"),
2422                              wxDefaultPosition, wxDefaultSize, 0);
2423   bSizer18->Add(m_buttonAdd, 0, wxALL, 5);
2424 
2425   m_buttonRemove = new wxButton(m_pNMEAForm, wxID_ANY, _("Remove Connection"),
2426                                 wxDefaultPosition, wxDefaultSize, 0);
2427   m_buttonRemove->Enable(FALSE);
2428   bSizer18->Add(m_buttonRemove, 0, wxALL, 5);
2429 
2430 
2431 //   wxBoxSizer* bSizer19 = new wxBoxSizer(wxHORIZONTAL);
2432 //   sbSizerLB->Add(bSizer19, 1, wxEXPAND, 5);
2433 //
2434    wxFont *dFont = GetOCPNScaledFont_PlugIn(_("Dialog"));
2435    double font_size = dFont->GetPointSize() * 17/16;
2436    wxFont *bFont = wxTheFontList->FindOrCreateFont( font_size, dFont->GetFamily(), dFont->GetStyle(), wxFONTWEIGHT_BOLD);
2437 //
2438 //   m_stEditCon = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Edit Selected Connection"));
2439 //   m_stEditCon->SetFont(*bFont);
2440 //   bSizer19->Add(m_stEditCon, 0, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL, 5);
2441 //
2442 
2443   //  Connections Properties
2444   m_sbConnEdit = new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Edit Selected Connection"));
2445   m_sbConnEdit->SetFont(*bFont);
2446 
2447   sbSizerConnectionProps = new wxStaticBoxSizer( m_sbConnEdit, wxVERTICAL);
2448 
2449   wxBoxSizer* bSizer15;
2450   bSizer15 = new wxBoxSizer(wxHORIZONTAL);
2451 
2452   sbSizerConnectionProps->Add(bSizer15, 0, wxTOP | wxEXPAND, 5);
2453 
2454   m_rbTypeSerial =
2455       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Serial"), wxDefaultPosition,
2456                         wxDefaultSize, wxRB_GROUP);
2457   m_rbTypeSerial->SetValue(TRUE);
2458   bSizer15->Add(m_rbTypeSerial, 0, wxALL, 5);
2459 
2460   m_rbTypeNet = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Network"),
2461                                   wxDefaultPosition, wxDefaultSize, 0);
2462   bSizer15->Add(m_rbTypeNet, 0, wxALL, 5);
2463 
2464   if (OCPNPlatform::hasInternalGPS()) {
2465     m_rbTypeInternalGPS =
2466         new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Built-in GPS"),
2467                           wxDefaultPosition, wxDefaultSize, 0);
2468     bSizer15->Add(m_rbTypeInternalGPS, 0, wxALL, 5);
2469   } else
2470     m_rbTypeInternalGPS = NULL;
2471 
2472   // has built-in Bluetooth
2473   if (OCPNPlatform::hasInternalBT()) {
2474     m_rbTypeInternalBT =
2475         new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Built-in Bluetooth SPP"),
2476                           wxDefaultPosition, wxDefaultSize, 0);
2477     bSizer15->Add(m_rbTypeInternalBT, 0, wxALL, 5);
2478 
2479     m_buttonScanBT = new wxButton(m_pNMEAForm, wxID_ANY, _("BT Scan"),
2480                                   wxDefaultPosition, wxDefaultSize);
2481     m_buttonScanBT->Hide();
2482 
2483     wxBoxSizer* bSizer15a = new wxBoxSizer(wxHORIZONTAL);
2484     sbSizerConnectionProps->Add(bSizer15a, 0, wxEXPAND, 5);
2485 
2486     bSizer15a->Add(m_buttonScanBT, 0, wxALL, 5);
2487 
2488     m_stBTPairs =
2489         new wxStaticText(m_pNMEAForm, wxID_ANY, _("Bluetooth Data Sources"),
2490                          wxDefaultPosition, wxDefaultSize, 0);
2491     m_stBTPairs->Wrap(-1);
2492     m_stBTPairs->Hide();
2493     bSizer15a->Add(m_stBTPairs, 0, wxALL, 5);
2494 
2495     wxArrayString mt;
2496     mt.Add(_T( "unscanned" ));
2497     m_choiceBTDataSources = new wxChoice(m_pNMEAForm, wxID_ANY,
2498                                          wxDefaultPosition, wxDefaultSize, mt);
2499 
2500 #if 0
2501         m_BTscan_results.Clear();
2502         m_BTscan_results.Add(_T("None"));
2503 
2504         m_BTscan_results = g_Platform->getBluetoothScanResults();
2505         m_choiceBTDataSources->Clear();
2506         m_choiceBTDataSources->Append(m_BTscan_results[0]);  // scan status
2507 
2508         unsigned int i=1;
2509         while( (i+1) < m_BTscan_results.GetCount()){
2510             wxString item1 = m_BTscan_results[i] + _T(";");
2511             wxString item2 = m_BTscan_results.Item(i+1);
2512             m_choiceBTDataSources->Append(item1 + item2);
2513 
2514             i += 2;
2515     }
2516 
2517     if( m_BTscan_results.GetCount() > 1){
2518         m_choiceBTDataSources->SetSelection( 1 );
2519     }
2520 #endif
2521 
2522     m_choiceBTDataSources->Hide();
2523     bSizer15a->Add(m_choiceBTDataSources, 1, wxEXPAND | wxTOP, 5);
2524 
2525     m_buttonScanBT->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2526                             wxCommandEventHandler(options::OnScanBTClick), NULL,
2527                             this);
2528   } else
2529     m_rbTypeInternalBT = NULL;
2530 
2531   gSizerNetProps = new wxGridSizer(0, 2, 0, 0);
2532 
2533   m_stNetProto = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Protocol"),
2534                                   wxDefaultPosition, wxDefaultSize, 0);
2535   m_stNetProto->Wrap(-1);
2536   gSizerNetProps->Add(m_stNetProto, 0, wxALL, 5);
2537 
2538   wxBoxSizer* bSizer16;
2539   bSizer16 = new wxBoxSizer(wxHORIZONTAL);
2540 
2541   m_rbNetProtoTCP =
2542       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("TCP"), wxDefaultPosition,
2543                         wxDefaultSize, wxRB_GROUP);
2544   m_rbNetProtoTCP->Enable(TRUE);
2545 
2546   bSizer16->Add(m_rbNetProtoTCP, 0, wxALL, 5);
2547 
2548   m_rbNetProtoUDP = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("UDP"),
2549                                       wxDefaultPosition, wxDefaultSize, 0);
2550   m_rbNetProtoUDP->Enable(TRUE);
2551 
2552   bSizer16->Add(m_rbNetProtoUDP, 0, wxALL, 5);
2553 
2554   m_rbNetProtoGPSD = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("GPSD"),
2555                                        wxDefaultPosition, wxDefaultSize, 0);
2556   m_rbNetProtoGPSD->SetValue(TRUE);
2557   bSizer16->Add(m_rbNetProtoGPSD, 0, wxALL, 5);
2558 
2559   m_rbNetProtoSignalK = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Signal K"),
2560                                        wxDefaultPosition, wxDefaultSize, 0);
2561   m_rbNetProtoSignalK->Enable(TRUE);
2562   bSizer16->Add(m_rbNetProtoSignalK, 0, wxALL, 5);
2563 
2564   gSizerNetProps->Add(bSizer16, 1, wxEXPAND, 5);
2565 
2566   m_stNetAddr = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Address"),
2567                                  wxDefaultPosition, wxDefaultSize, 0);
2568   m_stNetAddr->Wrap(-1);
2569   gSizerNetProps->Add(m_stNetAddr, 0, wxALL, 5);
2570 
2571   m_tNetAddress = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
2572                                  wxDefaultPosition, wxDefaultSize, 0);
2573   gSizerNetProps->Add(m_tNetAddress, 0, wxEXPAND | wxTOP, 5);
2574 
2575   m_stNetPort = new wxStaticText(m_pNMEAForm, wxID_ANY, _("DataPort"),
2576                                  wxDefaultPosition, wxDefaultSize, 0);
2577   m_stNetPort->Wrap(-1);
2578   gSizerNetProps->Add(m_stNetPort, 0, wxALL, 5);
2579 
2580   m_tNetPort = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
2581                               wxDefaultPosition, wxDefaultSize, 0);
2582   gSizerNetProps->Add(m_tNetPort, 1, wxEXPAND | wxTOP, 5);
2583 
2584   //  User Comments
2585   m_stNetComment = new wxStaticText(m_pNMEAForm, wxID_ANY, _("User Comment"),
2586                                  wxDefaultPosition, wxDefaultSize, 0);
2587   m_stNetComment->Wrap(-1);
2588   gSizerNetProps->Add(m_stNetComment, 0, wxALL, 5);
2589 
2590   m_tNetComment = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
2591                               wxDefaultPosition, wxDefaultSize, 0);
2592   gSizerNetProps->Add(m_tNetComment, 1, wxEXPAND | wxTOP, 5);
2593 
2594 
2595   sbSizerConnectionProps->Add(gSizerNetProps, 0, wxEXPAND, 5);
2596 
2597   gSizerSerProps = new wxGridSizer(0, 1, 0, 0);
2598 
2599   wxFlexGridSizer* fgSizer1;
2600   fgSizer1 = new wxFlexGridSizer(0, 4, 0, 0);
2601   fgSizer1->SetFlexibleDirection(wxBOTH);
2602   fgSizer1->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
2603 
2604   m_stSerPort = new wxStaticText(m_pNMEAForm, wxID_ANY, _("DataPort"),
2605                                  wxDefaultPosition, wxDefaultSize, 0);
2606   m_stSerPort->Wrap(-1);
2607   fgSizer1->Add(m_stSerPort, 0, wxALL, 5);
2608 
2609   m_comboPort = new wxComboBox(m_pNMEAForm, wxID_ANY, wxEmptyString,
2610                                wxDefaultPosition, wxDefaultSize, 0, NULL, 0);
2611   fgSizer1->Add(m_comboPort, 0, wxEXPAND | wxTOP, 5);
2612 
2613   m_stSerBaudrate = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Baudrate"),
2614                                      wxDefaultPosition, wxDefaultSize, 0);
2615   m_stSerBaudrate->Wrap(-1);
2616   fgSizer1->Add(m_stSerBaudrate, 0, wxALL, 5);
2617 
2618   wxString m_choiceBaudRateChoices[] = {
2619       _("150"),    _("300"),    _("600"),    _("1200"),  _("2400"),
2620       _("4800"),   _("9600"),   _("19200"),  _("38400"), _("57600"),
2621       _("115200"), _("230400"), _("460800"), _("921600")};
2622   int m_choiceBaudRateNChoices =
2623       sizeof(m_choiceBaudRateChoices) / sizeof(wxString);
2624   m_choiceBaudRate =
2625       new wxChoice(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2626                    m_choiceBaudRateNChoices, m_choiceBaudRateChoices, 0);
2627   m_choiceBaudRate->SetSelection(0);
2628   fgSizer1->Add(m_choiceBaudRate, 1, wxEXPAND | wxTOP, 5);
2629 
2630   m_stSerProtocol = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Protocol"),
2631                                      wxDefaultPosition, wxDefaultSize, 0);
2632   m_stSerProtocol->Wrap(-1);
2633   fgSizer1->Add(m_stSerProtocol, 0, wxALL, 5);
2634 
2635   wxString m_choiceSerialProtocolChoices[] = {_("NMEA 0183"), _("NMEA 2000"),
2636                                               _("Seatalk")};
2637   int m_choiceSerialProtocolNChoices =
2638       sizeof(m_choiceSerialProtocolChoices) / sizeof(wxString);
2639   m_choiceSerialProtocol = new wxChoice(
2640       m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2641       m_choiceSerialProtocolNChoices, m_choiceSerialProtocolChoices, 0);
2642   m_choiceSerialProtocol->SetSelection(0);
2643   m_choiceSerialProtocol->Enable(FALSE);
2644   fgSizer1->Add(m_choiceSerialProtocol, 1, wxEXPAND | wxTOP, 5);
2645 
2646   m_stPriority = new wxStaticText(m_pNMEAForm, wxID_ANY, _("Priority"),
2647                                   wxDefaultPosition, wxDefaultSize, 0);
2648   m_stPriority->Wrap(-1);
2649   fgSizer1->Add(m_stPriority, 0, wxALL, 5);
2650 
2651   wxString m_choicePriorityChoices[] = {_("0"), _("1"), _("2"), _("3"), _("4"),
2652                                         _("5"), _("6"), _("7"), _("8"), _("9")};
2653   int m_choicePriorityNChoices =
2654       sizeof(m_choicePriorityChoices) / sizeof(wxString);
2655   m_choicePriority =
2656       new wxChoice(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2657                    m_choicePriorityNChoices, m_choicePriorityChoices, 0);
2658   m_choicePriority->SetSelection(9);
2659   fgSizer1->Add(m_choicePriority, 0, wxEXPAND | wxTOP, 5);
2660 
2661   gSizerSerProps->Add(fgSizer1, 0, wxEXPAND, 5);
2662 
2663   wxFlexGridSizer* fgSizer5;
2664   fgSizer5 = new wxFlexGridSizer(0, 2, 0, 0);
2665   fgSizer5->SetFlexibleDirection(wxBOTH);
2666   fgSizer5->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
2667 
2668   //  User Comments
2669   m_stSerialComment = new wxStaticText(m_pNMEAForm, wxID_ANY, _("User Comment"),
2670                                  wxDefaultPosition, wxDefaultSize, 0);
2671   m_stSerialComment->Wrap(-1);
2672   fgSizer5->Add(m_stSerialComment, 0, wxALL, 5);
2673 
2674   m_tSerialComment = new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString,
2675                               wxDefaultPosition, wxDefaultSize, 0);
2676   fgSizer5->Add(m_tSerialComment, 1, wxEXPAND | wxTOP, 5);
2677 
2678   m_cbCheckCRC = new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Control checksum"),
2679                                 wxDefaultPosition, wxDefaultSize, 0);
2680   m_cbCheckCRC->SetValue(TRUE);
2681   m_cbCheckCRC->SetToolTip(
2682       _("If checked, only the sentences with a valid checksum are passed through"));
2683   fgSizer5->Add(m_cbCheckCRC, 0, wxALL, 5);
2684 
2685   m_cbGarminHost = new wxCheckBox(m_pNMEAForm, wxID_ANY,
2686                                   _("Use Garmin (GRMN) mode for input"),
2687                                   wxDefaultPosition, wxDefaultSize, 0);
2688   m_cbGarminHost->SetValue(FALSE);
2689   fgSizer5->Add(m_cbGarminHost, 0, wxALL, 5);
2690 #ifndef USE_GARMINHOST
2691   m_cbGarminHost->Hide();
2692 #endif
2693 
2694   m_cbInput =
2695       new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Receive Input on this Port"),
2696                      wxDefaultPosition, wxDefaultSize, 0);
2697   fgSizer5->Add(m_cbInput, 0, wxALL, 5);
2698 
2699   m_cbOutput =
2700       new wxCheckBox(m_pNMEAForm, wxID_ANY,
2701                      wxString::Format(_T("%s (%s)"), _("Output on this port"), _("as autopilot or NMEA repeater")),
2702                      wxDefaultPosition, wxDefaultSize, 0);
2703   fgSizer5->Add(m_cbOutput, 0, wxALL, 5);
2704 
2705   m_stTalkerIdText = new wxStaticText(m_pNMEAForm, wxID_ANY,
2706                                       wxString::Format(_T("%s (%s)"), _("Talker ID"), _("blank = default ID")),
2707                                       wxDefaultPosition, wxDefaultSize, 0);
2708   m_stTalkerIdText->Wrap(-1);
2709   fgSizer5->Add(m_stTalkerIdText, 0, wxALL, 5);
2710 
2711   m_TalkerIdText = new wxTextCtrl(m_pNMEAForm, ID_OPTEXTCTRL, _T( "" ),
2712                                   wxDefaultPosition, wxSize(50, -1), 0);
2713   m_TalkerIdText->SetMaxLength(2);
2714   fgSizer5->Add(m_TalkerIdText, 0, wxALIGN_LEFT | wxALL, group_item_spacing);
2715 
2716   m_stPrecision =
2717       new wxStaticText(m_pNMEAForm, wxID_ANY, _("APB bearing precision"),
2718                        wxDefaultPosition, wxDefaultSize, 0);
2719 
2720   m_stPrecision->Wrap(-1);
2721   fgSizer5->Add(m_stPrecision, 0, wxALL, 5);
2722 
2723   wxString m_choicePrecisionChoices[] = {_("x"), _("x.x"), _("x.xx"),
2724                                          _("x.xxx"), _("x.xxxx")};
2725   int m_choicePrecisionNChoices =
2726       sizeof(m_choicePrecisionChoices) / sizeof(wxString);
2727   m_choicePrecision =
2728       new wxChoice(m_pNMEAForm, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2729                    m_choicePrecisionNChoices, m_choicePrecisionChoices, 0);
2730   m_choicePrecision->SetSelection(g_NMEAAPBPrecision);
2731   fgSizer5->Add(m_choicePrecision, 0, wxALL, 5);
2732 
2733   // signalK discovery enable
2734   m_cbCheckSKDiscover = new wxCheckBox(m_pNMEAForm, wxID_ANY, _("Automatic server discovery"),
2735                                 wxDefaultPosition, wxDefaultSize, 0);
2736   m_cbCheckSKDiscover->SetValue(TRUE);
2737   m_cbCheckSKDiscover->SetToolTip(_("If checked, signal K server will be discovered automatically"));
2738   fgSizer5->Add(m_cbCheckSKDiscover, 0, wxALL, 5);
2739 
2740   // signal K "Discover now" button
2741   m_ButtonSKDiscover = new wxButton(m_pNMEAForm, wxID_ANY, _("Discover now..."),  wxDefaultPosition, wxDefaultSize, 0);
2742   m_ButtonSKDiscover->Hide();
2743   fgSizer5->Add(m_ButtonSKDiscover, 0, wxALL, 5);
2744 
2745   // signalK Server Status
2746   m_StaticTextSKServerStatus = new wxStaticText(m_pNMEAForm, wxID_ANY, _T(""),  wxDefaultPosition, wxDefaultSize, 0);
2747   fgSizer5->Add(m_StaticTextSKServerStatus, 0, wxALL, 5);
2748 
2749   sbSizerConnectionProps->Add(gSizerSerProps, 0, wxEXPAND, 5);
2750   sbSizerConnectionProps->Add(fgSizer5, 0, wxEXPAND, 5);
2751 
2752   sbSizerInFilter = new wxStaticBoxSizer(
2753       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Input filtering")), wxVERTICAL);
2754 
2755   wxBoxSizer* bSizer9;
2756   bSizer9 = new wxBoxSizer(wxHORIZONTAL);
2757 
2758   m_rbIAccept =
2759       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Accept only sentences"),
2760                         wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
2761   bSizer9->Add(m_rbIAccept, 0, wxALL, 5);
2762 
2763   m_rbIIgnore = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Ignore sentences"),
2764                                   wxDefaultPosition, wxDefaultSize, 0);
2765   bSizer9->Add(m_rbIIgnore, 0, wxALL, 5);
2766 
2767   sbSizerInFilter->Add(bSizer9, 0, wxEXPAND, 5);
2768 
2769   wxBoxSizer* bSizer11;
2770   bSizer11 = new wxBoxSizer(wxHORIZONTAL);
2771 
2772   m_tcInputStc =
2773       new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString, wxDefaultPosition,
2774                      wxDefaultSize, wxTE_READONLY);
2775   bSizer11->Add(m_tcInputStc, 1, wxALL | wxEXPAND, 5);
2776 
2777   m_btnInputStcList =
2778       new wxButton(m_pNMEAForm, wxID_ANY, _T("..."), wxDefaultPosition,
2779                    wxDefaultSize, wxBU_EXACTFIT);
2780   bSizer11->Add(m_btnInputStcList, 0, wxALL, 5);
2781 
2782   sbSizerInFilter->Add(bSizer11, 0, wxEXPAND, 5);
2783 
2784   sbSizerConnectionProps->Add(sbSizerInFilter, 0, wxEXPAND, 5);
2785 
2786   sbSizerOutFilter = new wxStaticBoxSizer(
2787       new wxStaticBox(m_pNMEAForm, wxID_ANY, _("Output filtering")),
2788       wxVERTICAL);
2789 
2790   wxBoxSizer* bSizer10;
2791   bSizer10 = new wxBoxSizer(wxHORIZONTAL);
2792 
2793   m_rbOAccept =
2794       new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Transmit sentences"),
2795                         wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
2796   bSizer10->Add(m_rbOAccept, 0, wxALL, 5);
2797 
2798   m_rbOIgnore = new wxRadioButton(m_pNMEAForm, wxID_ANY, _("Drop sentences"),
2799                                   wxDefaultPosition, wxDefaultSize, 0);
2800   bSizer10->Add(m_rbOIgnore, 0, wxALL, 5);
2801 
2802   sbSizerOutFilter->Add(bSizer10, 0, wxEXPAND, 5);
2803 
2804   wxBoxSizer* bSizer12;
2805   bSizer12 = new wxBoxSizer(wxHORIZONTAL);
2806 
2807   m_tcOutputStc =
2808       new wxTextCtrl(m_pNMEAForm, wxID_ANY, wxEmptyString, wxDefaultPosition,
2809                      wxDefaultSize, wxTE_READONLY);
2810   bSizer12->Add(m_tcOutputStc, 1, wxALL | wxEXPAND, 5);
2811 
2812   m_btnOutputStcList =
2813       new wxButton(m_pNMEAForm, wxID_ANY, _T("..."), wxDefaultPosition,
2814                    wxDefaultSize, wxBU_EXACTFIT);
2815   bSizer12->Add(m_btnOutputStcList, 0, wxALL, 5);
2816 
2817   sbSizerOutFilter->Add(bSizer12, 0, wxEXPAND, 5);
2818   sbSizerConnectionProps->Add(sbSizerOutFilter, 0, wxEXPAND, 5);
2819 
2820   bSizerOuterContainer->Add(sbSizerConnectionProps, 1, wxALL | wxEXPAND, 5);
2821 
2822   bSizer4->Add(bSizerOuterContainer, 1, wxEXPAND, 5);
2823 
2824   // Connect Events
2825 //   m_lcSources->Connect(wxEVT_COMMAND_LIST_ITEM_SELECTED,
2826 //                        wxListEventHandler(options::OnSelectDatasource), NULL,
2827 //                        this);
2828   m_buttonAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2829                        wxCommandEventHandler(options::OnAddDatasourceClick),
2830                        NULL, this);
2831   m_buttonRemove->Connect(
2832       wxEVT_COMMAND_BUTTON_CLICKED,
2833       wxCommandEventHandler(options::OnRemoveDatasourceClick), NULL, this);
2834 
2835   m_rbTypeSerial->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2836                           wxCommandEventHandler(options::OnTypeSerialSelected),
2837                           NULL, this);
2838   m_rbTypeNet->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2839                        wxCommandEventHandler(options::OnTypeNetSelected), NULL,
2840                        this);
2841 
2842   if (m_rbTypeInternalGPS)
2843     m_rbTypeInternalGPS->Connect(
2844         wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2845         wxCommandEventHandler(options::OnTypeGPSSelected), NULL, this);
2846   if (m_rbTypeInternalBT)
2847     m_rbTypeInternalBT->Connect(
2848         wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2849         wxCommandEventHandler(options::OnTypeBTSelected), NULL, this);
2850 
2851   m_rbNetProtoTCP->Connect(
2852       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2853       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2854   m_rbNetProtoUDP->Connect(
2855       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2856       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2857   m_rbNetProtoGPSD->Connect(
2858       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2859       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2860   m_rbNetProtoSignalK->Connect(
2861       wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2862       wxCommandEventHandler(options::OnNetProtocolSelected), NULL, this);
2863   m_tNetAddress->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2864                          wxCommandEventHandler(options::OnConnValChange), NULL,
2865                          this);
2866   m_tNetPort->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2867                       wxCommandEventHandler(options::OnConnValChange), NULL,
2868                       this);
2869   m_comboPort->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
2870                        wxCommandEventHandler(options::OnConnValChange), NULL,
2871                        this);
2872   m_comboPort->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2873                        wxCommandEventHandler(options::OnConnValChange), NULL,
2874                        this);
2875   m_choiceBaudRate->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
2876                             wxCommandEventHandler(options::OnBaudrateChoice),
2877                             NULL, this);
2878   m_choiceSerialProtocol->Connect(
2879       wxEVT_COMMAND_CHOICE_SELECTED,
2880       wxCommandEventHandler(options::OnProtocolChoice), NULL, this);
2881   m_choicePriority->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
2882                             wxCommandEventHandler(options::OnConnValChange),
2883                             NULL, this);
2884   m_cbCheckCRC->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2885                         wxCommandEventHandler(options::OnCrcCheck), NULL, this);
2886   m_cbGarminHost->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2887                           wxCommandEventHandler(options::OnUploadFormatChange),
2888                           NULL, this);
2889   m_cbGarminUploadHost->Connect(
2890       wxEVT_COMMAND_CHECKBOX_CLICKED,
2891       wxCommandEventHandler(options::OnUploadFormatChange), NULL, this);
2892   m_cbFurunoGP3X->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2893                           wxCommandEventHandler(options::OnUploadFormatChange),
2894                           NULL, this);
2895   m_cbCheckSKDiscover->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2896                         wxCommandEventHandler(options::OnConnValChange), NULL, this);
2897   m_ButtonSKDiscover->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2898                         wxCommandEventHandler(options::OnDiscoverButton), NULL, this);
2899 
2900   m_rbIAccept->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2901                        wxCommandEventHandler(options::OnRbAcceptInput), NULL,
2902                        this);
2903   m_rbIIgnore->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2904                        wxCommandEventHandler(options::OnRbIgnoreInput), NULL,
2905                        this);
2906   m_tcInputStc->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2907                         wxCommandEventHandler(options::OnConnValChange), NULL,
2908                         this);
2909   m_btnInputStcList->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2910                              wxCommandEventHandler(options::OnBtnIStcs), NULL,
2911                              this);
2912   m_cbInput->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2913                      wxCommandEventHandler(options::OnCbInput), NULL, this);
2914   m_cbOutput->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2915                       wxCommandEventHandler(options::OnCbOutput), NULL, this);
2916   m_rbOAccept->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2917                        wxCommandEventHandler(options::OnRbOutput), NULL, this);
2918   m_rbOIgnore->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
2919                        wxCommandEventHandler(options::OnRbOutput), NULL, this);
2920   m_tcOutputStc->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2921                          wxCommandEventHandler(options::OnConnValChange), NULL,
2922                          this);
2923   m_btnOutputStcList->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
2924                               wxCommandEventHandler(options::OnBtnOStcs), NULL,
2925                               this);
2926   m_cbCheckCRC->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2927                       wxCommandEventHandler(options::OnConnValChange), NULL, this);
2928 
2929   pOpenGL->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2930                    wxCommandEventHandler(options::OnGLClicked), NULL, this);
2931 
2932   m_cbNMEADebug->Connect(
2933       wxEVT_COMMAND_CHECKBOX_CLICKED,
2934       wxCommandEventHandler(options::OnShowGpsWindowCheckboxClick), NULL, this);
2935   m_cbFilterSogCog->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2936                             wxCommandEventHandler(options::OnValChange), NULL,
2937                             this);
2938   m_tFilterSec->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2939                         wxCommandEventHandler(options::OnValChange), NULL,
2940                         this);
2941   m_cbAPBMagnetic->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
2942                            wxCommandEventHandler(options::OnValChange), NULL,
2943                            this);
2944 
2945   m_tNetComment->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2946                          wxCommandEventHandler(options::OnConnValChange), NULL,
2947                          this);
2948   m_tSerialComment->Connect(wxEVT_COMMAND_TEXT_UPDATED,
2949                          wxCommandEventHandler(options::OnConnValChange), NULL,
2950                          this);
2951 
2952 #if 0
2953 //   m_lcSources->Connect(wxEVT_LEFT_DOWN,
2954 //                        wxMouseEventHandler(options::OnConnectionToggleEnableMouse),
2955 //                        NULL, this);
2956 // #if wxCHECK_VERSION(2, 9, 0)
2957 //   m_lcSources->Connect(wxEVT_LIST_ITEM_ACTIVATED,
2958 //                        wxListEventHandler(options::OnConnectionToggleEnable),
2959 //                        NULL, this);
2960 // #endif
2961 
2962   wxString columns[] = {_("Enable"),   _("Type"),       _("DataPort"),
2963                         _("Priority"), _("Parameters"), _("Connection"),
2964                         _("Filters")};
2965   for (int i = 0; i < 7; ++i) {
2966     wxListItem col;
2967     col.SetId(i);
2968     col.SetText(columns[i]);
2969 //    m_lcSources->InsertColumn(i, col);
2970   }
2971 
2972   //  Build the image list
2973   wxImageList* imglist = new wxImageList(16, 16, TRUE, 1);
2974   wxBitmap unchecked_bmp(16, 16), checked_bmp(16, 16);
2975   wxMemoryDC renderer_dc;
2976 
2977   // Unchecked
2978   renderer_dc.SelectObject(unchecked_bmp);
2979   renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(
2980       GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
2981   renderer_dc.Clear();
2982   wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, 16, 16),
2983                                        0);
2984 
2985   // Checked
2986   renderer_dc.SelectObject(checked_bmp);
2987   renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(
2988       GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
2989   renderer_dc.Clear();
2990   wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, 16, 16),
2991                                        wxCONTROL_CHECKED);
2992 
2993   // Deselect the renderer Object
2994   renderer_dc.SelectObject(wxNullBitmap);
2995 
2996   imglist->Add(unchecked_bmp);
2997   imglist->Add(checked_bmp);
2998 //  m_lcSources->AssignImageList(imglist, wxIMAGE_LIST_SMALL);
2999 
3000 //  m_lcSources->Refresh();
3001 #endif
3002   FillSourceList();
3003 
3004   ShowNMEACommon(FALSE);
3005   ShowNMEASerial(FALSE);
3006   ShowNMEANet(FALSE);
3007   connectionsaved = TRUE;
3008 }
3009 
3010 #if 0
3011 void options::EnableItem(const long index) {
3012   if (index == wxNOT_FOUND) {
3013     ClearNMEAForm();
3014     m_buttonRemove->Disable();
3015   } else {
3016     ConnectionParams* conn =
3017         g_pConnectionParams->Item(m_lcSources->GetItemData(index));
3018     if (!conn) return;
3019     conn->bEnabled = !conn->bEnabled;
3020     m_connection_enabled = conn->bEnabled;
3021     // Mark as changed
3022     conn->b_IsSetup = FALSE;
3023     m_lcSources->SetItemImage(index, conn->bEnabled);
3024   }
3025 }
3026 
3027 void options::OnConnectionToggleEnable(wxListEvent& event) {
3028   EnableItem(event.GetIndex());
3029   gFrame->RefreshAllCanvas();;
3030 }
3031 
3032 void options::OnConnectionToggleEnableMouse(wxMouseEvent& event) {
3033 #if 0
3034   int flags;
3035   long index = m_lcSources->HitTest(event.GetPosition(), flags);
3036   if (index == wxNOT_FOUND || event.GetX() < m_lcSources->GetColumnWidth(0))
3037     EnableItem(index);
3038 #endif
3039   // Allow wx to process...
3040   event.Skip();
3041 }
3042 #endif
3043 
EnableConnection(ConnectionParams * conn,bool value)3044 void options::EnableConnection( ConnectionParams *conn, bool value){
3045     if(conn){
3046         conn->bEnabled = value;
3047         conn->b_IsSetup = FALSE;  // trigger a rebuild/takedown of the connection
3048         m_connection_enabled = conn->bEnabled;
3049     }
3050 }
3051 
CreatePanel_Ownship(size_t parent,int border_size,int group_item_spacing)3052 void options::CreatePanel_Ownship(size_t parent, int border_size,
3053                                   int group_item_spacing) {
3054   itemPanelShip = AddPage(parent, _("Own ship"));
3055 
3056   ownShip = new wxBoxSizer(wxVERTICAL);
3057   itemPanelShip->SetSizer(ownShip);
3058 
3059   // OwnShip Display options
3060   wxStaticBox* osdBox =
3061       new wxStaticBox(itemPanelShip, wxID_ANY, _("Display Options"));
3062   dispOptions = new wxStaticBoxSizer(osdBox, wxVERTICAL);
3063   ownShip->Add(dispOptions, 0, wxTOP | wxALL | wxEXPAND, border_size);
3064 
3065   wxFlexGridSizer* dispOptionsGrid =
3066       new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
3067   dispOptionsGrid->AddGrowableCol(1);
3068   dispOptions->Add(dispOptionsGrid, 0, wxALL | wxEXPAND, border_size);
3069 
3070   wxStaticText* pStatic_OSCOG_Predictor = new wxStaticText(
3071       itemPanelShip, wxID_ANY, _("COG Predictor Length (min)"));
3072   dispOptionsGrid->Add(pStatic_OSCOG_Predictor, 0);
3073 
3074   m_pText_OSCOG_Predictor = new wxTextCtrl(itemPanelShip, wxID_ANY);
3075   dispOptionsGrid->Add(m_pText_OSCOG_Predictor, 0, wxALIGN_RIGHT);
3076 
3077   wxStaticText* pStatic_OSHDT_Predictor = new wxStaticText(
3078       itemPanelShip, wxID_ANY, _("Heading Predictor Length (NMi)"));
3079   dispOptionsGrid->Add(pStatic_OSHDT_Predictor, 0);
3080 
3081   m_pText_OSHDT_Predictor = new wxTextCtrl(itemPanelShip, wxID_ANY);
3082   dispOptionsGrid->Add(m_pText_OSHDT_Predictor, 0, wxALIGN_RIGHT);
3083 
3084   wxStaticText* iconTypeTxt =
3085       new wxStaticText(itemPanelShip, wxID_ANY, _("Ship Icon Type"));
3086   dispOptionsGrid->Add(iconTypeTxt, 0);
3087 
3088   wxString iconTypes[] = {_("Default"), _("Real Scale Bitmap"),
3089                           _("Real Scale Vector")};
3090 
3091   m_pShipIconType =
3092       new wxChoice(itemPanelShip, ID_SHIPICONTYPE, wxDefaultPosition, wxSize(GetCharWidth() * 20, GetCharHeight() * 2), 3, iconTypes);
3093   dispOptionsGrid->Add(m_pShipIconType, 0,
3094                        wxALIGN_RIGHT | wxLEFT | wxRIGHT | wxTOP,
3095                        group_item_spacing);
3096 
3097   realSizes = new wxFlexGridSizer(5, 2, group_item_spacing, group_item_spacing);
3098   realSizes->AddGrowableCol(1);
3099 
3100   dispOptions->Add(realSizes, 0, wxEXPAND | wxLEFT, 30);
3101 
3102   realSizes->Add(
3103       new wxStaticText(itemPanelShip, wxID_ANY, _("Length Over All (m)")), 1,
3104       wxALIGN_LEFT);
3105   m_pOSLength = new wxTextCtrl(itemPanelShip, 1);
3106   realSizes->Add(m_pOSLength, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
3107 
3108   realSizes->Add(
3109       new wxStaticText(itemPanelShip, wxID_ANY, _("Width Over All (m)")), 1,
3110       wxALIGN_LEFT);
3111   m_pOSWidth = new wxTextCtrl(itemPanelShip, wxID_ANY);
3112   realSizes->Add(m_pOSWidth, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
3113 
3114   realSizes->Add(
3115       new wxStaticText(itemPanelShip, wxID_ANY, _("GPS Offset from Bow (m)")),
3116       1, wxALIGN_LEFT);
3117   m_pOSGPSOffsetY = new wxTextCtrl(itemPanelShip, wxID_ANY);
3118   realSizes->Add(m_pOSGPSOffsetY, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
3119 
3120   realSizes->Add(new wxStaticText(itemPanelShip, wxID_ANY,
3121                                   _("GPS Offset from Midship (m)")),
3122                  1, wxALIGN_LEFT);
3123   m_pOSGPSOffsetX = new wxTextCtrl(itemPanelShip, wxID_ANY);
3124   realSizes->Add(m_pOSGPSOffsetX, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
3125 
3126   realSizes->Add(
3127       new wxStaticText(itemPanelShip, wxID_ANY, _("Minimum Screen Size (mm)")),
3128       1, wxALIGN_LEFT);
3129   m_pOSMinSize = new wxTextCtrl(itemPanelShip, wxID_ANY);
3130   realSizes->Add(m_pOSMinSize, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
3131 
3132   // Radar rings
3133   wxFlexGridSizer* rrSelect =
3134       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3135   rrSelect->AddGrowableCol(1);
3136   dispOptions->Add(rrSelect, 0, wxLEFT | wxRIGHT | wxEXPAND, border_size);
3137 
3138   wxStaticText* rrTxt =
3139       new wxStaticText(itemPanelShip, wxID_ANY, _("Show range rings"));
3140   rrSelect->Add(rrTxt, 1, wxEXPAND | wxALL, group_item_spacing);
3141 
3142   wxString rrAlt[] = {_("None"), _T( "1" ), _T( "2" ), _T( "3" ),
3143                       _T( "4" ), _T( "5" ), _T( "6" ), _T( "7" ),
3144                       _T( "8" ), _T( "9" ), _T( "10" )};
3145   pNavAidRadarRingsNumberVisible =
3146       new wxChoice(itemPanelShip, ID_RADARRINGS, wxDefaultPosition,
3147                    m_pShipIconType->GetSize(), 11, rrAlt);
3148   rrSelect->Add(pNavAidRadarRingsNumberVisible, 0, wxALIGN_RIGHT | wxALL,
3149                 group_item_spacing);
3150 
3151   radarGrid = new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
3152   radarGrid->AddGrowableCol(1);
3153   dispOptions->Add(radarGrid, 0, wxLEFT | wxEXPAND, 30);
3154 
3155   wxStaticText* distanceText =
3156       new wxStaticText(itemPanelShip, wxID_STATIC, _("Distance between rings"));
3157   radarGrid->Add(distanceText, 1, wxEXPAND | wxALL, group_item_spacing);
3158 
3159   pNavAidRadarRingsStep = new wxTextCtrl(itemPanelShip, ID_OPTEXTCTRL, _T(""),
3160                                          wxDefaultPosition, wxSize(100, -1), 0);
3161   radarGrid->Add(pNavAidRadarRingsStep, 0, wxALIGN_RIGHT | wxALL,
3162                  group_item_spacing);
3163 
3164   wxStaticText* unitText =
3165       new wxStaticText(itemPanelShip, wxID_STATIC, _("Distance Unit"));
3166   radarGrid->Add(unitText, 1, wxEXPAND | wxALL, group_item_spacing);
3167 
3168   wxString pDistUnitsStrings[] = {_("Nautical miles"), _("Kilometers")};
3169   m_itemRadarRingsUnits =
3170       new wxChoice(itemPanelShip, ID_RADARDISTUNIT, wxDefaultPosition,
3171                    m_pShipIconType->GetSize(), 2, pDistUnitsStrings);
3172   radarGrid->Add(m_itemRadarRingsUnits, 0, wxALIGN_RIGHT | wxALL, border_size);
3173 
3174   wxStaticText* colourText = new wxStaticText(itemPanelShip, wxID_STATIC, _("Range Ring Colour"));
3175   radarGrid->Add(colourText, 1, wxEXPAND | wxALL, group_item_spacing);
3176 
3177   m_colourOwnshipRangeRingColour = new OCPNColourPickerCtrl( itemPanelShip, wxID_ANY, *wxRED,
3178                   wxDefaultPosition, m_colourPickerDefaultSize, 0,  wxDefaultValidator, _T( "ID_COLOUROSRANGECOLOUR" ));
3179   radarGrid->Add(m_colourOwnshipRangeRingColour, 0, wxALIGN_RIGHT, border_size);
3180 
3181   //  Tracks
3182   wxStaticBox* trackText =
3183       new wxStaticBox(itemPanelShip, wxID_ANY, _("Tracks"));
3184   wxStaticBoxSizer* trackSizer = new wxStaticBoxSizer(trackText, wxVERTICAL);
3185   wxBoxSizer* trackSizer1 = new wxBoxSizer(wxHORIZONTAL);
3186   ownShip->Add(trackSizer, 0, wxGROW | wxALL, border_size);
3187 
3188   pTrackDaily = new wxCheckBox(itemPanelShip, ID_DAILYCHECKBOX,
3189                                _("Automatic Daily Tracks at midnight"));
3190 
3191   trackSizer1->Add(pTrackDaily, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, border_size);
3192 
3193   trackSizer1->Add( 0, 0, 1, wxEXPAND, 0 );
3194 
3195 #if wxCHECK_VERSION(2, 9, 0)
3196 #if  wxUSE_TIMEPICKCTRL
3197   pTrackDaily->SetLabel(_("Automatic Daily Tracks at"));
3198 #ifdef __WXGTK__
3199   pTrackRotateTime = new TimeCtrl( itemPanelShip, ID_TRACKROTATETIME, wxDateTime((time_t)g_track_rotate_time).ToUTC(), wxDefaultPosition, wxDefaultSize, 0 );
3200 #else
3201   pTrackRotateTime = new wxTimePickerCtrl( itemPanelShip, ID_TRACKROTATETIME, wxDateTime((time_t)g_track_rotate_time).ToUTC(), wxDefaultPosition, wxDefaultSize, 0 );
3202 #endif
3203   trackSizer1->Add( pTrackRotateTime, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, border_size );
3204 #endif
3205 #endif
3206 
3207   pTrackRotateComputerTime = new wxRadioButton( itemPanelShip, ID_TRACKROTATECOMPUTER, _("Computer"), wxDefaultPosition, wxDefaultSize, 0 );
3208   trackSizer1->Add( pTrackRotateComputerTime, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, border_size );
3209 
3210   pTrackRotateUTC = new wxRadioButton( itemPanelShip, ID_TRACKROTATEUTC, _("UTC"), wxDefaultPosition, wxDefaultSize, 0 );
3211   trackSizer1->Add( pTrackRotateUTC, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, border_size );
3212 
3213   pTrackRotateLMT = new wxRadioButton( itemPanelShip, ID_TRACKROTATELMT, _("LMT"), wxDefaultPosition, wxDefaultSize, 0 );
3214   trackSizer1->Add( pTrackRotateLMT, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, border_size );
3215 
3216   trackSizer->Add(trackSizer1, 1, wxEXPAND | wxALL, border_size);
3217 
3218   wxFlexGridSizer* hTrackGrid =
3219       new wxFlexGridSizer(1, 3, group_item_spacing, group_item_spacing);
3220   hTrackGrid->AddGrowableCol(1);
3221   trackSizer->Add(hTrackGrid, 0, wxALL | wxEXPAND, border_size);
3222 
3223   pTrackHighlite =
3224       new wxCheckBox(itemPanelShip, ID_TRACKHILITE, _("Highlight Tracks"));
3225   hTrackGrid->Add(pTrackHighlite, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, border_size);
3226   wxStaticText* trackColourText =
3227       new wxStaticText( itemPanelShip, wxID_STATIC, _("Track Colour"));
3228   hTrackGrid->Add(trackColourText, 1, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, border_size);
3229   m_colourTrackLineColour = new OCPNColourPickerCtrl(
3230       itemPanelShip, wxID_STATIC, *wxRED, wxDefaultPosition, m_colourPickerDefaultSize, 0,
3231       wxDefaultValidator, _T( "ID_COLOURTRACKCOLOUR" ));
3232   hTrackGrid->Add(m_colourTrackLineColour, 1,
3233                          wxALIGN_RIGHT, border_size);
3234 
3235   wxFlexGridSizer* pTrackGrid =
3236       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3237   pTrackGrid->AddGrowableCol(1);
3238   trackSizer->Add(pTrackGrid, 0, wxALL | wxEXPAND, border_size);
3239 
3240   wxStaticText* tpText =
3241       new wxStaticText(itemPanelShip, wxID_STATIC, _("Tracking Precision"));
3242   pTrackGrid->Add(tpText, 1, wxEXPAND | wxALL, group_item_spacing);
3243 
3244   wxString trackAlt[] = {_("Low"), _("Medium"), _("High")};
3245   pTrackPrecision = new wxChoice(itemPanelShip, wxID_ANY, wxDefaultPosition,
3246                                  m_pShipIconType->GetSize(), 3, trackAlt);
3247   pTrackGrid->Add(pTrackPrecision, 0, wxALIGN_RIGHT | wxALL,
3248                   group_item_spacing);
3249 
3250   //  Calculate values
3251   wxStaticBox* ownshipcalcText = new wxStaticBox(itemPanelShip, wxID_ANY, _("Calculate values"));
3252   wxStaticBoxSizer* ownshipcalcSizer = new wxStaticBoxSizer(ownshipcalcText, wxVERTICAL);
3253   ownShip->Add(ownshipcalcSizer, 0, wxTOP | wxALL | wxEXPAND, border_size);
3254 
3255   wxFlexGridSizer* dispOwnShipCalcOptionsGrid = new wxFlexGridSizer(2, 2, group_item_spacing, group_item_spacing);
3256   ownshipcalcSizer->Add(dispOwnShipCalcOptionsGrid, 0, wxTOP | wxALL | wxEXPAND, border_size);
3257 
3258   dispOwnShipCalcOptionsGrid->AddGrowableCol(1);
3259 
3260   pSogCogFromLLCheckBox = new wxCheckBox(itemPanelShip, ID_SOGCOGFROMLLCHECKBOX, _("Calculate SOG and COG from position changes"));
3261   dispOwnShipCalcOptionsGrid->Add(pSogCogFromLLCheckBox, 1, wxALL, 5);
3262   dispOwnShipCalcOptionsGrid->AddSpacer(0);
3263 
3264   wxStaticText* SogCogFromLLDampIntText = new wxStaticText(itemPanelShip, wxID_STATIC, _("Min seconds between updates"));
3265   dispOwnShipCalcOptionsGrid->Add(SogCogFromLLDampIntText, 1, wxEXPAND | wxALL, group_item_spacing);
3266 
3267   pSogCogFromLLDampInterval = new wxSpinCtrl(itemPanelShip, ID_SOGCOGDAMPINTTEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0 );
3268 
3269   dispOwnShipCalcOptionsGrid->Add(pSogCogFromLLDampInterval, 0, wxALIGN_RIGHT | wxALL, group_item_spacing);
3270 
3271   // DimeControl(itemPanelShip);
3272 }
3273 
CreatePanel_Routes(size_t parent,int border_size,int group_item_spacing)3274 void options::CreatePanel_Routes(size_t parent, int border_size,
3275                                   int group_item_spacing) {
3276   itemPanelRoutes = AddPage(parent, _("Routes/Points"));
3277 
3278   Routes = new wxBoxSizer(wxVERTICAL);
3279   itemPanelRoutes->SetSizer(Routes);
3280 
3281 
3282   wxString pDistUnitsStrings[] = {_("Nautical miles"), _("Kilometers")};
3283 
3284   wxString rrAlt[] = {_("None"), _T( "1" ), _T( "2" ), _T( "3" ),
3285                       _T( "4" ), _T( "5" ), _T( "6" ), _T( "7" ),
3286                       _T( "8" ), _T( "9" ), _T( "10" )};
3287 
3288   //  Routes
3289   wxStaticBox* routeText =
3290       new wxStaticBox(itemPanelRoutes, wxID_ANY, _("New Routes"));
3291   wxStaticBoxSizer* routeSizer = new wxStaticBoxSizer(routeText, wxVERTICAL);
3292   Routes->Add(routeSizer, 0, wxGROW | wxALL, border_size);
3293 
3294   routeSizer->AddSpacer(5);
3295 
3296   // Default ICON
3297   wxFlexGridSizer* routepointiconSelect =
3298       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3299   routepointiconSelect->AddGrowableCol(1);
3300   routeSizer->Add(routepointiconSelect, 0, wxLEFT | wxRIGHT | wxEXPAND,
3301                      border_size);
3302 
3303   wxStaticText* routepointiconTxt =
3304       new wxStaticText(itemPanelRoutes, wxID_ANY, _("Waypoint default icon"));
3305   routepointiconSelect->Add(routepointiconTxt, 1, wxEXPAND | wxALL, group_item_spacing);
3306 
3307   pRoutepointDefaultIconChoice = new OCPNIconCombo( itemPanelRoutes, wxID_ANY, _("Combo!"),
3308                                         wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY );
3309   routepointiconSelect->Add(pRoutepointDefaultIconChoice, 0, wxALIGN_RIGHT | wxALL,
3310                         group_item_spacing);
3311 
3312   pRoutepointDefaultIconChoice->SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
3313 
3314   //  Accomodate scaling of icon
3315    int min_size = GetCharHeight() * 2;
3316    min_size = wxMax( min_size, (32 *g_ChartScaleFactorExp) + 4 );
3317    pRoutepointDefaultIconChoice->SetMinSize( wxSize(GetCharHeight() * 15, min_size) );
3318 
3319   routeSizer->AddSpacer(5);
3320 
3321 
3322   wxFlexGridSizer* pRouteGrid =
3323       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3324   pRouteGrid->AddGrowableCol(1);
3325   routeSizer->Add(pRouteGrid, 0, wxALL | wxEXPAND, border_size);
3326 
3327   wxStaticText* raText = new wxStaticText(
3328       itemPanelRoutes, wxID_STATIC, _("Waypoint Arrival Circle Radius (NMi)"));
3329   pRouteGrid->Add(raText, 1, wxEXPAND | wxALL, group_item_spacing);
3330 
3331   m_pText_ACRadius = new wxTextCtrl(itemPanelRoutes, -1);
3332   pRouteGrid->Add(m_pText_ACRadius, 0, wxALL | wxALIGN_RIGHT,
3333                   group_item_spacing);
3334 
3335   pAdvanceRouteWaypointOnArrivalOnly =
3336       new wxCheckBox(itemPanelRoutes, ID_DAILYCHECKBOX,
3337                      _("Advance route waypoint on arrival only"));
3338   routeSizer->Add(pAdvanceRouteWaypointOnArrivalOnly, 0, wxALL, 5);
3339 
3340 #ifdef __WXGTK__
3341   Routes->AddSpacer(8 * group_item_spacing);
3342   wxStaticLine *pln = new wxStaticLine( itemPanelRoutes, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
3343   Routes->Add(pln, 0, wxEXPAND);
3344 #endif
3345 
3346   //  Waypoints
3347   wxStaticBox* waypointText =
3348       new wxStaticBox(itemPanelRoutes, wxID_ANY, _("New Waypoints"));
3349   wxStaticBoxSizer* waypointSizer =
3350       new wxStaticBoxSizer(waypointText, wxVERTICAL);
3351   Routes->Add(waypointSizer, 0, wxTOP | wxALL | wxEXPAND, border_size);
3352 
3353   waypointSizer->AddSpacer(5);
3354 
3355   // Default ICON
3356   wxFlexGridSizer* waypointiconSelect =
3357       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3358   waypointiconSelect->AddGrowableCol(1);
3359   waypointSizer->Add(waypointiconSelect, 0, wxLEFT | wxRIGHT | wxEXPAND,
3360                      border_size);
3361 
3362   wxStaticText* waypointiconTxt =
3363       new wxStaticText(itemPanelRoutes, wxID_ANY, _("Waypoint default icon"));
3364   waypointiconSelect->Add(waypointiconTxt, 1, wxEXPAND | wxALL, group_item_spacing);
3365 
3366   pWaypointDefaultIconChoice = new OCPNIconCombo( itemPanelRoutes, wxID_ANY, _("Combo!"),
3367                                         wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY );
3368   waypointiconSelect->Add(pWaypointDefaultIconChoice, 0, wxALIGN_RIGHT | wxALL,
3369                         group_item_spacing);
3370 
3371   pWaypointDefaultIconChoice->SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
3372 
3373   //  Accomodate scaling of icon
3374    int rmin_size = GetCharHeight() * 2;
3375    min_size = wxMax( rmin_size, (32 *g_ChartScaleFactorExp) + 4 );
3376    pWaypointDefaultIconChoice->SetMinSize( wxSize(GetCharHeight() * 15, rmin_size) );
3377 
3378   waypointSizer->AddSpacer(5);
3379   // ScaMin
3380   wxFlexGridSizer* ScaMinSizer =
3381       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3382   ScaMinSizer->AddGrowableCol(1);
3383   waypointSizer->Add(ScaMinSizer, 0, wxLEFT | wxRIGHT | wxEXPAND,
3384                      border_size);
3385   pScaMinChckB = new wxCheckBox(itemPanelRoutes, wxID_ANY,
3386                      _("Show waypoints only at a chartscale greater than 1 :"));
3387   ScaMinSizer->Add(pScaMinChckB, 0);
3388   m_pText_ScaMin = new wxTextCtrl(itemPanelRoutes, -1);
3389   ScaMinSizer->Add(m_pText_ScaMin, 0, wxALL | wxALIGN_RIGHT,
3390                   group_item_spacing);
3391 
3392   //Overrule the Scamin settings
3393   pScaMinOverruleChckB = new wxCheckBox(itemPanelRoutes, wxID_ANY,
3394                      _("Override the settings for chartscale based visibility and show always") );
3395   waypointSizer->Add(pScaMinOverruleChckB, 0, wxALL, 5);
3396 
3397   waypointSizer->AddSpacer(5);
3398   //Range Rings
3399   wxFlexGridSizer* waypointrrSelect =
3400       new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
3401   waypointrrSelect->AddGrowableCol(1);
3402   waypointSizer->Add(waypointrrSelect, 0, wxLEFT | wxRIGHT | wxEXPAND,
3403                      border_size);
3404 
3405   wxStaticText* waypointrrTxt =
3406       new wxStaticText(itemPanelRoutes, wxID_ANY, _("Waypoint range rings"));
3407   waypointrrSelect->Add(waypointrrTxt, 1, wxEXPAND | wxALL, group_item_spacing);
3408 
3409   pWaypointRangeRingsNumber =
3410       new wxChoice(itemPanelRoutes, ID_OPWAYPOINTRANGERINGS, wxDefaultPosition,
3411                    m_pShipIconType->GetSize(), 11, rrAlt);
3412   waypointrrSelect->Add(pWaypointRangeRingsNumber, 0, wxALIGN_RIGHT | wxALL,
3413                         group_item_spacing);
3414 
3415   waypointradarGrid =
3416       new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
3417   waypointradarGrid->AddGrowableCol(1);
3418   waypointSizer->Add(waypointradarGrid, 0, wxLEFT | wxEXPAND, 30);
3419 
3420   wxStaticText* waypointdistanceText = new wxStaticText(
3421       itemPanelRoutes, wxID_STATIC, _("Distance between rings"));
3422   waypointradarGrid->Add(waypointdistanceText, 1, wxEXPAND | wxALL,
3423                          group_item_spacing);
3424 
3425   pWaypointRangeRingsStep =
3426       new wxTextCtrl(itemPanelRoutes, ID_OPTEXTCTRL, _T(""), wxDefaultPosition,
3427                      wxSize(100, -1), 0);
3428   waypointradarGrid->Add(pWaypointRangeRingsStep, 0, wxALIGN_RIGHT | wxALL,
3429                          group_item_spacing);
3430 
3431   wxStaticText* waypointunitText =
3432       new wxStaticText(itemPanelRoutes, wxID_STATIC, _("Distance Unit"));
3433   waypointradarGrid->Add(waypointunitText, 1, wxEXPAND | wxALL,
3434                          group_item_spacing);
3435 
3436   m_itemWaypointRangeRingsUnits =
3437       new wxChoice(itemPanelRoutes, ID_RADARDISTUNIT, wxDefaultPosition,
3438                    m_pShipIconType->GetSize(), 2, pDistUnitsStrings);
3439   waypointradarGrid->Add(m_itemWaypointRangeRingsUnits, 0,
3440                          wxALIGN_RIGHT | wxALL, border_size);
3441 
3442   wxStaticText* waypointrangeringsColour = new wxStaticText(
3443       itemPanelRoutes, wxID_STATIC, _("Waypoint Range Ring Colours"));
3444   waypointradarGrid->Add(waypointrangeringsColour, 1, wxEXPAND | wxALL, 1);
3445 
3446   m_colourWaypointRangeRingsColour = new OCPNColourPickerCtrl(
3447       itemPanelRoutes, wxID_ANY, *wxRED, wxDefaultPosition, m_colourPickerDefaultSize, 0,
3448       wxDefaultValidator, _T( "ID_COLOURWAYPOINTRANGERINGSCOLOUR" ));
3449   waypointradarGrid->Add(m_colourWaypointRangeRingsColour, 0,
3450                          wxALIGN_RIGHT | wxALL, 1);
3451 
3452 
3453   // Control Options
3454 
3455 #ifdef __WXGTK__
3456     Routes->AddSpacer(8 * group_item_spacing);
3457     wxStaticLine *pln1 = new wxStaticLine( itemPanelRoutes, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
3458     Routes->Add(pln1, 0, wxEXPAND);
3459 #endif
3460 
3461     wxStaticBox* waypointControl =
3462         new wxStaticBox(itemPanelRoutes, wxID_ANY, _("Control Options"));
3463     wxStaticBoxSizer* ControlSizer =
3464         new wxStaticBoxSizer(waypointControl, wxVERTICAL);
3465     Routes->Add(ControlSizer, 0, wxTOP | wxALL | wxEXPAND, border_size);
3466 
3467     ControlSizer->AddSpacer(5);
3468 
3469     pWayPointPreventDragging = new wxCheckBox(
3470         itemPanelRoutes, ID_DRAGGINGCHECKBOX,
3471         _("Lock Waypoints (Unless waypoint property dialog visible)"));
3472     pWayPointPreventDragging->SetValue(FALSE);
3473     ControlSizer->Add(pWayPointPreventDragging, verticleInputFlags);
3474 
3475     pConfirmObjectDeletion =
3476         new wxCheckBox(itemPanelRoutes, ID_DELETECHECKBOX,
3477                         _("Confirm deletion of tracks and routes"));
3478     pConfirmObjectDeletion->SetValue(FALSE);
3479     ControlSizer->Add(pConfirmObjectDeletion, verticleInputFlags);
3480     ControlSizer->AddSpacer(5);
3481 
3482 
3483   // Fill the default waypoint icon selector combo box
3484   pWaypointDefaultIconChoice->Clear();
3485   //      Iterate on the Icon Descriptions, filling in the combo control
3486   bool fillCombo = true;
3487 
3488   if( fillCombo ){
3489       for( int i = 0; i < pWayPointMan->GetNumIcons(); i++ ) {
3490           wxString *ps = pWayPointMan->GetIconDescription( i );
3491           wxBitmap bmp = pWayPointMan->GetIconBitmapForList(i, 2 * GetCharHeight());
3492 
3493           pWaypointDefaultIconChoice->Append( *ps, bmp );
3494       }
3495   }
3496 
3497   // find the correct item in the combo box
3498    int iconToSelect = -1;
3499    for( int i = 0; i < pWayPointMan->GetNumIcons(); i++ ) {
3500        if( *pWayPointMan->GetIconKey( i ) == g_default_wp_icon ){
3501            iconToSelect = i;
3502            pWaypointDefaultIconChoice->Select( iconToSelect );
3503            break;
3504        }
3505    }
3506 
3507    // Fill the default Routepoint icon selector combo box
3508   pRoutepointDefaultIconChoice->Clear();
3509   //      Iterate on the Icon Descriptions, filling in the combo control
3510   fillCombo = true;
3511 
3512   if( fillCombo ){
3513       for( int i = 0; i < pWayPointMan->GetNumIcons(); i++ ) {
3514           wxString *ps = pWayPointMan->GetIconDescription( i );
3515           wxBitmap bmp = pWayPointMan->GetIconBitmapForList(i, 2 * GetCharHeight());
3516 
3517           pRoutepointDefaultIconChoice->Append( *ps, bmp );
3518       }
3519   }
3520 
3521   // find the correct item in the combo box
3522    iconToSelect = -1;
3523    for( int i = 0; i < pWayPointMan->GetNumIcons(); i++ ) {
3524        if( *pWayPointMan->GetIconKey( i ) == g_default_routepoint_icon ){
3525            iconToSelect = i;
3526            pRoutepointDefaultIconChoice->Select( iconToSelect );
3527            break;
3528        }
3529    }
3530 
3531   // DimeControl(itemPanelRoutes);
3532 }
3533 
CreatePanel_ChartsLoad(size_t parent,int border_size,int group_item_spacing)3534 void options::CreatePanel_ChartsLoad(size_t parent, int border_size,
3535                                      int group_item_spacing) {
3536   wxScrolledWindow* chartPanelWin = AddPage(m_pageCharts, _("Chart Files"));
3537 
3538   chartPanel = new wxBoxSizer(wxVERTICAL);
3539   chartPanelWin->SetSizer(chartPanel);
3540 
3541   wxStaticBox* loadedBox =
3542       new wxStaticBox(chartPanelWin, wxID_ANY, _("Directories"));
3543   activeSizer = new wxStaticBoxSizer(loadedBox, wxHORIZONTAL);
3544   chartPanel->Add(activeSizer, 1, wxALL | wxEXPAND, border_size);
3545 
3546   pActiveChartsList = new wxListCtrl( chartPanelWin, ID_LISTBOX, wxDefaultPosition, wxSize(100, -1),
3547                                        wxLC_REPORT | wxLC_NO_HEADER );
3548 #ifdef __OCPN__ANDROID__
3549     pActiveChartsList->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
3550 #endif
3551 
3552 
3553   activeSizer->Add(pActiveChartsList, 1, wxALL | wxEXPAND, border_size);
3554 
3555   pActiveChartsList->Connect(
3556       wxEVT_COMMAND_LIST_ITEM_SELECTED,
3557       wxCommandEventHandler(options::OnChartDirListSelect), NULL, this);
3558 
3559   wxBoxSizer* cmdButtonSizer = new wxBoxSizer(wxVERTICAL);
3560   activeSizer->Add(cmdButtonSizer, 0, wxALL, border_size);
3561 
3562   // Currently loaded chart dirs
3563   wxString dirname;
3564   if (pActiveChartsList) {
3565     pActiveChartsList->DeleteAllItems();
3566 
3567     // Add first column
3568     wxListItem col0;
3569     col0.SetId(0);
3570     col0.SetText( _("") );
3571     col0.SetAlign(wxLIST_FORMAT_LEFT);
3572     col0.SetWidth(500);
3573     pActiveChartsList->InsertColumn(0, col0);
3574 
3575     for (size_t i = 0; i < m_CurrentDirList.GetCount(); i++) {
3576         wxString dirname = m_CurrentDirList[i].fullpath;
3577         wxListItem li;
3578         li.SetId( i );
3579         li.SetAlign(wxLIST_FORMAT_LEFT);
3580         li.SetText(dirname);
3581         li.SetColumn(0);
3582         long idx = pActiveChartsList->InsertItem( li );
3583     }
3584   }
3585 
3586   wxButton* addBtn =
3587       new wxButton(chartPanelWin, ID_BUTTONADD, _("Add Directory..."));
3588   cmdButtonSizer->Add(addBtn, 1, wxALL | wxEXPAND, group_item_spacing);
3589 
3590   m_removeBtn =
3591       new wxButton(chartPanelWin, ID_BUTTONDELETE, _("Remove Selected"));
3592   cmdButtonSizer->Add(m_removeBtn, 1, wxALL | wxEXPAND, group_item_spacing);
3593   m_removeBtn->Disable();
3594 
3595 #ifdef OCPN_USE_LZMA
3596   m_compressBtn =
3597       new wxButton(chartPanelWin, ID_BUTTONCOMPRESS, _("Compress Selected"));
3598   cmdButtonSizer->Add(m_compressBtn, 1, wxALL | wxEXPAND, group_item_spacing);
3599   m_compressBtn->Disable();
3600 #else
3601   m_compressBtn = NULL;
3602 #endif
3603 
3604   wxStaticBox* itemStaticBoxUpdateStatic =
3605       new wxStaticBox(chartPanelWin, wxID_ANY, _("Update Control"));
3606   wxStaticBoxSizer* itemStaticBoxSizerUpdate =
3607       new wxStaticBoxSizer(itemStaticBoxUpdateStatic, wxVERTICAL);
3608   chartPanel->Add(itemStaticBoxSizerUpdate, 0, wxGROW | wxALL, 5);
3609 
3610   wxFlexGridSizer* itemFlexGridSizerUpdate = new wxFlexGridSizer(1);
3611   itemFlexGridSizerUpdate->SetFlexibleDirection( wxHORIZONTAL );
3612 
3613   pScanCheckBox = new wxCheckBox(chartPanelWin, ID_SCANCHECKBOX, _("Scan Charts and Update Database"));
3614   itemFlexGridSizerUpdate->Add(pScanCheckBox, 1, wxALL, 5);
3615 
3616   pUpdateCheckBox = new wxCheckBox(chartPanelWin, ID_UPDCHECKBOX, _("Force Full Database Rebuild"));
3617   itemFlexGridSizerUpdate->Add(pUpdateCheckBox, 1, wxALL, 5);
3618 
3619   pParseENCButton = new wxButton(chartPanelWin, ID_PARSEENCBUTTON, _("Prepare all ENC Charts"));
3620   itemFlexGridSizerUpdate->Add(pParseENCButton, 1, wxALL, 5);
3621 
3622   itemStaticBoxSizerUpdate->Add( itemFlexGridSizerUpdate, 1, wxEXPAND, 5 );
3623 
3624 
3625   chartPanel->Layout();
3626 }
3627 
UpdateTemplateTitleText()3628 void options::UpdateTemplateTitleText()
3629 {
3630     if(!m_templateTitleText)
3631         return;
3632 
3633     wxString activeTitle;
3634     if(!g_lastAppliedTemplateGUID.IsEmpty()){
3635         activeTitle = ConfigMgr::Get().GetTemplateTitle(g_lastAppliedTemplateGUID);
3636 
3637         bool configCompare = ConfigMgr::Get().CheckTemplateGUID(g_lastAppliedTemplateGUID);
3638         if(!configCompare)
3639             activeTitle += _(" [Modified]");
3640         m_templateTitleText->SetLabel(activeTitle);
3641     }
3642     else
3643         m_templateTitleText->SetLabel(_("None"));
3644 }
3645 
3646 
CreatePanel_Configs(size_t parent,int border_size,int group_item_spacing)3647 void options::CreatePanel_Configs(size_t parent, int border_size, int group_item_spacing)
3648 {
3649     m_DisplayConfigsPage = AddPage(parent, _("Templates"));
3650 
3651     //if (m_bcompact) {
3652     //}
3653     //else
3654     {
3655 
3656         wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
3657         m_DisplayConfigsPage->SetSizer(wrapperSizer);
3658 
3659         // Template management
3660 
3661         wxStaticBox* templateStatusBox = new wxStaticBox(m_DisplayConfigsPage, wxID_ANY, _("Template Status"));
3662         m_templateStatusBoxSizer = new wxStaticBoxSizer(templateStatusBox, wxHORIZONTAL);
3663         wrapperSizer->Add(m_templateStatusBoxSizer, 1, wxALL | wxEXPAND, border_size);
3664 
3665         wxBoxSizer* statSizer = new wxBoxSizer(wxVERTICAL);
3666         m_templateStatusBoxSizer->Add(statSizer, 0, wxALL | wxEXPAND, border_size);
3667 
3668         m_staticTextLastAppled = new wxStaticText(m_DisplayConfigsPage, wxID_ANY, _("Last Applied Template Title:"));
3669         m_staticTextLastAppled->Hide();
3670 
3671         statSizer->Add(m_staticTextLastAppled);
3672 
3673         m_templateTitleText = new wxStaticText(m_DisplayConfigsPage, wxID_ANY, wxEmptyString);
3674         statSizer->Add(m_templateTitleText);
3675         m_templateTitleText->Hide();
3676 
3677         UpdateTemplateTitleText();
3678 
3679 
3680         wxStaticBox* configsBox = new wxStaticBox(m_DisplayConfigsPage, wxID_ANY, _("Saved Templates"));
3681         wxStaticBoxSizer* configSizer = new wxStaticBoxSizer(configsBox, wxHORIZONTAL);
3682         wrapperSizer->Add(configSizer, 4, wxALL | wxEXPAND, border_size);
3683 
3684         wxPanel *cPanel = new wxPanel(m_DisplayConfigsPage, wxID_ANY );
3685         configSizer->Add(cPanel, 1, wxALL | wxEXPAND, border_size);
3686 
3687         wxBoxSizer *boxSizercPanel = new wxBoxSizer(wxVERTICAL);
3688         cPanel->SetSizer(boxSizercPanel);
3689 
3690         m_scrollWinConfigList = new wxScrolledWindow(cPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_RAISED | wxVSCROLL );
3691         m_scrollWinConfigList->SetScrollRate(1, 1);
3692         boxSizercPanel->Add(m_scrollWinConfigList, 0, wxALL|wxEXPAND, border_size);
3693         m_scrollWinConfigList->SetMinSize(wxSize(-1,15 * GetCharHeight()));
3694 
3695         m_boxSizerConfigs = new wxBoxSizer(wxVERTICAL);
3696         m_scrollWinConfigList->SetSizer(m_boxSizerConfigs);
3697 
3698 
3699         wxBoxSizer* btnSizer = new wxBoxSizer(wxVERTICAL);
3700         configSizer->Add(btnSizer);
3701 
3702         //    Add the "Insert/Remove" buttons
3703         wxButton* createButton = new wxButton(m_DisplayConfigsPage, wxID_ANY, _("Create Config..."));
3704         btnSizer->Add(createButton, 1, wxALL | wxEXPAND, group_item_spacing);
3705         createButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(options::OnCreateConfig), NULL, this);
3706 
3707         //wxButton* editButton = new wxButton(m_DisplayConfigsPage, wxID_ANY, _("Edit Config..."));
3708         //btnSizer->Add(editButton, 1, wxALL | wxEXPAND, group_item_spacing);
3709         //editButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(options::OnEditConfig), NULL, this);
3710 
3711         m_configDeleteButton = new wxButton(m_DisplayConfigsPage, wxID_ANY, _("Delete Selected Config..."));
3712         btnSizer->Add(m_configDeleteButton, 1, wxALL | wxEXPAND, group_item_spacing);
3713         m_configDeleteButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(options::OnDeleteConfig), NULL, this);
3714 
3715         m_configApplyButton = new wxButton(m_DisplayConfigsPage, wxID_ANY, _("Apply Selected Config"));
3716         btnSizer->Add(m_configApplyButton, 1, wxALL | wxEXPAND, group_item_spacing);
3717         m_configApplyButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(options::OnApplyConfig), NULL, this);
3718 
3719         // Populate the configs list from the ConfigMgr
3720         ClearConfigList();
3721         BuildConfigList();
3722 
3723         SetConfigButtonState();
3724     }
3725 }
3726 
ClearConfigList()3727 void options::ClearConfigList()
3728 {
3729     if(m_scrollWinConfigList){
3730         wxWindowList kids = m_scrollWinConfigList->GetChildren();
3731         for( unsigned int i = 0; i < kids.GetCount(); i++ ) {
3732             wxWindowListNode *node = kids.Item(i);
3733             wxWindow *win = node->GetData();
3734              wxPanel *pcp = wxDynamicCast(win, wxPanel);
3735              if(pcp){
3736                 ConfigPanel *cPanel = wxDynamicCast(pcp, ConfigPanel);
3737                 if(cPanel){
3738                     cPanel->Destroy();
3739                 }
3740              }
3741         }
3742     }
3743     SetConfigButtonState();
3744 }
3745 
BuildConfigList()3746 void options::BuildConfigList()
3747 {
3748     wxArrayString configGUIDs = ConfigMgr::Get().GetConfigGUIDArray();
3749 
3750     for(size_t i=0 ; i < configGUIDs.GetCount() ; i++){
3751         wxPanel *pp = ConfigMgr::Get().GetConfigPanel( m_scrollWinConfigList,configGUIDs[i]);
3752         if(pp){
3753         m_panelBackgroundUnselected = pp->GetBackgroundColour();
3754         m_boxSizerConfigs->Add(pp, 1, wxEXPAND);
3755         pp->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(options::OnConfigMouseSelected), NULL, this);
3756 
3757         //  Set mouse handler for children of the panel, too.
3758         wxWindowList kids = pp->GetChildren();
3759         for( unsigned int i = 0; i < kids.GetCount(); i++ ) {
3760             wxWindowListNode *node = kids.Item(i);
3761             wxWindow *win = node->GetData();
3762             win->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(options::OnConfigMouseSelected), NULL, this);
3763         }
3764     }
3765     }
3766 
3767     m_boxSizerConfigs->Layout();
3768 
3769     m_selectedConfigPanelGUID = _T("");
3770     SetConfigButtonState();
3771 }
3772 
SetConfigButtonState()3773 void options::SetConfigButtonState()
3774 {
3775     m_configDeleteButton->Enable(!m_selectedConfigPanelGUID.IsEmpty());
3776     if(m_selectedConfigPanelGUID.StartsWith(_T("11111111")))            // Cannot delete "Recovery" template
3777         m_configDeleteButton->Disable();
3778     m_configApplyButton->Enable(!m_selectedConfigPanelGUID.IsEmpty());
3779 }
3780 
OnCreateConfig(wxCommandEvent & event)3781 void options::OnCreateConfig( wxCommandEvent &event)
3782 {
3783     ConfigCreateDialog* pd = new ConfigCreateDialog(this, -1, _("Create Config"), wxDefaultPosition, wxSize(200, 200));
3784     DimeControl( pd );
3785     pd->ShowWindowModalThenDo([this,pd](int retcode){
3786         if ( retcode == wxID_OK ) {
3787             g_lastAppliedTemplateGUID = pd->GetCreatedTemplateGUID();
3788             UpdateTemplateTitleText();
3789 
3790             ClearConfigList();
3791             BuildConfigList();
3792             m_DisplayConfigsPage->Layout();
3793         }
3794         SetConfigButtonState();
3795     });
3796 }
3797 
OnEditConfig(wxCommandEvent & event)3798 void options::OnEditConfig( wxCommandEvent &event)
3799 {
3800 }
3801 
OnDeleteConfig(wxCommandEvent & event)3802 void options::OnDeleteConfig( wxCommandEvent &event)
3803 {
3804     if(m_selectedConfigPanelGUID.IsEmpty())
3805         return;
3806 
3807     ConfigMgr::Get().DeleteConfig( m_selectedConfigPanelGUID);
3808     m_selectedConfigPanelGUID = _T("");
3809 
3810     ClearConfigList();
3811     BuildConfigList();
3812 
3813     m_DisplayConfigsPage->Layout();
3814     SetConfigButtonState();
3815 }
3816 
OnApplyConfig(wxCommandEvent & event)3817 void options::OnApplyConfig( wxCommandEvent &event)
3818 {
3819     if(m_selectedConfigPanelGUID.IsEmpty())
3820         return;
3821 
3822     // Record a few special items
3823     wxString currentLocale = g_locale;
3824 
3825     //  Apply any changed settings other than the target config template.
3826     wxCommandEvent evt;
3827     evt.SetId(ID_APPLY);
3828     OnApplyClick(evt);
3829 
3830     // Then Apply the target config template
3831     bool bApplyStat = ConfigMgr::Get().ApplyConfigGUID( m_selectedConfigPanelGUID);
3832     if(bApplyStat){
3833 //        OCPNMessageBox(this, _("Configuration successfully applied."), _("OpenCPN Info"), wxOK);
3834         g_lastAppliedTemplateGUID = m_selectedConfigPanelGUID;
3835         wxString activeTitle = ConfigMgr::Get().GetTemplateTitle(g_lastAppliedTemplateGUID);
3836         m_templateTitleText->SetLabel(activeTitle);
3837         m_templateTitleText->Show();
3838         m_staticTextLastAppled->Show();
3839         m_templateStatusBoxSizer->Layout();
3840     }
3841     else
3842         OCPNMessageBox(this, _("Problem applying selected configuration."), _("OpenCPN Info"), wxOK);
3843 
3844     //  Clear all selections
3845     if(m_scrollWinConfigList){
3846         wxWindowList kids = m_scrollWinConfigList->GetChildren();
3847         for( unsigned int i = 0; i < kids.GetCount(); i++ ) {
3848             wxWindowListNode *node = kids.Item(i);
3849             wxWindow *win = node->GetData();
3850              wxPanel *pcp = wxDynamicCast(win, wxPanel);
3851              if(pcp){
3852                 ConfigPanel *cPanel = wxDynamicCast(pcp, ConfigPanel);
3853                 if(cPanel){
3854                     cPanel->SetBackgroundColour(m_panelBackgroundUnselected);
3855                 }
3856              }
3857         }
3858     }
3859     m_selectedConfigPanelGUID = wxEmptyString;
3860 
3861     m_returnChanges |= CONFIG_CHANGED;
3862 
3863     if(!currentLocale.IsSameAs(g_locale))
3864         m_returnChanges |= LOCALE_CHANGED;
3865 
3866     Finish();
3867 }
3868 
3869 
OnConfigMouseSelected(wxMouseEvent & event)3870 void options::OnConfigMouseSelected( wxMouseEvent &event)
3871 {
3872     wxPanel *selectedPanel = NULL;
3873     wxObject* obj = event.GetEventObject();
3874     if(obj){
3875         wxPanel *panel = wxDynamicCast(obj, wxPanel);
3876         if(panel){
3877             selectedPanel = panel;
3878         }
3879         //Clicked on child?
3880         else{
3881             wxWindow *win = wxDynamicCast(obj, wxWindow);
3882             if(win){
3883                 wxPanel *parentpanel = wxDynamicCast(win->GetParent(), wxPanel);
3884                 if(parentpanel){
3885                     selectedPanel = parentpanel;
3886                 }
3887             }
3888         }
3889 
3890         if(m_scrollWinConfigList){
3891             wxWindowList kids = m_scrollWinConfigList->GetChildren();
3892             for( unsigned int i = 0; i < kids.GetCount(); i++ ) {
3893                 wxWindowListNode *node = kids.Item(i);
3894                 wxWindow *win = node->GetData();
3895                 wxPanel *panel = wxDynamicCast(win, wxPanel);
3896                 if(panel){
3897                     if(panel == selectedPanel ){
3898                     wxColour colour;
3899                     GetGlobalColor(_T("UIBCK"), &colour);
3900                     panel->SetBackgroundColour(colour);
3901                     ConfigPanel *cPanel = wxDynamicCast(panel, ConfigPanel);
3902                     if(cPanel)
3903                         m_selectedConfigPanelGUID = cPanel->GetConfigGUID();
3904                 }
3905                 else
3906                     panel->SetBackgroundColour(m_panelBackgroundUnselected);
3907 
3908                 panel->Refresh(true);
3909             }
3910         }
3911         }
3912         m_DisplayConfigsPage->Layout();
3913         SetConfigButtonState();
3914     }
3915 }
3916 
3917 
3918 
CreatePanel_Advanced(size_t parent,int border_size,int group_item_spacing)3919 void options::CreatePanel_Advanced(size_t parent, int border_size,
3920                                    int group_item_spacing) {
3921   m_ChartDisplayPage = AddPage(parent, _("Advanced"));
3922 
3923   if (m_bcompact) {
3924     wxSize sz = g_Platform->getDisplaySize();
3925     double dpmm = g_Platform->GetDisplayDPmm();
3926 
3927     wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
3928     m_ChartDisplayPage->SetSizer(wrapperSizer);
3929 
3930     wxBoxSizer* itemBoxSizerUI = wrapperSizer;
3931 
3932     // spacer
3933     itemBoxSizerUI->Add(0, border_size * 3);
3934     itemBoxSizerUI->Add(0, border_size * 3);
3935 
3936     // Chart Display Options
3937     wxBoxSizer* boxCharts = new wxBoxSizer(wxVERTICAL);
3938     itemBoxSizerUI->Add(boxCharts, groupInputFlags);
3939 
3940     pSkewComp = new wxCheckBox(m_ChartDisplayPage, ID_SKEWCOMPBOX,
3941                                _("De-skew Raster Charts"));
3942     boxCharts->Add(pSkewComp, inputFlags);
3943 
3944     itemBoxSizerUI->Add(0, border_size * 3);
3945     itemBoxSizerUI->Add(0, border_size * 3);
3946 
3947     // OpenGL Options
3948     wxBoxSizer* OpenGLSizer = new wxBoxSizer(wxVERTICAL);
3949     itemBoxSizerUI->Add(OpenGLSizer, 0, 0, 0);
3950 
3951     pOpenGL = new wxCheckBox(m_ChartDisplayPage, ID_OPENGLBOX,
3952                              _("Use Accelerated Graphics (OpenGL)"));
3953     OpenGLSizer->Add(pOpenGL, inputFlags);
3954     pOpenGL->Enable(!g_bdisable_opengl);
3955 
3956 
3957     wxButton* bOpenGL =
3958         new wxButton(m_ChartDisplayPage, ID_OPENGLOPTIONS, _("OpenGL Options") + _T("..."));
3959     OpenGLSizer->Add(bOpenGL, inputFlags);
3960     bOpenGL->Enable(!g_bdisable_opengl);
3961 
3962 #ifdef __OCPN__ANDROID__
3963     pOpenGL->Hide();
3964     bOpenGL->Hide();
3965 #endif
3966 
3967     itemBoxSizerUI->Add(0, border_size * 3);
3968     itemBoxSizerUI->Add(0, border_size * 3);
3969 
3970     //  Course Up display update period
3971     wxStaticText *crat = new wxStaticText(m_ChartDisplayPage, wxID_ANY,  _("Chart Rotation Averaging Time"));
3972     crat->Wrap(-1);
3973     wrapperSizer->Add(crat, 0, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL, group_item_spacing);
3974 
3975 
3976     wxBoxSizer* pCOGUPFilterRow = new wxBoxSizer(wxHORIZONTAL);
3977     wrapperSizer->Add(pCOGUPFilterRow, 0, wxALL | wxEXPAND, group_item_spacing);
3978 
3979     pCOGUPUpdateSecs =
3980         new wxTextCtrl(m_ChartDisplayPage, ID_OPTEXTCTRL, _T(""), wxDefaultPosition, wxSize(sz.x / 5, -1), wxTE_RIGHT);
3981     pCOGUPFilterRow->Add(pCOGUPUpdateSecs, 0, wxALIGN_RIGHT | wxALL, group_item_spacing);
3982 
3983     pCOGUPFilterRow->Add( new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("seconds")), inputFlags);
3984 
3985     itemBoxSizerUI->Add(0, border_size * 3);
3986     itemBoxSizerUI->Add(0, border_size * 3);
3987 
3988     // Chart Zoom Scale Weighting
3989     wxStaticText* zoomTextHead =  new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Chart Zoom/Scale Weighting"));
3990      zoomTextHead->Wrap(-1);
3991      itemBoxSizerUI->Add(zoomTextHead, 0, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL, group_item_spacing);
3992      itemBoxSizerUI->Add(0, border_size * 1);
3993 
3994     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Raster")), inputFlags);
3995 
3996     m_pSlider_Zoom = new wxSlider(m_ChartDisplayPage, ID_RASTERZOOM, 0, -5, 5,
3997                                   wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
3998 
3999 #ifdef __OCPN__ANDROID__
4000      prepareSlider(m_pSlider_Zoom);
4001 #endif
4002 
4003     itemBoxSizerUI->Add(m_pSlider_Zoom, inputFlags);
4004 
4005     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Vector")), inputFlags);
4006 
4007     m_pSlider_Zoom_Vector = new wxSlider( m_ChartDisplayPage, ID_VECZOOM, 0, -5, 5,
4008                                           wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
4009 
4010 #ifdef __OCPN__ANDROID__
4011      prepareSlider(m_pSlider_Zoom_Vector);
4012 #endif
4013 
4014     itemBoxSizerUI->Add(m_pSlider_Zoom_Vector, inputFlags);
4015 
4016     itemBoxSizerUI->Add(
4017         new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("CM93 Detail level")), inputFlags);
4018     m_pSlider_CM93_Zoom = new wxSlider( m_ChartDisplayPage, ID_CM93ZOOM, 0,
4019                            -CM93_ZOOM_FACTOR_MAX_RANGE, CM93_ZOOM_FACTOR_MAX_RANGE,
4020                            wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
4021 
4022 #ifdef __OCPN__ANDROID__
4023     prepareSlider(m_pSlider_CM93_Zoom);
4024 #endif
4025 
4026     itemBoxSizerUI->Add(m_pSlider_CM93_Zoom, 0, wxALL, border_size);
4027 
4028 
4029     itemBoxSizerUI->Add(0, border_size * 3);
4030     itemBoxSizerUI->Add(0, border_size * 3);
4031     itemBoxSizerUI->Add(0, border_size * 3);
4032 
4033     //  Display size/DPI
4034     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage,
4035         wxID_ANY, _("Physical Screen Width")), inputFlags);
4036     wxBoxSizer* pDPIRow = new wxBoxSizer(wxHORIZONTAL);
4037     itemBoxSizerUI->Add(pDPIRow, 0, wxEXPAND);
4038 
4039     pRBSizeAuto = new wxRadioButton(m_ChartDisplayPage, wxID_ANY, _("Auto"));
4040     pDPIRow->Add(pRBSizeAuto, inputFlags);
4041     pDPIRow->AddSpacer(10);
4042     pRBSizeManual = new wxRadioButton(m_ChartDisplayPage, ID_SIZEMANUALRADIOBUTTON, _("Manual:"));
4043     pDPIRow->Add(pRBSizeManual, inputFlags);
4044 
4045     wxBoxSizer* pmmRow = new wxBoxSizer(wxHORIZONTAL);
4046     itemBoxSizerUI->Add(pmmRow, 0, wxEXPAND);
4047 
4048     pScreenMM = new wxTextCtrl(m_ChartDisplayPage, ID_OPTEXTCTRL, _T(""), wxDefaultPosition, wxSize(sz.x / 5, -1), wxTE_RIGHT);
4049     pmmRow->Add(pScreenMM, 0, wxALIGN_RIGHT | wxALL, group_item_spacing);
4050 
4051     pmmRow->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("mm")), inputFlags);
4052 
4053     pRBSizeAuto->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
4054                          wxCommandEventHandler(options::OnSizeAutoButton), NULL,
4055                          this);
4056     pRBSizeManual->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
4057                            wxCommandEventHandler(options::OnSizeManualButton),
4058                            NULL, this);
4059 
4060   }
4061 
4062   else {
4063     wxFlexGridSizer* itemBoxSizerUI = new wxFlexGridSizer(2);
4064     itemBoxSizerUI->SetHGap(border_size);
4065     //    itemBoxSizerUI->AddGrowableCol( 0, 1 );
4066     //    itemBoxSizerUI->AddGrowableCol( 1, 1 );
4067     //    m_ChartDisplayPage->SetSizer( itemBoxSizerUI );
4068 
4069     // wxFlexGridSizer grows wrongly in wx2.8, so we need to centre it in
4070     // another sizer instead of letting it grow.
4071     wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
4072     m_ChartDisplayPage->SetSizer(wrapperSizer);
4073     wrapperSizer->Add(itemBoxSizerUI, 1, wxALL | wxALIGN_CENTER, border_size);
4074 
4075     // spacer
4076     itemBoxSizerUI->Add(0, border_size * 3);
4077     itemBoxSizerUI->Add(0, border_size * 3);
4078 
4079     // Chart Display Options
4080     itemBoxSizerUI->Add(
4081         new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Chart Display")),
4082         groupLabelFlags);
4083     wxBoxSizer* boxCharts = new wxBoxSizer(wxVERTICAL);
4084     itemBoxSizerUI->Add(boxCharts, groupInputFlags);
4085 
4086     pSkewComp = new wxCheckBox(m_ChartDisplayPage, ID_SKEWCOMPBOX,
4087                                _("Show Skewed Raster Charts as North-Up"));
4088     boxCharts->Add(pSkewComp, verticleInputFlags);
4089 
4090 //     pFullScreenQuilt = new wxCheckBox(m_ChartDisplayPage, ID_FULLSCREENQUILT,
4091 //                                       _("Disable Full Screen Quilting"));
4092 //     boxCharts->Add(pFullScreenQuilt, verticleInputFlags);
4093 
4094 //     pOverzoomEmphasis =
4095 //         new wxCheckBox(m_ChartDisplayPage, ID_FULLSCREENQUILT,
4096 //                        _("Suppress blur/fog effects on overzoom"));
4097 //     boxCharts->Add(pOverzoomEmphasis, verticleInputFlags);
4098 //
4099 //     pOZScaleVector =
4100 //         new wxCheckBox(m_ChartDisplayPage, ID_FULLSCREENQUILT,
4101 //                        _("Suppress scaled vector charts on overzoom"));
4102 //     boxCharts->Add(pOZScaleVector, verticleInputFlags);
4103 
4104     // spacer
4105     itemBoxSizerUI->Add(0, border_size * 3);
4106     itemBoxSizerUI->Add(0, border_size * 3);
4107 
4108     //  Course Up display update period
4109     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY,
4110                                          _("Chart Rotation Averaging Time")),
4111                         labelFlags);
4112     wxBoxSizer* pCOGUPFilterRow = new wxBoxSizer(wxHORIZONTAL);
4113     itemBoxSizerUI->Add(pCOGUPFilterRow, 0, wxALL | wxEXPAND,
4114                         group_item_spacing);
4115 
4116     pCOGUPUpdateSecs =
4117         new wxTextCtrl(m_ChartDisplayPage, ID_OPTEXTCTRL, _T(""),
4118                        wxDefaultPosition, wxSize(50, -1), wxTE_RIGHT);
4119     pCOGUPFilterRow->Add(pCOGUPUpdateSecs, 0, wxALL,
4120                          group_item_spacing);
4121 
4122     pCOGUPFilterRow->Add(
4123         new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("seconds")),
4124         inputFlags);
4125 
4126     // spacer
4127     itemBoxSizerUI->Add(0, border_size * 8);
4128     itemBoxSizerUI->Add(0, border_size * 8);
4129 
4130     // Chart Zoom Scale Weighting
4131     wxStaticText* zoomTextHead =  new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Chart Zoom/Scale Weighting"));
4132 
4133     itemBoxSizerUI->Add(zoomTextHead, labelFlags);
4134     itemBoxSizerUI->Add(0, border_size * 1);
4135     itemBoxSizerUI->Add(0, border_size * 1);
4136 
4137     wxStaticText* zoomText =
4138         new wxStaticText(m_ChartDisplayPage, wxID_ANY,
4139             _("With a lower value, the same zoom level shows a less detailed chart.\n\
4140 With a higher value, the same zoom level shows a more detailed chart."));
4141 
4142     smallFont = *dialogFont;  // we can't use Smaller() because
4143                               // wx2.8 doesn't support it
4144     smallFont.SetPointSize((smallFont.GetPointSize() / 1.2) +
4145         0.5);  // + 0.5 to round instead of truncate
4146     zoomText->SetFont(smallFont);
4147     itemBoxSizerUI->Add(zoomText, 0, wxALL | wxEXPAND, group_item_spacing);
4148 
4149     // spacer
4150     /*itemBoxSizerUI->Add(0, border_size * 8); itemBoxSizerUI->Add(0, border_size * 8);*/
4151 
4152     //wxSize sz = g_Platform->getDisplaySize();
4153 
4154     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Raster")), labelFlags);
4155     m_pSlider_Zoom = new wxSlider(m_ChartDisplayPage, ID_RASTERZOOM, 0, -5, 5, wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
4156 
4157 #ifdef __OCPN__ANDROID__
4158     prepareSlider( m_pSlider_Zoom );
4159 #endif
4160 
4161     itemBoxSizerUI->Add(m_pSlider_Zoom, inputFlags);
4162 
4163     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Vector")), labelFlags);
4164     m_pSlider_Zoom_Vector = new wxSlider(m_ChartDisplayPage, ID_VECZOOM, 0, -5, 5,
4165                                          wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
4166 
4167 #ifdef __OCPN__ANDROID__
4168     prepareSlider( m_pSlider_Zoom_Vector );
4169 #endif
4170 
4171     itemBoxSizerUI->Add(m_pSlider_Zoom_Vector, inputFlags);
4172 
4173     //Spacer
4174     itemBoxSizerUI->Add(0, border_size * 3); itemBoxSizerUI->Add(0, border_size * 3);
4175 
4176     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY,
4177         _("CM93 Detail level")), labelFlags);
4178     m_pSlider_CM93_Zoom = new wxSlider(m_ChartDisplayPage, ID_CM93ZOOM, 0,
4179         -CM93_ZOOM_FACTOR_MAX_RANGE, CM93_ZOOM_FACTOR_MAX_RANGE,
4180         wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
4181 
4182 #ifdef __OCPN__ANDROID__
4183     prepareSlider(m_pSlider_CM93_Zoom);
4184 #endif
4185 
4186     itemBoxSizerUI->Add(m_pSlider_CM93_Zoom, 0, wxALL, border_size);
4187 
4188     // spacer
4189     itemBoxSizerUI->Add(0, border_size * 3); itemBoxSizerUI->Add(0, border_size * 3);
4190     itemBoxSizerUI->Add(0, border_size * 3); itemBoxSizerUI->Add(0, border_size * 3);
4191     itemBoxSizerUI->Add(0, border_size * 3); itemBoxSizerUI->Add(0, border_size * 3);
4192 
4193     //  Display size/DPI
4194     itemBoxSizerUI->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY,
4195                                          _("Physical Screen Width")),
4196                         labelFlags);
4197     wxBoxSizer* pDPIRow = new wxBoxSizer(wxHORIZONTAL);
4198     itemBoxSizerUI->Add(pDPIRow, 0, wxEXPAND);
4199 
4200     pRBSizeAuto = new wxRadioButton(m_ChartDisplayPage, wxID_ANY, _("Auto"));
4201     pDPIRow->Add(pRBSizeAuto, inputFlags);
4202     pDPIRow->AddSpacer(10);
4203     pRBSizeManual = new wxRadioButton(m_ChartDisplayPage,
4204                                       ID_SIZEMANUALRADIOBUTTON, _("Manual:"));
4205     pDPIRow->Add(pRBSizeManual, inputFlags);
4206 
4207     pScreenMM = new wxTextCtrl(m_ChartDisplayPage, ID_OPTEXTCTRL, _T(""),
4208                                wxDefaultPosition, wxSize(3 * m_fontHeight, -1),
4209                                wxTE_RIGHT);
4210     pDPIRow->Add(pScreenMM, 0, wxALL, group_item_spacing);
4211 
4212     pDPIRow->Add(new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("mm")),
4213                  inputFlags);
4214 
4215     pRBSizeAuto->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
4216                          wxCommandEventHandler(options::OnSizeAutoButton), NULL,
4217                          this);
4218     pRBSizeManual->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
4219                            wxCommandEventHandler(options::OnSizeManualButton),
4220                            NULL, this);
4221 
4222     // spacer
4223     itemBoxSizerUI->Add(0, border_size * 3);
4224     itemBoxSizerUI->Add(0, border_size * 3);
4225 
4226     // OpenGL Options
4227     itemBoxSizerUI->Add(
4228         new wxStaticText(m_ChartDisplayPage, wxID_ANY, _("Graphics")),
4229         labelFlags);
4230     wxBoxSizer* OpenGLSizer = new wxBoxSizer(wxHORIZONTAL);
4231     itemBoxSizerUI->Add(OpenGLSizer, 0, 0, 0);
4232 
4233     pOpenGL = new wxCheckBox(m_ChartDisplayPage, ID_OPENGLBOX,
4234                              _("Use Accelerated Graphics (OpenGL)"));
4235     OpenGLSizer->Add(pOpenGL, inputFlags);
4236     pOpenGL->Enable(!g_bdisable_opengl);
4237 
4238 #ifdef __OCPN__ANDROID__
4239     pOpenGL->Disable();
4240 #endif
4241 
4242     wxButton* bOpenGL =
4243         new wxButton(m_ChartDisplayPage, ID_OPENGLOPTIONS, _("Options") + _T("..."));
4244     OpenGLSizer->Add(bOpenGL, inputFlags);
4245     bOpenGL->Enable(!g_bdisable_opengl);
4246 
4247     itemBoxSizerUI->Add(0, border_size * 3);
4248 /*
4249     pTransparentToolbar =
4250         new wxCheckBox(m_ChartDisplayPage, ID_TRANSTOOLBARCHECKBOX,
4251                        _("Enable Transparent Toolbar"));
4252     itemBoxSizerUI->Add(pTransparentToolbar, 0, wxALL, border_size);
4253     if (g_bopengl && !g_bTransparentToolbarInOpenGLOK)
4254       pTransparentToolbar->Disable();
4255 */
4256   }
4257 }
4258 
CreatePanel_VectorCharts(size_t parent,int border_size,int group_item_spacing)4259 void options::CreatePanel_VectorCharts(size_t parent, int border_size,
4260                                        int group_item_spacing) {
4261   ps57Ctl = AddPage(parent, _("Vector Chart Display"));
4262 
4263   if (!m_bcompact) {
4264     vectorPanel = new wxBoxSizer(wxHORIZONTAL);
4265     ps57Ctl->SetSizer(vectorPanel);
4266 
4267     // 1st column, all options except Mariner's Standard
4268     wxFlexGridSizer* optionsColumn = new wxFlexGridSizer(2);
4269     optionsColumn->SetHGap(border_size);
4270     optionsColumn->AddGrowableCol(0, 2);
4271     optionsColumn->AddGrowableCol(1, 3);
4272     vectorPanel->Add(optionsColumn, 3, wxALL | wxEXPAND, border_size);
4273 
4274     // spacer
4275     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _T("")));
4276     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _T("")));
4277 
4278     if(!g_useMUI){
4279     // display category
4280         optionsColumn->Add( new wxStaticText(ps57Ctl, wxID_ANY, _("Display Category")), labelFlags);
4281         wxString pDispCatStrings[] = {_("Base"), _("Standard"), _("All"), _("Mariner's Standard")};
4282         pDispCat = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4283                             wxDefaultSize, 4, pDispCatStrings);
4284         optionsColumn->Add(pDispCat, 0, wxALL, 2);
4285     }
4286 
4287     // spacer
4288     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _T("")));
4289     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _T("")));
4290 
4291 
4292     // display options
4293     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Display")), groupLabelFlags);
4294 
4295     wxBoxSizer* miscSizer = new wxBoxSizer(wxVERTICAL);
4296     optionsColumn->Add(miscSizer, groupInputFlags);
4297 
4298     if(!g_useMUI){
4299         pCheck_SOUNDG = new wxCheckBox(ps57Ctl, ID_SOUNDGCHECKBOX, _("Depth Soundings"));
4300         pCheck_SOUNDG->SetValue(FALSE);
4301         miscSizer->Add(pCheck_SOUNDG, verticleInputFlags);
4302     }
4303 
4304     pCheck_META = new wxCheckBox(ps57Ctl, ID_METACHECKBOX, _("Chart Information Objects"));
4305     pCheck_META->SetValue(FALSE);
4306     miscSizer->Add(pCheck_META, verticleInputFlags);
4307 
4308 
4309     if(!g_useMUI){
4310         optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Buoys/Lights")), groupLabelFlags);
4311 
4312         wxBoxSizer* lightSizer = new wxBoxSizer(wxVERTICAL);
4313         optionsColumn->Add(lightSizer, groupInputFlags);
4314 
4315         pCheck_ATONTEXT = new wxCheckBox(ps57Ctl, ID_ATONTEXTCHECKBOX, _("Buoy/Light Labels"));
4316         pCheck_ATONTEXT->SetValue(FALSE);
4317         lightSizer->Add(pCheck_ATONTEXT, verticleInputFlags);
4318 
4319         pCheck_LDISTEXT = new wxCheckBox(ps57Ctl, ID_LDISTEXTCHECKBOX, _("Light Descriptions"));
4320         pCheck_LDISTEXT->SetValue(FALSE);
4321         lightSizer->Add(pCheck_LDISTEXT, verticleInputFlags);
4322 
4323         pCheck_XLSECTTEXT = new wxCheckBox(ps57Ctl, ID_LDISTEXTCHECKBOX, _("Extended Light Sectors"));
4324         pCheck_XLSECTTEXT->SetValue(FALSE);
4325         lightSizer->Add(pCheck_XLSECTTEXT, verticleInputFlags);
4326     }
4327 
4328     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Chart Texts")), groupLabelFlags);
4329 
4330     wxBoxSizer* textSizer = new wxBoxSizer(wxVERTICAL);
4331     optionsColumn->Add(textSizer, groupInputFlags);
4332 
4333     pCheck_NATIONALTEXT = new wxCheckBox(ps57Ctl, ID_NATIONALTEXTCHECKBOX, _("National text on chart"));
4334     pCheck_NATIONALTEXT->SetValue(FALSE);
4335     textSizer->Add(pCheck_NATIONALTEXT, verticleInputFlags);
4336 
4337     pCheck_SHOWIMPTEXT =
4338         new wxCheckBox(ps57Ctl, ID_IMPTEXTCHECKBOX, _("Important Text Only"));
4339     pCheck_SHOWIMPTEXT->SetValue(FALSE);
4340     textSizer->Add(pCheck_SHOWIMPTEXT, verticleInputFlags);
4341 
4342     pCheck_DECLTEXT =
4343         new wxCheckBox(ps57Ctl, ID_DECLTEXTCHECKBOX, _("De-Cluttered Text"));
4344     pCheck_DECLTEXT->SetValue(FALSE);
4345     textSizer->Add(pCheck_DECLTEXT, verticleInputFlags);
4346 
4347     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Chart Detail")),
4348                        labelFlags);
4349     pCheck_SCAMIN = new wxCheckBox(ps57Ctl, ID_SCAMINCHECKBOX,
4350                                    _("Reduced Detail at Small Scale"));
4351     pCheck_SCAMIN->SetValue(FALSE);
4352     optionsColumn->Add(pCheck_SCAMIN, inputFlags);
4353 
4354     // spacer
4355     optionsColumn->Add(0, border_size * 4);
4356     optionsColumn->Add(0, border_size * 4);
4357 
4358     // graphics options
4359     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Graphics Style")),
4360                        labelFlags);
4361     wxString pPointStyleStrings[] = {
4362         _("Paper Chart"), _("Simplified"),
4363     };
4364     pPointStyle = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4365                                wxDefaultSize, 2, pPointStyleStrings);
4366     optionsColumn->Add(pPointStyle, inputFlags);
4367 
4368     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Boundaries")),
4369                        labelFlags);
4370     wxString pBoundStyleStrings[] = {
4371         _("Plain"), _("Symbolized"),
4372     };
4373     pBoundStyle = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4374                                wxDefaultSize, 2, pBoundStyleStrings);
4375     optionsColumn->Add(pBoundStyle, inputFlags);
4376 
4377     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Colors")),
4378                        labelFlags);
4379     wxString pColorNumStrings[] = {
4380         _("2 Color"), _("4 Color"),
4381     };
4382     p24Color = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4383                             wxDefaultSize, 2, pColorNumStrings);
4384     optionsColumn->Add(p24Color, inputFlags);
4385 
4386     // spacer
4387     optionsColumn->Add(0, border_size * 4);
4388     optionsColumn->Add(0, border_size * 4);
4389 
4390     // depth options
4391     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Shallow Depth")),
4392                        labelFlags);
4393     wxBoxSizer* depShalRow = new wxBoxSizer(wxHORIZONTAL);
4394     optionsColumn->Add(depShalRow);
4395     m_ShallowCtl =
4396         new wxTextCtrl(ps57Ctl, ID_OPTEXTCTRL, _T(""), wxDefaultPosition,
4397                        wxSize(60, -1), wxTE_RIGHT);
4398     depShalRow->Add(m_ShallowCtl, inputFlags);
4399     m_depthUnitsShal = new wxStaticText(ps57Ctl, wxID_ANY, _("meters"));
4400     depShalRow->Add(m_depthUnitsShal, inputFlags);
4401 
4402     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Safety Depth")),
4403                        labelFlags);
4404     wxBoxSizer* depSafeRow = new wxBoxSizer(wxHORIZONTAL);
4405     optionsColumn->Add(depSafeRow);
4406     m_SafetyCtl = new wxTextCtrl(ps57Ctl, ID_OPTEXTCTRL, _T(""),
4407                                  wxDefaultPosition, wxSize(60, -1), wxTE_RIGHT);
4408     depSafeRow->Add(m_SafetyCtl, inputFlags);
4409     m_depthUnitsSafe = new wxStaticText(ps57Ctl, wxID_ANY, _("meters"));
4410     depSafeRow->Add(m_depthUnitsSafe, inputFlags);
4411 
4412     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Deep Depth")),
4413                        labelFlags);
4414     wxBoxSizer* depDeepRow = new wxBoxSizer(wxHORIZONTAL);
4415     optionsColumn->Add(depDeepRow);
4416     m_DeepCtl = new wxTextCtrl(ps57Ctl, ID_OPTEXTCTRL, _T(""),
4417                                wxDefaultPosition, wxSize(60, -1), wxTE_RIGHT);
4418     depDeepRow->Add(m_DeepCtl, inputFlags);
4419     m_depthUnitsDeep = new wxStaticText(ps57Ctl, wxID_ANY, _("meters"));
4420     depDeepRow->Add(m_depthUnitsDeep, inputFlags);
4421 
4422 
4423     // 2nd column, Display Category / Mariner's Standard options
4424     wxBoxSizer* dispSizer = new wxBoxSizer(wxVERTICAL);
4425     vectorPanel->Add(dispSizer, 2, wxALL | wxEXPAND, border_size);
4426 
4427     wxStaticBox* marinersBox =
4428         new wxStaticBox(ps57Ctl, wxID_ANY, _("User Standard Objects"));
4429     wxStaticBoxSizer* marinersSizer =
4430         new wxStaticBoxSizer(marinersBox, wxVERTICAL);
4431     dispSizer->Add(marinersSizer, 1, wxALL | wxEXPAND, border_size);
4432 
4433     ps57CtlListBox = new OCPNCheckedListCtrl(
4434         ps57Ctl, ID_CHECKLISTBOX, wxDefaultPosition, wxSize(250, 350));
4435     marinersSizer->Add(ps57CtlListBox, 1, wxALL | wxEXPAND, group_item_spacing);
4436 
4437     wxBoxSizer* btnRow1 = new wxBoxSizer(wxHORIZONTAL);
4438     itemButtonSelectList =  new wxButton(ps57Ctl, ID_SELECTLIST, _("Select All"));
4439     btnRow1->Add(itemButtonSelectList, 1, wxALL | wxEXPAND, group_item_spacing);
4440     itemButtonClearList = new wxButton(ps57Ctl, ID_CLEARLIST, _("Clear All"));
4441     btnRow1->Add(itemButtonClearList, 1, wxALL | wxEXPAND, group_item_spacing);
4442     marinersSizer->Add(btnRow1);
4443 
4444     wxBoxSizer* btnRow2 = new wxBoxSizer(wxHORIZONTAL);
4445     itemButtonSetStd = new wxButton(ps57Ctl, ID_SETSTDLIST, _("Reset to STANDARD"));
4446     btnRow2->Add(itemButtonSetStd, 1, wxALL | wxEXPAND, group_item_spacing);
4447     marinersSizer->Add(btnRow2);
4448 
4449 
4450   }
4451 
4452   else {                // compact
4453     vectorPanel = new wxBoxSizer(wxVERTICAL);
4454     ps57Ctl->SetSizer(vectorPanel);
4455 
4456     wxBoxSizer* optionsColumn = vectorPanel;
4457 
4458     // spacer
4459     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _T("")));
4460 
4461     // display category
4462     if(!g_useMUI){
4463         optionsColumn->Add( new wxStaticText(ps57Ctl, wxID_ANY, _("Display Category")), inputFlags);
4464         wxString pDispCatStrings[] = {_("Base"), _("Standard"), _("All"), _("Mariner's Standard")};
4465         pDispCat = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4466                             wxSize(350, -1), 4, pDispCatStrings);
4467         optionsColumn->Add(pDispCat, 0, wxALL, 2);
4468 
4469     // spacer
4470     optionsColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _T("")));
4471 
4472     }
4473 
4474     // display options
4475 
4476     wxBoxSizer* miscSizer = new wxBoxSizer(wxVERTICAL);
4477     optionsColumn->Add(miscSizer, groupInputFlags);
4478 
4479     pCheck_SOUNDG =
4480         new wxCheckBox(ps57Ctl, ID_SOUNDGCHECKBOX, _("Depth Soundings"));
4481     pCheck_SOUNDG->SetValue(FALSE);
4482     miscSizer->Add(pCheck_SOUNDG, inputFlags);
4483 
4484     pCheck_META = new wxCheckBox(ps57Ctl, ID_METACHECKBOX,
4485                                  _("Chart Information Objects"));
4486     pCheck_META->SetValue(FALSE);
4487     miscSizer->Add(pCheck_META, inputFlags);
4488 
4489     wxBoxSizer* lightSizer = new wxBoxSizer(wxVERTICAL);
4490     optionsColumn->Add(lightSizer, groupInputFlags);
4491 
4492     pCheck_ATONTEXT =
4493         new wxCheckBox(ps57Ctl, ID_ATONTEXTCHECKBOX, _("Buoy/Light Labels"));
4494     pCheck_ATONTEXT->SetValue(FALSE);
4495     lightSizer->Add(pCheck_ATONTEXT, inputFlags);
4496 
4497     pCheck_LDISTEXT =
4498         new wxCheckBox(ps57Ctl, ID_LDISTEXTCHECKBOX, _("Light Descriptions"));
4499     pCheck_LDISTEXT->SetValue(FALSE);
4500     lightSizer->Add(pCheck_LDISTEXT, inputFlags);
4501 
4502     pCheck_XLSECTTEXT = new wxCheckBox(ps57Ctl, ID_LDISTEXTCHECKBOX, _("Extended Light Sectors"));
4503     pCheck_XLSECTTEXT->SetValue(FALSE);
4504     lightSizer->Add(pCheck_XLSECTTEXT, inputFlags);
4505 
4506     wxBoxSizer* textSizer = new wxBoxSizer(wxVERTICAL);
4507     optionsColumn->Add(textSizer, groupInputFlags);
4508 
4509     pCheck_NATIONALTEXT = new wxCheckBox(ps57Ctl, ID_NATIONALTEXTCHECKBOX,
4510                                          _("National text on chart"));
4511     pCheck_NATIONALTEXT->SetValue(FALSE);
4512     textSizer->Add(pCheck_NATIONALTEXT, inputFlags);
4513 
4514     pCheck_SHOWIMPTEXT =
4515         new wxCheckBox(ps57Ctl, ID_IMPTEXTCHECKBOX, _("Important Text Only"));
4516     pCheck_SHOWIMPTEXT->SetValue(FALSE);
4517     textSizer->Add(pCheck_SHOWIMPTEXT, inputFlags);
4518 
4519     pCheck_DECLTEXT =
4520         new wxCheckBox(ps57Ctl, ID_DECLTEXTCHECKBOX, _("De-Cluttered Text"));
4521     pCheck_DECLTEXT->SetValue(FALSE);
4522     textSizer->Add(pCheck_DECLTEXT, inputFlags);
4523 
4524     pCheck_SCAMIN = new wxCheckBox(ps57Ctl, ID_SCAMINCHECKBOX,
4525                                    _("Reduced Detail at Small Scale"));
4526     pCheck_SCAMIN->SetValue(FALSE);
4527     optionsColumn->Add(pCheck_SCAMIN, inputFlags);
4528 
4529     // spacer
4530     optionsColumn->Add(0, border_size * 4);
4531     optionsColumn->Add(0, border_size * 4);
4532 
4533     // graphics options
4534 
4535     wxFlexGridSizer* StyleColumn = new wxFlexGridSizer(2);
4536     StyleColumn->SetHGap(border_size);
4537     StyleColumn->AddGrowableCol(0, 2);
4538     StyleColumn->AddGrowableCol(1, 3);
4539     optionsColumn->Add(StyleColumn);
4540 
4541     StyleColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Graphics Style")), inputFlags);
4542     wxString pPointStyleStrings[] = {
4543         _("Paper Chart"), _("Simplified"),
4544     };
4545     pPointStyle = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4546                                wxSize(m_fontHeight * 3, m_fontHeight), 2, pPointStyleStrings);
4547     #ifdef __OCPN__ANDROID__
4548     setChoiceStyleSheet( pPointStyle, m_fontHeight *8/10);
4549     #endif
4550 
4551     StyleColumn->Add(pPointStyle, inputFlags);
4552 
4553     StyleColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Boundaries")), inputFlags);
4554     wxString pBoundStyleStrings[] = {
4555         _("Plain"), _("Symbolized"),
4556     };
4557     pBoundStyle = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4558                                wxSize(m_fontHeight * 3, m_fontHeight), 2, pBoundStyleStrings);
4559     #ifdef __OCPN__ANDROID__
4560     setChoiceStyleSheet( pBoundStyle, m_fontHeight *8/10);
4561     #endif
4562 
4563     StyleColumn->Add(pBoundStyle, inputFlags);
4564 
4565     StyleColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Colors")), inputFlags);
4566 
4567     wxString pColorNumStrings[] = {
4568         _("2 Color"), _("4 Color"),
4569     };
4570     p24Color = new wxChoice(ps57Ctl, ID_RADARDISTUNIT, wxDefaultPosition,
4571                             wxSize(m_fontHeight * 3, m_fontHeight), 2, pColorNumStrings);
4572     #ifdef __OCPN__ANDROID__
4573     setChoiceStyleSheet( p24Color, m_fontHeight *8/10);
4574     #endif
4575     StyleColumn->Add(p24Color, inputFlags);
4576 
4577     // spacer
4578     optionsColumn->Add(0, border_size * 4);
4579     optionsColumn->Add(0, border_size * 4);
4580 
4581     wxFlexGridSizer* DepthColumn = new wxFlexGridSizer(3);
4582     DepthColumn->SetHGap(border_size);
4583     DepthColumn->AddGrowableCol(0, 3);
4584     DepthColumn->AddGrowableCol(1, 2);
4585     DepthColumn->AddGrowableCol(2, 3);
4586     optionsColumn->Add(DepthColumn);
4587 
4588     // depth options
4589     DepthColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Shallow Depth")),
4590                      inputFlags);
4591     m_ShallowCtl = new wxTextCtrl(ps57Ctl, ID_OPTEXTCTRL, _T(""), wxDefaultPosition,
4592                        wxSize(m_fontHeight * 2, m_fontHeight), wxTE_RIGHT);
4593     DepthColumn->Add(m_ShallowCtl, inputFlags);
4594     m_depthUnitsShal = new wxStaticText(ps57Ctl, wxID_ANY, _("meters"));
4595     DepthColumn->Add(m_depthUnitsShal, inputFlags);
4596 
4597     DepthColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Safety Depth")), inputFlags);
4598     m_SafetyCtl =  new wxTextCtrl(ps57Ctl, ID_OPTEXTCTRL, _T(""), wxDefaultPosition,
4599                        wxSize(m_fontHeight * 2, m_fontHeight), wxTE_RIGHT);
4600     DepthColumn->Add(m_SafetyCtl, inputFlags);
4601     m_depthUnitsSafe = new wxStaticText(ps57Ctl, wxID_ANY, _("meters"));
4602     DepthColumn->Add(m_depthUnitsSafe, inputFlags);
4603 
4604     DepthColumn->Add(new wxStaticText(ps57Ctl, wxID_ANY, _("Deep Depth")), inputFlags);
4605     m_DeepCtl = new wxTextCtrl(ps57Ctl, ID_OPTEXTCTRL, _T(""), wxDefaultPosition,
4606                         wxSize(m_fontHeight * 2, m_fontHeight), wxTE_CENTER);
4607     DepthColumn->Add(m_DeepCtl, inputFlags);
4608     m_depthUnitsDeep = new wxStaticText(ps57Ctl, wxID_ANY, _("meters"));
4609     DepthColumn->Add(m_depthUnitsDeep, inputFlags);
4610 
4611     // spacer
4612     optionsColumn->Add(0, border_size * 4);
4613     optionsColumn->Add(0, border_size * 4);
4614 
4615     //  Display Category / Mariner's Standard options
4616     wxBoxSizer* dispSizer = new wxBoxSizer(wxVERTICAL);
4617     vectorPanel->Add(dispSizer, 2, wxALL | wxEXPAND, border_size);
4618 
4619     wxStaticBox* marinersBox =
4620         new wxStaticBox(ps57Ctl, wxID_ANY, _("User Standard Objects"));
4621     wxStaticBoxSizer* marinersSizer =
4622         new wxStaticBoxSizer(marinersBox, wxVERTICAL);
4623     dispSizer->Add(marinersSizer, 1, wxALL | wxEXPAND, border_size);
4624 
4625     wxBoxSizer* btnRow1 = new wxBoxSizer(wxHORIZONTAL);
4626     itemButtonSelectList =  new wxButton(ps57Ctl, ID_SELECTLIST, _("Select All"));
4627     btnRow1->Add(itemButtonSelectList, 1, wxALL | wxEXPAND, group_item_spacing);
4628     itemButtonClearList = new wxButton(ps57Ctl, ID_CLEARLIST, _("Clear All"));
4629     btnRow1->Add(itemButtonClearList, 1, wxALL | wxEXPAND, group_item_spacing);
4630     marinersSizer->Add(btnRow1);
4631 
4632     wxBoxSizer* btnRow2 = new wxBoxSizer(wxHORIZONTAL);
4633     itemButtonSetStd = new wxButton(ps57Ctl, ID_SETSTDLIST, _("Reset to STANDARD"));
4634     btnRow2->Add(itemButtonSetStd, 1, wxALL | wxEXPAND, group_item_spacing);
4635     marinersSizer->Add(btnRow2);
4636 
4637 
4638 // #if defined(__WXMSW__) || defined(__WXOSX__)
4639 //     wxString* ps57CtlListBoxStrings = NULL;
4640 //     ps57CtlListBox = new wxCheckListBox(
4641 //         ps57Ctl, ID_CHECKLISTBOX, wxDefaultPosition, wxSize(250, 350), 0,
4642 //         ps57CtlListBoxStrings, wxLB_SINGLE | wxLB_HSCROLL | wxLB_SORT);
4643 // #else
4644     ps57CtlListBox = new OCPNCheckedListCtrl(
4645         ps57Ctl, ID_CHECKLISTBOX, wxDefaultPosition, wxSize(250, 350));
4646 // #endif
4647 
4648     marinersSizer->Add(ps57CtlListBox, 1, wxALL | wxEXPAND, group_item_spacing);
4649   }
4650 }
4651 
CreatePanel_TidesCurrents(size_t parent,int border_size,int group_item_spacing)4652 void options::CreatePanel_TidesCurrents(size_t parent, int border_size,
4653                                         int group_item_spacing) {
4654   wxScrolledWindow* tcPanel = AddPage(parent, _("Tides && Currents"));
4655 
4656   wxBoxSizer* mainHBoxSizer = new wxBoxSizer(wxVERTICAL);
4657   tcPanel->SetSizer(mainHBoxSizer);
4658 
4659   wxStaticBox* tcBox = new wxStaticBox(tcPanel, wxID_ANY, _("Active Datasets"));
4660   wxStaticBoxSizer* tcSizer = new wxStaticBoxSizer(tcBox, wxHORIZONTAL);
4661   mainHBoxSizer->Add(tcSizer, 1, wxALL | wxEXPAND, border_size);
4662 
4663   tcDataSelected =  new wxListCtrl(tcPanel, ID_TIDESELECTED, wxDefaultPosition, wxSize(100, -1), wxLC_REPORT | wxLC_NO_HEADER);
4664 
4665   tcSizer->Add(tcDataSelected, 1, wxALL | wxEXPAND, border_size);
4666 
4667   //  Populate Selection List Control with the contents
4668   //  of the Global static array
4669   tcDataSelected->DeleteAllItems();
4670 
4671     // Add first column
4672   wxListItem col0;
4673   col0.SetId(0);
4674   col0.SetText( _("") );
4675   col0.SetWidth(500);
4676   col0.SetAlign(wxLIST_FORMAT_LEFT);
4677 
4678   tcDataSelected->InsertColumn(0, col0);
4679 
4680   for (unsigned int id = 0; id < TideCurrentDataSet.Count(); id++) {
4681         wxListItem li;
4682         li.SetId( id );
4683         long idx = tcDataSelected->InsertItem( li );
4684 
4685         wxString setName = TideCurrentDataSet[id];
4686         tcDataSelected->SetItem(id, 0, setName);
4687   }
4688 
4689   //    Add the "Insert/Remove" buttons
4690   wxButton* insertButton =
4691       new wxButton(tcPanel, ID_TCDATAADD, _("Add Dataset..."));
4692   wxButton* removeButton =
4693       new wxButton(tcPanel, ID_TCDATADEL, _("Remove Selected"));
4694 
4695   wxBoxSizer* btnSizer = new wxBoxSizer(wxVERTICAL);
4696   tcSizer->Add(btnSizer);
4697 
4698   btnSizer->Add(insertButton, 1, wxALL | wxEXPAND, group_item_spacing);
4699   btnSizer->Add(removeButton, 1, wxALL | wxEXPAND, group_item_spacing);
4700 }
4701 
CreatePanel_ChartGroups(size_t parent,int border_size,int group_item_spacing)4702 void options::CreatePanel_ChartGroups(size_t parent, int border_size, int group_item_spacing)
4703 {
4704   // Special case for adding the tab here. We know this page has multiple tabs,
4705   // and we have the actual widgets in a separate class (because of its
4706   // complexity)
4707 
4708   wxWindow *chartsPage = m_pListbook->GetPage(parent);
4709   groupsPanel = new ChartGroupsUI(chartsPage);
4710 
4711   groupsPanel->m_panel = AddPage(parent, _("Chart Groups"));
4712 
4713   groupsPanel->CreatePanel(parent, border_size, group_item_spacing);
4714 
4715 }
4716 
CreatePanel(size_t parent,int border_size,int group_item_spacing)4717 void ChartGroupsUI::CreatePanel(size_t parent, int border_size,
4718                                 int group_item_spacing)
4719 {
4720 
4721   modified = FALSE;
4722   m_border_size = border_size;
4723   m_group_item_spacing = group_item_spacing;
4724 
4725 
4726     m_UIcomplete = FALSE;
4727 
4728   CompletePanel();
4729 
4730 }
4731 
CompletePanel(void)4732 void ChartGroupsUI::CompletePanel(void)
4733 {
4734     m_topSizer = new wxBoxSizer(wxVERTICAL);
4735     m_panel->SetSizer(m_topSizer);
4736 
4737   //    The chart file/dir tree
4738   wxStaticText* allChartsLabel = new wxStaticText(m_panel, wxID_ANY, _("All Available Charts"));
4739   m_topSizer->Add(allChartsLabel, 0, wxTOP | wxRIGHT | wxLEFT, m_border_size);
4740 
4741     wxBoxSizer *sizerCharts = new wxBoxSizer(wxHORIZONTAL);
4742     m_topSizer->Add(sizerCharts, 1, wxALL | wxEXPAND, 5);
4743 
4744   wxBoxSizer* activeListSizer = new wxBoxSizer(wxVERTICAL);
4745   sizerCharts->Add(activeListSizer, 1, wxALL | wxEXPAND, 5);
4746 
4747 #ifdef __OCPN__ANDROID__
4748   allAvailableCtl = new wxGenericDirCtrl(m_panel, ID_GROUPAVAILABLE, _T(""), wxDefaultPosition, wxDefaultSize, wxVSCROLL);
4749 #else
4750   allAvailableCtl = new wxGenericDirCtrl(m_panel, ID_GROUPAVAILABLE, _T(""), wxDefaultPosition,  wxDefaultSize, wxVSCROLL);
4751 #endif
4752   activeListSizer->Add(allAvailableCtl, 1, wxEXPAND);
4753 
4754   m_pAddButton = new wxButton(m_panel, ID_GROUPINSERTDIR, _("Add"));
4755   m_pAddButton->Disable();
4756   m_pRemoveButton = new wxButton(m_panel, ID_GROUPREMOVEDIR, _("Remove Chart"));
4757   m_pRemoveButton->Disable();
4758 
4759   m_pAddButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartGroupsUI::OnInsertChartItem), NULL, this );
4760   m_pRemoveButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartGroupsUI::OnRemoveChartItem), NULL, this );
4761 
4762   wxBoxSizer* addRemove = new wxBoxSizer(wxVERTICAL);
4763   sizerCharts->Add(addRemove, 0, wxALL | wxEXPAND, m_border_size);
4764   addRemove->Add(m_pAddButton, 0, wxALL | wxEXPAND, m_group_item_spacing);
4765 
4766   sizerCharts->AddSpacer(20);           // Avoid potential scrollbar
4767 
4768   //    Add the Groups notebook control
4769   wxStaticText* groupsLabel =  new wxStaticText(m_panel, wxID_ANY, _("Chart Groups"));
4770   m_topSizer->Add(groupsLabel, 0, wxTOP | wxRIGHT | wxLEFT, m_border_size);
4771 
4772 
4773   wxBoxSizer *sizerGroups = new wxBoxSizer(wxHORIZONTAL);
4774   m_topSizer->Add(sizerGroups, 1, wxALL | wxEXPAND, 5);
4775 
4776   wxBoxSizer* nbSizer = new wxBoxSizer(wxVERTICAL);
4777   sizerGroups->Add(nbSizer, 1, wxALL | wxEXPAND, m_border_size);
4778   m_GroupNB = new wxNotebook(m_panel, ID_GROUPNOTEBOOK, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
4779   nbSizer->Add(m_GroupNB, 1, wxEXPAND);
4780 
4781   m_GroupNB->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler(ChartGroupsUI::OnGroupPageChange), NULL, this);
4782 
4783   //    Add default (always present) Default Chart Group
4784   wxPanel* allActiveGroup = new wxPanel(m_GroupNB, -1, wxDefaultPosition, wxDefaultSize);
4785   m_GroupNB->AddPage(allActiveGroup, _("All Charts"));
4786 
4787   wxBoxSizer* page0BoxSizer = new wxBoxSizer(wxHORIZONTAL);
4788   allActiveGroup->SetSizer(page0BoxSizer);
4789 
4790   defaultAllCtl = new wxGenericDirCtrl(allActiveGroup, -1, _T(""), wxDefaultPosition, wxDefaultSize);
4791 
4792   //    Set the Font for the All Active Chart Group tree to be italic, dimmed
4793   iFont = new wxFont(*dialogFont);
4794   iFont->SetStyle(wxFONTSTYLE_ITALIC);
4795   iFont->SetWeight(wxFONTWEIGHT_LIGHT);
4796 
4797   page0BoxSizer->Add(defaultAllCtl, 1, wxALIGN_TOP | wxALL | wxEXPAND);
4798 
4799   m_DirCtrlArray.Add(defaultAllCtl);
4800 
4801   //    Add the Chart Group (page) "New" and "Delete" buttons
4802   m_pNewGroupButton = new wxButton(m_panel, ID_GROUPNEWGROUP, _("New Group..."));
4803   m_pDeleteGroupButton = new wxButton(m_panel, ID_GROUPDELETEGROUP, _("Delete Group"));
4804   m_pDeleteGroupButton->Disable();              // for default "all Charts" group
4805 
4806   m_pNewGroupButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartGroupsUI::OnNewGroup), NULL, this );
4807   m_pDeleteGroupButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartGroupsUI::OnDeleteGroup), NULL, this );
4808 
4809   wxBoxSizer* newDeleteGrp = new wxBoxSizer(wxVERTICAL);
4810   sizerGroups->Add(newDeleteGrp, 0, wxALL, m_border_size);
4811 
4812   newDeleteGrp->AddSpacer(25);
4813   newDeleteGrp->Add(m_pNewGroupButton, 0, wxALL | wxEXPAND,
4814                     m_group_item_spacing);
4815   newDeleteGrp->AddSpacer(15);
4816   newDeleteGrp->Add(m_pDeleteGroupButton, 0, wxALL | wxEXPAND,
4817                     m_group_item_spacing);
4818   newDeleteGrp->AddSpacer(25);
4819   newDeleteGrp->Add(m_pRemoveButton, 0, wxALL | wxEXPAND, m_group_item_spacing);
4820 
4821   sizerGroups->AddSpacer(20);            // Avoid potential scrollbar
4822 
4823   // Connect this last, otherwise handler is called before all objects are initialized.
4824    m_panel->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler(ChartGroupsUI::OnAvailableSelection), NULL,  this);
4825 
4826   m_UIcomplete = TRUE;
4827 }
4828 
CreatePanel_Display(size_t parent,int border_size,int group_item_spacing)4829 void options::CreatePanel_Display(size_t parent, int border_size,
4830                                   int group_item_spacing) {
4831   pDisplayPanel = AddPage(parent, _("General"));
4832 
4833   if (!m_bcompact) {
4834     wxFlexGridSizer* generalSizer = new wxFlexGridSizer(2);
4835     generalSizer->SetHGap(border_size);
4836     //    generalSizer->AddGrowableCol( 0, 1 );
4837     //    generalSizer->AddGrowableCol( 1, 1 );
4838     //    pDisplayPanel->SetSizer( generalSizer );
4839 
4840     // wxFlexGridSizer grows wrongly in wx2.8, so we need to centre it in
4841     // another sizer instead of letting it grow.
4842     wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
4843     pDisplayPanel->SetSizer(wrapperSizer);
4844     wrapperSizer->Add(generalSizer, 1, wxALL | wxALIGN_CENTER, border_size);
4845 
4846     // spacer
4847     generalSizer->Add(0, border_size * 4);
4848     generalSizer->Add(0, border_size * 4);
4849 
4850     if(!g_useMUI){
4851     // Nav Mode
4852     generalSizer->Add(
4853         new wxStaticText(pDisplayPanel, wxID_ANY, _("Navigation Mode")),
4854         groupLabelFlags);
4855     wxBoxSizer* boxNavMode = new wxBoxSizer(wxVERTICAL);
4856     generalSizer->Add(boxNavMode, groupInputFlags);
4857 
4858     wxBoxSizer* rowOrientation = new wxBoxSizer(wxHORIZONTAL);
4859     boxNavMode->Add(rowOrientation);
4860 
4861     pCBNorthUp = new wxRadioButton(pDisplayPanel, wxID_ANY, _("North Up"));
4862     rowOrientation->Add(pCBNorthUp, inputFlags);
4863     pCBCourseUp =
4864         new wxRadioButton(pDisplayPanel, ID_COURSEUPCHECKBOX, _("Course Up"));
4865     rowOrientation->Add(pCBCourseUp,
4866                         wxSizerFlags(0)
4867                             .Align(wxALIGN_CENTRE_VERTICAL)
4868                             .Border(wxLEFT, group_item_spacing * 2));
4869 
4870     pCBLookAhead =
4871         new wxCheckBox(pDisplayPanel, ID_CHECK_LOOKAHEAD, _("Look Ahead Mode"));
4872     boxNavMode->Add(pCBLookAhead, verticleInputFlags);
4873 
4874     // spacer
4875     generalSizer->Add(0, border_size * 4);
4876     generalSizer->Add(0, border_size * 4);
4877 
4878     // Control Options
4879     generalSizer->Add(
4880         new wxStaticText(pDisplayPanel, wxID_ANY, _("Chart Display")),
4881         groupLabelFlags);
4882     wxBoxSizer* boxCharts = new wxBoxSizer(wxVERTICAL);
4883     generalSizer->Add(boxCharts, groupInputFlags);
4884 
4885     pCDOQuilting = new wxCheckBox(pDisplayPanel, ID_QUILTCHECKBOX1,
4886                                   _("Enable Chart Quilting"));
4887     boxCharts->Add(pCDOQuilting, verticleInputFlags);
4888 
4889     pPreserveScale = new wxCheckBox(pDisplayPanel, ID_PRESERVECHECKBOX,
4890                                     _("Preserve scale when switching charts"));
4891     boxCharts->Add(pPreserveScale, verticleInputFlags);
4892 
4893     // spacer
4894     generalSizer->Add(0, border_size * 4);
4895     generalSizer->Add(0, border_size * 4);
4896     }
4897 
4898     // Control Options
4899     generalSizer->Add(new wxStaticText(pDisplayPanel, wxID_ANY, _("Controls")),
4900                       groupLabelFlags);
4901     wxBoxSizer* boxCtrls = new wxBoxSizer(wxVERTICAL);
4902     generalSizer->Add(boxCtrls, groupInputFlags);
4903 
4904     pSmoothPanZoom = new wxCheckBox(pDisplayPanel, ID_SMOOTHPANZOOMBOX,
4905                                     _("Smooth Panning / Zooming"));
4906     boxCtrls->Add(pSmoothPanZoom, verticleInputFlags);
4907 
4908     pEnableZoomToCursor =
4909         new wxCheckBox(pDisplayPanel, ID_ZTCCHECKBOX, _("Zoom to Cursor"));
4910     pEnableZoomToCursor->SetValue(FALSE);
4911     boxCtrls->Add(pEnableZoomToCursor, verticleInputFlags);
4912 
4913     // spacer
4914     generalSizer->Add(0, border_size * 4);
4915     generalSizer->Add(0, border_size * 4);
4916 
4917     if(!g_useMUI){
4918     // Display Options
4919     generalSizer->Add(
4920         new wxStaticText(pDisplayPanel, wxID_ANY, _("Display Features")),
4921         groupLabelFlags);
4922     wxBoxSizer* boxDisp = new wxBoxSizer(wxVERTICAL);
4923     generalSizer->Add(boxDisp, groupInputFlags);
4924 
4925     pSDisplayGrid =
4926         new wxCheckBox(pDisplayPanel, ID_CHECK_DISPLAYGRID, _("Show Grid"));
4927     boxDisp->Add(pSDisplayGrid, verticleInputFlags);
4928 
4929     pCDOOutlines = new wxCheckBox(pDisplayPanel, ID_OUTLINECHECKBOX1,
4930                                   _("Show Chart Outlines"));
4931     boxDisp->Add(pCDOOutlines, verticleInputFlags);
4932 
4933     pSDepthUnits = new wxCheckBox(pDisplayPanel, ID_SHOWDEPTHUNITSBOX1,
4934                                   _("Show Depth Units"));
4935     boxDisp->Add(pSDepthUnits, verticleInputFlags);
4936 
4937     }
4938 
4939     // CUSTOMIZATION - LIVE ETA OPTION
4940     // -------------------------------
4941     // Add a checkbox to activate live ETA option in status bar, and
4942     // Add a text field to set default boat speed (for calculation when
4943     // no GPS or when the boat is at the harbor).
4944 
4945     // Spacer
4946     generalSizer->Add(0, border_size * 4);
4947     generalSizer->Add(0, border_size * 4);
4948 
4949     // New menu status bar
4950     generalSizer->Add(new wxStaticText(pDisplayPanel, wxID_ANY, _("Status Bar Option")),
4951                       groupLabelFlags);
4952     wxBoxSizer* boxDispStatusBar = new wxBoxSizer(wxVERTICAL);
4953     generalSizer->Add(boxDispStatusBar, groupInputFlags);
4954 
4955     // Add option for live ETA
4956     pSLiveETA = new wxCheckBox(pDisplayPanel, ID_CHECK_LIVEETA, _("Live ETA at Cursor"));
4957     boxDispStatusBar->Add(pSLiveETA, verticleInputFlags);
4958 
4959     // Add text input for default boat speed
4960     // (for calculation, in case GPS speed is null)
4961     wxBoxSizer *defaultBoatSpeedSizer = new wxBoxSizer(wxHORIZONTAL);
4962     boxDispStatusBar->Add(defaultBoatSpeedSizer, wxALL, group_item_spacing);
4963     defaultBoatSpeedSizer->Add(new wxStaticText(pDisplayPanel, wxID_ANY, _("Default Boat Speed ")),
4964                                groupLabelFlagsHoriz);
4965     pSDefaultBoatSpeed = new wxTextCtrl(pDisplayPanel, ID_DEFAULT_BOAT_SPEED, _T(""), wxDefaultPosition,
4966                                         wxSize(50, -1), wxTE_RIGHT);
4967     defaultBoatSpeedSizer->Add(pSDefaultBoatSpeed, 0, wxALIGN_CENTER_VERTICAL, group_item_spacing);
4968 
4969     // --------------------------------------
4970     // END OF CUSTOMIZATION - LIVE ETA OPTION
4971 
4972 #ifndef __OCPN__ANDROID__
4973     // MultiChart selection panel
4974     if(g_Platform->GetDisplayAreaCM2() > 100){
4975 
4976     wxStaticBox* itemStaticBoxScreenConfig =  new wxStaticBox(pDisplayPanel, wxID_ANY, _("Canvas Layout"));
4977     wxStaticBoxSizer* itemStaticBoxSizerScreenConfig = new wxStaticBoxSizer(itemStaticBoxScreenConfig, wxHORIZONTAL);
4978     wrapperSizer->Add(itemStaticBoxSizerScreenConfig, 1, wxALL | wxEXPAND, 5);
4979 
4980     //  The standard screen configs...
4981     wxString iconDir = g_Platform->GetSharedDataDir();
4982     appendOSDirSlash(&iconDir);
4983     iconDir.append(_T("uidata"));
4984     appendOSDirSlash(&iconDir);
4985     iconDir.append(_T("MUI_flat"));
4986     appendOSDirSlash(&iconDir);
4987     int bmpSize = GetCharHeight() * 3;
4988 
4989     wxBitmap bmp = LoadSVG( iconDir + _T("MUI_Sconfig_1.svg"), bmpSize, bmpSize );
4990     m_sconfigSelect_single = new CanvasConfigSelect( pDisplayPanel, this, ID_SCREENCONFIG1, bmp);
4991     itemStaticBoxSizerScreenConfig->Add(m_sconfigSelect_single, 0, wxALIGN_LEFT);
4992 
4993     itemStaticBoxSizerScreenConfig->AddSpacer(GetCharHeight());
4994 
4995     bmp = LoadSVG( iconDir + _T("MUI_Sconfig_2.svg"), bmpSize, bmpSize );
4996     m_sconfigSelect_twovertical = new CanvasConfigSelect( pDisplayPanel, this, ID_SCREENCONFIG2, bmp);
4997     itemStaticBoxSizerScreenConfig->Add(m_sconfigSelect_twovertical, 0, wxALIGN_LEFT);
4998 
4999     itemStaticBoxSizerScreenConfig->AddSpacer(GetCharHeight());
5000     }
5001 #endif
5002 
5003   } else {      // compact follows
5004     wxFlexGridSizer* generalSizer = new wxFlexGridSizer(2);
5005     generalSizer->SetHGap(border_size);
5006     //    generalSizer->AddGrowableCol( 0, 1 );
5007     //    generalSizer->AddGrowableCol( 1, 1 );
5008     //    pDisplayPanel->SetSizer( generalSizer );
5009 
5010     // wxFlexGridSizer grows wrongly in wx2.8, so we need to centre it in
5011     // another sizer instead of letting it grow.
5012     wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
5013     pDisplayPanel->SetSizer(wrapperSizer);
5014     wrapperSizer->Add(generalSizer, 1, wxALL | wxALIGN_CENTER, border_size);
5015 
5016     // spacer
5017     generalSizer->Add(0, border_size * 4);
5018     generalSizer->Add(0, border_size * 4);
5019 
5020     if(!g_useMUI){
5021     // Nav Mode
5022     generalSizer->Add(
5023         new wxStaticText(pDisplayPanel, wxID_ANY, _("Navigation Mode")),
5024         groupLabelFlags);
5025     wxBoxSizer* boxNavMode = new wxBoxSizer(wxVERTICAL);
5026     generalSizer->Add(boxNavMode, groupInputFlags);
5027 
5028     wxBoxSizer* rowOrientation = new wxBoxSizer(wxHORIZONTAL);
5029     boxNavMode->Add(rowOrientation);
5030 
5031     pCBNorthUp = new wxRadioButton(pDisplayPanel, wxID_ANY, _("North Up"));
5032     rowOrientation->Add(pCBNorthUp, inputFlags);
5033     pCBCourseUp =
5034         new wxRadioButton(pDisplayPanel, ID_COURSEUPCHECKBOX, _("Course Up"));
5035     rowOrientation->Add(pCBCourseUp,
5036                         wxSizerFlags(0)
5037                             .Align(wxALIGN_CENTRE_VERTICAL)
5038                             .Border(wxLEFT, group_item_spacing * 2));
5039 
5040     pCBLookAhead =
5041         new wxCheckBox(pDisplayPanel, ID_CHECK_LOOKAHEAD, _("Look Ahead Mode"));
5042     boxNavMode->Add(pCBLookAhead, verticleInputFlags);
5043 
5044     // spacer
5045     generalSizer->Add(0, border_size * 4);
5046     generalSizer->Add(0, border_size * 4);
5047 
5048     // Control Options
5049     generalSizer->Add(
5050         new wxStaticText(pDisplayPanel, wxID_ANY, _("Chart Display")),
5051         groupLabelFlags);
5052     wxBoxSizer* boxCharts = new wxBoxSizer(wxVERTICAL);
5053     generalSizer->Add(boxCharts, groupInputFlags);
5054 
5055     pCDOQuilting = new wxCheckBox(pDisplayPanel, ID_QUILTCHECKBOX1,
5056                                   _("Enable Chart Quilting"));
5057     boxCharts->Add(pCDOQuilting, verticleInputFlags);
5058 
5059     pPreserveScale = new wxCheckBox(pDisplayPanel, ID_PRESERVECHECKBOX,
5060                                     _("Preserve scale when switching charts"));
5061     boxCharts->Add(pPreserveScale, verticleInputFlags);
5062 
5063     // spacer
5064     generalSizer->Add(0, border_size * 4);
5065     generalSizer->Add(0, border_size * 4);
5066     }
5067 
5068     // Control Options
5069     generalSizer->Add(new wxStaticText(pDisplayPanel, wxID_ANY, _("Controls")),
5070                       groupLabelFlags);
5071     wxBoxSizer* boxCtrls = new wxBoxSizer(wxVERTICAL);
5072     generalSizer->Add(boxCtrls, groupInputFlags);
5073 
5074     pSmoothPanZoom = new wxCheckBox(pDisplayPanel, ID_SMOOTHPANZOOMBOX,
5075                                     _("Smooth Panning / Zooming"));
5076     boxCtrls->Add(pSmoothPanZoom, verticleInputFlags);
5077     pEnableZoomToCursor =
5078         new wxCheckBox(pDisplayPanel, ID_ZTCCHECKBOX, _("Zoom to Cursor"));
5079     pEnableZoomToCursor->SetValue(FALSE);
5080     boxCtrls->Add(pEnableZoomToCursor, verticleInputFlags);
5081 
5082 #ifdef __OCPN__ANDROID__
5083     pSmoothPanZoom->Hide();
5084     pEnableZoomToCursor->Hide();
5085 #endif
5086 
5087     // spacer
5088     generalSizer->Add(0, border_size * 4);
5089     generalSizer->Add(0, border_size * 4);
5090 
5091     if(!g_useMUI){
5092     // Display Options
5093     generalSizer->Add(
5094         new wxStaticText(pDisplayPanel, wxID_ANY, _("Display Features")),
5095         groupLabelFlags);
5096     wxBoxSizer* boxDisp = new wxBoxSizer(wxVERTICAL);
5097     generalSizer->Add(boxDisp, groupInputFlags);
5098 
5099     pSDisplayGrid =
5100         new wxCheckBox(pDisplayPanel, ID_CHECK_DISPLAYGRID, _("Show Grid"));
5101     boxDisp->Add(pSDisplayGrid, verticleInputFlags);
5102 
5103     pCDOOutlines = new wxCheckBox(pDisplayPanel, ID_OUTLINECHECKBOX1,
5104                                   _("Show Chart Outlines"));
5105     boxDisp->Add(pCDOOutlines, verticleInputFlags);
5106 
5107     pSDepthUnits = new wxCheckBox(pDisplayPanel, ID_SHOWDEPTHUNITSBOX1,
5108                                   _("Show Depth Units"));
5109     boxDisp->Add(pSDepthUnits, verticleInputFlags);
5110 
5111     }
5112 
5113     // CUSTOMIZATION - LIVE ETA OPTION
5114     // -------------------------------
5115     // Add a checkbox to activate live ETA option in status bar, and
5116     // Add a text field to set default boat speed (for calculation when
5117     // no GPS or when the boat is at the harbor).
5118 
5119     // Spacer
5120     generalSizer->Add(0, border_size * 4);
5121     generalSizer->Add(0, border_size * 4);
5122 
5123     // New menu status bar
5124     generalSizer->Add(new wxStaticText(pDisplayPanel, wxID_ANY, _("Status Bar")),
5125                       groupLabelFlags);
5126     wxBoxSizer* boxDispStatusBar = new wxBoxSizer(wxVERTICAL);
5127     generalSizer->Add(boxDispStatusBar, groupInputFlags);
5128 
5129     // Add option for live ETA
5130     pSLiveETA = new wxCheckBox(pDisplayPanel, ID_CHECK_LIVEETA, _("Live ETA at Cursor"));
5131     boxDispStatusBar->Add(pSLiveETA, verticleInputFlags);
5132 
5133     // Add text input for default boat speed
5134     // (for calculation, in case GPS speed is null)
5135     wxBoxSizer *defaultBoatSpeedSizer = new wxBoxSizer(wxHORIZONTAL);
5136     boxDispStatusBar->Add(defaultBoatSpeedSizer, wxALL, group_item_spacing);
5137     defaultBoatSpeedSizer->Add(new wxStaticText(pDisplayPanel, wxID_ANY, _("Default Boat Speed ")),
5138                                groupLabelFlagsHoriz);
5139     pSDefaultBoatSpeed = new wxTextCtrl(pDisplayPanel, ID_DEFAULT_BOAT_SPEED, _T(""), wxDefaultPosition,
5140                                         wxSize(50, -1), wxTE_RIGHT);
5141     defaultBoatSpeedSizer->Add(pSDefaultBoatSpeed, 0, wxALIGN_CENTER_VERTICAL, group_item_spacing);
5142 
5143     // --------------------------------------
5144     // END OF CUSTOMIZATION - LIVE ETA OPTION
5145 
5146 #ifndef __OCPN__ANDROID__
5147     if(g_Platform->GetDisplayAreaCM2() > 100){
5148         // MultiChart selection panel
5149         wxStaticBox* itemStaticBoxScreenConfig =  new wxStaticBox(pDisplayPanel, wxID_ANY, _("Canvas Layout"));
5150         wxStaticBoxSizer* itemStaticBoxSizerScreenConfig = new wxStaticBoxSizer(itemStaticBoxScreenConfig, wxHORIZONTAL);
5151         wrapperSizer->Add(itemStaticBoxSizerScreenConfig, 1, wxALL | wxEXPAND, 5);
5152 
5153         //  The standard screen configs...
5154         wxString iconDir = g_Platform->GetSharedDataDir();
5155         appendOSDirSlash(&iconDir);
5156         iconDir.append(_T("uidata"));
5157         appendOSDirSlash(&iconDir);
5158         iconDir.append(_T("MUI_flat"));
5159         appendOSDirSlash(&iconDir);
5160         int bmpSize = GetCharHeight() * 3;
5161 
5162         wxBitmap bmp = LoadSVG( iconDir + _T("MUI_Sconfig_1.svg"), bmpSize, bmpSize );
5163         m_sconfigSelect_single = new CanvasConfigSelect( pDisplayPanel, this, ID_SCREENCONFIG1, bmp);
5164         itemStaticBoxSizerScreenConfig->Add(m_sconfigSelect_single, 0, wxALIGN_LEFT);
5165 
5166         itemStaticBoxSizerScreenConfig->AddSpacer(GetCharHeight());
5167 
5168         bmp = LoadSVG( iconDir + _T("MUI_Sconfig_2.svg"), bmpSize, bmpSize );
5169         m_sconfigSelect_twovertical = new CanvasConfigSelect( pDisplayPanel, this, ID_SCREENCONFIG2, bmp);
5170         itemStaticBoxSizerScreenConfig->Add(m_sconfigSelect_twovertical, 0, wxALIGN_LEFT);
5171 
5172         itemStaticBoxSizerScreenConfig->AddSpacer(GetCharHeight());
5173     }
5174 #endif
5175 
5176   }
5177 
5178 }
5179 
CreatePanel_Units(size_t parent,int border_size,int group_item_spacing)5180 void options::CreatePanel_Units(size_t parent, int border_size,
5181                                 int group_item_spacing) {
5182   wxScrolledWindow* panelUnits = AddPage(parent, _("Units"));
5183 
5184   if (m_bcompact) {
5185     wxFlexGridSizer* unitsSizer = new wxFlexGridSizer(2);
5186     unitsSizer->SetHGap(border_size);
5187 
5188     // wxFlexGridSizer grows wrongly in wx2.8, so we need to centre it in
5189     // another sizer instead of letting it grow.
5190     wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
5191     panelUnits->SetSizer(wrapperSizer);
5192 
5193     wrapperSizer->Add(1, border_size * 24);
5194     wrapperSizer->Add(unitsSizer, 1, wxALL | wxALIGN_CENTER, border_size);
5195 
5196     // spacer
5197     unitsSizer->Add(0, border_size * 4);
5198     unitsSizer->Add(0, border_size * 4);
5199 
5200     // distance units
5201     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Distance")),
5202                     labelFlags);
5203     wxString pDistanceFormats[] = {_("Nautical miles"), _("Statute miles"),
5204                                    _("Kilometers"), _("Meters")};
5205     int m_DistanceFormatsNChoices = sizeof(pDistanceFormats) / sizeof(wxString);
5206     pDistanceFormat = new wxChoice(panelUnits, ID_DISTANCEUNITSCHOICE,
5207                                    wxDefaultPosition, wxSize(m_fontHeight * 4, -1),
5208                                    m_DistanceFormatsNChoices, pDistanceFormats);
5209     #ifdef __OCPN__ANDROID__
5210     setChoiceStyleSheet( pDistanceFormat, m_fontHeight *8/10);
5211     #endif
5212     unitsSizer->Add(pDistanceFormat, inputFlags);
5213 
5214     // speed units
5215     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Speed")),
5216                     labelFlags);
5217     wxString pSpeedFormats[] = {_("Knots"), _("Mph"), _("km/h"), _("m/s")};
5218     int m_SpeedFormatsNChoices = sizeof(pSpeedFormats) / sizeof(wxString);
5219     pSpeedFormat =
5220         new wxChoice(panelUnits, ID_SPEEDUNITSCHOICE, wxDefaultPosition,
5221                      wxSize(m_fontHeight * 4, -1), m_SpeedFormatsNChoices, pSpeedFormats);
5222     #ifdef __OCPN__ANDROID__
5223         setChoiceStyleSheet( pSpeedFormat, m_fontHeight *8/10);
5224     #endif
5225     unitsSizer->Add(pSpeedFormat, inputFlags);
5226 
5227     // depth units
5228     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Depth")),
5229                     labelFlags);
5230     wxString pDepthUnitStrings[] = {
5231         _("Feet"), _("Meters"), _("Fathoms"),
5232     };
5233     pDepthUnitSelect =
5234         new wxChoice(panelUnits, ID_DEPTHUNITSCHOICE, wxDefaultPosition,
5235                      wxSize(m_fontHeight * 4, -1), 3, pDepthUnitStrings);
5236     #ifdef __OCPN__ANDROID__
5237         setChoiceStyleSheet( pDepthUnitSelect, m_fontHeight *8/10);
5238     #endif
5239     unitsSizer->Add(pDepthUnitSelect, inputFlags);
5240 
5241     // spacer
5242     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _T("")));
5243     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _T("")));
5244 
5245     // lat/long units
5246     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Lat/Long")),
5247                     labelFlags);
5248     wxString pSDMMFormats[] = {_("Degrees, Decimal Minutes"),
5249                                _("Decimal Degrees"),
5250                                _("Degrees, Minutes, Seconds")};
5251     int m_SDMMFormatsNChoices = sizeof(pSDMMFormats) / sizeof(wxString);
5252     pSDMMFormat =
5253         new wxChoice(panelUnits, ID_SDMMFORMATCHOICE, wxDefaultPosition,
5254                      wxSize(m_fontHeight * 4, -1), m_SDMMFormatsNChoices, pSDMMFormats);
5255     #ifdef __OCPN__ANDROID__
5256         setChoiceStyleSheet( pSDMMFormat, m_fontHeight *8/10);
5257     #endif
5258     unitsSizer->Add(pSDMMFormat, inputFlags);
5259 
5260     // spacer
5261     unitsSizer->Add(0, border_size * 4);
5262     unitsSizer->Add(0, border_size * 4);
5263 
5264     // bearings (magnetic/true, variation)
5265     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Bearings")),
5266                     groupLabelFlags);
5267 
5268     //  "Mag Heading" checkbox
5269     pCBTrueShow =
5270         new wxCheckBox(panelUnits, ID_TRUESHOWCHECKBOX, _("Show true"));
5271     unitsSizer->Add(pCBTrueShow, 0, wxALL, group_item_spacing);
5272     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _T("")));
5273 
5274     pCBMagShow =  new wxCheckBox(panelUnits, ID_MAGSHOWCHECKBOX, _("Show magnetic"));
5275     unitsSizer->Add(pCBMagShow, 0, wxALL, group_item_spacing);
5276     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _T("")));
5277 
5278     //  Mag Heading user variation
5279 
5280     wxStaticBox* itemStaticBoxVar = new wxStaticBox(panelUnits, wxID_ANY, _T(""));
5281 
5282     wxStaticBoxSizer* itemStaticBoxSizerVar = new wxStaticBoxSizer(itemStaticBoxVar, wxVERTICAL);
5283     wrapperSizer->Add(itemStaticBoxSizerVar, 0, wxALL | wxEXPAND, 5);
5284 
5285     itemStaticBoxSizerVar->Add(0, border_size * 4);
5286 
5287     itemStaticTextUserVar = new wxStaticText(panelUnits, wxID_ANY, _("Assumed magnetic variation") );
5288     itemStaticBoxSizerVar->Add(itemStaticTextUserVar, 1, wxEXPAND | wxALL, group_item_spacing);
5289 
5290     wxBoxSizer* magVarSizer = new wxBoxSizer(wxHORIZONTAL);
5291     itemStaticBoxSizerVar->Add(magVarSizer, 1, wxEXPAND | wxALL, group_item_spacing);
5292 
5293     pMagVar = new wxTextCtrl(panelUnits, ID_OPTEXTCTRL, _T(""),
5294                              wxDefaultPosition, wxSize(150, -1), wxTE_RIGHT);
5295     magVarSizer->AddSpacer(100);
5296 
5297     magVarSizer->Add(pMagVar, 0, wxALIGN_CENTRE_VERTICAL, group_item_spacing);
5298 
5299     itemStaticTextUserVar2 = new wxStaticText(panelUnits, wxID_ANY, _("deg (-W, +E)"));
5300 
5301     magVarSizer->Add(itemStaticTextUserVar2, 0, wxALL | wxALIGN_CENTRE_VERTICAL, group_item_spacing);
5302 
5303     itemStaticBoxSizerVar->Add(0, border_size * 40);
5304 
5305   } else {
5306     wxFlexGridSizer* unitsSizer = new wxFlexGridSizer(2);
5307     unitsSizer->SetHGap(border_size);
5308 
5309     // wxFlexGridSizer grows wrongly in wx2.8, so we need to centre it in
5310     // another sizer instead of letting it grow.
5311     wxBoxSizer* wrapperSizer = new wxBoxSizer(wxVERTICAL);
5312     panelUnits->SetSizer(wrapperSizer);
5313     wrapperSizer->Add(unitsSizer, 1, wxALL | wxALIGN_CENTER, border_size);
5314 
5315     // spacer
5316     unitsSizer->Add(0, border_size * 4);
5317     unitsSizer->Add(0, border_size * 4);
5318 
5319     // distance units
5320     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Distance")),
5321                     labelFlags);
5322     wxString pDistanceFormats[] = {_("Nautical miles"), _("Statute miles"),
5323                                    _("Kilometers"), _("Meters")};
5324     int m_DistanceFormatsNChoices = sizeof(pDistanceFormats) / sizeof(wxString);
5325     pDistanceFormat = new wxChoice(panelUnits, ID_DISTANCEUNITSCHOICE,
5326                                    wxDefaultPosition, wxDefaultSize,
5327                                    m_DistanceFormatsNChoices, pDistanceFormats);
5328     unitsSizer->Add(pDistanceFormat, inputFlags);
5329 
5330     // speed units
5331     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Speed")),
5332                     labelFlags);
5333     wxString pSpeedFormats[] = {_("Knots"), _("Mph"), _("km/h"), _("m/s")};
5334     int m_SpeedFormatsNChoices = sizeof(pSpeedFormats) / sizeof(wxString);
5335     pSpeedFormat =
5336         new wxChoice(panelUnits, ID_SPEEDUNITSCHOICE, wxDefaultPosition,
5337                      wxDefaultSize, m_SpeedFormatsNChoices, pSpeedFormats);
5338     unitsSizer->Add(pSpeedFormat, inputFlags);
5339 
5340     // depth units
5341     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Depth")),
5342                     labelFlags);
5343     wxString pDepthUnitStrings[] = {
5344         _("Feet"), _("Meters"), _("Fathoms"),
5345     };
5346     pDepthUnitSelect =
5347         new wxChoice(panelUnits, ID_DEPTHUNITSCHOICE, wxDefaultPosition,
5348                      wxDefaultSize, 3, pDepthUnitStrings);
5349     unitsSizer->Add(pDepthUnitSelect, inputFlags);
5350 
5351     // spacer
5352     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _T("")));
5353     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _T("")));
5354 
5355     // lat/long units
5356     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Lat/Long")),
5357                     labelFlags);
5358     wxString pSDMMFormats[] = {_("Degrees, Decimal Minutes"),
5359                                _("Decimal Degrees"),
5360                                _("Degrees, Minutes, Seconds")};
5361     int m_SDMMFormatsNChoices = sizeof(pSDMMFormats) / sizeof(wxString);
5362     pSDMMFormat =
5363         new wxChoice(panelUnits, ID_SDMMFORMATCHOICE, wxDefaultPosition,
5364                      wxDefaultSize, m_SDMMFormatsNChoices, pSDMMFormats);
5365     unitsSizer->Add(pSDMMFormat, inputFlags);
5366 
5367     // spacer
5368     unitsSizer->Add(0, border_size * 4);
5369     unitsSizer->Add(0, border_size * 4);
5370 
5371     // bearings (magnetic/true, variation)
5372     unitsSizer->Add(new wxStaticText(panelUnits, wxID_ANY, _("Bearings")),
5373                     groupLabelFlags);
5374 
5375     wxBoxSizer* bearingsSizer = new wxBoxSizer(wxVERTICAL);
5376     unitsSizer->Add(bearingsSizer, 0, 0, 0);
5377 
5378     //  "Mag Heading" checkbox
5379     pCBTrueShow = new wxCheckBox(panelUnits, ID_TRUESHOWCHECKBOX,
5380                                 _("Show true bearings and headings"));
5381     bearingsSizer->Add(pCBTrueShow, 0, wxALL, group_item_spacing);
5382     pCBMagShow = new wxCheckBox(panelUnits, ID_MAGSHOWCHECKBOX,
5383                                 _("Show magnetic bearings and headings."));
5384     bearingsSizer->Add(pCBMagShow, 0, wxALL, group_item_spacing);
5385 
5386     bearingsSizer->AddSpacer(10);
5387 
5388 
5389     //  Mag Heading user variation
5390     wxBoxSizer* magVarSizer = new wxBoxSizer(wxHORIZONTAL);
5391     bearingsSizer->Add(magVarSizer, 0, wxALL, group_item_spacing);
5392 
5393     itemStaticTextUserVar = new wxStaticText(panelUnits, wxID_ANY, wxEmptyString);
5394     itemStaticTextUserVar->SetLabel(_("WMM Plugin calculated magnetic variation"));
5395 
5396     magVarSizer->Add(itemStaticTextUserVar, 0, wxALL | wxALIGN_CENTRE_VERTICAL,
5397                      group_item_spacing);
5398 
5399     pMagVar = new wxTextCtrl(panelUnits, ID_OPTEXTCTRL, _T(""),
5400                              wxDefaultPosition, wxSize(50, -1), wxTE_RIGHT);
5401     magVarSizer->Add(pMagVar, 0, wxALIGN_CENTRE_VERTICAL, group_item_spacing);
5402 
5403 	itemStaticTextUserVar2 = new wxStaticText(panelUnits, wxID_ANY, _("deg (-W, +E)"));
5404     magVarSizer->Add(itemStaticTextUserVar2, 0, wxALL | wxALIGN_CENTRE_VERTICAL, group_item_spacing);
5405 
5406     bearingsSizer->AddSpacer(10);
5407 
5408     wxStaticText *varText = new wxStaticText(panelUnits, wxID_ANY, _(" To set the magnetic variation manually,\n you must disable the WMM plugin."));
5409     smallFont = *dialogFont;
5410     smallFont.SetPointSize((smallFont.GetPointSize() / 1.2) +  0.5);  // + 0.5 to round instead of truncate
5411     varText->SetFont(smallFont);
5412 
5413     bearingsSizer->Add(varText);
5414 
5415   }
5416 }
5417 
CreatePanel_MMSI(size_t parent,int border_size,int group_item_spacing)5418 void options::CreatePanel_MMSI(size_t parent, int border_size,
5419                                int group_item_spacing) {
5420   wxScrolledWindow* panelMMSI = AddPage(parent, _("MMSI Properties"));
5421 
5422   wxBoxSizer* MMSISizer = new wxBoxSizer(wxVERTICAL);
5423   panelMMSI->SetSizer(MMSISizer);
5424 
5425   // MMSI list control (panel)
5426   wxStaticBox* itemStaticBoxMMSI =
5427       new wxStaticBox(panelMMSI, wxID_ANY, _("MMSI Properties"));
5428   wxStaticBoxSizer* itemStaticBoxSizerMMSI =
5429       new wxStaticBoxSizer(itemStaticBoxMMSI, wxVERTICAL);
5430   MMSISizer->Add(itemStaticBoxSizerMMSI, 0, wxALL | wxEXPAND, border_size);
5431 
5432   MMSI_Props_Panel* pPropsPanel = new MMSI_Props_Panel(panelMMSI);
5433 
5434   pPropsPanel->UpdateMMSIList();
5435 
5436   itemStaticBoxSizerMMSI->Add(pPropsPanel, 0, wxALL | wxEXPAND, border_size);
5437 
5438   panelMMSI->Layout();
5439 }
5440 
CreatePanel_AIS(size_t parent,int border_size,int group_item_spacing)5441 void options::CreatePanel_AIS(size_t parent, int border_size,
5442                               int group_item_spacing) {
5443   wxScrolledWindow* panelAIS = AddPage(parent, _("AIS Targets"));
5444 
5445   wxBoxSizer* aisSizer = new wxBoxSizer(wxVERTICAL);
5446   panelAIS->SetSizer(aisSizer);
5447 
5448   //      CPA Box
5449   wxStaticBox* itemStaticBoxCPA =
5450       new wxStaticBox(panelAIS, wxID_ANY, _("CPA Calculation"));
5451   wxStaticBoxSizer* itemStaticBoxSizerCPA =
5452       new wxStaticBoxSizer(itemStaticBoxCPA, wxVERTICAL);
5453   aisSizer->Add(itemStaticBoxSizerCPA, 0, wxALL | wxEXPAND, border_size);
5454 
5455   wxFlexGridSizer* pCPAGrid = new wxFlexGridSizer(2);
5456   pCPAGrid->AddGrowableCol(1);
5457   itemStaticBoxSizerCPA->Add(pCPAGrid, 0, wxALL | wxEXPAND, border_size);
5458 
5459   m_pCheck_CPA_Max = new wxCheckBox(
5460       panelAIS, -1, _("No (T)CPA Alerts if target range is greater than (NMi)"));
5461   pCPAGrid->Add(m_pCheck_CPA_Max, 0, wxALL, group_item_spacing);
5462 
5463   m_pText_CPA_Max = new wxTextCtrl(panelAIS, -1);
5464   pCPAGrid->Add(m_pText_CPA_Max, 0, wxALL | wxALIGN_RIGHT, group_item_spacing);
5465 
5466   m_pCheck_CPA_Warn =
5467       new wxCheckBox(panelAIS, -1, _("Warn if CPA less than (NMi)"));
5468   pCPAGrid->Add(m_pCheck_CPA_Warn, 0, wxALL, group_item_spacing);
5469 
5470   m_pText_CPA_Warn =
5471       new wxTextCtrl(panelAIS, -1, _T(""), wxDefaultPosition, wxSize(-1, -1));
5472   pCPAGrid->Add(m_pText_CPA_Warn, 0, wxALL | wxALIGN_RIGHT, group_item_spacing);
5473 
5474   m_pCheck_CPA_Warn->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
5475                              wxCommandEventHandler(options::OnCPAWarnClick),
5476                              NULL, this);
5477 
5478   m_pCheck_CPA_WarnT =
5479       new wxCheckBox(panelAIS, -1, _("...and TCPA is less than (min)"));
5480   pCPAGrid->Add(m_pCheck_CPA_WarnT, 0, wxALL, group_item_spacing);
5481 
5482   m_pText_CPA_WarnT = new wxTextCtrl(panelAIS, -1);
5483   pCPAGrid->Add(m_pText_CPA_WarnT, 0, wxALL | wxALIGN_RIGHT,
5484                 group_item_spacing);
5485 
5486   //      Lost Targets
5487   wxStaticBox* lostBox = new wxStaticBox(panelAIS, wxID_ANY, _("Lost Targets"));
5488   wxStaticBoxSizer* lostSizer = new wxStaticBoxSizer(lostBox, wxVERTICAL);
5489   aisSizer->Add(lostSizer, 0, wxALL | wxEXPAND, 3);
5490 
5491   wxFlexGridSizer* pLostGrid = new wxFlexGridSizer(2);
5492   pLostGrid->AddGrowableCol(1);
5493   lostSizer->Add(pLostGrid, 0, wxALL | wxEXPAND, border_size);
5494 
5495   m_pCheck_Mark_Lost =
5496       new wxCheckBox(panelAIS, -1, _("Mark targets as lost after (min)"));
5497   pLostGrid->Add(m_pCheck_Mark_Lost, 1, wxALL, group_item_spacing);
5498 
5499   m_pText_Mark_Lost = new wxTextCtrl(panelAIS, -1);
5500   pLostGrid->Add(m_pText_Mark_Lost, 1, wxALL | wxALIGN_RIGHT,
5501                  group_item_spacing);
5502 
5503   m_pCheck_Remove_Lost = new wxCheckBox(panelAIS, -1, _("Remove lost targets after (min)"));
5504   pLostGrid->Add(m_pCheck_Remove_Lost, 1, wxALL, group_item_spacing);
5505 
5506   m_pText_Remove_Lost = new wxTextCtrl(panelAIS, -1);
5507   pLostGrid->Add(m_pText_Remove_Lost, 1, wxALL | wxALIGN_RIGHT,
5508                  group_item_spacing);
5509 
5510   if(g_bInlandEcdis)
5511       lostSizer->Hide(pLostGrid, true);
5512 
5513   //      Display
5514   wxStaticBox* displBox = new wxStaticBox(panelAIS, wxID_ANY, _("Display"));
5515   wxStaticBoxSizer* displSizer = new wxStaticBoxSizer(displBox, wxHORIZONTAL);
5516   aisSizer->Add(displSizer, 0, wxALL | wxEXPAND, border_size);
5517 
5518   wxFlexGridSizer* pDisplayGrid = new wxFlexGridSizer(2);
5519   pDisplayGrid->AddGrowableCol(1);
5520   displSizer->Add(pDisplayGrid, 1, wxALL | wxEXPAND, border_size);
5521 
5522   m_pCheck_Show_COG = new wxCheckBox(
5523       panelAIS, -1, _("Show target COG predictor arrow, length (min)"));
5524   pDisplayGrid->Add(m_pCheck_Show_COG, 1, wxALL | wxEXPAND, group_item_spacing);
5525 
5526   m_pText_COG_Predictor = new wxTextCtrl(panelAIS, -1);
5527   pDisplayGrid->Add(m_pText_COG_Predictor, 1, wxALL | wxALIGN_RIGHT,
5528                     group_item_spacing);
5529 
5530   m_pCheck_Show_Tracks =
5531       new wxCheckBox(panelAIS, -1, _("Show target tracks, length (min)"));
5532   pDisplayGrid->Add(m_pCheck_Show_Tracks, 1, wxALL, group_item_spacing);
5533 
5534   m_pText_Track_Length = new wxTextCtrl(panelAIS, -1);
5535   pDisplayGrid->Add(m_pText_Track_Length, 1, wxALL | wxALIGN_RIGHT,
5536                     group_item_spacing);
5537 
5538   m_pCheck_Hide_Moored = new wxCheckBox(
5539       panelAIS, -1, _("Suppress anchored/moored targets, speed max (kn)"));
5540   pDisplayGrid->Add(m_pCheck_Hide_Moored, 1, wxALL, group_item_spacing);
5541 
5542   m_pText_Moored_Speed = new wxTextCtrl(panelAIS, -1);
5543   pDisplayGrid->Add(m_pText_Moored_Speed, 1, wxALL | wxALIGN_RIGHT,
5544                     group_item_spacing);
5545 
5546   m_pCheck_Draw_Realtime_Prediction = new wxCheckBox(
5547       panelAIS, -1, _("Draw AIS realtime prediction, target speed min (kn)"));
5548   pDisplayGrid->Add(m_pCheck_Draw_Realtime_Prediction, 1, wxALL, group_item_spacing);
5549 
5550   m_pText_RealtPred_Speed = new wxTextCtrl(panelAIS, -1);
5551   pDisplayGrid->Add(m_pText_RealtPred_Speed, 1, wxALL | wxALIGN_RIGHT,
5552       group_item_spacing);
5553 
5554   m_pCheck_Scale_Priority = new wxCheckBox(
5555       panelAIS, -1, _("Allow attenuation of less critical targets if more than ... targets"));
5556   pDisplayGrid->Add(m_pCheck_Scale_Priority, 1, wxALL, group_item_spacing);
5557 
5558   m_pText_Scale_Priority = new wxTextCtrl(panelAIS, -1);
5559   pDisplayGrid->Add(m_pText_Scale_Priority, 1, wxALL | wxALIGN_RIGHT,
5560                     group_item_spacing);
5561 
5562   m_pCheck_Show_Area_Notices = new wxCheckBox(
5563       panelAIS, -1, _("Show area notices (from AIS binary messages)"));
5564   pDisplayGrid->Add(m_pCheck_Show_Area_Notices, 1, wxALL, group_item_spacing);
5565 
5566   wxStaticText* pStatic_Dummy5 = new wxStaticText(panelAIS, -1, _T(""));
5567   pDisplayGrid->Add(pStatic_Dummy5, 1, wxALL, group_item_spacing);
5568 
5569   m_pCheck_Draw_Target_Size =
5570       new wxCheckBox(panelAIS, -1, _("Show AIS targets real size"));
5571   pDisplayGrid->Add(m_pCheck_Draw_Target_Size, 1, wxALL, group_item_spacing);
5572 
5573   wxStaticText* pStatic_Dummy6 = new wxStaticText(panelAIS, -1, _T(""));
5574   pDisplayGrid->Add(pStatic_Dummy6, 1, wxALL, group_item_spacing);
5575 
5576   m_pCheck_Show_Target_Name = new wxCheckBox(
5577       panelAIS, -1, _("Show names with AIS targets at scale greater than 1:"));
5578   pDisplayGrid->Add(m_pCheck_Show_Target_Name, 1, wxALL, group_item_spacing);
5579 
5580   m_pText_Show_Target_Name_Scale = new wxTextCtrl(panelAIS, -1);
5581   pDisplayGrid->Add(m_pText_Show_Target_Name_Scale, 1, wxALL | wxALIGN_RIGHT,
5582                     group_item_spacing);
5583 
5584   m_pCheck_Wpl_Aprs = new wxCheckBox(
5585       panelAIS, -1, _("Treat WPL sentences as APRS position reports"));
5586   pDisplayGrid->Add(m_pCheck_Wpl_Aprs, 1, wxALL, group_item_spacing);
5587 
5588   wxStaticText* pStatic_Dummy7 = new wxStaticText(panelAIS, -1, _T(""));
5589   pDisplayGrid->Add(pStatic_Dummy7, 1, wxALL, group_item_spacing);
5590 
5591   wxStaticText* pStatic_Dummy5a = new wxStaticText(panelAIS, -1, _T(""));
5592   pDisplayGrid->Add(pStatic_Dummy5a, 1, wxALL, group_item_spacing);
5593 
5594   // Rollover
5595   wxStaticBox* rolloverBox = new wxStaticBox(panelAIS, wxID_ANY, _("Rollover"));
5596   wxStaticBoxSizer* rolloverSizer =
5597       new wxStaticBoxSizer(rolloverBox, wxVERTICAL);
5598   aisSizer->Add(rolloverSizer, 0, wxALL | wxEXPAND, border_size);
5599 
5600   pRollover = new wxCheckBox(panelAIS, ID_ROLLOVERBOX, _("Enable route/AIS info block"));
5601   rolloverSizer->Add(pRollover, 1, wxALL, 2 * group_item_spacing);
5602 
5603   pRollover->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED,  wxCommandEventHandler(options::OnAISRolloverClick), NULL, this);
5604 
5605   pStatic_CallSign = new wxStaticText(panelAIS, -1, _("\"Ship Name\" MMSI (Call Sign)"));
5606   rolloverSizer->Add(pStatic_CallSign, 1, wxALL, 2 * group_item_spacing);
5607 
5608   m_pCheck_Rollover_Class =
5609       new wxCheckBox(panelAIS, -1, _("[Class] Type (Status)"));
5610   rolloverSizer->Add(m_pCheck_Rollover_Class, 1, wxALL, 2 * group_item_spacing);
5611 
5612   m_pCheck_Rollover_COG = new wxCheckBox(panelAIS, -1, _("SOG COG"));
5613   rolloverSizer->Add(m_pCheck_Rollover_COG, 1, wxALL, 2 * group_item_spacing);
5614 
5615   m_pCheck_Rollover_CPA = new wxCheckBox(panelAIS, -1, _("CPA TCPA"));
5616   rolloverSizer->Add(m_pCheck_Rollover_CPA, 1, wxALL, 2 * group_item_spacing);
5617 
5618   //      Alert Box
5619   wxStaticBox* alertBox =
5620       new wxStaticBox(panelAIS, wxID_ANY, _("CPA/TCPA Alerts"));
5621   wxStaticBoxSizer* alertSizer = new wxStaticBoxSizer(alertBox, wxVERTICAL);
5622   aisSizer->Add(alertSizer, 0, wxALL | wxEXPAND, group_item_spacing);
5623 
5624   wxFlexGridSizer* pAlertGrid = new wxFlexGridSizer(2);
5625   pAlertGrid->AddGrowableCol(1);
5626   alertSizer->Add(pAlertGrid, 0, wxALL | wxEXPAND, group_item_spacing);
5627 
5628   m_pCheck_AlertDialog = new wxCheckBox(panelAIS, ID_AISALERTDIALOG,
5629                                         _("Show CPA/TCPA Alert Dialog"));
5630   pAlertGrid->Add(m_pCheck_AlertDialog, 0, wxALL, group_item_spacing);
5631 
5632   wxButton* m_SelSound =
5633       new wxButton(panelAIS, ID_AISALERTSELECTSOUND, _("Select Alert Sound"),
5634                    wxDefaultPosition, m_small_button_size, 0);
5635   pAlertGrid->Add(m_SelSound, 0, wxALL | wxALIGN_RIGHT, group_item_spacing);
5636 
5637   m_pCheck_AlertAudio = new wxCheckBox(
5638       panelAIS, ID_AISALERTAUDIO,
5639       _("Play Sound on CPA/TCPA Alerts and DSC/SART emergencies."));
5640   pAlertGrid->Add(m_pCheck_AlertAudio, 0, wxALL, group_item_spacing);
5641 
5642   wxButton* m_pPlay_Sound =
5643       new wxButton(panelAIS, ID_AISALERTTESTSOUND, _("Test Alert Sound"),
5644                    wxDefaultPosition, m_small_button_size, 0);
5645   pAlertGrid->Add(m_pPlay_Sound, 0, wxALL | wxALIGN_RIGHT, group_item_spacing);
5646 
5647   m_pCheck_Alert_Moored = new wxCheckBox(
5648       panelAIS, -1, _("Suppress Alerts for anchored/moored targets"));
5649   pAlertGrid->Add(m_pCheck_Alert_Moored, 1, wxALL, group_item_spacing);
5650 
5651   wxStaticText* pStatic_Dummy2 = new wxStaticText(panelAIS, -1, _T(""));
5652   pAlertGrid->Add(pStatic_Dummy2, 1, wxALL, group_item_spacing);
5653 
5654   m_pCheck_Ack_Timout = new wxCheckBox(
5655       panelAIS, -1, _("Enable Target Alert Acknowledge timeout (min)"));
5656   pAlertGrid->Add(m_pCheck_Ack_Timout, 1, wxALL, group_item_spacing);
5657 
5658   m_pText_ACK_Timeout = new wxTextCtrl(panelAIS, -1);
5659   pAlertGrid->Add(m_pText_ACK_Timeout, 1, wxALL | wxALIGN_RIGHT,
5660                   group_item_spacing);
5661 
5662   panelAIS->Layout();
5663 }
5664 
CreatePanel_UI(size_t parent,int border_size,int group_item_spacing)5665 void options::CreatePanel_UI(size_t parent, int border_size, int group_item_spacing)
5666 {
5667   wxScrolledWindow* itemPanelFont = AddPage(parent, _("General Options"));
5668 
5669   m_itemBoxSizerFontPanel = new wxBoxSizer(wxVERTICAL);
5670   itemPanelFont->SetSizer(m_itemBoxSizerFontPanel);
5671 
5672   wxBoxSizer* langStyleBox = new wxBoxSizer(wxHORIZONTAL);
5673   m_itemBoxSizerFontPanel->Add(langStyleBox, 0, wxEXPAND | wxALL, border_size);
5674 
5675   wxStaticBox* itemLangStaticBox = new wxStaticBox(itemPanelFont, wxID_ANY, _("Language"));
5676   wxStaticBoxSizer* itemLangStaticBoxSizer = new wxStaticBoxSizer(itemLangStaticBox, wxVERTICAL);
5677 
5678   langStyleBox->Add(itemLangStaticBoxSizer, 1, wxEXPAND | wxALL, border_size);
5679 
5680   m_itemLangListBox = new wxChoice(itemPanelFont, ID_CHOICE_LANG);
5681 
5682   itemLangStaticBoxSizer->Add(m_itemLangListBox, 0, wxEXPAND | wxALL, border_size);
5683 #ifdef __OCPN__ANDROID__
5684   m_itemLangListBox->Disable();
5685 #endif
5686 
5687   wxStaticBox* itemFontStaticBox = new wxStaticBox(itemPanelFont, wxID_ANY, _("Fonts"));
5688 
5689   wxSize fontChoiceSize = wxSize( -1, -1 );
5690 
5691   int fLayout = wxHORIZONTAL;
5692 #ifdef __OCPN__ANDROID__
5693   // Compensate for very narrow displays on Android
5694   if(m_nCharWidthMax <  40)
5695       fLayout = wxVERTICAL;
5696 
5697    // Need to set wxChoice vertical size explicitely in Android
5698    fontChoiceSize = wxSize( -1, m_fontHeight * 3 / 4);
5699 #endif
5700 
5701   wxStaticBoxSizer* itemFontStaticBoxSizer = new wxStaticBoxSizer(itemFontStaticBox, fLayout);
5702   m_itemBoxSizerFontPanel->Add(itemFontStaticBoxSizer, 0, wxEXPAND | wxALL, border_size);
5703 
5704   m_itemFontElementListBox = new wxChoice(itemPanelFont, ID_CHOICE_FONTELEMENT, wxDefaultPosition, fontChoiceSize, 0, NULL, wxCB_SORT);
5705 
5706   int nFonts = FontMgr::Get().GetNumFonts();
5707   for (int it = 0; it < nFonts; it++) {
5708     const wxString& t = FontMgr::Get().GetDialogString(it);
5709 
5710     if (FontMgr::Get().GetConfigString(it).StartsWith(g_locale)) {
5711       m_itemFontElementListBox->Append(t);
5712     }
5713   }
5714 
5715   if (nFonts) m_itemFontElementListBox->SetSelection(0);
5716 
5717   itemFontStaticBoxSizer->Add(m_itemFontElementListBox, 0, wxALL, border_size);
5718 
5719   wxButton* itemFontChooseButton =
5720       new wxButton(itemPanelFont, ID_BUTTONFONTCHOOSE, _("Choose Font..."),
5721                    wxDefaultPosition, wxDefaultSize, 0);
5722   itemFontStaticBoxSizer->Add(itemFontChooseButton, 0, wxALL, border_size);
5723 #if defined(__WXGTK__) || defined(__WXQT__)
5724   wxButton* itemFontColorButton =
5725       new wxButton(itemPanelFont, ID_BUTTONFONTCOLOR, _("Choose Font Color..."),
5726                    wxDefaultPosition, wxDefaultSize, 0);
5727   itemFontStaticBoxSizer->Add(itemFontColorButton, 0, wxALL, border_size);
5728 #endif
5729   m_textSample = new wxStaticText(itemPanelFont, wxID_ANY, _("Sample"), wxDefaultPosition, wxDefaultSize, 0);
5730   itemFontStaticBoxSizer->Add(m_textSample, 0, wxALL, border_size);
5731   wxCommandEvent e;
5732   OnFontChoice(e);
5733 
5734 #if 0
5735   wxStaticBox* itemStyleStaticBox =
5736       new wxStaticBox(itemPanelFont, wxID_ANY, _("Toolbar and Window Style"));
5737   wxStaticBoxSizer* itemStyleStaticBoxSizer =
5738       new wxStaticBoxSizer(itemStyleStaticBox, wxVERTICAL);
5739   langStyleBox->Add(itemStyleStaticBoxSizer, 1, wxEXPAND | wxALL, border_size);
5740 
5741   m_itemStyleListBox = new wxChoice(itemPanelFont, ID_STYLESCOMBOBOX);
5742 
5743   wxArrayPtrVoid styles = g_StyleManager->GetArrayOfStyles();
5744   for (unsigned int i = 0; i < styles.Count(); i++) {
5745     ocpnStyle::Style* style = (ocpnStyle::Style*)(styles[i]);
5746     m_itemStyleListBox->Append(style->name);
5747   }
5748   m_itemStyleListBox->SetStringSelection(
5749       g_StyleManager->GetCurrentStyle()->name);
5750   itemStyleStaticBoxSizer->Add(m_itemStyleListBox, 1, wxEXPAND | wxALL,
5751                                border_size);
5752 #endif
5753   wxStaticBox* miscOptionsBox =
5754       new wxStaticBox(itemPanelFont, wxID_ANY, _("Interface Options"));
5755   wxStaticBoxSizer* miscOptions =
5756       new wxStaticBoxSizer(miscOptionsBox, wxVERTICAL);
5757   m_itemBoxSizerFontPanel->Add(miscOptions, 0, wxALL | wxEXPAND, border_size);
5758 
5759   pShowStatusBar =
5760       new wxCheckBox(itemPanelFont, ID_DEBUGCHECKBOX1, _("Show Status Bar"));
5761   pShowStatusBar->SetValue(FALSE);
5762   miscOptions->Add(pShowStatusBar, 0, wxALL, border_size);
5763 
5764 #ifndef __WXOSX__
5765   pShowMenuBar = new wxCheckBox(itemPanelFont, wxID_ANY, _("Show Menu Bar"));
5766   pShowMenuBar->SetValue(FALSE);
5767   miscOptions->Add(pShowMenuBar, 0, wxALL, border_size);
5768 #endif
5769 
5770 #ifdef __OCPN__ANDROID__
5771   pShowMenuBar->Hide();
5772 #endif
5773 
5774   pShowChartBar = new wxCheckBox(itemPanelFont, wxID_ANY, _("Show Chart Bar"));
5775   pShowChartBar->SetValue(g_bShowChartBar);
5776   miscOptions->Add(pShowChartBar, 0, wxALL, border_size);
5777 
5778   pShowCompassWin = new wxCheckBox(itemPanelFont, wxID_ANY,
5779                                    _("Show Compass/GPS Status Window"));
5780   pShowCompassWin->SetValue(FALSE);
5781   miscOptions->Add(pShowCompassWin, 0, wxALL, border_size);
5782 
5783   wxBoxSizer* pToolbarAutoHide = new wxBoxSizer(wxHORIZONTAL);
5784   miscOptions->Add(pToolbarAutoHide, 0, wxALL | wxEXPAND, group_item_spacing);
5785 
5786   pToolbarAutoHideCB = new wxCheckBox(itemPanelFont, wxID_ANY,
5787                                       _("Enable Toolbar auto-hide"));
5788   pToolbarAutoHide->Add(pToolbarAutoHideCB, 0, wxALL, group_item_spacing);
5789 
5790   pToolbarHideSecs =
5791       new wxTextCtrl(itemPanelFont, ID_OPTEXTCTRL, _T(""), wxDefaultPosition,
5792                      wxSize(50, -1), wxTE_RIGHT);
5793   pToolbarAutoHide->Add(pToolbarHideSecs, 0, wxALL,
5794                         group_item_spacing);
5795 
5796   pToolbarAutoHide->Add(new wxStaticText(itemPanelFont, wxID_ANY, _("seconds")),
5797                         group_item_spacing);
5798 
5799   wxBoxSizer* pShipsBellsSizer = new wxBoxSizer(wxHORIZONTAL);
5800   miscOptions->Add(pShipsBellsSizer, 0, wxALL, group_item_spacing);
5801   // Sound options
5802   pPlayShipsBells =
5803       new wxCheckBox(itemPanelFont, ID_BELLSCHECKBOX, _("Play Ships Bells"));
5804   pShipsBellsSizer->Add(pPlayShipsBells, 0, wxALL | wxEXPAND, border_size);
5805 
5806 #ifndef __OCPN__ANDROID__
5807   if ( g_bUIexpert && (bool) dynamic_cast<SystemCmdSound*>(SoundFactory()) ) {
5808       wxBoxSizer* pSoundSizer = new wxBoxSizer( wxVERTICAL );
5809       pShipsBellsSizer->Add( pSoundSizer, 0, wxALL | wxEXPAND, group_item_spacing );
5810       pCmdSoundString = new wxTextCtrl( itemPanelFont, wxID_ANY, _T( "" ),
5811                                         wxDefaultPosition,
5812                                         wxSize( 450, -1 ), wxTE_LEFT );
5813       pSoundSizer->Add( new wxStaticText( itemPanelFont, wxID_ANY,
5814                         _( "Audio Play command:" ) ), 0,
5815                         wxALIGN_CENTER_HORIZONTAL | wxALL );
5816       pSoundSizer->Add( pCmdSoundString, 1, wxEXPAND | wxALIGN_LEFT, border_size );
5817   }
5818 #endif
5819 
5820   OcpnSound* sound = SoundFactory();
5821   int deviceCount = sound->DeviceCount();
5822   wxLogMessage("options: got device count: %d", deviceCount);
5823   if (deviceCount >= 1) {
5824     wxArrayString labels;
5825     for (int i = 0; i < deviceCount; i += 1) {
5826         if (!sound->IsOutputDevice(i)) {
5827             continue;
5828         }
5829         wxString label(sound->GetDeviceInfo(i));
5830         if (label == "")  {
5831             std::ostringstream stm ;
5832             stm << i ;
5833             label = _("Unknown device :") + stm.str();
5834             labels.Add(label);
5835         }
5836     }
5837     pSoundDeviceIndex = new wxChoice();
5838     if (pSoundDeviceIndex) {
5839         pSoundDeviceIndex->Create(itemPanelFont,
5840             wxID_ANY,
5841             wxDefaultPosition,
5842             wxDefaultSize,
5843             labels);
5844         pSoundDeviceIndex->SetSelection(g_iSoundDeviceIndex);
5845         pSoundDeviceIndex->Show();
5846         wxFlexGridSizer* pSoundDeviceIndexGrid = new wxFlexGridSizer(2);
5847         miscOptions->Add(pSoundDeviceIndexGrid, 0, wxALL | wxEXPAND,
5848             group_item_spacing);
5849 
5850         stSoundDeviceIndex = new wxStaticText(itemPanelFont, wxID_STATIC, _("Sound Device"));
5851         pSoundDeviceIndexGrid->Add(stSoundDeviceIndex, 0, wxALL, 5);
5852         pSoundDeviceIndexGrid->Add(pSoundDeviceIndex, 0, wxALL, border_size);
5853     }
5854   }
5855 #ifdef __OCPN__ANDROID__
5856     stSoundDeviceIndex->Hide();
5857     pSoundDeviceIndex->Hide();
5858 #endif
5859 
5860   //  Mobile/Touchscreen checkboxes
5861   pMobile = new wxCheckBox(itemPanelFont, ID_MOBILEBOX,
5862                            _("Enable Touchscreen interface"));
5863   miscOptions->Add(pMobile, 0, wxALL, border_size);
5864 
5865   pResponsive = new wxCheckBox(itemPanelFont, ID_REPONSIVEBOX,
5866                                _("Enable Scaled Graphics interface"));
5867   miscOptions->Add(pResponsive, 0, wxALL, border_size);
5868 
5869   //  This two options are always needed for Android
5870 #ifdef __OCPN__ANDROID__
5871   pMobile->Hide();
5872   pResponsive->Hide();
5873 #endif
5874 
5875   pZoomButtons = new wxCheckBox(itemPanelFont, ID_ZOOMBUTTONS, _("Show Zoom buttons"));
5876   miscOptions->Add(pZoomButtons, 0, wxALL, border_size);
5877 #ifndef __OCPN__ANDROID__
5878   pZoomButtons->Hide();
5879 #endif
5880 
5881   pInlandEcdis = new wxCheckBox(itemPanelFont, ID_INLANDECDISBOX,  _("Use Inland ECDIS V2.3"));
5882   miscOptions->Add(pInlandEcdis, 0, wxALL, border_size);
5883 
5884 #ifdef __OCPN__ANDROID__
5885   pInlandEcdis->Hide();
5886 #endif
5887 
5888 #ifdef __WXOSX__
5889   pDarkDecorations = new wxCheckBox(itemPanelFont, ID_DARKDECORATIONSBOX,
5890                                   _("Use dark window decorations"));
5891   miscOptions->Add(pDarkDecorations, 0, wxALL, border_size);
5892   pDarkDecorations->Enable( (osMajor >= 10) && (osMinor >= 12) );
5893 
5894 #endif
5895 
5896   miscOptions->AddSpacer(10);
5897 
5898   wxFlexGridSizer* sliderSizer;
5899   sliderSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
5900   sliderSizer->AddGrowableCol( 1 );
5901   sliderSizer->SetFlexibleDirection( wxBOTH );
5902   sliderSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
5903 
5904   m_pSlider_GUI_Factor = new wxSlider(
5905       itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
5906   m_pSlider_GUI_Factor->Hide();
5907   sliderSizer->Add(new wxStaticText(itemPanelFont, wxID_ANY,
5908                                     _("User Interface scale factor")),
5909                    inputFlags);
5910   sliderSizer->Add(m_pSlider_GUI_Factor, 0, wxALL, border_size);
5911   m_pSlider_GUI_Factor->Show();
5912 
5913 #ifdef __OCPN__ANDROID__
5914    prepareSlider( m_pSlider_GUI_Factor);
5915 #endif
5916 
5917   m_pSlider_Chart_Factor = new wxSlider(
5918       itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition, m_sliderSize, SLIDER_STYLE);
5919   m_pSlider_Chart_Factor->Hide();
5920   sliderSizer->Add(
5921       new wxStaticText(itemPanelFont, wxID_ANY, _("Chart Object scale factor")), inputFlags);
5922   sliderSizer->Add(m_pSlider_Chart_Factor, 0, wxALL, border_size);
5923   m_pSlider_Chart_Factor->Show();
5924 
5925 #ifdef __OCPN__ANDROID__
5926    prepareSlider(m_pSlider_Chart_Factor);
5927 #endif
5928 
5929   m_pSlider_Ship_Factor = new wxSlider( itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,  m_sliderSize, SLIDER_STYLE);
5930   m_pSlider_Ship_Factor->Hide();
5931   sliderSizer->Add(
5932       new wxStaticText(itemPanelFont, wxID_ANY, _("Ship scale factor")), inputFlags);
5933   sliderSizer->Add(m_pSlider_Ship_Factor, 0, wxALL, border_size);
5934   m_pSlider_Ship_Factor->Show();
5935 
5936 #ifdef __OCPN__ANDROID__
5937   m_pSlider_Ship_Factor->GetHandle()->setStyleSheet(getQtStyleSheet());
5938 #endif
5939 
5940   m_pSlider_Text_Factor = new wxSlider( itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,  m_sliderSize, SLIDER_STYLE);
5941   m_pSlider_Text_Factor->Hide();
5942   sliderSizer->Add(
5943       new wxStaticText(itemPanelFont, wxID_ANY, _("ENC Sounding factor")), inputFlags);
5944   sliderSizer->Add(m_pSlider_Text_Factor, 0, wxALL, border_size);
5945   m_pSlider_Text_Factor->Show();
5946 
5947 #ifdef __OCPN__ANDROID__
5948   m_pSlider_Text_Factor->GetHandle()->setStyleSheet(getQtStyleSheet());
5949 #endif
5950 
5951   miscOptions->Add( sliderSizer, 0, wxEXPAND, 5 );
5952   miscOptions->AddSpacer(20);
5953 }
5954 
CreateListbookIcons()5955 void options::CreateListbookIcons()
5956 {
5957     ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
5958 
5959     if(!g_bresponsive){
5960         m_topImgList = new wxImageList(40, 40, TRUE, 1);
5961 
5962         #if wxCHECK_VERSION(2, 8, 12)
5963         m_topImgList->Add(style->GetIcon(_T("Display")));
5964         m_topImgList->Add(style->GetIcon(_T("Charts")));
5965         m_topImgList->Add(style->GetIcon(_T("Connections")));
5966         m_topImgList->Add(style->GetIcon(_T("Ship")));
5967         m_topImgList->Add(style->GetIcon(_T("UI")));
5968         m_topImgList->Add(style->GetIcon(_T("Plugins")));
5969         #else
5970         wxBitmap bmp;
5971         wxImage img;
5972         bmp = style->GetIcon(_T("Display"));
5973         img = bmp.ConvertToImage();
5974         img.ConvertAlphaToMask(128);
5975         bmp = wxBitmap(img);
5976         m_topImgList->Add(bmp);
5977         bmp = style->GetIcon(_T("Charts"));
5978         img = bmp.ConvertToImage();
5979         img.ConvertAlphaToMask(128);
5980         bmp = wxBitmap(img);
5981         m_topImgList->Add(bmp);
5982         bmp = style->GetIcon(_T("Connections"));
5983         img = bmp.ConvertToImage();
5984         img.ConvertAlphaToMask(128);
5985         bmp = wxBitmap(img);
5986         m_topImgList->Add(bmp);
5987         bmp = style->GetIcon(_T("Ship"));
5988         img = bmp.ConvertToImage();
5989         img.ConvertAlphaToMask(128);
5990         bmp = wxBitmap(img);
5991         m_topImgList->Add(bmp);
5992         bmp = style->GetIcon(_T("UI"));
5993         img = bmp.ConvertToImage();
5994         img.ConvertAlphaToMask(128);
5995         bmp = wxBitmap(img);
5996         m_topImgList->Add(bmp);
5997         bmp = style->GetIcon(_T("Plugins"));
5998         img = bmp.ConvertToImage();
5999         img.ConvertAlphaToMask(128);
6000         bmp = wxBitmap(img);
6001         m_topImgList->Add(bmp);
6002         #endif
6003     }
6004     else{
6005         wxBitmap bmps;
6006         bmps = style->GetIcon(_T("Display"));
6007         int base_size = bmps.GetWidth();
6008         double tool_size = base_size;
6009 
6010         double premult = 1.0;
6011 
6012         // unless overridden by user, we declare the "best" size
6013         // to be roughly 6 mm square.
6014         double target_size = 6.0;                // mm
6015 
6016         double basic_tool_size_mm = tool_size / g_Platform->GetDisplayDPmm();
6017         premult = target_size / basic_tool_size_mm;
6018 
6019         //Adjust the scale factor using the global GUI scale parameter
6020         double postmult =  exp( g_GUIScaleFactor * (0.693 / 5.0) );       //  exp(2)
6021         postmult = wxMin(postmult, 3.0);
6022         postmult = wxMax(postmult, 1.0);
6023 
6024         int sizeTab = base_size * postmult * premult;
6025 
6026         m_topImgList = new wxImageList(sizeTab, sizeTab, TRUE, 1);
6027 
6028         wxBitmap bmp;
6029         wxImage img, simg;
6030         bmp = style->GetIcon(_T("Display"));
6031         img = bmp.ConvertToImage();
6032         simg = img.Scale(sizeTab, sizeTab);
6033         bmp = wxBitmap(simg);
6034         m_topImgList->Add(bmp);
6035         bmp = style->GetIcon(_T("Charts"));
6036         img = bmp.ConvertToImage();
6037         simg = img.Scale(sizeTab, sizeTab);
6038         bmp = wxBitmap(simg);
6039         m_topImgList->Add(bmp);
6040         bmp = style->GetIcon(_T("Connections"));
6041         img = bmp.ConvertToImage();
6042         simg = img.Scale(sizeTab, sizeTab);
6043         bmp = wxBitmap(simg);
6044         m_topImgList->Add(bmp);
6045         bmp = style->GetIcon(_T("Ship"));
6046         img = bmp.ConvertToImage();
6047         simg = img.Scale(sizeTab, sizeTab);
6048         bmp = wxBitmap(simg);
6049         m_topImgList->Add(bmp);
6050         bmp = style->GetIcon(_T("UI"));
6051         img = bmp.ConvertToImage();
6052         simg = img.Scale(sizeTab, sizeTab);
6053         bmp = wxBitmap(simg);
6054         m_topImgList->Add(bmp);
6055         bmp = style->GetIcon(_T("Plugins"));
6056         img = bmp.ConvertToImage();
6057         simg = img.Scale(sizeTab, sizeTab);
6058         bmp = wxBitmap(simg);
6059         m_topImgList->Add(bmp);
6060     }
6061 
6062 }
6063 
6064 
CreateControls(void)6065 void options::CreateControls(void) {
6066   int border_size = 4;
6067   // use for items within one group, with Add(...wxALL)
6068   int group_item_spacing = 2;
6069 
6070   int font_size_y, font_descent, font_lead;
6071   GetTextExtent(_T("0"), NULL, &font_size_y, &font_descent, &font_lead);
6072   m_fontHeight = font_size_y + font_descent + font_lead;
6073 
6074 #ifdef __OCPN__ANDROID__
6075   m_sliderSize = wxSize(wxMin(m_fontHeight * 8, g_Platform->getDisplaySize().x / 2), m_fontHeight * 8 / 10);
6076 #else
6077   m_sliderSize = wxSize(wxMin(m_fontHeight * 8, g_Platform->getDisplaySize().x / 2), m_fontHeight * 2);
6078 #endif
6079 
6080   m_small_button_size =
6081       wxSize(-1, (int)(1.4 * (font_size_y + font_descent + font_lead)));
6082 
6083   m_nCharWidthMax = GetSize().x / GetCharWidth();
6084 
6085   // Some members (pointers to controls) need to initialized
6086   pEnableZoomToCursor = NULL;
6087   pSmoothPanZoom = NULL;
6088 
6089   // Check the display size.
6090   // If "small", adjust some factors to squish out some more white space
6091   int width, height;
6092   ::wxDisplaySize(&width, &height);
6093 
6094   if (!g_bresponsive && height <= 800) {
6095     border_size = 2;
6096     group_item_spacing = 1;
6097   }
6098 
6099   labelFlags = wxSizerFlags(0)
6100                    .Align(wxALIGN_RIGHT)
6101                    .Border(wxALL, group_item_spacing);
6102   inputFlags = wxSizerFlags(0)
6103                    .Align(wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL)
6104                    .Border(wxALL, group_item_spacing);
6105   verticleInputFlags = wxSizerFlags(0)
6106                    .Align(wxALIGN_LEFT)
6107                    .Border(wxALL, group_item_spacing);
6108   groupLabelFlags = wxSizerFlags(0)
6109                         .Align(wxALIGN_RIGHT | wxALIGN_TOP)
6110                         .Border(wxALL, group_item_spacing);
6111   groupLabelFlagsHoriz = wxSizerFlags(0)
6112     .Align( wxALIGN_TOP)
6113     .Border(wxALL, group_item_spacing);
6114   groupInputFlags = wxSizerFlags(0)
6115                         .Align(wxALIGN_LEFT | wxALIGN_TOP)
6116                         .Border(wxBOTTOM, group_item_spacing * 2)
6117                         .Expand();
6118 
6119 #ifdef __WXGTK__
6120   groupLabelFlags.Border(wxTOP, group_item_spacing + 3);
6121 #endif
6122 
6123   options* itemDialog1 = this;
6124 
6125   wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
6126   itemDialog1->SetSizer(itemBoxSizer2);
6127 
6128 #ifdef __OCPN__ANDROID__
6129   //  Set Dialog Font by custom crafted Qt Stylesheet.
6130   wxFont* qFont = dialogFont;
6131 
6132   wxString wqs = getFontQtStylesheet(qFont);
6133   wxCharBuffer sbuf = wqs.ToUTF8();
6134   QString qsb = QString(sbuf.data());
6135 
6136   QString qsbq = getQtStyleSheet();  // basic scrollbars, etc
6137 
6138   itemDialog1->GetHandle()->setStyleSheet(qsb +
6139                                           qsbq);  // Concatenated style sheets
6140 
6141 #endif
6142 
6143   int flags = 0;
6144 
6145 #ifdef __OCPN__OPTIONS_USE_LISTBOOK__
6146   flags = wxLB_TOP;
6147   m_pListbook = new wxListbook(itemDialog1, ID_NOTEBOOK, wxDefaultPosition,
6148                                wxSize(-1, -1), flags);
6149   m_pListbook->Connect(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED,
6150                        wxListbookEventHandler(options::OnPageChange), NULL,
6151                        this);
6152 #else
6153   flags = wxNB_TOP;
6154   m_pListbook = new wxNotebook(itemDialog1, ID_NOTEBOOK, wxDefaultPosition,
6155                                wxSize(-1, -1), flags);
6156   m_pListbook->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
6157                        wxNotebookEventHandler(options::OnTopNBPageChange), NULL,
6158                        this);
6159 #endif
6160 
6161 #ifdef __OCPN__ANDROID__
6162   //  In wxQT, we can dynamically style the little scroll buttons on a small
6163   //  display, to make them bigger
6164   m_pListbook->GetHandle()->setStyleSheet( getListBookStyleSheet() );
6165 
6166 #endif
6167 
6168 #ifdef __WXMSW__
6169   //  Windows clips the width of listbook selectors to about twice icon size
6170   //  This makes the text render with ellipses if too large
6171 
6172   //  So, Measure and reduce the Font size on ListBook(ListView) selectors
6173   //  to allow text layout without ellipsis...
6174   wxBitmap tbmp = g_StyleManager->GetCurrentStyle()->GetIcon(_T("Display"));
6175   wxScreenDC sdc;
6176   int text_width = tbmp.GetWidth();
6177   if (sdc.IsOk())
6178     sdc.GetTextExtent(_("Connections"), &text_width, NULL, NULL, NULL,
6179                       dialogFont);
6180 
6181   if (text_width > tbmp.GetWidth() * 2) {
6182     wxListView* lv = m_pListbook->GetListView();
6183     wxFont* qFont = dialogFont;  // to get type, weight, etc...
6184 
6185     wxFont* sFont = FontMgr::Get().FindOrCreateFont(
6186         10, qFont->GetFamily(), qFont->GetStyle(), qFont->GetWeight());
6187     lv->SetFont(*sFont);
6188   }
6189 #endif
6190 
6191   CreateListbookIcons();
6192 
6193   m_pListbook->SetImageList(m_topImgList);
6194   itemBoxSizer2->Add( m_pListbook, 1, wxALL | wxEXPAND, border_size);
6195 
6196   wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
6197   itemBoxSizer2->Add(buttons, 0, wxALIGN_RIGHT | wxALL, border_size);
6198 
6199   m_OKButton = new wxButton(itemDialog1, xID_OK, _("OK"));
6200   m_OKButton->SetDefault();
6201   buttons->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, border_size);
6202 
6203   m_CancelButton = new wxButton(itemDialog1, wxID_CANCEL, _("Cancel"));
6204   buttons->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, border_size);
6205 
6206   m_ApplyButton = new wxButton(itemDialog1, ID_APPLY, _("Apply"));
6207   buttons->Add(m_ApplyButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, border_size);
6208 
6209   m_pageDisplay = CreatePanel(_("Display"));
6210   CreatePanel_Display(m_pageDisplay, border_size, group_item_spacing);
6211   CreatePanel_Units(m_pageDisplay, border_size, group_item_spacing);
6212   CreatePanel_Advanced(m_pageDisplay, border_size, group_item_spacing);
6213   CreatePanel_Configs(m_pageDisplay, border_size, group_item_spacing);
6214 
6215   m_pageCharts = CreatePanel(_("Charts"));
6216   CreatePanel_ChartsLoad(m_pageCharts, border_size, group_item_spacing);
6217   CreatePanel_VectorCharts(m_pageCharts, border_size, group_item_spacing);
6218   // ChartGroups must be created after ChartsLoad and must be at least third
6219   CreatePanel_ChartGroups(m_pageCharts, border_size, group_item_spacing);
6220   RecalculateSize();
6221   CreatePanel_TidesCurrents(m_pageCharts, border_size, group_item_spacing);
6222 
6223   wxNotebook* nb = dynamic_cast<wxNotebook*>(m_pListbook->GetPage(m_pageCharts));
6224   if (nb){
6225 
6226 #ifdef __OCPN__OPTIONS_USE_LISTBOOK__
6227       nb->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
6228                                   wxListbookEventHandler(options::OnChartsPageChange),
6229                                   NULL, this);
6230 #else
6231       nb->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
6232                   wxNotebookEventHandler(options::OnChartsPageChange),
6233                   NULL, this);
6234 
6235 #endif
6236   }
6237 
6238 
6239   m_pageConnections = CreatePanel(_("Connections"));
6240 #ifndef __OCPN__ANDROID__
6241   CreatePanel_NMEA(m_pageConnections, border_size, group_item_spacing);
6242 #else
6243   CreatePanel_NMEA(m_pageConnections, border_size, group_item_spacing);
6244 //CreatePanel_NMEA_Compact(m_pageConnections, border_size, group_item_spacing);
6245 #endif
6246 
6247   //    SetDefaultConnectionParams();
6248 
6249   m_pageShips = CreatePanel(_("Ships"));
6250   CreatePanel_Ownship(m_pageShips, border_size, group_item_spacing);
6251   CreatePanel_AIS(m_pageShips, border_size, group_item_spacing);
6252 #ifndef __OCPN__ANDROID__
6253   CreatePanel_MMSI(m_pageShips, border_size, group_item_spacing);
6254 #endif
6255 
6256   CreatePanel_Routes(m_pageShips, border_size, group_item_spacing);
6257 
6258   m_pageUI = CreatePanel(_("User Interface"));
6259   CreatePanel_UI(m_pageUI, border_size, group_item_spacing);
6260 
6261   m_pagePlugins = CreatePanel(_("Plugins"));
6262   itemPanelPlugins = AddPage(m_pagePlugins, _("Plugins"));
6263 
6264   itemBoxSizerPanelPlugins = new wxBoxSizer(wxVERTICAL);
6265   itemPanelPlugins->SetSizer(itemBoxSizerPanelPlugins);
6266 
6267   //      PlugIns can add panels, too
6268   if (g_pi_manager) g_pi_manager->NotifySetupOptions();
6269 
6270   SetColorScheme(static_cast<ColorScheme>(0));
6271 
6272   // Set the maximum size of the entire settings dialog
6273   // leaving a slightly larger border for larger displays.
6274   int marginx = 10;
6275   int marginy = 40;
6276   if(width > 800){
6277       marginx = 100;
6278       marginy = 100;
6279   }
6280 
6281   SetSizeHints(-1, -1, width - marginx, height - marginy);
6282 
6283   //  The s57 chart panel is the one which controls the minimum width required
6284   //  to avoid horizontal scroll bars
6285   vectorPanel->SetSizeHints(ps57Ctl);
6286 }
6287 
SetInitialPage(int page_sel,int sub_page)6288 void options::SetInitialPage(int page_sel, int sub_page)
6289 {
6290   if(page_sel < (int)m_pListbook->GetPageCount())
6291   m_pListbook->SetSelection(page_sel);
6292   else
6293      m_pListbook->SetSelection(0);
6294 
6295   if(sub_page >= 0){
6296   for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
6297     wxNotebookPage* pg = m_pListbook->GetPage(i);
6298     wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
6299     if (nb){
6300         if(i == (size_t) page_sel){
6301                 if(sub_page < (int)nb->GetPageCount())
6302                 nb->SetSelection(sub_page);
6303                 else
6304                     nb->SetSelection(0);
6305         }
6306         else
6307             nb->ChangeSelection(0);
6308     }
6309   }
6310 }
6311 }
6312 
SetColorScheme(ColorScheme cs)6313 void options::SetColorScheme(ColorScheme cs) {
6314   DimeControl(this);
6315 
6316 #ifdef __OCPN__OPTIONS_USE_LISTBOOK__
6317   wxListView* lv = m_pListbook->GetListView();
6318   lv->SetBackgroundColour(GetBackgroundColour());
6319 
6320   if(m_cs != cs){
6321       delete m_topImgList;
6322       CreateListbookIcons();
6323       m_pListbook->SetImageList(m_topImgList);
6324 
6325       m_cs = cs;
6326   }
6327 
6328 #endif
6329 }
6330 
OnAISRolloverClick(wxCommandEvent & event)6331 void options::OnAISRolloverClick(wxCommandEvent &event)
6332 {
6333     m_pCheck_Rollover_Class->Enable(event.IsChecked());
6334     m_pCheck_Rollover_COG->Enable(event.IsChecked());
6335     m_pCheck_Rollover_CPA->Enable(event.IsChecked());
6336     pStatic_CallSign->Enable(event.IsChecked());
6337 }
6338 
6339 
OnCanvasConfigSelectClick(int ID,bool selected)6340 void options::OnCanvasConfigSelectClick( int ID, bool selected)
6341 {
6342     switch(ID){
6343         case ID_SCREENCONFIG1:
6344             if(m_sconfigSelect_twovertical)
6345             m_sconfigSelect_twovertical->SetSelected(false);
6346             m_screenConfig = 0;
6347             break;
6348 
6349         case ID_SCREENCONFIG2:
6350             if(m_sconfigSelect_single)
6351             m_sconfigSelect_single->SetSelected(false);
6352             m_screenConfig = 1;
6353             break;
6354     }
6355 
6356 }
6357 
SetInitialSettings(void)6358 void options::SetInitialSettings(void) {
6359   wxString s;
6360 
6361   m_returnChanges = 0;                  // reset the flags
6362   m_bfontChanged = false;
6363 
6364   b_oldhaveWMM = b_haveWMM;
6365   b_haveWMM = g_pi_manager && g_pi_manager->IsPlugInAvailable(_T("WMM"));
6366 
6367   // Canvas configuration
6368   switch(g_canvasConfig){
6369       case 0:
6370       default:
6371           if(m_sconfigSelect_single)
6372           m_sconfigSelect_single->SetSelected(true);
6373           if(m_sconfigSelect_twovertical)
6374           m_sconfigSelect_twovertical->SetSelected(false);
6375           break;
6376       case 1:
6377           if(m_sconfigSelect_single)
6378           m_sconfigSelect_single->SetSelected(false);
6379           if(m_sconfigSelect_twovertical)
6380           m_sconfigSelect_twovertical->SetSelected(true);
6381           break;
6382   }
6383   m_screenConfig = g_canvasConfig;
6384 
6385   // ChartsLoad
6386 
6387   if (pActiveChartsList) {
6388     pActiveChartsList->DeleteAllItems();
6389 
6390     for (size_t i = 0; i < m_CurrentDirList.GetCount(); i++) {
6391         wxString dirname = m_CurrentDirList[i].fullpath;
6392         wxListItem li;
6393         li.SetId( i );
6394         li.SetAlign(wxLIST_FORMAT_LEFT);
6395         li.SetText(dirname);
6396         li.SetColumn(0);
6397         long idx = pActiveChartsList->InsertItem( li );
6398     }
6399   }
6400 
6401   // ChartGroups
6402   if (pActiveChartsList && m_pWorkDirList) {
6403     UpdateWorkArrayFromTextCtl();
6404     groupsPanel->SetDBDirs(*m_pWorkDirList);
6405 
6406     // Make a deep copy of the current global Group Array
6407     groupsPanel->EmptyChartGroupArray(m_pGroupArray);
6408     delete m_pGroupArray;
6409     m_pGroupArray = groupsPanel->CloneChartGroupArray(g_pGroupArray);
6410     groupsPanel->SetGroupArray(m_pGroupArray);
6411     groupsPanel->SetInitialSettings();
6412   }
6413 
6414   if (m_pConfig) {
6415     pShowStatusBar->SetValue(g_bShowStatusBar);
6416 #ifndef __WXOSX__
6417     pShowMenuBar->SetValue(g_bShowMenuBar);
6418 #endif
6419     pShowCompassWin->SetValue(g_bShowCompassWin);
6420   }
6421 
6422   s.Printf(_T("%d"), g_COGAvgSec);
6423   pCOGUPUpdateSecs->SetValue(s);
6424 
6425   if(pCDOOutlines) pCDOOutlines->SetValue(g_bShowOutlines);
6426   if(pCDOQuilting) pCDOQuilting->SetValue(g_bQuiltEnable);
6427 //  if(pFullScreenQuilt) pFullScreenQuilt->SetValue(!g_bFullScreenQuilt);
6428   if(pSDepthUnits) pSDepthUnits->SetValue(g_bShowDepthUnits);
6429   if(pSkewComp) pSkewComp->SetValue(g_bskew_comp);
6430   pMobile->SetValue(g_btouch);
6431   pResponsive->SetValue(g_bresponsive);
6432   pRollover->SetValue(g_bRollover);
6433   m_pCheck_Rollover_Class->Enable(g_bRollover);
6434   m_pCheck_Rollover_COG->Enable(g_bRollover);
6435   m_pCheck_Rollover_CPA->Enable(g_bRollover);
6436   pStatic_CallSign->Enable(g_bRollover);
6437 
6438 
6439   pZoomButtons->SetValue( g_bShowMuiZoomButtons );
6440 
6441   //pOverzoomEmphasis->SetValue(!g_fog_overzoom);
6442   //pOZScaleVector->SetValue(!g_oz_vector_scale);
6443   pInlandEcdis->SetValue(g_bInlandEcdis);
6444 #ifdef __WXOSX__
6445   pDarkDecorations->SetValue(g_bDarkDecorations);
6446 #endif
6447   pOpenGL->SetValue(g_bopengl);
6448   if(pSmoothPanZoom) pSmoothPanZoom->SetValue(g_bsmoothpanzoom);
6449   pCBTrueShow->SetValue(g_bShowTrue);
6450   pCBMagShow->SetValue(g_bShowMag);
6451 
6452   int oldLength = itemStaticTextUserVar->GetLabel().Length();
6453 
6454   //disable input for variation if WMM is available
6455   if(b_haveWMM){
6456       itemStaticTextUserVar->SetLabel(_("WMM Plugin calculated magnetic variation"));
6457       wxString s;
6458       s.Printf(_T("%4.1f"), gVar);
6459       pMagVar->SetValue(s);
6460   }
6461   else{
6462       itemStaticTextUserVar->SetLabel(_("User set magnetic variation"));
6463       wxString s;
6464       s.Printf(_T("%4.1f"), g_UserVar);
6465       pMagVar->SetValue(s);
6466   }
6467 
6468   int newLength = itemStaticTextUserVar->GetLabel().Length();
6469 
6470   // size hack to adjust change in static text size
6471   if( (newLength != oldLength) || (b_oldhaveWMM != b_haveWMM) ){
6472       wxSize sz = GetSize();
6473       SetSize(sz.x+1, sz.y);
6474       SetSize(sz);
6475   }
6476 
6477   itemStaticTextUserVar2->Enable(!b_haveWMM);
6478   pMagVar->Enable(!b_haveWMM);
6479 
6480   if(pSDisplayGrid) pSDisplayGrid->SetValue(g_bDisplayGrid);
6481 
6482   // LIVE ETA OPTION
6483 
6484   // Checkbox
6485   if(pSLiveETA) pSLiveETA->SetValue(g_bShowLiveETA);
6486 
6487   // Defaut boat speed text input field
6488   // Speed always in knots, and converted to user speed unit
6489   wxString stringDefaultBoatSpeed;
6490   if (!g_defaultBoatSpeed || !g_defaultBoatSpeedUserUnit)
6491   {
6492       g_defaultBoatSpeed = 6.0;
6493       g_defaultBoatSpeedUserUnit = toUsrSpeed(g_defaultBoatSpeed, -1);
6494   }
6495   stringDefaultBoatSpeed.Printf(_T("%d"), (int)g_defaultBoatSpeedUserUnit);
6496   if(pSDefaultBoatSpeed) pSDefaultBoatSpeed->SetValue(stringDefaultBoatSpeed);
6497 
6498   // END LIVE ETA OPTION
6499 
6500   if(pCBCourseUp) pCBCourseUp->SetValue(g_bCourseUp);
6501   if(pCBNorthUp) pCBNorthUp->SetValue(!g_bCourseUp);
6502   if(pCBLookAhead) pCBLookAhead->SetValue(g_bLookAhead);
6503 
6504   if (fabs(wxRound(g_ownship_predictor_minutes) - g_ownship_predictor_minutes) >
6505       1e-4)
6506     s.Printf(_T("%6.2f"), g_ownship_predictor_minutes);
6507   else
6508     s.Printf(_T("%4.0f"), g_ownship_predictor_minutes);
6509   m_pText_OSCOG_Predictor->SetValue(s);
6510 
6511   if (fabs(wxRound(g_ownship_HDTpredictor_miles) -
6512            g_ownship_HDTpredictor_miles) > 1e-4)
6513     s.Printf(_T("%6.2f"), g_ownship_HDTpredictor_miles);
6514   else
6515     s.Printf(_T("%4.0f"), g_ownship_HDTpredictor_miles);
6516   m_pText_OSHDT_Predictor->SetValue(s);
6517 
6518   m_pShipIconType->SetSelection(g_OwnShipIconType);
6519   wxCommandEvent eDummy;
6520   OnShipTypeSelect(eDummy);
6521   m_pOSLength->SetValue(
6522       wxString::Format(_T("%.1f"), g_n_ownship_length_meters));
6523   m_pOSWidth->SetValue(wxString::Format(_T("%.1f"), g_n_ownship_beam_meters));
6524   m_pOSGPSOffsetX->SetValue(
6525       wxString::Format(_T("%.1f"), g_n_gps_antenna_offset_x));
6526   m_pOSGPSOffsetY->SetValue(
6527       wxString::Format(_T("%.1f"), g_n_gps_antenna_offset_y));
6528   m_pOSMinSize->SetValue(wxString::Format(_T("%d"), g_n_ownship_min_mm));
6529   m_pText_ACRadius->SetValue(
6530       wxString::Format(_T("%.3f"), g_n_arrival_circle_radius));
6531 
6532   wxString buf;
6533   if (g_iNavAidRadarRingsNumberVisible > 10)
6534     g_iNavAidRadarRingsNumberVisible = 10;
6535   pNavAidRadarRingsNumberVisible->SetSelection(
6536       g_iNavAidRadarRingsNumberVisible);
6537   buf.Printf(_T("%.3f"), g_fNavAidRadarRingsStep);
6538   pNavAidRadarRingsStep->SetValue(buf);
6539   m_itemRadarRingsUnits->SetSelection(g_pNavAidRadarRingsStepUnits);
6540   m_colourOwnshipRangeRingColour->SetColour(g_colourOwnshipRangeRingsColour);
6541 
6542   pScaMinChckB->SetValue( g_bUseWptScaMin );
6543   m_pText_ScaMin->SetValue( wxString::Format(_T("%i"), g_iWpt_ScaMin ));
6544   pScaMinOverruleChckB->SetValue( g_bOverruleScaMin );
6545 
6546   OnRadarringSelect(eDummy);
6547 
6548   if (g_iWaypointRangeRingsNumber > 10) g_iWaypointRangeRingsNumber = 10;
6549   pWaypointRangeRingsNumber->SetSelection(g_iWaypointRangeRingsNumber);
6550   buf.Printf(_T("%.3f"), g_fWaypointRangeRingsStep);
6551   pWaypointRangeRingsStep->SetValue(buf);
6552   m_itemWaypointRangeRingsUnits->SetSelection(g_iWaypointRangeRingsStepUnits);
6553   m_colourWaypointRangeRingsColour->SetColour(g_colourWaypointRangeRingsColour);
6554   OnWaypointRangeRingSelect(eDummy);
6555 
6556   pWayPointPreventDragging->SetValue(g_bWayPointPreventDragging);
6557   pConfirmObjectDeletion->SetValue(g_bConfirmObjectDelete);
6558 
6559   pSogCogFromLLCheckBox->SetValue(g_own_ship_sog_cog_calc);
6560   pSogCogFromLLDampInterval->SetValue(g_own_ship_sog_cog_calc_damp_sec);
6561 
6562   if(pEnableZoomToCursor) pEnableZoomToCursor->SetValue(g_bEnableZoomToCursor);
6563 
6564   if(pPreserveScale) pPreserveScale->SetValue(g_bPreserveScaleOnX);
6565   pPlayShipsBells->SetValue(g_bPlayShipsBells);
6566 
6567   if ( g_bUIexpert && pCmdSoundString )
6568       pCmdSoundString->SetValue(g_CmdSoundString);
6569 
6570   if (pSoundDeviceIndex)
6571       pSoundDeviceIndex->SetSelection(g_iSoundDeviceIndex);
6572   //    pFullScreenToolbar->SetValue( g_bFullscreenToolbar );
6573   //pTransparentToolbar->SetValue(g_bTransparentToolbar);
6574   pSDMMFormat->Select(g_iSDMMFormat);
6575   pDistanceFormat->Select(g_iDistanceFormat);
6576   pSpeedFormat->Select(g_iSpeedFormat);
6577 
6578   pAdvanceRouteWaypointOnArrivalOnly->SetValue(
6579       g_bAdvanceRouteWaypointOnArrivalOnly);
6580 
6581   pTrackDaily->SetValue(g_bTrackDaily);
6582   pTrackRotateLMT->SetValue(g_track_rotate_time_type == TIME_TYPE_LMT);
6583   pTrackRotateUTC->SetValue(g_track_rotate_time_type == TIME_TYPE_UTC);
6584   pTrackRotateComputerTime->SetValue(g_track_rotate_time_type == TIME_TYPE_COMPUTER);
6585   pTrackHighlite->SetValue(g_bHighliteTracks);
6586   m_colourTrackLineColour->SetColour(g_colourTrackLineColour);
6587 
6588   pTrackPrecision->SetSelection(g_nTrackPrecision);
6589 
6590   //    AIS Parameters
6591   //      CPA Box
6592   m_pCheck_CPA_Max->SetValue(g_bCPAMax);
6593 
6594   s.Printf(_T("%4.1f"), g_CPAMax_NM);
6595   m_pText_CPA_Max->SetValue(s);
6596 
6597   m_pCheck_CPA_Warn->SetValue(g_bCPAWarn);
6598 
6599   s.Printf(_T("%4.1f"), g_CPAWarn_NM);
6600   m_pText_CPA_Warn->SetValue(s);
6601 
6602   if (m_pCheck_CPA_Warn->GetValue()) {
6603     m_pCheck_CPA_WarnT->Enable();
6604     m_pCheck_CPA_WarnT->SetValue(g_bTCPA_Max);
6605   } else
6606     m_pCheck_CPA_WarnT->Disable();
6607 
6608   s.Printf(_T("%4.0f"), g_TCPA_Max);
6609   m_pText_CPA_WarnT->SetValue(s);
6610 
6611   //      Lost Targets
6612   m_pCheck_Mark_Lost->SetValue(g_bMarkLost);
6613 
6614   s.Printf(_T("%4.0f"), g_MarkLost_Mins);
6615   m_pText_Mark_Lost->SetValue(s);
6616 
6617   m_pCheck_Remove_Lost->SetValue(g_bRemoveLost);
6618 
6619   s.Printf(_T("%4.0f"), g_RemoveLost_Mins);
6620   m_pText_Remove_Lost->SetValue(s);
6621 
6622   //      Display
6623   m_pCheck_Show_COG->SetValue(g_bShowCOG);
6624 
6625   s.Printf(_T("%4.0f"), g_ShowCOG_Mins);
6626   m_pText_COG_Predictor->SetValue(s);
6627 
6628   m_pCheck_Show_Tracks->SetValue(g_bAISShowTracks);
6629 
6630   s.Printf(_T("%4.0f"), g_AISShowTracks_Mins);
6631   m_pText_Track_Length->SetValue(s);
6632 
6633   m_pCheck_Hide_Moored->SetValue(g_bHideMoored);
6634 
6635   s.Printf(_T("%4.1f"), g_ShowMoored_Kts);
6636   m_pText_Moored_Speed->SetValue(s);
6637 
6638   m_pCheck_Draw_Realtime_Prediction->SetValue(g_bDrawAISRealtime);
6639 
6640   s.Printf(_T("%4.1f"), g_AIS_RealtPred_Kts);
6641   m_pText_RealtPred_Speed->SetValue(s);
6642 
6643   m_pCheck_Scale_Priority->SetValue(g_bAllowShowScaled);
6644 
6645   s.Printf(_T("%i"), g_ShowScaled_Num);
6646   m_pText_Scale_Priority->SetValue(s);
6647 
6648 
6649   m_pCheck_Show_Area_Notices->SetValue(g_bShowAreaNotices);
6650 
6651   m_pCheck_Draw_Target_Size->SetValue(g_bDrawAISSize);
6652   m_pCheck_Draw_Realtime_Prediction->SetValue(g_bDrawAISRealtime);
6653 
6654   m_pCheck_Show_Target_Name->SetValue(g_bShowAISName);
6655 
6656   s.Printf(_T("%d"), g_Show_Target_Name_Scale);
6657   m_pText_Show_Target_Name_Scale->SetValue(s);
6658 
6659   m_pCheck_Wpl_Aprs->SetValue(g_bWplIsAprsPosition);
6660 
6661   // Alerts
6662   m_pCheck_AlertDialog->SetValue(g_bAIS_CPA_Alert);
6663   m_pCheck_AlertAudio->SetValue(g_bAIS_CPA_Alert_Audio);
6664   m_pCheck_Alert_Moored->SetValue(g_bAIS_CPA_Alert_Suppress_Moored);
6665 
6666   m_pCheck_Ack_Timout->SetValue(g_bAIS_ACK_Timeout);
6667   s.Printf(_T("%4.0f"), g_AckTimeout_Mins);
6668   m_pText_ACK_Timeout->SetValue(s);
6669 
6670   // Rollover
6671   m_pCheck_Rollover_Class->SetValue(g_bAISRolloverShowClass);
6672   m_pCheck_Rollover_COG->SetValue(g_bAISRolloverShowCOG);
6673   m_pCheck_Rollover_CPA->SetValue(g_bAISRolloverShowCPA);
6674 
6675   m_pSlider_Zoom->SetValue(g_chart_zoom_modifier);
6676   m_pSlider_Zoom_Vector->SetValue(g_chart_zoom_modifier_vector);
6677 
6678   m_pSlider_GUI_Factor->SetValue(g_GUIScaleFactor);
6679   m_pSlider_Chart_Factor->SetValue(g_ChartScaleFactor);
6680   m_pSlider_Ship_Factor->SetValue(g_ShipScaleFactor);
6681   m_pSlider_Text_Factor->SetValue(g_ENCSoundingScaleFactor);
6682   wxString screenmm;
6683 
6684   if (!g_config_display_size_manual) {
6685     pRBSizeAuto->SetValue(TRUE);
6686     screenmm.Printf(_T("%d"), int(g_Platform->GetDisplaySizeMM()));
6687     pScreenMM->Disable();
6688   } else {
6689     screenmm.Printf(_T("%d"), int(g_config_display_size_mm));
6690     pRBSizeManual->SetValue(TRUE);
6691   }
6692 
6693   pScreenMM->SetValue(screenmm);
6694 
6695   m_TalkerIdText->SetValue(g_TalkerIdText.MakeUpper());
6696 
6697   pDepthUnitSelect->SetSelection(g_nDepthUnitDisplay);
6698   UpdateOptionsUnits();  // sets depth values using the user's unit preference
6699 
6700   SetInitialVectorSettings();
6701 
6702   pToolbarAutoHideCB->SetValue(g_bAutoHideToolbar);
6703 
6704   s.Printf(_T("%d"), g_nAutoHideToolbar);
6705   pToolbarHideSecs->SetValue(s);
6706 
6707   m_cbNMEADebug->SetValue(false);
6708   if(NMEALogWindow::Get().GetTTYWindow()){
6709       if(NMEALogWindow::Get().GetTTYWindow()->IsShown()){
6710           m_cbNMEADebug->SetValue(true);
6711       }
6712   }
6713 
6714   //  Serial ports
6715 
6716   delete m_pSerialArray;
6717   m_pSerialArray = NULL;
6718   m_pSerialArray = EnumerateSerialPorts();
6719 
6720   if (m_pSerialArray) {
6721       m_comboPort->Clear();
6722       for (size_t i = 0; i < m_pSerialArray->Count(); i++) {
6723           m_comboPort->Append(m_pSerialArray->Item(i));
6724       }
6725   }
6726 
6727   //  On some platforms, the global connections list may be changed outside of the options dialog.
6728   //  Pick up any changes here, and re-populate the dialog list.
6729   FillSourceList();
6730 
6731   //  Reset the touch flag...
6732   connectionsaved = true;
6733 
6734   SetSelectedConnectionPanel( nullptr);
6735 
6736 }
6737 
resetMarStdList(bool bsetConfig,bool bsetStd)6738 void options::resetMarStdList(bool bsetConfig, bool bsetStd)
6739 {
6740     if (ps57CtlListBox) {
6741         //    S52 Primary Filters
6742         ps57CtlListBox->Clear();
6743         marinersStdXref.clear();
6744 
6745         for (unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++) {
6746             OBJLElement* pOLE = (OBJLElement*)(ps52plib->pOBJLArray->Item(iPtr));
6747 
6748             wxString item;
6749             if (iPtr < ps52plib->OBJLDescriptions.size()) {
6750                 item = ps52plib->OBJLDescriptions[iPtr];
6751             } else {
6752                 item = wxString(pOLE->OBJLName, wxConvUTF8);
6753             }
6754 
6755 
6756             // Find the most conservative Category, among Point, Area, and Line LUPs
6757             DisCat cat = OTHER;
6758 
6759             DisCat catp = ps52plib->findLUPDisCat(pOLE->OBJLName, SIMPLIFIED);
6760             DisCat cata = ps52plib->findLUPDisCat(pOLE->OBJLName, PLAIN_BOUNDARIES);
6761             DisCat catl = ps52plib->findLUPDisCat(pOLE->OBJLName, LINES);
6762 
6763             if((catp == DISPLAYBASE) || (cata == DISPLAYBASE) || (catl== DISPLAYBASE) )
6764                 cat = DISPLAYBASE;
6765             else if((catp == STANDARD) || (cata == STANDARD) || (catl== STANDARD) )
6766                 cat = STANDARD;
6767 
6768             bool benable = true;
6769             if(cat > 0)
6770                 benable = cat != DISPLAYBASE;
6771 
6772             // The ListBox control will insert entries in sorted order, which means
6773                 // we need to
6774                 // keep track of already inserted items that gets pushed down the line.
6775                 int newpos = ps57CtlListBox->Append(item, benable);
6776                 marinersStdXref.push_back(newpos);
6777                 for (size_t i = 0; i < iPtr; i++) {
6778                     if (marinersStdXref[i] >= newpos) marinersStdXref[i]++;
6779                 }
6780 
6781                 bool bviz = 0;
6782                 if(bsetConfig)
6783                     bviz = !(pOLE->nViz == 0);
6784 
6785                 if(cat == DISPLAYBASE)
6786                     bviz = true;
6787 
6788                 if(bsetStd){
6789                     if(cat == STANDARD){
6790                         bviz = true;
6791                     }
6792                 }
6793 
6794                 ps57CtlListBox->Check(newpos, bviz);
6795         }
6796         //  Force the wxScrolledWindow to recalculate its scroll bars
6797         wxSize s = ps57CtlListBox->GetSize();
6798         ps57CtlListBox->SetSize(s.x, s.y-1);
6799     }
6800 }
6801 
SetInitialVectorSettings(void)6802 void options::SetInitialVectorSettings(void)
6803 {
6804     m_pSlider_CM93_Zoom->SetValue(g_cm93_zoom_factor);
6805 
6806     //    Diplay Category
6807     if (ps52plib) {
6808         m_bVectorInit = true;
6809         resetMarStdList(true, false);
6810 
6811         #ifdef __OCPN__ANDROID__
6812         ps57CtlListBox->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
6813         #endif
6814 
6815         int nset = 2;  // default OTHER
6816         switch (ps52plib->GetDisplayCategory()) {
6817             case (DISPLAYBASE):
6818                 nset = 0;
6819                 break;
6820             case (STANDARD):
6821                 nset = 1;
6822                 break;
6823             case (OTHER):
6824                 nset = 2;
6825                 break;
6826             case (MARINERS_STANDARD):
6827                 nset = 3;
6828                 break;
6829             default:
6830                 nset = 3;
6831                 break;
6832         }
6833 
6834         if(pDispCat)
6835             pDispCat->SetSelection(nset);
6836 
6837         // Enable the UserStandard object list if either canvas is in MARINERS_STANDARD display category
6838         bool benableMarStd = false;
6839         // .. for each canvas...
6840         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6841             ChartCanvas *cc = g_canvasArray.Item(i);
6842             if(cc){
6843                 if(cc->GetENCDisplayCategory() == MARINERS_STANDARD)
6844                     benableMarStd = true;
6845             }
6846         }
6847 
6848 
6849 //        if(g_useMUI)
6850 //           benableMarStd = true;
6851 
6852 
6853         if( ps57CtlListBox )
6854             ps57CtlListBox->Enable(benableMarStd);
6855         itemButtonClearList->Enable(benableMarStd);
6856         itemButtonSelectList->Enable(benableMarStd);
6857         itemButtonSetStd->Enable(benableMarStd);
6858 
6859 
6860         //  Other Display Filters
6861         if(pCheck_SOUNDG) pCheck_SOUNDG->SetValue(ps52plib->m_bShowSoundg);
6862         if(pCheck_ATONTEXT) pCheck_ATONTEXT->SetValue(ps52plib->m_bShowAtonText);
6863         if(pCheck_LDISTEXT) pCheck_LDISTEXT->SetValue(ps52plib->m_bShowLdisText);
6864         if(pCheck_XLSECTTEXT) pCheck_XLSECTTEXT->SetValue(ps52plib->m_bExtendLightSectors);
6865 
6866         pCheck_META->SetValue(ps52plib->m_bShowMeta);
6867         pCheck_SHOWIMPTEXT->SetValue(ps52plib->m_bShowS57ImportantTextOnly);
6868         pCheck_SCAMIN->SetValue(ps52plib->m_bUseSCAMIN);
6869         pCheck_DECLTEXT->SetValue(ps52plib->m_bDeClutterText);
6870         pCheck_NATIONALTEXT->SetValue(ps52plib->m_bShowNationalTexts);
6871 
6872         // Chart Display Style
6873         if (ps52plib->m_nSymbolStyle == PAPER_CHART)
6874             pPointStyle->SetSelection(0);
6875         else
6876             pPointStyle->SetSelection(1);
6877 
6878         if (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES)
6879             pBoundStyle->SetSelection(0);
6880         else
6881             pBoundStyle->SetSelection(1);
6882 
6883         if (S52_getMarinerParam(S52_MAR_TWO_SHADES) == 1.0)
6884             p24Color->SetSelection(0);
6885         else
6886             p24Color->SetSelection(1);
6887 
6888         UpdateOptionsUnits();  // sets depth values using the user's unit preference
6889 
6890     }
6891 }
6892 
6893 
UpdateOptionsUnits(void)6894 void options::UpdateOptionsUnits(void) {
6895   int depthUnit = pDepthUnitSelect->GetSelection();
6896 
6897   depthUnit = wxMax(depthUnit, 0);
6898   depthUnit = wxMin(depthUnit, 2);
6899 
6900   // depth unit conversion factor
6901   float conv = 1;
6902   if (depthUnit == 0)  // feet
6903     conv = 0.3048f;    // international definiton of 1 foot is 0.3048 metres
6904   else if (depthUnit == 2)  // fathoms
6905     conv = 0.3048f * 6;     // 1 fathom is 6 feet
6906 
6907   // set depth input values
6908 
6909     // set depth unit labels
6910   wxString depthUnitStrings[] = {_("feet"), _("meters"), _("fathoms")};
6911   wxString depthUnitString = depthUnitStrings[depthUnit];
6912   m_depthUnitsShal->SetLabel(depthUnitString);
6913   m_depthUnitsSafe->SetLabel(depthUnitString);
6914   m_depthUnitsDeep->SetLabel(depthUnitString);
6915 
6916   wxString s;
6917   s.Printf(_T( "%6.2f" ), S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) / conv);
6918   s.Trim(FALSE);
6919   m_ShallowCtl->SetValue(s);
6920 
6921   s.Printf(_T( "%6.2f" ), S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) / conv);
6922   s.Trim(FALSE);
6923   m_SafetyCtl->SetValue(s);
6924 
6925   s.Printf(_T( "%6.2f" ), S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) / conv);
6926   s.Trim(FALSE);
6927   m_DeepCtl->SetValue(s);
6928 /*
6929   int oldLength = itemStaticTextUserVar->GetLabel().Length();
6930 
6931   //disable input for variation if WMM is available
6932   if(b_haveWMM){
6933       itemStaticTextUserVar->SetLabel(_("WMM Plugin calculated magnetic variation"));
6934       wxString s;
6935       s.Printf(_T("%4.1f"), gVar);
6936       pMagVar->SetValue(s);
6937   }
6938   else{
6939       itemStaticTextUserVar->SetLabel(_("User set magnetic variation"));
6940       wxString s;
6941       s.Printf(_T("%4.1f"), g_UserVar);
6942       pMagVar->SetValue(s);
6943   }
6944 
6945   int newLength = itemStaticTextUserVar->GetLabel().Length();
6946 
6947   // size hack to adjust change in static text size
6948   if( (newLength != oldLength) || (b_oldhaveWMM != b_haveWMM) ){
6949     wxSize sz = GetSize();
6950     SetSize(sz.x+1, sz.y);
6951     SetSize(sz);
6952   }
6953 
6954   itemStaticTextUserVar2->Enable(!b_haveWMM);
6955   pMagVar->Enable(!b_haveWMM);
6956 */
6957 }
6958 
OnSizeAutoButton(wxCommandEvent & event)6959 void options::OnSizeAutoButton(wxCommandEvent& event) {
6960   wxString screenmm = wxString::Format(
6961       _T( "%d" ), static_cast<int>(g_Platform->GetDisplaySizeMM()));
6962   pScreenMM->SetValue(screenmm);
6963   pScreenMM->Disable();
6964   g_config_display_size_manual = FALSE;
6965 }
6966 
OnSizeManualButton(wxCommandEvent & event)6967 void options::OnSizeManualButton(wxCommandEvent& event) {
6968   wxString screenmm = wxString::Format(
6969       _T( "%d" ), static_cast<int>(g_config_display_size_mm > 0
6970                                        ? g_config_display_size_mm
6971                                        : g_Platform->GetDisplaySizeMM()));
6972   pScreenMM->SetValue(screenmm);
6973   pScreenMM->Enable();
6974   g_config_display_size_manual = TRUE;
6975 }
6976 
OnUnitsChoice(wxCommandEvent & event)6977 void options::OnUnitsChoice(wxCommandEvent& event) { UpdateOptionsUnits(); }
6978 
OnCPAWarnClick(wxCommandEvent & event)6979 void options::OnCPAWarnClick(wxCommandEvent& event) {
6980   if (m_pCheck_CPA_Warn->GetValue()) {
6981     m_pCheck_CPA_WarnT->Enable();
6982   } else {
6983     m_pCheck_CPA_WarnT->SetValue(FALSE);
6984     m_pCheck_CPA_WarnT->Disable();
6985   }
6986 }
6987 
OnShowGpsWindowCheckboxClick(wxCommandEvent & event)6988 void options::OnShowGpsWindowCheckboxClick(wxCommandEvent& event) {
6989   if (!m_cbNMEADebug->GetValue()) {
6990     NMEALogWindow::Get().DestroyWindow();
6991   } else {
6992     NMEALogWindow::Get().Create(pParent, 35);
6993 
6994     // Try to ensure that the log window is a least a little bit visible
6995     wxRect logRect(NMEALogWindow::Get().GetPosX(), NMEALogWindow::Get().GetPosY(),
6996                    NMEALogWindow::Get().GetSizeW(), NMEALogWindow::Get().GetSizeH());
6997 
6998     if(GetRect().Contains(logRect)){
6999         NMEALogWindow::Get().SetPos(GetRect().x/2, (GetRect().y + (GetRect().height - logRect.height)/2) );
7000         NMEALogWindow::Get().Move();
7001     }
7002 
7003     Raise();
7004   }
7005 }
7006 
OnShipTypeSelect(wxCommandEvent & event)7007 void options::OnShipTypeSelect(wxCommandEvent& event) {
7008   realSizes->ShowItems(m_pShipIconType->GetSelection() != 0);
7009   dispOptions->Layout();
7010   ownShip->Layout();
7011   itemPanelShip->Layout();
7012   itemPanelShip->Refresh();
7013   event.Skip();
7014 }
7015 
OnRadarringSelect(wxCommandEvent & event)7016 void options::OnRadarringSelect(wxCommandEvent& event) {
7017   radarGrid->ShowItems(pNavAidRadarRingsNumberVisible->GetSelection() != 0);
7018   dispOptions->Layout();
7019   ownShip->Layout();
7020   itemPanelShip->Layout();
7021   itemPanelShip->Refresh();
7022   event.Skip();
7023 }
7024 
OnWaypointRangeRingSelect(wxCommandEvent & event)7025 void options::OnWaypointRangeRingSelect(wxCommandEvent& event) {
7026   waypointradarGrid->ShowItems(pWaypointRangeRingsNumber->GetSelection() != 0);
7027   dispOptions->Layout();
7028   Routes->Layout();
7029   itemPanelRoutes->Layout();
7030   itemPanelRoutes->Refresh();
7031   event.Skip();
7032 }
7033 
OnGLClicked(wxCommandEvent & event)7034 void options::OnGLClicked(wxCommandEvent& event) {
7035 //   if (!g_bTransparentToolbarInOpenGLOK)
7036 //     pTransparentToolbar->Enable(!pOpenGL->GetValue());
7037 }
7038 
OnOpenGLOptions(wxCommandEvent & event)7039 void options::OnOpenGLOptions(wxCommandEvent& event) {
7040 #ifdef ocpnUSE_GL
7041   OpenGLOptionsDlg dlg(this);
7042 
7043   if (dlg.ShowModal() == wxID_OK) {
7044     if(gFrame->GetPrimaryCanvas()->GetglCanvas()){
7045         g_GLOptions.m_bUseAcceleratedPanning =
7046         g_bGLexpert ? dlg.GetAcceleratedPanning()
7047                   : gFrame->GetPrimaryCanvas()->GetglCanvas()->CanAcceleratePanning();
7048     }
7049 
7050     g_bShowFPS = dlg.GetShowFPS();
7051     g_bSoftwareGL = dlg.GetSoftwareGL();
7052 
7053     g_GLOptions.m_GLPolygonSmoothing = dlg.GetPolygonSmoothing();
7054     g_GLOptions.m_GLLineSmoothing = dlg.GetLineSmoothing();
7055 
7056     if (g_bGLexpert) {
7057       // user defined
7058       g_GLOptions.m_bTextureCompressionCaching =
7059           dlg.GetTextureCompressionCaching();
7060       g_GLOptions.m_iTextureMemorySize = dlg.GetTextureMemorySize();
7061     } else {
7062       // caching is on if textures are compressed
7063       g_GLOptions.m_bTextureCompressionCaching = dlg.GetTextureCompression();
7064     }
7065 
7066     if (g_bopengl && g_glTextureManager && g_GLOptions.m_bTextureCompression != dlg.GetTextureCompression()) {
7067       // new g_GLoptions setting is needed in callees
7068       g_GLOptions.m_bTextureCompression = dlg.GetTextureCompression();
7069 
7070       if(gFrame->GetPrimaryCanvas()->GetglCanvas()){
7071         ::wxBeginBusyCursor();
7072         gFrame->GetPrimaryCanvas()->GetglCanvas()->SetupCompression();
7073         g_glTextureManager->ClearAllRasterTextures();
7074         ::wxEndBusyCursor();
7075       }
7076     }
7077     else
7078       g_GLOptions.m_bTextureCompression = dlg.GetTextureCompression();
7079 
7080   }
7081 
7082   if (dlg.GetRebuildCache()) {
7083     m_returnChanges = REBUILD_RASTER_CACHE;
7084     Finish();
7085   }
7086 #endif
7087 }
7088 
OnChartDirListSelect(wxCommandEvent & event)7089 void options::OnChartDirListSelect(wxCommandEvent& event)
7090 {
7091     bool selected = (pActiveChartsList->GetSelectedItemCount() > 0);
7092     m_removeBtn->Enable(selected);
7093     if(m_compressBtn)
7094         m_compressBtn->Enable(selected);
7095 }
7096 
OnDisplayCategoryRadioButton(wxCommandEvent & event)7097 void options::OnDisplayCategoryRadioButton(wxCommandEvent& event) {
7098 
7099     if(!g_useMUI){
7100         if(pDispCat){
7101             const bool select = pDispCat->GetSelection() == 3;
7102             ps57CtlListBox->Enable(select);
7103             itemButtonClearList->Enable(select);
7104             itemButtonSelectList->Enable(select);
7105             itemButtonSetStd->Enable(select);
7106         }
7107     }
7108   event.Skip();
7109 }
7110 
OnButtonClearClick(wxCommandEvent & event)7111 void options::OnButtonClearClick(wxCommandEvent& event) {
7112   resetMarStdList(false, false);
7113 
7114 //   int nOBJL = ps57CtlListBox->GetCount();
7115 //   for (int iPtr = 0; iPtr < nOBJL; iPtr++){
7116 //           ps57CtlListBox->Check(iPtr, FALSE);
7117 //   }
7118   event.Skip();
7119 }
7120 
OnButtonSelectClick(wxCommandEvent & event)7121 void options::OnButtonSelectClick(wxCommandEvent& event) {
7122   int nOBJL = ps57CtlListBox->GetCount();
7123   for (int iPtr = 0; iPtr < nOBJL; iPtr++) ps57CtlListBox->Check(iPtr, TRUE);
7124 
7125   event.Skip();
7126 }
7127 
OnButtonSetStd(wxCommandEvent & event)7128 void options::OnButtonSetStd(wxCommandEvent& event) {
7129     resetMarStdList(false, true);
7130 
7131     event.Skip();
7132 }
7133 
ShowToolTips(void)7134 bool options::ShowToolTips(void) { return TRUE; }
7135 
OnCharHook(wxKeyEvent & event)7136 void options::OnCharHook(wxKeyEvent& event) {
7137   if (event.GetKeyCode() == WXK_RETURN &&
7138       event.GetModifiers() == wxMOD_CONTROL) {
7139     wxCommandEvent okEvent;
7140     okEvent.SetId(xID_OK);
7141     okEvent.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
7142     GetEventHandler()->AddPendingEvent(okEvent);
7143   }
7144   event.Skip();
7145 }
7146 
OnButtonaddClick(wxCommandEvent & event)7147 void options::OnButtonaddClick(wxCommandEvent& event) {
7148   wxString selDir;
7149   int dresult = g_Platform->DoDirSelectorDialog( this, &selDir, _("Add a directory containing chart files"),*pInit_Chart_Dir, false);      // no add files allowed
7150 
7151   if (dresult != wxID_CANCEL) AddChartDir(selDir);
7152 
7153   event.Skip();
7154 }
7155 
AddChartDir(const wxString & dir)7156 void options::AddChartDir(const wxString& dir) {
7157    wxFileName dirname = wxFileName(dir);
7158    pInit_Chart_Dir->Empty();
7159 
7160    wxString dirAdd;
7161    if (g_bportable) {
7162      wxFileName f(dir);
7163      f.MakeRelativeTo(g_Platform->GetHomeDir());
7164      dirAdd = f.GetFullPath();
7165    } else {
7166      pInit_Chart_Dir->Append(dirname.GetPath());
7167      dirAdd = dir;
7168    }
7169 
7170    wxListItem li;
7171    int id = pActiveChartsList->GetItemCount();      // next index
7172    li.SetId( id );
7173    li.SetAlign(wxLIST_FORMAT_LEFT);
7174    li.SetText(dirAdd);
7175    li.SetColumn(0);
7176 
7177    long idx = pActiveChartsList->InsertItem( li );
7178 
7179    k_charts |= CHANGE_CHARTS;
7180 
7181    pScanCheckBox->Disable();
7182 }
7183 
UpdateDisplayedChartDirList(ArrayOfCDI p)7184 void options::UpdateDisplayedChartDirList(ArrayOfCDI p) {
7185    if (pActiveChartsList) {
7186        pActiveChartsList->DeleteAllItems();
7187        for (size_t i = 0; i < p.GetCount(); i++) {
7188             wxString dirname = p[i].fullpath;
7189             wxListItem li;
7190             li.SetId( i );
7191             li.SetAlign(wxLIST_FORMAT_LEFT);
7192             li.SetText(dirname);
7193             li.SetColumn(0);
7194             long idx = pActiveChartsList->InsertItem( li );
7195         }
7196    }
7197 }
7198 
UpdateWorkArrayFromTextCtl(void)7199 void options::UpdateWorkArrayFromTextCtl(void) {
7200 
7201    wxString dirname;
7202 
7203   int n = pActiveChartsList->GetItemCount();
7204   if (m_pWorkDirList) {
7205     m_pWorkDirList->Clear();
7206     for (int i = 0; i < n; i++) {
7207 
7208       dirname = pActiveChartsList->GetItemText(i);
7209       if (!dirname.IsEmpty()) {
7210         //    This is a fix for OSX, which appends EOL to results of
7211         //    GetLineText()
7212         while ((dirname.Last() == wxChar(_T('\n'))) ||
7213                (dirname.Last() == wxChar(_T('\r'))))
7214           dirname.RemoveLast();
7215 
7216         //    scan the current array to find a match
7217         //    if found, add the info to the work list, preserving the magic
7218         //    number
7219         //    If not found, make a new ChartDirInfo, and add it
7220         bool b_added = FALSE;
7221         //                        if(m_pCurrentDirList)
7222         {
7223           int nDir = m_CurrentDirList.GetCount();
7224 
7225           for (int i = 0; i < nDir; i++) {
7226             if (m_CurrentDirList[i].fullpath == dirname) {
7227               ChartDirInfo cdi = m_CurrentDirList[i];
7228               m_pWorkDirList->Add(cdi);
7229               b_added = TRUE;
7230               break;
7231             }
7232           }
7233         }
7234         if (!b_added) {
7235           ChartDirInfo cdin;
7236           cdin.fullpath = dirname;
7237           m_pWorkDirList->Add(cdin);
7238         }
7239       }
7240     }
7241   }
7242 
7243 }
7244 
CreateConnectionParamsFromSelectedItem(void)7245 ConnectionParams* options::CreateConnectionParamsFromSelectedItem(void) {
7246   if (!m_bNMEAParams_shown) return NULL;
7247 
7248   //  Special encoding for deleted connection
7249   if (m_rbTypeSerial->GetValue() && m_comboPort->GetValue() == _T("Deleted" ))
7250     return NULL;
7251 
7252   //  We check some values here for consistency.
7253   //  If necessary, set defaults so user will see some result, however wrong...
7254 
7255   //  DataStreams should be Input, Output, or Both
7256   if (!(m_cbInput->GetValue() || m_cbOutput->GetValue())) {
7257       m_cbInput->SetValue( true );
7258   }
7259 
7260   if (m_rbTypeSerial->GetValue() && m_comboPort->GetValue() == wxEmptyString) {
7261       m_comboPort->Select(0);
7262   }
7263   //  TCP, GPSD and UDP require port field to be set.
7264   //  TCP clients, GPSD and UDP output sockets require an address
7265   else if (m_rbTypeNet->GetValue()) {
7266     if (wxAtoi(m_tNetPort->GetValue()) == 0) {
7267         m_tNetPort->SetValue(_T("2947"));       // reset to default
7268     }
7269     if (m_tNetAddress->GetValue() == wxEmptyString) {
7270         m_tNetAddress->SetValue(_T("0.0.0.0"));
7271     }
7272   }
7273 
7274   ConnectionParams* pConnectionParams = new ConnectionParams();
7275 
7276   UpdateConnectionParamsFromSelectedItem( pConnectionParams );
7277 
7278   ConnectionParamsPanel *pPanel = new ConnectionParamsPanel( m_scrollWinConnections, wxID_ANY, wxDefaultPosition, wxDefaultSize,
7279                              pConnectionParams, this);
7280   pPanel->SetSelected(false);
7281   boxSizerConnections->Add( pPanel, 0, wxEXPAND|wxALL, 0 );
7282   pConnectionParams->m_optionsPanel = pPanel;
7283 
7284   return pConnectionParams;
7285 
7286 }
7287 
UpdateConnectionParamsFromSelectedItem(ConnectionParams * pConnectionParams)7288 ConnectionParams* options::UpdateConnectionParamsFromSelectedItem(ConnectionParams *pConnectionParams) {
7289 
7290   pConnectionParams->Valid = TRUE;
7291   if (m_rbTypeSerial->GetValue())
7292     pConnectionParams->Type = SERIAL;
7293   else if (m_rbTypeNet->GetValue())
7294     pConnectionParams->Type = NETWORK;
7295   else if (m_rbTypeInternalGPS && m_rbTypeInternalGPS->GetValue())
7296     pConnectionParams->Type = INTERNAL_GPS;
7297   else if (m_rbTypeInternalBT && m_rbTypeInternalBT->GetValue())
7298     pConnectionParams->Type = INTERNAL_BT;
7299 
7300   //  Save the existing addr/port to allow closing of existing port
7301   pConnectionParams->LastNetworkAddress = pConnectionParams->NetworkAddress;
7302   pConnectionParams->LastNetworkPort = pConnectionParams->NetworkPort;
7303   pConnectionParams->LastNetProtocol = pConnectionParams->NetProtocol;
7304 
7305   pConnectionParams->NetworkAddress = m_tNetAddress->GetValue();
7306   pConnectionParams->NetworkPort = wxAtoi(m_tNetPort->GetValue());
7307   if (m_rbNetProtoTCP->GetValue())
7308     pConnectionParams->NetProtocol = TCP;
7309   else if (m_rbNetProtoUDP->GetValue())
7310     pConnectionParams->NetProtocol = UDP;
7311   else if (m_rbNetProtoGPSD->GetValue())
7312     pConnectionParams->NetProtocol = GPSD;
7313   else if (m_rbNetProtoSignalK->GetValue())
7314     pConnectionParams->NetProtocol = SIGNALK;
7315   else
7316     pConnectionParams->NetProtocol = PROTO_UNDEFINED;
7317 
7318   pConnectionParams->Baudrate = wxAtoi(m_choiceBaudRate->GetStringSelection());
7319   pConnectionParams->Priority = wxAtoi(m_choicePriority->GetStringSelection());
7320   pConnectionParams->ChecksumCheck = m_cbCheckCRC->GetValue();
7321   pConnectionParams->AutoSKDiscover = m_cbCheckSKDiscover->GetValue();
7322   pConnectionParams->Garmin = m_cbGarminHost->GetValue();
7323   pConnectionParams->InputSentenceList =
7324       wxStringTokenize(m_tcInputStc->GetValue(), _T(","));
7325   if (m_rbIAccept->GetValue())
7326     pConnectionParams->InputSentenceListType = WHITELIST;
7327   else
7328     pConnectionParams->InputSentenceListType = BLACKLIST;
7329   if (m_cbInput->GetValue()) {
7330     if (m_cbOutput->GetValue()) {
7331       pConnectionParams->IOSelect = DS_TYPE_INPUT_OUTPUT;
7332     } else {
7333       pConnectionParams->IOSelect = DS_TYPE_INPUT;
7334     }
7335   } else
7336     pConnectionParams->IOSelect = DS_TYPE_OUTPUT;
7337 
7338   pConnectionParams->OutputSentenceList =
7339       wxStringTokenize(m_tcOutputStc->GetValue(), _T(","));
7340   if (m_rbOAccept->GetValue())
7341     pConnectionParams->OutputSentenceListType = WHITELIST;
7342   else
7343     pConnectionParams->OutputSentenceListType = BLACKLIST;
7344   pConnectionParams->Port = m_comboPort->GetValue().BeforeFirst(' ');
7345 
7346   if( (pConnectionParams->Type != INTERNAL_GPS) && (pConnectionParams->Type != INTERNAL_BT) )
7347     CheckDeviceAccess(pConnectionParams->Port);
7348   pConnectionParams->Protocol = PROTO_NMEA0183;
7349 
7350   pConnectionParams->bEnabled = m_connection_enabled;
7351   pConnectionParams->b_IsSetup = FALSE;
7352 
7353   if (pConnectionParams->Type == INTERNAL_GPS) {
7354     pConnectionParams->NetworkAddress = _T("");
7355     pConnectionParams->NetworkPort = 0;
7356     pConnectionParams->NetProtocol = PROTO_UNDEFINED;
7357     pConnectionParams->Baudrate = 0;
7358   }
7359 
7360   if (pConnectionParams->Type == INTERNAL_BT) {
7361     wxString parms = m_choiceBTDataSources->GetStringSelection();
7362     wxStringTokenizer tkz(parms, _T(";"));
7363     wxString name = tkz.GetNextToken();
7364     wxString mac = tkz.GetNextToken();
7365 
7366     pConnectionParams->NetworkAddress = name;
7367     pConnectionParams->Port = mac;
7368     pConnectionParams->NetworkPort = 0;
7369     pConnectionParams->NetProtocol = PROTO_UNDEFINED;
7370     pConnectionParams->Baudrate = 0;
7371     //        pConnectionParams->SetAuxParameterStr(m_choiceBTDataSources->GetStringSelection());
7372   }
7373 
7374   if (pConnectionParams->Type == SERIAL) {
7375     pConnectionParams->UserComment = m_tSerialComment->GetValue();
7376   }
7377   else if (pConnectionParams->Type == NETWORK) {
7378     pConnectionParams->UserComment = m_tNetComment->GetValue();
7379   }
7380 
7381 
7382   return pConnectionParams;
7383 }
7384 
OnApplyClick(wxCommandEvent & event)7385 void options::OnApplyClick(wxCommandEvent& event) {
7386   //::wxBeginBusyCursor();
7387   StopBTScan();
7388 
7389   // Start with the stuff that requires intelligent validation.
7390 
7391   if (m_pShipIconType->GetSelection() > 0) {
7392     double n_ownship_length_meters;
7393     double n_ownship_beam_meters;
7394     double n_gps_antenna_offset_y;
7395     double n_gps_antenna_offset_x;
7396     long n_ownship_min_mm;
7397     m_pOSLength->GetValue().ToDouble(&n_ownship_length_meters);
7398     m_pOSWidth->GetValue().ToDouble(&n_ownship_beam_meters);
7399     m_pOSGPSOffsetX->GetValue().ToDouble(&n_gps_antenna_offset_x);
7400     m_pOSGPSOffsetY->GetValue().ToDouble(&n_gps_antenna_offset_y);
7401     m_pOSMinSize->GetValue().ToLong(&n_ownship_min_mm);
7402     wxString msg;
7403     if (n_ownship_length_meters <= 0)
7404       msg += _("\n - your ship's length must be > 0");
7405     if (n_ownship_beam_meters <= 0)
7406       msg += _("\n - your ship's beam must be > 0");
7407     if (fabs(n_gps_antenna_offset_x) > n_ownship_beam_meters / 2.0)
7408       msg += _(
7409           "\n - your GPS offset from midship must be within your ship's beam");
7410     if (n_gps_antenna_offset_y < 0 ||
7411         n_gps_antenna_offset_y > n_ownship_length_meters)
7412       msg +=
7413           _("\n - your GPS offset from bow must be within your ship's length");
7414     if (n_ownship_min_mm <= 0 || n_ownship_min_mm > 100)
7415       msg += _("\n - your minimum ship icon size must be between 1 and 100 mm");
7416     if (!msg.IsEmpty()) {
7417       msg.Prepend(_("The settings for own ship real size are not correct:"));
7418       OCPNMessageBox(this, msg, _("OpenCPN info"), wxICON_ERROR | wxOK);
7419       ::wxEndBusyCursor();
7420       event.SetInt(wxID_STOP);
7421       return;
7422     }
7423     g_n_ownship_length_meters = n_ownship_length_meters;
7424     g_n_ownship_beam_meters = n_ownship_beam_meters;
7425     g_n_gps_antenna_offset_y = n_gps_antenna_offset_y;
7426     g_n_gps_antenna_offset_x = n_gps_antenna_offset_x;
7427     g_n_ownship_min_mm = static_cast<int>(n_ownship_min_mm);
7428   }
7429   g_OwnShipIconType = m_pShipIconType->GetSelection();
7430 
7431   m_pText_ACRadius->GetValue().ToDouble(&g_n_arrival_circle_radius);
7432   g_n_arrival_circle_radius = wxClip(g_n_arrival_circle_radius, 0.001, 0.6); // Correct abnormally
7433 
7434   wxString *icon_name = pWayPointMan->GetIconKey( pWaypointDefaultIconChoice->GetSelection() );
7435   if(icon_name && icon_name->Length())
7436     g_default_wp_icon = *icon_name;
7437 
7438   icon_name = pWayPointMan->GetIconKey( pRoutepointDefaultIconChoice->GetSelection() );
7439   if(icon_name && icon_name->Length())
7440     g_default_routepoint_icon = *icon_name;
7441 
7442   g_bUseWptScaMin = pScaMinChckB->GetValue();
7443   g_iWpt_ScaMin = wxAtoi( m_pText_ScaMin->GetValue() );
7444   g_bOverruleScaMin = pScaMinOverruleChckB->GetValue();
7445 
7446   //  Any Font changes?
7447   if(m_bfontChanged)
7448       m_returnChanges |= FONT_CHANGED;
7449 
7450   // Handle Chart Tab
7451   if (pActiveChartsList) {
7452     UpdateWorkArrayFromTextCtl();
7453   } else {
7454     m_pWorkDirList->Clear();
7455     int nDir = m_CurrentDirList.GetCount();
7456 
7457     for (int i = 0; i < nDir; i++) {
7458       ChartDirInfo cdi = m_CurrentDirList[i];
7459       m_pWorkDirList->Add(cdi);
7460     }
7461   }
7462   groupsPanel->SetDBDirs(*m_pWorkDirList);  // update the Groups tab
7463   groupsPanel->m_treespopulated = FALSE;
7464 
7465   int k_force = FORCE_UPDATE;
7466   if (pUpdateCheckBox) {
7467     if (!pUpdateCheckBox->GetValue()) k_force = 0;
7468     pUpdateCheckBox->Enable();
7469     pUpdateCheckBox->SetValue(FALSE);
7470   } else {
7471     k_force = 0;
7472   }
7473 
7474   m_returnChanges |= k_force;
7475 
7476   int k_scan = SCAN_UPDATE;
7477   if (pScanCheckBox) {
7478     if (!pScanCheckBox->GetValue()) k_scan = 0;
7479     pScanCheckBox->Enable();
7480     pScanCheckBox->SetValue(FALSE);
7481   } else {
7482     k_scan = 0;
7483   }
7484 
7485   m_returnChanges |= k_scan;
7486 
7487   // Chart Groups
7488 
7489   if (groupsPanel->modified) {
7490     groupsPanel->EmptyChartGroupArray(g_pGroupArray);
7491     delete g_pGroupArray;
7492     g_pGroupArray = groupsPanel->CloneChartGroupArray(m_pGroupArray);
7493     m_returnChanges |= GROUPS_CHANGED;
7494   }
7495 
7496   // Handle Settings Tab
7497   if (m_pConfig) {
7498     g_bShowStatusBar = pShowStatusBar->GetValue();
7499 #ifndef __WXOSX__
7500     g_bShowMenuBar = pShowMenuBar->GetValue();
7501 #endif
7502     g_bShowCompassWin = pShowCompassWin->GetValue();
7503   }
7504 
7505   g_bShowChartBar = pShowChartBar->GetValue();
7506 
7507   wxString screenmm = pScreenMM->GetValue();
7508   long mm = -1;
7509   screenmm.ToLong(&mm);
7510   g_config_display_size_mm = mm > 0 ? mm : -1;
7511   g_config_display_size_manual = pRBSizeManual->GetValue();
7512 
7513   // Connections page.
7514   g_bfilter_cogsog = m_cbFilterSogCog->GetValue();
7515 
7516   long filter_val = 1;
7517   m_tFilterSec->GetValue().ToLong(&filter_val);
7518   g_COGFilterSec = wxMin(static_cast<int>(filter_val), MAX_COGSOG_FILTER_SECONDS);
7519   g_COGFilterSec = wxMax(g_COGFilterSec, 1);
7520   g_SOGFilterSec = g_COGFilterSec;
7521 
7522   g_bMagneticAPB = m_cbAPBMagnetic->GetValue();
7523   g_NMEAAPBPrecision = m_choicePrecision->GetCurrentSelection();
7524 
7525   // NMEA Source
7526   //  If the stream selected exists, capture some of its existing parameters
7527   //  to facility identification and allow stop and restart of the stream
7528   wxString lastAddr;
7529   int lastPort = 0;
7530   NetworkProtocol lastNetProtocol = PROTO_UNDEFINED;
7531 
7532   if (mSelectedConnection) {
7533     ConnectionParams* cpo = mSelectedConnection;
7534     lastAddr = cpo->NetworkAddress;
7535     lastPort = cpo->NetworkPort;
7536     lastNetProtocol = cpo->NetProtocol;
7537   }
7538 
7539   if (!connectionsaved) {
7540     size_t nCurrentPanelCount = g_pConnectionParams->GetCount();
7541     ConnectionParams *cp = NULL;
7542     int old_priority = -1;
7543     {
7544       if (mSelectedConnection) {
7545         cp =  mSelectedConnection;
7546         old_priority = cp->Priority;
7547         UpdateConnectionParamsFromSelectedItem( cp );
7548         cp->b_IsSetup = false;
7549 
7550         //delete g_pConnectionParams->Item(itemIndex)->m_optionsPanel;
7551         //old_priority = g_pConnectionParams->Item(itemIndex)->Priority;
7552         //g_pConnectionParams->RemoveAt(itemIndex);
7553         //g_pConnectionParams->Insert(cp, itemIndex);
7554         //mSelectedConnection = cp;
7555         //cp->m_optionsPanel->SetSelected( true );
7556       } else {
7557         cp = CreateConnectionParamsFromSelectedItem();
7558         if(cp)
7559             g_pConnectionParams->Add(cp);
7560       }
7561 
7562       //  Record the previous parameters, if any
7563       if(cp){
7564         cp->LastNetProtocol = lastNetProtocol;
7565         cp->LastNetworkAddress = lastAddr;
7566         cp->LastNetworkPort = lastPort;
7567       }
7568 
7569       if(g_pConnectionParams->GetCount() != nCurrentPanelCount)
7570         FillSourceList();
7571       else if(old_priority >= 0){
7572           if(old_priority != cp->Priority)             // need resort
7573              UpdateSourceList( true );
7574           else
7575              UpdateSourceList( false );
7576       }
7577 
7578 
7579 
7580 
7581       connectionsaved = TRUE;
7582     }
7583 //     else {
7584 //       ::wxEndBusyCursor();
7585 //       if (m_bNMEAParams_shown) event.SetInt(wxID_STOP);
7586 //     }
7587 
7588     SetSelectedConnectionPanel( nullptr );
7589 
7590   }
7591 
7592   // Recreate datastreams that are new, or have been edited
7593   for (size_t i = 0; i < g_pConnectionParams->Count(); i++) {
7594     ConnectionParams* cp = g_pConnectionParams->Item(i);
7595 
7596     // Stream is new, or edited
7597     if (cp->b_IsSetup) continue;
7598     // Terminate and remove any existing stream with the same port name
7599     DataStream* pds_existing = g_pMUX->FindStream(cp->GetDSPort());
7600     if (pds_existing) g_pMUX->StopAndRemoveStream(pds_existing);
7601 
7602     //  Try to stop any previous stream to avoid orphans
7603     pds_existing = g_pMUX->FindStream(cp->GetLastDSPort());
7604     if (pds_existing) g_pMUX->StopAndRemoveStream(pds_existing);
7605 
7606     //  This for Bluetooth, which has strange parameters
7607     if(cp->Type == INTERNAL_BT){
7608         pds_existing = g_pMUX->FindStream(cp->GetPortStr());
7609         if (pds_existing) g_pMUX->StopAndRemoveStream(pds_existing);
7610     }
7611 
7612     // Internal BlueTooth driver stacks commonly need a time delay to purge their buffers, etc.
7613     // before restating with new parameters...
7614     if(cp->Type == INTERNAL_BT)
7615         wxSleep(1);
7616 
7617     if (!cp->bEnabled) continue;
7618     g_pMUX->AddStream(makeDataStream(g_pMUX, cp));
7619     cp->b_IsSetup = TRUE;
7620   }
7621 
7622   g_bGarminHostUpload = m_cbGarminUploadHost->GetValue();
7623   g_GPS_Ident = m_cbFurunoGP3X->GetValue() ? _T( "FurunoGP3X" ) : _T( "Generic" );
7624 
7625   // End of Connections page
7626   if(pCDOOutlines) g_bShowOutlines = pCDOOutlines->GetValue();
7627   if(pSDisplayGrid) g_bDisplayGrid = pSDisplayGrid->GetValue();
7628 
7629   if(pCDOQuilting){
7630     bool temp_bquilting = pCDOQuilting->GetValue();
7631 //   if (!g_bQuiltEnable && temp_bquilting)
7632 //     cc1->ReloadVP(); /* compose the quilt */
7633     g_bQuiltEnable = temp_bquilting;
7634   }
7635 //  g_bFullScreenQuilt = !pFullScreenQuilt->GetValue();
7636 
7637   if(pSDepthUnits) g_bShowDepthUnits = pSDepthUnits->GetValue();
7638   g_bskew_comp = pSkewComp->GetValue();
7639   g_btouch = pMobile->GetValue();
7640   g_bresponsive = pResponsive->GetValue();
7641   g_bRollover = pRollover->GetValue();
7642   g_bShowMuiZoomButtons = pZoomButtons->GetValue();
7643 
7644   g_bAutoHideToolbar = pToolbarAutoHideCB->GetValue();
7645 
7646   long hide_val = 10;
7647   pToolbarHideSecs->GetValue().ToLong(&hide_val);
7648   g_nAutoHideToolbar = wxMin(static_cast<int>(hide_val), 100);
7649   g_nAutoHideToolbar = wxMax(g_nAutoHideToolbar, 2);
7650 
7651   //g_fog_overzoom = !pOverzoomEmphasis->GetValue();
7652   //g_oz_vector_scale = !pOZScaleVector->GetValue();
7653 
7654   g_bsmoothpanzoom = pSmoothPanZoom->GetValue();
7655   #ifdef __OCPN__ANDROID__
7656   g_bsmoothpanzoom = false;
7657   #endif
7658   if(pSmoothPanZoom) g_bsmoothpanzoom = pSmoothPanZoom->GetValue();
7659 #ifdef __OCPN__ANDROID__
7660   g_bsmoothpanzoom = false;
7661 #endif
7662 
7663   long update_val = 1;
7664   pCOGUPUpdateSecs->GetValue().ToLong(&update_val);
7665   g_COGAvgSec = wxMin(static_cast<int>(update_val), MAX_COG_AVERAGE_SECONDS);
7666 
7667   //TODO if (g_bCourseUp != pCBCourseUp->GetValue()) gFrame->ToggleCourseUp();
7668 
7669   if(pCBLookAhead) g_bLookAhead = pCBLookAhead->GetValue();
7670 
7671   g_bShowTrue = pCBTrueShow->GetValue();
7672   g_bShowMag = pCBMagShow->GetValue();
7673 
7674   b_haveWMM = g_pi_manager && g_pi_manager->IsPlugInAvailable(_T("WMM"));
7675   if(!b_haveWMM  && !b_oldhaveWMM)
7676     pMagVar->GetValue().ToDouble(&g_UserVar);
7677 
7678   m_pText_OSCOG_Predictor->GetValue().ToDouble(&g_ownship_predictor_minutes);
7679   m_pText_OSHDT_Predictor->GetValue().ToDouble(&g_ownship_HDTpredictor_miles);
7680 
7681   double temp_dbl;
7682   g_iNavAidRadarRingsNumberVisible =
7683       pNavAidRadarRingsNumberVisible->GetSelection();
7684   if (pNavAidRadarRingsStep->GetValue().ToDouble(&temp_dbl))
7685     g_fNavAidRadarRingsStep = temp_dbl;
7686   g_pNavAidRadarRingsStepUnits = m_itemRadarRingsUnits->GetSelection();
7687   g_iWaypointRangeRingsNumber = pWaypointRangeRingsNumber->GetSelection();
7688   if (pWaypointRangeRingsStep->GetValue().ToDouble(&temp_dbl))
7689     g_fWaypointRangeRingsStep = temp_dbl;
7690   g_iWaypointRangeRingsStepUnits = m_itemWaypointRangeRingsUnits->GetSelection();
7691   g_colourWaypointRangeRingsColour =  m_colourWaypointRangeRingsColour->GetColour();
7692    g_colourWaypointRangeRingsColour =
7693        wxColour(g_colourWaypointRangeRingsColour.Red(), g_colourWaypointRangeRingsColour.Green(), g_colourWaypointRangeRingsColour.Blue());
7694   g_bWayPointPreventDragging = pWayPointPreventDragging->GetValue();
7695   g_own_ship_sog_cog_calc = pSogCogFromLLCheckBox->GetValue();
7696   g_own_ship_sog_cog_calc_damp_sec = pSogCogFromLLDampInterval->GetValue();
7697 
7698   g_bConfirmObjectDelete = pConfirmObjectDeletion->GetValue();
7699 
7700   if(pPreserveScale) g_bPreserveScaleOnX = pPreserveScale->GetValue();
7701 
7702   if ( g_bUIexpert && pCmdSoundString) {
7703       g_CmdSoundString = pCmdSoundString->GetValue( );
7704       if ( wxIsEmpty( g_CmdSoundString ) ) {
7705           g_CmdSoundString = wxString( SYSTEM_SOUND_CMD );
7706           pCmdSoundString->SetValue( g_CmdSoundString );
7707       }
7708   }
7709 
7710   g_bPlayShipsBells = pPlayShipsBells->GetValue();
7711   if (pSoundDeviceIndex)
7712       g_iSoundDeviceIndex = pSoundDeviceIndex->GetSelection();
7713   //g_bTransparentToolbar = pTransparentToolbar->GetValue();
7714   g_iSDMMFormat = pSDMMFormat->GetSelection();
7715   g_iDistanceFormat = pDistanceFormat->GetSelection();
7716   g_iSpeedFormat = pSpeedFormat->GetSelection();
7717 
7718   // LIVE ETA OPTION
7719   if(pSLiveETA) g_bShowLiveETA = pSLiveETA->GetValue();
7720   if(pSDefaultBoatSpeed) pSDefaultBoatSpeed->GetValue().ToDouble(&g_defaultBoatSpeedUserUnit);
7721   g_defaultBoatSpeed = fromUsrSpeed(g_defaultBoatSpeedUserUnit);
7722 
7723   g_bAdvanceRouteWaypointOnArrivalOnly = pAdvanceRouteWaypointOnArrivalOnly->GetValue();
7724 
7725   g_colourTrackLineColour =  m_colourTrackLineColour->GetColour();
7726   g_colourTrackLineColour =  wxColour(g_colourTrackLineColour.Red(), g_colourTrackLineColour.Green(), g_colourTrackLineColour.Blue());
7727   g_nTrackPrecision = pTrackPrecision->GetSelection();
7728 
7729   g_bTrackDaily = pTrackDaily->GetValue();
7730 
7731   g_track_rotate_time = 0;
7732 #if wxCHECK_VERSION(2, 9, 0)
7733 #if  wxUSE_TIMEPICKCTRL
7734   int h,m,s;
7735   if( pTrackRotateTime->GetTime(&h, &m, &s) )
7736       g_track_rotate_time = h*3600 + m*60 + s;
7737 #endif
7738 #endif
7739 
7740     if( pTrackRotateUTC->GetValue() )
7741         g_track_rotate_time_type = TIME_TYPE_UTC;
7742     else if( pTrackRotateLMT->GetValue() )
7743         g_track_rotate_time_type = TIME_TYPE_LMT;
7744     else g_track_rotate_time_type = TIME_TYPE_COMPUTER;
7745 
7746 
7747   g_bHighliteTracks = pTrackHighlite->GetValue();
7748 
7749   if(pEnableZoomToCursor) g_bEnableZoomToCursor = pEnableZoomToCursor->GetValue();
7750 #ifdef __OCPN__ANDROID__
7751   g_bEnableZoomToCursor = false;
7752 #endif
7753 
7754   g_colourOwnshipRangeRingsColour =  m_colourOwnshipRangeRingColour->GetColour();
7755   g_colourOwnshipRangeRingsColour =  wxColour(g_colourOwnshipRangeRingsColour.Red(), g_colourOwnshipRangeRingsColour.Green(), g_colourOwnshipRangeRingsColour.Blue());
7756 
7757   // AIS Parameters
7758   //   CPA Box
7759   g_bCPAMax = m_pCheck_CPA_Max->GetValue();
7760   m_pText_CPA_Max->GetValue().ToDouble(&g_CPAMax_NM);
7761   g_bCPAWarn = m_pCheck_CPA_Warn->GetValue();
7762   m_pText_CPA_Warn->GetValue().ToDouble(&g_CPAWarn_NM);
7763   g_bTCPA_Max = m_pCheck_CPA_WarnT->GetValue();
7764   m_pText_CPA_WarnT->GetValue().ToDouble(&g_TCPA_Max);
7765 
7766   //   Lost Targets
7767   g_bMarkLost = m_pCheck_Mark_Lost->GetValue();
7768   m_pText_Mark_Lost->GetValue().ToDouble(&g_MarkLost_Mins);
7769   g_bRemoveLost = m_pCheck_Remove_Lost->GetValue();
7770   m_pText_Remove_Lost->GetValue().ToDouble(&g_RemoveLost_Mins);
7771 
7772   //   Display
7773   g_bShowCOG = m_pCheck_Show_COG->GetValue();
7774   m_pText_COG_Predictor->GetValue().ToDouble(&g_ShowCOG_Mins);
7775 
7776   g_bAISShowTracks = m_pCheck_Show_Tracks->GetValue();
7777   m_pText_Track_Length->GetValue().ToDouble(&g_AISShowTracks_Mins);
7778 
7779   //   Update all the current targets
7780   if (g_pAIS) {
7781     AIS_Target_Hash::iterator it;
7782     AIS_Target_Hash* current_targets = g_pAIS->GetTargetList();
7783     for (it = current_targets->begin(); it != current_targets->end(); ++it) {
7784       AIS_Target_Data* pAISTarget = it->second;
7785       if (NULL != pAISTarget) pAISTarget->b_show_track = g_bAISShowTracks;
7786     }
7787   }
7788 
7789   g_bHideMoored = m_pCheck_Hide_Moored->GetValue();
7790   m_pText_Moored_Speed->GetValue().ToDouble(&g_ShowMoored_Kts);
7791 
7792   g_bDrawAISRealtime = m_pCheck_Draw_Realtime_Prediction->GetValue();
7793   m_pText_RealtPred_Speed->GetValue().ToDouble(&g_AIS_RealtPred_Kts);
7794 
7795   g_bAllowShowScaled = m_pCheck_Scale_Priority->GetValue();
7796   long l;
7797   m_pText_Scale_Priority->GetValue().ToLong(&l);
7798   g_ShowScaled_Num = (int)l;
7799 
7800   g_bShowAreaNotices = m_pCheck_Show_Area_Notices->GetValue();
7801   g_bDrawAISSize = m_pCheck_Draw_Target_Size->GetValue();
7802   g_bShowAISName = m_pCheck_Show_Target_Name->GetValue();
7803   long ais_name_scale = 5000;
7804   m_pText_Show_Target_Name_Scale->GetValue().ToLong(&ais_name_scale);
7805   g_Show_Target_Name_Scale = (int)wxMax(5000, ais_name_scale);
7806 
7807   g_bWplIsAprsPosition = m_pCheck_Wpl_Aprs->GetValue();
7808 
7809   //   Alert
7810   g_bAIS_CPA_Alert = m_pCheck_AlertDialog->GetValue();
7811   g_bAIS_CPA_Alert_Audio = m_pCheck_AlertAudio->GetValue();
7812   g_bAIS_CPA_Alert_Suppress_Moored = m_pCheck_Alert_Moored->GetValue();
7813 
7814   g_bAIS_ACK_Timeout = m_pCheck_Ack_Timout->GetValue();
7815   m_pText_ACK_Timeout->GetValue().ToDouble(&g_AckTimeout_Mins);
7816 
7817   //   Rollover
7818   g_bAISRolloverShowClass = m_pCheck_Rollover_Class->GetValue();
7819   g_bAISRolloverShowCOG = m_pCheck_Rollover_COG->GetValue();
7820   g_bAISRolloverShowCPA = m_pCheck_Rollover_CPA->GetValue();
7821 
7822   g_chart_zoom_modifier = m_pSlider_Zoom->GetValue();
7823   g_chart_zoom_modifier_vector = m_pSlider_Zoom_Vector->GetValue();
7824   g_cm93_zoom_factor = m_pSlider_CM93_Zoom->GetValue();
7825   g_GUIScaleFactor = m_pSlider_GUI_Factor->GetValue();
7826   g_ChartScaleFactor = m_pSlider_Chart_Factor->GetValue();
7827   g_ChartScaleFactorExp = g_Platform->getChartScaleFactorExp(g_ChartScaleFactor);
7828   g_ShipScaleFactor = m_pSlider_Ship_Factor->GetValue();
7829   g_ShipScaleFactorExp = g_Platform->getChartScaleFactorExp(g_ShipScaleFactor);
7830   g_ENCSoundingScaleFactor =  m_pSlider_Text_Factor->GetValue();
7831 
7832 
7833   //  Only reload the icons if user has actually visted the UI page
7834   //if(m_bVisitLang)
7835   //  pWayPointMan->ReloadAllIcons();
7836 
7837   g_NMEAAPBPrecision = m_choicePrecision->GetCurrentSelection();
7838 
7839   g_TalkerIdText = m_TalkerIdText->GetValue().MakeUpper();
7840 
7841   if (g_bopengl != pOpenGL->GetValue()) m_returnChanges |= GL_CHANGED;
7842   g_bopengl = pOpenGL->GetValue();
7843 
7844   //   Handle Vector Charts Tab
7845   int depthUnit = pDepthUnitSelect->GetSelection();
7846   g_nDepthUnitDisplay = depthUnit;
7847 
7848   //  Process the UserStandard display list, noting if any changes were made
7849   bool bUserStdChange = false;
7850 
7851   int nOBJL = ps57CtlListBox->GetCount();
7852 
7853   for (int iPtr = 0; iPtr < nOBJL; iPtr++) {
7854     int itemIndex = -1;
7855     for (size_t i = 0; i < marinersStdXref.size(); i++) {
7856       if (marinersStdXref[i] == iPtr) {
7857         itemIndex = i;
7858         break;
7859       }
7860     }
7861     assert(itemIndex >= 0);
7862     OBJLElement* pOLE = (OBJLElement*)(ps52plib->pOBJLArray->Item(itemIndex));
7863     if(pOLE->nViz != ps57CtlListBox->IsChecked(iPtr))
7864         bUserStdChange = true;
7865     pOLE->nViz = ps57CtlListBox->IsChecked(iPtr);
7866   }
7867 
7868   if (ps52plib) {
7869 
7870     // Take a snapshot of the S52 config right now,
7871     // for later comparison
7872     ps52plib->GenerateStateHash();
7873     long stateHash = ps52plib->GetStateHash();
7874 
7875 
7876     if (m_returnChanges & GL_CHANGED) {
7877       // Do this now to handle the screen refresh that is automatically
7878       // generated on Windows at closure of the options dialog...
7879       ps52plib->FlushSymbolCaches();
7880       // some CNSY depends on renderer (e.g. CARC)
7881       ps52plib->ClearCNSYLUPArray();
7882       ps52plib->GenerateStateHash();
7883     }
7884 
7885     if(pDispCat) {
7886         enum _DisCat nset = OTHER;
7887         switch (pDispCat->GetSelection()) {
7888         case 0:
7889             nset = DISPLAYBASE;
7890             break;
7891         case 1:
7892             nset = STANDARD;
7893             break;
7894         case 2:
7895             nset = OTHER;
7896             break;
7897         case 3:
7898             nset = MARINERS_STANDARD;
7899             break;
7900         }
7901         ps52plib->SetDisplayCategory(nset);
7902     }
7903 
7904     if(pCheck_SOUNDG) ps52plib->m_bShowSoundg = pCheck_SOUNDG->GetValue();
7905     if(pCheck_ATONTEXT) ps52plib->m_bShowAtonText = pCheck_ATONTEXT->GetValue();
7906     if(pCheck_LDISTEXT) ps52plib->m_bShowLdisText = pCheck_LDISTEXT->GetValue();
7907     if(pCheck_XLSECTTEXT) ps52plib->m_bExtendLightSectors = pCheck_XLSECTTEXT->GetValue();
7908 
7909     ps52plib->m_bShowMeta = pCheck_META->GetValue();
7910     ps52plib->m_bDeClutterText = pCheck_DECLTEXT->GetValue();
7911     ps52plib->m_bShowNationalTexts = pCheck_NATIONALTEXT->GetValue();
7912     ps52plib->m_bShowS57ImportantTextOnly = pCheck_SHOWIMPTEXT->GetValue();
7913     ps52plib->m_bUseSCAMIN = pCheck_SCAMIN->GetValue();
7914 
7915     ps52plib->m_nSymbolStyle = pPointStyle->GetSelection() == 0 ? PAPER_CHART : SIMPLIFIED;
7916 
7917     ps52plib->m_nBoundaryStyle = pBoundStyle->GetSelection() == 0
7918                                      ? PLAIN_BOUNDARIES
7919                                      : SYMBOLIZED_BOUNDARIES;
7920     ps52plib->m_nSoundingFactor = m_pSlider_Text_Factor->GetValue();
7921 
7922     S52_setMarinerParam(S52_MAR_TWO_SHADES, (p24Color->GetSelection() == 0) ? 1.0 : 0.0);
7923 
7924     // Depths
7925     double dval;
7926     float conv = 1;
7927 
7928     if (depthUnit == 0)  // feet
7929       conv = 0.3048f;    // international definiton of 1 foot is 0.3048 metres
7930     else if (depthUnit == 2)  // fathoms
7931       conv = 0.3048f * 6;     // 1 fathom is 6 feet
7932 
7933     if (m_SafetyCtl->GetValue().ToDouble(&dval)) {
7934       S52_setMarinerParam(S52_MAR_SAFETY_DEPTH, dval * conv);  // controls sounding display
7935       S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR, dval * conv);  // controls colour
7936     }
7937 
7938     if (m_ShallowCtl->GetValue().ToDouble(&dval))
7939       S52_setMarinerParam(S52_MAR_SHALLOW_CONTOUR, dval * conv);
7940 
7941     if (m_DeepCtl->GetValue().ToDouble(&dval))
7942       S52_setMarinerParam(S52_MAR_DEEP_CONTOUR, dval * conv);
7943 
7944     ps52plib->UpdateMarinerParams();
7945     ps52plib->m_nDepthUnitDisplay = depthUnit;
7946 
7947     ps52plib->GenerateStateHash();
7948 
7949     // Detect a change to S52 library config
7950     if( (stateHash != ps52plib->GetStateHash()) || bUserStdChange )
7951         m_returnChanges |= S52_CHANGED;
7952 
7953   }
7954 
7955 // User Interface Panel
7956 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
7957   if (m_bVisitLang) {
7958     wxString new_canon = _T("en_US");
7959     wxString lang_sel = m_itemLangListBox->GetStringSelection();
7960 
7961     int nLang = sizeof(lang_list) / sizeof(int);
7962     for (int it = 0; it < nLang; it++) {
7963       const wxLanguageInfo* pli = wxLocale::GetLanguageInfo(lang_list[it]);
7964       if (pli) {
7965         wxString lang_canonical = pli->CanonicalName;
7966         wxString test_string = GetOCPNKnownLanguage(lang_canonical);
7967         if (lang_sel == test_string) {
7968           new_canon = lang_canonical;
7969           break;
7970         }
7971       }
7972     }
7973 
7974     wxString locale_old = g_locale;
7975     g_locale = new_canon;
7976 
7977     if (g_locale != locale_old) m_returnChanges |= LOCALE_CHANGED;
7978 
7979     wxString oldStyle = g_StyleManager->GetCurrentStyle()->name;
7980     //g_StyleManager->SetStyleNextInvocation( m_itemStyleListBox->GetStringSelection());
7981     if (g_StyleManager->GetStyleNextInvocation() != oldStyle) {
7982       m_returnChanges |= STYLE_CHANGED;
7983     }
7984     wxSizeEvent nullEvent;
7985     gFrame->OnSize(nullEvent);
7986   }
7987 #endif
7988     if ( g_bInlandEcdis != pInlandEcdis->GetValue() ){ // InlandEcdis changed
7989         g_bInlandEcdis = pInlandEcdis->GetValue();
7990         SwitchInlandEcdisMode( g_bInlandEcdis );
7991         m_returnChanges |= TOOLBAR_CHANGED;
7992     }
7993 #ifdef __WXOSX__
7994     if ( g_bDarkDecorations != pDarkDecorations->GetValue() ) {
7995         g_bDarkDecorations = pDarkDecorations->GetValue();
7996 
7997         OCPNMessageBox(this,
7998                        _("The changes to the window decorations will take full effect the next time you start OpenCPN."),
7999                        _("OpenCPN"));
8000     }
8001 #endif
8002   // PlugIn Manager Panel
8003 
8004   // Pick up any changes to selections
8005   if (g_pi_manager->UpdatePlugIns())
8006       m_returnChanges |= TOOLBAR_CHANGED;
8007 
8008   // And keep config in sync
8009   if (m_pPlugInCtrl) m_pPlugInCtrl->UpdatePluginsOrder();
8010   g_pi_manager->UpdateConfig();
8011 
8012   // PlugIns may have added panels
8013   if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxOK);
8014 
8015   m_returnChanges |= GENERIC_CHANGED | k_vectorcharts | k_charts |
8016                      m_groups_changed | k_plugins | k_tides;
8017 
8018   // Pick up all the entries in the Tide/current DataSelected control
8019   // and update the global static array
8020   TideCurrentDataSet.Clear();
8021   int nEntry = tcDataSelected->GetItemCount();
8022   for (int i = 0; i < nEntry; i++) {
8023       wxString setName = tcDataSelected->GetItemText(i);
8024       TideCurrentDataSet.Add(setName);
8025   }
8026 
8027   if (event.GetId() != ID_APPLY)                // only on ID_OK
8028     g_canvasConfig = m_screenConfig;
8029 
8030   if (event.GetId() == ID_APPLY) {
8031     gFrame->ProcessOptionsDialog(m_returnChanges, m_pWorkDirList);
8032     m_CurrentDirList = *m_pWorkDirList; // Perform a deep copy back to main database.
8033 
8034     //  We can clear a few flag bits on "Apply", so they won't be recognised at the "OK" click.
8035     //  Their actions have already been accomplished once...
8036     m_returnChanges &= ~( CHANGE_CHARTS | FORCE_UPDATE | SCAN_UPDATE );
8037     k_charts = 0;
8038 
8039     gFrame->RefreshAllCanvas();
8040   }
8041 
8042   // Some layout changes requiring a new options instance?
8043   if(m_bneedNew)
8044     m_returnChanges |= NEED_NEW_OPTIONS;
8045 
8046   //  Record notice of any changes to last applied template
8047   UpdateTemplateTitleText();
8048 
8049   if (::wxIsBusy()) //FIXME: Not sure why this is needed here
8050       ::wxEndBusyCursor();
8051 }
8052 
OnXidOkClick(wxCommandEvent & event)8053 void options::OnXidOkClick(wxCommandEvent& event) {
8054   // When closing the form with Ctrl-Enter sometimes we get double events, the
8055   // second is empty??
8056   if (event.GetEventObject() == NULL) return;
8057 
8058   OnApplyClick(event);
8059   if (event.GetInt() == wxID_STOP) return;
8060 
8061   Finish();
8062 }
8063 
Finish(void)8064 void options::Finish(void) {
8065   //  Required to avoid intermittent crash on wxGTK
8066   m_pListbook->ChangeSelection(0);
8067   for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
8068     wxNotebookPage* pg = m_pListbook->GetPage(i);
8069     wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
8070     if (nb) nb->ChangeSelection(0);
8071   }
8072 
8073   lastWindowPos = GetPosition();
8074   lastWindowSize = GetSize();
8075   SetReturnCode(m_returnChanges);
8076   EndModal(m_returnChanges);
8077 }
8078 
OnButtondeleteClick(wxCommandEvent & event)8079 void options::OnButtondeleteClick(wxCommandEvent& event)
8080 {
8081   long item = -1;
8082   for ( ;; )
8083   {
8084       item = pActiveChartsList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
8085       if ( item == -1 )
8086           break;
8087       pActiveChartsList->DeleteItem( item );
8088 
8089       // On Android, there is some trouble with wxLIST_STATE_SELECTED.
8090       // So, only allow deletion of one item per click.
8091 #ifdef __OCPN__ANDROID__
8092       break;
8093 #endif
8094 
8095       item = -1;      // Restart
8096   }
8097 
8098   UpdateWorkArrayFromTextCtl();
8099 
8100   if (m_pWorkDirList) {
8101       pActiveChartsList->DeleteAllItems();
8102       for (size_t id = 0; id < m_pWorkDirList->GetCount(); id++) {
8103         wxString dirname = m_pWorkDirList->Item(id).fullpath;
8104         wxListItem li;
8105         li.SetId( id );
8106         li.SetAlign(wxLIST_FORMAT_LEFT);
8107         li.SetText(dirname);
8108         li.SetColumn(0);
8109         long idx = pActiveChartsList->InsertItem( li );
8110      }
8111   }
8112 
8113   k_charts |= CHANGE_CHARTS;
8114 
8115   pScanCheckBox->Disable();
8116 
8117   event.Skip();
8118 
8119 }
8120 
OnButtonParseENC(wxCommandEvent & event)8121 void options::OnButtonParseENC(wxCommandEvent &event)
8122 {
8123     gFrame->GetPrimaryCanvas()->EnablePaint(false);
8124 
8125     extern void ParseAllENC(wxWindow* parent);
8126 
8127     ParseAllENC(g_pOptions);
8128 
8129     ViewPort vp;
8130     gFrame->ChartsRefresh();
8131 
8132     gFrame->GetPrimaryCanvas()->EnablePaint(true);
8133 
8134 }
8135 
8136 #ifdef OCPN_USE_LZMA
8137 #include <lzma.h>
8138 
8139 static bool
compress(lzma_stream * strm,FILE * infile,FILE * outfile)8140 compress(lzma_stream *strm, FILE *infile, FILE *outfile)
8141 {
8142     // This will be LZMA_RUN until the end of the input file is reached.
8143     // This tells lzma_code() when there will be no more input.
8144     lzma_action action = LZMA_RUN;
8145 
8146     // Buffers to temporarily hold uncompressed input
8147     // and compressed output.
8148     uint8_t inbuf[BUFSIZ];
8149     uint8_t outbuf[BUFSIZ];
8150 
8151     // Initialize the input and output pointers. Initializing next_in
8152     // and avail_in isn't really necessary when we are going to encode
8153     // just one file since LZMA_STREAM_INIT takes care of initializing
8154     // those already. But it doesn't hurt much and it will be needed
8155     // if encoding more than one file like we will in 02_decompress.c.
8156     //
8157     // While we don't care about strm->total_in or strm->total_out in this
8158     // example, it is worth noting that initializing the encoder will
8159     // always reset total_in and total_out to zero. But the encoder
8160     // initialization doesn't touch next_in, avail_in, next_out, or
8161     // avail_out.
8162     strm->next_in = NULL;
8163     strm->avail_in = 0;
8164     strm->next_out = outbuf;
8165     strm->avail_out = sizeof(outbuf);
8166 
8167     // Loop until the file has been successfully compressed or until
8168     // an error occurs.
8169     while (true) {
8170         // Fill the input buffer if it is empty.
8171         if (strm->avail_in == 0 && !feof(infile)) {
8172             strm->next_in = inbuf;
8173             strm->avail_in = fread(inbuf, 1, sizeof(inbuf),
8174                                    infile);
8175 
8176             if (ferror(infile)) {
8177                 fprintf(stderr, "Read error: %s\n",
8178                         strerror(errno));
8179                 return false;
8180             }
8181 
8182             // Once the end of the input file has been reached,
8183             // we need to tell lzma_code() that no more input
8184             // will be coming and that it should finish the
8185             // encoding.
8186             if (feof(infile))
8187                 action = LZMA_FINISH;
8188         }
8189 
8190         // Tell liblzma do the actual encoding.
8191         //
8192         // This reads up to strm->avail_in bytes of input starting
8193         // from strm->next_in. avail_in will be decremented and
8194         // next_in incremented by an equal amount to match the
8195         // number of input bytes consumed.
8196         //
8197         // Up to strm->avail_out bytes of compressed output will be
8198         // written starting from strm->next_out. avail_out and next_out
8199         // will be incremented by an equal amount to match the number
8200         // of output bytes written.
8201         //
8202         // The encoder has to do internal buffering, which means that
8203         // it may take quite a bit of input before the same data is
8204         // available in compressed form in the output buffer.
8205         lzma_ret ret = lzma_code(strm, action);
8206 
8207         // If the output buffer is full or if the compression finished
8208         // successfully, write the data from the output bufffer to
8209         // the output file.
8210         if (strm->avail_out == 0 || ret == LZMA_STREAM_END) {
8211             // When lzma_code() has returned LZMA_STREAM_END,
8212             // the output buffer is likely to be only partially
8213             // full. Calculate how much new data there is to
8214             // be written to the output file.
8215             size_t write_size = sizeof(outbuf) - strm->avail_out;
8216 
8217             if (fwrite(outbuf, 1, write_size, outfile)
8218                 != write_size) {
8219                 fprintf(stderr, "Write error: %s\n",
8220                         strerror(errno));
8221                 return false;
8222             }
8223 
8224             // Reset next_out and avail_out.
8225             strm->next_out = outbuf;
8226             strm->avail_out = sizeof(outbuf);
8227         }
8228 
8229         // Normally the return value of lzma_code() will be LZMA_OK
8230         // until everything has been encoded.
8231         if (ret != LZMA_OK) {
8232             // Once everything has been encoded successfully, the
8233             // return value of lzma_code() will be LZMA_STREAM_END.
8234             //
8235             // It is important to check for LZMA_STREAM_END. Do not
8236             // assume that getting ret != LZMA_OK would mean that
8237             // everything has gone well.
8238             if (ret == LZMA_STREAM_END)
8239                 return true;
8240 
8241             // It's not LZMA_OK nor LZMA_STREAM_END,
8242             // so it must be an error code. See lzma/base.h
8243             // (src/liblzma/api/lzma/base.h in the source package
8244             // or e.g. /usr/include/lzma/base.h depending on the
8245             // install prefix) for the list and documentation of
8246             // possible values. Most values listen in lzma_ret
8247             // enumeration aren't possible in this example.
8248             const char *msg;
8249             switch (ret) {
8250             case LZMA_MEM_ERROR:
8251                 msg = "Memory allocation failed";
8252                 break;
8253 
8254             case LZMA_DATA_ERROR:
8255                 // This error is returned if the compressed
8256                 // or uncompressed size get near 8 EiB
8257                 // (2^63 bytes) because that's where the .xz
8258                 // file format size limits currently are.
8259                 // That is, the possibility of this error
8260                 // is mostly theoretical unless you are doing
8261                 // something very unusual.
8262                 //
8263                 // Note that strm->total_in and strm->total_out
8264                 // have nothing to do with this error. Changing
8265                 // those variables won't increase or decrease
8266                 // the chance of getting this error.
8267                 msg = "File size limits exceeded";
8268                 break;
8269 
8270             default:
8271                 // This is most likely LZMA_PROG_ERROR, but
8272                 // if this program is buggy (or liblzma has
8273                 // a bug), it may be e.g. LZMA_BUF_ERROR or
8274                 // LZMA_OPTIONS_ERROR too.
8275                 //
8276                 // It is inconvenient to have a separate
8277                 // error message for errors that should be
8278                 // impossible to occur, but knowing the error
8279                 // code is important for debugging. That's why
8280                 // it is good to print the error code at least
8281                 // when there is no good error message to show.
8282                 msg = "Unknown error, possibly a bug";
8283                 break;
8284             }
8285 
8286             wxLogMessage(_T("LZMA Encoder error: %s (error code %u)\n"),
8287                          msg, ret);
8288             return false;
8289         }
8290     }
8291 }
8292 #endif
8293 
CompressChart(wxString in,wxString out)8294 static bool CompressChart(wxString in, wxString out)
8295 {
8296 #ifdef OCPN_USE_LZMA
8297     FILE *infile = fopen(in.mb_str(), "rb");
8298     if(!infile)
8299         return false;
8300 
8301     FILE *outfile = fopen(out.mb_str(), "wb");
8302     if(!outfile) {
8303         fclose(infile);
8304         return false;
8305     }
8306 
8307     lzma_stream strm = LZMA_STREAM_INIT;
8308     bool success = false;
8309     if(lzma_easy_encoder(&strm, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64) == LZMA_OK)
8310         success = compress(&strm, infile, outfile);
8311 
8312     lzma_end(&strm);
8313     fclose(infile);
8314     fclose(outfile);
8315 
8316     return success;
8317 #endif
8318     return false;
8319 }
8320 
OnButtoncompressClick(wxCommandEvent & event)8321 void options::OnButtoncompressClick(wxCommandEvent& event)
8322 {
8323   wxArrayInt pListBoxSelections;
8324   long item = -1;
8325   for ( ;; )
8326   {
8327       item = pActiveChartsList->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
8328       if ( item == -1 )
8329           break;
8330       pListBoxSelections.Add((int)item);
8331       item = -1;      // Restart
8332   }
8333 
8334 
8335     if(OCPNMessageBox( this, _("Compression will alter chart files on disk.\n\
8336 This may make them incompatible with other programs or older versions of OpenCPN.\n\
8337 Compressed charts may take slightly longer to load and display on some systems.\n\
8338 They can be decompressed again using unxz or 7 zip programs."),
8339                      _("OpenCPN Warning"),
8340                      wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING) != wxID_YES)
8341       return;
8342 
8343     wxArrayString filespecs;
8344     filespecs.Add("*.kap");
8345     filespecs.Add("*.KAP");
8346     filespecs.Add("*.000");
8347 
8348     // should we verify we are in a cm93 directory for these?
8349     filespecs.Add("*.A"), filespecs.Add("*.B"), filespecs.Add("*.C"), filespecs.Add("*.D");
8350     filespecs.Add("*.E"), filespecs.Add("*.F"), filespecs.Add("*.G"), filespecs.Add("*.Z");
8351 
8352     wxGenericProgressDialog prog1(_("OpenCPN Compress Charts"), wxEmptyString,
8353                            filespecs.GetCount()*pListBoxSelections.GetCount()+1, this,
8354                           wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
8355                           wxPD_REMAINING_TIME | wxPD_CAN_SKIP);
8356 
8357   //    Make sure the dialog is big enough to be readable
8358   wxSize sz = prog1.GetSize();
8359   sz.x = gFrame->GetClientSize().x * 8 / 10;
8360   prog1.SetSize( sz );
8361 
8362   wxArrayString charts;
8363   for(unsigned int i=0; i<pListBoxSelections.GetCount(); i++) {
8364       wxString dirname = pActiveChartsList->GetItemText( pListBoxSelections[i] );
8365       if (dirname.IsEmpty())
8366           continue;
8367       //    This is a fix for OSX, which appends EOL to results of
8368       //    GetLineText()
8369       while ((dirname.Last() == wxChar(_T('\n'))) ||
8370              (dirname.Last() == wxChar(_T('\r'))))
8371           dirname.RemoveLast();
8372 
8373       if(!wxDir::Exists(dirname))
8374           continue;
8375 
8376       wxDir dir(dirname);
8377       wxArrayString FileList;
8378       for(unsigned int j = 0; j<filespecs.GetCount(); j++) {
8379           dir.GetAllFiles(dirname, &FileList, filespecs[j]);
8380           bool skip = false;
8381           prog1.Update(i*filespecs.GetCount()+j, dirname+filespecs[j], &skip);
8382           if(skip)
8383               return;
8384       }
8385 
8386 
8387       for(unsigned int j=0; j<FileList.GetCount(); j++)
8388           charts.Add(FileList[j]);
8389   }
8390   prog1.Hide();
8391 
8392   if(charts.GetCount() == 0) {
8393       OCPNMessageBox(
8394       this,
8395       _("No charts found to compress."),
8396       _("OpenCPN Info"));
8397       return;
8398   }
8399 
8400 
8401   // TODO: make this use threads
8402   unsigned long total_size = 0, total_compressed_size = 0, count = 0;
8403   wxGenericProgressDialog prog(_("OpenCPN Compress Charts"), wxEmptyString, charts.GetCount()+1, this,
8404                         wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
8405                         wxPD_REMAINING_TIME | wxPD_CAN_SKIP);
8406 
8407   prog.SetSize( sz );
8408 
8409   for(unsigned int i=0; i<charts.GetCount(); i++) {
8410       bool skip = false;
8411       prog.Update(i, charts[i], &skip);
8412       if(skip)
8413           break;
8414 
8415       wxString compchart = charts[i] + _T(".xz");
8416       if(CompressChart(charts[i], compchart)) {
8417           total_size += wxFileName::GetSize(charts[i]).ToULong();
8418           total_compressed_size += wxFileName::GetSize(compchart).ToULong();
8419           wxRemoveFile(charts[i]);
8420           count++;
8421       }
8422   }
8423 
8424   // report statistics
8425   double total_size_mb = total_size/1024.0/1024.0;
8426   double total_compressed_size_mb = total_compressed_size/1024.0/1024.0;
8427   OCPNMessageBox(
8428       this,
8429       wxString::Format(_("compressed %ld charts\nfrom %.1fMB to %.1fMB\nsaved %.1fMB (%.1f%%)"),
8430                        count, total_size_mb, total_compressed_size_mb,
8431                        total_size_mb - total_compressed_size_mb,
8432                        (1 - total_compressed_size_mb / total_size_mb) * 100.0),
8433       _("OpenCPN Info"));
8434 
8435   UpdateWorkArrayFromTextCtl();
8436 
8437   if (m_pWorkDirList) {
8438       pActiveChartsList->DeleteAllItems();
8439       for (size_t id = 0; id < m_pWorkDirList->GetCount(); id++) {
8440         wxString dirname = m_pWorkDirList->Item(id).fullpath;
8441         wxListItem li;
8442         li.SetId( id );
8443         li.SetAlign(wxLIST_FORMAT_LEFT);
8444         li.SetText(dirname);
8445         li.SetColumn(0);
8446         long idx = pActiveChartsList->InsertItem( li );
8447      }
8448   }
8449 
8450 
8451   k_charts |= CHANGE_CHARTS;
8452 
8453   pScanCheckBox->Disable();
8454 
8455   event.Skip();
8456 
8457 }
8458 
OnDebugcheckbox1Click(wxCommandEvent & event)8459 void options::OnDebugcheckbox1Click(wxCommandEvent& event) { event.Skip(); }
8460 
OnCancelClick(wxCommandEvent & event)8461 void options::OnCancelClick(wxCommandEvent& event) {
8462 
8463   m_pListbook->ChangeSelection(0);
8464 
8465   lastWindowPos = GetPosition();
8466   lastWindowSize = GetSize();
8467 
8468   if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxCANCEL);
8469 
8470   EndModal(0);
8471 }
8472 
OnClose(wxCloseEvent & event)8473 void options::OnClose(wxCloseEvent& event) {
8474   //      PlugIns may have added panels
8475   if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxOK);
8476 
8477   m_pListbook->ChangeSelection(0);
8478 
8479   lastWindowPos = GetPosition();
8480   lastWindowSize = GetSize();
8481 
8482   EndModal(0);
8483 }
8484 
OnFontChoice(wxCommandEvent & event)8485 void options::OnFontChoice(wxCommandEvent& event) {
8486     wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8487 
8488     wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8489     wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8490 
8491     m_textSample->SetFont(*pif);
8492     m_textSample->SetForegroundColour(init_color);
8493     m_itemBoxSizerFontPanel->Layout();
8494     event.Skip();
8495 }
8496 
OnChooseFont(wxCommandEvent & event)8497 void options::OnChooseFont(wxCommandEvent& event) {
8498 
8499 #ifdef __OCPN__ANDROID__
8500     androidDisableRotation();
8501 #endif
8502 
8503   wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8504   wxFontData font_data;
8505 
8506   wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8507   wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8508 
8509   wxFontData init_font_data;
8510   if (pif) init_font_data.SetInitialFont(*pif);
8511   init_font_data.SetColour(init_color);
8512 
8513 #ifdef __WXGTK__
8514   wxFontDialog dg(this, init_font_data);
8515 #else
8516   wxFontDialog dg(pParent, init_font_data);
8517 #endif
8518 
8519   wxFont* qFont = dialogFont;
8520   dg.SetFont(*qFont);
8521 
8522 #ifdef __WXQT__
8523   // Make sure that font dialog will fit on the screen without scrolling
8524   // We do this by setting the dialog font size "small enough" to show "n" lines
8525   wxSize proposed_size = GetSize();
8526   float n_lines = 30;
8527   float font_size = dialogFont->GetPointSize();
8528 
8529   if ((proposed_size.y / font_size) < n_lines) {
8530     float new_font_size = proposed_size.y / n_lines;
8531     wxFont* smallFont = new wxFont(*dialogFont);
8532     smallFont->SetPointSize(new_font_size);
8533     dg.SetFont(*smallFont);
8534   }
8535 #endif
8536 
8537   if (g_bresponsive) {
8538     dg.SetSize(GetSize());
8539     dg.Centre();
8540   }
8541 
8542   int retval = dg.ShowModal();
8543   if (wxID_CANCEL != retval) {
8544     font_data = dg.GetFontData();
8545     wxFont font = font_data.GetChosenFont();
8546     wxFont* psfont = new wxFont(font);
8547     wxColor color = font_data.GetColour();
8548     FontMgr::Get().SetFont(sel_text_element, psfont, color);
8549     pParent->UpdateAllFonts();
8550     m_bfontChanged = true;
8551     OnFontChoice(event);
8552   }
8553 
8554 #ifdef __OCPN__ANDROID__
8555   androidEnableRotation();
8556 #endif
8557 
8558   event.Skip();
8559 }
8560 
8561 #if defined(__WXGTK__) || defined(__WXQT__)
OnChooseFontColor(wxCommandEvent & event)8562 void options::OnChooseFontColor(wxCommandEvent& event) {
8563   wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8564 
8565   wxColourData colour_data;
8566 
8567   wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8568   wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8569 
8570 #ifdef __OCPN__ANDROID__
8571   androidDisableRotation();
8572 
8573   unsigned int cco = 0;
8574   cco |= 0xff;  cco  = cco << 8;
8575   cco |= init_color.Red(); cco = cco << 8;
8576   cco |= init_color.Green(); cco = cco << 8;
8577   cco |= init_color.Blue();
8578   unsigned int cc = androidColorPicker( cco);
8579 
8580   wxColor cn;
8581   unsigned char blue = (unsigned char) cc % 256;
8582   unsigned char green = (unsigned char) (cc >> 8) % 256;;
8583   unsigned char red = (unsigned char) (cc >> 16) % 256;
8584   cn.Set(red, green, blue);
8585 
8586   FontMgr::Get().SetFont(sel_text_element, pif, cn);
8587 
8588   pParent->UpdateAllFonts();
8589   m_bfontChanged = true;
8590 
8591   androidEnableRotation();
8592 #else
8593   wxScrolledWindow *sw = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(400, 400));
8594 
8595   wxColourData init_colour_data;
8596   init_colour_data.SetColour(init_color);
8597 
8598   wxColourDialog dg(sw, &init_colour_data);
8599 
8600   int retval = dg.ShowModal();
8601   if (wxID_CANCEL != retval) {
8602     colour_data = dg.GetColourData();
8603 
8604     wxColor color = colour_data.GetColour();
8605     FontMgr::Get().SetFont(sel_text_element, pif, color);
8606 
8607     pParent->UpdateAllFonts();
8608     m_bfontChanged = true;
8609     OnFontChoice(event);
8610   }
8611 
8612   sw->Destroy();
8613 #endif
8614   event.Skip();
8615 }
8616 #endif
8617 
OnChartsPageChange(wxListbookEvent & event)8618 void options::OnChartsPageChange(wxListbookEvent& event) {
8619   unsigned int i = event.GetSelection();
8620 
8621   //    User selected Chart Groups Page?
8622   //    If so, build the remaining UI elements
8623   if (2 == i) {  // 2 is the index of "Chart Groups" page
8624     if (!groupsPanel->m_UIcomplete) groupsPanel->CompletePanel();
8625 
8626     if (!groupsPanel->m_settingscomplete) {
8627       ::wxBeginBusyCursor();
8628       groupsPanel->CompleteInitialSettings();
8629       ::wxEndBusyCursor();
8630     } else if (!groupsPanel->m_treespopulated) {
8631       groupsPanel->PopulateTrees();
8632       groupsPanel->m_treespopulated = TRUE;
8633     }
8634   }
8635   else if(1 == i){              // Vector charts panel
8636     LoadS57();
8637     if (!m_bVectorInit){
8638         SetInitialVectorSettings();
8639         UpdateOptionsUnits();  // sets depth values, overriding defaults
8640     }
8641   }
8642 
8643   event.Skip();  // Allow continued event processing
8644 }
8645 
OnPageChange(wxListbookEvent & event)8646 void options::OnPageChange(wxListbookEvent& event) {
8647   DoOnPageChange(event.GetSelection());
8648 }
8649 
OnSubNBPageChange(wxNotebookEvent & event)8650 void options::OnSubNBPageChange(wxNotebookEvent& event) {
8651   // In the case where wxNotebooks are nested, we need to identify the subpage
8652   // But otherwise do nothing
8653   if(event.GetEventObject()){
8654       if(dynamic_cast<wxWindow*>(event.GetEventObject())){
8655           wxWindow *win = dynamic_cast<wxWindow*>(event.GetEventObject());
8656           wxWindow *parent = dynamic_cast<wxWindow*>(win->GetParent());
8657           if(dynamic_cast<wxNotebook*>(parent)){
8658             lastSubPage = event.GetSelection();
8659             return;
8660           }
8661           if(dynamic_cast<wxListbook*>(parent)){
8662             lastSubPage = event.GetSelection();
8663             return;
8664           }
8665 
8666       }
8667   }
8668 }
8669 
OnTopNBPageChange(wxNotebookEvent & event)8670 void options::OnTopNBPageChange(wxNotebookEvent& event) {
8671   DoOnPageChange(event.GetSelection());
8672 }
8673 
DoOnPageChange(size_t page)8674 void options::DoOnPageChange(size_t page) {
8675 
8676   unsigned int i = page;
8677 
8678   //  Sometimes there is a (-1) page selected.
8679   if(page > 10)
8680       return;
8681 
8682   lastPage = i;
8683 
8684 #ifndef __OCPN__ANDROID__
8685   if (0 == i) {  // Display
8686     if(m_sconfigSelect_single)
8687        m_sconfigSelect_single->Refresh( true );
8688     if(m_sconfigSelect_twovertical)
8689        m_sconfigSelect_twovertical->Refresh( true );
8690   }
8691 #endif
8692 
8693   //    User selected Chart Page?
8694   //    If so, build the "Charts" page variants
8695   if (1 == i) {  // 2 is the index of "Charts" page
8696     k_charts = VISIT_CHARTS;
8697   }
8698 
8699   else if (m_pageUI == i) {  // 5 is the index of "User Interface" page
8700 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
8701 
8702     if (!m_bVisitLang) {
8703       ::wxBeginBusyCursor();
8704 
8705       int current_language = plocale_def_lang->GetLanguage();
8706       wxString current_sel = wxLocale::GetLanguageName(current_language);
8707 
8708       current_sel = GetOCPNKnownLanguage(g_locale);
8709 
8710       int nLang = sizeof(lang_list) / sizeof(int);
8711 
8712 #ifdef __WXMSW__
8713       // always add us english
8714       m_itemLangListBox->Append(_T("English (U.S.)"));
8715 
8716       wxString lang_dir = g_Platform->GetSharedDataDir() + _T("share/locale/");
8717       for (int it = 1; it < nLang; it++) {
8718         if (wxLocale::IsAvailable(lang_list[it])) {
8719           wxLocale ltest(lang_list[it], 0);
8720           ltest.AddCatalog(_T("opencpn"));
8721           if (!ltest.IsLoaded(_T("opencpn"))) continue;
8722 
8723           // Defaults
8724           wxString loc_lang_name = wxLocale::GetLanguageName(lang_list[it]);
8725           wxString widgets_lang_name = loc_lang_name;
8726           wxString lang_canonical =
8727               wxLocale::GetLanguageInfo(lang_list[it])->CanonicalName;
8728 
8729           //  Make opencpn substitutions
8730           wxString lang_suffix;
8731           loc_lang_name = GetOCPNKnownLanguage(lang_canonical, lang_suffix);
8732 
8733           //  Look explicitely to see if .mo is available
8734           wxString test_dir = lang_dir + lang_suffix;
8735           if (!wxDir::Exists(test_dir)) continue;
8736 
8737           m_itemLangListBox->Append(loc_lang_name);
8738         }
8739       }
8740 #else
8741       wxArrayString lang_array;
8742 
8743       // always add us english
8744       lang_array.Add(_T("en_US"));
8745 
8746       for (int it = 0; it < nLang; it++) {
8747         {
8748           wxLog::EnableLogging(
8749               FALSE);  // avoid "Cannot set locale to..." log message
8750 
8751           wxLocale ltest(lang_list[it], 0);
8752 #if wxCHECK_VERSION(2, 9, 0)
8753 #ifdef __WXGTK__
8754           ltest.AddCatalogLookupPathPrefix(wxStandardPaths::Get().GetInstallPrefix() + _T( "/share/locale" ) );
8755 #endif
8756 #endif
8757           ltest.AddCatalog(_T("opencpn"));
8758 
8759           wxLog::EnableLogging(TRUE);
8760 
8761           if (ltest.IsLoaded(_T("opencpn"))) {
8762             wxString s0 =
8763                 wxLocale::GetLanguageInfo(lang_list[it])->CanonicalName;
8764             wxString sl = wxLocale::GetLanguageName(lang_list[it]);
8765             if (wxNOT_FOUND == lang_array.Index(s0)) lang_array.Add(s0);
8766           }
8767         }
8768       }
8769 
8770       for (unsigned int i = 0; i < lang_array.GetCount(); i++) {
8771         //  Make opencpn substitutions
8772         wxString loc_lang_name = GetOCPNKnownLanguage(lang_array[i]);
8773         m_itemLangListBox->Append(loc_lang_name);
8774       }
8775 #endif
8776 
8777       // BUGBUG
8778       //  Remember that wxLocale ctor has the effect of changing the system
8779       //  locale, including the "C" libraries.
8780       //  It should then also happen that the locale should be switched back to
8781       //  ocpn initial load setting
8782       //  upon the dtor of the above wxLocale instantiations....
8783       //  wxWidgets may do so internally, but there seems to be no effect upon
8784       //  the system libraries, so that
8785       //  functions like strftime() do not revert to the correct locale setting.
8786       //  Also, the catalog for the application is not reloaded by the ctor, so
8787       //  we must reload them directly
8788       //  So as workaround, we reset the locale explicitely.
8789 
8790       delete plocale_def_lang;
8791       plocale_def_lang = new wxLocale(current_language);
8792 
8793       setlocale(LC_NUMERIC, "C");
8794       plocale_def_lang->AddCatalog(_T("opencpn"));
8795 
8796       m_itemLangListBox->SetStringSelection(current_sel);
8797 
8798       //      Initialize Language tab
8799       const wxLanguageInfo* pli = wxLocale::FindLanguageInfo(g_locale);
8800       if (pli) {
8801         wxString clang = pli->Description;
8802         //                        m_itemLangListBox->SetValue(clang);
8803       }
8804 
8805       m_bVisitLang = TRUE;
8806 
8807       ::wxEndBusyCursor();
8808     }
8809 #endif
8810   } else if (m_pagePlugins == i) {  // 7 is the index of "Plugins" page
8811     // load the disabled plugins finally because the user might want to enable
8812     // them
8813     if (g_pi_manager->LoadAllPlugIns(FALSE)) {
8814       delete m_pPlugInCtrl;
8815       m_pPlugInCtrl = NULL;
8816       delete m_PluginCatalogMgrPanel;
8817       m_PluginCatalogMgrPanel = NULL;
8818       itemBoxSizerPanelPlugins->Clear();
8819     }
8820 
8821     if (!m_pPlugInCtrl) {
8822       //      Build the PlugIn Manager Panel
8823       ::wxBeginBusyCursor();
8824 
8825       m_pPlugInCtrl =
8826           new PluginListPanel(itemPanelPlugins, ID_PANELPIM, wxDefaultPosition,
8827                               wxDefaultSize, g_pi_manager->GetPlugInArray());
8828       m_pPlugInCtrl->SetScrollRate(m_scrollRate, m_scrollRate);
8829       itemBoxSizerPanelPlugins->Add(m_pPlugInCtrl, 01, wxEXPAND | wxGROW | wxALL, 4);
8830       if(g_pi_manager)
8831           g_pi_manager->SetListPanelPtr(m_pPlugInCtrl);
8832 
8833       m_PluginCatalogMgrPanel = new CatalogMgrPanel(itemPanelPlugins);
8834       m_PluginCatalogMgrPanel->SetListPanelPtr(m_pPlugInCtrl);
8835 
8836       itemBoxSizerPanelPlugins->Add(m_PluginCatalogMgrPanel, 0, wxEXPAND | wxALL, 4);
8837       itemBoxSizerPanelPlugins->Layout();
8838 
8839       //  Update the PlugIn page to reflect the state of individual selections
8840       m_pPlugInCtrl->UpdateSelections();
8841 
8842       ::wxEndBusyCursor();
8843     }
8844 
8845     k_plugins = TOOLBAR_CHANGED;
8846   }
8847 }
8848 
8849 // void options::OnNMEASourceChoice( wxCommandEvent& event )
8850 //{
8851 /*TODO
8852     int i = event.GetSelection();
8853     wxString src( m_itemNMEAListBox->GetString( i ) );
8854     if( ( src.Upper().Find( _T("GPSD") ) != wxNOT_FOUND )
8855             || ( src.Upper().Find( _T("LIBGPS") ) != wxNOT_FOUND ) ) {
8856         m_itemNMEA_TCPIP_StaticBox->Enable();
8857         m_itemNMEA_TCPIP_Source->Enable();
8858 
8859         m_itemNMEA_TCPIP_Source->Clear();
8860         m_itemNMEA_TCPIP_Source->WriteText( _T("localhost") ); // default
8861 
8862         wxString source;
8863         source = *pNMEADataSource;
8864         if( source.Upper().StartsWith( _T("GPSD") ) ||
8865    source.Upper().StartsWith( _T("LIBGPS") ) ) {
8866             wxString ip;
8867             ip = source.AfterFirst( ':' );
8868 
8869             if( ip.Len() ) {
8870                 m_itemNMEA_TCPIP_Source->Clear();
8871                 m_itemNMEA_TCPIP_Source->WriteText( ip );
8872             }
8873         }
8874     } else {
8875         m_itemNMEA_TCPIP_StaticBox->Disable();
8876         m_itemNMEA_TCPIP_Source->Disable();
8877     }
8878 */
8879 //}
8880 
OnButtonSelectSound(wxCommandEvent & event)8881 void options::OnButtonSelectSound(wxCommandEvent& event) {
8882   wxString sound_dir = g_Platform->GetSharedDataDir();
8883   sound_dir.Append(_T("sounds"));
8884   wxString sel_file;
8885   int response;
8886 
8887 #ifndef __OCPN__ANDROID__
8888   wxFileDialog* popenDialog = new wxFileDialog(
8889       NULL, _("Select Sound File"), sound_dir, wxEmptyString,
8890       _T("WAV files (*.wav)|*.wav|All files (*.*)|*.*"), wxFD_OPEN);
8891   if (g_bresponsive)
8892     popenDialog = g_Platform->AdjustFileDialogFont(this, popenDialog);
8893 
8894   response = popenDialog->ShowModal();
8895   sel_file = popenDialog->GetPath();
8896   delete popenDialog;
8897 
8898 #else
8899   response =
8900       g_Platform->DoFileSelectorDialog(this, &sel_file, _("Select Sound File"),
8901                                        sound_dir, wxEmptyString, wxT("*.*"));
8902 #endif
8903 
8904   if (response == wxID_OK) {
8905     g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(sel_file);
8906 
8907     g_anchorwatch_sound->Stop();
8908   }
8909 }
8910 
8911 
OnButtonTestSound(wxCommandEvent & event)8912 void options::OnButtonTestSound(wxCommandEvent& event) {
8913     auto sound = SoundFactory();
8914 #ifndef __OCPN__ANDROID__
8915     if ((bool) dynamic_cast<SystemCmdSound*>(sound)) {
8916         sound->SetCmd(g_CmdSoundString.mb_str());
8917     }
8918 #endif
8919     sound->SetFinishedCallback([sound](void*) { delete sound; });
8920     sound->Load(g_sAIS_Alert_Sound_File, g_iSoundDeviceIndex);
8921     sound->Play();
8922 }
8923 
8924 
GetOCPNKnownLanguage(wxString lang_canonical,wxString & lang_dir)8925 wxString GetOCPNKnownLanguage(wxString lang_canonical, wxString& lang_dir) {
8926   wxString return_string;
8927   wxString dir_suffix;
8928 
8929 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
8930 
8931   if (lang_canonical == _T("en_US")) {
8932     dir_suffix = _T("en");
8933     return_string = wxString("English (U.S.)", wxConvUTF8);
8934   } else if (lang_canonical == _T("cs_CZ")) {
8935     dir_suffix = _T("cs");
8936     return_string = wxString("Čeština", wxConvUTF8);
8937   } else if (lang_canonical == _T("da_DK")) {
8938     dir_suffix = _T("da");
8939     return_string = wxString("Dansk", wxConvUTF8);
8940   } else if (lang_canonical == _T("de_DE")) {
8941     dir_suffix = _T("de");
8942     return_string = wxString("Deutsch", wxConvUTF8);
8943   } else if (lang_canonical == _T("et_EE")) {
8944     dir_suffix = _T("et");
8945     return_string = wxString("Eesti", wxConvUTF8);
8946   } else if (lang_canonical == _T("es_ES")) {
8947     dir_suffix = _T("es");
8948     return_string = wxString("Español", wxConvUTF8);
8949   } else if (lang_canonical == _T("fr_FR")) {
8950     dir_suffix = _T("fr");
8951     return_string = wxString("Français", wxConvUTF8);
8952   } else if (lang_canonical == _T("it_IT")) {
8953     dir_suffix = _T("it");
8954     return_string = wxString("Italiano", wxConvUTF8);
8955   } else if (lang_canonical == _T("nl_NL")) {
8956     dir_suffix = _T("nl");
8957     return_string = wxString("Nederlands", wxConvUTF8);
8958   } else if (lang_canonical == _T("pl_PL")) {
8959     dir_suffix = _T("pl");
8960     return_string = wxString("Polski", wxConvUTF8);
8961   } else if (lang_canonical == _T("pt_PT")) {
8962     dir_suffix = _T("pt_PT");
8963     return_string = wxString("Português", wxConvUTF8);
8964   } else if (lang_canonical == _T("pt_BR")) {
8965     dir_suffix = _T("pt_BR");
8966     return_string = wxString("Português Brasileiro", wxConvUTF8);
8967   } else if (lang_canonical == _T("ru_RU")) {
8968     dir_suffix = _T("ru");
8969     return_string = wxString("Русский", wxConvUTF8);
8970   } else if (lang_canonical == _T("sv_SE")) {
8971     dir_suffix = _T("sv");
8972     return_string = wxString("Svenska", wxConvUTF8);
8973   } else if (lang_canonical == _T("fi_FI")) {
8974     dir_suffix = _T("fi_FI");
8975     return_string = wxString("Suomi", wxConvUTF8);
8976   } else if (lang_canonical == _T("nb_NO")) {
8977     dir_suffix = _T("nb_NO");
8978     return_string = wxString("Norsk", wxConvUTF8);
8979   } else if (lang_canonical == _T("tr_TR")) {
8980     dir_suffix = _T("tr_TR");
8981     return_string = wxString("Türkçe", wxConvUTF8);
8982   } else if (lang_canonical == _T("el_GR")) {
8983     dir_suffix = _T("el_GR");
8984     return_string = wxString("Ελληνικά", wxConvUTF8);
8985   } else if (lang_canonical == _T("hu_HU")) {
8986     dir_suffix = _T("hu_HU");
8987     return_string = wxString("Magyar", wxConvUTF8);
8988   } else if (lang_canonical == _T("zh_TW")) {
8989     dir_suffix = _T("zh_TW");
8990     return_string = wxString("正體字", wxConvUTF8);
8991   } else if (lang_canonical == _T("zh_CN")) {
8992       dir_suffix = _T("zh_CN");
8993       return_string = wxString("Simplified Chinese", wxConvUTF8);
8994   } else if (lang_canonical == _T("ca_ES")) {
8995     dir_suffix = _T("ca_ES");
8996     return_string = wxString("Catalan", wxConvUTF8);
8997   } else if (lang_canonical == _T("gl_ES")) {
8998     dir_suffix = _T("gl_ES");
8999     return_string = wxString("Galician", wxConvUTF8);
9000   } else if (lang_canonical == _T("ja_JP")) {
9001     dir_suffix = _T("ja_JP");
9002     return_string = wxString("Japanese", wxConvUTF8);
9003   } else if (lang_canonical == _T("ar_SA")) {
9004     dir_suffix = _T("ar_SA");
9005     return_string = wxString("Arabic", wxConvUTF8);
9006   } else if (lang_canonical == _T("vi_VN")) {
9007     dir_suffix = _T("vi_VN");
9008     return_string = wxString("Vietnamese", wxConvUTF8);
9009   } else {
9010     dir_suffix = lang_canonical;
9011     const wxLanguageInfo* info = wxLocale::FindLanguageInfo(lang_canonical);
9012     if(info)
9013         return_string = info->Description;
9014     else
9015         return_string = lang_canonical;
9016   }
9017 
9018   lang_dir = dir_suffix;
9019 #endif
9020   return return_string;
9021 }
9022 
GetOCPNKnownLanguage(const wxString lang_canonical)9023 wxString GetOCPNKnownLanguage(const wxString lang_canonical) {
9024   wxString lang_dir;
9025   return GetOCPNKnownLanguage(lang_canonical, lang_dir);
9026 }
9027 
CloneChartGroupArray(ChartGroupArray * s)9028 ChartGroupArray* ChartGroupsUI::CloneChartGroupArray(ChartGroupArray* s) {
9029   ChartGroupArray* d = new ChartGroupArray;
9030   for (unsigned int i = 0; i < s->GetCount(); i++) {
9031     ChartGroup* psg = s->Item(i);
9032     ChartGroup* pdg = new ChartGroup;
9033     pdg->m_group_name = psg->m_group_name;
9034     pdg->m_element_array.reserve(psg->m_element_array.size());
9035 
9036     for(auto& elem : psg->m_element_array)
9037             pdg->m_element_array.emplace_back(new ChartGroupElement(*elem));
9038 
9039     d->Add(pdg);
9040   }
9041   return d;
9042 }
9043 
EmptyChartGroupArray(ChartGroupArray * s)9044 void ChartGroupsUI::EmptyChartGroupArray(ChartGroupArray* s) {
9045   if (!s) return;
9046 
9047   // ChartGroups don't need anything special for delete, just calling the destructor is enough.
9048   WX_CLEAR_ARRAY(*s);
9049 }
9050 
9051 //    Chart Groups dialog implementation
BEGIN_EVENT_TABLE(ChartGroupsUI,wxEvtHandler)9052  BEGIN_EVENT_TABLE(ChartGroupsUI, wxEvtHandler)
9053 EVT_TREE_ITEM_EXPANDED(wxID_TREECTRL, ChartGroupsUI::OnNodeExpanded)
9054  EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, ChartGroupsUI::OnGroupPageChange) // This should work under Windows :-(
9055 END_EVENT_TABLE()
9056 
9057 ChartGroupsUI::ChartGroupsUI(wxWindow* parent)
9058 {
9059   m_GroupSelectedPage = -1;
9060   m_pActiveChartsTree = 0;
9061   pParent = parent;
9062   lastSelectedCtl = NULL;
9063   allAvailableCtl = NULL;
9064   defaultAllCtl = NULL;
9065   iFont = NULL;
9066   m_pAddButton = NULL;
9067   m_pRemoveButton = NULL;
9068   m_pDeleteGroupButton = NULL;
9069   m_pNewGroupButton = NULL;
9070   m_pGroupArray = NULL;
9071   m_GroupNB = NULL;
9072   modified = false;
9073   m_UIcomplete = false;
9074   m_treespopulated = false;
9075   dialogFont = GetOCPNScaledFont(_("Dialog"));
9076 }
9077 
~ChartGroupsUI(void)9078 ChartGroupsUI::~ChartGroupsUI(void) {
9079   m_DirCtrlArray.Clear();
9080   m_GroupNB->Disconnect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler(ChartGroupsUI::OnGroupPageChange), NULL, this);
9081 
9082   delete iFont;
9083 }
9084 
SetInitialSettings(void)9085 void ChartGroupsUI::SetInitialSettings(void) {
9086   m_settingscomplete = FALSE;
9087   m_treespopulated = FALSE;
9088 }
9089 
PopulateTrees(void)9090 void ChartGroupsUI::PopulateTrees(void) {
9091   //    Fill in the "Active chart" tree control
9092   //    from the options dialog "Active Chart Directories" list
9093   wxArrayString dir_array;
9094   int nDir = m_db_dirs.GetCount();
9095   for (int i = 0; i < nDir; i++) {
9096     wxString dirname = m_db_dirs[i].fullpath;
9097     if (!dirname.IsEmpty()) dir_array.Add(dirname);
9098   }
9099 
9100   PopulateTreeCtrl(allAvailableCtl->GetTreeCtrl(), dir_array, wxColour(0, 0, 0),
9101                    dialogFont);
9102   m_pActiveChartsTree = allAvailableCtl->GetTreeCtrl();
9103 
9104   //    Fill in the Page 0 tree control
9105   //    from the options dialog "Active Chart Directories" list
9106   wxArrayString dir_array0;
9107   int nDir0 = m_db_dirs.GetCount();
9108   for (int i = 0; i < nDir0; i++) {
9109     wxString dirname = m_db_dirs[i].fullpath;
9110     if (!dirname.IsEmpty()) dir_array0.Add(dirname);
9111   }
9112   PopulateTreeCtrl(defaultAllCtl->GetTreeCtrl(), dir_array0,  wxColour(128, 128, 128), iFont);
9113 }
9114 
CompleteInitialSettings(void)9115 void ChartGroupsUI::CompleteInitialSettings(void) {
9116   PopulateTrees();
9117 
9118   BuildNotebookPages(m_pGroupArray);
9119 
9120   m_panel->GetSizer()->Layout();
9121 
9122   m_settingscomplete = TRUE;
9123   m_treespopulated = TRUE;
9124 }
9125 
PopulateTreeCtrl(wxTreeCtrl * ptc,const wxArrayString & dir_array,const wxColour & col,wxFont * pFont)9126 void ChartGroupsUI::PopulateTreeCtrl(wxTreeCtrl* ptc,
9127                                      const wxArrayString& dir_array,
9128                                      const wxColour& col, wxFont* pFont) {
9129   ptc->DeleteAllItems();
9130 
9131   wxDirItemData* rootData = new wxDirItemData(_T("Dummy"), _T("Dummy"), TRUE);
9132   wxString rootName;
9133   rootName = _T("Dummy");
9134   wxTreeItemId m_rootId = ptc->AddRoot(rootName, 3, -1, rootData);
9135   ptc->SetItemHasChildren(m_rootId);
9136 
9137   wxString dirname;
9138   int nDir = dir_array.GetCount();
9139   for (int i = 0; i < nDir; i++) {
9140     wxString dirname = dir_array[i];
9141     if (!dirname.IsEmpty()) {
9142       wxDirItemData* dir_item = new wxDirItemData(dirname, dirname, TRUE);
9143       wxTreeItemId id = ptc->AppendItem(m_rootId, dirname, 0, -1, dir_item);
9144 
9145       // wxWidgets bug workaraound (Ticket #10085)
9146       ptc->SetItemText(id, dirname);
9147       if (pFont) ptc->SetItemFont(id, *pFont);
9148       ptc->SetItemTextColour(id, col);
9149       ptc->SetItemHasChildren(id);
9150     }
9151   }
9152 }
9153 
OnInsertChartItem(wxCommandEvent & event)9154 void ChartGroupsUI::OnInsertChartItem(wxCommandEvent& event) {
9155   wxString insert_candidate = allAvailableCtl->GetPath();
9156   if (!insert_candidate.IsEmpty()) {
9157     if (m_DirCtrlArray.GetCount()) {
9158       wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9159       ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9160       if (pDirCtrl) {
9161         wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9162         if (ptree) {
9163           if (ptree->IsEmpty()) {
9164             wxDirItemData* rootData =
9165                 new wxDirItemData(wxEmptyString, wxEmptyString, TRUE);
9166             wxString rootName = _T("Dummy");
9167             wxTreeItemId rootId = ptree->AddRoot(rootName, 3, -1, rootData);
9168 
9169             ptree->SetItemHasChildren(rootId);
9170           }
9171 
9172           wxTreeItemId root_Id = ptree->GetRootItem();
9173           wxDirItemData* dir_item =
9174               new wxDirItemData(insert_candidate, insert_candidate, TRUE);
9175           wxTreeItemId id =
9176               ptree->AppendItem(root_Id, insert_candidate, 0, -1, dir_item);
9177           if (wxDir::Exists(insert_candidate)) ptree->SetItemHasChildren(id);
9178         }
9179 
9180         pGroup->m_element_array.emplace_back(new ChartGroupElement{insert_candidate});
9181       }
9182     }
9183   }
9184   modified = TRUE;
9185   allAvailableCtl->GetTreeCtrl()->UnselectAll();
9186   m_pAddButton->Disable();
9187 }
9188 
OnRemoveChartItem(wxCommandEvent & event)9189 void ChartGroupsUI::OnRemoveChartItem(wxCommandEvent& event) {
9190   if (m_DirCtrlArray.GetCount()) {
9191     wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9192     ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9193 
9194     if (pDirCtrl) {
9195       wxString sel_item = pDirCtrl->GetPath();
9196 
9197       wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9198       if (ptree && ptree->GetCount()) {
9199         wxTreeItemId id = ptree->GetSelection();
9200         lastDeletedItem = id;
9201         if (id.IsOk()) {
9202           wxString branch_adder;
9203           int group_item_index =
9204               FindGroupBranch(pGroup, ptree, id, &branch_adder);
9205           if (group_item_index >= 0) {
9206             ChartGroupElement* pelement = pGroup->m_element_array[group_item_index].get();
9207             bool b_duplicate = FALSE;
9208             for (unsigned int k = 0; k < pelement->m_missing_name_array.size(); k++) {
9209               if (pelement->m_missing_name_array[k] == sel_item) {
9210                 b_duplicate = TRUE;
9211                 break;
9212               }
9213             }
9214             if (!b_duplicate) {
9215               pelement->m_missing_name_array.Add(sel_item);
9216             }
9217 
9218             //    Special case...
9219             //    If the selection is a branch itself,
9220             //    Then delete from the tree, and delete from the group
9221             if (branch_adder == _T("")) {
9222               ptree->Delete(id);
9223               pGroup->m_element_array.erase(pGroup->m_element_array.begin() + group_item_index);
9224             } else {
9225               ptree->SetItemTextColour(id, wxColour(128, 128, 128));
9226               //   what about toggle back?
9227             }
9228           }
9229         }
9230         modified = TRUE;
9231         lastSelectedCtl->Unselect();
9232         lastSelectedCtl = 0;
9233         m_pRemoveButton->Disable();
9234         wxLogMessage(_T("Disable"));
9235       }
9236     }
9237   }
9238   event.Skip();
9239 }
9240 
OnGroupPageChange(wxNotebookEvent & event)9241 void ChartGroupsUI::OnGroupPageChange(wxNotebookEvent& event) {
9242   m_GroupSelectedPage = event.GetSelection();
9243   allAvailableCtl->GetTreeCtrl()->UnselectAll();
9244   if (lastSelectedCtl) {
9245       lastSelectedCtl->UnselectAll();
9246       lastSelectedCtl = 0;
9247   }
9248   m_pRemoveButton->Disable();
9249   m_pAddButton->Disable();
9250 
9251   // Disable delete option for "All Charts" group
9252   if(m_GroupSelectedPage == 0){
9253       if(m_pDeleteGroupButton)m_pDeleteGroupButton->Disable();
9254   }
9255   else{
9256       if(m_pDeleteGroupButton)m_pDeleteGroupButton->Enable();
9257   }
9258 }
9259 
OnAvailableSelection(wxTreeEvent & event)9260 void ChartGroupsUI::OnAvailableSelection(wxTreeEvent& event) {
9261   wxObject* evtObj = event.GetEventObject();
9262   if (allAvailableCtl && (evtObj == allAvailableCtl->GetTreeCtrl())) {
9263     wxTreeItemId item = allAvailableCtl->GetTreeCtrl()->GetSelection();
9264     if (item && item.IsOk() && m_GroupSelectedPage > 0) {
9265       m_pAddButton->Enable();
9266     } else {
9267       m_pAddButton->Disable();
9268     }
9269   } else {
9270     lastSelectedCtl = dynamic_cast<wxTreeCtrl*>(evtObj);
9271     if (!lastSelectedCtl) goto out;
9272     wxTreeItemId item = lastSelectedCtl->GetSelection();
9273     if (item && item.IsOk() && m_GroupSelectedPage > 0) {
9274       // We need a trick for wxGTK here, since it gives us a Selection
9275       // event with the just deleted element after OnRemoveChartItem()
9276       wxGenericDirCtrl* dirCtrl =
9277           dynamic_cast<wxGenericDirCtrl*>(lastSelectedCtl->GetParent());
9278       if (!dirCtrl) goto out;
9279       wxString itemPath = dirCtrl->GetPath();
9280       if (!itemPath.IsEmpty()) m_pRemoveButton->Enable();
9281     } else {
9282       m_pRemoveButton->Disable();
9283     }
9284   }
9285 
9286 out:
9287   event.Skip();
9288 }
9289 
OnNewGroup(wxCommandEvent & event)9290 void ChartGroupsUI::OnNewGroup(wxCommandEvent& event) {
9291   wxTextEntryDialog* pd = new wxTextEntryDialog();
9292   wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
9293   pd->SetFont(*qFont);
9294 
9295   pd->Create(m_panel, _("Enter Group Name"), _("New Chart Group"));
9296 
9297   if (pd->ShowModal() == wxID_OK) {
9298     if (pd->GetValue().Length()) {
9299       AddEmptyGroupPage(pd->GetValue());
9300       ChartGroup* pGroup = new ChartGroup;
9301       pGroup->m_group_name = pd->GetValue();
9302       m_pGroupArray->Add(pGroup);
9303 
9304       m_GroupSelectedPage =
9305           m_GroupNB->GetPageCount() - 1;  // select the new page
9306       m_GroupNB->ChangeSelection(m_GroupSelectedPage);
9307       m_pDeleteGroupButton->Enable();
9308       modified = TRUE;
9309     }
9310   }
9311   delete pd;
9312 }
9313 
OnDeleteGroup(wxCommandEvent & event)9314 void ChartGroupsUI::OnDeleteGroup(wxCommandEvent& event) {
9315   if (0 != m_GroupSelectedPage) {
9316     m_DirCtrlArray.RemoveAt(m_GroupSelectedPage);
9317     if (m_pGroupArray) m_pGroupArray->RemoveAt(m_GroupSelectedPage - 1);
9318     m_GroupNB->DeletePage(m_GroupSelectedPage);
9319     modified = TRUE;
9320   }
9321 }
9322 
FindGroupBranch(ChartGroup * pGroup,wxTreeCtrl * ptree,wxTreeItemId item,wxString * pbranch_adder)9323 int ChartGroupsUI::FindGroupBranch(ChartGroup* pGroup, wxTreeCtrl* ptree,
9324                                    wxTreeItemId item, wxString* pbranch_adder) {
9325   wxString branch_name;
9326   wxString branch_adder;
9327 
9328   wxTreeItemId current_node = item;
9329   while (current_node.IsOk()) {
9330     wxTreeItemId parent_node = ptree->GetItemParent(current_node);
9331     if (!parent_node) break;
9332 
9333     if (parent_node == ptree->GetRootItem()) {
9334       branch_name = ptree->GetItemText(current_node);
9335       break;
9336     }
9337 
9338     branch_adder.Prepend(ptree->GetItemText(current_node));
9339     branch_adder.Prepend(wxString(wxFILE_SEP_PATH));
9340 
9341     current_node = ptree->GetItemParent(current_node);
9342   }
9343 
9344   // Find the index and element pointer of the target branch in the Group
9345   unsigned int target_item_index = -1;
9346 
9347   for (unsigned int i = 0; i < pGroup->m_element_array.size(); i++) {
9348     wxString target = pGroup->m_element_array[i]->m_element_name;
9349     if (branch_name == target) {
9350       target_item_index = i;
9351       break;
9352     }
9353   }
9354 
9355   if (pbranch_adder) *pbranch_adder = branch_adder;
9356 
9357   return target_item_index;
9358 }
9359 
OnNodeExpanded(wxTreeEvent & event)9360 void ChartGroupsUI::OnNodeExpanded(wxTreeEvent& event) {
9361   wxTreeItemId node = event.GetItem();
9362 
9363   if (m_GroupSelectedPage <= 0) return;
9364   wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9365   ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9366   if (!pDirCtrl) return;
9367 
9368   wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9369   wxString branch_adder;
9370   int target_item_index = FindGroupBranch(pGroup, ptree, node, &branch_adder);
9371   if (target_item_index < 0) return;
9372   ChartGroupElement* target_element =
9373     pGroup->m_element_array[target_item_index].get();
9374   wxString branch_name = target_element->m_element_name;
9375 
9376   // Walk the children of the expanded node, marking any items which appear in
9377   // the "missing" list
9378   if (!target_element->m_missing_name_array.GetCount()) return;
9379   wxString full_root = branch_name;
9380   full_root += branch_adder;
9381   full_root += wxString(wxFILE_SEP_PATH);
9382 
9383   wxTreeItemIdValue cookie;
9384   wxTreeItemId child = ptree->GetFirstChild(node, cookie);
9385   while (child.IsOk()) {
9386     wxString target_string = full_root;
9387     target_string += ptree->GetItemText(child);
9388 
9389     for (unsigned int k = 0;
9390          k < target_element->m_missing_name_array.GetCount(); k++) {
9391       if (target_element->m_missing_name_array[k] == target_string) {
9392         ptree->SetItemTextColour(child, wxColour(128, 128, 128));
9393         break;
9394       }
9395     }
9396     child = ptree->GetNextChild(node, cookie);
9397   }
9398 }
9399 
BuildNotebookPages(ChartGroupArray * pGroupArray)9400 void ChartGroupsUI::BuildNotebookPages(ChartGroupArray* pGroupArray)
9401 {
9402   ClearGroupPages();
9403 
9404   for (unsigned int i = 0; i < pGroupArray->GetCount(); i++) {
9405     ChartGroup* pGroup = pGroupArray->Item(i);
9406     wxTreeCtrl* ptc = AddEmptyGroupPage(pGroup->m_group_name);
9407 
9408     wxString itemname;
9409     int nItems = pGroup->m_element_array.size();
9410     for (int i = 0; i < nItems; i++) {
9411       wxString itemname = pGroup->m_element_array[i]->m_element_name;
9412       if (!itemname.IsEmpty()) {
9413         wxDirItemData* dir_item = new wxDirItemData(itemname, itemname, TRUE);
9414         wxTreeItemId id =
9415             ptc->AppendItem(ptc->GetRootItem(), itemname, 0, -1, dir_item);
9416 
9417         if (wxDir::Exists(itemname)) ptc->SetItemHasChildren(id);
9418       }
9419     }
9420   }
9421 }
9422 
AddEmptyGroupPage(const wxString & label)9423 wxTreeCtrl* ChartGroupsUI::AddEmptyGroupPage(const wxString& label) {
9424   wxGenericDirCtrl* GroupDirCtl =
9425       new wxGenericDirCtrl(m_GroupNB, wxID_ANY, _T("TESTDIR"));
9426   m_GroupNB->AddPage(GroupDirCtl, label);
9427 
9428   wxTreeCtrl* ptree = GroupDirCtl->GetTreeCtrl();
9429   ptree->DeleteAllItems();
9430 
9431   wxDirItemData* rootData =
9432       new wxDirItemData(wxEmptyString, wxEmptyString, TRUE);
9433   wxString rootName = _T("Dummy");
9434   wxTreeItemId rootId = ptree->AddRoot(rootName, 3, -1, rootData);
9435   ptree->SetItemHasChildren(rootId);
9436 
9437   m_DirCtrlArray.Add(GroupDirCtl);
9438 
9439   return ptree;
9440 }
9441 
ClearGroupPages()9442 void ChartGroupsUI::ClearGroupPages()
9443 {
9444     if (m_GroupNB->GetPageCount() == 0)
9445         return;
9446 
9447     for(unsigned int i = m_GroupNB->GetPageCount()-1 ; i > 0 ; i--){
9448         m_DirCtrlArray.RemoveAt(i);
9449         m_GroupNB->DeletePage(i);
9450     }
9451 }
9452 
9453 
OnInsertTideDataLocation(wxCommandEvent & event)9454 void options::OnInsertTideDataLocation(wxCommandEvent& event) {
9455   wxString sel_file;
9456   int response = wxID_CANCEL;
9457 
9458 #ifndef __OCPN__ANDROID__
9459   wxFileDialog* popenDialog = new wxFileDialog(
9460       NULL, _("Select Tide/Current Data"), g_TCData_Dir, wxT(""),
9461       wxT("Tide/Current Data files (*.IDX; *.TCD)|*.IDX;*.idx;*.TCD;*.tcd|All ")
9462           wxT("files (*.*)|*.*"),
9463       wxFD_OPEN);
9464   if (g_bresponsive)
9465     popenDialog = g_Platform->AdjustFileDialogFont(this, popenDialog);
9466 
9467   response = popenDialog->ShowModal();
9468   sel_file = popenDialog->GetPath();
9469   delete popenDialog;
9470 
9471 #else
9472   wxString path;
9473   response = g_Platform->DoFileSelectorDialog(this, &path,
9474                                               _("Select Tide/Current Data"),
9475                                               g_TCData_Dir, _T(""), wxT("*.*"));
9476   sel_file = path;
9477 #endif
9478 
9479   if (response == wxID_OK) {
9480     wxListItem li;
9481    int id = tcDataSelected->GetItemCount();      // next index
9482    li.SetId( id );
9483    long idx = tcDataSelected->InsertItem( li );
9484    tcDataSelected->SetItem(id, 0, g_Platform->NormalizePath(sel_file));
9485 
9486     //    Record the currently selected directory for later use
9487     wxFileName fn(sel_file);
9488     wxString data_dir = fn.GetPath();
9489      g_TCData_Dir = g_Platform->NormalizePath(data_dir);
9490   }
9491 }
9492 
OnRemoveTideDataLocation(wxCommandEvent & event)9493 void options::OnRemoveTideDataLocation(wxCommandEvent& event)
9494 {
9495   long item = -1;
9496   for ( ;; )
9497   {
9498       item = tcDataSelected->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
9499       if ( item == -1 )
9500           break;
9501       tcDataSelected->DeleteItem( item );
9502       item = -1;      // Restart
9503   }
9504 }
9505 
OnValChange(wxCommandEvent & event)9506 void options::OnValChange(wxCommandEvent& event) { event.Skip(); }
9507 
OnScanBTClick(wxCommandEvent & event)9508 void options::OnScanBTClick(wxCommandEvent& event) {
9509   if (m_BTscanning)
9510     StopBTScan();
9511   else {
9512     m_btNoChangeCounter = 0;
9513     m_btlastResultCount = 0;
9514 
9515     m_BTScanTimer.Start(1000, wxTIMER_CONTINUOUS);
9516     g_Platform->startBluetoothScan();
9517     m_BTscanning = 1;
9518     if (m_buttonScanBT) {
9519       m_buttonScanBT->SetLabel(_("Stop Scan"));
9520     }
9521   }
9522 }
9523 
onBTScanTimer(wxTimerEvent & event)9524 void options::onBTScanTimer(wxTimerEvent& event) {
9525   if (m_BTscanning) {
9526     m_BTscanning++;
9527 
9528     m_BTscan_results = g_Platform->getBluetoothScanResults();
9529 
9530     m_choiceBTDataSources->Clear();
9531     m_choiceBTDataSources->Append(m_BTscan_results[0]);  // scan status
9532 
9533     unsigned int i = 1;
9534     while ((i + 1) < m_BTscan_results.GetCount()) {
9535       wxString item1 = m_BTscan_results[i] + _T(";");
9536       wxString item2 = m_BTscan_results.Item(i + 1);
9537       m_choiceBTDataSources->Append(item1 + item2);
9538 
9539       i += 2;
9540     }
9541 
9542     if (m_BTscan_results.GetCount() > 1) {
9543       m_choiceBTDataSources->SetSelection(1);
9544     }
9545 
9546     //  Watch for changes.  When no changes occur after n seconds, stop the scan
9547     if (m_btNoChangeCounter > 5) StopBTScan();
9548 
9549     if ((int)m_BTscan_results.GetCount() == m_btlastResultCount)
9550       m_btNoChangeCounter++;
9551     else
9552       m_btNoChangeCounter = 0;
9553 
9554     m_btlastResultCount = m_BTscan_results.GetCount();
9555 
9556     // Absolute fallback
9557     if (m_BTscanning >= 15) {
9558       StopBTScan();
9559     }
9560   } else {
9561   }
9562   return;
9563 }
9564 
StopBTScan(void)9565 void options::StopBTScan(void) {
9566   m_BTScanTimer.Stop();
9567 
9568   g_Platform->stopBluetoothScan();
9569 
9570   m_BTscanning = 0;
9571 
9572   if (m_buttonScanBT) {
9573     m_buttonScanBT->SetLabel(_("BT Scan"));
9574     m_buttonScanBT->Enable();
9575   }
9576 }
9577 
OnConnValChange(wxCommandEvent & event)9578 void options::OnConnValChange(wxCommandEvent& event) {
9579   connectionsaved = FALSE;
9580   event.Skip();
9581 }
9582 
OnTypeSerialSelected(wxCommandEvent & event)9583 void options::OnTypeSerialSelected(wxCommandEvent& event) {
9584 #ifdef __WXGTK__
9585   if (!g_bserial_access_checked) {
9586     if (!CheckSerialAccess()) {
9587     }
9588     g_bserial_access_checked = TRUE;
9589   }
9590 #endif
9591 
9592   OnConnValChange(event);
9593   SetNMEAFormToSerial();
9594 }
9595 
OnTypeNetSelected(wxCommandEvent & event)9596 void options::OnTypeNetSelected(wxCommandEvent& event) {
9597   OnConnValChange(event);
9598   SetNMEAFormToNet();
9599 }
9600 
OnTypeGPSSelected(wxCommandEvent & event)9601 void options::OnTypeGPSSelected(wxCommandEvent& event) {
9602   OnConnValChange(event);
9603   SetNMEAFormToGPS();
9604 }
9605 
OnTypeBTSelected(wxCommandEvent & event)9606 void options::OnTypeBTSelected(wxCommandEvent& event) {
9607   OnConnValChange(event);
9608   SetNMEAFormToBT();
9609 }
9610 
OnUploadFormatChange(wxCommandEvent & event)9611 void options::OnUploadFormatChange(wxCommandEvent& event) {
9612   if (event.GetEventObject() == m_cbGarminUploadHost && event.IsChecked())
9613     m_cbFurunoGP3X->SetValue(FALSE);
9614   else if (event.GetEventObject() == m_cbFurunoGP3X && event.IsChecked())
9615     m_cbGarminUploadHost->SetValue(FALSE);
9616 
9617   OnConnValChange(event);
9618   event.Skip();
9619 }
9620 
ShowNMEACommon(bool visible)9621 void options::ShowNMEACommon(bool visible) {
9622   m_rbTypeSerial->Show(visible);
9623   m_rbTypeNet->Show(visible);
9624   if (m_rbTypeInternalGPS) m_rbTypeInternalGPS->Show(visible);
9625   if (m_rbTypeInternalBT) m_rbTypeInternalBT->Show(visible);
9626   m_rbIAccept->Show(visible);
9627   m_rbIIgnore->Show(visible);
9628   m_rbOAccept->Show(visible);
9629   m_rbOIgnore->Show(visible);
9630   m_tcInputStc->Show(visible);
9631   m_btnInputStcList->Show(visible);
9632   m_tcOutputStc->Show(visible);
9633   m_btnOutputStcList->Show(visible);
9634   m_cbInput->Show(visible);
9635   m_cbOutput->Show(visible);
9636   m_stPrecision->Show(visible);
9637   m_choicePrecision->Show(visible);
9638   m_choicePriority->Show(visible);
9639   m_stPriority->Show(visible);
9640   m_stPrecision->Show(visible);
9641   m_stTalkerIdText->Show(visible);
9642   m_TalkerIdText->Show(visible);
9643   m_cbCheckCRC->Show(visible);
9644   m_cbCheckSKDiscover->Show(visible);
9645   m_ButtonSKDiscover->Show(visible);
9646   if (visible) {
9647     const bool output = m_cbOutput->IsChecked();
9648     m_stPrecision->Enable(output);
9649     m_choicePrecision->Enable(output);
9650     m_stTalkerIdText->Enable(output);
9651     m_TalkerIdText->Enable(output);
9652   } else {
9653     sbSizerOutFilter->SetDimension(0, 0, 0, 0);
9654     sbSizerInFilter->SetDimension(0, 0, 0, 0);
9655     sbSizerConnectionProps->SetDimension(0, 0, 0, 0);
9656     m_sbConnEdit->SetLabel(_T(""));
9657   }
9658   m_bNMEAParams_shown = visible;
9659 }
9660 
ShowNMEANet(bool visible)9661 void options::ShowNMEANet(bool visible) {
9662   m_stNetAddr->Show(visible);
9663   m_tNetAddress->Show(visible);
9664   m_stNetPort->Show(visible);
9665   m_tNetPort->Show(visible);
9666   m_stNetProto->Show(visible);
9667   m_rbNetProtoSignalK->Show(visible);
9668   m_rbNetProtoGPSD->Show(visible);
9669   m_rbNetProtoTCP->Show(visible);
9670   m_rbNetProtoUDP->Show(visible);
9671   m_stNetComment->Show(visible);
9672   m_tNetComment->Show(visible);
9673 }
9674 
ShowNMEASerial(bool visible)9675 void options::ShowNMEASerial(bool visible) {
9676   m_stSerBaudrate->Show(visible);
9677   m_choiceBaudRate->Show(visible);
9678   m_stSerPort->Show(visible);
9679   m_comboPort->Show(visible);
9680   m_stSerProtocol->Show(visible);
9681   m_choiceSerialProtocol->Show(visible);
9682   m_cbGarminHost->Show(visible);
9683   m_stSerialComment->Show(visible);
9684   m_tSerialComment->Show(visible);
9685 }
9686 
ShowNMEAGPS(bool visible)9687 void options::ShowNMEAGPS(bool visible) {}
9688 
ShowNMEABT(bool visible)9689 void options::ShowNMEABT(bool visible) {
9690   if (visible) {
9691     if (m_buttonScanBT) m_buttonScanBT->Show();
9692     if (m_stBTPairs) m_stBTPairs->Show();
9693     if (m_choiceBTDataSources) {
9694       if (m_choiceBTDataSources->GetCount() > 1)
9695         m_choiceBTDataSources->SetSelection(1);
9696       m_choiceBTDataSources->Show();
9697     }
9698   } else {
9699     if (m_buttonScanBT) m_buttonScanBT->Hide();
9700     if (m_stBTPairs) m_stBTPairs->Hide();
9701     if (m_choiceBTDataSources) m_choiceBTDataSources->Hide();
9702   }
9703   m_tcOutputStc->Show(visible);
9704   m_btnOutputStcList->Show(visible);
9705   m_cbOutput->Show(visible);
9706 
9707 }
9708 
SetNMEAFormToSerial(void)9709 void options::SetNMEAFormToSerial(void) {
9710   ShowNMEACommon(TRUE);
9711   ShowNMEANet(FALSE);
9712   ShowNMEAGPS(FALSE);
9713   ShowNMEABT(FALSE);
9714   ShowNMEASerial(TRUE);
9715 
9716   m_pNMEAForm->FitInside();
9717   Fit();
9718   RecalculateSize();
9719   SetDSFormRWStates();
9720 }
9721 
SetNMEAFormToNet(void)9722 void options::SetNMEAFormToNet(void) {
9723   ShowNMEACommon(TRUE);
9724   ShowNMEANet(TRUE);
9725   ShowNMEAGPS(FALSE);
9726   ShowNMEABT(FALSE);
9727   ShowNMEASerial(FALSE);
9728   m_pNMEAForm->FitInside();
9729   Fit();
9730   RecalculateSize();
9731   SetDSFormRWStates();
9732 }
9733 
SetNMEAFormToGPS(void)9734 void options::SetNMEAFormToGPS(void) {
9735   ShowNMEACommon(TRUE);
9736   ShowNMEANet(FALSE);
9737   ShowNMEAGPS(TRUE);
9738   ShowNMEABT(FALSE);
9739   ShowNMEASerial(FALSE);
9740   m_pNMEAForm->FitInside();
9741   Fit();
9742   RecalculateSize();
9743   SetDSFormRWStates();
9744 }
9745 
SetNMEAFormToBT(void)9746 void options::SetNMEAFormToBT(void) {
9747   m_rbNetProtoUDP->SetValue( true );
9748   ShowNMEACommon(TRUE);
9749   ShowNMEANet(FALSE);
9750   ShowNMEAGPS(FALSE);
9751   ShowNMEABT(TRUE);
9752   ShowNMEASerial(FALSE);
9753   m_pNMEAForm->FitInside();
9754   Fit();
9755   RecalculateSize();
9756   SetDSFormRWStates();
9757 }
9758 
ClearNMEAForm(void)9759 void options::ClearNMEAForm(void) {
9760   ShowNMEACommon(FALSE);
9761   ShowNMEANet(FALSE);
9762   ShowNMEAGPS(FALSE);
9763   ShowNMEABT(FALSE);
9764   ShowNMEASerial(FALSE);
9765   m_pNMEAForm->FitInside();
9766   Fit();
9767   RecalculateSize();
9768 }
9769 
StringArrayToString(wxArrayString arr)9770 wxString StringArrayToString(wxArrayString arr) {
9771   wxString ret = wxEmptyString;
9772   for (size_t i = 0; i < arr.Count(); i++) {
9773     if (i > 0) ret.Append(_T(","));
9774     ret.Append(arr[i]);
9775   }
9776   return ret;
9777 }
9778 
SetDSFormOptionVizStates(void)9779 void options::SetDSFormOptionVizStates(void) {
9780     m_cbInput->Show();
9781     m_cbOutput->Show();
9782     m_cbCheckCRC->Show();
9783     m_stPrecision->Show();
9784     m_choicePrecision->Show();
9785     m_stTalkerIdText->Show();
9786     m_TalkerIdText->Show();
9787     sbSizerInFilter->GetStaticBox()->Show();
9788     m_rbIAccept->Show();
9789     m_rbIIgnore->Show();
9790     sbSizerOutFilter->GetStaticBox()->Show();
9791     m_rbOAccept->Show();
9792     m_rbOIgnore->Show();
9793     m_tcInputStc->Show();
9794     m_btnInputStcList->Show();
9795     m_tcOutputStc->Show();
9796     m_btnOutputStcList->Show();
9797     m_cbCheckSKDiscover->Show();
9798     m_ButtonSKDiscover->Show();
9799     m_StaticTextSKServerStatus->Show();
9800 
9801   if (m_rbTypeSerial->GetValue()) {
9802     m_cbCheckSKDiscover->Hide();
9803     m_ButtonSKDiscover->Hide();
9804     m_StaticTextSKServerStatus->Hide();
9805 
9806   } else if (m_rbNetProtoGPSD->GetValue()) {
9807     m_cbCheckSKDiscover->Hide();
9808     m_cbInput->Hide();
9809     m_cbOutput->Hide();
9810     sbSizerOutFilter->GetStaticBox()->Hide();
9811     m_rbOAccept->Hide();
9812     m_rbOIgnore->Hide();
9813     m_tcOutputStc->Hide();
9814     m_btnOutputStcList->Hide();
9815     m_stPrecision->Hide();
9816     m_choicePrecision->Hide();
9817     m_stTalkerIdText->Hide();
9818     m_TalkerIdText->Hide();
9819     m_cbCheckSKDiscover->Hide();
9820     m_ButtonSKDiscover->Hide();
9821     m_StaticTextSKServerStatus->Hide();
9822 
9823 
9824   } else if (m_rbNetProtoSignalK->GetValue()) {
9825     //here
9826     m_cbInput->Hide();
9827     m_cbOutput->Hide();
9828     m_cbCheckCRC->Hide();
9829     m_stPrecision->Hide();
9830     m_choicePrecision->Hide();
9831     m_stTalkerIdText->Hide();
9832     m_TalkerIdText->Hide();
9833     sbSizerInFilter->GetStaticBox()->Hide();
9834     m_rbIAccept->Hide();
9835     m_rbIIgnore->Hide();
9836     sbSizerOutFilter->GetStaticBox()->Hide();
9837     m_rbOAccept->Hide();
9838     m_rbOIgnore->Hide();
9839     m_tcInputStc->Hide();
9840     m_btnInputStcList->Hide();
9841     m_tcOutputStc->Hide();
9842     m_btnOutputStcList->Hide();
9843 
9844 
9845   } else {
9846     m_cbCheckSKDiscover->Hide();
9847     m_ButtonSKDiscover->Hide();
9848     m_StaticTextSKServerStatus->Hide();
9849   }
9850 }
9851 
9852 
SetDSFormRWStates(void)9853 void options::SetDSFormRWStates(void) {
9854   if (m_rbTypeSerial->GetValue()) {
9855     m_cbInput->Enable(FALSE);
9856     m_cbOutput->Enable(TRUE);
9857     m_rbOAccept->Enable(TRUE);
9858     m_rbOIgnore->Enable(TRUE);
9859     m_btnOutputStcList->Enable(TRUE);
9860   } else if (m_rbNetProtoGPSD->GetValue()) {
9861     if (m_tNetPort->GetValue() == wxEmptyString)
9862       m_tNetPort->SetValue(_T("2947"));
9863     m_cbInput->SetValue(TRUE);
9864     m_cbInput->Enable(FALSE);
9865     m_cbOutput->SetValue(FALSE);
9866     m_cbOutput->Enable(FALSE);
9867     m_rbOAccept->Enable(FALSE);
9868     m_rbOIgnore->Enable(FALSE);
9869     m_btnOutputStcList->Enable(FALSE);
9870   } else if (m_rbNetProtoSignalK->GetValue()) {
9871     if (m_tNetPort->GetValue() == wxEmptyString)
9872       m_tNetPort->SetValue(_T("3000"));
9873     m_cbInput->SetValue(TRUE);
9874     m_cbInput->Enable(FALSE);
9875     m_cbOutput->SetValue(FALSE);
9876     m_cbOutput->Enable(FALSE);
9877     m_rbOAccept->Enable(FALSE);
9878     m_rbOIgnore->Enable(FALSE);
9879     UpdateDiscoverStatus( wxEmptyString );
9880 
9881   } else {
9882     if (m_tNetPort->GetValue() == wxEmptyString)
9883       m_tNetPort->SetValue(_T("10110"));
9884     m_cbInput->Enable(TRUE);
9885     m_cbOutput->Enable(TRUE);
9886     m_rbOAccept->Enable(TRUE);
9887     m_rbOIgnore->Enable(TRUE);
9888     m_btnOutputStcList->Enable(TRUE);
9889   }
9890 
9891   SetDSFormOptionVizStates();
9892   m_pNMEAForm->FitInside();
9893   //Fit();
9894   //RecalculateSize();
9895 
9896 }
9897 
SetConnectionParams(ConnectionParams * cp)9898 void options::SetConnectionParams(ConnectionParams* cp) {
9899   if(wxNOT_FOUND == m_comboPort->FindString(cp->Port))
9900        m_comboPort->Append(cp->Port);
9901 
9902   m_comboPort->Select(m_comboPort->FindString(cp->Port));
9903 
9904   m_cbCheckCRC->SetValue(cp->ChecksumCheck);
9905   m_cbGarminHost->SetValue(cp->Garmin);
9906   m_cbInput->SetValue(cp->IOSelect != DS_TYPE_OUTPUT);
9907   m_cbOutput->SetValue(cp->IOSelect != DS_TYPE_INPUT);
9908   m_cbCheckSKDiscover->SetValue(cp->AutoSKDiscover);
9909 
9910   if (cp->InputSentenceListType == WHITELIST)
9911     m_rbIAccept->SetValue(TRUE);
9912   else
9913     m_rbIIgnore->SetValue(TRUE);
9914   if (cp->OutputSentenceListType == WHITELIST)
9915     m_rbOAccept->SetValue(TRUE);
9916   else
9917     m_rbOIgnore->SetValue(TRUE);
9918   m_tcInputStc->SetValue(StringArrayToString(cp->InputSentenceList));
9919   m_tcOutputStc->SetValue(StringArrayToString(cp->OutputSentenceList));
9920   m_choiceBaudRate->Select(
9921       m_choiceBaudRate->FindString(wxString::Format(_T( "%d" ), cp->Baudrate)));
9922   m_choiceSerialProtocol->Select(cp->Protocol);  // TODO
9923   m_choicePriority->Select(
9924       m_choicePriority->FindString(wxString::Format(_T( "%d" ), cp->Priority)));
9925   m_tNetAddress->SetValue(cp->NetworkAddress);
9926 
9927   if (cp->NetworkPort == 0)
9928     m_tNetPort->SetValue(wxEmptyString);
9929   else
9930     m_tNetPort->SetValue(wxString::Format(wxT("%i"), cp->NetworkPort));
9931 
9932   if (cp->NetProtocol == TCP)
9933     m_rbNetProtoTCP->SetValue(TRUE);
9934   else if (cp->NetProtocol == UDP)
9935     m_rbNetProtoUDP->SetValue(TRUE);
9936   else if (cp->NetProtocol == GPSD)
9937     m_rbNetProtoGPSD->SetValue(TRUE);
9938   else if (cp->NetProtocol == SIGNALK)
9939     m_rbNetProtoSignalK->SetValue(TRUE);
9940   else
9941     m_rbNetProtoGPSD->SetValue(TRUE);
9942 
9943   if (cp->Type == SERIAL) {
9944     m_rbTypeSerial->SetValue(TRUE);
9945     SetNMEAFormToSerial();
9946   } else if (cp->Type == NETWORK) {
9947     m_rbTypeNet->SetValue(TRUE);
9948     SetNMEAFormToNet();
9949   } else if (cp->Type == INTERNAL_GPS) {
9950     if (m_rbTypeInternalGPS) m_rbTypeInternalGPS->SetValue(TRUE);
9951     SetNMEAFormToGPS();
9952   } else if (cp->Type == INTERNAL_BT) {
9953     if (m_rbTypeInternalBT) m_rbTypeInternalBT->SetValue(TRUE);
9954     SetNMEAFormToBT();
9955 
9956     // Preset the source selector
9957     wxString bts = cp->NetworkAddress + _T(";") + cp->GetPortStr();
9958     m_choiceBTDataSources->Clear();
9959     m_choiceBTDataSources->Append(bts);
9960     m_choiceBTDataSources->SetSelection(0);
9961   } else
9962     ClearNMEAForm();
9963 
9964   if(cp->Type == SERIAL)
9965       m_tSerialComment->SetValue(cp->UserComment);
9966   else if (cp->Type == NETWORK)
9967       m_tNetComment->SetValue(cp->UserComment);
9968 
9969   m_connection_enabled = cp->bEnabled;
9970 
9971   // Reset touch flag
9972   connectionsaved = true;
9973 
9974 }
9975 
SetDefaultConnectionParams(void)9976 void options::SetDefaultConnectionParams(void) {
9977   m_comboPort->Select(0);
9978   m_comboPort->SetValue(wxEmptyString);
9979   m_cbCheckCRC->SetValue(TRUE);
9980   m_cbGarminHost->SetValue(FALSE);
9981   m_cbInput->SetValue(TRUE);
9982   m_cbOutput->SetValue(FALSE);
9983   m_rbIAccept->SetValue(TRUE);
9984   m_rbOAccept->SetValue(TRUE);
9985   m_tcInputStc->SetValue(wxEmptyString);
9986   m_tcOutputStc->SetValue(wxEmptyString);
9987   m_choiceBaudRate->Select(m_choiceBaudRate->FindString(_T( "4800" )));
9988   //    m_choiceSerialProtocol->Select( cp->Protocol ); // TODO
9989   m_choicePriority->Select(m_choicePriority->FindString(_T( "1" )));
9990 
9991   m_tNetAddress->SetValue(_T("0.0.0.0"));
9992 
9993   m_tNetComment->SetValue(wxEmptyString);
9994   m_tSerialComment->SetValue(wxEmptyString);
9995 
9996   bool bserial = TRUE;
9997 #ifdef __WXGTK__
9998   if (!g_bserial_access_checked) bserial = FALSE;
9999 #endif
10000 
10001 
10002 #ifdef __OCPN__ANDROID__
10003   if(m_rbTypeInternalGPS){
10004       m_rbTypeInternalGPS->SetValue(true);
10005       SetNMEAFormToGPS();
10006   }
10007   else{
10008       m_rbTypeNet->SetValue( true );
10009       SetNMEAFormToNet();
10010   }
10011 
10012 #else
10013   m_rbTypeSerial->SetValue(bserial);
10014   m_rbTypeNet->SetValue(!bserial);
10015   bserial ? SetNMEAFormToSerial() : SetNMEAFormToNet();
10016 #endif
10017 
10018   m_connection_enabled = TRUE;
10019 
10020   // Reset touch flag
10021   connectionsaved = false;
10022 
10023 }
10024 
SortSourceList(void)10025 bool options::SortSourceList(void) {
10026 
10027     if(g_pConnectionParams->Count() < 2)
10028         return false;
10029 
10030     std::vector<int> ivec;
10031     for (size_t i = 0; i < g_pConnectionParams->Count(); i++)
10032         ivec.push_back(i);
10033 
10034     bool did_sort = false;
10035     bool did_swap = true;
10036     while(did_swap){
10037         did_swap = false;
10038         for (size_t j=1 ; j < ivec.size() ; j++){
10039             ConnectionParams *c1 = g_pConnectionParams->Item(ivec[j]);
10040             ConnectionParams *c2 = g_pConnectionParams->Item(ivec[j-1]);
10041 
10042             if(c1->Priority > c2->Priority){
10043                 int t = ivec[j-1];
10044                 ivec[j-1] = ivec[j];
10045                 ivec[j] = t;
10046                 did_swap = true;
10047                 did_sort = true;
10048             }
10049         }
10050     }
10051 
10052     //if(did_sort)
10053     {
10054         boxSizerConnections = new wxBoxSizer(wxVERTICAL);
10055         m_scrollWinConnections->SetSizer(boxSizerConnections );
10056 
10057         for(size_t i=0 ; i < ivec.size() ; i++){
10058             ConnectionParamsPanel *pPanel = g_pConnectionParams->Item(ivec[i])->m_optionsPanel;
10059             boxSizerConnections->Add( pPanel, 0, wxEXPAND|wxALL, 0 );
10060         }
10061     }
10062 
10063     return did_sort;
10064 
10065 }
10066 
FillSourceList(void)10067 void options::FillSourceList(void) {
10068   m_buttonRemove->Enable(FALSE);
10069 
10070   // Add new panels as necessary
10071   for (size_t i = 0; i < g_pConnectionParams->Count(); i++) {
10072 
10073       if(!g_pConnectionParams->Item(i)->m_optionsPanel){
10074             ConnectionParamsPanel *pPanel = new ConnectionParamsPanel( m_scrollWinConnections, wxID_ANY, wxDefaultPosition, wxDefaultSize,
10075                              g_pConnectionParams->Item(i), this);
10076             pPanel->SetSelected(false);
10077             boxSizerConnections->Add( pPanel, 0, wxEXPAND|wxALL, 0 );
10078             g_pConnectionParams->Item(i)->m_optionsPanel = pPanel;
10079       }
10080       else{
10081           g_pConnectionParams->Item(i)->m_optionsPanel->Update(g_pConnectionParams->Item(i));
10082       }
10083 
10084   }
10085   SortSourceList();
10086   m_scrollWinConnections->Layout();
10087 
10088   mSelectedConnection = NULL;
10089   m_buttonAdd->Enable( true );
10090   m_buttonAdd->Show();
10091 
10092 }
10093 
UpdateSourceList(bool bResort)10094 void options::UpdateSourceList( bool bResort ) {
10095 
10096     for (size_t i = 0; i < g_pConnectionParams->Count(); i++){
10097         ConnectionParams *cp = g_pConnectionParams->Item(i);
10098         ConnectionParamsPanel *panel = cp->m_optionsPanel;
10099         if(panel)
10100             panel->Update(g_pConnectionParams->Item(i));
10101     }
10102 
10103     if(bResort){
10104         SortSourceList();
10105     }
10106 
10107     m_scrollWinConnections->Layout();
10108 }
10109 
OnAddDatasourceClick(wxCommandEvent & event)10110 void options::OnAddDatasourceClick(wxCommandEvent& event) {
10111 
10112   //  Unselect all panels
10113   for (size_t i = 0; i < g_pConnectionParams->Count(); i++)
10114     g_pConnectionParams->Item(i)->m_optionsPanel->SetSelected( false );
10115 
10116   connectionsaved = FALSE;
10117   SetDefaultConnectionParams();
10118   m_sbConnEdit->SetLabel(_("Configure new connection"));
10119 
10120   m_buttonRemove->Hide();//Disable();
10121   m_buttonAdd->Hide(); //Disable();
10122 
10123   SetDSFormRWStates();
10124 
10125   RecalculateSize();
10126 
10127   //  Scroll the panel to allow the user to see more of the NMEA parameter settings area
10128   wxPoint buttonPosition  = m_buttonAdd->GetPosition();
10129   m_pNMEAForm->Scroll(-1, buttonPosition.y / m_scrollRate);
10130 }
10131 
10132 
OnRemoveDatasourceClick(wxCommandEvent & event)10133 void options::OnRemoveDatasourceClick(wxCommandEvent& event) {
10134   if(mSelectedConnection){
10135       // Find the index
10136       int index = -1;
10137       ConnectionParams *cp = NULL;
10138       for (size_t i = 0; i < g_pConnectionParams->Count(); i++){
10139         cp = g_pConnectionParams->Item(i);
10140         if(mSelectedConnection == cp){
10141             index = i;
10142             break;
10143         }
10144       }
10145 
10146       if((index >= 0) && (cp)){
10147         delete g_pConnectionParams->Item(index)->m_optionsPanel;
10148         g_pConnectionParams->RemoveAt(index);
10149 
10150         DataStream* pds_existing = g_pMUX->FindStream(cp->GetDSPort());
10151         if (pds_existing)
10152             g_pMUX->StopAndRemoveStream(pds_existing);
10153         //delete mSelectedConnection->m_optionsPanel;
10154         mSelectedConnection = NULL;
10155       }
10156    }
10157 
10158   //  Mark connection deleted
10159   m_rbTypeSerial->SetValue(TRUE);
10160   m_comboPort->SetValue(_T( "Deleted" ));
10161 
10162   FillSourceList();
10163   ShowNMEACommon(FALSE);
10164   ShowNMEANet(FALSE);
10165   ShowNMEASerial(FALSE);
10166 }
10167 
OnSelectDatasource(wxListEvent & event)10168 void options::OnSelectDatasource(wxListEvent& event) {
10169   SetConnectionParams(g_pConnectionParams->Item(event.GetData()));
10170   m_buttonRemove->Enable();
10171   m_buttonRemove->Show();
10172   event.Skip();
10173 }
10174 
SetSelectedConnectionPanel(ConnectionParamsPanel * panel)10175 void options::SetSelectedConnectionPanel( ConnectionParamsPanel *panel ) {
10176   //  Only one panel can be selected at any time
10177   //  Clear any selections
10178 
10179   if(mSelectedConnection && mSelectedConnection->m_optionsPanel)
10180       mSelectedConnection->m_optionsPanel->SetSelected( false );
10181 
10182   if(panel){
10183     mSelectedConnection = panel->m_pConnectionParams;
10184     panel->SetSelected( true );
10185     SetConnectionParams(mSelectedConnection);
10186     m_buttonRemove->Enable();
10187     m_buttonRemove->Show();
10188     m_buttonAdd->Disable();
10189     m_sbConnEdit->SetLabel(_("Edit Selected Connection"));
10190 
10191   }
10192   else{
10193     mSelectedConnection = NULL;
10194     m_buttonRemove->Disable();
10195     m_buttonAdd->Enable();
10196     m_buttonAdd->Show();
10197     m_sbConnEdit->SetLabel(_T(""));
10198     ClearNMEAForm();
10199   }
10200 
10201 }
10202 
OnDiscoverButton(wxCommandEvent & event)10203 void options::OnDiscoverButton(wxCommandEvent &event){
10204 
10205     wxString ip;
10206     int port;
10207     std::string serviceIdent = std::string("_signalk-ws._tcp.local.");              // Works for node.js server
10208 
10209     g_Platform->ShowBusySpinner();
10210 
10211     if(SignalKDataStream::DiscoverSKServer( serviceIdent, ip, port, 1))               // 1 second scan
10212     {
10213         m_tNetAddress->SetValue( ip);
10214         m_tNetPort->SetValue(wxString::Format(wxT("%i"), port));
10215         UpdateDiscoverStatus(_("Signal K server available."));
10216     }
10217     else{
10218         UpdateDiscoverStatus(_("Signal K server not found."));
10219     }
10220     g_Platform->HideBusySpinner();
10221 
10222 
10223     event.Skip();
10224 }
10225 
UpdateDiscoverStatus(wxString stat)10226 void options::UpdateDiscoverStatus(wxString stat){
10227     m_StaticTextSKServerStatus->SetLabel(stat);
10228 }
10229 
OnBtnIStcs(wxCommandEvent & event)10230 void options::OnBtnIStcs(wxCommandEvent& event) {
10231   const ListType type = m_rbIAccept->GetValue() ? WHITELIST : BLACKLIST;
10232   const wxArrayString list =
10233       wxStringTokenize(m_tcInputStc->GetValue(), _T( "," ));
10234   SentenceListDlg dlg(this, FILTER_INPUT, type, list);
10235 
10236   if (dlg.ShowModal() == wxID_OK) m_tcInputStc->SetValue(dlg.GetSentences());
10237 }
10238 
OnBtnOStcs(wxCommandEvent & event)10239 void options::OnBtnOStcs(wxCommandEvent& event) {
10240   const ListType type = m_rbOAccept->GetValue() ? WHITELIST : BLACKLIST;
10241   const wxArrayString list =
10242       wxStringTokenize(m_tcOutputStc->GetValue(), _T( "," ));
10243   SentenceListDlg dlg(this, FILTER_OUTPUT, type, list);
10244 
10245   if (dlg.ShowModal() == wxID_OK) m_tcOutputStc->SetValue(dlg.GetSentences());
10246 }
10247 
OnNetProtocolSelected(wxCommandEvent & event)10248 void options::OnNetProtocolSelected(wxCommandEvent& event) {
10249   if (m_rbNetProtoGPSD->GetValue()) {
10250     if (m_tNetPort->GetValue().IsEmpty()) m_tNetPort->SetValue(_T( "2947" ));
10251   } else if (m_rbNetProtoUDP->GetValue()) {
10252     if (m_tNetPort->GetValue().IsEmpty()) m_tNetPort->SetValue(_T( "10110" ));
10253     if (m_tNetAddress->GetValue().IsEmpty())
10254       m_tNetAddress->SetValue(_T( "0.0.0.0" ));
10255   } else if (m_rbNetProtoSignalK->GetValue()) {
10256     if (m_tNetPort->GetValue().IsEmpty()) m_tNetPort->SetValue(_T( "8375" ));
10257   } else if (m_rbNetProtoTCP->GetValue()) {
10258     if (m_tNetPort->GetValue().IsEmpty()) m_tNetPort->SetValue(_T( "10110" ));
10259   }
10260 
10261   SetDSFormRWStates();
10262   OnConnValChange(event);
10263 }
10264 
OnRbAcceptInput(wxCommandEvent & event)10265 void options::OnRbAcceptInput(wxCommandEvent& event) { OnConnValChange(event); }
OnRbIgnoreInput(wxCommandEvent & event)10266 void options::OnRbIgnoreInput(wxCommandEvent& event) { OnConnValChange(event); }
10267 
OnRbOutput(wxCommandEvent & event)10268 void options::OnRbOutput(wxCommandEvent& event) { OnConnValChange(event); }
10269 
OnCbInput(wxCommandEvent & event)10270 void options::OnCbInput(wxCommandEvent& event) { OnConnValChange(event); }
10271 
OnCbOutput(wxCommandEvent & event)10272 void options::OnCbOutput(wxCommandEvent& event) {
10273   OnConnValChange(event);
10274   const bool checked = m_cbOutput->IsChecked();
10275   m_stPrecision->Enable(checked);
10276   m_choicePrecision->Enable(checked);
10277   m_stTalkerIdText->Enable(checked);
10278   m_TalkerIdText->Enable(checked);
10279 }
10280 
SentenceListDlg(wxWindow * parent,FilterDirection dir,ListType type,const wxArrayString & list)10281 SentenceListDlg::SentenceListDlg(wxWindow* parent, FilterDirection dir,
10282                                  ListType type, const wxArrayString& list)
10283     : wxDialog(parent, wxID_ANY, _("Sentence Filter"), wxDefaultPosition,
10284                wxSize(280, 420)),
10285       m_type(type),
10286       m_dir(dir),
10287       m_sentences(NMEA0183().GetRecognizedArray()) {
10288   wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
10289   wxBoxSizer* secondSizer = new wxBoxSizer(wxHORIZONTAL);
10290   wxStaticBox* pclbBox = new wxStaticBox(this, wxID_ANY, GetBoxLabel());
10291   wxStaticBoxSizer* stcSizer = new wxStaticBoxSizer(pclbBox, wxVERTICAL);
10292   m_clbSentences = new wxCheckListBox(this, wxID_ANY, wxDefaultPosition,
10293                                       wxDefaultSize, m_sentences);
10294   wxBoxSizer* btnEntrySizer = new wxBoxSizer(wxVERTICAL);
10295   wxButton* btnCheckAll = new wxButton(this, wxID_ANY, _("Select All"));
10296   wxButton* btnClearAll = new wxButton(this, wxID_ANY, _("Clear All"));
10297   wxButton* btnAdd = new wxButton(this, wxID_ANY, _("Add"));
10298   m_btnDel = new wxButton(this, wxID_ANY, _("Delete"));
10299   m_btnDel->Disable();
10300   wxStdDialogButtonSizer* btnSizer = new wxStdDialogButtonSizer();
10301   wxButton* btnOK = new wxButton(this, wxID_OK);
10302   wxButton* btnCancel = new wxButton(this, wxID_CANCEL, _("Cancel"));
10303 
10304   secondSizer->Add(stcSizer, 1, wxALL | wxEXPAND, 5);
10305   stcSizer->Add(m_clbSentences, 1, wxALL | wxEXPAND, 5);
10306   btnEntrySizer->Add(btnCheckAll, 0, wxALL, 5);
10307   btnEntrySizer->Add(btnClearAll, 0, wxALL, 5);
10308   btnEntrySizer->AddSpacer(1);
10309   btnEntrySizer->Add(btnAdd, 0, wxALL, 5);
10310   btnEntrySizer->Add(m_btnDel, 0, wxALL, 5);
10311   secondSizer->Add(btnEntrySizer, 0, wxALL | wxEXPAND, 5);
10312   mainSizer->Add(secondSizer, 1, wxEXPAND, 5);
10313   btnSizer->AddButton(btnOK);
10314   btnSizer->AddButton(btnCancel);
10315   btnSizer->Realize();
10316   mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
10317 
10318   SetSizer(mainSizer);
10319   mainSizer->SetSizeHints(this);
10320   Centre();
10321 
10322   // Connect Events
10323   btnAdd->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
10324                   wxCommandEventHandler(SentenceListDlg::OnAddClick), NULL,
10325                   this);
10326   m_btnDel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
10327                     wxCommandEventHandler(SentenceListDlg::OnDeleteClick), NULL,
10328                     this);
10329   m_clbSentences->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
10330                           wxCommandEventHandler(SentenceListDlg::OnCLBSelect),
10331                           NULL, this);
10332   btnCheckAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
10333                        wxCommandEventHandler(SentenceListDlg::OnCheckAllClick),
10334                        NULL, this);
10335   btnClearAll->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
10336                        wxCommandEventHandler(SentenceListDlg::OnClearAllClick),
10337                        NULL, this);
10338 
10339   Populate(list);
10340 }
10341 
GetBoxLabel(void) const10342 wxString SentenceListDlg::GetBoxLabel(void) const {
10343   if (m_dir == FILTER_OUTPUT)
10344     return m_type == WHITELIST ? _("Transmit sentences") : _("Drop sentences");
10345   else
10346     return m_type == WHITELIST ? _("Accept only sentences") : _("Ignore sentences");
10347 }
10348 
Populate(const wxArrayString & list)10349 void SentenceListDlg::Populate(const wxArrayString& list) {
10350   if (m_dir == FILTER_OUTPUT) {
10351     m_sentences.Add(_T("ECRMB"));
10352     m_sentences.Add(_T("ECRMC"));
10353     m_sentences.Add(_T("ECAPB"));
10354   }
10355   m_sentences.Add(_T("AIVDM"));
10356   m_sentences.Add(_T("AIVDO"));
10357   m_sentences.Add(_T("FRPOS"));
10358   m_sentences.Add(_T("CD"));
10359   m_clbSentences->Clear();
10360   m_clbSentences->InsertItems(m_sentences, 0);
10361 
10362   if (list.Count() == 0) {
10363     for (size_t i = 0; i < m_clbSentences->GetCount(); ++i)
10364       m_clbSentences->Check(i, m_type == WHITELIST);
10365   } else {
10366     m_clbSentences->InsertItems(list, m_sentences.GetCount());
10367     for (size_t i = 0; i < list.Count(); ++i) {
10368       int item = m_clbSentences->FindString(list[i]);
10369       if (item != wxNOT_FOUND) m_clbSentences->Check(item);
10370     }
10371   }
10372 }
10373 
GetSentences(void)10374 wxString SentenceListDlg::GetSentences(void) {
10375   wxArrayString retString;
10376   for (size_t i = 0; i < m_clbSentences->GetCount(); i++) {
10377     if (m_clbSentences->IsChecked(i))
10378       retString.Add(m_clbSentences->GetString(i));
10379   }
10380   return StringArrayToString(retString);
10381 }
10382 
OnCLBSelect(wxCommandEvent & e)10383 void SentenceListDlg::OnCLBSelect(wxCommandEvent& e) {
10384   // Only activate the "Delete" button if the selection is not in the standard
10385   // list
10386   m_btnDel->Enable(m_sentences.Index(e.GetString()) == wxNOT_FOUND);
10387 }
10388 
OnAddClick(wxCommandEvent & event)10389 void SentenceListDlg::OnAddClick(wxCommandEvent& event) {
10390   wxTextEntryDialog textdlg(
10391       this, _("Enter the NMEA sentence (2, 3 or 5 characters) "),
10392       _("Enter the NMEA sentence"));
10393 #if wxCHECK_VERSION(2, 9, 0)
10394   textdlg.SetMaxLength(5);
10395 #endif
10396 
10397   textdlg.SetTextValidator(wxFILTER_ALPHANUMERIC);
10398   if (textdlg.ShowModal() == wxID_CANCEL) return;
10399   wxString stc = textdlg.GetValue();
10400 
10401   if (stc.Length() == 2 || stc.Length() == 3 || stc.Length() == 5) {
10402     m_clbSentences->Append(stc);
10403     m_clbSentences->Check(m_clbSentences->FindString(stc));
10404     return;
10405   }
10406 
10407   OCPNMessageBox(
10408       this,
10409       _("An NMEA sentence is generally 3 characters long (like RMC, GGA etc.)\n \
10410           It can also have a two letter prefix identifying the source, or TALKER, of the message.\n \
10411           The whole sentences then looks like GPGGA or AITXT.\n \
10412           You may filter out all the sentences with certain TALKER prefix (like GP, AI etc.).\n\n \
10413           The filter accepts just these three formats."),
10414       _("OpenCPN Info"));
10415 }
10416 
OnDeleteClick(wxCommandEvent & event)10417 void SentenceListDlg::OnDeleteClick(wxCommandEvent& event) {
10418   m_clbSentences->Delete(event.GetSelection());
10419 }
10420 
OnClearAllClick(wxCommandEvent & event)10421 void SentenceListDlg::OnClearAllClick(wxCommandEvent& event) {
10422   for (size_t i = 0; i < m_clbSentences->GetCount(); i++)
10423     m_clbSentences->Check(i, FALSE);
10424 }
10425 
OnCheckAllClick(wxCommandEvent & event)10426 void SentenceListDlg::OnCheckAllClick(wxCommandEvent& event) {
10427   for (size_t i = 0; i < m_clbSentences->GetCount(); i++)
10428     m_clbSentences->Check(i, TRUE);
10429 }
10430 
10431 // OpenGLOptionsDlg
10432 enum { ID_BUTTON_REBUILD, ID_BUTTON_CLEAR };
10433 
10434 #ifdef ocpnUSE_GL
BEGIN_EVENT_TABLE(OpenGLOptionsDlg,wxDialog)10435 BEGIN_EVENT_TABLE(OpenGLOptionsDlg, wxDialog)
10436 EVT_BUTTON(ID_BUTTON_REBUILD, OpenGLOptionsDlg::OnButtonRebuild)
10437 EVT_BUTTON(ID_BUTTON_CLEAR, OpenGLOptionsDlg::OnButtonClear)
10438 END_EVENT_TABLE()
10439 
10440 OpenGLOptionsDlg::OpenGLOptionsDlg(wxWindow* parent)
10441     : wxDialog(parent, wxID_ANY, _T( "OpenGL Options" ), wxDefaultPosition,
10442                wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER
10443 #ifdef __WXOSX__
10444                                   | wxSTAY_ON_TOP
10445 #endif
10446                ),
10447       m_brebuild_cache(FALSE) {
10448 
10449   wxFont* dialogFont = GetOCPNScaledFont(_("Dialog"));
10450   SetFont(*dialogFont);
10451 
10452   wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
10453   wxFlexGridSizer* flexSizer = new wxFlexGridSizer(2);
10454 
10455   m_cbTextureCompression = new wxCheckBox(
10456       this, wxID_ANY, g_bGLexpert ? _("Texture Compression")
10457                                 : _("Texture Compression with Caching"));
10458   m_cbTextureCompressionCaching =
10459       new wxCheckBox(this, wxID_ANY, _("Texture Compression Caching"));
10460   m_memorySize =
10461       new wxStaticText(this, wxID_ANY, _("Texture Memory Size (MB)"));
10462   m_sTextureMemorySize = new wxSpinCtrl(this);
10463   m_sTextureMemorySize->SetRange(1, 16384);
10464   m_cacheSize =
10465       new wxStaticText(this, wxID_ANY, _("Size: ") + GetTextureCacheSize());
10466   wxButton* btnRebuild =
10467       new wxButton(this, ID_BUTTON_REBUILD, _("Rebuild Texture Cache"));
10468   wxButton* btnClear =
10469       new wxButton(this, ID_BUTTON_CLEAR, _("Clear Texture Cache"));
10470   btnRebuild->Enable(g_GLOptions.m_bTextureCompressionCaching);
10471   if (!g_bopengl || g_raster_format == GL_RGB) btnRebuild->Disable();
10472   btnClear->Enable(g_GLOptions.m_bTextureCompressionCaching);
10473   m_cbShowFPS = new wxCheckBox(this, wxID_ANY, _("Show FPS"));
10474   m_cbPolygonSmoothing = new wxCheckBox(this, wxID_ANY, _("Polygon Smoothing"));
10475   m_cbLineSmoothing = new wxCheckBox(this, wxID_ANY, _("Line Smoothing"));
10476   m_cbSoftwareGL =
10477       new wxCheckBox(this, wxID_ANY, _("Software OpenGL (restart OpenCPN)"));
10478   m_cbUseAcceleratedPanning =
10479       new wxCheckBox(this, wxID_ANY, _("Use Accelerated Panning"));
10480 
10481   flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Texture Settings")), 0,
10482                  wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
10483   flexSizer->Add(m_cbTextureCompression, 0, wxALL | wxEXPAND, 5);
10484   flexSizer->AddSpacer(0);
10485   flexSizer->Add(m_cbTextureCompressionCaching, 0, wxALL | wxEXPAND, 5);
10486   flexSizer->Add(m_memorySize, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
10487   flexSizer->Add(m_sTextureMemorySize, 0, wxALL | wxEXPAND, 5);
10488   flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Texture Cache")), 0,
10489                  wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
10490   flexSizer->Add(m_cacheSize, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, 5);
10491   flexSizer->AddSpacer(0);
10492   flexSizer->Add(btnRebuild, 0, wxALL | wxEXPAND, 5);
10493   flexSizer->AddSpacer(0);
10494   flexSizer->Add(btnClear, 0, wxALL | wxEXPAND, 5);
10495   flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Miscellaneous")), 0,
10496                  wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
10497   flexSizer->Add(m_cbPolygonSmoothing, 0, wxALL | wxEXPAND, 5);
10498   flexSizer->AddSpacer(0);
10499   flexSizer->Add(m_cbLineSmoothing, 0, wxALL | wxEXPAND, 5);
10500   flexSizer->AddSpacer(0);
10501   flexSizer->Add(m_cbShowFPS, 0, wxALL | wxEXPAND, 5);
10502   flexSizer->AddSpacer(0);
10503   flexSizer->Add(m_cbSoftwareGL, 0, wxALL | wxEXPAND, 5);
10504   flexSizer->AddSpacer(0);
10505   flexSizer->Add(m_cbUseAcceleratedPanning, 0, wxALL | wxEXPAND, 5);
10506   flexSizer->AddGrowableCol(1);
10507   mainSizer->Add(flexSizer, 0, wxALL | wxEXPAND, 5);
10508 
10509   wxStdDialogButtonSizer* btnSizer = new wxStdDialogButtonSizer();
10510   btnSizer->AddButton(new wxButton(this, wxID_OK));
10511   btnSizer->AddButton(new wxButton(this, wxID_CANCEL, _("Cancel")));
10512   btnSizer->Realize();
10513 
10514   mainSizer->AddStretchSpacer();
10515   mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
10516 
10517   Populate();
10518 
10519   SetSizer(mainSizer);
10520   mainSizer->SetSizeHints(this);
10521   Centre();
10522 }
10523 
GetAcceleratedPanning(void) const10524 bool OpenGLOptionsDlg::GetAcceleratedPanning(void) const {
10525   return m_cbUseAcceleratedPanning->GetValue();
10526 }
10527 
GetTextureCompression(void) const10528 bool OpenGLOptionsDlg::GetTextureCompression(void) const {
10529   return m_cbTextureCompression->GetValue();
10530 }
10531 
GetPolygonSmoothing(void) const10532 bool OpenGLOptionsDlg::GetPolygonSmoothing(void) const {
10533     return m_cbPolygonSmoothing->GetValue();
10534 }
10535 
GetLineSmoothing(void) const10536 bool OpenGLOptionsDlg::GetLineSmoothing(void) const {
10537     return m_cbLineSmoothing->GetValue();
10538 }
10539 
GetShowFPS(void) const10540 bool OpenGLOptionsDlg::GetShowFPS(void) const {
10541   return m_cbShowFPS->GetValue();
10542 }
10543 
GetSoftwareGL(void) const10544 bool OpenGLOptionsDlg::GetSoftwareGL(void) const {
10545   return m_cbSoftwareGL->GetValue();
10546 }
10547 
GetTextureCompressionCaching(void) const10548 bool OpenGLOptionsDlg::GetTextureCompressionCaching(void) const {
10549   return m_cbTextureCompressionCaching->GetValue();
10550 }
10551 
GetRebuildCache(void) const10552 bool OpenGLOptionsDlg::GetRebuildCache(void) const {
10553   return m_brebuild_cache;
10554 }
10555 
GetTextureMemorySize(void) const10556 int OpenGLOptionsDlg::GetTextureMemorySize(void) const {
10557   return m_sTextureMemorySize->GetValue();
10558 }
10559 
Populate(void)10560 void OpenGLOptionsDlg::Populate(void) {
10561   extern PFNGLCOMPRESSEDTEXIMAGE2DPROC s_glCompressedTexImage2D;
10562   extern bool b_glEntryPointsSet;
10563 
10564   m_cbTextureCompression->SetValue(g_GLOptions.m_bTextureCompression);
10565   /* disable caching if unsupported */
10566   if (b_glEntryPointsSet && !s_glCompressedTexImage2D) {
10567     g_GLOptions.m_bTextureCompressionCaching = FALSE;
10568     m_cbTextureCompression->Disable();
10569     m_cbTextureCompression->SetValue(FALSE);
10570   }
10571 
10572   m_cbTextureCompressionCaching->Show(g_bGLexpert);
10573   m_memorySize->Show(g_bGLexpert);
10574   m_sTextureMemorySize->Show(g_bGLexpert);
10575   if (g_bGLexpert) {
10576     m_cbTextureCompressionCaching->SetValue(
10577         g_GLOptions.m_bTextureCompressionCaching);
10578     m_sTextureMemorySize->SetValue(g_GLOptions.m_iTextureMemorySize);
10579   }
10580   m_cbShowFPS->SetValue(g_bShowFPS);
10581   m_cbPolygonSmoothing->SetValue(g_GLOptions.m_GLPolygonSmoothing);
10582   m_cbLineSmoothing->SetValue(g_GLOptions.m_GLLineSmoothing);
10583 
10584 #if defined(__UNIX__) && !defined(__OCPN__ANDROID__) && !defined(__WXOSX__)
10585   if (gFrame->GetPrimaryCanvas()->GetglCanvas()){
10586       if(gFrame->GetPrimaryCanvas()->GetglCanvas()->GetVersionString().Upper().Find(_T( "MESA" )) !=  wxNOT_FOUND)
10587         m_cbSoftwareGL->SetValue(g_bSoftwareGL);
10588   }
10589 #else
10590   m_cbSoftwareGL->Hide();
10591 #endif
10592 
10593   wxFont* dialogFont = GetOCPNScaledFont(_("Dialog"));
10594   SetFont(*dialogFont);
10595 
10596   if (g_bGLexpert) {
10597       if (gFrame->GetPrimaryCanvas()->GetglCanvas()){
10598           if(gFrame->GetPrimaryCanvas()->GetglCanvas()->CanAcceleratePanning()) {
10599             m_cbUseAcceleratedPanning->Enable();
10600             m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
10601           } else {
10602             m_cbUseAcceleratedPanning->SetValue(FALSE);
10603             m_cbUseAcceleratedPanning->Disable();
10604           }
10605       } else {
10606           m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
10607       }
10608   } else {
10609     m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
10610     m_cbUseAcceleratedPanning->Disable();
10611   }
10612 }
10613 
OnButtonRebuild(wxCommandEvent & event)10614 void OpenGLOptionsDlg::OnButtonRebuild(wxCommandEvent& event) {
10615   if (g_GLOptions.m_bTextureCompressionCaching) {
10616     m_brebuild_cache = TRUE;
10617     EndModal(wxID_CANCEL);
10618   }
10619 }
10620 
OnButtonClear(wxCommandEvent & event)10621 void OpenGLOptionsDlg::OnButtonClear(wxCommandEvent& event) {
10622 
10623   if (g_bopengl && g_glTextureManager){
10624       ::wxBeginBusyCursor();
10625       g_glTextureManager->ClearAllRasterTextures();
10626 
10627       wxString path = g_Platform->GetPrivateDataDir();
10628       appendOSDirSlash(&path);
10629       path.append(_T("raster_texture_cache"));
10630 
10631       if (::wxDirExists(path)) {
10632           wxArrayString files;
10633           size_t nfiles = wxDir::GetAllFiles(path, &files);
10634           for (unsigned int i = 0; i < files.GetCount(); i++)
10635             ::wxRemoveFile(files[i]);
10636       }
10637 
10638       m_cacheSize->SetLabel(_("Size: ") + GetTextureCacheSize());
10639       ::wxEndBusyCursor();
10640   }
10641 }
10642 
GetTextureCacheSize(void)10643 wxString OpenGLOptionsDlg::GetTextureCacheSize(void) {
10644   wxString path = g_Platform->GetPrivateDataDir();
10645   appendOSDirSlash(&path);
10646   path.append(_T("raster_texture_cache"));
10647   long long total = 0;
10648 
10649   if (::wxDirExists(path)) {
10650     wxArrayString files;
10651     size_t nfiles = wxDir::GetAllFiles(path, &files);
10652     for (unsigned int i = 0; i < files.GetCount(); i++)
10653       total += wxFile(files[i]).Length();
10654   }
10655   double mb = total / (1024.0 * 1024.0);
10656   if (mb < 10000.0) return wxString::Format(_T( "%.1f MB" ), mb);
10657   mb = mb / 1024.0;
10658   return wxString::Format(_T( "%.1f GB" ), mb);
10659 }
10660 
10661 
10662 //-------------------------------------------------------------------------------------------------
10663 //  CanvasConfig selection panel
10664 //-------------------------------------------------------------------------------------------------
10665 
BEGIN_EVENT_TABLE(CanvasConfigSelect,wxPanel)10666 BEGIN_EVENT_TABLE(CanvasConfigSelect, wxPanel)
10667 EVT_PAINT ( CanvasConfigSelect::OnPaint )
10668 END_EVENT_TABLE()
10669 
10670 CanvasConfigSelect::CanvasConfigSelect(wxWindow *parent, options *parentOptions, wxWindowID id, wxBitmap &bmp, const wxPoint &pos, const wxSize &size)
10671 :wxPanel(parent, id, pos, size, wxBORDER_NONE)
10672 {
10673     m_parentOptions = parentOptions;
10674     m_bmpNormal = bmp;
10675     m_borderWidth = 5;
10676     SetSelected(false);
10677 
10678     int refHeight = GetCharHeight();
10679     //SetMinSize(wxSize(-1, 5 * refHeight));
10680     SetMinSize(wxSize(bmp.GetSize().x + m_borderWidth * 2, bmp.GetSize().y + m_borderWidth * 2));
10681 
10682     Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CanvasConfigSelect::OnMouseSelected), NULL, this);
10683 }
10684 
~CanvasConfigSelect()10685 CanvasConfigSelect::~CanvasConfigSelect()
10686 {
10687 }
10688 
OnMouseSelected(wxMouseEvent & event)10689 void CanvasConfigSelect::OnMouseSelected( wxMouseEvent &event )
10690 {
10691     if(!m_bSelected){
10692         SetSelected( true );
10693     }
10694     else{
10695         SetSelected( false );
10696     }
10697     if(m_parentOptions)
10698         m_parentOptions->OnCanvasConfigSelectClick( GetId(), GetSelected());
10699 
10700 }
10701 
SetSelected(bool selected)10702 void CanvasConfigSelect::SetSelected( bool selected )
10703 {
10704     m_bSelected = selected;
10705     wxColour colour;
10706 
10707     if (selected)
10708     {
10709         GetGlobalColor(_T("UIBCK"), &colour);
10710         m_boxColour = colour;
10711     }
10712     else
10713     {
10714         GetGlobalColor(_T("DILG0"), &colour);
10715         m_boxColour = colour;
10716     }
10717 
10718     Refresh( true );
10719 
10720 }
10721 
OnPaint(wxPaintEvent & event)10722 void CanvasConfigSelect::OnPaint( wxPaintEvent &event )
10723 {
10724     int width, height;
10725     GetSize( &width, &height );
10726     wxPaintDC dc( this );
10727 
10728     dc.SetBackground(*wxLIGHT_GREY);
10729 
10730     dc.SetPen(*wxTRANSPARENT_PEN);
10731     dc.SetBrush(wxBrush(GetBackgroundColour()));
10732     dc.DrawRectangle(GetVirtualSize());
10733 
10734     wxColour c;
10735 
10736     if(m_bSelected){
10737         dc.SetBrush( wxBrush( m_boxColour ) );
10738 
10739         GetGlobalColor( _T ( "UITX1" ), &c );
10740         dc.SetPen( wxPen( wxColor(0xCE, 0xD5, 0xD6), 3 ));
10741 
10742         dc.DrawRoundedRectangle( 0, 0, width-1, height-1, height / 10);
10743     }
10744     else {
10745         dc.SetBrush( wxBrush( m_boxColour ) );
10746 
10747         GetGlobalColor( _T ( "UITX1" ), &c );
10748         dc.SetPen( wxPen( wxColor(0xCE, 0xD5, 0xD6), 3 ));
10749 
10750         dc.DrawRoundedRectangle( 0, 0, width-1, height-1, height / 10);
10751     }
10752 
10753     dc.DrawBitmap(m_bmpNormal, m_borderWidth, m_borderWidth, false);
10754 }
10755 
10756 #endif  // ocpnUSE_GL
10757