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