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