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