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