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