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 "observable/evtvar.h"
83#include "o_sound/o_sound.h"
84
85#include "model/ais_decoder.h"
88#include "model/cmdline.h"
90#include "model/comm_util.h"
91#include "model/config_vars.h"
92#include "model/gui_events.h"
93#include "model/gui_vars.h"
94#include "model/idents.h"
95#include "model/multiplexer.h"
96#include "model/navutil_base.h"
97#include "model/own_ship.h"
98#include "model/routeman.h"
99#include "model/ser_ports.h"
100#include "model/svg_utils.h"
101
102#include "ais.h"
103#include "chart_ctx_factory.h"
104#include "chartdbs.h"
105#include "chcanv.h"
106#include "cm93.h"
107#include "config_mgr.h"
108#include "conn_params_panel.h"
109#include "connections_dlg.h"
110#include "displays.h"
111#include "dychart.h"
112#include "font_mgr.h"
113#include "mark_info.h"
114#include "navutil.h"
115#include "ocpn_platform.h"
116#include "options.h"
117#include "s52plib.h"
118#include "s52utils.h"
119#include "s57_load.h"
120#include "styles.h"
121#include "top_frame.h"
122#include "usb_devices.h"
123#include "waypointman_gui.h"
124
125#ifdef ocpnUSE_GL
126#include "gl_chart_canvas.h"
127extern GLuint g_raster_format;
128#endif
129
130// Centralized tooltip strings to avoid duplication. Keep translatable.
131static inline wxString ttDistance() {
132 return _(
133 "Horizontal measurements and distances. Examples: Distance between "
134 "geographic positions, visibility range, radar range.");
135}
136static inline wxString ttSpeed() {
137 return _("Vessel and surface speed measurements");
138}
139static inline wxString ttWindSpeed() {
140 return _("Wind speed measurements and forecasts");
141}
142static inline wxString ttDepth() {
143 return _("Measurements below the water surface");
144}
145static inline wxString ttHeight() {
146 return _(
147 "Vertical measurements above reference datum. Examples: Tide level, wave "
148 "height, air gap, mast clearance, elevation above reference datum.");
149}
150static inline wxString ttTemp() {
151 return _("Temperature measurements (air, water, engine)");
152}
153static inline wxString ttCoordFormat() {
154 return _("Coordinate display format for latitude and longitude");
155}
156
157#ifdef __linux__
158#include "udev_rule_mgr.h"
159#endif
160
161#ifdef __ANDROID__
162#include "androidUTIL.h"
163#endif
164
165#ifdef __ANDROID__
166#include <QtWidgets/QScroller>
167#endif
168
169#ifdef __WXOSX__
170#if wxCHECK_VERSION(3, 2, 0)
171#define SLIDER_STYLE wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS
172#else
173#define SLIDER_STYLE wxSL_HORIZONTAL | wxSL_AUTOTICKS
174#endif
175#else
176#define SLIDER_STYLE wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS
177#endif
178
179#define ID_CHOICE_NMEA wxID_HIGHEST + 1
180
181options* g_options; // global instance
182options* g_pOptions; // Duplicate to be removed FIXME (leamas)
183
184#if wxUSE_XLOCALE
185extern wxLocale* plocale_def_lang;
186#endif
187
188#ifdef ocpnUSE_GL
189extern ocpnGLOptions g_GLOptions;
190#endif
191
192#ifdef __ANDROID__
193extern int g_Android_SDK_Version;
194extern MigrateAssistantDialog* g_migrateDialog;
195#endif
196
197static wxString GetOCPNKnownLanguage(const wxString lang_canonical,
198 wxString& lang_dir);
199static wxString GetOCPNKnownLanguage(const wxString lang_canonical);
200
201#if wxUSE_XLOCALE
202static int lang_list[] = {
203 wxLANGUAGE_DEFAULT, wxLANGUAGE_ABKHAZIAN, wxLANGUAGE_AFAR,
204 wxLANGUAGE_AFRIKAANS, wxLANGUAGE_ALBANIAN, wxLANGUAGE_AMHARIC,
205 wxLANGUAGE_ARABIC, wxLANGUAGE_ARABIC_ALGERIA, wxLANGUAGE_ARABIC_BAHRAIN,
206 wxLANGUAGE_ARABIC_EGYPT, wxLANGUAGE_ARABIC_IRAQ, wxLANGUAGE_ARABIC_JORDAN,
207 wxLANGUAGE_ARABIC_KUWAIT, wxLANGUAGE_ARABIC_LEBANON,
208 wxLANGUAGE_ARABIC_LIBYA, wxLANGUAGE_ARABIC_MOROCCO, wxLANGUAGE_ARABIC_OMAN,
209 wxLANGUAGE_ARABIC_QATAR, wxLANGUAGE_ARABIC_SAUDI_ARABIA,
210 wxLANGUAGE_ARABIC_SUDAN, wxLANGUAGE_ARABIC_SYRIA, wxLANGUAGE_ARABIC_TUNISIA,
211 // wxLANGUAGE_ARABIC_UAE,
212 wxLANGUAGE_ARABIC_YEMEN, wxLANGUAGE_ARMENIAN, wxLANGUAGE_ASSAMESE,
213 wxLANGUAGE_AYMARA, wxLANGUAGE_AZERI, wxLANGUAGE_AZERI_CYRILLIC,
214 wxLANGUAGE_AZERI_LATIN, wxLANGUAGE_BASHKIR, wxLANGUAGE_BASQUE,
215 wxLANGUAGE_BELARUSIAN, wxLANGUAGE_BENGALI, wxLANGUAGE_BHUTANI,
216 wxLANGUAGE_BIHARI, wxLANGUAGE_BISLAMA, wxLANGUAGE_BRETON,
217 wxLANGUAGE_BULGARIAN, wxLANGUAGE_BURMESE, wxLANGUAGE_CAMBODIAN,
218 wxLANGUAGE_CATALAN,
219 // wxLANGUAGE_CHINESE,
220 // wxLANGUAGE_CHINESE_SIMPLIFIED,
221 // wxLANGUAGE_CHINESE_TRADITIONAL,
222 // wxLANGUAGE_CHINESE_HONGKONG,
223 // wxLANGUAGE_CHINESE_MACAU,
224 // wxLANGUAGE_CHINESE_SINGAPORE,
225 wxLANGUAGE_CHINESE_TAIWAN, wxLANGUAGE_CORSICAN, wxLANGUAGE_CROATIAN,
226 wxLANGUAGE_CZECH, wxLANGUAGE_DANISH, wxLANGUAGE_DUTCH,
227 wxLANGUAGE_DUTCH_BELGIAN, wxLANGUAGE_ENGLISH_UK, wxLANGUAGE_ENGLISH_US,
228 wxLANGUAGE_ENGLISH_AUSTRALIA, wxLANGUAGE_ENGLISH_BELIZE,
229 wxLANGUAGE_ENGLISH_BOTSWANA, wxLANGUAGE_ENGLISH_CANADA,
230 wxLANGUAGE_ENGLISH_CARIBBEAN, wxLANGUAGE_ENGLISH_DENMARK,
231 wxLANGUAGE_ENGLISH_EIRE, wxLANGUAGE_ENGLISH_JAMAICA,
232 wxLANGUAGE_ENGLISH_NEW_ZEALAND, wxLANGUAGE_ENGLISH_PHILIPPINES,
233 wxLANGUAGE_ENGLISH_SOUTH_AFRICA, wxLANGUAGE_ENGLISH_TRINIDAD,
234 wxLANGUAGE_ENGLISH_ZIMBABWE, wxLANGUAGE_ESPERANTO, wxLANGUAGE_ESTONIAN,
235 wxLANGUAGE_FAEROESE, wxLANGUAGE_FARSI, wxLANGUAGE_FIJI, wxLANGUAGE_FINNISH,
236 wxLANGUAGE_FRENCH, wxLANGUAGE_FRENCH_BELGIAN, wxLANGUAGE_FRENCH_CANADIAN,
237 wxLANGUAGE_FRENCH_LUXEMBOURG, wxLANGUAGE_FRENCH_MONACO,
238 wxLANGUAGE_FRENCH_SWISS, wxLANGUAGE_FRISIAN, wxLANGUAGE_GALICIAN,
239 wxLANGUAGE_GEORGIAN, wxLANGUAGE_GERMAN, wxLANGUAGE_GERMAN_AUSTRIAN,
240 wxLANGUAGE_GERMAN_BELGIUM, wxLANGUAGE_GERMAN_LIECHTENSTEIN,
241 wxLANGUAGE_GERMAN_LUXEMBOURG, wxLANGUAGE_GERMAN_SWISS, wxLANGUAGE_GREEK,
242 wxLANGUAGE_GREENLANDIC, wxLANGUAGE_GUARANI, wxLANGUAGE_GUJARATI,
243 wxLANGUAGE_HAUSA, wxLANGUAGE_HEBREW, wxLANGUAGE_HINDI, wxLANGUAGE_HUNGARIAN,
244 wxLANGUAGE_ICELANDIC, wxLANGUAGE_INDONESIAN, wxLANGUAGE_INTERLINGUA,
245 wxLANGUAGE_INTERLINGUE, wxLANGUAGE_INUKTITUT, wxLANGUAGE_INUPIAK,
246 wxLANGUAGE_IRISH, wxLANGUAGE_ITALIAN, wxLANGUAGE_ITALIAN_SWISS,
247 wxLANGUAGE_JAPANESE, wxLANGUAGE_JAVANESE, wxLANGUAGE_KANNADA,
248 wxLANGUAGE_KASHMIRI, wxLANGUAGE_KASHMIRI_INDIA, wxLANGUAGE_KAZAKH,
249 wxLANGUAGE_KERNEWEK, wxLANGUAGE_KINYARWANDA, wxLANGUAGE_KIRGHIZ,
250 wxLANGUAGE_KIRUNDI,
251 // wxLANGUAGE_KONKANI,
252 wxLANGUAGE_KOREAN, wxLANGUAGE_KURDISH, wxLANGUAGE_LAOTHIAN,
253 wxLANGUAGE_LATIN, wxLANGUAGE_LATVIAN, wxLANGUAGE_LINGALA,
254 wxLANGUAGE_LITHUANIAN, wxLANGUAGE_MACEDONIAN, wxLANGUAGE_MALAGASY,
255 wxLANGUAGE_MALAY, wxLANGUAGE_MALAYALAM, wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM,
256 wxLANGUAGE_MALAY_MALAYSIA, wxLANGUAGE_MALTESE,
257 // wxLANGUAGE_MANIPURI,
258 wxLANGUAGE_MAORI, wxLANGUAGE_MARATHI, wxLANGUAGE_MOLDAVIAN,
259 wxLANGUAGE_MONGOLIAN, wxLANGUAGE_NAURU, wxLANGUAGE_NEPALI,
260 wxLANGUAGE_NEPALI_INDIA, wxLANGUAGE_NORWEGIAN_BOKMAL,
261 wxLANGUAGE_NORWEGIAN_NYNORSK, wxLANGUAGE_OCCITAN, wxLANGUAGE_ORIYA,
262 wxLANGUAGE_OROMO, wxLANGUAGE_PASHTO, wxLANGUAGE_POLISH,
263 wxLANGUAGE_PORTUGUESE, wxLANGUAGE_PORTUGUESE_BRAZILIAN, wxLANGUAGE_PUNJABI,
264 wxLANGUAGE_QUECHUA, wxLANGUAGE_RHAETO_ROMANCE, wxLANGUAGE_ROMANIAN,
265 wxLANGUAGE_RUSSIAN, wxLANGUAGE_RUSSIAN_UKRAINE, wxLANGUAGE_SAMOAN,
266 wxLANGUAGE_SANGHO, wxLANGUAGE_SANSKRIT, wxLANGUAGE_SCOTS_GAELIC,
267 wxLANGUAGE_SERBIAN, wxLANGUAGE_SERBIAN_CYRILLIC, wxLANGUAGE_SERBIAN_LATIN,
268 wxLANGUAGE_SERBO_CROATIAN, wxLANGUAGE_SESOTHO, wxLANGUAGE_SETSWANA,
269 wxLANGUAGE_SHONA, wxLANGUAGE_SINDHI, wxLANGUAGE_SINHALESE,
270 wxLANGUAGE_SISWATI, wxLANGUAGE_SLOVAK, wxLANGUAGE_SLOVENIAN,
271 wxLANGUAGE_SOMALI, wxLANGUAGE_SPANISH, wxLANGUAGE_SPANISH_ARGENTINA,
272 wxLANGUAGE_SPANISH_BOLIVIA, wxLANGUAGE_SPANISH_CHILE,
273 wxLANGUAGE_SPANISH_COLOMBIA, wxLANGUAGE_SPANISH_COSTA_RICA,
274 wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, wxLANGUAGE_SPANISH_ECUADOR,
275 wxLANGUAGE_SPANISH_EL_SALVADOR, wxLANGUAGE_SPANISH_GUATEMALA,
276 wxLANGUAGE_SPANISH_HONDURAS, wxLANGUAGE_SPANISH_MEXICAN,
277 // wxLANGUAGE_SPANISH_MODERN,
278 wxLANGUAGE_SPANISH_NICARAGUA, wxLANGUAGE_SPANISH_PANAMA,
279 wxLANGUAGE_SPANISH_PARAGUAY, wxLANGUAGE_SPANISH_PERU,
280 wxLANGUAGE_SPANISH_PUERTO_RICO, wxLANGUAGE_SPANISH_URUGUAY,
281 wxLANGUAGE_SPANISH_US, wxLANGUAGE_SPANISH_VENEZUELA, wxLANGUAGE_SUNDANESE,
282 wxLANGUAGE_SWAHILI, wxLANGUAGE_SWEDISH, wxLANGUAGE_SWEDISH_FINLAND,
283 wxLANGUAGE_TAGALOG, wxLANGUAGE_TAJIK, wxLANGUAGE_TAMIL, wxLANGUAGE_TATAR,
284 wxLANGUAGE_TELUGU, wxLANGUAGE_THAI, wxLANGUAGE_TIBETAN, wxLANGUAGE_TIGRINYA,
285 wxLANGUAGE_TONGA, wxLANGUAGE_TSONGA, wxLANGUAGE_TURKISH, wxLANGUAGE_TURKMEN,
286 wxLANGUAGE_TWI, wxLANGUAGE_UIGHUR, wxLANGUAGE_UKRAINIAN, wxLANGUAGE_URDU,
287 wxLANGUAGE_URDU_INDIA, wxLANGUAGE_URDU_PAKISTAN, wxLANGUAGE_UZBEK,
288 wxLANGUAGE_UZBEK_CYRILLIC, wxLANGUAGE_UZBEK_LATIN, wxLANGUAGE_VIETNAMESE,
289 wxLANGUAGE_VOLAPUK, wxLANGUAGE_WELSH, wxLANGUAGE_WOLOF, wxLANGUAGE_XHOSA,
290 wxLANGUAGE_YIDDISH, wxLANGUAGE_YORUBA, wxLANGUAGE_ZHUANG, wxLANGUAGE_ZULU};
291#endif
292
293#ifdef __ANDROID__
294void prepareSlider(wxSlider* slider) {
295 slider->GetHandle()->setStyleSheet(
296 prepareAndroidSliderStyleSheet(slider->GetSize().x));
297 slider->GetHandle()->setAttribute(Qt::WA_AcceptTouchEvents);
298 slider->GetHandle()->grabGesture(Qt::PanGesture);
299 slider->GetHandle()->grabGesture(Qt::SwipeGesture);
300}
301#endif
302
304
305class ChartDirPanelHardBreakWrapper : public wxTextWrapper {
306public:
307 ChartDirPanelHardBreakWrapper(wxWindow* win, const wxString& text,
308 int widthMax) {
309 m_lineCount = 0;
310
311 // Replace all spaces in the string with a token character '^'
312 wxString textMod = text;
313 textMod.Replace(" ", "^");
314
315 // Replace all path separators with spaces
316 wxString sep = wxFileName::GetPathSeparator();
317 textMod.Replace(sep, " ");
318
319 Wrap(win, textMod, widthMax);
320
321 // walk the output array, repairing the substitutions
322 for (size_t i = 0; i < m_array.GetCount(); i++) {
323 wxString a = m_array[i];
324 a.Replace(" ", sep);
325 if (m_array.GetCount() > 1) {
326 if (i < m_array.GetCount() - 1) a += sep;
327 }
328 a.Replace("^", " ");
329 m_array[i] = a;
330 }
331 }
332 wxString const& GetWrapped() const { return m_wrapped; }
333 int const GetLineCount() const { return m_lineCount; }
334 wxArrayString GetLineArray() { return m_array; }
335
336protected:
337 virtual void OnOutputLine(const wxString& line) {
338 m_wrapped += line;
339 m_array.Add(line);
340 }
341 virtual void OnNewLine() {
342 m_wrapped += '\n';
343 m_lineCount++;
344 }
345
346private:
347 wxString m_wrapped;
348 int m_lineCount;
349 wxArrayString m_array;
350};
351
352class OCPNChartDirPanel : public wxPanel {
353public:
354 OCPNChartDirPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos,
355 const wxSize& size, ChartDirInfo& cdi);
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 obs::GlobalVar<wxString> compat_os(&g_compatOS);
1463 compat_os_listener.Listen(compat_os, this, EVT_COMPAT_OS_CHANGE);
1464 Bind(EVT_COMPAT_OS_CHANGE, [&](wxCommandEvent&) {
1465 PluginLoader::GetInstance()->LoadAllPlugIns(false);
1466 m_pPlugInCtrl->ReloadPluginPanels();
1467 });
1468 auto action = [&](wxCommandEvent& evt) {
1469 g_persist_active_route = m_persist_active_route_chkbox->IsChecked();
1470 };
1471 m_persist_active_route_chkbox->Bind(wxEVT_CHECKBOX, action);
1472 m_persist_active_route_chkbox->SetValue(g_persist_active_route);
1473
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 obs::Listener 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 pHiconColors = new wxCheckBox(itemPanelFont, ID_HICONCOLORS,
5690 _("Use High Contrast Chart Colors"));
5691 miscOptions->Add(pHiconColors, 0, wxALL, border_size);
5692
5693 pInlandEcdis =
5694 new wxCheckBox(itemPanelFont, ID_INLANDECDISBOX, _("Use Inland ECDIS"));
5695 miscOptions->Add(pInlandEcdis, 0, wxALL, border_size);
5696
5697 wxButton* itemEcdisHelp =
5698 new wxButton(itemPanelFont, ID_BUTTONECDISHELP, _("Inland ECDIS Manual"),
5699 wxDefaultPosition, wxDefaultSize, 0);
5700 miscOptions->Add(itemEcdisHelp, 0, wxALL, border_size);
5701
5702#ifdef __ANDROID__
5703 pInlandEcdis->Hide();
5704 itemEcdisHelp->Hide();
5705#endif
5706
5707 miscOptions->AddSpacer(10);
5708
5709 wxFlexGridSizer* sliderSizer;
5710 sliderSizer = new wxFlexGridSizer(0, 2, 0, 0);
5711 sliderSizer->AddGrowableCol(1);
5712 sliderSizer->SetFlexibleDirection(wxBOTH);
5713 sliderSizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
5714
5715 m_pSlider_GUI_Factor =
5716 new wxSlider(itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,
5717 m_sliderSize, SLIDER_STYLE);
5718 m_pSlider_GUI_Factor->Hide();
5719 sliderSizer->Add(new wxStaticText(itemPanelFont, wxID_ANY,
5720 _("User Interface scale factor")),
5721 inputFlags);
5722 sliderSizer->Add(m_pSlider_GUI_Factor, 0, wxALL, border_size);
5723 m_pSlider_GUI_Factor->Show();
5724
5725#ifdef __ANDROID__
5726 prepareSlider(m_pSlider_GUI_Factor);
5727#endif
5728
5729 m_pSlider_Chart_Factor =
5730 new wxSlider(itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,
5731 m_sliderSize, SLIDER_STYLE);
5732 m_pSlider_Chart_Factor->Hide();
5733 sliderSizer->Add(
5734 new wxStaticText(itemPanelFont, wxID_ANY, _("Chart Object scale factor")),
5735 inputFlags);
5736 sliderSizer->Add(m_pSlider_Chart_Factor, 0, wxALL, border_size);
5737 m_pSlider_Chart_Factor->Show();
5738
5739#ifdef __ANDROID__
5740 prepareSlider(m_pSlider_Chart_Factor);
5741#endif
5742
5743 m_pSlider_Ship_Factor =
5744 new wxSlider(itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,
5745 m_sliderSize, SLIDER_STYLE);
5746 m_pSlider_Ship_Factor->Hide();
5747 sliderSizer->Add(
5748 new wxStaticText(itemPanelFont, wxID_ANY, _("Ship scale factor")),
5749 inputFlags);
5750 sliderSizer->Add(m_pSlider_Ship_Factor, 0, wxALL, border_size);
5751 m_pSlider_Ship_Factor->Show();
5752
5753#ifdef __ANDROID__
5754 m_pSlider_Ship_Factor->GetHandle()->setStyleSheet(getQtStyleSheet());
5755#endif
5756
5757 m_pSlider_Text_Factor =
5758 new wxSlider(itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,
5759 m_sliderSize, SLIDER_STYLE);
5760 m_pSlider_Text_Factor->Hide();
5761 sliderSizer->Add(
5762 new wxStaticText(itemPanelFont, wxID_ANY, _("ENC Sounding factor")),
5763 inputFlags);
5764 sliderSizer->Add(m_pSlider_Text_Factor, 0, wxALL, border_size);
5765 m_pSlider_Text_Factor->Show();
5766
5767#ifdef __ANDROID__
5768 m_pSlider_Text_Factor->GetHandle()->setStyleSheet(getQtStyleSheet());
5769#endif
5770
5771 m_pSlider_ENCText_Factor =
5772 new wxSlider(itemPanelFont, wxID_ANY, 0, -5, 5, wxDefaultPosition,
5773 m_sliderSize, SLIDER_STYLE);
5774 m_pSlider_ENCText_Factor->Hide();
5775 sliderSizer->Add(
5776 new wxStaticText(itemPanelFont, wxID_ANY, _("ENC Text Scale")),
5777 inputFlags);
5778 sliderSizer->Add(m_pSlider_ENCText_Factor, 0, wxALL, border_size);
5779 m_pSlider_ENCText_Factor->Show();
5780
5781#ifdef __ANDROID__
5782 m_pSlider_ENCText_Factor->GetHandle()->setStyleSheet(getQtStyleSheet());
5783#endif
5784
5785 sliderSizer->Add(new wxStaticText(itemPanelFont, wxID_ANY,
5786 _("Mouse wheel zoom sensitivity")),
5787 inputFlags);
5788 m_pMouse_Zoom_Slider = new MouseZoomSlider(itemPanelFont, m_sliderSize);
5789 sliderSizer->Add(m_pMouse_Zoom_Slider, 0, wxALL, border_size);
5790
5791 miscOptions->Add(sliderSizer, 0, wxEXPAND, 5);
5792 miscOptions->AddSpacer(20);
5793}
5794
5795void options::OnResetFont(wxCommandEvent& event) {
5796 wxString itemElement;
5797 int i = m_itemFontElementListBox->GetSelection();
5798 if (i >= 0) {
5799 itemElement = m_itemFontElementListBox->GetString(i);
5800
5801 if (FontMgr::Get().ResetFontToDefault(itemElement)) {
5802 // Update the sample text with new default font
5803 wxFont* pFont = FontMgr::Get().GetFont(itemElement);
5804 wxColour colour = FontMgr::Get().GetFontColor(itemElement);
5805
5806 if (pFont) {
5807 m_textSample->SetFont(*pFont);
5808 m_textSample->SetForegroundColour(colour);
5809 m_textSample->Refresh();
5810 }
5811 // Force immediate update of UI elements
5812 top_frame::Get()->UpdateAllFonts();
5813 m_bfontChanged = true;
5814 OnFontChoice(event);
5815 }
5816 }
5817}
5818
5819void options::OnAlertEnableButtonClick(wxCommandEvent& event) {
5820 m_pCheck_AlertAudio->Enable(event.IsChecked());
5821 if (!event.IsChecked()) m_pCheck_AlertAudio->SetValue(false);
5822}
5823
5824void options::OnAlertAudioEnableButtonClick(wxCommandEvent& event) {
5825 if (event.IsChecked()) {
5826 m_soundPanelAIS->GetCheckBox()->SetValue(true);
5827 m_soundPanelSART->GetCheckBox()->SetValue(true);
5828 m_soundPanelDSC->GetCheckBox()->SetValue(true);
5829 }
5830}
5831
5832void options::CreateListbookIcons() {
5833 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
5834
5835 if (!g_bresponsive) {
5836 int sx = 40;
5837 int sy = 40;
5838 m_topImgList = new wxImageList(sx, sy, TRUE, 0);
5839
5840#if wxCHECK_VERSION(2, 8, 12)
5841 m_topImgList->Add(style->GetIcon("Display", sx, sy));
5842 m_topImgList->Add(style->GetIcon("Charts", sx, sy));
5843 m_topImgList->Add(style->GetIcon("Connections", sx, sy));
5844 m_topImgList->Add(style->GetIcon("Ship", sx, sy));
5845 m_topImgList->Add(style->GetIcon("UI", sx, sy));
5846 m_topImgList->Add(style->GetIcon("Plugins", sx, sy));
5847#else
5848 wxBitmap bmp;
5849 wxImage img;
5850 bmp = style->GetIcon("Display");
5851 img = bmp.ConvertToImage();
5852 img.ConvertAlphaToMask(128);
5853 bmp = wxBitmap(img);
5854 m_topImgList->Add(bmp);
5855 bmp = style->GetIcon("Charts");
5856 img = bmp.ConvertToImage();
5857 img.ConvertAlphaToMask(128);
5858 bmp = wxBitmap(img);
5859 m_topImgList->Add(bmp);
5860 bmp = style->GetIcon("Connections");
5861 img = bmp.ConvertToImage();
5862 img.ConvertAlphaToMask(128);
5863 bmp = wxBitmap(img);
5864 m_topImgList->Add(bmp);
5865 bmp = style->GetIcon("Ship");
5866 img = bmp.ConvertToImage();
5867 img.ConvertAlphaToMask(128);
5868 bmp = wxBitmap(img);
5869 m_topImgList->Add(bmp);
5870 bmp = style->GetIcon("UI");
5871 img = bmp.ConvertToImage();
5872 img.ConvertAlphaToMask(128);
5873 bmp = wxBitmap(img);
5874 m_topImgList->Add(bmp);
5875 bmp = style->GetIcon("Plugins");
5876 img = bmp.ConvertToImage();
5877 img.ConvertAlphaToMask(128);
5878 bmp = wxBitmap(img);
5879 m_topImgList->Add(bmp);
5880#endif
5881 } else {
5882 wxBitmap bmps;
5883 bmps = style->GetIcon("Display");
5884 int base_size = bmps.GetWidth();
5885 double tool_size = base_size;
5886
5887 double premult = 1.0;
5888
5889 // unless overridden by user, we declare the "best" size
5890 // to be roughly 6 mm square.
5891 double target_size = 6.0; // mm
5892
5893 double basic_tool_size_mm = tool_size / g_Platform->GetDisplayDPmm();
5894 premult = target_size / basic_tool_size_mm;
5895
5896 // Adjust the scale factor using the global GUI scale parameter
5897 double postmult = exp(g_GUIScaleFactor * (0.693 / 5.0)); // exp(2)
5898 postmult = wxMin(postmult, 3.0);
5899 postmult = wxMax(postmult, 1.0);
5900
5901 int sizeTab = base_size * postmult * premult;
5902
5903 m_topImgList = new wxImageList(sizeTab, sizeTab, TRUE, 1);
5904
5905 wxBitmap bmp;
5906 wxImage img, simg;
5907 bmp = style->GetIcon("Display");
5908 img = bmp.ConvertToImage();
5909 simg = img.Scale(sizeTab, sizeTab);
5910 bmp = wxBitmap(simg);
5911 m_topImgList->Add(bmp);
5912 bmp = style->GetIcon("Charts");
5913 img = bmp.ConvertToImage();
5914 simg = img.Scale(sizeTab, sizeTab);
5915 bmp = wxBitmap(simg);
5916 m_topImgList->Add(bmp);
5917 bmp = style->GetIcon("Connections");
5918 img = bmp.ConvertToImage();
5919 simg = img.Scale(sizeTab, sizeTab);
5920 bmp = wxBitmap(simg);
5921 m_topImgList->Add(bmp);
5922 bmp = style->GetIcon("Ship");
5923 img = bmp.ConvertToImage();
5924 simg = img.Scale(sizeTab, sizeTab);
5925 bmp = wxBitmap(simg);
5926 m_topImgList->Add(bmp);
5927 bmp = style->GetIcon("UI");
5928 img = bmp.ConvertToImage();
5929 simg = img.Scale(sizeTab, sizeTab);
5930 bmp = wxBitmap(simg);
5931 m_topImgList->Add(bmp);
5932 bmp = style->GetIcon("Plugins");
5933 img = bmp.ConvertToImage();
5934 simg = img.Scale(sizeTab, sizeTab);
5935 bmp = wxBitmap(simg);
5936 m_topImgList->Add(bmp);
5937 }
5938}
5939
5940void options::CreateControls() {
5941 int border_size = 4;
5942 // use for items within one group, with Add(...wxALL)
5943 int group_item_spacing = 2;
5944
5945 int font_size_y, font_descent, font_lead;
5946 GetTextExtent("0", NULL, &font_size_y, &font_descent, &font_lead);
5947 m_fontHeight = font_size_y + font_descent + font_lead;
5948
5949#ifdef __ANDROID__
5950 m_sliderSize =
5951 wxSize(wxMin(m_fontHeight * 8, g_Platform->getDisplaySize().x / 2),
5952 m_fontHeight * 8 / 10);
5953#else
5954 m_sliderSize =
5955 wxSize(wxMin(m_fontHeight * 8, g_Platform->getDisplaySize().x / 2),
5956 m_fontHeight * 2);
5957#endif
5958
5959 m_small_button_size =
5960 wxSize(-1, (int)(1.2 * (font_size_y + font_descent /*+ font_lead*/)));
5961
5962 m_nCharWidthMax = GetSize().x / GetCharWidth();
5963
5964 // Some members (pointers to controls) need to initialized
5965 pEnableZoomToCursor = NULL;
5966 pSmoothPanZoom = NULL;
5967
5968 // Check the display size.
5969 // If "small", adjust some factors to squish out some more white space
5970 int width, height;
5971 width = g_monitor_info[g_current_monitor].width;
5972 height = g_monitor_info[g_current_monitor].height;
5973
5974 if (!g_bresponsive && height <= 800) {
5975 border_size = 2;
5976 group_item_spacing = 1;
5977 }
5978
5979 labelFlags =
5980 wxSizerFlags(0).Align(wxALIGN_RIGHT).Border(wxALL, group_item_spacing);
5981 inputFlags = wxSizerFlags(0)
5982 .Align(wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL)
5983 .Border(wxALL, group_item_spacing);
5984 verticleInputFlags =
5985 wxSizerFlags(0).Align(wxALIGN_LEFT).Border(wxALL, group_item_spacing);
5986 groupLabelFlags = wxSizerFlags(0)
5987 .Align(wxALIGN_RIGHT | wxALIGN_TOP)
5988 .Border(wxALL, group_item_spacing);
5989 groupLabelFlagsHoriz =
5990 wxSizerFlags(0).Align(wxALIGN_TOP).Border(wxALL, group_item_spacing);
5991 groupInputFlags = wxSizerFlags(0)
5992 .Align(wxALIGN_LEFT | wxALIGN_TOP)
5993 .Border(wxBOTTOM, group_item_spacing * 2)
5994 .Expand();
5995
5996#ifdef __WXGTK__
5997 groupLabelFlags.Border(wxTOP, group_item_spacing + 3);
5998#endif
5999
6000 options* itemDialog1 = this;
6001
6002 wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
6003 itemDialog1->SetSizer(itemBoxSizer2);
6004
6005#ifdef __ANDROID__
6006 // Set Dialog Font by custom crafted Qt Stylesheet.
6007 wxFont* qFont = dialogFont;
6008
6009 wxString wqs = getFontQtStylesheet(qFont);
6010 wxCharBuffer sbuf = wqs.ToUTF8();
6011 QString qsb = QString(sbuf.data());
6012
6013 QString qsbq = getQtStyleSheet(); // basic scrollbars, etc
6014
6015 itemDialog1->GetHandle()->setStyleSheet(qsb +
6016 qsbq); // Concatenated style sheets
6017
6018#endif
6019
6020 int flags = 0;
6021
6022#ifdef OCPN_OPTIONS_USE_LISTBOOK
6023 flags = wxLB_TOP;
6024 m_pListbook = new wxListbook(itemDialog1, ID_NOTEBOOK, wxDefaultPosition,
6025 wxSize(-1, -1), flags);
6026 m_pListbook->Connect(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED,
6027 wxListbookEventHandler(options::OnPageChange), NULL,
6028 this);
6029#else
6030 flags = wxNB_TOP;
6031 m_pListbook = new wxNotebook(itemDialog1, ID_NOTEBOOK, wxDefaultPosition,
6032 wxSize(-1, -1), flags);
6033 m_pListbook->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
6034 wxNotebookEventHandler(options::OnTopNBPageChange), NULL,
6035 this);
6036#endif
6037
6038#ifdef __ANDROID__
6039 // In wxQT, we can dynamically style the little scroll buttons on a small
6040 // display, to make them bigger
6041 m_pListbook->GetHandle()->setStyleSheet(getListBookStyleSheet());
6042
6043#endif
6044
6045 CreateListbookIcons();
6046
6047 m_pListbook->SetImageList(m_topImgList);
6048 itemBoxSizer2->Add(m_pListbook, 1, wxALL | wxEXPAND, border_size);
6049
6050 m_OK_Cancel_Apply_buttons = new wxBoxSizer(wxHORIZONTAL);
6051 itemBoxSizer2->Add(m_OK_Cancel_Apply_buttons, 0, wxALIGN_RIGHT | wxALL,
6052 border_size);
6053
6054 m_OKButton = new wxButton(itemDialog1, xID_OK, _("Ok"));
6055 m_OKButton->SetDefault();
6056 m_OK_Cancel_Apply_buttons->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL,
6057 border_size);
6058
6059 m_CancelButton = new wxButton(itemDialog1, wxID_CANCEL, _("Cancel"));
6060 m_OK_Cancel_Apply_buttons->Add(m_CancelButton, 0,
6061 wxALIGN_CENTER_VERTICAL | wxALL, border_size);
6062
6063 m_ApplyButton = new wxButton(itemDialog1, ID_APPLY, _("Apply"));
6064 m_OK_Cancel_Apply_buttons->Add(m_ApplyButton, 0,
6065 wxALIGN_CENTER_VERTICAL | wxALL, border_size);
6066
6067 m_pageDisplay = CreatePanel(_("Display"));
6068 CreatePanel_Display(m_pageDisplay, border_size, group_item_spacing);
6069 CreatePanel_Units(m_pageDisplay, border_size, group_item_spacing);
6070 CreatePanel_Advanced(m_pageDisplay, border_size, group_item_spacing);
6071 CreatePanel_Configs(m_pageDisplay, border_size, group_item_spacing);
6072
6073 m_pageCharts = CreatePanel(_("Charts"));
6074 CreatePanel_ChartsLoad(m_pageCharts, border_size, group_item_spacing);
6075 CreatePanel_VectorCharts(m_pageCharts, border_size, group_item_spacing);
6076
6077 // ChartGroups must be created after ChartsLoad and must be at least third
6078 CreatePanel_ChartGroups(m_pageCharts, border_size, group_item_spacing);
6079 CreatePanel_TidesCurrents(m_pageCharts, border_size, group_item_spacing);
6080
6081 wxNotebook* nb =
6082 dynamic_cast<wxNotebook*>(m_pListbook->GetPage(m_pageCharts));
6083 if (nb) {
6084#ifdef OCPN_OPTIONS_USE_LISTBOOK
6085 nb->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
6086 wxListbookEventHandler(options::OnChartsPageChange), NULL,
6087 this);
6088#else
6089 nb->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
6090 wxNotebookEventHandler(options::OnChartsPageChange), NULL,
6091 this);
6092
6093#endif
6094 }
6095
6096 wxString ConnTab = _("Connections");
6097 if (g_Platform->GetDisplayDIPMult(wxTheApp->GetTopWindow()) < 1)
6098 ConnTab = _("Connect");
6099
6100 m_pageConnections = CreatePanel(ConnTab);
6101 CreatePanel_NMEA(m_pageConnections, border_size, group_item_spacing);
6102
6103 // SetDefaultConnectionParams();
6104
6105 m_pageShips = CreatePanel(_("Ships"));
6106 CreatePanel_Ownship(m_pageShips, border_size, group_item_spacing);
6107 CreatePanel_AIS(m_pageShips, border_size, group_item_spacing);
6108 CreatePanel_MMSI(m_pageShips, border_size, group_item_spacing);
6109
6110 CreatePanel_Routes(m_pageShips, border_size, group_item_spacing);
6111
6112 wxString UITab = _("User Interface");
6113 if (g_Platform->GetDisplayDIPMult(wxTheApp->GetTopWindow()) < 1)
6114 UITab = _("User");
6115
6116 m_pageUI = CreatePanel(UITab);
6117 CreatePanel_UI(m_pageUI, border_size, group_item_spacing);
6118 CreatePanel_Sounds(m_pageUI, border_size, group_item_spacing);
6119
6120 m_pagePlugins = CreatePanel(_("Plugins"));
6121 itemPanelPlugins = AddPage(m_pagePlugins, _("Plugins"));
6122
6123 itemBoxSizerPanelPlugins = new wxBoxSizer(wxVERTICAL);
6124 itemPanelPlugins->SetSizer(itemBoxSizerPanelPlugins);
6125
6126 // PlugIns can add panels, too
6127 if (g_pi_manager) g_pi_manager->NotifySetupOptions();
6128
6129 SetColorScheme(static_cast<ColorScheme>(0));
6130
6131 // Set the maximum size of the entire settings dialog
6132 // leaving a slightly larger border for larger displays.
6133 int marginx = 10;
6134 int marginy = 40;
6135 if (width > 800) {
6136 marginx = 100;
6137 marginy = 100;
6138 }
6139
6140 SetSizeHints(-1, -1, width - marginx, height - marginy);
6141
6142#ifndef __WXGTK__
6143 // The s57 chart panel is the one which controls the minimum width required
6144 // to avoid horizontal scroll bars
6145 // vectorPanel->SetSizeHints(ps57Ctl);
6146#endif
6147}
6148
6149void options::SetInitialPage(int page_sel, int sub_page) {
6150 if (page_sel < (int)m_pListbook->GetPageCount())
6151 m_pListbook->SetSelection(page_sel);
6152 else
6153 m_pListbook->SetSelection(0);
6154
6155 if (sub_page >= 0) {
6156 for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
6157 wxNotebookPage* pg = m_pListbook->GetPage(i);
6158 wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
6159 if (nb) {
6160 if (i == (size_t)page_sel) {
6161 if (sub_page < (int)nb->GetPageCount())
6162 nb->SetSelection(sub_page);
6163 else
6164 nb->SetSelection(0);
6165 } else
6166 nb->ChangeSelection(0);
6167 }
6168 }
6169 }
6170}
6171
6172void options::SetColorScheme(ColorScheme cs) {
6173 DimeControl(this);
6174
6175#ifdef OCPN_OPTIONS_USE_LISTBOOK
6176 wxListView* lv = m_pListbook->GetListView();
6177 lv->SetBackgroundColour(GetBackgroundColour());
6178
6179 if (m_cs != cs) {
6180 delete m_topImgList;
6181 CreateListbookIcons();
6182 m_pListbook->SetImageList(m_topImgList);
6183
6184 m_cs = cs;
6185 }
6186
6187#endif
6188
6189 // Some panels need specific color change method
6190 comm_dialog->SetColorScheme(cs);
6191}
6192
6193void options::OnAISRolloverClick(wxCommandEvent& event) {
6194 m_pCheck_Rollover_Class->Enable(event.IsChecked());
6195 m_pCheck_Rollover_COG->Enable(event.IsChecked());
6196 m_pCheck_Rollover_CPA->Enable(event.IsChecked());
6197 pStatic_CallSign->Enable(event.IsChecked());
6198}
6199
6200void options::OnCanvasConfigSelectClick(int ID, bool selected) {
6201 switch (ID) {
6202 case ID_SCREENCONFIG1:
6203 if (m_sconfigSelect_twovertical)
6204 m_sconfigSelect_twovertical->SetSelected(false);
6205 m_screenConfig = 0;
6206 break;
6207
6208 case ID_SCREENCONFIG2:
6209 if (m_sconfigSelect_single) m_sconfigSelect_single->SetSelected(false);
6210 m_screenConfig = 1;
6211 break;
6212 }
6213}
6214
6215void options::SetInitialSettings() {
6216 wxString s;
6217
6218 m_returnChanges = 0; // reset the flags
6219 m_bfontChanged = false;
6220 m_font_element_array.Clear();
6221
6222 b_oldhaveWMM = b_haveWMM;
6223 auto loader = PluginLoader::GetInstance();
6224 b_haveWMM = loader && loader->IsPlugInAvailable("WMM");
6225
6226 // Canvas configuration
6227 switch (g_canvasConfig) {
6228 case 0:
6229 default:
6230 if (m_sconfigSelect_single) m_sconfigSelect_single->SetSelected(true);
6231 if (m_sconfigSelect_twovertical)
6232 m_sconfigSelect_twovertical->SetSelected(false);
6233 break;
6234 case 1:
6235 if (m_sconfigSelect_single) m_sconfigSelect_single->SetSelected(false);
6236 if (m_sconfigSelect_twovertical)
6237 m_sconfigSelect_twovertical->SetSelected(true);
6238 break;
6239 }
6240 m_screenConfig = g_canvasConfig;
6241
6242 // Initial Charts Load
6243
6244 ActiveChartArray.Clear();
6245 for (size_t i = 0; i < m_CurrentDirList.GetCount(); i++) {
6246 ActiveChartArray.Add(m_CurrentDirList[i]);
6247 }
6248
6249 // ChartGroups
6250 if (m_pWorkDirList) {
6251 UpdateWorkArrayFromDisplayPanel();
6252 groupsPanel->SetDBDirs(*m_pWorkDirList);
6253
6254 // Make a deep copy of the current global Group Array
6255 groupsPanel->EmptyChartGroupArray(m_pGroupArray);
6256 delete m_pGroupArray;
6257 m_pGroupArray = groupsPanel->CloneChartGroupArray(g_pGroupArray);
6258 groupsPanel->SetGroupArray(m_pGroupArray);
6259 groupsPanel->SetInitialSettings();
6260 }
6261
6262 if (m_pConfig) {
6263 pShowStatusBar->SetValue(g_bShowStatusBar);
6264#ifndef __WXOSX__
6265 pShowMenuBar->SetValue(g_bShowMenuBar);
6266#endif
6267 pShowCompassWin->SetValue(g_bShowCompassWin);
6268 }
6269
6270 s.Printf("%d", g_COGAvgSec);
6271 pCOGUPUpdateSecs->SetValue(s);
6272
6273 if (pCDOOutlines) pCDOOutlines->SetValue(g_bShowOutlines);
6274 if (pCDOQuilting) pCDOQuilting->SetValue(g_bQuiltEnable);
6275 // if(pFullScreenQuilt) pFullScreenQuilt->SetValue(!g_bFullScreenQuilt);
6276 if (pSDepthUnits) pSDepthUnits->SetValue(g_bShowDepthUnits);
6277 if (pSkewComp) pSkewComp->SetValue(g_bskew_comp);
6278 pMobile->SetValue(g_btouch);
6279 pResponsive->SetValue(g_bresponsive);
6280 pRollover->SetValue(g_bRollover);
6281 m_pCheck_Rollover_Class->Enable(g_bRollover);
6282 m_pCheck_Rollover_COG->Enable(g_bRollover);
6283 m_pCheck_Rollover_CPA->Enable(g_bRollover);
6284 pStatic_CallSign->Enable(g_bRollover);
6285
6286 pZoomButtons->SetValue(g_bShowMuiZoomButtons);
6287
6288 // pOverzoomEmphasis->SetValue(!g_fog_overzoom);
6289 // pOZScaleVector->SetValue(!g_oz_vector_scale);
6290 pInlandEcdis->SetValue(g_bInlandEcdis);
6291 pHiconColors->SetValue(g_hicon_colors);
6292
6293#ifdef ocpnUSE_GL
6294 pOpenGL->SetValue(g_bopengl);
6295 if (auto* w = wxWindow::FindWindowById(ID_OPENGLOPTIONS))
6296 w->Enable(pOpenGL->IsChecked());
6297#endif
6298 if (pSmoothPanZoom) pSmoothPanZoom->SetValue(g_bsmoothpanzoom);
6299 pCBTrueShow->SetValue(g_bShowTrue);
6300 pCBMagShow->SetValue(g_bShowMag);
6301
6302 int oldLength = itemStaticTextUserVar->GetLabel().Length();
6303
6304 // disable input for variation if WMM is available
6305 if (b_haveWMM) {
6306 itemStaticTextUserVar->SetLabel(
6307 _("WMM Plugin calculated magnetic variation"));
6308 wxString s;
6309 s.Printf("%4.1f", gVar);
6310 pMagVar->SetValue(s);
6311 } else {
6312 itemStaticTextUserVar->SetLabel(_("User set magnetic variation"));
6313 wxString s;
6314 s.Printf("%4.1f", g_UserVar);
6315 pMagVar->SetValue(s);
6316 }
6317
6318 int newLength = itemStaticTextUserVar->GetLabel().Length();
6319
6320 // size hack to adjust change in static text size
6321 if ((newLength != oldLength) || (b_oldhaveWMM != b_haveWMM)) {
6322 wxSize sz = GetSize();
6323 SetSize(sz.x + 1, sz.y);
6324 SetSize(sz);
6325 }
6326
6327 itemStaticTextUserVar2->Enable(!b_haveWMM);
6328 pMagVar->Enable(!b_haveWMM);
6329
6330 if (pSDisplayGrid) pSDisplayGrid->SetValue(g_bDisplayGrid);
6331
6332 // LIVE ETA OPTION
6333
6334 // Checkbox
6335 if (pSLiveETA) pSLiveETA->SetValue(g_bShowLiveETA);
6336
6337 // Defaut boat speed text input field
6338 // Speed always in knots, and converted to user speed unit
6339 wxString stringDefaultBoatSpeed;
6340 if (!g_defaultBoatSpeed || !g_defaultBoatSpeedUserUnit) {
6341 g_defaultBoatSpeed = 6.0;
6342 g_defaultBoatSpeedUserUnit = toUsrSpeed(g_defaultBoatSpeed, -1);
6343 }
6344 stringDefaultBoatSpeed.Printf("%d", (int)g_defaultBoatSpeedUserUnit);
6345 if (pSDefaultBoatSpeed) pSDefaultBoatSpeed->SetValue(stringDefaultBoatSpeed);
6346
6347 // END LIVE ETA OPTION
6348
6349 if (pCBCourseUp) pCBCourseUp->SetValue(g_bCourseUp);
6350 if (pCBNorthUp) pCBNorthUp->SetValue(!g_bCourseUp);
6351 if (pCBLookAhead) pCBLookAhead->SetValue(g_bLookAhead);
6352
6353 if (fabs(wxRound(g_ownship_predictor_minutes) - g_ownship_predictor_minutes) >
6354 1e-4)
6355 s.Printf("%6.2f", g_ownship_predictor_minutes);
6356 else
6357 s.Printf("%4.0f", g_ownship_predictor_minutes);
6358 m_pText_OSCOG_Predictor->SetValue(s);
6359
6360 if (fabs(wxRound(g_ownship_HDTpredictor_miles) -
6361 g_ownship_HDTpredictor_miles) > 1e-4)
6362 s.Printf("%6.2f", g_ownship_HDTpredictor_miles);
6363 else
6364 s.Printf("%4.0f", g_ownship_HDTpredictor_miles);
6365 m_pText_OSHDT_Predictor->SetValue(s);
6366
6367 if (g_OwnShipmmsi > 0) {
6368 wxString s = wxString::Format("%i", g_OwnShipmmsi);
6369 m_pTxt_OwnMMSI->SetValue(s);
6370 } else
6371 m_pTxt_OwnMMSI->SetValue("");
6372
6373 m_pShipIconType->SetSelection(g_OwnShipIconType);
6374 wxCommandEvent eDummy;
6375 OnShipTypeSelect(eDummy);
6376 m_pOSLength->SetValue(wxString::Format("%.1f", g_n_ownship_length_meters));
6377 m_pOSWidth->SetValue(wxString::Format("%.1f", g_n_ownship_beam_meters));
6378 m_pOSGPSOffsetX->SetValue(wxString::Format("%.1f", g_n_gps_antenna_offset_x));
6379 m_pOSGPSOffsetY->SetValue(wxString::Format("%.1f", g_n_gps_antenna_offset_y));
6380 m_pOSMinSize->SetValue(wxString::Format("%d", g_n_ownship_min_mm));
6381 m_pText_ACRadius->SetValue(
6382 wxString::Format("%.3f", g_n_arrival_circle_radius));
6383
6384 wxString buf;
6385 if (g_iNavAidRadarRingsNumberVisible > 10)
6386 g_iNavAidRadarRingsNumberVisible = 10;
6387 pNavAidRadarRingsNumberVisible->SetSelection(
6388 g_iNavAidRadarRingsNumberVisible);
6389 buf.Printf("%.3f", g_fNavAidRadarRingsStep);
6390 pNavAidRadarRingsStep->SetValue(buf);
6391 m_itemRadarRingsUnits->SetSelection(g_pNavAidRadarRingsStepUnits);
6392 m_colourOwnshipRangeRingColour->SetColour(g_colourOwnshipRangeRingsColour);
6393
6394 pScaMinChckB->SetValue(g_bUseWptScaMin);
6395 m_pText_ScaMin->SetValue(wxString::Format("%i", g_iWpt_ScaMin));
6396 m_pText_ScaMax->SetValue(wxString::Format("%i", g_iWpt_ScaMax));
6397 pScaMinOverruleChckB->SetValue(g_bOverruleScaMin);
6398
6399 OnRadarringSelect(eDummy);
6400
6401 if (g_iWaypointRangeRingsNumber > 10) g_iWaypointRangeRingsNumber = 10;
6402 pWaypointRangeRingsNumber->SetSelection(g_iWaypointRangeRingsNumber);
6403 buf.Printf("%.3f", g_fWaypointRangeRingsStep);
6404 pWaypointRangeRingsStep->SetValue(buf);
6405 m_itemWaypointRangeRingsUnits->SetSelection(g_iWaypointRangeRingsStepUnits);
6406 m_colourWaypointRangeRingsColour->SetColour(g_colourWaypointRangeRingsColour);
6407 OnWaypointRangeRingSelect(eDummy);
6408 pShowshipToActive->SetValue(g_bShowShipToActive);
6409 m_shipToActiveStyle->SetSelection(g_shipToActiveStyle);
6410 m_shipToActiveColor->SetSelection(g_shipToActiveColor);
6411
6412 pWayPointPreventDragging->SetValue(g_bWayPointPreventDragging);
6413 pConfirmObjectDeletion->SetValue(g_bConfirmObjectDelete);
6414
6415 if (pEnableZoomToCursor) pEnableZoomToCursor->SetValue(g_bEnableZoomToCursor);
6416 if (pEnableTenHertz) pEnableTenHertz->SetValue(g_btenhertz);
6417
6418 if (pPreserveScale) pPreserveScale->SetValue(g_bPreserveScaleOnX);
6419 pPlayShipsBells->SetValue(g_bPlayShipsBells);
6420
6421 if (pCmdSoundString) pCmdSoundString->SetValue(g_CmdSoundString);
6422
6423 if (pSoundDeviceIndex) pSoundDeviceIndex->SetSelection(g_iSoundDeviceIndex);
6424 // pFullScreenToolbar->SetValue( g_bFullscreenToolbar );
6425 // pTransparentToolbar->SetValue(g_bTransparentToolbar);
6426 pSDMMFormat->Select(g_iSDMMFormat);
6427 // Map DISTANCE_* enum to dropdown index using the mapping table
6428 {
6429 int distance_ui_index = GetDistanceFormatIndex(g_iDistanceFormat);
6430 pDistanceFormat->SetSelection(distance_ui_index);
6431 }
6432 pSpeedFormat->Select(g_iSpeedFormat);
6433 pWindSpeedFormat->Select(g_iWindSpeedFormat);
6434 pTempFormat->Select(g_iTempFormat);
6435 if (pHeightUnitSelect) pHeightUnitSelect->SetSelection(g_iHeightFormat);
6436
6437 pAdvanceRouteWaypointOnArrivalOnly->SetValue(
6438 g_bAdvanceRouteWaypointOnArrivalOnly);
6439
6440 if (g_datetime_format == "Local Time") {
6441 pTimezoneLocalTime->SetValue(true);
6442 } else if (g_datetime_format == "UTC") {
6443 pTimezoneUTC->SetValue(true);
6444 } else {
6445 // Default to UTC if no saved timezone or if it's not in the list.
6446 pTimezoneUTC->SetValue(true);
6447 }
6448
6449 pTrackDaily->SetValue(g_bTrackDaily);
6450 pTrackRotateLMT->SetValue(g_track_rotate_time_type == TIME_TYPE_LMT);
6451 pTrackRotateUTC->SetValue(g_track_rotate_time_type == TIME_TYPE_UTC);
6452 pTrackRotateComputerTime->SetValue(g_track_rotate_time_type ==
6453 TIME_TYPE_COMPUTER);
6454 pTrackHighlite->SetValue(g_bHighliteTracks);
6455 m_colourTrackLineColour->SetColour(g_colourTrackLineColour);
6456 pTrackPrecision->SetSelection(g_nTrackPrecision);
6457
6458 m_soundPanelAnchor->GetCheckBox()->SetValue(g_bAnchor_Alert_Audio);
6459
6460 // AIS Parameters
6461 // CPA Box
6462 m_pCheck_CPA_Max->SetValue(g_bCPAMax);
6463
6464 s.Printf("%4.1f", g_CPAMax_NM);
6465 m_pText_CPA_Max->SetValue(s);
6466
6467 m_pCheck_CPA_Warn->SetValue(g_bCPAWarn);
6468
6469 s.Printf("%4.1f", g_CPAWarn_NM);
6470 m_pText_CPA_Warn->SetValue(s);
6471
6472 if (m_pCheck_CPA_Warn->GetValue()) {
6473 m_pCheck_CPA_WarnT->Enable();
6474 m_pCheck_CPA_WarnT->SetValue(g_bTCPA_Max);
6475 } else
6476 m_pCheck_CPA_WarnT->Disable();
6477
6478 s.Printf("%4.0f", g_TCPA_Max);
6479 m_pText_CPA_WarnT->SetValue(s);
6480
6481 // Lost Targets
6482 m_pCheck_Mark_Lost->SetValue(g_bMarkLost);
6483
6484 s.Printf("%4.0f", g_MarkLost_Mins);
6485 m_pText_Mark_Lost->SetValue(s);
6486
6487 m_pCheck_Remove_Lost->SetValue(g_bRemoveLost);
6488
6489 s.Printf("%4.0f", g_RemoveLost_Mins);
6490 m_pText_Remove_Lost->SetValue(s);
6491
6492 // Display
6493 m_pCheck_Show_COG->SetValue(g_bShowCOG);
6494
6495 s.Printf("%4.0f", g_ShowCOG_Mins);
6496 m_pText_COG_Predictor->SetValue(s);
6497
6498 m_pCheck_Sync_OCOG_ACOG->SetValue(g_bSyncCogPredictors);
6499 if (g_bSyncCogPredictors) m_pText_COG_Predictor->Disable();
6500
6501 m_pCheck_Show_Tracks->SetValue(g_bAISShowTracks);
6502
6503 s.Printf("%4.0f", g_AISShowTracks_Mins);
6504 m_pText_Track_Length->SetValue(s);
6505
6506 m_pCheck_Hide_Moored->SetValue(g_bHideMoored);
6507
6508 s.Printf("%4.1f", g_ShowMoored_Kts);
6509 m_pText_Moored_Speed->SetValue(s);
6510
6511 m_pCheck_Draw_Realtime_Prediction->SetValue(g_bDrawAISRealtime);
6512
6513 s.Printf("%4.1f", g_AIS_RealtPred_Kts);
6514 m_pText_RealtPred_Speed->SetValue(s);
6515
6516 m_pCheck_Scale_Priority->SetValue(g_bAllowShowScaled);
6517
6518 s.Printf("%i", g_ShowScaled_Num);
6519 m_pText_Scale_Priority->SetValue(s);
6520
6521 m_pCheck_Show_Area_Notices->SetValue(g_bShowAreaNotices);
6522
6523 m_pCheck_Draw_Target_Size->SetValue(g_bDrawAISSize);
6524 m_pCheck_Draw_Realtime_Prediction->SetValue(g_bDrawAISRealtime);
6525
6526 m_pCheck_Show_Target_Name->SetValue(g_bShowAISName);
6527
6528 s.Printf("%d", g_Show_Target_Name_Scale);
6529 m_pText_Show_Target_Name_Scale->SetValue(s);
6530
6531 m_pCheck_use_Wpl->SetValue(g_bWplUsePosition);
6532 m_pWplAction->SetSelection(g_WplAction);
6533
6534 // Alerts
6535 m_pCheck_AlertDialog->SetValue(g_bAIS_CPA_Alert);
6536 if (g_bAIS_CPA_Alert) {
6537 m_pCheck_AlertAudio->Enable();
6538 m_pCheck_AlertAudio->SetValue(g_bAIS_CPA_Alert_Audio);
6539 } else {
6540 m_pCheck_AlertAudio->Disable();
6541 m_pCheck_AlertAudio->SetValue(false);
6542 }
6543
6544 m_pCheck_Alert_Moored->SetValue(g_bAIS_CPA_Alert_Suppress_Moored);
6545
6546 m_pCheck_Ack_Timout->SetValue(g_bAIS_ACK_Timeout);
6547 s.Printf("%4.0f", g_AckTimeout_Mins);
6548 m_pText_ACK_Timeout->SetValue(s);
6549
6550 // Sounds
6551 m_soundPanelAIS->GetCheckBox()->SetValue(g_bAIS_GCPA_Alert_Audio);
6552 m_soundPanelSART->GetCheckBox()->SetValue(g_bAIS_SART_Alert_Audio);
6553 m_soundPanelDSC->GetCheckBox()->SetValue(g_bAIS_DSC_Alert_Audio);
6554
6555 // Rollover
6556 m_pCheck_Rollover_Class->SetValue(g_bAISRolloverShowClass);
6557 m_pCheck_Rollover_COG->SetValue(g_bAISRolloverShowCOG);
6558 m_pCheck_Rollover_CPA->SetValue(g_bAISRolloverShowCPA);
6559
6560 m_pSlider_Zoom_Raster->SetValue(g_chart_zoom_modifier_raster);
6561 m_pSlider_Zoom_Vector->SetValue(g_chart_zoom_modifier_vector);
6562
6563 m_pSlider_GUI_Factor->SetValue(g_GUIScaleFactor);
6564 m_pSlider_Chart_Factor->SetValue(g_ChartScaleFactor);
6565 m_pSlider_Ship_Factor->SetValue(g_ShipScaleFactor);
6566 m_pSlider_Text_Factor->SetValue(g_ENCSoundingScaleFactor);
6567 m_pSlider_ENCText_Factor->SetValue(g_ENCTextScaleFactor);
6568 m_pMouse_Zoom_Slider->SetValue(g_mouse_zoom_sensitivity_ui);
6569#ifndef __ANDROID__
6570 wxString screenmm;
6571 if (!g_config_display_size_manual) {
6572 pRBSizeAuto->SetValue(TRUE);
6573 for (const auto& mm : g_monitor_info) {
6574 screenmm.Append(wxString::Format("%zu,", mm.width_mm));
6575 }
6576 screenmm.RemoveLast(); // Strip last comma
6577 pScreenMM->Disable();
6578 } else {
6579 for (const auto& mm : g_config_display_size_mm) {
6580 screenmm.Append(wxString::Format("%zu,", mm));
6581 }
6582 screenmm.RemoveLast(); // Strip last comma
6583 pRBSizeManual->SetValue(TRUE);
6584 }
6585
6586 pScreenMM->SetValue(screenmm);
6587#endif
6588
6589 pDepthUnitSelect->SetSelection(g_nDepthUnitDisplay);
6590 UpdateOptionsUnits(); // sets depth values using the user's unit preference
6591
6592 SetInitialVectorSettings();
6593
6594 pToolbarAutoHideCB->SetValue(g_bAutoHideToolbar);
6595
6596 s.Printf("%d", g_nAutoHideToolbar);
6597 pToolbarHideSecs->SetValue(s);
6598
6599 // Serial ports
6600
6601 delete m_pSerialArray;
6602 m_pSerialArray = NULL;
6603 m_pSerialArray = EnumerateSerialPorts();
6604 m_bForceNewToolbaronCancel = false;
6605}
6606
6607void options::resetMarStdList(bool bsetConfig, bool bsetStd) {
6608 if (ps57CtlListBox) {
6609 // S52 Primary Filters
6610 ps57CtlListBox->Clear();
6611 marinersStdXref.clear();
6612
6613 ps57CtlListBox->Freeze();
6614
6615 for (unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount();
6616 iPtr++) {
6617 OBJLElement* pOLE = (OBJLElement*)(ps52plib->pOBJLArray->Item(iPtr));
6618
6619 wxString item;
6620 if (iPtr < ps52plib->OBJLDescriptions.size()) {
6621 item = ps52plib->OBJLDescriptions[iPtr];
6622 } else {
6623 item = wxString(pOLE->OBJLName, wxConvUTF8);
6624 }
6625
6626 // Find the most conservative Category, among Point, Area, and Line LUPs
6627 DisCat cat = OTHER;
6628
6629 DisCat catp = ps52plib->findLUPDisCat(pOLE->OBJLName, SIMPLIFIED);
6630 DisCat cata = ps52plib->findLUPDisCat(pOLE->OBJLName, PLAIN_BOUNDARIES);
6631 DisCat catl = ps52plib->findLUPDisCat(pOLE->OBJLName, LINES);
6632
6633 if ((catp == DISPLAYBASE) || (cata == DISPLAYBASE) ||
6634 (catl == DISPLAYBASE))
6635 cat = DISPLAYBASE;
6636 else if ((catp == STANDARD) || (cata == STANDARD) || (catl == STANDARD))
6637 cat = STANDARD;
6638
6639 bool benable = true;
6640 if (cat > 0) benable = cat != DISPLAYBASE;
6641
6642 // The ListBox control will insert entries in sorted order, which means
6643 // we need to
6644 // keep track of already inserted items that gets pushed down the line.
6645 int newpos = ps57CtlListBox->Append(item, benable, false);
6646 marinersStdXref.push_back(newpos);
6647 for (size_t i = 0; i < iPtr; i++) {
6648 if (marinersStdXref[i] >= newpos) marinersStdXref[i]++;
6649 }
6650
6651 bool bviz = 0;
6652 if (bsetConfig) bviz = !(pOLE->nViz == 0);
6653
6654 if (cat == DISPLAYBASE) bviz = true;
6655
6656 if (bsetStd) {
6657 if (cat == STANDARD) {
6658 bviz = true;
6659 }
6660 }
6661
6662 ps57CtlListBox->Check(newpos, bviz);
6663 }
6664 ps57CtlListBox->Thaw();
6665
6666 // Deferred layout instead of after every appended checkbox
6667 ps57CtlListBox->RunLayout();
6668
6669 // Force the wxScrolledWindow to recalculate its scroll bars
6670 wxSize s = ps57CtlListBox->GetSize();
6671 ps57CtlListBox->SetSize(s.x, s.y - 1);
6672 }
6673}
6674
6675void options::SetInitialVectorSettings() {
6676 m_pSlider_CM93_Zoom->SetValue(g_cm93_zoom_factor);
6677
6678 // Diplay Category
6679 if (ps52plib) {
6680 m_bVectorInit = true;
6681 resetMarStdList(true, false);
6682
6683#ifdef __ANDROID__
6684 ps57CtlListBox->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
6685#endif
6686
6687 int nset = 2; // default OTHER
6688 switch (ps52plib->GetDisplayCategory()) {
6689 case (DISPLAYBASE):
6690 nset = 0;
6691 break;
6692 case (STANDARD):
6693 nset = 1;
6694 break;
6695 case (OTHER):
6696 nset = 2;
6697 break;
6698 case (MARINERS_STANDARD):
6699 nset = 3;
6700 break;
6701 default:
6702 nset = 3;
6703 break;
6704 }
6705
6706 if (pDispCat) pDispCat->SetSelection(nset);
6707
6708 // Enable the UserStandard object list if either canvas is in
6709 // MARINERS_STANDARD display category
6710 bool benableMarStd = false;
6711 // .. for each canvas...
6712 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
6713 ChartCanvas* cc = g_canvasArray.Item(i);
6714 if (cc) {
6715 if (cc->GetENCDisplayCategory() == MARINERS_STANDARD) {
6716 benableMarStd = true;
6717 break;
6718 }
6719 }
6720 }
6721
6722 // if(g_useMUI)
6723 // benableMarStd = true;
6724
6725 if (ps57CtlListBox) ps57CtlListBox->Enable(benableMarStd);
6726 itemButtonClearList->Enable(benableMarStd);
6727 itemButtonSelectList->Enable(benableMarStd);
6728 itemButtonSetStd->Enable(benableMarStd);
6729
6730 // Other Display Filters
6731 if (pCheck_SOUNDG) pCheck_SOUNDG->SetValue(ps52plib->m_bShowSoundg);
6732 if (pCheck_ATONTEXT) pCheck_ATONTEXT->SetValue(ps52plib->m_bShowAtonText);
6733 if (pCheck_LDISTEXT) pCheck_LDISTEXT->SetValue(ps52plib->m_bShowLdisText);
6734 if (pCheck_XLSECTTEXT)
6735 pCheck_XLSECTTEXT->SetValue(ps52plib->m_bExtendLightSectors);
6736
6737 pCheck_META->SetValue(ps52plib->m_bShowMeta);
6738 pCheck_SHOWIMPTEXT->SetValue(ps52plib->m_bShowS57ImportantTextOnly);
6739 pCheck_SCAMIN->SetValue(ps52plib->m_bUseSCAMIN);
6740 pCheck_SuperSCAMIN->SetValue(ps52plib->m_bUseSUPER_SCAMIN);
6741
6742 pCheck_DECLTEXT->SetValue(ps52plib->m_bDeClutterText);
6743 pCheck_NATIONALTEXT->SetValue(ps52plib->m_bShowNationalTexts);
6744
6745 // Chart Display Style
6746 if (ps52plib->m_nSymbolStyle == PAPER_CHART)
6747 pPointStyle->SetSelection(0);
6748 else
6749 pPointStyle->SetSelection(1);
6750
6751 if (ps52plib->m_nBoundaryStyle == PLAIN_BOUNDARIES)
6752 pBoundStyle->SetSelection(0);
6753 else
6754 pBoundStyle->SetSelection(1);
6755
6756 if (S52_getMarinerParam(S52_MAR_TWO_SHADES) == 1.0)
6757 p24Color->SetSelection(0);
6758 else
6759 p24Color->SetSelection(1);
6760
6761 UpdateOptionsUnits(); // sets depth values using the user's unit preference
6762 }
6763}
6764
6765void options::UpdateOptionsUnits() {
6766 int depthUnit = pDepthUnitSelect->GetSelection();
6767
6768 depthUnit = wxMax(depthUnit, 0);
6769 depthUnit = wxMin(depthUnit, 2);
6770
6771 // depth unit conversion factor
6772 float conv = 1;
6773 if (depthUnit == 0) // feet
6774 conv = 0.3048f; // international definiton of 1 foot is 0.3048 metres
6775 else if (depthUnit == 2) // fathoms
6776 conv = 0.3048f * 6; // 1 fathom is 6 feet
6777
6778 // set depth input values
6779
6780 // set depth unit labels
6781 wxString depthUnitStrings[] = {_("feet"), _("meters"), _("fathoms")};
6782 wxString depthUnitString = depthUnitStrings[depthUnit];
6783 m_depthUnitsShal->SetLabel(depthUnitString);
6784 m_depthUnitsSafe->SetLabel(depthUnitString);
6785 m_depthUnitsDeep->SetLabel(depthUnitString);
6786
6787 wxString s;
6788 s.Printf("%6.2f", S52_getMarinerParam(S52_MAR_SHALLOW_CONTOUR) / conv);
6789 s.Trim(FALSE);
6790 m_ShallowCtl->SetValue(s);
6791
6792 s.Printf("%6.2f", S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR) / conv);
6793 s.Trim(FALSE);
6794 m_SafetyCtl->SetValue(s);
6795
6796 s.Printf("%6.2f", S52_getMarinerParam(S52_MAR_DEEP_CONTOUR) / conv);
6797 s.Trim(FALSE);
6798 m_DeepCtl->SetValue(s);
6799 /*
6800 int oldLength = itemStaticTextUserVar->GetLabel().Length();
6801
6802 //disable input for variation if WMM is available
6803 if(b_haveWMM){
6804 itemStaticTextUserVar->SetLabel(_("WMM Plugin calculated magnetic
6805 variation")); wxString s; s.Printf("%4.1f", gVar); pMagVar->SetValue(s);
6806 }
6807 else{
6808 itemStaticTextUserVar->SetLabel(_("User set magnetic variation"));
6809 wxString s;
6810 s.Printf("%4.1f", g_UserVar);
6811 pMagVar->SetValue(s);
6812 }
6813
6814 int newLength = itemStaticTextUserVar->GetLabel().Length();
6815
6816 // size hack to adjust change in static text size
6817 if( (newLength != oldLength) || (b_oldhaveWMM != b_haveWMM) ){
6818 wxSize sz = GetSize();
6819 SetSize(sz.x+1, sz.y);
6820 SetSize(sz);
6821 }
6822
6823 itemStaticTextUserVar2->Enable(!b_haveWMM);
6824 pMagVar->Enable(!b_haveWMM);
6825 */
6826}
6827
6828void options::OnSizeAutoButton(wxCommandEvent& event) {
6829 wxString screenmm;
6830 for (const auto& mm : g_monitor_info) {
6831 screenmm.Append(wxString::Format("%zu,", mm.width_mm));
6832 }
6833 screenmm.RemoveLast(); // Strip last comma
6834 pScreenMM->SetValue(screenmm);
6835 pScreenMM->Disable();
6836 g_config_display_size_manual = FALSE;
6837}
6838
6839void options::OnSizeManualButton(wxCommandEvent& event) {
6840 wxString screenmm;
6841 if (g_config_display_size_mm.size() > 0 && g_config_display_size_mm[0] > 0) {
6842 for (const auto& mm : g_config_display_size_mm) {
6843 screenmm.Append(wxString::Format("%zu,", mm));
6844 }
6845 } else {
6846 for (const auto& mm : g_monitor_info) {
6847 screenmm.Append(wxString::Format("%zu,", mm.width_mm));
6848 }
6849 }
6850 screenmm.RemoveLast(); // Strip last comma
6851 pScreenMM->SetValue(screenmm);
6852 pScreenMM->Enable();
6853 g_config_display_size_manual = TRUE;
6854}
6855
6856void options::OnUnitsChoice(wxCommandEvent& event) { UpdateOptionsUnits(); }
6857
6858void options::OnCPAWarnClick(wxCommandEvent& event) {
6859 if (m_pCheck_CPA_Warn->GetValue()) {
6860 m_pCheck_CPA_WarnT->Enable();
6861 } else {
6862 m_pCheck_CPA_WarnT->SetValue(FALSE);
6863 m_pCheck_CPA_WarnT->Disable();
6864 }
6865}
6866
6867void options::OnSyncCogPredClick(wxCommandEvent& event) {
6868 if (m_pCheck_Sync_OCOG_ACOG->GetValue()) {
6869 m_pText_COG_Predictor->SetValue(m_pText_OSCOG_Predictor->GetValue());
6870 m_pText_COG_Predictor->Disable();
6871 } else {
6872 wxString s;
6873 s.Printf("%4.0f", g_ShowCOG_Mins);
6874 m_pText_COG_Predictor->SetValue(s);
6875 m_pText_COG_Predictor->Enable();
6876 }
6877}
6878
6879void options::OnShipTypeSelect(wxCommandEvent& event) {
6880 realSizes->ShowItems(m_pShipIconType->GetSelection() != 0);
6881 dispOptions->Layout();
6882 ownShip->Layout();
6883 itemPanelShip->Layout();
6884 itemPanelShip->Refresh();
6885 event.Skip();
6886}
6887
6888void options::OnRadarringSelect(wxCommandEvent& event) {
6889 radarGrid->ShowItems(pNavAidRadarRingsNumberVisible->GetSelection() != 0);
6890 dispOptions->Layout();
6891 ownShip->Layout();
6892 itemPanelShip->Layout();
6893 itemPanelShip->Refresh();
6894 event.Skip();
6895}
6896
6897void options::OnWaypointRangeRingSelect(wxCommandEvent& event) {
6898 waypointradarGrid->ShowItems(pWaypointRangeRingsNumber->GetSelection() != 0);
6899 dispOptions->Layout();
6900 Routes->Layout();
6901 itemPanelRoutes->Layout();
6902 itemPanelRoutes->Refresh();
6903 event.Skip();
6904}
6905
6906void options::OnGLClicked(wxCommandEvent& event) {
6907 // if (!g_bTransparentToolbarInOpenGLOK)
6908 // pTransparentToolbar->Enable(!pOpenGL->GetValue());
6909 if (auto* w = wxWindow::FindWindowById(ID_OPENGLOPTIONS))
6910 w->Enable(pOpenGL->IsChecked());
6911}
6912
6913void options::OnOpenGLOptions(wxCommandEvent& event) {
6914#ifdef ocpnUSE_GL
6915 OpenGLOptionsDlg dlg(this);
6916
6917 if (dlg.ShowModal() == wxID_OK) {
6918 if (top_frame::Get()->GetWxGlCanvas()) {
6919 g_GLOptions.m_bUseAcceleratedPanning =
6920 g_bGLexpert ? dlg.GetAcceleratedPanning()
6921 : top_frame::Get()
6922 ->GetAbstractPrimaryCanvas()
6923 ->CanAccelerateGlPanning();
6924 }
6925
6926 g_bSoftwareGL = dlg.GetSoftwareGL();
6927
6928 g_GLOptions.m_GLPolygonSmoothing = dlg.GetPolygonSmoothing();
6929 g_GLOptions.m_GLLineSmoothing = dlg.GetLineSmoothing();
6930
6931 if (g_bGLexpert) {
6932 // user defined
6933 g_GLOptions.m_bTextureCompressionCaching =
6934 dlg.GetTextureCompressionCaching();
6935 g_GLOptions.m_iTextureMemorySize = dlg.GetTextureMemorySize();
6936 } else {
6937 // caching is on if textures are compressed
6938 g_GLOptions.m_bTextureCompressionCaching = dlg.GetTextureCompression();
6939 }
6940
6941 if (g_bopengl && g_glTextureManager &&
6942 g_GLOptions.m_bTextureCompression != dlg.GetTextureCompression()) {
6943 // new g_GLoptions setting is needed in callees
6944 g_GLOptions.m_bTextureCompression = dlg.GetTextureCompression();
6945
6946 if (top_frame::Get()->GetWxGlCanvas()) {
6947 ::wxBeginBusyCursor();
6948 top_frame::Get()->GetAbstractPrimaryCanvas()->SetupGlCompression();
6949 g_glTextureManager->ClearAllRasterTextures();
6950 ::wxEndBusyCursor();
6951 }
6952 } else
6953 g_GLOptions.m_bTextureCompression = dlg.GetTextureCompression();
6954 }
6955
6956 if (dlg.GetRebuildCache()) {
6957 m_returnChanges = REBUILD_RASTER_CACHE;
6958 Finish();
6959 }
6960#endif
6961}
6962
6963void options::OnChartDirListSelect(wxCommandEvent& event) {
6964#if 0
6965 bool selected = (pActiveChartsList->GetSelectedItemCount() > 0);
6966 m_removeBtn->Enable(selected);
6967 if (m_compressBtn) m_compressBtn->Enable(selected);
6968#endif
6969}
6970
6971void options::OnDisplayCategoryRadioButton(wxCommandEvent& event) {
6972 if (!g_useMUI) {
6973 if (pDispCat) {
6974 const bool select = pDispCat->GetSelection() == 3;
6975 ps57CtlListBox->Enable(select);
6976 itemButtonClearList->Enable(select);
6977 itemButtonSelectList->Enable(select);
6978 itemButtonSetStd->Enable(select);
6979 }
6980 }
6981 event.Skip();
6982}
6983
6984void options::OnButtonClearClick(wxCommandEvent& event) {
6985 resetMarStdList(false, false);
6986
6987 // int nOBJL = ps57CtlListBox->GetCount();
6988 // for (int iPtr = 0; iPtr < nOBJL; iPtr++){
6989 // ps57CtlListBox->Check(iPtr, FALSE);
6990 // }
6991 event.Skip();
6992}
6993
6994void options::OnButtonSelectClick(wxCommandEvent& event) {
6995 int nOBJL = ps57CtlListBox->GetCount();
6996 for (int iPtr = 0; iPtr < nOBJL; iPtr++) ps57CtlListBox->Check(iPtr, TRUE);
6997
6998 event.Skip();
6999}
7000
7001void options::OnButtonSetStd(wxCommandEvent& event) {
7002 resetMarStdList(false, true);
7003
7004 event.Skip();
7005}
7006
7007bool options::ShowToolTips() { return TRUE; }
7008
7009void options::OnCharHook(wxKeyEvent& event) {
7010 if (event.GetKeyCode() == WXK_RETURN &&
7011 event.GetModifiers() == wxMOD_CONTROL) {
7012 wxCommandEvent okEvent;
7013 okEvent.SetId(xID_OK);
7014 okEvent.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
7015 GetEventHandler()->AddPendingEvent(okEvent);
7016 }
7017 event.Skip();
7018}
7019
7020void options::OnButtonaddClick(wxCommandEvent& event) {
7021 wxString selDir;
7022 int dresult = g_Platform->DoDirSelectorDialog(
7023 this, &selDir, _("Add a directory containing chart files"),
7024 *pInit_Chart_Dir, false); // no add files allowed
7025
7026 if (dresult != wxID_CANCEL) AddChartDir(selDir);
7027
7028 event.Skip();
7029}
7030
7031void options::AddChartDir(const wxString& dir) {
7032 wxFileName dirname = wxFileName(dir);
7033 pInit_Chart_Dir->Empty();
7034
7035 wxString dirAdd;
7036 if (g_bportable) {
7037 wxFileName f(dir);
7038 f.MakeRelativeTo(g_Platform->GetHomeDir());
7039 dirAdd = f.GetFullPath();
7040 } else {
7041 pInit_Chart_Dir->Append(dirname.GetPath());
7042 dirAdd = dir;
7043 }
7044
7045 ChartDirInfo cdi;
7046 cdi.fullpath = dirAdd;
7047 ActiveChartArray.Add(cdi);
7048
7049 UpdateChartDirList();
7050
7051 k_charts |= CHANGE_CHARTS;
7052
7053 pScanCheckBox->Disable();
7054}
7055
7056void options::UpdateDisplayedChartDirList(ArrayOfCDI p) {
7057 // Called by pluginmanager after adding single chart to database
7058
7059 ActiveChartArray.Clear();
7060 for (size_t i = 0; i < p.GetCount(); i++) {
7061 ActiveChartArray.Add(p[i]);
7062 }
7063
7064 UpdateChartDirList();
7065}
7066
7067void options::UpdateWorkArrayFromDisplayPanel() {
7068 wxString dirname;
7069 int n = ActiveChartArray.GetCount();
7070 if (m_pWorkDirList) {
7071 m_pWorkDirList->Clear();
7072 for (int i = 0; i < n; i++) {
7073 dirname = ActiveChartArray[i].fullpath;
7074 if (!dirname.IsEmpty()) {
7075 // This is a fix for OSX, which appends EOL to results of
7076 // GetLineText()
7077 while ((dirname.Last() == wxChar(_T('\n'))) ||
7078 (dirname.Last() == wxChar(_T('\r'))))
7079 dirname.RemoveLast();
7080
7081 // scan the current array to find a match
7082 // if found, add the info to the work list, preserving the magic
7083 // number
7084 // If not found, make a new ChartDirInfo, and add it
7085 bool b_added = FALSE;
7086 // if(m_pCurrentDirList)
7087 {
7088 int nDir = m_CurrentDirList.GetCount();
7089
7090 for (int i = 0; i < nDir; i++) {
7091 if (m_CurrentDirList[i].fullpath == dirname) {
7092 ChartDirInfo cdi = m_CurrentDirList[i];
7093 m_pWorkDirList->Add(cdi);
7094 b_added = TRUE;
7095 break;
7096 }
7097 }
7098 }
7099 if (!b_added) {
7100 ChartDirInfo cdin;
7101 cdin.fullpath = dirname;
7102 m_pWorkDirList->Add(cdin);
7103 }
7104 }
7105 }
7106 }
7107}
7108
7109void options::OnApplyClick(wxCommandEvent& event) {
7110 ApplyChanges(event);
7111
7112 // Complete processing
7113 // Force reload of options dialog to pick up font changes, locale changes,
7114 // or other major layout changes
7115 if ((m_returnChanges & FONT_CHANGED) ||
7116 (m_returnChanges & NEED_NEW_OPTIONS)) {
7117 // This will require an options reload
7118 // Clear the plugin options pages toggle
7119 if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxOK);
7120
7121 m_callbacks.prepare_close(this, m_returnChanges);
7122 if (!(m_returnChanges & FONT_CHANGED_SAFE))
7123 top_frame::Get()->ScheduleReconfigAndSettingsReload(true, true);
7124 } else {
7125 // If we had a config change,
7126 // then schedule a re-entry to the settings dialog
7127 if ((m_returnChanges & CONFIG_CHANGED)) {
7128 top_frame::Get()->ScheduleReconfigAndSettingsReload(true, false);
7129 }
7130 }
7131}
7132
7133void options::ApplyChanges(wxCommandEvent& event) {
7134 //::wxBeginBusyCursor();
7135 // FIXME This function is in ConnectionsDialog StopBTScan();
7136
7137 // Start with the stuff that requires intelligent validation.
7138
7139 if (m_pShipIconType->GetSelection() > 0) {
7140 double n_ownship_length_meters;
7141 double n_ownship_beam_meters;
7142 double n_gps_antenna_offset_y;
7143 double n_gps_antenna_offset_x;
7144 long n_ownship_min_mm;
7145 m_pOSLength->GetValue().ToDouble(&n_ownship_length_meters);
7146 m_pOSWidth->GetValue().ToDouble(&n_ownship_beam_meters);
7147 m_pOSGPSOffsetX->GetValue().ToDouble(&n_gps_antenna_offset_x);
7148 m_pOSGPSOffsetY->GetValue().ToDouble(&n_gps_antenna_offset_y);
7149 m_pOSMinSize->GetValue().ToLong(&n_ownship_min_mm);
7150 wxString msg;
7151 if (n_ownship_length_meters <= 0)
7152 msg += _("\n - your ship's length must be > 0");
7153 if (n_ownship_beam_meters <= 0)
7154 msg += _("\n - your ship's beam must be > 0");
7155 if (fabs(n_gps_antenna_offset_x) > n_ownship_beam_meters / 2.0)
7156 msg += _(
7157 "\n - your GPS offset from midship must be within your ship's beam");
7158 if (n_gps_antenna_offset_y < 0 ||
7159 n_gps_antenna_offset_y > n_ownship_length_meters)
7160 msg +=
7161 _("\n - your GPS offset from bow must be within your ship's length");
7162 if (n_ownship_min_mm <= 0 || n_ownship_min_mm > 100)
7163 msg += _("\n - your minimum ship icon size must be between 1 and 100 mm");
7164 if (!msg.IsEmpty()) {
7165 msg.Prepend(_("The settings for own ship real size are not correct:"));
7166 OCPNMessageBox(this, msg, _("OpenCPN info"), wxICON_ERROR | wxOK);
7167 ::wxEndBusyCursor();
7168 event.SetInt(wxID_STOP);
7169 return;
7170 }
7171 g_n_ownship_length_meters = n_ownship_length_meters;
7172 g_n_ownship_beam_meters = n_ownship_beam_meters;
7173 g_n_gps_antenna_offset_y = n_gps_antenna_offset_y;
7174 g_n_gps_antenna_offset_x = n_gps_antenna_offset_x;
7175 g_n_ownship_min_mm = static_cast<int>(n_ownship_min_mm);
7176 }
7177 g_OwnShipIconType = m_pShipIconType->GetSelection();
7178 g_bShowShipToActive = pShowshipToActive->GetValue();
7179 g_shipToActiveStyle = m_shipToActiveStyle->GetSelection();
7180 g_shipToActiveColor = m_shipToActiveColor->GetSelection();
7181
7182 m_pText_ACRadius->GetValue().ToDouble(&g_n_arrival_circle_radius);
7183 g_n_arrival_circle_radius =
7184 wxClip(g_n_arrival_circle_radius, 0.001, 0.6); // Correct abnormally
7185
7186 wxString* icon_name =
7187 pWayPointMan->GetIconKey(pWaypointDefaultIconChoice->GetSelection());
7188 if (icon_name && icon_name->Length()) g_default_wp_icon = *icon_name;
7189
7190 icon_name =
7191 pWayPointMan->GetIconKey(pRoutepointDefaultIconChoice->GetSelection());
7192 if (icon_name && icon_name->Length()) g_default_routepoint_icon = *icon_name;
7193
7194 g_bUseWptScaMin = pScaMinChckB->GetValue();
7195 g_iWpt_ScaMin = wxAtoi(m_pText_ScaMin->GetValue());
7196 g_iWpt_ScaMax = wxAtoi(m_pText_ScaMax->GetValue());
7197 g_bOverruleScaMin = pScaMinOverruleChckB->GetValue();
7198
7199 // Any Font changes?
7200 if (m_bfontChanged) {
7201#ifdef ocpnUSE_GL
7202 if (top_frame::Get()->GetWxGlCanvas()) {
7203 top_frame::Get()->GetAbstractPrimaryCanvas()->ResetGridFont();
7204 }
7205#endif
7206 if (top_frame::Get()->GetAbstractPrimaryCanvas()) {
7207 top_frame::Get()->GetAbstractPrimaryCanvas()->ResetGridFont();
7208 }
7209
7210 m_returnChanges |= FONT_CHANGED;
7211
7212 // If the font element changed was not "Dialog", then we don't need a full
7213 // reload
7214 if (m_font_element_array.Index("Dialog") == wxNOT_FOUND)
7215 m_returnChanges |= FONT_CHANGED_SAFE;
7216 }
7217
7218 // Handle Chart Tab
7219 UpdateWorkArrayFromDisplayPanel();
7220
7221 groupsPanel->SetDBDirs(*m_pWorkDirList); // update the Groups tab
7222 groupsPanel->m_treespopulated = FALSE;
7223
7224 int k_force = FORCE_UPDATE;
7225 if (pUpdateCheckBox) {
7226 if (!pUpdateCheckBox->GetValue()) k_force = 0;
7227 pUpdateCheckBox->Enable();
7228 pUpdateCheckBox->SetValue(FALSE);
7229 } else {
7230 k_force = 0;
7231 }
7232
7233 m_returnChanges |= k_force;
7234
7235 int k_scan = SCAN_UPDATE;
7236 if (pScanCheckBox) {
7237 if (!pScanCheckBox->GetValue()) k_scan = 0;
7238 pScanCheckBox->Enable();
7239 pScanCheckBox->SetValue(FALSE);
7240 } else {
7241 k_scan = 0;
7242 }
7243
7244 m_returnChanges |= k_scan;
7245
7246 pConfig->UpdateChartDirs(*m_pWorkDirList);
7247
7248 // Chart Groups
7249
7250 if (groupsPanel->modified) {
7251 groupsPanel->EmptyChartGroupArray(g_pGroupArray);
7252 delete g_pGroupArray;
7253 g_pGroupArray = groupsPanel->CloneChartGroupArray(m_pGroupArray);
7254 m_returnChanges |= GROUPS_CHANGED;
7255 }
7256
7257 // Handle Settings Tab
7258 if (m_pConfig) {
7259 g_bShowStatusBar = pShowStatusBar->GetValue();
7260
7261#ifndef __WXOSX__
7262 bool bmenu_shown = g_bShowMenuBar;
7263 if (pShowMenuBar->GetValue() != bmenu_shown)
7264 m_returnChanges |= MENU_CHANGED;
7265 g_bShowMenuBar = pShowMenuBar->GetValue();
7266#endif
7267
7268 g_bShowCompassWin = pShowCompassWin->GetValue();
7269 }
7270
7271 g_bShowChartBar = pShowChartBar->GetValue();
7272#ifndef __ANDROID__
7273 wxString screenmm = pScreenMM->GetValue();
7274 wxStringTokenizer tkz(screenmm, ",");
7276 while (tkz.HasMoreTokens()) {
7277 wxString token = tkz.GetNextToken();
7278 long mm = -1;
7279 if (token.ToLong(&mm) && mm > 0) {
7280 g_config_display_size_mm.push_back(mm);
7281 } else {
7282 g_config_display_size_mm.push_back(0);
7283 }
7284 }
7285 g_config_display_size_manual = pRBSizeManual->GetValue();
7286#endif
7287
7288 // Connections page.
7289 comm_dialog->ApplySettings();
7290
7291 if (pCDOOutlines) g_bShowOutlines = pCDOOutlines->GetValue();
7292 if (pSDisplayGrid) g_bDisplayGrid = pSDisplayGrid->GetValue();
7293
7294 if (pCDOQuilting) {
7295 bool temp_bquilting = pCDOQuilting->GetValue();
7296 // if (!g_bQuiltEnable && temp_bquilting)
7297 // cc1->ReloadVP(); /* compose the quilt */
7298 g_bQuiltEnable = temp_bquilting;
7299 }
7300 // g_bFullScreenQuilt = !pFullScreenQuilt->GetValue();
7301
7302 if (pSDepthUnits) g_bShowDepthUnits = pSDepthUnits->GetValue();
7303 g_bskew_comp = pSkewComp->GetValue();
7304 g_btouch = pMobile->GetValue();
7305 g_bresponsive = pResponsive->GetValue();
7306 g_bRollover = pRollover->GetValue();
7307 g_bShowMuiZoomButtons = pZoomButtons->GetValue();
7308
7309 g_bAutoHideToolbar = pToolbarAutoHideCB->GetValue();
7310
7311 long hide_val = 10;
7312 pToolbarHideSecs->GetValue().ToLong(&hide_val);
7313 g_nAutoHideToolbar = wxMin(static_cast<int>(hide_val), 100);
7314 g_nAutoHideToolbar = wxMax(g_nAutoHideToolbar, 2);
7315
7316 // g_fog_overzoom = !pOverzoomEmphasis->GetValue();
7317 // g_oz_vector_scale = !pOZScaleVector->GetValue();
7318
7319 g_bsmoothpanzoom = pSmoothPanZoom->GetValue();
7320#ifdef __ANDROID__
7321 g_bsmoothpanzoom = false;
7322#endif
7323 if (pSmoothPanZoom) g_bsmoothpanzoom = pSmoothPanZoom->GetValue();
7324#ifdef __ANDROID__
7325 g_bsmoothpanzoom = false;
7326#endif
7327
7328 long update_val = 1;
7329 pCOGUPUpdateSecs->GetValue().ToLong(&update_val);
7330 g_COGAvgSec = wxMin(static_cast<int>(update_val), kMaxCogAverageSeconds);
7331
7332 // TODO if (g_bCourseUp != pCBCourseUp->GetValue()) gFrame->ToggleCourseUp();
7333
7334 if (pCBLookAhead) g_bLookAhead = pCBLookAhead->GetValue();
7335
7336 g_bShowTrue = pCBTrueShow->GetValue();
7337 g_bShowMag = pCBMagShow->GetValue();
7338
7339 auto loader = PluginLoader::GetInstance();
7340 b_haveWMM = loader && loader->IsPlugInAvailable("WMM");
7341 if (!b_haveWMM && !b_oldhaveWMM) {
7342 pMagVar->GetValue().ToDouble(&g_UserVar);
7343 gVar = g_UserVar;
7344 }
7345
7346 g_OwnShipmmsi = wxAtoi(m_pTxt_OwnMMSI->GetValue());
7347 m_pText_OSCOG_Predictor->GetValue().ToDouble(&g_ownship_predictor_minutes);
7348 m_pText_OSHDT_Predictor->GetValue().ToDouble(&g_ownship_HDTpredictor_miles);
7349
7350 double temp_dbl;
7351 g_iNavAidRadarRingsNumberVisible =
7352 pNavAidRadarRingsNumberVisible->GetSelection();
7353 g_bNavAidRadarRingsShown = g_iNavAidRadarRingsNumberVisible > 0;
7354 if (pNavAidRadarRingsStep->GetValue().ToDouble(&temp_dbl))
7355 g_fNavAidRadarRingsStep = temp_dbl;
7356 g_pNavAidRadarRingsStepUnits = m_itemRadarRingsUnits->GetSelection();
7357 g_iWaypointRangeRingsNumber = pWaypointRangeRingsNumber->GetSelection();
7358 if (pWaypointRangeRingsStep->GetValue().ToDouble(&temp_dbl))
7359 g_fWaypointRangeRingsStep = temp_dbl;
7360 g_iWaypointRangeRingsStepUnits =
7361 m_itemWaypointRangeRingsUnits->GetSelection();
7363 m_colourWaypointRangeRingsColour->GetColour();
7365 wxColour(g_colourWaypointRangeRingsColour.Red(),
7368 g_bWayPointPreventDragging = pWayPointPreventDragging->GetValue();
7369
7370 g_bConfirmObjectDelete = pConfirmObjectDeletion->GetValue();
7371
7372 if (pPreserveScale) g_bPreserveScaleOnX = pPreserveScale->GetValue();
7373
7374 if (pCmdSoundString) {
7375 g_CmdSoundString = pCmdSoundString->GetValue();
7376 if (wxIsEmpty(g_CmdSoundString)) {
7377 g_CmdSoundString = wxString(OCPN_SOUND_CMD);
7378 pCmdSoundString->SetValue(g_CmdSoundString);
7379 }
7380 }
7381
7382 g_bPlayShipsBells = pPlayShipsBells->GetValue();
7383 if (pSoundDeviceIndex)
7384 g_iSoundDeviceIndex = pSoundDeviceIndex->GetSelection();
7385 // g_bTransparentToolbar = pTransparentToolbar->GetValue();
7386 g_iSDMMFormat = pSDMMFormat->GetSelection();
7387 // Map dropdown selection index explicitly to DISTANCE_* enum.
7388 {
7389 int sel = pDistanceFormat->GetSelection();
7390 g_iDistanceFormat = GetDistanceFormatEnum(sel);
7391 }
7392 g_iSpeedFormat = pSpeedFormat->GetSelection();
7393 g_iWindSpeedFormat = pWindSpeedFormat->GetSelection();
7394 g_iTempFormat = pTempFormat->GetSelection();
7395 if (pHeightUnitSelect) g_iHeightFormat = pHeightUnitSelect->GetSelection();
7396
7397 // LIVE ETA OPTION
7398 if (pSLiveETA) g_bShowLiveETA = pSLiveETA->GetValue();
7399 if (pSDefaultBoatSpeed)
7400 pSDefaultBoatSpeed->GetValue().ToDouble(&g_defaultBoatSpeedUserUnit);
7401 g_defaultBoatSpeed = fromUsrSpeed(g_defaultBoatSpeedUserUnit);
7402 m_Text_def_boat_speed->SetLabel(_("Default Boat Speed ") + "(" +
7403 getUsrSpeedUnit() + ")");
7404
7405 g_bAdvanceRouteWaypointOnArrivalOnly =
7406 pAdvanceRouteWaypointOnArrivalOnly->GetValue();
7407
7408 g_colourTrackLineColour = m_colourTrackLineColour->GetColour();
7409 g_colourTrackLineColour =
7410 wxColour(g_colourTrackLineColour.Red(), g_colourTrackLineColour.Green(),
7411 g_colourTrackLineColour.Blue());
7412 g_nTrackPrecision = pTrackPrecision->GetSelection();
7413
7414 g_bTrackDaily = pTrackDaily->GetValue();
7415
7416 g_track_rotate_time = 0;
7417#if wxUSE_TIMEPICKCTRL
7418 int h, m, s;
7419 if (pTrackRotateTime && pTrackRotateTime->GetTime(&h, &m, &s))
7420 g_track_rotate_time = h * 3600 + m * 60 + s;
7421#endif
7422
7423 if (pTrackRotateUTC->GetValue())
7424 g_track_rotate_time_type = TIME_TYPE_UTC;
7425 else if (pTrackRotateLMT->GetValue())
7426 g_track_rotate_time_type = TIME_TYPE_LMT;
7427 else
7428 g_track_rotate_time_type = TIME_TYPE_COMPUTER;
7429
7430 g_bHighliteTracks = pTrackHighlite->GetValue();
7431
7432 if (pTimezoneUTC->GetValue())
7433 g_datetime_format = "UTC";
7434 else if (pTimezoneLocalTime->GetValue())
7435 g_datetime_format = "Local Time";
7436
7437 if (pEnableZoomToCursor)
7438 g_bEnableZoomToCursor = pEnableZoomToCursor->GetValue();
7439
7440 if (pEnableTenHertz) g_btenhertz = pEnableTenHertz->GetValue();
7441
7442#ifdef __ANDROID__
7443 g_bEnableZoomToCursor = false;
7444#endif
7445
7446 g_colourOwnshipRangeRingsColour = m_colourOwnshipRangeRingColour->GetColour();
7447 g_colourOwnshipRangeRingsColour =
7448 wxColour(g_colourOwnshipRangeRingsColour.Red(),
7449 g_colourOwnshipRangeRingsColour.Green(),
7450 g_colourOwnshipRangeRingsColour.Blue());
7451
7452 // Sounds
7453 g_bAIS_GCPA_Alert_Audio = m_soundPanelAIS->GetCheckBox()->GetValue();
7454 g_bAIS_SART_Alert_Audio = m_soundPanelSART->GetCheckBox()->GetValue();
7455 g_bAIS_DSC_Alert_Audio = m_soundPanelDSC->GetCheckBox()->GetValue();
7456 g_bAnchor_Alert_Audio = m_soundPanelAnchor->GetCheckBox()->GetValue();
7457
7458 // AIS Parameters
7459 // CPA Box
7460 g_bCPAMax = m_pCheck_CPA_Max->GetValue();
7461 m_pText_CPA_Max->GetValue().ToDouble(&g_CPAMax_NM);
7462 g_bCPAWarn = m_pCheck_CPA_Warn->GetValue();
7463 m_pText_CPA_Warn->GetValue().ToDouble(&g_CPAWarn_NM);
7464 g_bTCPA_Max = m_pCheck_CPA_WarnT->GetValue();
7465 m_pText_CPA_WarnT->GetValue().ToDouble(&g_TCPA_Max);
7466
7467 // Lost Targets
7468 g_bMarkLost = m_pCheck_Mark_Lost->GetValue();
7469 m_pText_Mark_Lost->GetValue().ToDouble(&g_MarkLost_Mins);
7470 g_bRemoveLost = m_pCheck_Remove_Lost->GetValue();
7471 m_pText_Remove_Lost->GetValue().ToDouble(&g_RemoveLost_Mins);
7472
7473 // Display
7474 g_bShowCOG = m_pCheck_Show_COG->GetValue();
7475 // If synchronized with own ship predictor
7476 g_bSyncCogPredictors = m_pCheck_Sync_OCOG_ACOG->GetValue();
7477 if (g_bSyncCogPredictors) {
7478 m_pText_COG_Predictor->SetValue(m_pText_OSCOG_Predictor->GetValue());
7479 }
7480 m_pText_COG_Predictor->GetValue().ToDouble(&g_ShowCOG_Mins);
7481
7482 g_bAISShowTracks = m_pCheck_Show_Tracks->GetValue();
7483 m_pText_Track_Length->GetValue().ToDouble(&g_AISShowTracks_Mins);
7484
7485 // Update all the current targets
7486 if (g_pAIS) {
7487 for (const auto& it : g_pAIS->GetTargetList()) {
7488 auto pAISTarget = it.second;
7489 if (NULL != pAISTarget) {
7490 pAISTarget->b_show_track = g_bAISShowTracks;
7491 // Check for exceptions in MMSI properties
7492 for (unsigned int i = 0; i < g_MMSI_Props_Array.GetCount(); i++) {
7493 if (pAISTarget->MMSI == g_MMSI_Props_Array[i]->MMSI) {
7495 if (TRACKTYPE_NEVER == props->TrackType) {
7496 pAISTarget->b_show_track = false;
7497 break;
7498 } else if (TRACKTYPE_ALWAYS == props->TrackType) {
7499 pAISTarget->b_show_track = true;
7500 break;
7501 } else
7502 break;
7503 }
7504 }
7505 // Check for any persistently tracked target, force b_show_track ON
7506 std::map<int, Track*>::iterator it;
7507 it = g_pAIS->m_persistent_tracks.find(pAISTarget->MMSI);
7508 if (it != g_pAIS->m_persistent_tracks.end())
7509 pAISTarget->b_show_track = true;
7510 pAISTarget->b_show_track_old = g_bAISShowTracks;
7511 }
7512 }
7513 }
7514
7515 g_bHideMoored = m_pCheck_Hide_Moored->GetValue();
7516 m_pText_Moored_Speed->GetValue().ToDouble(&g_ShowMoored_Kts);
7517
7518 g_bDrawAISRealtime = m_pCheck_Draw_Realtime_Prediction->GetValue();
7519 m_pText_RealtPred_Speed->GetValue().ToDouble(&g_AIS_RealtPred_Kts);
7520
7521 g_bAllowShowScaled = m_pCheck_Scale_Priority->GetValue();
7522 long l;
7523 m_pText_Scale_Priority->GetValue().ToLong(&l);
7524 g_ShowScaled_Num = (int)l;
7525
7526 g_bShowAreaNotices = m_pCheck_Show_Area_Notices->GetValue();
7527 g_bDrawAISSize = m_pCheck_Draw_Target_Size->GetValue();
7528 g_bShowAISName = m_pCheck_Show_Target_Name->GetValue();
7529 long ais_name_scale = 5000;
7530 m_pText_Show_Target_Name_Scale->GetValue().ToLong(&ais_name_scale);
7531 g_Show_Target_Name_Scale = (int)wxMax(5000, ais_name_scale);
7532 g_bWplUsePosition = m_pCheck_use_Wpl->GetValue();
7533 g_WplAction = m_pWplAction->GetSelection();
7534
7535 // Alert
7536 g_bAIS_CPA_Alert = m_pCheck_AlertDialog->GetValue();
7537 g_bAIS_CPA_Alert_Audio = m_pCheck_AlertAudio->GetValue();
7538 g_bAIS_CPA_Alert_Suppress_Moored = m_pCheck_Alert_Moored->GetValue();
7539
7540 g_bAIS_ACK_Timeout = m_pCheck_Ack_Timout->GetValue();
7541 m_pText_ACK_Timeout->GetValue().ToDouble(&g_AckTimeout_Mins);
7542
7543 // Rollover
7544 g_bAISRolloverShowClass = m_pCheck_Rollover_Class->GetValue();
7545 g_bAISRolloverShowCOG = m_pCheck_Rollover_COG->GetValue();
7546 g_bAISRolloverShowCPA = m_pCheck_Rollover_CPA->GetValue();
7547
7548 g_chart_zoom_modifier_raster = m_pSlider_Zoom_Raster->GetValue();
7549 g_chart_zoom_modifier_vector = m_pSlider_Zoom_Vector->GetValue();
7550 g_cm93_zoom_factor = m_pSlider_CM93_Zoom->GetValue();
7551 g_GUIScaleFactor = m_pSlider_GUI_Factor->GetValue();
7552
7553 bool bchange_scale = false;
7554 if (g_ChartScaleFactor != m_pSlider_Chart_Factor->GetValue())
7555 bchange_scale = true;
7556 g_ChartScaleFactor = m_pSlider_Chart_Factor->GetValue();
7557
7559 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
7560 g_MarkScaleFactorExp = g_Platform->GetMarkScaleFactorExp(g_ChartScaleFactor);
7561 g_ShipScaleFactor = m_pSlider_Ship_Factor->GetValue();
7562 g_ShipScaleFactorExp = g_Platform->GetChartScaleFactorExp(g_ShipScaleFactor);
7563 g_ENCSoundingScaleFactor = m_pSlider_Text_Factor->GetValue();
7564 g_ENCTextScaleFactor = m_pSlider_ENCText_Factor->GetValue();
7565
7566 g_mouse_zoom_sensitivity_ui = m_pMouse_Zoom_Slider->GetValue();
7567 g_mouse_zoom_sensitivity =
7568 MouseZoom::ui_to_config(g_mouse_zoom_sensitivity_ui);
7569
7570 // Only reload the icons if user has actually visted the UI page
7571 if (m_bVisitLang) {
7572 if (pWayPointMan) WayPointmanGui(*pWayPointMan).ReloadRoutepointIcons();
7573 }
7574
7575 // FIXME Move these two
7576 // g_NMEAAPBPrecision = m_choicePrecision->GetCurrentSelection();
7577 // g_TalkerIdText = m_TalkerIdText->GetValue().MakeUpper();
7578
7579#ifdef ocpnUSE_GL
7580 if (g_bopengl != pOpenGL->GetValue()) m_returnChanges |= GL_CHANGED;
7581 g_bopengl = pOpenGL->GetValue();
7582#endif
7583
7584 g_bChartBarEx = pChartBarEX->GetValue();
7585
7586 // Handle Vector Charts Tab
7587 int depthUnit = pDepthUnitSelect->GetSelection();
7588 g_nDepthUnitDisplay = depthUnit;
7589
7590 // Process the UserStandard display list, noting if any changes were made
7591 bool bUserStdChange = false;
7592
7593 int nOBJL = ps57CtlListBox->GetCount();
7594
7595 for (int iPtr = 0; iPtr < nOBJL; iPtr++) {
7596 int itemIndex = -1;
7597 for (size_t i = 0; i < marinersStdXref.size(); i++) {
7598 if (marinersStdXref[i] == iPtr) {
7599 itemIndex = i;
7600 break;
7601 }
7602 }
7603 assert(itemIndex >= 0);
7604 OBJLElement* pOLE = (OBJLElement*)(ps52plib->pOBJLArray->Item(itemIndex));
7605 if (pOLE->nViz != (int)(ps57CtlListBox->IsChecked(iPtr)))
7606 bUserStdChange = true;
7607 pOLE->nViz = ps57CtlListBox->IsChecked(iPtr);
7608 }
7609
7610 if (ps52plib) {
7611 // Take a snapshot of the S52 config right now,
7612 // for later comparison
7613 ps52plib->GenerateStateHash();
7614 long stateHash = ps52plib->GetStateHash();
7615
7616 if (m_returnChanges & GL_CHANGED) {
7617 // Do this now to handle the screen refresh that is automatically
7618 // generated on Windows at closure of the options dialog...
7619 ps52plib->FlushSymbolCaches(ChartCtxFactory());
7620 // some CNSY depends on renderer (e.g. CARC)
7621 ps52plib->ClearCNSYLUPArray();
7622 ps52plib->GenerateStateHash();
7623 }
7624
7625 if (pDispCat) {
7626 enum _DisCat nset = OTHER;
7627 switch (pDispCat->GetSelection()) {
7628 case 0:
7629 nset = DISPLAYBASE;
7630 break;
7631 case 1:
7632 nset = STANDARD;
7633 break;
7634 case 2:
7635 nset = OTHER;
7636 break;
7637 case 3:
7638 nset = MARINERS_STANDARD;
7639 break;
7640 }
7641 ps52plib->SetDisplayCategory(nset);
7642 }
7643
7644 if (pCheck_SOUNDG) ps52plib->m_bShowSoundg = pCheck_SOUNDG->GetValue();
7645 if (pCheck_ATONTEXT)
7646 ps52plib->m_bShowAtonText = pCheck_ATONTEXT->GetValue();
7647 if (pCheck_LDISTEXT)
7648 ps52plib->m_bShowLdisText = pCheck_LDISTEXT->GetValue();
7649 if (pCheck_XLSECTTEXT)
7650 ps52plib->m_bExtendLightSectors = pCheck_XLSECTTEXT->GetValue();
7651
7652 ps52plib->m_bShowMeta = pCheck_META->GetValue();
7653 ps52plib->m_bDeClutterText = pCheck_DECLTEXT->GetValue();
7654 ps52plib->m_bShowNationalTexts = pCheck_NATIONALTEXT->GetValue();
7655 ps52plib->m_bShowS57ImportantTextOnly = pCheck_SHOWIMPTEXT->GetValue();
7656 ps52plib->m_bUseSCAMIN = pCheck_SCAMIN->GetValue();
7657 ps52plib->m_bUseSUPER_SCAMIN = pCheck_SuperSCAMIN->GetValue();
7658
7659 ps52plib->m_nSymbolStyle =
7660 pPointStyle->GetSelection() == 0 ? PAPER_CHART : SIMPLIFIED;
7661
7662 ps52plib->m_nBoundaryStyle = pBoundStyle->GetSelection() == 0
7663 ? PLAIN_BOUNDARIES
7664 : SYMBOLIZED_BOUNDARIES;
7665 ps52plib->m_nSoundingFactor = m_pSlider_Text_Factor->GetValue();
7666 ps52plib->m_nTextFactor = m_pSlider_ENCText_Factor->GetValue();
7667
7668 S52_setMarinerParam(S52_MAR_TWO_SHADES,
7669 (p24Color->GetSelection() == 0) ? 1.0 : 0.0);
7670
7671 // Depths
7672 double dval;
7673 float conv = 1;
7674
7675 if (depthUnit == 0) // feet
7676 conv = 0.3048f; // international definiton of 1 foot is 0.3048 metres
7677 else if (depthUnit == 2) // fathoms
7678 conv = 0.3048f * 6; // 1 fathom is 6 feet
7679
7680 if (m_SafetyCtl->GetValue().ToDouble(&dval)) {
7681 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH,
7682 dval * conv); // controls sounding display
7683 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR,
7684 dval * conv); // controls colour
7685 }
7686
7687 if (m_ShallowCtl->GetValue().ToDouble(&dval))
7688 S52_setMarinerParam(S52_MAR_SHALLOW_CONTOUR, dval * conv);
7689
7690 if (m_DeepCtl->GetValue().ToDouble(&dval))
7691 S52_setMarinerParam(S52_MAR_DEEP_CONTOUR, dval * conv);
7692
7693 ps52plib->UpdateMarinerParams();
7694 ps52plib->m_nDepthUnitDisplay = depthUnit;
7695 // Keep s52plib height display in sync with height preference
7696 ps52plib->m_nHeightUnitDisplay = g_iHeightFormat;
7697
7698 ps52plib->GenerateStateHash();
7699
7700 // Detect a change to S52 library config
7701 if ((stateHash != ps52plib->GetStateHash()) || bUserStdChange)
7702 m_returnChanges |= S52_CHANGED;
7703
7704 if (bchange_scale) m_returnChanges |= S52_CHANGED;
7705 }
7706
7707// User Interface Panel
7708#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
7709 if (m_bVisitLang) {
7710 wxString new_canon = "en_US";
7711 wxString lang_sel = m_itemLangListBox->GetStringSelection();
7712
7713 int nLang = sizeof(lang_list) / sizeof(int);
7714 for (int it = 0; it < nLang; it++) {
7715 const wxLanguageInfo* pli = wxLocale::GetLanguageInfo(lang_list[it]);
7716 if (pli) {
7717 wxString lang_canonical = pli->CanonicalName;
7718 wxString test_string = GetOCPNKnownLanguage(lang_canonical);
7719 if (lang_sel == test_string) {
7720 new_canon = lang_canonical;
7721 break;
7722 }
7723 }
7724 }
7725
7726 wxString locale_old = g_locale;
7727 g_locale = new_canon;
7728
7729 if (g_locale != locale_old) m_returnChanges |= LOCALE_CHANGED;
7730
7731 wxString oldStyle = g_StyleManager->GetCurrentStyle()->name;
7732 // g_StyleManager->SetStyleNextInvocation(
7733 // m_itemStyleListBox->GetStringSelection());
7734 if (g_StyleManager->GetStyleNextInvocation() != oldStyle) {
7735 m_returnChanges |= STYLE_CHANGED;
7736 }
7737 wxSizeEvent nullEvent;
7738 top_frame::Get()->OnSize(nullEvent);
7739 }
7740#endif
7741 if (g_bInlandEcdis != pInlandEcdis->GetValue()) { // InlandEcdis changed
7742 g_bInlandEcdis = pInlandEcdis->GetValue();
7743 SwitchInlandEcdisMode(g_bInlandEcdis);
7744 m_returnChanges |= TOOLBAR_CHANGED;
7745 }
7746
7747 if (pHiconColors) g_hicon_colors = pHiconColors->GetValue();
7748
7749 // PlugIn Manager Panel
7750 // Pick up any changes to selections
7751 if (PluginLoader::GetInstance()->UpdatePlugIns())
7752 m_returnChanges |= TOOLBAR_CHANGED;
7753
7754 // And keep config in sync
7755 // if (m_pPlugInCtrl) m_pPlugInCtrl->UpdatePluginsOrder(); FIXME(leamas)
7756 g_pi_manager->UpdateConfig();
7757
7758 m_returnChanges |= GENERIC_CHANGED | k_vectorcharts | k_charts |
7759 m_groups_changed | k_plugins;
7760
7761 // Pick up all the entries in the Tide/current DataSelected control
7762 // and update the global static array if changed
7763 // Get signature of existing array
7764 wxString string_acc;
7765 for (wxString entry : TideCurrentDataSet) {
7766 string_acc += entry;
7767 }
7768 // Get signature for options control
7769 wxString string_acc_control;
7770 for (int i = 0; i < tcDataSelected->GetItemCount(); i++) {
7771 wxString setName = tcDataSelected->GetItemText(i);
7772 string_acc_control += setName;
7773 }
7774 // Any change?
7775 if (!string_acc.IsSameAs(string_acc_control)) {
7776 TideCurrentDataSet.clear();
7777 int nEntry = tcDataSelected->GetItemCount();
7778 for (int i = 0; i < nEntry; i++) {
7779 wxString setName = tcDataSelected->GetItemText(i);
7780 TideCurrentDataSet.push_back(setName.ToStdString());
7781 }
7782 m_returnChanges |= TIDES_CHANGED;
7783 }
7784
7785 if (g_canvasConfig != m_screenConfig) m_returnChanges |= CONFIG_CHANGED;
7786 g_canvasConfig = m_screenConfig;
7787
7788 UpdateWorkArrayFromDisplayPanel();
7789
7790 // Start a chartdbs update directly, if required
7791 if ((m_returnChanges & VISIT_CHARTS) &&
7792 ((m_returnChanges & CHANGE_CHARTS) || (m_returnChanges & SCAN_UPDATE))) {
7793 DoDBSUpdate((m_returnChanges & FORCE_UPDATE) == FORCE_UPDATE);
7794 } else {
7795 bool b_groupchange = ChartData->ScrubGroupArray();
7796 ChartData->ApplyGroupArray(g_pGroupArray);
7797 if (b_groupchange ||
7798 ((m_returnChanges & GROUPS_CHANGED) == GROUPS_CHANGED)) {
7799 pConfig->DestroyConfigGroups();
7800 pConfig->CreateConfigGroups(g_pGroupArray);
7801 }
7802 if ((m_returnChanges & GROUPS_CHANGED) == GROUPS_CHANGED)
7803 ChartData->ApplyGroupArray(g_pGroupArray);
7804 }
7805
7806 m_callbacks.process_dialog(m_returnChanges, m_pWorkDirList);
7807
7808 // We can clear a few flag bits on "Apply", so they won't be recognised at
7809 // the "Close" click. Their actions have already been accomplished once...
7810 m_returnChanges &= ~(CHANGE_CHARTS | FORCE_UPDATE | SCAN_UPDATE);
7811 k_charts = 0;
7812
7813 top_frame::Get()->RefreshAllCanvas();
7814
7815 // Some layout changes requiring a new options instance?
7816 if (m_bneedNew) m_returnChanges |= NEED_NEW_OPTIONS;
7817
7818 if (m_bVisitPlugins) m_returnChanges |= FORCE_RELOAD;
7819
7820 // Record notice of any changes to last applied template
7821 UpdateTemplateTitleText();
7822
7823 if (::wxIsBusy()) // FIXME: Not sure why this is needed here
7824 ::wxEndBusyCursor();
7825}
7826
7827void options::OnXidOkClick(wxCommandEvent& event) {
7828 // When closing the form with Ctrl-Enter sometimes we get double events, the
7829 // second is empty??
7830 if (event.GetEventObject() == NULL) return;
7831
7832 ApplyChanges(event);
7833
7834 // Complete processing
7835 m_callbacks.prepare_close(this, m_returnChanges);
7836
7837 // If we had a config change, then do it now
7838 if ((m_returnChanges & CONFIG_CHANGED) || (m_returnChanges & GL_CHANGED))
7839 top_frame::Get()->ScheduleReconfigAndSettingsReload(false, false);
7840
7841 // Special case for "Dialog" font edit
7842 if ((m_returnChanges & FONT_CHANGED) &&
7843 !(m_returnChanges & FONT_CHANGED_SAFE))
7844 top_frame::Get()->ScheduleDeleteSettingsDialog();
7845
7846 // And for locale change
7847 if (m_returnChanges & LOCALE_CHANGED)
7848 top_frame::Get()->ScheduleDeleteSettingsDialog();
7849
7850 if ((m_returnChanges & FONT_CHANGED) ||
7851 (m_returnChanges & NEED_NEW_OPTIONS)) {
7852 // This will require an options reload
7853 // Clear the plugin options pages toggle
7854 if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxOK);
7855 }
7856
7857 // Also for FORCE_RELOAD
7858 if (m_returnChanges & FORCE_RELOAD) top_frame::Get()->ScheduleReloadCharts();
7859
7860 Finish();
7861 Hide();
7862}
7863
7864void options::Finish() {
7865 // Required to avoid intermittent crash on wxGTK
7866 m_pListbook->ChangeSelection(0);
7867 for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
7868 wxNotebookPage* pg = m_pListbook->GetPage(i);
7869 wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
7870 if (nb) nb->ChangeSelection(0);
7871 }
7872
7873 lastWindowPos = GetPosition();
7874 lastWindowSize = GetSize();
7875
7876 pConfig->SetPath("/Settings");
7877 pConfig->Write("OptionsSizeX", lastWindowSize.x);
7878 pConfig->Write("OptionsSizeY", lastWindowSize.y);
7879}
7880
7881ArrayOfCDI options::GetSelectedChartDirs() {
7882 ArrayOfCDI rv;
7883 for (size_t i = 0; i < panelVector.size(); i++) {
7884 if (panelVector[i]->IsSelected()) {
7885 rv.Add(panelVector[i]->GetCDI());
7886 }
7887 }
7888
7889 return rv;
7890}
7891
7892ArrayOfCDI options::GetUnSelectedChartDirs() {
7893 ArrayOfCDI rv;
7894 for (size_t i = 0; i < panelVector.size(); i++) {
7895 if (!panelVector[i]->IsSelected()) {
7896 rv.Add(panelVector[i]->GetCDI());
7897 }
7898 }
7899
7900 return rv;
7901}
7902
7903void options::SetDirActionButtons() {
7904 ArrayOfCDI selArray = GetSelectedChartDirs();
7905 if (selArray.GetCount())
7906 m_removeBtn->Enable();
7907 else
7908 m_removeBtn->Disable();
7909}
7910
7911void options::OnButtondeleteClick(wxCommandEvent& event) {
7912 ArrayOfCDI unselArray = GetUnSelectedChartDirs();
7913 ActiveChartArray.Clear();
7914 for (size_t i = 0; i < unselArray.GetCount(); i++) {
7915 ActiveChartArray.Add(unselArray[i]);
7916 }
7917
7918 UpdateChartDirList();
7919
7920 UpdateWorkArrayFromDisplayPanel();
7921
7922#if 0
7923 if (m_pWorkDirList) {
7924 pActiveChartsList->DeleteAllItems();
7925 for (size_t id = 0; id < m_pWorkDirList->GetCount(); id++) {
7926 wxString dirname = m_pWorkDirList->Item(id).fullpath;
7927 wxListItem li;
7928 li.SetId(id);
7929 li.SetAlign(wxLIST_FORMAT_LEFT);
7930 li.SetText(dirname);
7931 li.SetColumn(0);
7932 long idx = pActiveChartsList->InsertItem(li);
7933 }
7934 }
7935#endif
7936
7937 k_charts |= CHANGE_CHARTS;
7938
7939 pScanCheckBox->Disable();
7940
7941 event.Skip();
7942}
7943
7944void options::DoDBSUpdate(bool force_full) {
7945 m_OKButton->Disable();
7946 m_CancelButton->Disable();
7947 m_ApplyButton->Disable();
7948
7949 wxString longmsg = _("OpenCPN Chart Update");
7950 longmsg +=
7951 ".................................................................."
7952 "........";
7953
7954 m_pCBDSprog = new wxGenericProgressDialog();
7955
7956 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
7957 m_pCBDSprog->SetFont(*qFont);
7958
7959 //
7960 m_pCBDSprog->Create(_("OpenCPN Chart Update"), longmsg, 100, nullptr,
7961 wxPD_SMOOTH);
7962
7963 DimeControl(m_pCBDSprog);
7964 m_pCBDSprog->Show();
7965
7966 ChartData->PurgeCache();
7967
7968 // Disable texture compression cacheing
7969 m_bTextureCacheingSave = g_GLOptions.m_bTextureCompressionCaching;
7970 g_GLOptions.m_bTextureCompressionCaching = false;
7971
7972 ChartData->UpdateChartDatabaseInplace(*m_pWorkDirList, force_full,
7973 m_pCBDSprog);
7974}
7975
7976void options::OnButtonRebuildChartDb(wxCommandEvent& event) {
7977 DoDBSUpdate(true); // Force full update
7978}
7979
7980void options::OnButtonParseENC(wxCommandEvent& event) {
7981 top_frame::Get()->GetAbstractPrimaryCanvas()->EnablePaint(false);
7982
7983 extern void ParseAllENC(wxWindow * parent);
7984
7985 ParseAllENC(g_pOptions);
7986
7987 ViewPort vp;
7988 top_frame::Get()->ChartsRefresh();
7989
7990 top_frame::Get()->GetAbstractPrimaryCanvas()->EnablePaint(true);
7991}
7992
7993#ifdef OCPN_USE_LZMA
7994#include <lzma.h>
7995
7996static bool compress(lzma_stream* strm, FILE* infile, FILE* outfile) {
7997 // This will be LZMA_RUN until the end of the input file is reached.
7998 // This tells lzma_code() when there will be no more input.
7999 lzma_action action = LZMA_RUN;
8000
8001 // Buffers to temporarily hold uncompressed input
8002 // and compressed output.
8003 uint8_t inbuf[BUFSIZ];
8004 uint8_t outbuf[BUFSIZ];
8005
8006 // Initialize the input and output pointers. Initializing next_in
8007 // and avail_in isn't really necessary when we are going to encode
8008 // just one file since LZMA_STREAM_INIT takes care of initializing
8009 // those already. But it doesn't hurt much and it will be needed
8010 // if encoding more than one file like we will in 02_decompress.c.
8011 //
8012 // While we don't care about strm->total_in or strm->total_out in this
8013 // example, it is worth noting that initializing the encoder will
8014 // always reset total_in and total_out to zero. But the encoder
8015 // initialization doesn't touch next_in, avail_in, next_out, or
8016 // avail_out.
8017 strm->next_in = NULL;
8018 strm->avail_in = 0;
8019 strm->next_out = outbuf;
8020 strm->avail_out = sizeof(outbuf);
8021
8022 // Loop until the file has been successfully compressed or until
8023 // an error occurs.
8024 while (true) {
8025 // Fill the input buffer if it is empty.
8026 if (strm->avail_in == 0 && !feof(infile)) {
8027 strm->next_in = inbuf;
8028 strm->avail_in = fread(inbuf, 1, sizeof(inbuf), infile);
8029
8030 if (ferror(infile)) {
8031 fprintf(stderr, "Read error: %s\n", strerror(errno));
8032 return false;
8033 }
8034
8035 // Once the end of the input file has been reached,
8036 // we need to tell lzma_code() that no more input
8037 // will be coming and that it should finish the
8038 // encoding.
8039 if (feof(infile)) action = LZMA_FINISH;
8040 }
8041
8042 // Tell liblzma do the actual encoding.
8043 //
8044 // This reads up to strm->avail_in bytes of input starting
8045 // from strm->next_in. avail_in will be decremented and
8046 // next_in incremented by an equal amount to match the
8047 // number of input bytes consumed.
8048 //
8049 // Up to strm->avail_out bytes of compressed output will be
8050 // written starting from strm->next_out. avail_out and next_out
8051 // will be incremented by an equal amount to match the number
8052 // of output bytes written.
8053 //
8054 // The encoder has to do internal buffering, which means that
8055 // it may take quite a bit of input before the same data is
8056 // available in compressed form in the output buffer.
8057 lzma_ret ret = lzma_code(strm, action);
8058
8059 // If the output buffer is full or if the compression finished
8060 // successfully, write the data from the output bufffer to
8061 // the output file.
8062 if (strm->avail_out == 0 || ret == LZMA_STREAM_END) {
8063 // When lzma_code() has returned LZMA_STREAM_END,
8064 // the output buffer is likely to be only partially
8065 // full. Calculate how much new data there is to
8066 // be written to the output file.
8067 size_t write_size = sizeof(outbuf) - strm->avail_out;
8068
8069 if (fwrite(outbuf, 1, write_size, outfile) != write_size) {
8070 fprintf(stderr, "Write error: %s\n", strerror(errno));
8071 return false;
8072 }
8073
8074 // Reset next_out and avail_out.
8075 strm->next_out = outbuf;
8076 strm->avail_out = sizeof(outbuf);
8077 }
8078
8079 // Normally the return value of lzma_code() will be LZMA_OK
8080 // until everything has been encoded.
8081 if (ret != LZMA_OK) {
8082 // Once everything has been encoded successfully, the
8083 // return value of lzma_code() will be LZMA_STREAM_END.
8084 //
8085 // It is important to check for LZMA_STREAM_END. Do not
8086 // assume that getting ret != LZMA_OK would mean that
8087 // everything has gone well.
8088 if (ret == LZMA_STREAM_END) return true;
8089
8090 // It's not LZMA_OK nor LZMA_STREAM_END,
8091 // so it must be an error code. See lzma/base.h
8092 // (src/liblzma/api/lzma/base.h in the source package
8093 // or e.g. /usr/include/lzma/base.h depending on the
8094 // install prefix) for the list and documentation of
8095 // possible values. Most values listen in lzma_ret
8096 // enumeration aren't possible in this example.
8097 const char* msg;
8098 switch (ret) {
8099 case LZMA_MEM_ERROR:
8100 msg = "Memory allocation failed";
8101 break;
8102
8103 case LZMA_DATA_ERROR:
8104 // This error is returned if the compressed
8105 // or uncompressed size get near 8 EiB
8106 // (2^63 bytes) because that's where the .xz
8107 // file format size limits currently are.
8108 // That is, the possibility of this error
8109 // is mostly theoretical unless you are doing
8110 // something very unusual.
8111 //
8112 // Note that strm->total_in and strm->total_out
8113 // have nothing to do with this error. Changing
8114 // those variables won't increase or decrease
8115 // the chance of getting this error.
8116 msg = "File size limits exceeded";
8117 break;
8118
8119 default:
8120 // This is most likely LZMA_PROG_ERROR, but
8121 // if this program is buggy (or liblzma has
8122 // a bug), it may be e.g. LZMA_BUF_ERROR or
8123 // LZMA_OPTIONS_ERROR too.
8124 //
8125 // It is inconvenient to have a separate
8126 // error message for errors that should be
8127 // impossible to occur, but knowing the error
8128 // code is important for debugging. That's why
8129 // it is good to print the error code at least
8130 // when there is no good error message to show.
8131 msg = "Unknown error, possibly a bug";
8132 break;
8133 }
8134
8135 wxLogMessage("LZMA Encoder error: %s (error code %u)\n", msg, ret);
8136 return false;
8137 }
8138 }
8139}
8140#endif
8141
8142static bool CompressChart(wxString in, wxString out) {
8143#ifdef OCPN_USE_LZMA
8144 FILE* infile = fopen(in.mb_str(), "rb");
8145 if (!infile) return false;
8146
8147 FILE* outfile = fopen(out.mb_str(), "wb");
8148 if (!outfile) {
8149 fclose(infile);
8150 return false;
8151 }
8152
8153 lzma_stream strm = LZMA_STREAM_INIT;
8154 bool success = false;
8155 if (lzma_easy_encoder(&strm, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64) ==
8156 LZMA_OK)
8157 success = compress(&strm, infile, outfile);
8158
8159 lzma_end(&strm);
8160 fclose(infile);
8161 fclose(outfile);
8162
8163 return success;
8164#endif
8165 return false;
8166}
8167
8168void options::OnButtonmigrateClick(wxCommandEvent& event) {
8169#ifdef __ANDROID__
8170
8171 // Run the chart migration assistant
8172 g_migrateDialog =
8173 // skip Folder scan
8174 new MigrateAssistantDialog(wxTheApp->GetTopWindow(), true);
8175 g_migrateDialog->SetSize(top_frame::Get()->GetSize());
8176 g_migrateDialog->Centre();
8177 g_migrateDialog->Raise();
8178 g_migrateDialog->ShowModal();
8179#endif
8180}
8181
8182void options::OnButtonEcdisHelp(wxCommandEvent& event) {
8183 wxString testFile = "/doc/iECDIS/index.html";
8184
8185 if (!::wxFileExists(testFile)) {
8186 wxString msg = _("The Inland ECDIS Manual is not available locally.");
8187 msg += "\n";
8188 msg +=
8189 _("Would you like to visit the iECDIS Manual website for more "
8190 "information?");
8191
8192 if (wxID_YES == OCPNMessageBox(NULL, msg, _("Inland ECDIS Manual"),
8193 wxYES_NO | wxCENTER, 60)) {
8194 wxLaunchDefaultBrowser("https://opencpn-manuals.github.io/inland-ecdis");
8195 }
8196 } else {
8197#ifdef __WXMSW__
8198 wxLaunchDefaultBrowser("file:///" + *GetpSharedDataLocation() + testFile);
8199#else
8200 wxLaunchDefaultBrowser("file://" + *GetpSharedDataLocation() + testFile);
8201#endif
8202 }
8203}
8204
8205void options::OnButtoncompressClick(wxCommandEvent& event) {
8206#if 0
8207 wxArrayInt pListBoxSelections;
8208 long item = -1;
8209 for (;;) {
8210 item = pActiveChartsList->GetNextItem(item, wxLIST_NEXT_ALL,
8211 wxLIST_STATE_SELECTED);
8212 if (item == -1) break;
8213 //pListBoxSelections.Add((int)item);
8214 item = -1; // Restart
8215 }
8216
8217 if (OCPNMessageBox(this, _("Compression will alter chart files on disk.\n\
8218This may make them incompatible with other programs or older versions of OpenCPN.\n\
8219Compressed charts may take slightly longer to load and display on some systems.\n\
8220They can be decompressed again using unxz or 7 zip programs."),
8221 _("OpenCPN Warning"),
8222 wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING) !=
8223 wxID_YES)
8224 return;
8225
8226 wxArrayString filespecs;
8227 filespecs.Add("*.kap");
8228 filespecs.Add("*.KAP");
8229 filespecs.Add("*.000");
8230
8231 // should we verify we are in a cm93 directory for these?
8232 filespecs.Add("*.A"), filespecs.Add("*.B"), filespecs.Add("*.C"),
8233 filespecs.Add("*.D");
8234 filespecs.Add("*.E"), filespecs.Add("*.F"), filespecs.Add("*.G"),
8235 filespecs.Add("*.Z");
8236
8237 wxGenericProgressDialog prog1(
8238 _("OpenCPN Compress Charts"), wxEmptyString,
8239 filespecs.GetCount() * pListBoxSelections.GetCount() + 1, this,
8240 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
8241 wxPD_REMAINING_TIME | wxPD_CAN_SKIP);
8242
8243 // Make sure the dialog is big enough to be readable
8244 wxSize sz = prog1.GetSize();
8245 sz.x = top_frame::Get()->GetClientSize().x * 8 / 10;
8246 prog1.SetSize(sz);
8247
8248 wxArrayString charts;
8249 for (unsigned int i = 0; i < pListBoxSelections.GetCount(); i++) {
8250 wxString dirname = pActiveChartsList->GetItemText(pListBoxSelections[i]);
8251 if (dirname.IsEmpty()) continue;
8252 // This is a fix for OSX, which appends EOL to results of
8253 // GetLineText()
8254 while ((dirname.Last() == wxChar(_T('\n'))) ||
8255 (dirname.Last() == wxChar(_T('\r'))))
8256 dirname.RemoveLast();
8257
8258 if (!wxDir::Exists(dirname)) continue;
8259
8260 wxDir dir(dirname);
8261 wxArrayString FileList;
8262 for (unsigned int j = 0; j < filespecs.GetCount(); j++) {
8263 dir.GetAllFiles(dirname, &FileList, filespecs[j]);
8264 bool skip = false;
8265 prog1.Update(i * filespecs.GetCount() + j, dirname + filespecs[j], &skip);
8266 if (skip) return;
8267 }
8268
8269 for (unsigned int j = 0; j < FileList.GetCount(); j++)
8270 charts.Add(FileList[j]);
8271 }
8272 prog1.Hide();
8273
8274 if (charts.GetCount() == 0) {
8275 OCPNMessageBox(this, _("No charts found to compress."), _("OpenCPN Info"));
8276 return;
8277 }
8278
8279 // TODO: make this use threads
8280 unsigned long total_size = 0, total_compressed_size = 0, count = 0;
8281 wxGenericProgressDialog prog(
8282 _("OpenCPN Compress Charts"), wxEmptyString, charts.GetCount() + 1, this,
8283 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
8284 wxPD_REMAINING_TIME | wxPD_CAN_SKIP);
8285
8286 prog.SetSize(sz);
8287
8288 for (unsigned int i = 0; i < charts.GetCount(); i++) {
8289 bool skip = false;
8290 prog.Update(i, charts[i], &skip);
8291 if (skip) break;
8292
8293 wxString compchart = charts[i] + ".xz";
8294 if (CompressChart(charts[i], compchart)) {
8295 total_size += wxFileName::GetSize(charts[i]).ToULong();
8296 total_compressed_size += wxFileName::GetSize(compchart).ToULong();
8297 wxRemoveFile(charts[i]);
8298 count++;
8299 }
8300 }
8301
8302 // report statistics
8303 double total_size_mb = total_size / 1024.0 / 1024.0;
8304 double total_compressed_size_mb = total_compressed_size / 1024.0 / 1024.0;
8305 OCPNMessageBox(
8306 this,
8307 wxString::Format(_("compressed %ld charts\nfrom %.1fMB to %.1fMB\nsaved "
8308 "%.1fMB (%.1f%%)"),
8309 count, total_size_mb, total_compressed_size_mb,
8310 total_size_mb - total_compressed_size_mb,
8311 (1 - total_compressed_size_mb / total_size_mb) * 100.0),
8312 _("OpenCPN Info"));
8313
8314 UpdateWorkArrayFromTextCtl();
8315
8316 if (m_pWorkDirList) {
8317 pActiveChartsList->DeleteAllItems();
8318 for (size_t id = 0; id < m_pWorkDirList->GetCount(); id++) {
8319 wxString dirname = m_pWorkDirList->Item(id).fullpath;
8320 wxListItem li;
8321 li.SetId(id);
8322 li.SetAlign(wxLIST_FORMAT_LEFT);
8323 li.SetText(dirname);
8324 li.SetColumn(0);
8325 long idx = pActiveChartsList->InsertItem(li);
8326 }
8327 }
8328
8329 k_charts |= CHANGE_CHARTS;
8330
8331 pScanCheckBox->Disable();
8332
8333 event.Skip();
8334#endif
8335}
8336
8337void options::OnDebugcheckbox1Click(wxCommandEvent& event) { event.Skip(); }
8338
8339void options::OnCancelClick(wxCommandEvent& event) {
8340 m_pListbook->ChangeSelection(0);
8341 comm_dialog->CancelSettings();
8342
8343 lastWindowPos = GetPosition();
8344 lastWindowSize = GetSize();
8345
8346 pConfig->SetPath("/Settings");
8347 pConfig->Write("OptionsSizeX", lastWindowSize.x);
8348 pConfig->Write("OptionsSizeY", lastWindowSize.y);
8349
8350#ifdef __ANDROID__
8351 androidEnableBackButton(true);
8352 androidEnableRotation();
8353 androidEnableOptionItems(true);
8354#endif
8355
8356 top_frame::Get()->ThawCharts();
8357 Hide();
8358 top_frame::Get()->EnableSettingsTool(true);
8359}
8360
8361void options::OnClose(wxCloseEvent& event) {
8362 m_pListbook->ChangeSelection(0);
8363
8364 lastWindowPos = GetPosition();
8365 lastWindowSize = GetSize();
8366
8367 pConfig->SetPath("/Settings");
8368 pConfig->Write("OptionsSizeX", lastWindowSize.x);
8369 pConfig->Write("OptionsSizeY", lastWindowSize.y);
8370
8371 m_callbacks.prepare_close(this, m_returnChanges);
8372 Hide();
8373}
8374
8375void options::OnFontChoice(wxCommandEvent& event) {
8376 wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8377 m_font_element_array.Add(sel_text_element);
8378
8379 wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8380 wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8381
8382 m_textSample->SetFont(*pif);
8383 m_textSample->SetForegroundColour(init_color);
8384 m_itemBoxSizerFontPanel->Layout();
8385 event.Skip();
8386}
8387
8388void options::OnChooseFont(wxCommandEvent& event) {
8389#ifdef __ANDROID__
8390 androidDisableRotation();
8391#endif
8392
8393 wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8394 m_font_element_array.Add(sel_text_element);
8395 wxFontData font_data;
8396
8397 wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8398 wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8399
8400 wxFontData init_font_data;
8401 if (pif) init_font_data.SetInitialFont(*pif);
8402 init_font_data.SetColour(init_color);
8403
8404#ifdef __WXGTK__
8405 if (g_Platform->getDisplaySize().y < 800) {
8406 ocpnGenericFontDialog dg(this, init_font_data);
8407 wxFont* qFont = dialogFont;
8408 dg.SetFont(*qFont);
8409
8410 int retval = dg.ShowModal();
8411 if (wxID_CANCEL != retval) {
8412 font_data = dg.GetFontData();
8413 wxFont font = font_data.GetChosenFont();
8414 wxFont* psfont = new wxFont(font);
8415 wxColor color = font_data.GetColour();
8416 FontMgr::Get().SetFont(sel_text_element, psfont, color);
8417 top_frame::Get()->UpdateAllFonts();
8418 m_bfontChanged = true;
8419 OnFontChoice(event);
8420 }
8421 } else
8422#endif
8423 {
8424#ifdef __WXGTK__
8425 wxFontDialog dg(this, init_font_data);
8426#else
8427 wxFontDialog dg(pParent, init_font_data);
8428#endif
8429
8430 wxFont* qFont = dialogFont;
8431 dg.SetFont(*qFont);
8432
8433#ifdef __WXQT__
8434 // Make sure that font dialog will fit on the screen without scrolling
8435 // We do this by setting the dialog font size "small enough" to show "n"
8436 // lines
8437 wxSize proposed_size = GetSize();
8438 float n_lines = 30;
8439 float font_size = dialogFont->GetPointSize();
8440
8441 if ((proposed_size.y / font_size) < n_lines) {
8442 float new_font_size = proposed_size.y / n_lines;
8443 wxFont* smallFont = new wxFont(*dialogFont);
8444 smallFont->SetPointSize(new_font_size);
8445 dg.SetFont(*smallFont);
8446 }
8447#endif
8448
8449 if (g_bresponsive) {
8450 dg.SetSize(GetSize());
8451 dg.Centre();
8452 }
8453
8454 int retval = dg.ShowModal();
8455 if (wxID_CANCEL != retval) {
8456 font_data = dg.GetFontData();
8457 wxFont font = font_data.GetChosenFont();
8458 wxFont* psfont = new wxFont(font);
8459 wxColor color = font_data.GetColour();
8460 FontMgr::Get().SetFont(sel_text_element, psfont, color);
8461 top_frame::Get()->UpdateAllFonts();
8462 m_bfontChanged = true;
8463 OnFontChoice(event);
8464 }
8465 }
8466
8467#ifdef __ANDROID__
8468 androidEnableRotation();
8469#endif
8470
8471 event.Skip();
8472}
8473
8474#if defined(__WXGTK__) || defined(__WXQT__)
8475void options::OnChooseFontColor(wxCommandEvent& event) {
8476 wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8477 m_font_element_array.Add(sel_text_element);
8478
8479 wxColourData colour_data;
8480
8481 wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8482 wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8483
8484#ifdef __ANDROID__
8485 androidDisableRotation();
8486
8487 unsigned int cco = 0;
8488 cco |= 0xff;
8489 cco = cco << 8;
8490 cco |= init_color.Red();
8491 cco = cco << 8;
8492 cco |= init_color.Green();
8493 cco = cco << 8;
8494 cco |= init_color.Blue();
8495 unsigned int cc = androidColorPicker(cco);
8496
8497 wxColor cn;
8498 unsigned char blue = (unsigned char)cc % 256;
8499 unsigned char green = (unsigned char)(cc >> 8) % 256;
8500 ;
8501 unsigned char red = (unsigned char)(cc >> 16) % 256;
8502 cn.Set(red, green, blue);
8503
8504 FontMgr::Get().SetFont(sel_text_element, pif, cn);
8505
8506 top_frame::Get()->UpdateAllFonts();
8507 m_bfontChanged = true;
8508
8509 androidEnableRotation();
8510#else
8511 wxScrolledWindow* sw =
8512 new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(400, 400));
8513
8514 wxColourData init_colour_data;
8515 init_colour_data.SetColour(init_color);
8516
8517 wxColourDialog dg(sw, &init_colour_data);
8518
8519 int retval = dg.ShowModal();
8520 if (wxID_CANCEL != retval) {
8521 colour_data = dg.GetColourData();
8522
8523 wxColor color = colour_data.GetColour();
8524 FontMgr::Get().SetFont(sel_text_element, pif, color);
8525
8526 top_frame::Get()->UpdateAllFonts();
8527 m_bfontChanged = true;
8528 OnFontChoice(event);
8529 }
8530
8531 sw->Destroy();
8532#endif
8533 event.Skip();
8534}
8535#endif
8536
8537void options::OnChartsPageChange(wxListbookEvent& event) {
8538 unsigned int i = event.GetSelection();
8539
8540 UpdateChartDirList();
8541
8542 // User selected Chart Groups Page?
8543 // If so, build the remaining UI elements
8544 if (2 == i) { // 2 is the index of "Chart Groups" page
8545 if (!groupsPanel->m_UIcomplete) groupsPanel->CompletePanel();
8546
8547 // Make sure any recently added chart dirs appear in the
8548 // Groups panel, making them available for addition to groups.
8549 UpdateWorkArrayFromDisplayPanel();
8550 groupsPanel->SetDBDirs(*m_pWorkDirList); // update the Groups tab
8551 groupsPanel->m_treespopulated = FALSE;
8552
8553 if (!groupsPanel->m_settingscomplete) {
8554 ::wxBeginBusyCursor();
8555 groupsPanel->CompleteInitialSettings();
8556 ::wxEndBusyCursor();
8557 } else if (!groupsPanel->m_treespopulated) {
8558 groupsPanel->PopulateTrees();
8559 groupsPanel->m_treespopulated = TRUE;
8560 }
8561 } else if (1 == i) { // Vector charts panel
8562 LoadS57();
8563 if (!m_bVectorInit) {
8564 SetInitialVectorSettings();
8565 UpdateOptionsUnits(); // sets depth values, overriding defaults
8566 }
8567 }
8568
8569 event.Skip(); // Allow continued event processing
8570}
8571
8572void options::OnPageChange(wxListbookEvent& event) {
8573 DoOnPageChange(event.GetSelection());
8574}
8575
8576void options::OnSubNBPageChange(wxNotebookEvent& event) {
8577 // In the case where wxNotebooks are nested, we need to identify the subpage
8578 // But otherwise do nothing
8579 if (event.GetEventObject()) {
8580 if (dynamic_cast<wxWindow*>(event.GetEventObject())) {
8581 wxWindow* win = dynamic_cast<wxWindow*>(event.GetEventObject());
8582 wxWindow* parent = dynamic_cast<wxWindow*>(win->GetParent());
8583 if (dynamic_cast<wxNotebook*>(parent)) {
8584 lastSubPage = event.GetSelection();
8585 return;
8586 }
8587 if (dynamic_cast<wxListbook*>(parent)) {
8588 lastSubPage = event.GetSelection();
8589 return;
8590 }
8591 }
8592 }
8593}
8594
8595void options::OnTopNBPageChange(wxNotebookEvent& event) {
8596 DoOnPageChange(event.GetSelection());
8597}
8598
8599void options::DoOnPageChange(size_t page) {
8600 unsigned int i = page;
8601
8602 // Sometimes there is a (-1) page selected.
8603 if (page > 10) return;
8604
8605 lastSubPage = 0; // Reset sub-page
8606
8607 lastPage = i;
8608
8609#ifndef __ANDROID__
8610 if (0 == i) { // Display
8611 if (m_sconfigSelect_single) m_sconfigSelect_single->Refresh(true);
8612 if (m_sconfigSelect_twovertical) m_sconfigSelect_twovertical->Refresh(true);
8613 }
8614#endif
8615 // User selected Chart Page?
8616 // If so, build the "Charts" page variants
8617 if (1 == i) { // 2 is the index of "Charts" page
8618 k_charts = VISIT_CHARTS;
8619 UpdateChartDirList();
8620 }
8621
8622 else if (m_pageConnections == i) {
8623 // Only required on some Windows hosts, but should not hurt. See #4570
8624 wxWindow* w = m_pListbook->GetCurrentPage();
8625 comm_dialog->OnResize(w ? w->GetClientSize() : wxSize());
8626 }
8627
8628 else if (m_pageUI == i) { // 5 is the index of "User Interface" page
8629 if (!m_itemLangListBox) return;
8630#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
8631
8632 if (!m_bVisitLang) {
8633 ::wxBeginBusyCursor();
8634
8635 int current_language = plocale_def_lang->GetLanguage();
8636 wxString current_sel = wxLocale::GetLanguageName(current_language);
8637
8638 current_sel = GetOCPNKnownLanguage(g_locale);
8639
8640 int nLang = sizeof(lang_list) / sizeof(int);
8641#ifdef __WXMSW__
8642 // always add us english
8643 m_itemLangListBox->Append("English (U.S.)");
8644
8645 wxString lang_dir = g_Platform->GetSharedDataDir() + "share/locale/";
8646 for (int it = 1; it < nLang; it++) {
8647 if (wxLocale::IsAvailable(lang_list[it])) {
8648 wxLocale ltest(lang_list[it], 0);
8649 ltest.AddCatalog("opencpn");
8650 if (!ltest.IsLoaded("opencpn")) continue;
8651
8652 // Defaults
8653 wxString loc_lang_name = wxLocale::GetLanguageName(lang_list[it]);
8654 wxString widgets_lang_name = loc_lang_name;
8655 wxString lang_canonical =
8656 wxLocale::GetLanguageInfo(lang_list[it])->CanonicalName;
8657
8658 // Make opencpn substitutions
8659 wxString lang_suffix;
8660 loc_lang_name = GetOCPNKnownLanguage(lang_canonical, lang_suffix);
8661
8662 // Look explicitely to see if .mo is available
8663 wxString test_dir = lang_dir + lang_suffix;
8664 if (!wxDir::Exists(test_dir)) continue;
8665
8666 m_itemLangListBox->Append(loc_lang_name);
8667 }
8668 }
8669#else
8670 wxArrayString lang_array;
8671
8672 // always add us english
8673 lang_array.Add("en_US");
8674 for (int it = 0; it < nLang; it++) {
8675 {
8676 wxLog::EnableLogging(
8677 FALSE); // avoid "Cannot set locale to..." log message
8678
8679 wxLocale ltest(lang_list[it], 0);
8680#if wxCHECK_VERSION(2, 9, 0)
8681#ifdef __WXGTK__
8682 ltest.AddCatalogLookupPathPrefix(
8683 wxStandardPaths::Get().GetInstallPrefix() + "/share/locale");
8684#endif
8685#endif
8686 ltest.AddCatalog("opencpn");
8687
8688 wxLog::EnableLogging(TRUE);
8689 if (ltest.IsLoaded("opencpn")) {
8690 auto x = wxLocale::GetLanguageInfo(lang_list[it]);
8691 wxString s0;
8692 if (x)
8693 s0 = x->CanonicalName;
8694 else
8695 continue;
8696 wxString sl = wxLocale::GetLanguageName(lang_list[it]);
8697 if (wxNOT_FOUND == lang_array.Index(s0)) {
8698 lang_array.Add(s0);
8699 }
8700 }
8701 }
8702 }
8703
8704 for (unsigned int i = 0; i < lang_array.GetCount(); i++) {
8705 // Make opencpn substitutions
8706 wxString loc_lang_name = GetOCPNKnownLanguage(lang_array[i]);
8707 m_itemLangListBox->Append(loc_lang_name);
8708 }
8709#endif
8710 // BUGBUG
8711 // Remember that wxLocale ctor has the effect of changing the system
8712 // locale, including the "C" libraries.
8713 // It should then also happen that the locale should be switched back to
8714 // ocpn initial load setting
8715 // upon the dtor of the above wxLocale instantiations....
8716 // wxWidgets may do so internally, but there seems to be no effect upon
8717 // the system libraries, so that
8718 // functions like strftime() do not revert to the correct locale setting.
8719 // Also, the catalog for the application is not reloaded by the ctor, so
8720 // we must reload them directly
8721 // So as workaround, we reset the locale explicitely.
8722
8723 delete plocale_def_lang;
8724 plocale_def_lang = new wxLocale(current_language);
8725
8726 setlocale(LC_NUMERIC, "C");
8727 plocale_def_lang->AddCatalog("opencpn");
8728
8729 m_itemLangListBox->SetStringSelection(current_sel);
8730
8731 // Initialize Language tab
8732 const wxLanguageInfo* pli = wxLocale::FindLanguageInfo(g_locale);
8733 if (pli) {
8734 wxString clang = pli->Description;
8735 // m_itemLangListBox->SetValue(clang);
8736 }
8737
8738 m_bVisitLang = TRUE;
8739
8740 ::wxEndBusyCursor();
8741 }
8742#endif
8743 } else if (m_pagePlugins == i) { // 7 is the index of "Plugins" page
8744 m_bVisitPlugins = TRUE;
8745 top_frame::Get()->FreezeCharts();
8746
8747 // load the disabled plugins finally because the user might want to enable
8748 // them
8749 auto loader = PluginLoader::GetInstance();
8750 if (LoadAllPlugIns(false)) {
8751 delete m_pPlugInCtrl;
8752 m_pPlugInCtrl = NULL;
8753 delete m_PluginCatalogMgrPanel;
8754 m_PluginCatalogMgrPanel = NULL;
8755 itemBoxSizerPanelPlugins->Clear();
8756 }
8757
8758 if (!m_pPlugInCtrl) {
8759 // Build the PlugIn Manager Panel
8760 ::wxBeginBusyCursor();
8761
8762 m_pPlugInCtrl = new PluginListPanel(itemPanelPlugins, ID_PANELPIM,
8763 wxDefaultPosition, wxDefaultSize);
8764 m_pPlugInCtrl->SetScrollRate(m_scrollRate, m_scrollRate);
8765 itemBoxSizerPanelPlugins->Add(m_pPlugInCtrl, 01,
8766 wxEXPAND | wxGROW | wxALL, 4);
8767 if (g_pi_manager) g_pi_manager->SetListPanelPtr(m_pPlugInCtrl);
8768
8769 m_PluginCatalogMgrPanel = new CatalogMgrPanel(itemPanelPlugins);
8770 m_PluginCatalogMgrPanel->SetListPanelPtr(m_pPlugInCtrl);
8771
8772 itemBoxSizerPanelPlugins->Add(m_PluginCatalogMgrPanel, 0,
8773 wxEXPAND | wxALL, 4);
8774 itemBoxSizerPanelPlugins->Layout();
8775
8776 // Update the PlugIn page to reflect the state of individual selections
8777 m_pPlugInCtrl->UpdateSelections();
8778
8779 ::wxEndBusyCursor();
8780
8781 wxDEFINE_EVENT(EVT_COMPAT_OS_CHANGE, wxCommandEvent);
8782 obs::GlobalVar<wxString> compat_os(&g_compatOS);
8783 }
8784 k_plugins = TOOLBAR_CHANGED;
8785 // TODO Only if o-charts is touched?
8786 k_plugins |= FORCE_RELOAD;
8787 }
8788}
8789
8790wxString options::SelectSoundFile() {
8791 wxString sound_dir = g_Platform->GetSharedDataDir();
8792 sound_dir.Append("sounds");
8793 wxString sel_file;
8794 int response;
8795
8796#ifndef __ANDROID__
8797 wxFileDialog* popenDialog = new wxFileDialog(
8798 NULL, _("Select Sound File"), sound_dir, wxEmptyString,
8799 "WAV files (*.wav)|*.wav|All files (*.*)|*.*", wxFD_OPEN);
8800 if (g_bresponsive)
8801 popenDialog = g_Platform->AdjustFileDialogFont(this, popenDialog);
8802
8803 response = popenDialog->ShowModal();
8804 sel_file = popenDialog->GetPath();
8805 delete popenDialog;
8806
8807#else
8808 response = g_Platform->DoFileSelectorDialog(
8809 this, &sel_file, _("Select Sound File"), sound_dir, wxEmptyString, "*.*");
8810#endif
8811
8812 if (response == wxID_OK)
8813 return g_Platform->NormalizePath(sel_file);
8814 else
8815 return "";
8816}
8817
8818void options::OnButtonSelectSound(wxCommandEvent& event) {
8819 wxString sel_file = SelectSoundFile();
8820
8821 if (!sel_file.IsEmpty()) {
8822 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(sel_file);
8823 }
8824}
8825
8826void options::OnButtonTestSound(wxCommandEvent& event) {
8827 auto sound = o_sound::Factory();
8828 auto cmd_sound = dynamic_cast<o_sound::SystemCmdSound*>(sound);
8829 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str());
8830 sound->SetFinishedCallback([&](void* snd) { m_on_sound_done.Notify(snd); });
8831 sound->Load(m_soundPanelAIS->GetSoundFile(), g_iSoundDeviceIndex);
8832 sound->Play();
8833}
8834
8835wxString GetOCPNKnownLanguage(wxString lang_canonical, wxString& lang_dir) {
8836 wxString return_string;
8837 wxString dir_suffix;
8838
8839#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
8840
8841 if (lang_canonical == "en_US") {
8842 dir_suffix = "en";
8843 return_string = wxString("English (U.S.)", wxConvUTF8);
8844
8845 } else if ((lang_canonical == "cs_CZ") || (lang_canonical == "cs")) {
8846 dir_suffix = "cs";
8847 return_string = wxString("Čeština", wxConvUTF8);
8848
8849 } else if ((lang_canonical == "da_DK") || (lang_canonical == "da")) {
8850 dir_suffix = "da";
8851 return_string = wxString("Dansk", wxConvUTF8);
8852
8853 } else if ((lang_canonical == "de_DE") || (lang_canonical == "de")) {
8854 dir_suffix = "de";
8855 return_string = wxString("Deutsch", wxConvUTF8);
8856
8857 } else if ((lang_canonical == "et_EE") || (lang_canonical == "et")) {
8858 dir_suffix = "et";
8859 return_string = wxString("Eesti", wxConvUTF8);
8860
8861 } else if ((lang_canonical == "es_ES") || (lang_canonical == "es")) {
8862 dir_suffix = "es";
8863 return_string = wxString("Español", wxConvUTF8);
8864
8865 } else if ((lang_canonical == "fr_FR") || (lang_canonical == "fr")) {
8866 dir_suffix = "fr";
8867 return_string = wxString("Français", wxConvUTF8);
8868
8869 } else if ((lang_canonical == "it_IT") || (lang_canonical == "it")) {
8870 dir_suffix = "it";
8871 return_string = wxString("Italiano", wxConvUTF8);
8872
8873 } else if ((lang_canonical == "nl_NL") || (lang_canonical == "nl")) {
8874 dir_suffix = "nl";
8875 return_string = wxString("Nederlands", wxConvUTF8);
8876
8877 } else if ((lang_canonical == "pl_PL") || (lang_canonical == "pl")) {
8878 dir_suffix = "pl";
8879 return_string = wxString("Polski", wxConvUTF8);
8880
8881 } else if ((lang_canonical == "pt_PT") || (lang_canonical == "pt")) {
8882 dir_suffix = "pt_PT";
8883 return_string = wxString("Português", wxConvUTF8);
8884
8885 } else if ((lang_canonical == "pt_BR") || (lang_canonical == "pt_BR")) {
8886 dir_suffix = "pt_BR";
8887 return_string = wxString("Português Brasileiro", wxConvUTF8);
8888
8889 } else if ((lang_canonical == "ru_RU") || (lang_canonical == "ru")) {
8890 dir_suffix = "ru";
8891 return_string = wxString("Русский", wxConvUTF8);
8892
8893 } else if ((lang_canonical == "sv_SE") || (lang_canonical == "sv")) {
8894 dir_suffix = "sv";
8895 return_string = wxString("Svenska", wxConvUTF8);
8896
8897 } else if ((lang_canonical == "fi_FI") || (lang_canonical == "fi")) {
8898 dir_suffix = "fi_FI";
8899 return_string = wxString("Suomi", wxConvUTF8);
8900
8901 } else if ((lang_canonical == "nb_NO") || (lang_canonical == "nb")) {
8902 dir_suffix = "nb_NO";
8903 return_string = wxString("Norsk", wxConvUTF8);
8904
8905 } else if ((lang_canonical == "tr_TR") || (lang_canonical == "tr")) {
8906 dir_suffix = "tr_TR";
8907 return_string = wxString("Türkçe", wxConvUTF8);
8908
8909 } else if ((lang_canonical == "el_GR") || (lang_canonical == "el")) {
8910 dir_suffix = "el_GR";
8911 return_string = wxString("Ελληνικά", wxConvUTF8);
8912
8913 } else if ((lang_canonical == "hu_HU") || (lang_canonical == "hu")) {
8914 dir_suffix = "hu_HU";
8915 return_string = wxString("Magyar", wxConvUTF8);
8916
8917 } else if ((lang_canonical == "zh_TW") || (lang_canonical == "zh_TW")) {
8918 dir_suffix = "zh_TW";
8919 return_string = wxString("正體字", wxConvUTF8);
8920
8921 } else if ((lang_canonical == "zh_CN") || (lang_canonical == "zh_CN")) {
8922 dir_suffix = "zh_CN";
8923 return_string = wxString("Simplified Chinese", wxConvUTF8);
8924
8925 } else if ((lang_canonical == "ca_ES") || (lang_canonical == "ca")) {
8926 dir_suffix = "ca_ES";
8927 return_string = wxString("Catalan", wxConvUTF8);
8928
8929 } else if ((lang_canonical == "gl_ES") || (lang_canonical == "gl_ES")) {
8930 dir_suffix = "gl_ES";
8931 return_string = wxString("Galician", wxConvUTF8);
8932
8933 } else if ((lang_canonical == "ja_JP") || (lang_canonical == "ja_JP")) {
8934 dir_suffix = "ja_JP";
8935 return_string = wxString("Japanese", wxConvUTF8);
8936
8937 } else if ((lang_canonical == "vi_VN") || (lang_canonical == "vi_VN")) {
8938 dir_suffix = "vi_VN";
8939 return_string = wxString("Vietnamese", wxConvUTF8);
8940
8941 } else {
8942 dir_suffix = lang_canonical;
8943 const wxLanguageInfo* info = wxLocale::FindLanguageInfo(lang_canonical);
8944 if (info)
8945 return_string = info->Description;
8946 else
8947 return_string = lang_canonical;
8948 }
8949
8950 lang_dir = dir_suffix;
8951#endif
8952 return return_string;
8953}
8954
8955wxString GetOCPNKnownLanguage(const wxString lang_canonical) {
8956 wxString lang_dir;
8957 return GetOCPNKnownLanguage(lang_canonical, lang_dir);
8958}
8959
8960ChartGroupArray* ChartGroupsUI::CloneChartGroupArray(ChartGroupArray* s) {
8961 ChartGroupArray* d = new ChartGroupArray;
8962 for (unsigned int i = 0; i < s->GetCount(); i++) {
8963 ChartGroup* psg = s->Item(i);
8964 ChartGroup* pdg = new ChartGroup;
8965 pdg->m_group_name = psg->m_group_name;
8966 pdg->m_element_array.reserve(psg->m_element_array.size());
8967
8968 for (auto& elem : psg->m_element_array)
8969 pdg->m_element_array.push_back(elem);
8970
8971 d->Add(pdg);
8972 }
8973 return d;
8974}
8975
8976void ChartGroupsUI::EmptyChartGroupArray(ChartGroupArray* s) {
8977 if (!s) return;
8978
8979 // ChartGroups don't need anything special for delete, just calling the
8980 // destructor is enough.
8981 WX_CLEAR_ARRAY(*s);
8982}
8983
8984// Chart Groups dialog implementation
8985BEGIN_EVENT_TABLE(ChartGroupsUI, wxEvtHandler)
8986EVT_TREE_ITEM_EXPANDED(wxID_TREECTRL, ChartGroupsUI::OnNodeExpanded)
8987EVT_NOTEBOOK_PAGE_CHANGED(
8988 wxID_ANY,
8989 ChartGroupsUI::OnGroupPageChange) // This should work under Windows :-(
8990END_EVENT_TABLE()
8991
8992ChartGroupsUI::ChartGroupsUI(wxWindow* parent) : wxScrolledWindow(parent) {
8993 m_GroupSelectedPage = -1;
8994 m_pActiveChartsTree = 0;
8995 pParent = parent;
8996 lastSelectedCtl = NULL;
8997 allAvailableCtl = NULL;
8998 defaultAllCtl = NULL;
8999 iFont = NULL;
9000 m_pAddButton = NULL;
9001 m_pRemoveButton = NULL;
9002 m_pDeleteGroupButton = NULL;
9003 m_pNewGroupButton = NULL;
9004 m_pGroupArray = NULL;
9005 m_GroupNB = NULL;
9006 modified = false;
9007 m_UIcomplete = false;
9008 m_treespopulated = false;
9009 dialogFont = GetOCPNScaledFont(_("Dialog"));
9010}
9011
9012ChartGroupsUI::~ChartGroupsUI() {
9013 m_DirCtrlArray.Clear();
9014 m_GroupNB->Disconnect(
9015 wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
9016 wxNotebookEventHandler(ChartGroupsUI::OnGroupPageChange), NULL, this);
9017
9018 delete iFont;
9019}
9020
9021void ChartGroupsUI::SetInitialSettings() {
9022 m_settingscomplete = FALSE;
9023 m_treespopulated = FALSE;
9024}
9025
9026void ChartGroupsUI::PopulateTrees() {
9027 // Fill in the "Active chart" tree control
9028 // from the options dialog "Active Chart Directories" list
9029 wxArrayString dir_array;
9030 int nDir = m_db_dirs.GetCount();
9031 for (int i = 0; i < nDir; i++) {
9032 wxString dirname = m_db_dirs[i].fullpath;
9033 if (!dirname.IsEmpty()) dir_array.Add(dirname);
9034 }
9035
9036 PopulateTreeCtrl(allAvailableCtl->GetTreeCtrl(), dir_array,
9037 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),
9038 dialogFont);
9039 m_pActiveChartsTree = allAvailableCtl->GetTreeCtrl();
9040
9041 // Fill in the Page 0 tree control
9042 // from the options dialog "Active Chart Directories" list
9043 wxArrayString dir_array0;
9044 int nDir0 = m_db_dirs.GetCount();
9045 for (int i = 0; i < nDir0; i++) {
9046 wxString dirname = m_db_dirs[i].fullpath;
9047 if (!dirname.IsEmpty()) dir_array0.Add(dirname);
9048 }
9049 PopulateTreeCtrl(defaultAllCtl->GetTreeCtrl(), dir_array0,
9050 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), iFont);
9051}
9052
9053void ChartGroupsUI::CompleteInitialSettings() {
9054 PopulateTrees();
9055
9056 BuildNotebookPages(m_pGroupArray);
9057
9058 m_panel->GetSizer()->Layout();
9059
9060 m_settingscomplete = TRUE;
9061 m_treespopulated = TRUE;
9062}
9063
9064void ChartGroupsUI::PopulateTreeCtrl(wxTreeCtrl* ptc,
9065 const wxArrayString& dir_array,
9066 const wxColour& col, wxFont* pFont) {
9067 ptc->DeleteAllItems();
9068
9069 wxDirItemData* rootData = new wxDirItemData("Dummy", "Dummy", TRUE);
9070 wxString rootName;
9071 rootName = "Dummy";
9072 wxTreeItemId m_rootId = ptc->AddRoot(rootName, 3, -1, rootData);
9073 ptc->SetItemHasChildren(m_rootId);
9074
9075 wxString dirname;
9076 int nDir = dir_array.GetCount();
9077 for (int i = 0; i < nDir; i++) {
9078 wxString dirname = dir_array[i];
9079 if (!dirname.IsEmpty()) {
9080 wxDirItemData* dir_item = new wxDirItemData(dirname, dirname, TRUE);
9081 wxTreeItemId id = ptc->AppendItem(m_rootId, dirname, 0, -1, dir_item);
9082
9083 // wxWidgets bug workaraound (Ticket #10085)
9084 ptc->SetItemText(id, dirname);
9085 if (pFont) ptc->SetItemFont(id, *pFont);
9086
9087#ifndef __WXOSX__
9088 // On MacOS, use the default system dialog color, to honor Dark mode.
9089 ptc->SetItemTextColour(id, col);
9090#endif
9091 ptc->SetItemHasChildren(id);
9092 }
9093 }
9094}
9095
9096void ChartGroupsUI::OnInsertChartItem(wxCommandEvent& event) {
9097 wxString insert_candidate = allAvailableCtl->GetPath();
9098 if (!insert_candidate.IsEmpty()) {
9099 if (m_DirCtrlArray.GetCount()) {
9100 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9101 ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9102 if (pDirCtrl) {
9103 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9104 if (ptree) {
9105 if (ptree->IsEmpty()) {
9106 wxDirItemData* rootData =
9107 new wxDirItemData(wxEmptyString, wxEmptyString, TRUE);
9108 wxString rootName = "Dummy";
9109 wxTreeItemId rootId = ptree->AddRoot(rootName, 3, -1, rootData);
9110
9111 ptree->SetItemHasChildren(rootId);
9112 }
9113
9114 wxTreeItemId root_Id = ptree->GetRootItem();
9115 wxDirItemData* dir_item =
9116 new wxDirItemData(insert_candidate, insert_candidate, TRUE);
9117 wxTreeItemId id =
9118 ptree->AppendItem(root_Id, insert_candidate, 0, -1, dir_item);
9119 if (wxDir::Exists(insert_candidate)) ptree->SetItemHasChildren(id);
9120 }
9121
9122 pGroup->m_element_array.push_back({insert_candidate});
9123 }
9124 }
9125 }
9126 modified = TRUE;
9127 allAvailableCtl->GetTreeCtrl()->UnselectAll();
9128 m_pAddButton->Disable();
9129
9130 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9131 if (pDirCtrl) {
9132 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9133 if (ptree) ptree->Refresh();
9134 }
9135}
9136
9137void ChartGroupsUI::OnRemoveChartItem(wxCommandEvent& event) {
9138 if (m_DirCtrlArray.GetCount()) {
9139 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9140 ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9141
9142 if (pDirCtrl) {
9143 wxString sel_item = pDirCtrl->GetPath();
9144
9145 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9146 if (ptree && ptree->GetCount()) {
9147 wxTreeItemId id = ptree->GetSelection();
9148 lastDeletedItem = id;
9149 if (id.IsOk()) {
9150 wxString branch_adder;
9151 int group_item_index =
9152 FindGroupBranch(pGroup, ptree, id, &branch_adder);
9153 if (group_item_index >= 0) {
9154 ChartGroupElement& pelement =
9155 pGroup->m_element_array[group_item_index];
9156 bool b_duplicate = FALSE;
9157 for (unsigned int k = 0; k < pelement.m_missing_name_array.size();
9158 k++) {
9159 if (pelement.m_missing_name_array[k] == sel_item) {
9160 b_duplicate = TRUE;
9161 break;
9162 }
9163 }
9164 if (!b_duplicate) {
9165 pelement.m_missing_name_array.Add(sel_item);
9166 }
9167
9168 // Special case...
9169 // If the selection is a branch itself,
9170 // Then delete from the tree, and delete from the group
9171 if (branch_adder == "") {
9172 ptree->Delete(id);
9173 pGroup->m_element_array.erase(pGroup->m_element_array.begin() +
9174 group_item_index);
9175 } else {
9176 ptree->SetItemTextColour(id, wxColour(128, 128, 128));
9177 // what about toggle back?
9178 }
9179 }
9180 }
9181 modified = TRUE;
9182 lastSelectedCtl->Unselect();
9183 lastSelectedCtl = 0;
9184 m_pRemoveButton->Disable();
9185
9186 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9187 if (pDirCtrl) {
9188 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9189 if (ptree) ptree->Refresh();
9190 }
9191 }
9192 }
9193 }
9194 event.Skip();
9195}
9196
9197void ChartGroupsUI::OnGroupPageChange(wxNotebookEvent& event) {
9198 m_GroupSelectedPage = event.GetSelection();
9199 allAvailableCtl->GetTreeCtrl()->UnselectAll();
9200 if (lastSelectedCtl) {
9201 lastSelectedCtl->UnselectAll();
9202 lastSelectedCtl = 0;
9203 }
9204 m_pRemoveButton->Disable();
9205 m_pAddButton->Disable();
9206
9207 // Disable delete option for "All Charts" group
9208 if (m_GroupSelectedPage == 0) {
9209 if (m_pDeleteGroupButton) m_pDeleteGroupButton->Disable();
9210 } else {
9211 if (m_pDeleteGroupButton) m_pDeleteGroupButton->Enable();
9212 }
9213}
9214
9215void ChartGroupsUI::OnAvailableSelection(wxTreeEvent& event) {
9216 wxObject* evtObj = event.GetEventObject();
9217 if (allAvailableCtl && (evtObj == allAvailableCtl->GetTreeCtrl())) {
9218 wxTreeItemId item = allAvailableCtl->GetTreeCtrl()->GetSelection();
9219 if (item && item.IsOk() && m_GroupSelectedPage > 0) {
9220 m_pAddButton->Enable();
9221 } else {
9222 m_pAddButton->Disable();
9223 }
9224 } else {
9225 lastSelectedCtl = dynamic_cast<wxTreeCtrl*>(evtObj);
9226 if (!lastSelectedCtl) goto out;
9227 wxTreeItemId item = lastSelectedCtl->GetSelection();
9228 if (item && item.IsOk() && m_GroupSelectedPage > 0) {
9229 // We need a trick for wxGTK here, since it gives us a Selection
9230 // event with the just deleted element after OnRemoveChartItem()
9231 wxGenericDirCtrl* dirCtrl =
9232 dynamic_cast<wxGenericDirCtrl*>(lastSelectedCtl->GetParent());
9233 if (!dirCtrl) goto out;
9234 wxString itemPath = dirCtrl->GetPath();
9235 if (!itemPath.IsEmpty()) m_pRemoveButton->Enable();
9236 } else {
9237 m_pRemoveButton->Disable();
9238 }
9239 }
9240
9241out:
9242 event.Skip();
9243}
9244
9245void ChartGroupsUI::OnNewGroup(wxCommandEvent& event) {
9246 wxTextEntryDialog* pd = new wxTextEntryDialog();
9247 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
9248 pd->SetFont(*qFont);
9249
9250 pd->Create(m_panel, _("Enter Group Name"), _("New Chart Group"));
9251
9252#ifdef __ANDROID__
9253 androidDisableRotation();
9254#endif
9255
9256 if (pd->ShowModal() == wxID_OK) {
9257 if (pd->GetValue().Length()) {
9258 AddEmptyGroupPage(pd->GetValue());
9259 ChartGroup* pGroup = new ChartGroup;
9260 pGroup->m_group_name = pd->GetValue();
9261 m_pGroupArray->Add(pGroup);
9262
9263 m_GroupSelectedPage =
9264 m_GroupNB->GetPageCount() - 1; // select the new page
9265 m_GroupNB->ChangeSelection(m_GroupSelectedPage);
9266 m_pDeleteGroupButton->Enable();
9267 modified = TRUE;
9268 }
9269 }
9270 delete pd;
9271
9272#ifdef __ANDROID__
9273 androidEnableRotation();
9274#endif
9275}
9276
9277void ChartGroupsUI::OnDeleteGroup(wxCommandEvent& event) {
9278 if (0 != m_GroupSelectedPage) {
9279 m_DirCtrlArray.RemoveAt(m_GroupSelectedPage);
9280 if (m_pGroupArray) m_pGroupArray->RemoveAt(m_GroupSelectedPage - 1);
9281 m_GroupNB->DeletePage(m_GroupSelectedPage);
9282 modified = TRUE;
9283 }
9284 if (m_GroupSelectedPage <= 0) {
9285 m_pAddButton->Disable();
9286 m_pDeleteGroupButton->Disable();
9287 }
9288}
9289
9290int ChartGroupsUI::FindGroupBranch(ChartGroup* pGroup, wxTreeCtrl* ptree,
9291 wxTreeItemId item, wxString* pbranch_adder) {
9292 wxString branch_name;
9293 wxString branch_adder;
9294
9295 wxTreeItemId current_node = item;
9296 while (current_node.IsOk()) {
9297 wxTreeItemId parent_node = ptree->GetItemParent(current_node);
9298 if (!parent_node) break;
9299
9300 if (parent_node == ptree->GetRootItem()) {
9301 branch_name = ptree->GetItemText(current_node);
9302 break;
9303 }
9304
9305 branch_adder.Prepend(ptree->GetItemText(current_node));
9306 branch_adder.Prepend(wxString(wxFILE_SEP_PATH));
9307
9308 current_node = ptree->GetItemParent(current_node);
9309 }
9310
9311 // Find the index and element pointer of the target branch in the Group
9312 unsigned int target_item_index = -1;
9313
9314 for (unsigned int i = 0; i < pGroup->m_element_array.size(); i++) {
9315 const wxString& target = pGroup->m_element_array[i].m_element_name;
9316 if (branch_name == target) {
9317 target_item_index = i;
9318 break;
9319 }
9320 }
9321
9322 if (pbranch_adder) *pbranch_adder = branch_adder;
9323
9324 return target_item_index;
9325}
9326
9327void ChartGroupsUI::OnNodeExpanded(wxTreeEvent& event) {
9328 wxTreeItemId node = event.GetItem();
9329
9330 if (m_GroupSelectedPage <= 0) return;
9331 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9332 ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9333 if (!pDirCtrl) return;
9334
9335 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9336 wxString branch_adder;
9337 int target_item_index = FindGroupBranch(pGroup, ptree, node, &branch_adder);
9338 if (target_item_index < 0) return;
9339 const ChartGroupElement& target_element =
9340 pGroup->m_element_array[target_item_index];
9341 const wxString& branch_name = target_element.m_element_name;
9342
9343 // Walk the children of the expanded node, marking any items which appear in
9344 // the "missing" list
9345 if (!target_element.m_missing_name_array.GetCount()) return;
9346 wxString full_root = branch_name;
9347 full_root += branch_adder;
9348 full_root += wxString(wxFILE_SEP_PATH);
9349
9350 wxTreeItemIdValue cookie;
9351 wxTreeItemId child = ptree->GetFirstChild(node, cookie);
9352 while (child.IsOk()) {
9353 wxString target_string = full_root;
9354 target_string += ptree->GetItemText(child);
9355
9356 for (unsigned int k = 0; k < target_element.m_missing_name_array.GetCount();
9357 k++) {
9358 if (target_element.m_missing_name_array[k] == target_string) {
9359 ptree->SetItemTextColour(child, wxColour(128, 128, 128));
9360 break;
9361 }
9362 }
9363 child = ptree->GetNextChild(node, cookie);
9364 }
9365}
9366
9367void ChartGroupsUI::BuildNotebookPages(ChartGroupArray* pGroupArray) {
9368 ClearGroupPages();
9369
9370 for (unsigned int i = 0; i < pGroupArray->GetCount(); i++) {
9371 ChartGroup* pGroup = pGroupArray->Item(i);
9372 wxTreeCtrl* ptc = AddEmptyGroupPage(pGroup->m_group_name);
9373
9374 wxString itemname;
9375 int nItems = pGroup->m_element_array.size();
9376 for (int i = 0; i < nItems; i++) {
9377 const wxString& itemname = pGroup->m_element_array[i].m_element_name;
9378 if (!itemname.IsEmpty()) {
9379 wxDirItemData* dir_item = new wxDirItemData(itemname, itemname, TRUE);
9380 wxTreeItemId id =
9381 ptc->AppendItem(ptc->GetRootItem(), itemname, 0, -1, dir_item);
9382
9383 if (wxDir::Exists(itemname)) ptc->SetItemHasChildren(id);
9384 }
9385 }
9386 }
9387}
9388
9389wxTreeCtrl* ChartGroupsUI::AddEmptyGroupPage(const wxString& label) {
9390 wxGenericDirCtrl* GroupDirCtl =
9391 new wxGenericDirCtrl(m_GroupNB, wxID_ANY, "TESTDIR");
9392 m_GroupNB->AddPage(GroupDirCtl, label);
9393
9394 wxTreeCtrl* ptree = GroupDirCtl->GetTreeCtrl();
9395 ptree->DeleteAllItems();
9396
9397 wxDirItemData* rootData =
9398 new wxDirItemData(wxEmptyString, wxEmptyString, TRUE);
9399 wxString rootName = "Dummy";
9400 wxTreeItemId rootId = ptree->AddRoot(rootName, 3, -1, rootData);
9401 ptree->SetItemHasChildren(rootId);
9402
9403 m_DirCtrlArray.Add(GroupDirCtl);
9404
9405 return ptree;
9406}
9407
9408void ChartGroupsUI::ClearGroupPages() {
9409 if (m_GroupNB->GetPageCount() == 0) return;
9410
9411 for (unsigned int i = m_GroupNB->GetPageCount() - 1; i > 0; i--) {
9412 m_DirCtrlArray.RemoveAt(i);
9413 m_GroupNB->DeletePage(i);
9414 }
9415}
9416
9417void options::OnInsertTideDataLocation(wxCommandEvent& event) {
9418 wxString sel_file;
9419 int response = wxID_CANCEL;
9420
9421#ifndef __ANDROID__
9422 wxFileDialog* popenDialog = new wxFileDialog(
9423 NULL, _("Select Tide/Current Data"), g_TCData_Dir, "",
9424 "Tide/Current Data files (*.IDX; *.TCD)|*.IDX;*.idx;*.TCD;*.tcd|All "
9425 "files (*.*)|*.*",
9426 wxFD_OPEN);
9427 if (g_bresponsive)
9428 popenDialog = g_Platform->AdjustFileDialogFont(this, popenDialog);
9429
9430 response = popenDialog->ShowModal();
9431 sel_file = popenDialog->GetPath();
9432 delete popenDialog;
9433
9434#else
9435 wxString path;
9436 response = g_Platform->DoFileSelectorDialog(
9437 this, &path, _("Select Tide/Current Data"), g_TCData_Dir, "", "*.*");
9438 sel_file = path;
9439#endif
9440
9441 if (response == wxID_OK) {
9442 wxListItem li;
9443 int id = tcDataSelected->GetItemCount(); // next index
9444 li.SetId(id);
9445 long idx = tcDataSelected->InsertItem(li);
9446 tcDataSelected->SetItem(id, 0, g_Platform->NormalizePath(sel_file));
9447
9448 // Record the currently selected directory for later use
9449 wxFileName fn(sel_file);
9450 wxString data_dir = fn.GetPath();
9451 g_TCData_Dir = g_Platform->NormalizePath(data_dir);
9452 }
9453}
9454
9455void options::OnRemoveTideDataLocation(wxCommandEvent& event) {
9456 long item = -1;
9457 for (;;) {
9458 item = tcDataSelected->GetNextItem(item, wxLIST_NEXT_ALL,
9459 wxLIST_STATE_SELECTED);
9460 if (item == -1) break;
9461 tcDataSelected->DeleteItem(item);
9462 item = -1; // Restart
9463 }
9464}
9465
9466// OpenGLOptionsDlg
9467enum { ID_BUTTON_REBUILD, ID_BUTTON_CLEAR };
9468
9469#ifdef ocpnUSE_GL
9470BEGIN_EVENT_TABLE(OpenGLOptionsDlg, wxDialog)
9471EVT_BUTTON(ID_BUTTON_REBUILD, OpenGLOptionsDlg::OnButtonRebuild)
9472EVT_BUTTON(ID_BUTTON_CLEAR, OpenGLOptionsDlg::OnButtonClear)
9473END_EVENT_TABLE()
9474
9475OpenGLOptionsDlg::OpenGLOptionsDlg(wxWindow* parent)
9476 : wxDialog(parent, wxID_ANY, "OpenGL Options", wxDefaultPosition,
9477 wxDefaultSize,
9478 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER
9479#ifdef __WXOSX__
9480 | wxSTAY_ON_TOP
9481#endif
9482 ),
9483 m_brebuild_cache(FALSE) {
9484
9485 wxFont* dialogFont = GetOCPNScaledFont(_("Dialog"));
9486 SetFont(*dialogFont);
9487
9488 wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
9489 wxFlexGridSizer* flexSizer = new wxFlexGridSizer(2);
9490
9491 m_cbTextureCompression =
9492 new wxCheckBox(this, wxID_ANY,
9493 g_bGLexpert ? _("Texture Compression")
9494 : _("Texture Compression with Caching"));
9495 m_cbTextureCompressionCaching =
9496 new wxCheckBox(this, wxID_ANY, _("Texture Compression Caching"));
9497 m_memorySize =
9498 new wxStaticText(this, wxID_ANY, _("Texture Memory Size (MB)"));
9499 m_sTextureMemorySize = new wxSpinCtrl(this);
9500 m_sTextureMemorySize->SetRange(1, 16384);
9501 m_cacheSize =
9502 new wxStaticText(this, wxID_ANY, _("Size: ") + GetTextureCacheSize());
9503 wxButton* btnRebuild =
9504 new wxButton(this, ID_BUTTON_REBUILD, _("Rebuild Texture Cache"));
9505 wxButton* btnClear =
9506 new wxButton(this, ID_BUTTON_CLEAR, _("Clear Texture Cache"));
9507 btnRebuild->Enable(g_GLOptions.m_bTextureCompressionCaching);
9508 if (!g_bopengl || g_raster_format == GL_RGB) btnRebuild->Disable();
9509 btnClear->Enable(g_GLOptions.m_bTextureCompressionCaching);
9510 m_cbPolygonSmoothing = new wxCheckBox(this, wxID_ANY, _("Polygon Smoothing"));
9511 m_cbLineSmoothing = new wxCheckBox(this, wxID_ANY, _("Line Smoothing"));
9512 m_cbSoftwareGL =
9513 new wxCheckBox(this, wxID_ANY, _("Software OpenGL (restart OpenCPN)"));
9514 m_cbUseAcceleratedPanning =
9515 new wxCheckBox(this, wxID_ANY, _("Use Accelerated Panning"));
9516
9517 flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Texture Settings")), 0,
9518 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9519 flexSizer->Add(m_cbTextureCompression, 0, wxALL | wxEXPAND, 5);
9520 flexSizer->AddSpacer(0);
9521 flexSizer->Add(m_cbTextureCompressionCaching, 0, wxALL | wxEXPAND, 5);
9522 flexSizer->Add(m_memorySize, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9523 flexSizer->Add(m_sTextureMemorySize, 0, wxALL | wxEXPAND, 5);
9524 flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Texture Cache")), 0,
9525 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9526 flexSizer->Add(m_cacheSize, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, 5);
9527 flexSizer->AddSpacer(0);
9528 flexSizer->Add(btnRebuild, 0, wxALL | wxEXPAND, 5);
9529 flexSizer->AddSpacer(0);
9530 flexSizer->Add(btnClear, 0, wxALL | wxEXPAND, 5);
9531 flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Miscellaneous")), 0,
9532 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9533 flexSizer->Add(m_cbPolygonSmoothing, 0, wxALL | wxEXPAND, 5);
9534 flexSizer->AddSpacer(0);
9535 flexSizer->Add(m_cbLineSmoothing, 0, wxALL | wxEXPAND, 5);
9536 flexSizer->AddSpacer(0);
9537 flexSizer->AddSpacer(0);
9538 flexSizer->Add(m_cbSoftwareGL, 0, wxALL | wxEXPAND, 5);
9539 flexSizer->AddSpacer(0);
9540 flexSizer->Add(m_cbUseAcceleratedPanning, 0, wxALL | wxEXPAND, 5);
9541 flexSizer->AddGrowableCol(1);
9542 mainSizer->Add(flexSizer, 0, wxALL | wxEXPAND, 5);
9543
9544 wxStdDialogButtonSizer* btnSizer = new wxStdDialogButtonSizer();
9545 btnSizer->AddButton(new wxButton(this, wxID_OK));
9546 btnSizer->AddButton(new wxButton(this, wxID_CANCEL, _("Cancel")));
9547 btnSizer->Realize();
9548
9549 mainSizer->AddStretchSpacer();
9550 mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
9551
9552 Populate();
9553
9554 SetSizer(mainSizer);
9555 mainSizer->SetSizeHints(this);
9556 Centre();
9557}
9558
9559bool OpenGLOptionsDlg::GetAcceleratedPanning() const {
9560 return m_cbUseAcceleratedPanning->GetValue();
9561}
9562
9563bool OpenGLOptionsDlg::GetTextureCompression() const {
9564 return m_cbTextureCompression->GetValue();
9565}
9566
9567bool OpenGLOptionsDlg::GetPolygonSmoothing() const {
9568 return m_cbPolygonSmoothing->GetValue();
9569}
9570
9571bool OpenGLOptionsDlg::GetLineSmoothing() const {
9572 return m_cbLineSmoothing->GetValue();
9573}
9574
9575bool OpenGLOptionsDlg::GetSoftwareGL() const {
9576 return m_cbSoftwareGL->GetValue();
9577}
9578
9579bool OpenGLOptionsDlg::GetTextureCompressionCaching() const {
9580 return m_cbTextureCompressionCaching->GetValue();
9581}
9582
9583bool OpenGLOptionsDlg::GetRebuildCache() const { return m_brebuild_cache; }
9584
9585int OpenGLOptionsDlg::GetTextureMemorySize() const {
9586 return m_sTextureMemorySize->GetValue();
9587}
9588
9589void OpenGLOptionsDlg::Populate() {
9590 m_cbTextureCompression->SetValue(g_GLOptions.m_bTextureCompression);
9591 /* disable caching if unsupported */
9592 // if (b_glEntryPointsSet && !s_glCompressedTexImage2D) {
9593 // g_GLOptions.m_bTextureCompressionCaching = FALSE;
9594 // m_cbTextureCompression->Disable();
9595 // m_cbTextureCompression->SetValue(FALSE);
9596 // }
9597
9598 m_cbTextureCompressionCaching->Show(g_bGLexpert);
9599 m_memorySize->Show(g_bGLexpert);
9600 m_sTextureMemorySize->Show(g_bGLexpert);
9601 if (g_bGLexpert) {
9602 m_cbTextureCompressionCaching->SetValue(
9603 g_GLOptions.m_bTextureCompressionCaching);
9604 m_sTextureMemorySize->SetValue(g_GLOptions.m_iTextureMemorySize);
9605 }
9606 m_cbPolygonSmoothing->SetValue(g_GLOptions.m_GLPolygonSmoothing);
9607 m_cbLineSmoothing->SetValue(g_GLOptions.m_GLLineSmoothing);
9608
9609#if defined(__UNIX__) && !defined(__ANDROID__) && !defined(__WXOSX__)
9610 if (top_frame::Get()->GetWxGlCanvas()) {
9611 if (top_frame::Get()->GetGlVersionString().Upper().Find("MESA") !=
9612 wxNOT_FOUND)
9613 m_cbSoftwareGL->SetValue(g_bSoftwareGL);
9614 }
9615#else
9616 m_cbSoftwareGL->Hide();
9617#endif
9618
9619 wxFont* dialogFont = GetOCPNScaledFont(_("Dialog"));
9620 SetFont(*dialogFont);
9621
9622 if (g_bGLexpert) {
9623 if (top_frame::Get()->GetWxGlCanvas()) {
9624 if (top_frame::Get()
9625 ->GetAbstractPrimaryCanvas()
9626 ->CanAccelerateGlPanning()) {
9627 m_cbUseAcceleratedPanning->Enable();
9628 m_cbUseAcceleratedPanning->SetValue(
9629 g_GLOptions.m_bUseAcceleratedPanning);
9630 } else {
9631 m_cbUseAcceleratedPanning->SetValue(FALSE);
9632 m_cbUseAcceleratedPanning->Disable();
9633 }
9634 } else {
9635 m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
9636 }
9637 } else {
9638 m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
9639 m_cbUseAcceleratedPanning->Disable();
9640 }
9641}
9642
9643void OpenGLOptionsDlg::OnButtonRebuild(wxCommandEvent& event) {
9644 if (g_GLOptions.m_bTextureCompressionCaching) {
9645 m_brebuild_cache = TRUE;
9646 EndModal(wxID_CANCEL);
9647 }
9648}
9649
9650void OpenGLOptionsDlg::OnButtonClear(wxCommandEvent& event) {
9651 if (g_bopengl && g_glTextureManager) {
9652 ::wxBeginBusyCursor();
9653 g_glTextureManager->ClearAllRasterTextures();
9654
9655 wxString path = g_Platform->GetPrivateDataDir();
9656 appendOSDirSlash(&path);
9657 path.append("raster_texture_cache");
9658
9659 if (::wxDirExists(path)) {
9660 wxArrayString files;
9661 size_t nfiles = wxDir::GetAllFiles(path, &files);
9662 for (unsigned int i = 0; i < files.GetCount(); i++)
9663 ::wxRemoveFile(files[i]);
9664 }
9665
9666 m_cacheSize->SetLabel(_("Size: ") + GetTextureCacheSize());
9667 ::wxEndBusyCursor();
9668 }
9669}
9670
9671wxString OpenGLOptionsDlg::GetTextureCacheSize() {
9672 wxString path = g_Platform->GetPrivateDataDir();
9673 appendOSDirSlash(&path);
9674 path.append("raster_texture_cache");
9675 long long total = 0;
9676
9677 if (::wxDirExists(path)) {
9678 wxArrayString files;
9679 size_t nfiles = wxDir::GetAllFiles(path, &files);
9680 for (unsigned int i = 0; i < files.GetCount(); i++)
9681 total += wxFile(files[i]).Length();
9682 }
9683 double mb = total / (1024.0 * 1024.0);
9684 if (mb < 10000.0) return wxString::Format("%.1f MB", mb);
9685 mb = mb / 1024.0;
9686 return wxString::Format("%.1f GB", mb);
9687}
9688#endif
9689//-------------------------------------------------------------------------------------------------
9690// CanvasConfig selection panel
9691//-------------------------------------------------------------------------------------------------
9692
9693BEGIN_EVENT_TABLE(CanvasConfigSelect, wxPanel)
9694EVT_PAINT(CanvasConfigSelect::OnPaint)
9695END_EVENT_TABLE()
9696
9697CanvasConfigSelect::CanvasConfigSelect(wxWindow* parent, options* parentOptions,
9698 wxWindowID id, wxBitmap& bmp,
9699 const wxPoint& pos, const wxSize& size)
9700 : wxPanel(parent, id, pos, size, wxBORDER_NONE) {
9701 m_parentOptions = parentOptions;
9702 m_bmpNormal = bmp;
9703 m_borderWidth = 5;
9704 SetSelected(false);
9705
9706 int refHeight = GetCharHeight();
9707 // SetMinSize(wxSize(-1, 5 * refHeight));
9708 SetMinSize(wxSize(bmp.GetSize().x + m_borderWidth * 2,
9709 bmp.GetSize().y + m_borderWidth * 2));
9710
9711 Connect(wxEVT_LEFT_DOWN,
9712 wxMouseEventHandler(CanvasConfigSelect::OnMouseSelected), NULL, this);
9713}
9714
9715CanvasConfigSelect::~CanvasConfigSelect() {}
9716
9717void CanvasConfigSelect::OnMouseSelected(wxMouseEvent& event) {
9718 if (!m_bSelected) {
9719 SetSelected(true);
9720 } else {
9721 SetSelected(false);
9722 }
9723 if (m_parentOptions)
9724 m_parentOptions->OnCanvasConfigSelectClick(GetId(), GetSelected());
9725}
9726
9727void CanvasConfigSelect::SetSelected(bool selected) {
9728 m_bSelected = selected;
9729
9730 if (selected) {
9731 m_boxColour =
9732 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT);
9733 } else {
9734 m_boxColour =
9735 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOW);
9736 }
9737
9738 Refresh(true);
9739}
9740
9741void CanvasConfigSelect::OnPaint(wxPaintEvent& event) {
9742 int width, height;
9743 GetSize(&width, &height);
9744 wxPaintDC dc(this);
9745
9746 dc.SetBackground(*wxLIGHT_GREY);
9747
9748 dc.SetPen(*wxTRANSPARENT_PEN);
9749 dc.SetBrush(wxBrush(GetBackgroundColour()));
9750 dc.DrawRectangle(GetVirtualSize());
9751
9752 if (m_bSelected) {
9753 dc.SetBrush(wxBrush(m_boxColour));
9754 dc.SetPen(wxPen(
9755 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT),
9756 3));
9757 dc.DrawRoundedRectangle(0, 0, width - 1, height - 1, height / 10);
9758 } else {
9759 dc.SetBrush(wxBrush(m_boxColour));
9760 dc.SetPen(wxPen(
9761 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT),
9762 3));
9763 dc.DrawRoundedRectangle(0, 0, width - 1, height - 1, height / 10);
9764 }
9765
9766 dc.DrawBitmap(m_bmpNormal, m_borderWidth, m_borderWidth, false);
9767}
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:174
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
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
Process incoming AIS messages.
Definition ais_decoder.h:76
static double ui_to_config(int slider_pos)
Convert a slider scale 1-100 value to configuration value 1.02..3.0.
Definition navutil.h:157
Custom combobox for selecting waypoint icons.
Definition mark_info.h:150
wxSize getDisplaySize()
Get the display size in logical pixels.
double GetDisplaySizeMM()
Get the width of the screen in millimeters.
obs::EventVar m_on_sp_sound_done
Notified with a OCPN_Sound* pointer when sound has completed.
Definition options.cpp:4818
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
Generic event handling between for example MVC Model and Controller based on a shared EventVar variab...
Definition evtvar.h:78
void Notify() override
Notify all listeners, no data supplied.
Definition evtvar.h:83
Wrapper for global variable, supports notification events when value changes.
Definition global_var.h:69
obs::EventVar m_on_sound_done
Notified with a OCPN_Sound* pointer when sound has completed.
Definition options.h:642
wxRadioButton * pTimezoneUTC
Specify date/time should be formatted in UTC.
Definition options.h:444
wxRadioButton * pTimezoneLocalTime
Specify date/time should be formatted in timezone as configured in the operating system.
Definition options.h:442
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
Communication drivers factory and support.
Misc driver utilities.
Config file user configuration interface.
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.
std::vector< ConnectionParams * > & TheConnectionParams()
Return global list of connections.
Panel for editing a connection.
Options | Connections GUI tab managing connections
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
Definition displays.cpp:45
Display utilities.
A common variable shared between producer and consumer which supports Listen() and Notify().
Font list manager.
GLuint g_raster_format
Global instance.
OpenGL chart rendering canvas.
Platform independent GL includes.
glTextureManager * g_glTextureManager
Global instance.
Global variables Listen()/Notify() wrapper.
Misc GUI event vars, a singleton.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:61
wxFont GetOCPNGUIScaledFont(wxString item)
Retrieves a font optimized for touch and high-resolution interfaces.
Definition gui_lib.cpp:90
size_t g_current_monitor
Current monitor displaying main application frame.
Definition gui_vars.cpp:75
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
GUI constant definitions.
Waypoint properties maintenance dialog.
Multiplexer class and helpers.
MyConfig * pConfig
Global instance.
Definition navutil.cpp:118
Utility functions.
Navigation Utility Functions without GUI dependencies.
Generic font dialog for OpenCPN.
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.