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