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