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