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