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