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