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