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