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