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