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