OpenCPN Partial API docs
Loading...
Searching...
No Matches
options.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 **************************************************************************/
19
26#include <chrono>
27#include <iterator>
28#include <list>
29#include <map>
30#include <memory>
31#include <sstream>
32
33#ifdef __linux__
34#include <unistd.h>
35#endif
36
37#include "gl_headers.h" // Must be included before anything using GL stuff
38
39#ifdef __MINGW32__
40#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
41#include <windows.h>
42#endif
43
44// For compilers that support precompilation, includes "wx/wx.h".
45#include <wx/wxprec.h>
46
47#ifndef WX_PRECOMP
48#include <wx/wx.h>
49#endif
50
51#include <wx/choice.h>
52#include <wx/clrpicker.h>
53#include <wx/dirdlg.h>
54#include <wx/dir.h>
55#include <wx/display.h>
56#include <wx/fontdata.h>
57#include <wx/fontdlg.h>
58#include <wx/imaglist.h>
59#include <wx/listbox.h>
60#include <wx/mediactrl.h>
61#include <wx/odcombo.h>
62#include <wx/progdlg.h>
63#include <wx/radiobox.h>
64#include <wx/regex.h>
65#include <wx/renderer.h>
66#include <wx/statline.h>
67#include <wx/stdpaths.h>
68#include <wx/textwrapper.h>
69#include <wx/tokenzr.h>
70
71#if defined(__WXGTK__) || defined(__WXQT__)
72#include <wx/colordlg.h>
73#endif
74
75#ifdef __WXGTK__
76#include "ocpn_fontdlg.h"
77#endif
78
79#include "config.h"
80
81#include "o_sound/o_sound.h"
82
83#include "model/ais_decoder.h"
86#include "model/cmdline.h"
88#include "model/comm_util.h"
89#include "model/config_vars.h"
90#include "model/gui_events.h"
91#include "model/gui_vars.h"
92#include "model/idents.h"
93#include "model/multiplexer.h"
94#include "model/navutil_base.h"
95#include "model/own_ship.h"
96#include "model/routeman.h"
97#include "model/ser_ports.h"
98#include "model/svg_utils.h"
99
100#include "ais.h"
101#include "chart_ctx_factory.h"
102#include "chartdbs.h"
103#include "chcanv.h"
104#include "cm93.h"
105#include "config_mgr.h"
106#include "conn_params_panel.h"
107#include "connections_dlg.h"
108#include "displays.h"
109#include "dychart.h"
110#include "font_mgr.h"
111#include "mark_info.h"
112#include "navutil.h"
113#include "observable_evtvar.h"
114#include "observable_globvar.h"
115#include "ocpn_platform.h"
116#include "options.h"
117#include "s52plib.h"
118#include "s52utils.h"
119#include "s57_load.h"
120#include "styles.h"
121#include "top_frame.h"
122#include "usb_devices.h"
123#include "waypointman_gui.h"
124
125#ifdef ocpnUSE_GL
126#include "gl_chart_canvas.h"
127extern GLuint g_raster_format;
128#endif
129
130// Centralized tooltip strings to avoid duplication. Keep translatable.
131static inline wxString ttDistance() {
132 return _(
133 "Horizontal measurements and distances. Examples: Distance between "
134 "geographic positions, visibility range, radar range.");
135}
136static inline wxString ttSpeed() {
137 return _("Vessel and surface speed measurements");
138}
139static inline wxString ttWindSpeed() {
140 return _("Wind speed measurements and forecasts");
141}
142static inline wxString ttDepth() {
143 return _("Measurements below the water surface");
144}
145static inline wxString ttHeight() {
146 return _(
147 "Vertical measurements above reference datum. Examples: Tide level, wave "
148 "height, air gap, mast clearance, elevation above reference datum.");
149}
150static inline wxString ttTemp() {
151 return _("Temperature measurements (air, water, engine)");
152}
153static inline wxString ttCoordFormat() {
154 return _("Coordinate display format for latitude and longitude");
155}
156
157#ifdef __linux__
158#include "udev_rule_mgr.h"
159#endif
160
161#ifdef __ANDROID__
162#include "androidUTIL.h"
163#endif
164
165#ifdef __ANDROID__
166#include <QtWidgets/QScroller>
167#endif
168
169#ifdef __WXOSX__
170#if wxCHECK_VERSION(3, 2, 0)
171#define SLIDER_STYLE wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS
172#else
173#define SLIDER_STYLE wxSL_HORIZONTAL | wxSL_AUTOTICKS
174#endif
175#else
176#define SLIDER_STYLE wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS
177#endif
178
179#define ID_CHOICE_NMEA wxID_HIGHEST + 1
180
181using CBList = std::list<wxCheckBox*>;
182
183options* g_options; // global instance
184options* g_pOptions; // Duplicate to be removed FIXME (leamas)
185
186#if wxUSE_XLOCALE
187extern wxLocale* plocale_def_lang;
188#endif
189
190#ifdef ocpnUSE_GL
191extern ocpnGLOptions g_GLOptions;
192#endif
193
194#ifdef __ANDROID__
195extern int g_Android_SDK_Version;
196extern MigrateAssistantDialog* g_migrateDialog;
197#endif
198
199static wxString GetOCPNKnownLanguage(const wxString lang_canonical,
200 wxString& lang_dir);
201static wxString GetOCPNKnownLanguage(const wxString lang_canonical);
202
203#if wxUSE_XLOCALE
204static int lang_list[] = {
205 wxLANGUAGE_DEFAULT, wxLANGUAGE_ABKHAZIAN, wxLANGUAGE_AFAR,
206 wxLANGUAGE_AFRIKAANS, wxLANGUAGE_ALBANIAN, wxLANGUAGE_AMHARIC,
207 wxLANGUAGE_ARABIC, wxLANGUAGE_ARABIC_ALGERIA, wxLANGUAGE_ARABIC_BAHRAIN,
208 wxLANGUAGE_ARABIC_EGYPT, wxLANGUAGE_ARABIC_IRAQ, wxLANGUAGE_ARABIC_JORDAN,
209 wxLANGUAGE_ARABIC_KUWAIT, wxLANGUAGE_ARABIC_LEBANON,
210 wxLANGUAGE_ARABIC_LIBYA, wxLANGUAGE_ARABIC_MOROCCO, wxLANGUAGE_ARABIC_OMAN,
211 wxLANGUAGE_ARABIC_QATAR, wxLANGUAGE_ARABIC_SAUDI_ARABIA,
212 wxLANGUAGE_ARABIC_SUDAN, wxLANGUAGE_ARABIC_SYRIA, wxLANGUAGE_ARABIC_TUNISIA,
213 // wxLANGUAGE_ARABIC_UAE,
214 wxLANGUAGE_ARABIC_YEMEN, wxLANGUAGE_ARMENIAN, wxLANGUAGE_ASSAMESE,
215 wxLANGUAGE_AYMARA, wxLANGUAGE_AZERI, wxLANGUAGE_AZERI_CYRILLIC,
216 wxLANGUAGE_AZERI_LATIN, wxLANGUAGE_BASHKIR, wxLANGUAGE_BASQUE,
217 wxLANGUAGE_BELARUSIAN, wxLANGUAGE_BENGALI, wxLANGUAGE_BHUTANI,
218 wxLANGUAGE_BIHARI, wxLANGUAGE_BISLAMA, wxLANGUAGE_BRETON,
219 wxLANGUAGE_BULGARIAN, wxLANGUAGE_BURMESE, wxLANGUAGE_CAMBODIAN,
220 wxLANGUAGE_CATALAN,
221 // wxLANGUAGE_CHINESE,
222 // wxLANGUAGE_CHINESE_SIMPLIFIED,
223 // wxLANGUAGE_CHINESE_TRADITIONAL,
224 // wxLANGUAGE_CHINESE_HONGKONG,
225 // wxLANGUAGE_CHINESE_MACAU,
226 // wxLANGUAGE_CHINESE_SINGAPORE,
227 wxLANGUAGE_CHINESE_TAIWAN, wxLANGUAGE_CORSICAN, wxLANGUAGE_CROATIAN,
228 wxLANGUAGE_CZECH, wxLANGUAGE_DANISH, wxLANGUAGE_DUTCH,
229 wxLANGUAGE_DUTCH_BELGIAN, wxLANGUAGE_ENGLISH_UK, wxLANGUAGE_ENGLISH_US,
230 wxLANGUAGE_ENGLISH_AUSTRALIA, wxLANGUAGE_ENGLISH_BELIZE,
231 wxLANGUAGE_ENGLISH_BOTSWANA, wxLANGUAGE_ENGLISH_CANADA,
232 wxLANGUAGE_ENGLISH_CARIBBEAN, wxLANGUAGE_ENGLISH_DENMARK,
233 wxLANGUAGE_ENGLISH_EIRE, wxLANGUAGE_ENGLISH_JAMAICA,
234 wxLANGUAGE_ENGLISH_NEW_ZEALAND, wxLANGUAGE_ENGLISH_PHILIPPINES,
235 wxLANGUAGE_ENGLISH_SOUTH_AFRICA, wxLANGUAGE_ENGLISH_TRINIDAD,
236 wxLANGUAGE_ENGLISH_ZIMBABWE, wxLANGUAGE_ESPERANTO, wxLANGUAGE_ESTONIAN,
237 wxLANGUAGE_FAEROESE, wxLANGUAGE_FARSI, wxLANGUAGE_FIJI, wxLANGUAGE_FINNISH,
238 wxLANGUAGE_FRENCH, wxLANGUAGE_FRENCH_BELGIAN, wxLANGUAGE_FRENCH_CANADIAN,
239 wxLANGUAGE_FRENCH_LUXEMBOURG, wxLANGUAGE_FRENCH_MONACO,
240 wxLANGUAGE_FRENCH_SWISS, wxLANGUAGE_FRISIAN, wxLANGUAGE_GALICIAN,
241 wxLANGUAGE_GEORGIAN, wxLANGUAGE_GERMAN, wxLANGUAGE_GERMAN_AUSTRIAN,
242 wxLANGUAGE_GERMAN_BELGIUM, wxLANGUAGE_GERMAN_LIECHTENSTEIN,
243 wxLANGUAGE_GERMAN_LUXEMBOURG, wxLANGUAGE_GERMAN_SWISS, wxLANGUAGE_GREEK,
244 wxLANGUAGE_GREENLANDIC, wxLANGUAGE_GUARANI, wxLANGUAGE_GUJARATI,
245 wxLANGUAGE_HAUSA, wxLANGUAGE_HEBREW, wxLANGUAGE_HINDI, wxLANGUAGE_HUNGARIAN,
246 wxLANGUAGE_ICELANDIC, wxLANGUAGE_INDONESIAN, wxLANGUAGE_INTERLINGUA,
247 wxLANGUAGE_INTERLINGUE, wxLANGUAGE_INUKTITUT, wxLANGUAGE_INUPIAK,
248 wxLANGUAGE_IRISH, wxLANGUAGE_ITALIAN, wxLANGUAGE_ITALIAN_SWISS,
249 wxLANGUAGE_JAPANESE, wxLANGUAGE_JAVANESE, wxLANGUAGE_KANNADA,
250 wxLANGUAGE_KASHMIRI, wxLANGUAGE_KASHMIRI_INDIA, wxLANGUAGE_KAZAKH,
251 wxLANGUAGE_KERNEWEK, wxLANGUAGE_KINYARWANDA, wxLANGUAGE_KIRGHIZ,
252 wxLANGUAGE_KIRUNDI,
253 // wxLANGUAGE_KONKANI,
254 wxLANGUAGE_KOREAN, wxLANGUAGE_KURDISH, wxLANGUAGE_LAOTHIAN,
255 wxLANGUAGE_LATIN, wxLANGUAGE_LATVIAN, wxLANGUAGE_LINGALA,
256 wxLANGUAGE_LITHUANIAN, wxLANGUAGE_MACEDONIAN, wxLANGUAGE_MALAGASY,
257 wxLANGUAGE_MALAY, wxLANGUAGE_MALAYALAM, wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM,
258 wxLANGUAGE_MALAY_MALAYSIA, wxLANGUAGE_MALTESE,
259 // wxLANGUAGE_MANIPURI,
260 wxLANGUAGE_MAORI, wxLANGUAGE_MARATHI, wxLANGUAGE_MOLDAVIAN,
261 wxLANGUAGE_MONGOLIAN, wxLANGUAGE_NAURU, wxLANGUAGE_NEPALI,
262 wxLANGUAGE_NEPALI_INDIA, wxLANGUAGE_NORWEGIAN_BOKMAL,
263 wxLANGUAGE_NORWEGIAN_NYNORSK, wxLANGUAGE_OCCITAN, wxLANGUAGE_ORIYA,
264 wxLANGUAGE_OROMO, wxLANGUAGE_PASHTO, wxLANGUAGE_POLISH,
265 wxLANGUAGE_PORTUGUESE, wxLANGUAGE_PORTUGUESE_BRAZILIAN, wxLANGUAGE_PUNJABI,
266 wxLANGUAGE_QUECHUA, wxLANGUAGE_RHAETO_ROMANCE, wxLANGUAGE_ROMANIAN,
267 wxLANGUAGE_RUSSIAN, wxLANGUAGE_RUSSIAN_UKRAINE, wxLANGUAGE_SAMOAN,
268 wxLANGUAGE_SANGHO, wxLANGUAGE_SANSKRIT, wxLANGUAGE_SCOTS_GAELIC,
269 wxLANGUAGE_SERBIAN, wxLANGUAGE_SERBIAN_CYRILLIC, wxLANGUAGE_SERBIAN_LATIN,
270 wxLANGUAGE_SERBO_CROATIAN, wxLANGUAGE_SESOTHO, wxLANGUAGE_SETSWANA,
271 wxLANGUAGE_SHONA, wxLANGUAGE_SINDHI, wxLANGUAGE_SINHALESE,
272 wxLANGUAGE_SISWATI, wxLANGUAGE_SLOVAK, wxLANGUAGE_SLOVENIAN,
273 wxLANGUAGE_SOMALI, wxLANGUAGE_SPANISH, wxLANGUAGE_SPANISH_ARGENTINA,
274 wxLANGUAGE_SPANISH_BOLIVIA, wxLANGUAGE_SPANISH_CHILE,
275 wxLANGUAGE_SPANISH_COLOMBIA, wxLANGUAGE_SPANISH_COSTA_RICA,
276 wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, wxLANGUAGE_SPANISH_ECUADOR,
277 wxLANGUAGE_SPANISH_EL_SALVADOR, wxLANGUAGE_SPANISH_GUATEMALA,
278 wxLANGUAGE_SPANISH_HONDURAS, wxLANGUAGE_SPANISH_MEXICAN,
279 // wxLANGUAGE_SPANISH_MODERN,
280 wxLANGUAGE_SPANISH_NICARAGUA, wxLANGUAGE_SPANISH_PANAMA,
281 wxLANGUAGE_SPANISH_PARAGUAY, wxLANGUAGE_SPANISH_PERU,
282 wxLANGUAGE_SPANISH_PUERTO_RICO, wxLANGUAGE_SPANISH_URUGUAY,
283 wxLANGUAGE_SPANISH_US, wxLANGUAGE_SPANISH_VENEZUELA, wxLANGUAGE_SUNDANESE,
284 wxLANGUAGE_SWAHILI, wxLANGUAGE_SWEDISH, wxLANGUAGE_SWEDISH_FINLAND,
285 wxLANGUAGE_TAGALOG, wxLANGUAGE_TAJIK, wxLANGUAGE_TAMIL, wxLANGUAGE_TATAR,
286 wxLANGUAGE_TELUGU, wxLANGUAGE_THAI, wxLANGUAGE_TIBETAN, wxLANGUAGE_TIGRINYA,
287 wxLANGUAGE_TONGA, wxLANGUAGE_TSONGA, wxLANGUAGE_TURKISH, wxLANGUAGE_TURKMEN,
288 wxLANGUAGE_TWI, wxLANGUAGE_UIGHUR, wxLANGUAGE_UKRAINIAN, wxLANGUAGE_URDU,
289 wxLANGUAGE_URDU_INDIA, wxLANGUAGE_URDU_PAKISTAN, wxLANGUAGE_UZBEK,
290 wxLANGUAGE_UZBEK_CYRILLIC, wxLANGUAGE_UZBEK_LATIN, wxLANGUAGE_VIETNAMESE,
291 wxLANGUAGE_VOLAPUK, wxLANGUAGE_WELSH, wxLANGUAGE_WOLOF, wxLANGUAGE_XHOSA,
292 wxLANGUAGE_YIDDISH, wxLANGUAGE_YORUBA, wxLANGUAGE_ZHUANG, wxLANGUAGE_ZULU};
293#endif
294
295#ifdef __ANDROID__
296void prepareSlider(wxSlider* slider) {
297 slider->GetHandle()->setStyleSheet(
298 prepareAndroidSliderStyleSheet(slider->GetSize().x));
299 slider->GetHandle()->setAttribute(Qt::WA_AcceptTouchEvents);
300 slider->GetHandle()->grabGesture(Qt::PanGesture);
301 slider->GetHandle()->grabGesture(Qt::SwipeGesture);
302}
303#endif
304
306
307class ChartDirPanelHardBreakWrapper : public wxTextWrapper {
308public:
309 ChartDirPanelHardBreakWrapper(wxWindow* win, const wxString& text,
310 int widthMax) {
311 m_lineCount = 0;
312
313 // Replace all spaces in the string with a token character '^'
314 wxString textMod = text;
315 textMod.Replace(" ", "^");
316
317 // Replace all path separators with spaces
318 wxString sep = wxFileName::GetPathSeparator();
319 textMod.Replace(sep, " ");
320
321 Wrap(win, textMod, widthMax);
322
323 // walk the output array, repairing the substitutions
324 for (size_t i = 0; i < m_array.GetCount(); i++) {
325 wxString a = m_array[i];
326 a.Replace(" ", sep);
327 if (m_array.GetCount() > 1) {
328 if (i < m_array.GetCount() - 1) a += sep;
329 }
330 a.Replace("^", " ");
331 m_array[i] = a;
332 }
333 }
334 wxString const& GetWrapped() const { return m_wrapped; }
335 int const GetLineCount() const { return m_lineCount; }
336 wxArrayString GetLineArray() { return m_array; }
337
338protected:
339 virtual void OnOutputLine(const wxString& line) {
340 m_wrapped += line;
341 m_array.Add(line);
342 }
343 virtual void OnNewLine() {
344 m_wrapped += '\n';
345 m_lineCount++;
346 }
347
348private:
349 wxString m_wrapped;
350 int m_lineCount;
351 wxArrayString m_array;
352};
353
354class OCPNChartDirPanel : public wxPanel {
355public:
356 OCPNChartDirPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos,
357 const wxSize& size, ChartDirInfo& cdi);
359
360 void DoChartSelected();
361 void SetSelected(bool selected);
362 void OnPaint(wxPaintEvent& event);
363 // void OnEraseBackground( wxEraseEvent &event );
364 void OnSize(wxSizeEvent& event);
365 ChartDirInfo GetCDI() { return m_cdi; }
366 int GetUnselectedHeight() { return m_unselectedHeight; }
367 int GetRefHeight() { return m_refHeight; }
368 bool IsSelected() { return m_bSelected; }
369 void OnClickDown(wxMouseEvent& event);
370 void OnClickUp(wxMouseEvent& event);
371
372private:
373 // shopPanel *m_pContainer;
374 bool m_bSelected;
375 wxColour m_boxColour;
376 int m_unselectedHeight;
377 wxString m_pChartDir;
378 int m_refHeight;
379 ChartDirInfo m_cdi;
380
381 DECLARE_EVENT_TABLE()
382};
383
384BEGIN_EVENT_TABLE(OCPNChartDirPanel, wxPanel)
385EVT_PAINT(OCPNChartDirPanel::OnPaint)
386// EVT_ERASE_BACKGROUND( OCPNChartDirPanel::OnEraseBackground)
387EVT_SIZE(OCPNChartDirPanel::OnSize)
388END_EVENT_TABLE()
389
390OCPNChartDirPanel::OCPNChartDirPanel(wxWindow* parent, wxWindowID id,
391 const wxPoint& pos, const wxSize& size,
392 ChartDirInfo& cdi)
393 : wxPanel(parent, id, pos, size, wxBORDER_NONE) {
394 m_pChartDir = cdi.fullpath;
395
396 // On Android, shorten the displayed path name by removing well-known prefix
397 if (cdi.fullpath.StartsWith(
398 "/storage/emulated/0/Android/data/org.opencpn.opencpn/files"))
399 m_pChartDir = "..." + cdi.fullpath.Mid(58);
400
401 m_cdi = cdi;
402 m_bSelected = false;
403
404 m_refHeight = GetCharHeight();
405
406 m_unselectedHeight = 2 * m_refHeight;
407
408 // #ifdef __ANDROID__
409 // m_unselectedHeight = 2 * m_refHeight;
410 // #endif
411
412 SetMinSize(wxSize(-1, m_unselectedHeight));
413
414 Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(OCPNChartDirPanel::OnClickDown),
415 NULL, this);
416#ifdef __ANDROID__
417 Connect(wxEVT_LEFT_UP, wxMouseEventHandler(OCPNChartDirPanel::OnClickUp),
418 NULL, this);
419#endif
420}
421
422OCPNChartDirPanel::~OCPNChartDirPanel() {}
423
424static wxStopWatch swclick;
425#ifdef __ANDROID__
426static int downx, downy;
427#endif
428
429void OCPNChartDirPanel::OnClickDown(wxMouseEvent& event) {
430#ifdef __ANDROID__
431 swclick.Start();
432 event.GetPosition(&downx, &downy);
433#else
434 DoChartSelected();
435#endif
436}
437
438void OCPNChartDirPanel::OnClickUp(wxMouseEvent& event) {
439#ifdef __ANDROID__
440 qDebug() << swclick.Time();
441 if (swclick.Time() < 200) {
442 int upx, upy;
443 event.GetPosition(&upx, &upy);
444 if ((fabs(upx - downx) < GetCharWidth()) &&
445 (fabs(upy - downy) < GetCharWidth())) {
446 DoChartSelected();
447 }
448 }
449 swclick.Start();
450#endif
451}
452
453void OCPNChartDirPanel::DoChartSelected() {
454 if (!m_bSelected) {
455 SetSelected(true);
456 // m_pContainer->SelectChart( this );
457 } else {
458 SetSelected(false);
459 // m_pContainer->SelectChart( (OCPNChartDirPanel*)NULL );
460 }
461}
462
463void OCPNChartDirPanel::SetSelected(bool selected) {
464 m_bSelected = selected;
465
466 if (selected) {
467 m_boxColour =
468 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT);
469 } else {
470 m_boxColour =
471 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOW);
472 }
473
474 Refresh(true);
475
476 g_pOptions->SetDirActionButtons();
477}
478
479// void OCPNChartDirPanel::OnEraseBackground( wxEraseEvent &event )
480// {
481// }
482
483void OCPNChartDirPanel::OnSize(wxSizeEvent& event) {
484 if (m_pChartDir.Length()) {
485 int x, y;
486 GetClientSize(&x, &y);
487
488 ChartDirPanelHardBreakWrapper wrapper(this, m_pChartDir, x * 9 / 10);
489 wxArrayString nameWrapped = wrapper.GetLineArray();
490
491 SetMinSize(wxSize(-1, (nameWrapped.GetCount() + 1) * m_refHeight));
492 }
493
494 event.Skip();
495}
496
497void OCPNChartDirPanel::OnPaint(wxPaintEvent& event) {
498 int width, height;
499 GetSize(&width, &height);
500 wxPaintDC dc(this);
501
502 dc.SetPen(*wxTRANSPARENT_PEN);
503 dc.SetBrush(wxBrush(GetBackgroundColour()));
504 dc.DrawRectangle(GetVirtualSize());
505
506 wxString nameString = m_pChartDir;
507 ChartDirPanelHardBreakWrapper wrapper(this, nameString, width * 9 / 10);
508 wxArrayString nameWrapped = wrapper.GetLineArray();
509
510 if (height < (int)(nameWrapped.GetCount() + 1) * m_refHeight) {
511 SetMinSize(wxSize(-1, (nameWrapped.GetCount() + 1) * m_refHeight));
512 GetParent()->GetSizer()->Layout();
513 }
514
515 if (m_bSelected) {
516 dc.SetBrush(wxBrush(m_boxColour));
517
518 dc.SetPen(wxPen(wxColor(0xCE, 0xD5, 0xD6), 3));
519
520 dc.DrawRoundedRectangle(0, 0, width - 1, height - 1, height / 10);
521
522 int offset = height / 10;
523 int text_x = offset * 2;
524
525 wxFont* dFont = GetOCPNScaledFont_PlugIn(_("Dialog"));
526 dc.SetFont(*dFont);
527
528 dc.SetTextForeground(
529 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOWTEXT));
530
531 int yd = height * 20 / 100;
532 for (size_t i = 0; i < nameWrapped.GetCount(); i++) {
533 if (i == 0)
534 dc.DrawText(nameWrapped[i], text_x, yd);
535 else
536 dc.DrawText(nameWrapped[i], text_x + GetCharWidth(), yd);
537 yd += GetCharHeight();
538 }
539 } // selected
540 else {
541 dc.SetBrush(wxBrush(m_boxColour));
542
543 dc.SetPen(wxPen(
544 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOWFRAME),
545 1));
546
547 int offset = height / 10;
548 dc.DrawRoundedRectangle(offset, offset, width - (2 * offset),
549 height - (2 * offset), height / 10);
550
551 int text_x = offset * 2;
552
553 wxFont* dFont = GetOCPNScaledFont_PlugIn(_("Dialog"));
554 dc.SetFont(*dFont);
555
556 dc.SetTextForeground(
557 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOWTEXT));
558
559 int yd = height * 20 / 100;
560 for (size_t i = 0; i < nameWrapped.GetCount(); i++) {
561 if (i == 0)
562 dc.DrawText(nameWrapped[i], text_x, yd);
563 else
564 dc.DrawText(nameWrapped[i], text_x + GetCharWidth(), yd);
565 yd += GetCharHeight();
566 }
567
568 } // not selected
569}
570
572
573static bool LoadAllPlugIns(bool load_enabled) {
574 g_Platform->ShowBusySpinner();
575 bool b = PluginLoader::GetInstance()->LoadAllPlugIns(load_enabled);
576 g_Platform->HideBusySpinner();
577 return b;
578}
579
580class OCPNCheckedListCtrl : public wxScrolledWindow {
581public:
583
584 OCPNCheckedListCtrl(wxWindow* parent, wxWindowID id = -1,
585 const wxPoint& pt = wxDefaultPosition,
586 const wxSize& sz = wxDefaultSize,
587 long style = wxHSCROLL | wxVSCROLL,
588 const wxString& name = "scrolledWindow") {
589 Create(parent, id, pt, sz, style, name);
590 }
591
592 bool Create(wxWindow* parent, wxWindowID id = -1,
593 const wxPoint& pt = wxDefaultPosition,
594 const wxSize& sz = wxDefaultSize,
595 long style = wxHSCROLL | wxVSCROLL,
596 const wxString& name = "scrolledWindow");
597
598 virtual ~OCPNCheckedListCtrl() {}
599
600 unsigned int Append(wxString& label, bool benable = true,
601 bool bsizerLayout = true);
602 unsigned int GetCount() { return m_list.size(); }
603
604 void RunLayout();
605
606 void Clear();
607 void Check(int index, bool val);
608 bool IsChecked(int index);
609
610private:
611 wxBoxSizer* m_sizer;
612
613 CBList m_list;
614};
615
616bool OCPNCheckedListCtrl::Create(wxWindow* parent, wxWindowID id,
617 const wxPoint& pt, const wxSize& sz,
618 long style, const wxString& name) {
619 if (!wxScrolledWindow::Create(parent, id, pt, sz, style, name)) return FALSE;
620
621#ifdef __ANDROID__
622 GetHandle()->setObjectName("OCPNCheckedListCtrl");
623 GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
624#endif
625
626 SetScrollRate(0, 2);
627 m_sizer = new wxBoxSizer(wxVERTICAL);
628 SetSizer(m_sizer);
629
630 return TRUE;
631}
632
633unsigned int OCPNCheckedListCtrl::Append(wxString& label, bool benable,
634 bool bsizerLayout) {
635 wxCheckBox* cb = new wxCheckBox(this, wxID_ANY, label);
636 cb->Enable(benable);
637 cb->SetValue(!benable);
638 m_sizer->Add(cb);
639 if (bsizerLayout) m_sizer->Layout();
640
641 m_list.push_back(cb);
642
643 return m_list.size() - 1;
644}
645
646void OCPNCheckedListCtrl::Check(int index, bool val) {
647 auto it = m_list.begin();
648 std::advance(it, index);
649 wxCheckBox* cb = *it;
650
651 if (cb) cb->SetValue(val);
652}
653
654bool OCPNCheckedListCtrl::IsChecked(int index) {
655 auto it = m_list.begin();
656 std::advance(it, index);
657 wxCheckBox* cb = *it;
658
659 return cb ? cb->GetValue() : false;
660}
661
662void OCPNCheckedListCtrl::RunLayout() { m_sizer->Layout(); }
663
664void OCPNCheckedListCtrl::Clear() {
665 m_list.clear();
666 Scroll(0, 0);
667}
668
669// Helper for conditional file name separator
670void appendOSDirSlash(wxString* pString);
671
672extern ArrayOfMmsiProperties g_MMSI_Props_Array;
673
677
678BEGIN_EVENT_TABLE(ConfigCreateDialog, wxDialog)
679EVT_BUTTON(ID_CONFIGEDIT_CANCEL, ConfigCreateDialog::OnConfigEditCancelClick)
680EVT_BUTTON(ID_CONFIGEDIT_OK, ConfigCreateDialog::OnConfigEditOKClick)
681END_EVENT_TABLE()
682
683ConfigCreateDialog::ConfigCreateDialog(wxWindow* parent, wxWindowID id,
684 const wxString& caption,
685 const wxPoint& pos, const wxSize& size,
686 long style)
687 : wxDialog(parent, id, caption, pos, size,
688 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {
689 CreateControls();
690 GetSizer()->SetSizeHints(this);
691 Centre();
692}
693
694ConfigCreateDialog::~ConfigCreateDialog() {}
695
696void ConfigCreateDialog::CreateControls() {
697 wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
698 SetSizer(mainSizer);
699
700 mainSizer->Add(new wxStaticText(this, wxID_STATIC, _("Title")), 0,
701 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
702
703 m_TitleCtl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
704 wxSize(40 * GetCharHeight(), -1), 0);
705 mainSizer->Add(m_TitleCtl, 0,
706 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
707
708 mainSizer->AddSpacer(2 * GetCharHeight());
709
710 mainSizer->Add(new wxStaticText(this, wxID_STATIC, _("Description")), 0,
711 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
712
713 m_DescriptionCtl =
714 new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
715 wxSize(-1, 6 * GetCharHeight()), wxTE_MULTILINE);
716 mainSizer->Add(m_DescriptionCtl, 0,
717 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
718
719 mainSizer->AddSpacer(2 * GetCharHeight());
720
721 mainSizer->Add(
722 new wxStaticText(
723 this, wxID_STATIC,
724 _("Create a private configuration template based on current settings.\n\
725This template will be saved, and may be selected for further use at any time.\n\
726 ")),
727 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
728
729 mainSizer->AddSpacer(2 * GetCharHeight());
730
731 wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
732 mainSizer->Add(btnSizer, 0, wxALIGN_RIGHT | wxALL, 5);
733
734 m_CancelButton = new wxButton(this, ID_CONFIGEDIT_CANCEL, _("Cancel"));
735 btnSizer->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
736
737 m_OKButton = new wxButton(this, ID_CONFIGEDIT_OK, _("OK"));
738 btnSizer->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
739 m_OKButton->SetDefault();
740}
741
742void ConfigCreateDialog::OnConfigEditCancelClick(wxCommandEvent& event) {
743 EndModal(wxID_CANCEL);
744}
745
746void ConfigCreateDialog::OnConfigEditOKClick(wxCommandEvent& event) {
747 const wxString& title = m_TitleCtl->GetValue();
748 const wxString& desc = m_DescriptionCtl->GetValue();
749 m_createdTemplateGUID = ConfigMgr::Get().CreateNamedConfig(title, desc, "");
750 EndModal(wxID_OK);
751}
752
756
757BEGIN_EVENT_TABLE(MMSIEditDialog, wxDialog)
758EVT_BUTTON(ID_MMSIEDIT_CANCEL, MMSIEditDialog::OnMMSIEditCancelClick)
759EVT_BUTTON(ID_MMSIEDIT_OK, MMSIEditDialog::OnMMSIEditOKClick)
760END_EVENT_TABLE()
761
763 wxWindowID id, const wxString& caption,
764 const wxPoint& pos, const wxSize& size,
765 long style)
766 : wxDialog(parent, id, caption, pos, size,
767 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
768 m_props(props) {
769 CreateControls();
770 GetSizer()->SetSizeHints(this);
771 Centre();
772}
773
774MMSIEditDialog::~MMSIEditDialog() { delete m_MMSICtl; }
775
776void MMSIEditDialog::CreateControls() {
777 wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
778 SetSizer(mainSizer);
779
780 wxStaticBox* mmsiBox =
781 new wxStaticBox(this, wxID_ANY, _("MMSI Extended Properties"));
782
783 wxStaticBoxSizer* mmsiSizer = new wxStaticBoxSizer(mmsiBox, wxVERTICAL);
784 mainSizer->Add(mmsiSizer, 0, wxEXPAND | wxALL, 5);
785
786 wxStaticText* mmsiLabel = new wxStaticText(this, wxID_STATIC, _("MMSI"));
787 mmsiLabel->SetToolTip(
788 _("Maritime Mobile Service Identity - A unique 9-digit number assigned "
789 "to a vessel or navigation aid. Used to identify vessels and devices "
790 "in AIS transmissions and DSC calls."));
791 mmsiSizer->Add(mmsiLabel, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
792
793 m_MMSICtl = new wxTextCtrl(this, ID_MMSI_CTL, wxEmptyString,
794 wxDefaultPosition, wxSize(180, -1), 0);
795 m_MMSICtl->SetToolTip(
796 _("Enter the 9-digit MMSI number for this vessel or station"));
797 mmsiSizer->Add(m_MMSICtl, 0,
798 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
799 m_MMSICtl->Bind(wxEVT_TEXT, &MMSIEditDialog::OnMMSIChanged, this);
800
801 wxStaticText* userLabelText = new wxStaticText(this, wxID_STATIC, _("Name"));
802 userLabelText->SetToolTip(
803 _("Display name for this vessel or device - can override names received "
804 "in AIS messages"));
805 mmsiSizer->Add(userLabelText, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
806
807 m_ShipNameCtl = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
808 wxDefaultPosition, wxSize(180, -1), 0);
809 m_ShipNameCtl->SetToolTip(_(
810 "Set the name for this vessel or device. If specified, this name takes "
811 "precedence over names received via AIS messages. Note that standard AIS "
812 "only supports uppercase letters (A-Z), numbers, and limited "
813 "punctuation. Your manual entries are stored in the mmsitoname.csv file "
814 "and preserved across sessions."));
815 mmsiSizer->Add(m_ShipNameCtl, 0,
816 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
817
818 wxStaticBox* trackBox = new wxStaticBox(this, wxID_ANY, _("Tracking"));
819 trackBox->SetToolTip(_("Control how tracks are created for this MMSI"));
820 wxStaticBoxSizer* trackSizer = new wxStaticBoxSizer(trackBox, wxVERTICAL);
821
822 wxGridSizer* gridSizer = new wxGridSizer(0, 3, 0, 0);
823
824 m_rbTypeTrackDefault =
825 new wxRadioButton(this, wxID_ANY, _("Default tracking"),
826 wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
827 m_rbTypeTrackDefault->SetToolTip(
828 _("Use the global tracking settings for this vessel"));
829 m_rbTypeTrackDefault->SetValue(TRUE);
830 gridSizer->Add(m_rbTypeTrackDefault, 0, wxALL, 5);
831
832 m_rbTypeTrackAlways = new wxRadioButton(this, wxID_ANY, _("Always track"));
833 m_rbTypeTrackAlways->SetToolTip(_(
834 "Always create a track for this vessel, regardless of global settings"));
835 gridSizer->Add(m_rbTypeTrackAlways, 0, wxALL, 5);
836
837 m_rbTypeTrackNever = new wxRadioButton(this, wxID_ANY, _(" Never track"));
838 m_rbTypeTrackNever->SetToolTip(
839 _("Never create a track for this vessel, regardless of global settings"));
840 gridSizer->Add(m_rbTypeTrackNever, 0, wxALL, 5);
841
842 m_cbTrackPersist = new wxCheckBox(this, wxID_ANY, _("Persistent"));
843 m_cbTrackPersist->SetToolTip(
844 _("Save this vessel's track between OpenCPN sessions. Useful for vessels "
845 "you want to monitor continuously over time."));
846 gridSizer->Add(m_cbTrackPersist, 0, wxALL, 5);
847
848 trackSizer->Add(gridSizer, 0, wxEXPAND, 0);
849 mmsiSizer->Add(trackSizer, 0, wxEXPAND, 0);
850
851 m_IgnoreButton = new wxCheckBox(this, wxID_ANY, _("Ignore this MMSI"));
852 m_IgnoreButton->SetToolTip(
853 _("When checked, AIS data for this MMSI will be ignored and the vessel "
854 "will not appear on the chart. Useful for suppressing shore stations, "
855 "permanently moored vessels, or duplicate AIS signals that you don't "
856 "need to monitor."));
857 mmsiSizer->Add(m_IgnoreButton, 0, wxEXPAND, 5);
858
859 m_MOBButton = new wxCheckBox(this, wxID_ANY,
860 _("Handle this MMSI as SART/PLB(AIS) MOB."));
861 m_MOBButton->SetToolTip(
862 _("When checked, OpenCPN will display a special icon for this device, "
863 "sound a distinctive alarm, and automatically create a temporary MOB "
864 "route from your vessel to this device in emergency. For crew safety "
865 "devices, you can assign the crew member's name using the Name "
866 "field above for quick identification."));
867 mmsiSizer->Add(m_MOBButton, 0, wxEXPAND, 5);
868
869 m_VDMButton =
870 new wxCheckBox(this, wxID_ANY, _("Convert AIVDM to AIVDO for this MMSI"));
871 m_VDMButton->SetToolTip(
872 _("When checked, converts AIS messages for this vessel from AIVDM (other "
873 "vessel) to AIVDO (own vessel) format."));
874 mmsiSizer->Add(m_VDMButton, 0, wxEXPAND, 5);
875
876 m_FollowerButton = new wxCheckBox(
877 this, wxID_ANY, _("This MMSI is my Follower - No CPA Alert"));
878 m_FollowerButton->SetToolTip(
879 _("When checked, disables CPA (Closest Point of Approach) alerts for "
880 "this vessel as it's considered intentionally following your vessel. "
881 "Follower vessels are displayed with a special own-ship style icon."));
882 mmsiSizer->Add(m_FollowerButton, 0, wxEXPAND, 5);
883
884 wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
885 mainSizer->Add(btnSizer, 0, wxALIGN_RIGHT | wxALL, 5);
886
887 m_CancelButton = new wxButton(this, ID_MMSIEDIT_CANCEL, _("Cancel"));
888 btnSizer->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
889
890 m_OKButton = new wxButton(this, ID_MMSIEDIT_OK, _("OK"));
891 btnSizer->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
892 m_OKButton->SetDefault();
893
894 // Set initial values...
895 wxString sMMSI;
896 if (m_props->MMSI > 0)
897 sMMSI.Printf("%d", m_props->MMSI);
898 else
899 sMMSI = "";
900 m_MMSICtl->AppendText(sMMSI);
901
902 // Initialize user label with existing ship name if available
903 if (!m_props->m_ShipName.IsEmpty()) {
904 m_ShipNameCtl->SetValue(m_props->m_ShipName);
905 }
906
907 switch (m_props->TrackType) {
908 case TRACKTYPE_ALWAYS:
909 m_rbTypeTrackAlways->SetValue(TRUE);
910 break;
911 case TRACKTYPE_NEVER:
912 m_rbTypeTrackNever->SetValue(TRUE);
913 break;
914 default:
915 break;
916 }
917
918 m_cbTrackPersist->SetValue(m_props->m_bPersistentTrack);
919 m_IgnoreButton->SetValue(m_props->m_bignore);
920 m_MOBButton->SetValue(m_props->m_bMOB);
921 m_VDMButton->SetValue(m_props->m_bVDM);
922 m_FollowerButton->SetValue(m_props->m_bFollower);
923
924 SetColorScheme(GLOBAL_COLOR_SCHEME_RGB);
925}
926
927void MMSIEditDialog::SetColorScheme(ColorScheme cs) { DimeControl(this); }
928
929void MMSIEditDialog::OnMMSIEditCancelClick(wxCommandEvent& event) {
930 EndModal(wxID_CANCEL);
931}
932
933void MMSIEditDialog::Persist() {
934 if (m_props) {
935 if (m_rbTypeTrackDefault->GetValue())
936 m_props->TrackType = TRACKTYPE_DEFAULT;
937 else if (m_rbTypeTrackAlways->GetValue())
938 m_props->TrackType = TRACKTYPE_ALWAYS;
939 else
940 m_props->TrackType = TRACKTYPE_NEVER;
941
942 m_props->m_bignore = m_IgnoreButton->GetValue();
943 m_props->m_bMOB = m_MOBButton->GetValue();
944 m_props->m_bVDM = m_VDMButton->GetValue();
945 m_props->m_bFollower = m_FollowerButton->GetValue();
946 m_props->m_bPersistentTrack = m_cbTrackPersist->GetValue();
947
948 // Get user-defined ship name if provided.
949 wxString shipName = m_ShipNameCtl->GetValue().Upper();
950 if (!shipName.IsEmpty()) {
951 m_props->m_ShipName = shipName;
952
953 // Save the custom name to mmsitoname.csv file
954 wxString mmsi = m_MMSICtl->GetValue();
955 if (!mmsi.IsEmpty() && mmsi.Length() == 9 && mmsi.IsNumber()) {
956 g_pAIS->UpdateMMSItoNameFile(mmsi, shipName);
957 }
958 }
959 // If no user label provided and no existing name, try to get from AIS data
960 // or file
961 else if (m_props->m_ShipName == wxEmptyString) {
962 auto proptarget = g_pAIS->Get_Target_Data_From_MMSI(m_props->MMSI);
963 if (proptarget) {
964 wxString s = proptarget->GetFullName();
965 m_props->m_ShipName = s;
966 } else {
967 wxString GetShipNameFromFile(int);
968 m_props->m_ShipName = GetShipNameFromFile(m_props->MMSI);
969 }
970 }
971 }
972}
973
974void MMSIEditDialog::OnMMSIEditOKClick(wxCommandEvent& event) {
975 // Update the MmsiProperties by the passed pointer
976 if (m_props) {
977 long nmmsi;
978 m_MMSICtl->GetValue().ToLong(&nmmsi);
979 m_props->MMSI = nmmsi;
980 Persist();
981
982 if (m_MMSICtl->GetValue().Length() != 9) {
984 this,
985 _("An MMSI Id is generally a number of nine digits.\nPlease check "
986 "your entries and cancel if necessary."),
987 _("OpenCPN Info"), wxOK | wxCANCEL);
988
989 dlg->ShowWindowModalThenDo([this, dlg](int retcode) {
990 if (retcode == wxID_OK) {
991 Persist();
992 }
993 EndModal(retcode);
994 });
995 } else {
996 EndModal(wxID_OK);
997 }
998 }
999}
1000
1001void MMSIEditDialog::OnCtlUpdated(wxCommandEvent& event) {}
1002
1003void MMSIEditDialog::OnMMSIChanged(wxCommandEvent& event) {
1004 wxString mmsi = m_MMSICtl->GetValue();
1005
1006 // Only proceed if we have a valid MMSI (9 digits)
1007 if (!mmsi.IsEmpty() && mmsi.Length() == 9 && mmsi.IsNumber()) {
1008 // First check for a stored name in mmsitoname.csv
1009 wxString shipName = g_pAIS->GetMMSItoNameEntry(mmsi);
1010
1011 // If no stored name found, try to get from AIS data
1012 if (shipName.IsEmpty()) {
1013 auto target = g_pAIS->Get_Target_Data_From_MMSI(wxAtoi(mmsi));
1014 if (target) {
1015 shipName = target->GetFullName();
1016 }
1017 }
1018
1019 // Update the ship name field if we found a name
1020 if (!shipName.IsEmpty()) {
1021 m_ShipNameCtl->SetValue(shipName);
1022 }
1023 }
1024
1025 event.Skip();
1026}
1027
1028BEGIN_EVENT_TABLE(MMSIListCtrl, wxListCtrl)
1029EVT_LIST_ITEM_SELECTED(ID_MMSI_PROPS_LIST, MMSIListCtrl::OnListItemClick)
1030EVT_LIST_ITEM_ACTIVATED(ID_MMSI_PROPS_LIST, MMSIListCtrl::OnListItemActivated)
1031EVT_LIST_ITEM_RIGHT_CLICK(ID_MMSI_PROPS_LIST,
1032 MMSIListCtrl::OnListItemRightClick)
1033EVT_MENU(ID_DEF_MENU_MMSI_EDIT, MMSIListCtrl::PopupMenuHandler)
1034EVT_MENU(ID_DEF_MENU_MMSI_DELETE, MMSIListCtrl::PopupMenuHandler)
1035END_EVENT_TABLE()
1036
1037MMSIListCtrl::MMSIListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
1038 const wxSize& size, long style)
1039 : wxListCtrl(parent, id, pos, size, style) {
1040 m_parent = parent;
1041}
1042
1043MMSIListCtrl::~MMSIListCtrl() {}
1044
1045wxString MMSIListCtrl::OnGetItemText(long item, long column) const {
1046 wxString ret;
1047 MmsiProperties* props = g_MMSI_Props_Array[item];
1048
1049 if (!props) return ret;
1050 switch (column) {
1051 case mlMMSI:
1052 if (props->MMSI > 0) ret = wxString::Format("%d", props->MMSI);
1053 break;
1054 case mlTrackMode:
1055 switch (props->TrackType) {
1056 case TRACKTYPE_DEFAULT:
1057 ret = _("Default");
1058 break;
1059 case TRACKTYPE_ALWAYS:
1060 ret = _("Always");
1061 break;
1062 case TRACKTYPE_NEVER:
1063 ret = _("Never");
1064 break;
1065 default:
1066 ret = "???";
1067 }
1068 if (props->m_bPersistentTrack) ret.Append(", ").Append(_("Persistent"));
1069 break;
1070 case mlIgnore:
1071 if (props->m_bignore) ret = "X";
1072 break;
1073 case mlMOB:
1074 if (props->m_bMOB) ret = "X";
1075 break;
1076 case mlVDM:
1077 if (props->m_bVDM) ret = "X";
1078 break;
1079 case mlFollower:
1080 if (props->m_bFollower) ret = "X";
1081 break;
1082 case mlShipName:
1083 ret = props->m_ShipName;
1084 break;
1085 default:
1086 ret = "??";
1087 break;
1088 }
1089 return ret;
1090}
1091
1092void MMSIListCtrl::OnListItemClick(wxListEvent& event) {}
1093
1094void MMSIListCtrl::OnListItemActivated(wxListEvent& event) {
1095 MmsiProperties* props = g_MMSI_Props_Array.Item(event.GetIndex());
1096 MmsiProperties* props_new = new MmsiProperties(*props);
1097
1098 MMSIEditDialog* pd =
1099 new MMSIEditDialog(props_new, m_parent, -1, _("Edit MMSI Properties"),
1100 wxDefaultPosition, wxSize(200, 200));
1101
1102 if (pd->ShowModal() == wxID_OK) {
1103 g_MMSI_Props_Array.RemoveAt(event.GetIndex());
1104 delete props;
1105 g_MMSI_Props_Array.Insert(props_new, event.GetIndex());
1106 } else
1107 delete props_new;
1108
1109 pd->Destroy();
1110}
1111
1112void MMSIListCtrl::OnListItemRightClick(wxListEvent& event) {
1113 m_context_item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
1114 if (m_context_item == wxNOT_FOUND) return;
1115 wxMenu* menu = new wxMenu(_("MMSI Properties"));
1116 wxMenuItem* item_edit =
1117 new wxMenuItem(menu, ID_DEF_MENU_MMSI_EDIT, _("Edit") + "...");
1118 menu->Append(item_edit);
1119 wxMenuItem* item_delete =
1120 new wxMenuItem(menu, ID_DEF_MENU_MMSI_DELETE, _("Delete"));
1121 menu->Append(item_delete);
1122
1123#ifdef __WXMSW__
1124 wxFont* qFont = GetOCPNScaledFont(_("Menu"));
1125 item_edit->SetFont(*qFont);
1126 item_delete->SetFont(*qFont);
1127#endif
1128
1129 wxPoint p = ScreenToClient(wxGetMousePosition());
1130 PopupMenu(menu, p.x, p.y);
1131
1132 SetItemCount(g_MMSI_Props_Array.GetCount());
1133 Refresh(TRUE);
1134}
1135
1136void MMSIListCtrl::PopupMenuHandler(wxCommandEvent& event) {
1137 int context_item = m_context_item;
1138 MmsiProperties* props = g_MMSI_Props_Array[context_item];
1139
1140 if (!props) return;
1141
1142 switch (event.GetId()) {
1143 case ID_DEF_MENU_MMSI_EDIT: {
1144 MmsiProperties* props_new = new MmsiProperties(*props);
1145 MMSIEditDialog* pd =
1146 new MMSIEditDialog(props_new, m_parent, -1, _("Edit MMSI Properties"),
1147 wxDefaultPosition, wxSize(200, 200));
1148
1149 if (pd->ShowModal() == wxID_OK) {
1150 g_MMSI_Props_Array.RemoveAt(context_item);
1151 delete props;
1152 props_new->m_ShipName = GetShipNameFromFile(props_new->MMSI);
1153 g_MMSI_Props_Array.Insert(props_new, context_item);
1154 } else {
1155 delete props_new;
1156 }
1157 pd->Destroy();
1158 break;
1159 }
1160 case ID_DEF_MENU_MMSI_DELETE:
1161 g_MMSI_Props_Array.RemoveAt(context_item);
1162 delete props;
1163 break;
1164 }
1165}
1166
1167MMSI_Props_Panel::MMSI_Props_Panel(wxWindow* parent)
1168 : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1169 wxBORDER_NONE) {
1170 m_pparent = parent;
1171
1172 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
1173 SetFont(*qFont);
1174
1175 wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
1176 SetSizer(topSizer);
1177
1178 wxString MMSI_props_column_spec = "120;120;100;100;100;100;100;100";
1179 // Parse the global column width string as read from config file
1180 wxStringTokenizer tkz(MMSI_props_column_spec, ";");
1181 wxString s_width = tkz.GetNextToken();
1182 int width;
1183 long lwidth;
1184
1185 m_pListCtrlMMSI = new MMSIListCtrl(
1186 this, ID_MMSI_PROPS_LIST, wxDefaultPosition, wxSize(-1, -1),
1187 wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES |
1188 wxBORDER_SUNKEN | wxLC_VIRTUAL);
1189 // wxImageList* imglist = new wxImageList(16, 16, TRUE, 2);
1190
1191 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
1192 // imglist->Add(style->GetIcon("sort_asc"));
1193 // imglist->Add(style->GetIcon("sort_desc"));
1194
1195 // m_pListCtrlMMSI->AssignImageList( imglist, wxIMAGE_LIST_SMALL );
1196 int dx = GetCharWidth();
1197
1198 width = dx * 5;
1199 if (s_width.ToLong(&lwidth)) {
1200 width = wxMax(dx * 2, lwidth);
1201 width = wxMin(width, dx * 13);
1202 }
1203 m_pListCtrlMMSI->InsertColumn(tlMMSI, _("MMSI"), wxLIST_FORMAT_LEFT, width);
1204
1205 s_width = tkz.GetNextToken();
1206 width = dx * 12;
1207 if (s_width.ToLong(&lwidth)) {
1208 width = wxMax(dx * 2, lwidth);
1209 width = wxMin(width, dx * 25);
1210 }
1211 m_pListCtrlMMSI->InsertColumn(tlCLASS, _("Track Mode"), wxLIST_FORMAT_CENTER,
1212 width);
1213
1214 s_width = tkz.GetNextToken();
1215 width = dx * 8;
1216 if (s_width.ToLong(&lwidth)) {
1217 width = wxMax(dx * 2, lwidth);
1218 width = wxMin(width, dx * 10);
1219 }
1220 m_pListCtrlMMSI->InsertColumn(tlTYPE, _("Ignore"), wxLIST_FORMAT_CENTER,
1221 width);
1222
1223 s_width = tkz.GetNextToken();
1224 width = dx * 8;
1225 if (s_width.ToLong(&lwidth)) {
1226 width = wxMax(dx * 2, lwidth);
1227 width = wxMin(width, dx * 10);
1228 }
1229 m_pListCtrlMMSI->InsertColumn(tlTYPE, _("MOB"), wxLIST_FORMAT_CENTER, width);
1230
1231 s_width = tkz.GetNextToken();
1232 width = dx * 8;
1233 if (s_width.ToLong(&lwidth)) {
1234 width = wxMax(dx * 2, lwidth);
1235 width = wxMin(width, dx * 15);
1236 }
1237 m_pListCtrlMMSI->InsertColumn(tlTYPE, _("VDM->VDO"), wxLIST_FORMAT_CENTER,
1238 width);
1239
1240 s_width = tkz.GetNextToken();
1241 width = dx * 8;
1242 if (s_width.ToLong(&lwidth)) {
1243 width = wxMax(dx * 2, lwidth);
1244 width = wxMin(width, dx * 30);
1245 }
1246 m_pListCtrlMMSI->InsertColumn(tlTYPE, _("Ship name"), wxLIST_FORMAT_CENTER,
1247 width);
1248
1249 s_width = tkz.GetNextToken();
1250 width = dx * 8;
1251 if (s_width.ToLong(&lwidth)) {
1252 width = wxMax(dx * 2, lwidth);
1253 width = wxMin(width, dx * 10);
1254 }
1255 m_pListCtrlMMSI->InsertColumn(tlTYPE, _("Follower"), wxLIST_FORMAT_CENTER,
1256 width); // Has
1257
1258 topSizer->Add(m_pListCtrlMMSI, 1, wxEXPAND | wxALL, 0);
1259
1260 m_pButtonNew = new wxButton(this, wxID_ANY, _("New..."), wxDefaultPosition,
1261 wxSize(200, -1));
1262 m_pButtonNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
1263 wxCommandEventHandler(MMSI_Props_Panel::OnNewButton),
1264 NULL, this);
1265 topSizer->Add(m_pButtonNew, 0, wxALIGN_RIGHT | wxALL, 0);
1266
1267 topSizer->Layout();
1268
1269 // This is silly, but seems to be required for __WXMSW__ build
1270 // If not done, the SECOND invocation of the panel fails to expand the list
1271 // to the full wxSizer size....
1272 SetSize(GetSize().x, GetSize().y - 1);
1273
1274 SetColorScheme(GLOBAL_COLOR_SCHEME_RGB);
1275}
1276
1277MMSI_Props_Panel::~MMSI_Props_Panel() {}
1278
1279void MMSI_Props_Panel::OnNewButton(wxCommandEvent& event) {
1280 MmsiProperties* props = new MmsiProperties(-1);
1281
1282 MMSIEditDialog* pd =
1283 new MMSIEditDialog(props, m_parent, -1, _("Add MMSI Properties"),
1284 wxDefaultPosition, wxSize(200, 200));
1285
1286 DimeControl(pd);
1287 pd->ShowWindowModalThenDo([this, pd, props](int retcode) {
1288 if (retcode == wxID_OK) {
1289 g_MMSI_Props_Array.Add(props);
1290 } else {
1291 delete props;
1292 }
1293 UpdateMMSIList();
1294 });
1295}
1296
1297void MMSI_Props_Panel::UpdateMMSIList() {
1298 // Capture the MMSI of the curently selected list item
1299 long selItemID = wxNOT_FOUND;
1300 m_pListCtrlMMSI->GetNextItem(selItemID, wxLIST_NEXT_ALL,
1301 wxLIST_STATE_SELECTED);
1302
1303 int selMMSI = wxNOT_FOUND;
1304 if (selItemID != wxNOT_FOUND) selMMSI = g_MMSI_Props_Array[selItemID]->MMSI;
1305
1306 m_pListCtrlMMSI->SetItemCount(g_MMSI_Props_Array.GetCount());
1307
1308 // Restore selected item
1309 long item_sel = wxNOT_FOUND;
1310 if (selItemID != wxNOT_FOUND && selMMSI != wxNOT_FOUND) {
1311 for (unsigned int i = 0; i < g_MMSI_Props_Array.GetCount(); i++) {
1312 if (g_MMSI_Props_Array[i]->MMSI == selMMSI) {
1313 item_sel = i;
1314 break;
1315 }
1316 }
1317 }
1318
1319 if (g_MMSI_Props_Array.GetCount() > 0)
1320 m_pListCtrlMMSI->SetItemState(item_sel,
1321 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
1322 wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
1323
1324#ifdef __WXMSW__
1325 m_pListCtrlMMSI->Refresh(FALSE);
1326#endif
1327}
1328
1329void MMSI_Props_Panel::SetColorScheme(ColorScheme cs) { DimeControl(this); }
1330
1331// WX_DECLARE_OBJARRAY(wxBitmap, ArrayOfBitmaps);
1332// #include <wx/arrimpl.cpp>
1333// WX_DEFINE_OBJARRAY(ArrayOfBitmaps);
1334
1335class OCPNFatCombo : public wxOwnerDrawnComboBox {
1336public:
1337 OCPNFatCombo();
1338
1339 OCPNFatCombo(wxWindow* parent, wxWindowID id, const wxString& value = "",
1340 const wxPoint& pos = wxDefaultPosition,
1341 const wxSize& size = wxDefaultSize, int n = 0,
1342 const wxString choices[] = NULL, long style = 0,
1343 const wxValidator& validator = wxDefaultValidator,
1344 const wxString& name = "OCPNFatCombo");
1345
1346 ~OCPNFatCombo();
1347
1348 void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const;
1349 wxCoord OnMeasureItem(size_t item) const;
1350 wxCoord OnMeasureItemWidth(size_t item) const;
1351 bool SetFont(const wxFont& font);
1352
1353 int Append(const wxString& item, wxBitmap bmp);
1354 void Clear();
1355
1356 const wxFont* dfont;
1357
1358private:
1359 int itemHeight;
1360 ArrayOfBitmaps bmpArray;
1361};
1362
1363OCPNFatCombo::OCPNFatCombo() : wxOwnerDrawnComboBox() {}
1364
1365OCPNFatCombo::OCPNFatCombo(wxWindow* parent, wxWindowID id,
1366 const wxString& value, const wxPoint& pos,
1367 const wxSize& size, int n, const wxString choices[],
1368 long style, const wxValidator& validator,
1369 const wxString& name)
1370 : wxOwnerDrawnComboBox(parent, id, value, pos, size, n, choices, style,
1371 validator, name) {
1372 double fontHeight =
1373 GetFont().GetPointSize() / g_Platform->getFontPointsperPixel();
1374 itemHeight = (int)wxRound(fontHeight);
1375 SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
1376}
1377
1378OCPNFatCombo::~OCPNFatCombo() {}
1379
1380bool OCPNFatCombo::SetFont(const wxFont& font) {
1381 dfont = &font;
1382 return true;
1383}
1384
1385void OCPNFatCombo::OnDrawItem(wxDC& dc, const wxRect& rect, int item,
1386 int flags) const {
1387 int offset_x = 10;
1388 // dc.DrawBitmap(bmpArray.Item(item), rect.x, rect.y + (rect.height -
1389 // bmpHeight)/2, true);
1390 dc.SetFont(*dfont);
1391
1392 wxColor bg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
1393 wxBrush br = wxBrush(bg);
1394 wxBrush sv = dc.GetBrush();
1395 dc.SetBrush(br);
1396 dc.DrawRectangle(0, 0, rect.width, rect.height);
1397 dc.SetBrush(sv);
1398 dc.SetTextForeground(wxColour(0, 0, 0));
1399
1400 if (flags & wxODCB_PAINTING_CONTROL) {
1401 wxString text = GetValue();
1402 int margin_x = 2;
1403 dc.DrawText(text, rect.x + margin_x + offset_x,
1404 (rect.height - dc.GetCharHeight()) / 2 + rect.y);
1405 } else {
1406 dc.SetBackground(wxBrush(br));
1407 dc.Clear();
1408 dc.DrawText(GetVListBoxComboPopup()->GetString(item), rect.x + 2 + offset_x,
1409 (rect.height - dc.GetCharHeight()) / 2 + rect.y);
1410 }
1411}
1412
1413wxCoord OCPNFatCombo::OnMeasureItem(size_t item) const {
1414 if (item < bmpArray.GetCount())
1415 return wxMax(itemHeight, bmpArray.Item(item).GetHeight());
1416
1417 return itemHeight * 12 / 10;
1418}
1419
1420wxCoord OCPNFatCombo::OnMeasureItemWidth(size_t item) const { return -1; }
1421
1422int OCPNFatCombo::Append(const wxString& item, wxBitmap bmp) {
1423 bmpArray.Add(bmp);
1424 int idx = wxOwnerDrawnComboBox::Append(item);
1425
1426 return idx;
1427}
1428
1429void OCPNFatCombo::Clear() {
1430 wxOwnerDrawnComboBox::Clear();
1431 bmpArray.Clear();
1432}
1433
1434BEGIN_EVENT_TABLE(options, wxDialog)
1435EVT_INIT_DIALOG(options::OnDialogInit)
1436EVT_CHECKBOX(ID_DEBUGCHECKBOX1, options::OnDebugcheckbox1Click)
1437EVT_BUTTON(ID_BUTTONADD, options::OnButtonaddClick)
1438EVT_BUTTON(ID_BUTTONDELETE, options::OnButtondeleteClick)
1439EVT_BUTTON(ID_PARSEENCBUTTON, options::OnButtonParseENC)
1440EVT_BUTTON(ID_REBUILDBUTTON, options::OnButtonRebuildChartDb)
1441EVT_BUTTON(ID_BUTTONCOMPRESS, options::OnButtoncompressClick)
1442EVT_BUTTON(ID_BUTTONMIGRATE, options::OnButtonmigrateClick)
1443EVT_BUTTON(ID_TCDATAADD, options::OnInsertTideDataLocation)
1444EVT_BUTTON(ID_TCDATADEL, options::OnRemoveTideDataLocation)
1445EVT_BUTTON(ID_APPLY, options::OnApplyClick)
1446EVT_BUTTON(xID_OK, options::OnXidOkClick)
1447EVT_BUTTON(wxID_CANCEL, options::OnCancelClick)
1448EVT_BUTTON(ID_BUTTONFONTCHOOSE, options::OnChooseFont)
1449EVT_BUTTON(ID_BUTTONFONT_RESET, options::OnResetFont)
1450EVT_BUTTON(ID_BUTTONECDISHELP, options::OnButtonEcdisHelp)
1451
1452EVT_CHOICE(ID_CHOICE_FONTELEMENT, options::OnFontChoice)
1453EVT_CLOSE(options::OnClose)
1454
1455#if defined(__WXGTK__) || defined(__WXQT__)
1456EVT_BUTTON(ID_BUTTONFONTCOLOR, options::OnChooseFontColor)
1457#endif
1458#ifdef ocpnUSE_GL
1459EVT_BUTTON(ID_OPENGLOPTIONS, options::OnOpenGLOptions)
1460#endif
1461EVT_CHOICE(ID_RADARDISTUNIT, options::OnDisplayCategoryRadioButton)
1462EVT_CHOICE(ID_DEPTHUNITSCHOICE, options::OnUnitsChoice)
1463EVT_CHOICE(ID_HEIGHTUNITSCHOICE, options::OnUnitsChoice)
1464EVT_BUTTON(ID_CLEARLIST, options::OnButtonClearClick)
1465EVT_BUTTON(ID_SELECTLIST, options::OnButtonSelectClick)
1466EVT_BUTTON(ID_SETSTDLIST, options::OnButtonSetStd)
1467EVT_CHOICE(ID_SHIPICONTYPE, options::OnShipTypeSelect)
1468EVT_CHOICE(ID_RADARRINGS, options::OnRadarringSelect)
1469EVT_CHOICE(ID_OPWAYPOINTRANGERINGS, options::OnWaypointRangeRingSelect)
1470EVT_CHAR_HOOK(options::OnCharHook)
1471
1472END_EVENT_TABLE()
1473
1474options::options(wxWindow* parent, OptionsCallbacks callbacks, wxWindowID id,
1475 const wxString& caption, const wxPoint& pos,
1476 const wxSize& size, long style)
1477 : pTrackRotateTime(0), m_callbacks(callbacks) {
1478 Init();
1479
1480 pParent = parent;
1481
1482 SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
1483
1484 wxDialog::Create(parent, id, caption, pos, size, style, "Options");
1485 SetFont(*dialogFont);
1486
1487 CreateControls();
1488 RecalculateSize(size.x, size.y);
1489
1490 wxDEFINE_EVENT(EVT_COMPAT_OS_CHANGE, wxCommandEvent);
1491 GlobalVar<wxString> compat_os(&g_compatOS);
1492 compat_os_listener.Listen(compat_os, this, EVT_COMPAT_OS_CHANGE);
1493 Bind(EVT_COMPAT_OS_CHANGE, [&](wxCommandEvent&) {
1494 PluginLoader::GetInstance()->LoadAllPlugIns(false);
1495 m_pPlugInCtrl->ReloadPluginPanels();
1496 });
1497 auto action = [&](wxCommandEvent& evt) {
1498 g_persist_active_route = m_persist_active_route_chkbox->IsChecked();
1499 };
1500 m_persist_active_route_chkbox->Bind(wxEVT_CHECKBOX, action);
1501 m_persist_active_route_chkbox->SetValue(g_persist_active_route);
1502
1503 m_OnChartDb_finalize_listener.Init(
1504 GuiEvents::GetInstance().on_finalize_chartdbs,
1505 [&](ObservedEvt& ev) { OptionsFinalizeChartDBUpdate(); });
1506}
1507
1508options::~options() {
1509 wxNotebook* nb =
1510 dynamic_cast<wxNotebook*>(m_pListbook->GetPage(m_pageCharts));
1511 if (nb)
1512 nb->Disconnect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
1513 wxListbookEventHandler(options::OnChartsPageChange), NULL,
1514 this);
1515
1516 groupsPanel->EmptyChartGroupArray(m_pGroupArray);
1517
1518 delete m_pSerialArray;
1519 delete m_pGroupArray;
1520 delete m_topImgList;
1521
1522 // Take care of the plugin manager...
1523
1524 delete m_pPlugInCtrl;
1525 if (g_pi_manager) g_pi_manager->SetListPanelPtr(NULL);
1526#ifndef __ANDROID__
1527 delete m_PluginCatalogMgrPanel;
1528#endif
1529}
1530
1531// with AIS it's called very often
1532bool options::SendIdleEvents(wxIdleEvent& event) {
1533 if (IsShown()) return wxDialog::SendIdleEvents(event);
1534 return false;
1535}
1536
1537void options::OptionsFinalizeChartDBUpdate() {
1538 m_CurrentDirList =
1539 *m_pWorkDirList; // Perform a deep copy back to main database.
1540 // Re-enable RNC texture caching
1541 g_GLOptions.m_bTextureCompressionCaching = m_bTextureCacheingSave;
1542}
1543
1544void options::RecalculateSize(int hint_x, int hint_y) {
1545 if (!g_bresponsive) {
1546 m_nCharWidthMax = GetSize().x / GetCharWidth();
1547
1548 // Protect against unreasonable small size
1549 // And also handle the empty config file init case.
1550 if ((hint_x < 200) || (hint_y < 200)) {
1551 // Constrain size on small displays
1552 int display_width, display_height;
1553 display_width = g_monitor_info[g_current_monitor].width;
1554 display_height = g_monitor_info[g_current_monitor].height;
1555
1556 if (display_height < 600) {
1557 SetSize(wxSize(GetOCPNCanvasWindow()->GetSize()));
1558 } else {
1559 vectorPanel->SetSizeHints(ps57Ctl);
1560 Fit();
1561 }
1562 }
1563
1564 CenterOnScreen();
1565 return;
1566 }
1567
1568 wxSize esize;
1569 esize.x = GetCharWidth() * 110;
1570 esize.y = GetCharHeight() * 40;
1571
1572 wxSize dsize = GetParent()->GetSize(); // GetClientSize();
1573 esize.y = wxMin(esize.y, dsize.y - 0 /*(2 * GetCharHeight())*/);
1574 esize.x = wxMin(esize.x, dsize.x - 0 /*(2 * GetCharHeight())*/);
1575 SetSize(esize);
1576
1577 wxSize fsize = GetSize();
1578 wxSize canvas_size = GetParent()->GetSize();
1579 wxPoint screen_pos = GetParent()->GetScreenPosition();
1580 int xp = (canvas_size.x - fsize.x) / 2;
1581 int yp = (canvas_size.y - fsize.y) / 2;
1582 Move(screen_pos.x + xp, screen_pos.y + yp);
1583
1584 m_nCharWidthMax = GetSize().x / GetCharWidth();
1585}
1586
1587void options::Init() {
1588 m_pWorkDirList = NULL;
1589
1590 pShowStatusBar = NULL;
1591 pShowMenuBar = NULL;
1592 pShowCompassWin = NULL;
1593 pSelCtl = NULL;
1594 // pActiveChartsList = NULL;
1595 m_scrollWinChartList = NULL;
1596 ps57CtlListBox = NULL;
1597 pDispCat = NULL;
1598 m_pSerialArray = NULL;
1599 pUpdateCheckBox = NULL;
1600 pParseENCButton = NULL;
1601 k_charts = 0;
1602 k_vectorcharts = 0;
1603 k_plugins = 0;
1604 m_pConfig = NULL;
1605
1606 pSoundDeviceIndex = NULL;
1607
1608 pCBNorthUp = NULL;
1609 pCBCourseUp = NULL;
1610 pCBLookAhead = NULL;
1611 pCDOQuilting = NULL;
1612 pPreserveScale = NULL;
1613 pSmoothPanZoom = NULL;
1614 pEnableZoomToCursor = NULL;
1615 pSDisplayGrid = NULL;
1616 pCDOOutlines = NULL;
1617 pSDepthUnits = NULL;
1618 pSLiveETA = NULL;
1619 pSDefaultBoatSpeed = NULL;
1620
1621 activeSizer = NULL;
1622 itemActiveChartStaticBox = NULL;
1623
1624 pCheck_SOUNDG = NULL;
1625 pCheck_META = NULL;
1626 pCheck_SHOWIMPTEXT = NULL;
1627 pCheck_SCAMIN = NULL;
1628 pCheck_ATONTEXT = NULL;
1629 pCheck_LDISTEXT = NULL;
1630 pCheck_XLSECTTEXT = NULL;
1631
1632 m_bVisitLang = FALSE;
1633 m_bVisitPlugins = FALSE;
1634 m_itemFontElementListBox = NULL;
1635 m_textSample = NULL;
1636 m_topImgList = NULL;
1637
1638 m_pListbook = NULL;
1639 m_pGroupArray = NULL;
1640 m_groups_changed = 0;
1641
1642 m_pageDisplay = -1;
1643 m_pageConnections = -1;
1644 m_pageCharts = -1;
1645 m_pageShips = -1;
1646 m_pageUI = -1;
1647 m_pagePlugins = -1;
1648 m_pageConnections = -1;
1649
1650 pEnableTenHertz = nullptr;
1651
1652 auto loader = PluginLoader::GetInstance();
1653 b_haveWMM = loader && loader->IsPlugInAvailable("WMM");
1654 b_oldhaveWMM = b_haveWMM;
1655
1656 lastPage = 0;
1657 m_bneedNew = false;
1658
1659 m_bForceNewToolbaronCancel = false;
1660
1661 m_cs = (ColorScheme)0;
1662
1663 // for deferred loading
1664 m_pPlugInCtrl = NULL;
1665 m_PluginCatalogMgrPanel = NULL;
1666
1667 m_pNMEAForm = NULL;
1668 // FIXME Do this in CTOR of connections dialog
1669 // mSelectedConnection = NULL;
1670
1671#ifdef __ANDROID__
1672 m_scrollRate = 1;
1673#else
1674 m_scrollRate = 15;
1675#endif
1676
1677 dialogFont = GetOCPNScaledFont(_("Dialog"));
1678
1679 m_bVectorInit = false;
1680
1681 // This variable is used by plugin callback function AddOptionsPage
1682 g_pOptions = this;
1683
1684 pCmdSoundString = NULL;
1685
1686 m_sconfigSelect_single = NULL;
1687 m_sconfigSelect_twovertical = NULL;
1688
1689 wxScreenDC dc;
1690 dc.SetFont(*dialogFont);
1691 int width, height;
1692 dc.GetTextExtent("H", &width, &height, NULL, NULL, dialogFont);
1693
1694 m_colourPickerDefaultSize =
1695 wxSize(4 * height, height * 2 * OCPN_GetWinDIPScaleFactor());
1696
1697 m_bcompact = false;
1698
1699 // wxSize dSize = g_Platform->getDisplaySize();
1700 // if ( dSize.x < width * 40)
1701 // m_bcompact = true;
1702
1703 double dsizemm = g_Platform->GetDisplaySizeMM();
1704 if (dsizemm < 80) // Probably and Android Phone, portrait mode
1705 m_bcompact = true;
1706
1707 auto sound_action = [](ObservedEvt ev) {
1708 auto sound = static_cast<o_sound::Sound*>(ev.GetClientData());
1709
1710 delete sound;
1711 };
1712 m_sound_done_listener.Init(m_on_sound_done, sound_action);
1713}
1714
1715// Distance format mapping helper functions
1717 wxString label;
1718 int enumValue;
1719};
1720
1721static const DistanceFormatMapping kDistanceFormats[] = {
1722 {_("Nautical miles"), DISTANCE_NMI},
1723 {_("Statute miles"), DISTANCE_MI},
1724 {_("Kilometers"), DISTANCE_KM},
1725 {_("Meters"), DISTANCE_M}};
1726
1727static const int kNumDistanceFormats =
1728 sizeof(kDistanceFormats) / sizeof(DistanceFormatMapping);
1729
1730// Get the index for a given distance format enum value
1731static int GetDistanceFormatIndex(int enumValue) {
1732 for (int i = 0; i < kNumDistanceFormats; i++) {
1733 if (kDistanceFormats[i].enumValue == enumValue) {
1734 return i;
1735 }
1736 }
1737 return 0; // Default to NMi
1738}
1739
1740// Get the enum value for a given index
1741static int GetDistanceFormatEnum(int index) {
1742 if (index >= 0 && index < kNumDistanceFormats) {
1743 return kDistanceFormats[index].enumValue;
1744 }
1745 return DISTANCE_NMI; // Default to NMi
1746}
1747
1748#if defined(__GNUC__) && __GNUC__ < 8
1749// Handle old gcc C++-11 bugs, remove when builders updated to gcc >= 8.1.1.
1750
1751static const wxString BAD_ACCESS_MSG = _(
1752 "The device selected is not accessible; opencpn will likely not be able\n"
1753 "to use this device as-is. You might want to exit OpenCPN, reboot and\n"
1754 "retry after creating a file called /etc/udev/rules.d/70-opencpn.rules\n"
1755 "with the following contents:\n\n"
1756 " KERNEL==\"ttyUSB*\", MODE=\"0666\"\n"
1757 " KERNEL==\"ttyACM*\", MODE=\"0666\"\n"
1758 " KERNEL==\"ttyS*\", MODE=\"0666\"\n\n"
1759 "For more info, see the file LINUX_DEVICES.md in the distribution docs.\n");
1760
1761#else
1762
1763static const wxString BAD_ACCESS_MSG = _(R"(
1764The device selected is not accessible; opencpn will likely not be able
1765to use this device as-is. You might want to exit OpenCPN, reboot and
1766retry after creating a file called /etc/udev/rules.d/70-opencpn.rules
1767with the following contents:
1768
1769 KERNEL=="ttyUSB*", MODE="0666"
1770 KERNEL=="ttyACM*", MODE="0666"
1771 KERNEL=="ttyS*", MODE="0666"
1772
1773For more info, see the file LINUX_DEVICES.md in the distribution docs.
1774)");
1775
1776#endif // defined(__GNUC__) && __GNUC__ < 8
1777
1778void options::OnDialogInit(wxInitDialogEvent& event) {}
1779
1780void options::CheckDeviceAccess(/*[[maybe_unused]]*/ wxString& path) {}
1781
1782size_t options::CreatePanel(const wxString& title) {
1783 size_t id = m_pListbook->GetPageCount();
1784 /* This is the default empty content for any top tab.
1785 It'll be replaced when we call AddPage */
1786 wxPanel* panel = new wxPanel(m_pListbook, wxID_ANY, wxDefaultPosition,
1787 wxDefaultSize, wxTAB_TRAVERSAL, title);
1788 m_pListbook->AddPage(panel, title, FALSE, id);
1789 return id;
1790}
1791
1792wxScrolledWindow* options::AddPage(size_t parent, const wxString& title) {
1793 if (parent > m_pListbook->GetPageCount() - 1) {
1794 wxLogMessage(
1795 wxString::Format("Warning: invalid parent in options::AddPage( %d, ",
1796 parent) +
1797 title + " )");
1798 return NULL;
1799 }
1800 wxNotebookPage* page = m_pListbook->GetPage(parent);
1801 wxNotebook* nb;
1802 wxScrolledWindow* sw;
1803
1804 int style = wxVSCROLL | wxTAB_TRAVERSAL;
1805 if ((nb = dynamic_cast<wxNotebook*>(page))) {
1806 // Check and avoid adding duplicate
1807 for (size_t i_page = 0; i_page < nb->GetPageCount(); i_page++) {
1808 wxString candidate_title = nb->GetPageText(i_page);
1809 if (candidate_title.IsSameAs(title))
1810 return static_cast<wxScrolledWindow*>(nb->GetPage(i_page));
1811 }
1812
1813 sw = new wxScrolledWindow(page, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1814 style);
1815 sw->SetScrollRate(m_scrollRate, m_scrollRate);
1816 nb->AddPage(sw, title);
1817 } else if ((sw = dynamic_cast<wxScrolledWindow*>(page))) {
1818 wxString toptitle = m_pListbook->GetPageText(parent);
1819 wxNotebook* nb = new wxNotebook(m_pListbook, wxID_ANY, wxDefaultPosition,
1820 wxDefaultSize, wxNB_TOP);
1821 /* Only remove the tab from listbook, we still have original content in
1822 * {page} */
1823 m_pListbook->InsertPage(parent, nb, toptitle, FALSE, parent);
1824 m_pListbook->SetSelection(0); // avoid gtk assertions
1825 m_pListbook->RemovePage(parent + 1);
1826 wxString previoustitle = page->GetName();
1827 page->Reparent(nb);
1828 nb->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
1829 wxNotebookEventHandler(options::OnSubNBPageChange), NULL, this);
1830
1831 nb->AddPage(page, previoustitle);
1832 /* wxNotebookPage is hidden under wxGTK after RemovePage/Reparent
1833 * we must explicitely Show() it */
1834 page->Show();
1835 sw = new wxScrolledWindow(nb, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1836 style);
1837 sw->SetScrollRate(m_scrollRate, m_scrollRate);
1838 nb->AddPage(sw, title);
1839 nb->ChangeSelection(0);
1840 } else { // This is the default content, we can replace it now
1841 sw = new wxScrolledWindow(m_pListbook, wxID_ANY, wxDefaultPosition,
1842 wxDefaultSize, style, title);
1843 sw->SetScrollRate(m_scrollRate, m_scrollRate);
1844 wxString toptitle = m_pListbook->GetPageText(parent);
1845 m_pListbook->InsertPage(parent, sw, toptitle, FALSE, parent);
1846 m_pListbook->SetSelection(0); // avoid gtk assertions
1847 m_pListbook->DeletePage(parent + 1);
1848 }
1849
1850#ifdef __ANDROID__
1851 sw->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
1852#endif
1853
1854 return sw;
1855}
1856
1857bool options::DeletePluginPage(wxScrolledWindow* page) {
1858 for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
1859 wxNotebookPage* pg = m_pListbook->GetPage(i);
1860 auto nb = dynamic_cast<wxNotebook*>(pg);
1861
1862 if (nb) {
1863 for (size_t j = 0; j < nb->GetPageCount(); j++) {
1864 wxNotebookPage* spg = nb->GetPage(j);
1865 if (spg == page) {
1866 nb->DeletePage(j);
1867 if (nb->GetPageCount() != 1) return TRUE;
1868 /* There's only one page, remove inner notebook */
1869 spg = nb->GetPage(0);
1870 spg->Reparent(m_pListbook);
1871 nb->RemovePage(0);
1872 wxString toptitle = m_pListbook->GetPageText(i);
1873 m_pListbook->DeletePage(i);
1874 m_pListbook->InsertPage(i, spg, toptitle, FALSE, i);
1875 return TRUE;
1876 }
1877 }
1878 } else if (pg == page) {
1879 /* There's only one page, replace it with empty panel */
1880 m_pListbook->DeletePage(i);
1881 wxPanel* panel = new wxPanel(m_pListbook);
1882 wxString toptitle = m_pListbook->GetPageText(i);
1883 m_pListbook->InsertPage(i, panel, toptitle, FALSE, i);
1884 return TRUE;
1885 }
1886 }
1887 return FALSE;
1888}
1889
1890void options::CreatePanel_NMEA(size_t parent, int border_size,
1891 int group_item_spacing) {
1892 m_pNMEAForm = AddPage(parent, _("NMEA"));
1893
1894 comm_dialog =
1895 std::make_shared<ConnectionsDlg>(m_pNMEAForm, TheConnectionParams());
1896 // Hijack the options | Resize event for use by comm_dialog only.
1897 // Needs new solution if other pages also have a need to act on it.
1898 Bind(wxEVT_SIZE, [&](wxSizeEvent& ev) {
1899 auto w = m_pListbook->GetCurrentPage();
1900 comm_dialog->OnResize(w ? w->GetClientSize() : wxSize());
1901 ev.Skip();
1902 });
1903#ifdef __ANDROID__
1904 comm_dialog->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet());
1905#endif
1906}
1907
1908void options::CreatePanel_Ownship(size_t parent, int border_size,
1909 int group_item_spacing) {
1910 itemPanelShip = AddPage(parent, _("Own ship"));
1911
1912 ownShip = new wxBoxSizer(wxVERTICAL);
1913 itemPanelShip->SetSizer(ownShip);
1914
1915 // OwnShip Display options
1916 wxStaticBox* osdBox =
1917 new wxStaticBox(itemPanelShip, wxID_ANY, _("Display Options"));
1918 dispOptions = new wxStaticBoxSizer(osdBox, wxVERTICAL);
1919 ownShip->Add(dispOptions, 0, wxTOP | wxALL | wxEXPAND, border_size);
1920
1921 wxFlexGridSizer* dispOptionsGrid =
1922 new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
1923 dispOptionsGrid->AddGrowableCol(1);
1924 dispOptions->Add(dispOptionsGrid, 0, wxALL | wxEXPAND, border_size);
1925
1926 wxStaticText* pStatic_OSCOG_Predictor = new wxStaticText(
1927 itemPanelShip, wxID_ANY, _("COG Predictor Length (min)"));
1928 dispOptionsGrid->Add(pStatic_OSCOG_Predictor, 0);
1929
1930 m_pText_OSCOG_Predictor = new wxTextCtrl(itemPanelShip, wxID_ANY, "TEXT");
1931 dispOptionsGrid->Add(m_pText_OSCOG_Predictor, 0, wxALIGN_RIGHT);
1932
1933 wxStaticText* pStatic_OSHDT_Predictor = new wxStaticText(
1934 itemPanelShip, wxID_ANY, _("Heading Predictor Length (NMi)"));
1935 dispOptionsGrid->Add(pStatic_OSHDT_Predictor, 0);
1936
1937 m_pText_OSHDT_Predictor = new wxTextCtrl(itemPanelShip, wxID_ANY, "TEXT");
1938 dispOptionsGrid->Add(m_pText_OSHDT_Predictor, 0, wxALIGN_RIGHT);
1939
1940 wxStaticText* iconTypeTxt =
1941 new wxStaticText(itemPanelShip, wxID_ANY, _("Ship Icon Type"));
1942 dispOptionsGrid->Add(iconTypeTxt, 0);
1943
1944 wxString iconTypes[] = {_("Default"), _("Real Scale Bitmap"),
1945 _("Real Scale Vector")};
1946
1947 m_pShipIconType = new wxChoice(
1948 itemPanelShip, ID_SHIPICONTYPE, wxDefaultPosition,
1949 wxSize(GetCharWidth() * 20, GetCharHeight() * 2), 3, iconTypes);
1950 dispOptionsGrid->Add(m_pShipIconType, 0,
1951 wxALIGN_RIGHT | wxLEFT | wxRIGHT | wxTOP,
1952 group_item_spacing);
1953
1954 realSizes = new wxFlexGridSizer(5, 2, group_item_spacing, group_item_spacing);
1955 realSizes->AddGrowableCol(1);
1956
1957 dispOptions->Add(realSizes, 0, wxEXPAND | wxLEFT, 30);
1958
1959 realSizes->Add(
1960 new wxStaticText(itemPanelShip, wxID_ANY, _("Length Over All (m)")), 1,
1961 wxALIGN_LEFT);
1962 m_pOSLength = new wxTextCtrl(itemPanelShip, 1, "TEXT ");
1963 realSizes->Add(m_pOSLength, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
1964
1965 realSizes->Add(
1966 new wxStaticText(itemPanelShip, wxID_ANY, _("Width Over All (m)")), 1,
1967 wxALIGN_LEFT);
1968 m_pOSWidth = new wxTextCtrl(itemPanelShip, wxID_ANY, "TEXT ");
1969 realSizes->Add(m_pOSWidth, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
1970
1971 realSizes->Add(
1972 new wxStaticText(itemPanelShip, wxID_ANY, _("GPS Offset from Bow (m)")),
1973 1, wxALIGN_LEFT);
1974 m_pOSGPSOffsetY = new wxTextCtrl(itemPanelShip, wxID_ANY, "TEXT ");
1975 realSizes->Add(m_pOSGPSOffsetY, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
1976
1977 realSizes->Add(new wxStaticText(itemPanelShip, wxID_ANY,
1978 _("GPS Offset from Midship (m)")),
1979 1, wxALIGN_LEFT);
1980 m_pOSGPSOffsetX = new wxTextCtrl(itemPanelShip, wxID_ANY, "TEXT ");
1981 realSizes->Add(m_pOSGPSOffsetX, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
1982
1983 realSizes->Add(
1984 new wxStaticText(itemPanelShip, wxID_ANY, _("Minimum Screen Size (mm)")),
1985 1, wxALIGN_LEFT);
1986 m_pOSMinSize = new wxTextCtrl(itemPanelShip, wxID_ANY, "TEXT ");
1987 realSizes->Add(m_pOSMinSize, 1, wxALIGN_RIGHT | wxALL, group_item_spacing);
1988
1989 // Radar rings
1990 wxFlexGridSizer* rrSelect =
1991 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
1992 rrSelect->AddGrowableCol(1);
1993 dispOptions->Add(rrSelect, 0, wxLEFT | wxRIGHT | wxEXPAND, border_size);
1994
1995 wxStaticText* rrTxt =
1996 new wxStaticText(itemPanelShip, wxID_ANY, _("Show range rings"));
1997 rrSelect->Add(rrTxt, 1, wxEXPAND | wxALL, group_item_spacing);
1998
1999 wxString rrAlt[] = {_("None"), "1", "2", "3", "4", "5",
2000 "6", "7", "8", "9", "10"};
2001 pNavAidRadarRingsNumberVisible =
2002 new wxChoice(itemPanelShip, ID_RADARRINGS, wxDefaultPosition,
2003 m_pShipIconType->GetSize(), 11, rrAlt);
2004 rrSelect->Add(pNavAidRadarRingsNumberVisible, 0, wxALIGN_RIGHT | wxALL,
2005 group_item_spacing);
2006
2007 radarGrid = new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
2008 radarGrid->AddGrowableCol(1);
2009 dispOptions->Add(radarGrid, 0, wxLEFT | wxEXPAND, 30);
2010
2011 wxStaticText* distanceText =
2012 new wxStaticText(itemPanelShip, wxID_STATIC, _("Distance between rings"));
2013 radarGrid->Add(distanceText, 1, wxEXPAND | wxALL, group_item_spacing);
2014
2015 pNavAidRadarRingsStep = new wxTextCtrl(itemPanelShip, ID_OPTEXTCTRL, "",
2016 wxDefaultPosition, wxSize(100, -1), 0);
2017 radarGrid->Add(pNavAidRadarRingsStep, 0, wxALIGN_RIGHT | wxALL,
2018 group_item_spacing);
2019
2020 wxStaticText* unitText =
2021 new wxStaticText(itemPanelShip, wxID_STATIC, _("Distance Unit"));
2022 radarGrid->Add(unitText, 1, wxEXPAND | wxALL, group_item_spacing);
2023
2024 wxString pDistUnitsStrings[] = {_("Nautical miles"), _("Kilometers"),
2025 _("Minutes (time)")};
2026 m_itemRadarRingsUnits =
2027 new wxChoice(itemPanelShip, ID_RADARDISTUNIT, wxDefaultPosition,
2028 m_pShipIconType->GetSize(), 3, pDistUnitsStrings);
2029 radarGrid->Add(m_itemRadarRingsUnits, 0, wxALIGN_RIGHT | wxALL, border_size);
2030
2031 wxStaticText* colourText =
2032 new wxStaticText(itemPanelShip, wxID_STATIC, _("Range Ring Color"));
2033 radarGrid->Add(colourText, 1, wxEXPAND | wxALL, group_item_spacing);
2034
2035 m_colourOwnshipRangeRingColour =
2036 new OCPNColourPickerCtrl(itemPanelShip, wxID_ANY, *wxRED,
2037 wxDefaultPosition, m_colourPickerDefaultSize, 0,
2038 wxDefaultValidator, "ID_COLOUROSRANGECOLOUR");
2039 radarGrid->Add(m_colourOwnshipRangeRingColour, 0, wxALIGN_RIGHT, border_size);
2040
2041 // ship to active
2042 wxFlexGridSizer* shipToActiveGrid =
2043 new wxFlexGridSizer(1, 5, group_item_spacing, group_item_spacing);
2044 shipToActiveGrid->AddGrowableCol(1);
2045 dispOptions->Add(shipToActiveGrid, 0, wxALL | wxEXPAND, border_size);
2046 pShowshipToActive = new wxCheckBox(itemPanelShip, wxID_ANY,
2047 _("Show direction to Active Waypoint"));
2048 shipToActiveGrid->Add(pShowshipToActive, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT,
2049 border_size);
2050
2051 wxStaticText* shipToActiveText1 =
2052 new wxStaticText(itemPanelShip, wxID_STATIC, _("Style"));
2053 shipToActiveGrid->Add(shipToActiveText1, 1,
2054 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, border_size);
2055
2056 wxString LineStyleChoices[] = {_("Default"), _("Solid"), _("Dot"),
2057 _("Long dash"), _("Short dash")};
2058 int LineStyleNChoices = sizeof(LineStyleChoices) / sizeof(wxString);
2059 m_shipToActiveStyle =
2060 new wxChoice(itemPanelShip, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2061 LineStyleNChoices, LineStyleChoices, 0);
2062 m_shipToActiveStyle->SetSelection(0);
2063 shipToActiveGrid->Add(m_shipToActiveStyle, 0, wxALL, 5);
2064
2065 wxStaticText* shipToActiveText2 =
2066 new wxStaticText(itemPanelShip, wxID_STATIC, _("Color"));
2067 shipToActiveGrid->Add(shipToActiveText2, 1,
2068 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, border_size);
2069
2070 wxString m_LineColorChoices[] = {
2071 _("Default color"), _("Black"), _("Dark Red"), _("Dark Green"),
2072 _("Dark Yellow"), _("Dark Blue"), _("Dark Magenta"), _("Dark Cyan"),
2073 _("Light Gray"), _("Dark Gray"), _("Red"), _("Green"),
2074 _("Yellow"), _("Blue"), _("Magenta"), _("Cyan"),
2075 _("White")};
2076 int LineColorNChoices = sizeof(m_LineColorChoices) / sizeof(wxString);
2077 m_shipToActiveColor =
2078 new wxChoice(itemPanelShip, wxID_ANY, wxDefaultPosition, wxDefaultSize,
2079 LineColorNChoices, m_LineColorChoices, 0);
2080 m_shipToActiveColor->SetSelection(0);
2081 shipToActiveGrid->Add(m_shipToActiveColor, 0, wxALL, 5);
2082
2083 // Ship's data
2084 wxStaticBox* shipdata =
2085 new wxStaticBox(itemPanelShip, wxID_ANY, _("Ship's identifier"));
2086 wxStaticBoxSizer* datasizer = new wxStaticBoxSizer(shipdata, wxVERTICAL);
2087 ownShip->Add(datasizer, 0, wxGROW | wxALL, border_size);
2088
2089 wxFlexGridSizer* ownmmsisizer =
2090 new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
2091 ownmmsisizer->AddGrowableCol(1);
2092 datasizer->Add(ownmmsisizer, 0, wxALL | wxEXPAND, border_size);
2093
2094 // Enter own ship mmsi for a AIS transponder connection.
2095 // Especially N2k devices may lack that info.
2096 wxStaticText* pStatic_ownshipmmsi =
2097 new wxStaticText(itemPanelShip, wxID_ANY,
2098 _("Own ship's MMSI. (If available) Nine digits"));
2099 ownmmsisizer->Add(pStatic_ownshipmmsi, 0);
2100
2101 // Make a rule for mmsi txt control input
2102 const wxString AllowDigits[] = {"0", "1", "2", "3", "4",
2103 "5", "6", "7", "8", "9"};
2104 wxArrayString ArrayAllowDigits(10, AllowDigits);
2105 wxTextValidator mmsiVal(wxFILTER_INCLUDE_CHAR_LIST);
2106 mmsiVal.SetIncludes(ArrayAllowDigits);
2107 m_pTxt_OwnMMSI = new wxTextCtrl(itemPanelShip, wxID_ANY, "",
2108 wxDefaultPosition, wxDefaultSize, 0, mmsiVal);
2109 ownmmsisizer->Add(m_pTxt_OwnMMSI, 0, wxALIGN_RIGHT);
2110
2111 // Tracks
2112 wxStaticBox* trackText =
2113 new wxStaticBox(itemPanelShip, wxID_ANY, _("Tracks"));
2114 wxStaticBoxSizer* trackSizer = new wxStaticBoxSizer(trackText, wxVERTICAL);
2115 wxBoxSizer* trackSizer1 = new wxBoxSizer(wxHORIZONTAL);
2116 ownShip->Add(trackSizer, 0, wxGROW | wxALL, border_size);
2117
2118 pTrackDaily = new wxCheckBox(itemPanelShip, ID_DAILYCHECKBOX,
2119 _("Automatic Daily Tracks at midnight"));
2120
2121 trackSizer1->Add(pTrackDaily, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT,
2122 border_size);
2123
2124 trackSizer1->Add(0, 0, 1, wxEXPAND, 0);
2125
2126#if wxUSE_TIMEPICKCTRL
2127 pTrackDaily->SetLabel(_("Automatic Daily Tracks at"));
2128#ifdef __WXGTK__
2129 pTrackRotateTime =
2130 new TimeCtrl(itemPanelShip, ID_TRACKROTATETIME,
2131 wxDateTime((time_t)g_track_rotate_time).ToUTC(),
2132 wxDefaultPosition, wxDefaultSize, 0);
2133#else
2134 pTrackRotateTime =
2135 new wxTimePickerCtrl(itemPanelShip, ID_TRACKROTATETIME,
2136 wxDateTime((time_t)g_track_rotate_time).ToUTC(),
2137 wxDefaultPosition, wxDefaultSize, 0);
2138#endif // __WXGTK__
2139 trackSizer1->Add(pTrackRotateTime, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT,
2140 border_size);
2141#endif // wxUSE_TIMEPICKCTRL
2142
2143 pTrackRotateComputerTime =
2144 new wxRadioButton(itemPanelShip, ID_TRACKROTATECOMPUTER, _("Computer"),
2145 wxDefaultPosition, wxDefaultSize, 0);
2146 trackSizer1->Add(pTrackRotateComputerTime, 0,
2147 wxALIGN_CENTER_VERTICAL | wxRIGHT, border_size);
2148
2149 pTrackRotateUTC =
2150 new wxRadioButton(itemPanelShip, ID_TRACKROTATEUTC, _("UTC"),
2151 wxDefaultPosition, wxDefaultSize, 0);
2152 trackSizer1->Add(pTrackRotateUTC, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT,
2153 border_size);
2154
2155 pTrackRotateLMT =
2156 new wxRadioButton(itemPanelShip, ID_TRACKROTATELMT, _("LMT"),
2157 wxDefaultPosition, wxDefaultSize, 0);
2158 trackSizer1->Add(pTrackRotateLMT, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT,
2159 border_size);
2160
2161 trackSizer->Add(trackSizer1, 1, wxEXPAND | wxALL, border_size);
2162
2163 wxFlexGridSizer* hTrackGrid =
2164 new wxFlexGridSizer(1, 3, group_item_spacing, group_item_spacing);
2165 hTrackGrid->AddGrowableCol(1);
2166 trackSizer->Add(hTrackGrid, 0, wxALL | wxEXPAND, border_size);
2167
2168 pTrackHighlite =
2169 new wxCheckBox(itemPanelShip, ID_TRACKHILITE, _("Highlight Tracks"));
2170 hTrackGrid->Add(pTrackHighlite, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,
2171 border_size);
2172 wxStaticText* trackColourText =
2173 new wxStaticText(itemPanelShip, wxID_STATIC, _("Highlight Color"));
2174 hTrackGrid->Add(trackColourText, 1, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL,
2175 border_size);
2176 m_colourTrackLineColour = new OCPNColourPickerCtrl(
2177 itemPanelShip, wxID_STATIC, *wxRED, wxDefaultPosition,
2178 m_colourPickerDefaultSize, 0, wxDefaultValidator, "ID_COLOURTRACKCOLOUR");
2179 hTrackGrid->Add(m_colourTrackLineColour, 1, wxALIGN_RIGHT, border_size);
2180
2181 wxFlexGridSizer* pTrackGrid =
2182 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2183 pTrackGrid->AddGrowableCol(1);
2184 trackSizer->Add(pTrackGrid, 0, wxALL | wxEXPAND, border_size);
2185
2186 wxStaticText* tpText =
2187 new wxStaticText(itemPanelShip, wxID_STATIC, _("Tracking Precision"));
2188 pTrackGrid->Add(tpText, 1, wxEXPAND | wxALL, group_item_spacing);
2189
2190 wxString trackAlt[] = {_("Low"), _("Medium"), _("High")};
2191 pTrackPrecision = new wxChoice(itemPanelShip, wxID_ANY, wxDefaultPosition,
2192 m_pShipIconType->GetSize(), 3, trackAlt);
2193 pTrackGrid->Add(pTrackPrecision, 0, wxALIGN_RIGHT | wxALL,
2194 group_item_spacing);
2195}
2196
2197void options::CreatePanel_Routes(size_t parent, int border_size,
2198 int group_item_spacing) {
2199 itemPanelRoutes = AddPage(parent, _("Routes/Points"));
2200
2201 Routes = new wxBoxSizer(wxVERTICAL);
2202 itemPanelRoutes->SetSizer(Routes);
2203
2204 wxString pDistUnitsStrings[] = {_("Nautical miles"), _("Kilometers")};
2205
2206 wxString rrAlt[] = {_("None"), "1", "2", "3", "4", "5",
2207 "6", "7", "8", "9", "10"};
2208
2209 // Routes
2210 wxStaticBox* routeText =
2211 new wxStaticBox(itemPanelRoutes, wxID_ANY, _("New Routes"));
2212 wxStaticBoxSizer* routeSizer = new wxStaticBoxSizer(routeText, wxVERTICAL);
2213 Routes->Add(routeSizer, 0, wxGROW | wxALL, border_size);
2214
2215 wxStaticBox* activeRouteText =
2216 new wxStaticBox(itemPanelRoutes, wxID_ANY, _("Active Route"));
2217 wxStaticBoxSizer* activeRouteSizer =
2218 new wxStaticBoxSizer(activeRouteText, wxVERTICAL);
2219
2220 m_persist_active_route_chkbox = new wxCheckBox(
2221 itemPanelRoutes, wxID_ANY,
2222 _("Persist active route, automatically activate on start up"));
2223 activeRouteSizer->Add(m_persist_active_route_chkbox, 0, wxALL, 5);
2224 Routes->Add(activeRouteSizer, 0, wxGROW | wxALL, border_size);
2225
2226 routeSizer->AddSpacer(5);
2227
2228 // Default ICON
2229 wxFlexGridSizer* routepointiconSelect =
2230 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2231 routepointiconSelect->AddGrowableCol(1);
2232 routeSizer->Add(routepointiconSelect, 0, wxLEFT | wxRIGHT | wxEXPAND,
2233 border_size);
2234
2235 wxStaticText* routepointiconTxt =
2236 new wxStaticText(itemPanelRoutes, wxID_ANY, _("Waypoint default icon"));
2237 routepointiconSelect->Add(routepointiconTxt, 1, wxEXPAND | wxALL,
2238 group_item_spacing);
2239
2240 pRoutepointDefaultIconChoice = new OCPNIconCombo(
2241 itemPanelRoutes, wxID_ANY, _("Combo!"), wxDefaultPosition, wxDefaultSize,
2242 0, NULL, wxCB_READONLY);
2243 routepointiconSelect->Add(pRoutepointDefaultIconChoice, 0,
2244 wxALIGN_RIGHT | wxALL, group_item_spacing);
2245
2246 pRoutepointDefaultIconChoice->SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
2247
2248 // Accomodate scaling of icon
2249 int min_size = GetCharHeight() * 2;
2250 min_size = wxMax(min_size, (32 * g_MarkScaleFactorExp) + 4);
2251 pRoutepointDefaultIconChoice->SetMinSize(
2252 wxSize(GetCharHeight() * 15, min_size));
2253
2254 routeSizer->AddSpacer(5);
2255
2256 wxFlexGridSizer* pRouteGrid =
2257 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2258 pRouteGrid->AddGrowableCol(1);
2259 routeSizer->Add(pRouteGrid, 0, wxALL | wxEXPAND, border_size);
2260
2261 wxStaticText* raText = new wxStaticText(
2262 itemPanelRoutes, wxID_STATIC, _("Waypoint Arrival Circle Radius (NMi)"));
2263 pRouteGrid->Add(raText, 1, wxEXPAND | wxALL, group_item_spacing);
2264
2265 m_pText_ACRadius = new wxTextCtrl(itemPanelRoutes, -1, "TEXT ");
2266 pRouteGrid->Add(m_pText_ACRadius, 0, wxALL | wxALIGN_RIGHT,
2267 group_item_spacing);
2268
2269 pAdvanceRouteWaypointOnArrivalOnly =
2270 new wxCheckBox(itemPanelRoutes, ID_DAILYCHECKBOX,
2271 _("Advance route waypoint on arrival only"));
2272 routeSizer->Add(pAdvanceRouteWaypointOnArrivalOnly, 0, wxALL, 5);
2273
2274#ifdef __WXGTK__
2275 Routes->AddSpacer(8 * group_item_spacing);
2276 wxStaticLine* pln =
2277 new wxStaticLine(itemPanelRoutes, wxID_ANY, wxDefaultPosition,
2278 wxDefaultSize, wxLI_HORIZONTAL);
2279 Routes->Add(pln, 0, wxEXPAND);
2280#endif
2281
2282 // Waypoints
2283 wxStaticBox* waypointText =
2284 new wxStaticBox(itemPanelRoutes, wxID_ANY, _("New Marks"));
2285 wxStaticBoxSizer* waypointSizer =
2286 new wxStaticBoxSizer(waypointText, wxVERTICAL);
2287 Routes->Add(waypointSizer, 0, wxTOP | wxALL | wxEXPAND, border_size);
2288
2289 waypointSizer->AddSpacer(5);
2290
2291 // Default ICON
2292 wxFlexGridSizer* waypointiconSelect =
2293 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2294 waypointiconSelect->AddGrowableCol(1);
2295 waypointSizer->Add(waypointiconSelect, 0, wxLEFT | wxRIGHT | wxEXPAND,
2296 border_size);
2297
2298 wxStaticText* waypointiconTxt =
2299 new wxStaticText(itemPanelRoutes, wxID_ANY, _("Mark default icon"));
2300 waypointiconSelect->Add(waypointiconTxt, 1, wxEXPAND | wxALL,
2301 group_item_spacing);
2302
2303 pWaypointDefaultIconChoice = new OCPNIconCombo(
2304 itemPanelRoutes, wxID_ANY, _("Combo!"), wxDefaultPosition, wxDefaultSize,
2305 0, NULL, wxCB_READONLY);
2306 waypointiconSelect->Add(pWaypointDefaultIconChoice, 0, wxALIGN_RIGHT | wxALL,
2307 group_item_spacing);
2308
2309 pWaypointDefaultIconChoice->SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
2310
2311 // Accomodate scaling of icon
2312 int rmin_size = GetCharHeight() * 2;
2313 min_size = wxMax(rmin_size, (32 * g_MarkScaleFactorExp) + 4);
2314 pWaypointDefaultIconChoice->SetMinSize(
2315 wxSize(GetCharHeight() * 15, rmin_size));
2316
2317 waypointSizer->AddSpacer(5);
2318 // ScaMin
2319 wxFlexGridSizer* ScaMinSizer =
2320 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2321 ScaMinSizer->AddGrowableCol(1);
2322 waypointSizer->Add(ScaMinSizer, 0, wxLEFT | wxRIGHT | wxEXPAND, border_size);
2323 pScaMinChckB =
2324 new wxCheckBox(itemPanelRoutes, wxID_ANY,
2325 _("Show marks only at a chartscale greater than 1 :"));
2326 ScaMinSizer->Add(pScaMinChckB, 0);
2327 m_pText_ScaMin = new wxTextCtrl(itemPanelRoutes, -1, "TEXTTEXTTEXT");
2328 ScaMinSizer->Add(m_pText_ScaMin, 0, wxALL | wxALIGN_RIGHT,
2329 group_item_spacing);
2330
2331 wxFlexGridSizer* ScaMaxSizer =
2332 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2333 ScaMaxSizer->AddGrowableCol(1);
2334 waypointSizer->Add(ScaMaxSizer, 0, wxLEFT | wxRIGHT | wxEXPAND, border_size);
2335 wxStaticText* scaMaxLabel =
2336 new wxStaticText(itemPanelRoutes, wxID_ANY,
2337 _("Show marks only at a chartscale smaller than 1 :"));
2338 ScaMaxSizer->Add(scaMaxLabel, 0);
2339 m_pText_ScaMax = new wxTextCtrl(itemPanelRoutes, -1, "TEXTTEXTTEXT");
2340 ScaMaxSizer->Add(m_pText_ScaMax, 0, wxALL | wxALIGN_RIGHT,
2341 group_item_spacing);
2342
2343 // Overrule the Scamin settings
2344 pScaMinOverruleChckB =
2345 new wxCheckBox(itemPanelRoutes, wxID_ANY,
2346 _("Override the settings for chartscale based visibility "
2347 "and show always"));
2348 waypointSizer->Add(pScaMinOverruleChckB, 0, wxALL, 5);
2349
2350 waypointSizer->AddSpacer(5);
2351 // Range Rings
2352 wxFlexGridSizer* waypointrrSelect =
2353 new wxFlexGridSizer(1, 2, group_item_spacing, group_item_spacing);
2354 waypointrrSelect->AddGrowableCol(1);
2355 waypointSizer->Add(waypointrrSelect, 0, wxLEFT | wxRIGHT | wxEXPAND,
2356 border_size);
2357
2358 wxStaticText* waypointrrTxt =
2359 new wxStaticText(itemPanelRoutes, wxID_ANY, _("Mark range rings"));
2360 waypointrrSelect->Add(waypointrrTxt, 1, wxEXPAND | wxALL, group_item_spacing);
2361
2362 pWaypointRangeRingsNumber =
2363 new wxChoice(itemPanelRoutes, ID_OPWAYPOINTRANGERINGS, wxDefaultPosition,
2364 m_pShipIconType->GetSize(), 11, rrAlt);
2365 waypointrrSelect->Add(pWaypointRangeRingsNumber, 0, wxALIGN_RIGHT | wxALL,
2366 group_item_spacing);
2367
2368 waypointradarGrid =
2369 new wxFlexGridSizer(0, 2, group_item_spacing, group_item_spacing);
2370 waypointradarGrid->AddGrowableCol(1);
2371 waypointSizer->Add(waypointradarGrid, 0, wxLEFT | wxEXPAND, 30);
2372
2373 wxStaticText* waypointdistanceText = new wxStaticText(
2374 itemPanelRoutes, wxID_STATIC, _("Distance between rings"));
2375 waypointradarGrid->Add(waypointdistanceText, 1, wxEXPAND | wxALL,
2376 group_item_spacing);
2377
2378 pWaypointRangeRingsStep =
2379 new wxTextCtrl(itemPanelRoutes, ID_OPTEXTCTRL, "", wxDefaultPosition,
2380 wxSize(100, -1), 0);
2381 waypointradarGrid->Add(pWaypointRangeRingsStep, 0, wxALIGN_RIGHT | wxALL,
2382 group_item_spacing);
2383
2384 wxStaticText* waypointunitText =
2385 new wxStaticText(itemPanelRoutes, wxID_STATIC, _("Distance Unit"));
2386 waypointradarGrid->Add(waypointunitText, 1, wxEXPAND | wxALL,
2387 group_item_spacing);
2388
2389 m_itemWaypointRangeRingsUnits =
2390 new wxChoice(itemPanelRoutes, ID_RADARDISTUNIT, wxDefaultPosition,
2391 m_pShipIconType->GetSize(), 2, pDistUnitsStrings);
2392 waypointradarGrid->Add(m_itemWaypointRangeRingsUnits, 0,
2393 wxALIGN_RIGHT | wxALL, border_size);
2394
2395 wxStaticText* waypointrangeringsColour = new wxStaticText(
2396 itemPanelRoutes, wxID_STATIC, _("Waypoint Range Ring Colors"));
2397 waypointradarGrid->Add(waypointrangeringsColour, 1, wxEXPAND | wxALL, 1);
2398
2399 m_colourWaypointRangeRingsColour = new OCPNColourPickerCtrl(
2400 itemPanelRoutes, wxID_ANY, *wxRED, wxDefaultPosition,
2401 m_colourPickerDefaultSize, 0, wxDefaultValidator,
2402 "ID_COLOURWAYPOINTRANGERINGSCOLOUR");
2403 waypointradarGrid->Add(m_colourWaypointRangeRingsColour, 0,
2404 wxALIGN_RIGHT | wxALL, 1);
2405
2406 // Control Options
2407
2408#ifdef __WXGTK__
2409 Routes->AddSpacer(8 * group_item_spacing);
2410 wxStaticLine* pln1 =
2411 new wxStaticLine(itemPanelRoutes, wxID_ANY, wxDefaultPosition,
2412 wxDefaultSize, wxLI_HORIZONTAL);
2413 Routes->Add(pln1, 0, wxEXPAND);
2414#endif
2415
2416 wxStaticBox* waypointControl =
2417 new wxStaticBox(itemPanelRoutes, wxID_ANY, _("Control Options"));
2418 wxStaticBoxSizer* ControlSizer =
2419 new wxStaticBoxSizer(waypointControl, wxVERTICAL);
2420 Routes->Add(ControlSizer, 0, wxTOP | wxALL | wxEXPAND, border_size);
2421
2422 ControlSizer->AddSpacer(5);
2423
2424 pWayPointPreventDragging = new wxCheckBox(
2425 itemPanelRoutes, ID_DRAGGINGCHECKBOX,
2426 _("Lock marks and waypoints (Unless object property dialog visible)"));
2427 pWayPointPreventDragging->SetValue(FALSE);
2428 ControlSizer->Add(pWayPointPreventDragging, verticleInputFlags);
2429
2430 pConfirmObjectDeletion =
2431 new wxCheckBox(itemPanelRoutes, ID_DELETECHECKBOX,
2432 _("Confirm deletion of tracks and routes"));
2433 pConfirmObjectDeletion->SetValue(FALSE);
2434 ControlSizer->Add(pConfirmObjectDeletion, verticleInputFlags);
2435 ControlSizer->AddSpacer(5);
2436
2437 // Fill the default waypoint icon selector combo box
2438 pWaypointDefaultIconChoice->Clear();
2439 // Iterate on the Icon Descriptions, filling in the combo control
2440 bool fillCombo = true;
2441
2442 if (fillCombo) {
2443 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
2444 wxString* ps = pWayPointMan->GetIconDescription(i);
2445 wxBitmap bmp = pWayPointMan->GetIconBitmapForList(i, 2 * GetCharHeight());
2446
2447 pWaypointDefaultIconChoice->Append(*ps, bmp);
2448 }
2449 }
2450
2451 // find the correct item in the combo box
2452 int iconToSelect = -1;
2453 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
2454 if (*pWayPointMan->GetIconKey(i) == g_default_wp_icon) {
2455 iconToSelect = i;
2456 pWaypointDefaultIconChoice->Select(iconToSelect);
2457 break;
2458 }
2459 }
2460
2461 // Fill the default Routepoint icon selector combo box
2462 pRoutepointDefaultIconChoice->Clear();
2463 // Iterate on the Icon Descriptions, filling in the combo control
2464 fillCombo = true;
2465
2466 if (fillCombo) {
2467 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
2468 wxString* ps = pWayPointMan->GetIconDescription(i);
2469 wxBitmap bmp = pWayPointMan->GetIconBitmapForList(i, 2 * GetCharHeight());
2470
2471 pRoutepointDefaultIconChoice->Append(*ps, bmp);
2472 }
2473 }
2474
2475 // find the correct item in the combo box
2476 iconToSelect = -1;
2477 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
2478 if (*pWayPointMan->GetIconKey(i) == g_default_routepoint_icon) {
2479 iconToSelect = i;
2480 pRoutepointDefaultIconChoice->Select(iconToSelect);
2481 break;
2482 }
2483 }
2484
2485 // DimeControl(itemPanelRoutes);
2486}
2487
2488void options::CreatePanel_ChartsLoad(size_t parent, int border_size,
2489 int group_item_spacing) {
2490 chartPanelWin = AddPage(m_pageCharts, _("Chart Files"));
2491
2492 chartPanel = new wxBoxSizer(wxVERTICAL);
2493 chartPanelWin->SetSizer(chartPanel);
2494
2495 loadedBox = new wxStaticBox(chartPanelWin, wxID_ANY, _("Directories"));
2496 activeSizer = new wxStaticBoxSizer(loadedBox, wxHORIZONTAL);
2497 chartPanel->Add(activeSizer, 1, wxALL | wxEXPAND, border_size);
2498
2499 m_scrollWinChartList = new wxScrolledWindow(
2500 chartPanelWin, wxID_ANY, wxDefaultPosition,
2501 wxDLG_UNIT(this, wxSize(-1, -1)), wxBORDER_RAISED | wxVSCROLL);
2502
2503 activeSizer->Add(m_scrollWinChartList, 1, wxALL | wxEXPAND, 5);
2504
2505#ifndef __ANDROID__
2506 m_scrollRate = 5;
2507#else
2508 m_scrollRate = 1;
2509#endif
2510 m_scrollWinChartList->SetScrollRate(m_scrollRate, m_scrollRate);
2511
2512 boxSizerCharts = new wxBoxSizer(wxVERTICAL);
2513 m_scrollWinChartList->SetSizer(boxSizerCharts);
2514
2515 cmdButtonSizer = new wxBoxSizer(wxVERTICAL);
2516 activeSizer->Add(cmdButtonSizer, 0, wxALL, border_size);
2517
2518 wxString b1 = _("Add Directory...");
2519 wxString b2 = _("Remove Selected");
2520 wxString b3 = _("Compress Selected");
2521
2522 if (m_bcompact) {
2523 b1 = _("Add..");
2524 b2 = _("Remove");
2525 b3 = _("Compress");
2526 }
2527
2528 wxButton* addBtn = new wxButton(chartPanelWin, ID_BUTTONADD, b1);
2529 cmdButtonSizer->Add(addBtn, 1, wxALL | wxEXPAND, group_item_spacing);
2530
2531 cmdButtonSizer->AddSpacer(GetCharHeight());
2532
2533 m_removeBtn = new wxButton(chartPanelWin, ID_BUTTONDELETE, b2);
2534 cmdButtonSizer->Add(m_removeBtn, 1, wxALL | wxEXPAND, group_item_spacing);
2535 m_removeBtn->Disable();
2536
2537 cmdButtonSizer->AddSpacer(GetCharHeight());
2538
2539#ifdef OCPN_USE_LZMA
2540 m_compressBtn = new wxButton(chartPanelWin, ID_BUTTONCOMPRESS, b3);
2541 cmdButtonSizer->Add(m_compressBtn, 1, wxALL | wxEXPAND, group_item_spacing);
2542 m_compressBtn->Disable();
2543#else
2544 m_compressBtn = NULL;
2545#endif
2546
2547#ifdef __ANDROID__
2548 if (g_Android_SDK_Version >= 30) {
2549 m_migrateBtn =
2550 new wxButton(chartPanelWin, ID_BUTTONMIGRATE, _("Migrate Charts.."));
2551 cmdButtonSizer->Add(m_migrateBtn, 1, wxALL | wxEXPAND, group_item_spacing);
2552 }
2553#endif
2554
2555 cmdButtonSizer->AddSpacer(GetCharHeight());
2556
2557 wxStaticBox* itemStaticBoxUpdateStatic =
2558 new wxStaticBox(chartPanelWin, wxID_ANY, _("Update Control"));
2559 wxStaticBoxSizer* itemStaticBoxSizerUpdate =
2560 new wxStaticBoxSizer(itemStaticBoxUpdateStatic, wxVERTICAL);
2561 chartPanel->Add(itemStaticBoxSizerUpdate, 0, wxGROW | wxALL, 5);
2562
2563 wxFlexGridSizer* itemFlexGridSizerUpdate = new wxFlexGridSizer(1);
2564 itemFlexGridSizerUpdate->SetFlexibleDirection(wxHORIZONTAL);
2565
2566 pScanCheckBox = new wxCheckBox(chartPanelWin, ID_SCANCHECKBOX,
2567 _("Scan Charts and Update Database"));
2568 itemFlexGridSizerUpdate->Add(pScanCheckBox, 1, wxALL, 5);
2569
2570 pUpdateCheckBox = new wxCheckBox(chartPanelWin, ID_UPDCHECKBOX,
2571 _("Force Full Database Rebuild"));
2572 // itemFlexGridSizerUpdate->Add(pUpdateCheckBox, 1, wxALL, 5);
2573 pUpdateCheckBox->Hide();
2574
2575 pRebuildChartDatabase = new wxButton(chartPanelWin, ID_REBUILDBUTTON,
2576 _("Rebuild Chart Database"));
2577 itemFlexGridSizerUpdate->Add(pRebuildChartDatabase, 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 o_sound::Sound* 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 = o_sound::Factory();
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<o_sound::Sound>(o_sound::Factory());
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<o_sound::SystemCmdSound*>(o_sound::Factory())) {
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 top_frame::Get()->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(wxTheApp->GetTopWindow()) < 1)
6111 ConnTab = _("Connect");
6112
6113 m_pageConnections = CreatePanel(ConnTab);
6114 CreatePanel_NMEA(m_pageConnections, border_size, group_item_spacing);
6115
6116 // SetDefaultConnectionParams();
6117
6118 m_pageShips = CreatePanel(_("Ships"));
6119 CreatePanel_Ownship(m_pageShips, border_size, group_item_spacing);
6120 CreatePanel_AIS(m_pageShips, border_size, group_item_spacing);
6121 CreatePanel_MMSI(m_pageShips, border_size, group_item_spacing);
6122
6123 CreatePanel_Routes(m_pageShips, border_size, group_item_spacing);
6124
6125 wxString UITab = _("User Interface");
6126 if (g_Platform->GetDisplayDIPMult(wxTheApp->GetTopWindow()) < 1)
6127 UITab = _("User");
6128
6129 m_pageUI = CreatePanel(UITab);
6130 CreatePanel_UI(m_pageUI, border_size, group_item_spacing);
6131 CreatePanel_Sounds(m_pageUI, border_size, group_item_spacing);
6132
6133 m_pagePlugins = CreatePanel(_("Plugins"));
6134 itemPanelPlugins = AddPage(m_pagePlugins, _("Plugins"));
6135
6136 itemBoxSizerPanelPlugins = new wxBoxSizer(wxVERTICAL);
6137 itemPanelPlugins->SetSizer(itemBoxSizerPanelPlugins);
6138
6139 // PlugIns can add panels, too
6140 if (g_pi_manager) g_pi_manager->NotifySetupOptions();
6141
6142 SetColorScheme(static_cast<ColorScheme>(0));
6143
6144 // Set the maximum size of the entire settings dialog
6145 // leaving a slightly larger border for larger displays.
6146 int marginx = 10;
6147 int marginy = 40;
6148 if (width > 800) {
6149 marginx = 100;
6150 marginy = 100;
6151 }
6152
6153 SetSizeHints(-1, -1, width - marginx, height - marginy);
6154
6155#ifndef __WXGTK__
6156 // The s57 chart panel is the one which controls the minimum width required
6157 // to avoid horizontal scroll bars
6158 // vectorPanel->SetSizeHints(ps57Ctl);
6159#endif
6160}
6161
6162void options::SetInitialPage(int page_sel, int sub_page) {
6163 if (page_sel < (int)m_pListbook->GetPageCount())
6164 m_pListbook->SetSelection(page_sel);
6165 else
6166 m_pListbook->SetSelection(0);
6167
6168 if (sub_page >= 0) {
6169 for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
6170 wxNotebookPage* pg = m_pListbook->GetPage(i);
6171 wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
6172 if (nb) {
6173 if (i == (size_t)page_sel) {
6174 if (sub_page < (int)nb->GetPageCount())
6175 nb->SetSelection(sub_page);
6176 else
6177 nb->SetSelection(0);
6178 } else
6179 nb->ChangeSelection(0);
6180 }
6181 }
6182 }
6183}
6184
6185void options::SetColorScheme(ColorScheme cs) {
6186 DimeControl(this);
6187
6188#ifdef OCPN_OPTIONS_USE_LISTBOOK
6189 wxListView* lv = m_pListbook->GetListView();
6190 lv->SetBackgroundColour(GetBackgroundColour());
6191
6192 if (m_cs != cs) {
6193 delete m_topImgList;
6194 CreateListbookIcons();
6195 m_pListbook->SetImageList(m_topImgList);
6196
6197 m_cs = cs;
6198 }
6199
6200#endif
6201
6202 // Some panels need specific color change method
6203 comm_dialog->SetColorScheme(cs);
6204}
6205
6206void options::OnAISRolloverClick(wxCommandEvent& event) {
6207 m_pCheck_Rollover_Class->Enable(event.IsChecked());
6208 m_pCheck_Rollover_COG->Enable(event.IsChecked());
6209 m_pCheck_Rollover_CPA->Enable(event.IsChecked());
6210 pStatic_CallSign->Enable(event.IsChecked());
6211}
6212
6213void options::OnCanvasConfigSelectClick(int ID, bool selected) {
6214 switch (ID) {
6215 case ID_SCREENCONFIG1:
6216 if (m_sconfigSelect_twovertical)
6217 m_sconfigSelect_twovertical->SetSelected(false);
6218 m_screenConfig = 0;
6219 break;
6220
6221 case ID_SCREENCONFIG2:
6222 if (m_sconfigSelect_single) m_sconfigSelect_single->SetSelected(false);
6223 m_screenConfig = 1;
6224 break;
6225 }
6226}
6227
6228void options::SetInitialSettings() {
6229 wxString s;
6230
6231 m_returnChanges = 0; // reset the flags
6232 m_bfontChanged = false;
6233 m_font_element_array.Clear();
6234
6235 b_oldhaveWMM = b_haveWMM;
6236 auto loader = PluginLoader::GetInstance();
6237 b_haveWMM = loader && loader->IsPlugInAvailable("WMM");
6238
6239 // Canvas configuration
6240 switch (g_canvasConfig) {
6241 case 0:
6242 default:
6243 if (m_sconfigSelect_single) m_sconfigSelect_single->SetSelected(true);
6244 if (m_sconfigSelect_twovertical)
6245 m_sconfigSelect_twovertical->SetSelected(false);
6246 break;
6247 case 1:
6248 if (m_sconfigSelect_single) m_sconfigSelect_single->SetSelected(false);
6249 if (m_sconfigSelect_twovertical)
6250 m_sconfigSelect_twovertical->SetSelected(true);
6251 break;
6252 }
6253 m_screenConfig = g_canvasConfig;
6254
6255 // Initial Charts Load
6256
6257 ActiveChartArray.Clear();
6258 for (size_t i = 0; i < m_CurrentDirList.GetCount(); i++) {
6259 ActiveChartArray.Add(m_CurrentDirList[i]);
6260 }
6261
6262 // ChartGroups
6263 if (m_pWorkDirList) {
6264 UpdateWorkArrayFromDisplayPanel();
6265 groupsPanel->SetDBDirs(*m_pWorkDirList);
6266
6267 // Make a deep copy of the current global Group Array
6268 groupsPanel->EmptyChartGroupArray(m_pGroupArray);
6269 delete m_pGroupArray;
6270 m_pGroupArray = groupsPanel->CloneChartGroupArray(g_pGroupArray);
6271 groupsPanel->SetGroupArray(m_pGroupArray);
6272 groupsPanel->SetInitialSettings();
6273 }
6274
6275 if (m_pConfig) {
6276 pShowStatusBar->SetValue(g_bShowStatusBar);
6277#ifndef __WXOSX__
6278 pShowMenuBar->SetValue(g_bShowMenuBar);
6279#endif
6280 pShowCompassWin->SetValue(g_bShowCompassWin);
6281 }
6282
6283 s.Printf("%d", g_COGAvgSec);
6284 pCOGUPUpdateSecs->SetValue(s);
6285
6286 if (pCDOOutlines) pCDOOutlines->SetValue(g_bShowOutlines);
6287 if (pCDOQuilting) pCDOQuilting->SetValue(g_bQuiltEnable);
6288 // if(pFullScreenQuilt) pFullScreenQuilt->SetValue(!g_bFullScreenQuilt);
6289 if (pSDepthUnits) pSDepthUnits->SetValue(g_bShowDepthUnits);
6290 if (pSkewComp) pSkewComp->SetValue(g_bskew_comp);
6291 pMobile->SetValue(g_btouch);
6292 pResponsive->SetValue(g_bresponsive);
6293 pRollover->SetValue(g_bRollover);
6294 m_pCheck_Rollover_Class->Enable(g_bRollover);
6295 m_pCheck_Rollover_COG->Enable(g_bRollover);
6296 m_pCheck_Rollover_CPA->Enable(g_bRollover);
6297 pStatic_CallSign->Enable(g_bRollover);
6298
6299 pZoomButtons->SetValue(g_bShowMuiZoomButtons);
6300
6301 // pOverzoomEmphasis->SetValue(!g_fog_overzoom);
6302 // pOZScaleVector->SetValue(!g_oz_vector_scale);
6303 pInlandEcdis->SetValue(g_bInlandEcdis);
6304#ifdef ocpnUSE_GL
6305 pOpenGL->SetValue(g_bopengl);
6306 if (auto* w = wxWindow::FindWindowById(ID_OPENGLOPTIONS))
6307 w->Enable(pOpenGL->IsChecked());
6308#endif
6309 if (pSmoothPanZoom) pSmoothPanZoom->SetValue(g_bsmoothpanzoom);
6310 pCBTrueShow->SetValue(g_bShowTrue);
6311 pCBMagShow->SetValue(g_bShowMag);
6312
6313 int oldLength = itemStaticTextUserVar->GetLabel().Length();
6314
6315 // disable input for variation if WMM is available
6316 if (b_haveWMM) {
6317 itemStaticTextUserVar->SetLabel(
6318 _("WMM Plugin calculated magnetic variation"));
6319 wxString s;
6320 s.Printf("%4.1f", gVar);
6321 pMagVar->SetValue(s);
6322 } else {
6323 itemStaticTextUserVar->SetLabel(_("User set magnetic variation"));
6324 wxString s;
6325 s.Printf("%4.1f", g_UserVar);
6326 pMagVar->SetValue(s);
6327 }
6328
6329 int newLength = itemStaticTextUserVar->GetLabel().Length();
6330
6331 // size hack to adjust change in static text size
6332 if ((newLength != oldLength) || (b_oldhaveWMM != b_haveWMM)) {
6333 wxSize sz = GetSize();
6334 SetSize(sz.x + 1, sz.y);
6335 SetSize(sz);
6336 }
6337
6338 itemStaticTextUserVar2->Enable(!b_haveWMM);
6339 pMagVar->Enable(!b_haveWMM);
6340
6341 if (pSDisplayGrid) pSDisplayGrid->SetValue(g_bDisplayGrid);
6342
6343 // LIVE ETA OPTION
6344
6345 // Checkbox
6346 if (pSLiveETA) pSLiveETA->SetValue(g_bShowLiveETA);
6347
6348 // Defaut boat speed text input field
6349 // Speed always in knots, and converted to user speed unit
6350 wxString stringDefaultBoatSpeed;
6351 if (!g_defaultBoatSpeed || !g_defaultBoatSpeedUserUnit) {
6352 g_defaultBoatSpeed = 6.0;
6353 g_defaultBoatSpeedUserUnit = toUsrSpeed(g_defaultBoatSpeed, -1);
6354 }
6355 stringDefaultBoatSpeed.Printf("%d", (int)g_defaultBoatSpeedUserUnit);
6356 if (pSDefaultBoatSpeed) pSDefaultBoatSpeed->SetValue(stringDefaultBoatSpeed);
6357
6358 // END LIVE ETA OPTION
6359
6360 if (pCBCourseUp) pCBCourseUp->SetValue(g_bCourseUp);
6361 if (pCBNorthUp) pCBNorthUp->SetValue(!g_bCourseUp);
6362 if (pCBLookAhead) pCBLookAhead->SetValue(g_bLookAhead);
6363
6364 if (fabs(wxRound(g_ownship_predictor_minutes) - g_ownship_predictor_minutes) >
6365 1e-4)
6366 s.Printf("%6.2f", g_ownship_predictor_minutes);
6367 else
6368 s.Printf("%4.0f", g_ownship_predictor_minutes);
6369 m_pText_OSCOG_Predictor->SetValue(s);
6370
6371 if (fabs(wxRound(g_ownship_HDTpredictor_miles) -
6372 g_ownship_HDTpredictor_miles) > 1e-4)
6373 s.Printf("%6.2f", g_ownship_HDTpredictor_miles);
6374 else
6375 s.Printf("%4.0f", g_ownship_HDTpredictor_miles);
6376 m_pText_OSHDT_Predictor->SetValue(s);
6377
6378 if (g_OwnShipmmsi > 0) {
6379 wxString s = wxString::Format("%i", g_OwnShipmmsi);
6380 m_pTxt_OwnMMSI->SetValue(s);
6381 } else
6382 m_pTxt_OwnMMSI->SetValue("");
6383
6384 m_pShipIconType->SetSelection(g_OwnShipIconType);
6385 wxCommandEvent eDummy;
6386 OnShipTypeSelect(eDummy);
6387 m_pOSLength->SetValue(wxString::Format("%.1f", g_n_ownship_length_meters));
6388 m_pOSWidth->SetValue(wxString::Format("%.1f", g_n_ownship_beam_meters));
6389 m_pOSGPSOffsetX->SetValue(wxString::Format("%.1f", g_n_gps_antenna_offset_x));
6390 m_pOSGPSOffsetY->SetValue(wxString::Format("%.1f", g_n_gps_antenna_offset_y));
6391 m_pOSMinSize->SetValue(wxString::Format("%d", g_n_ownship_min_mm));
6392 m_pText_ACRadius->SetValue(
6393 wxString::Format("%.3f", g_n_arrival_circle_radius));
6394
6395 wxString buf;
6396 if (g_iNavAidRadarRingsNumberVisible > 10)
6397 g_iNavAidRadarRingsNumberVisible = 10;
6398 pNavAidRadarRingsNumberVisible->SetSelection(
6399 g_iNavAidRadarRingsNumberVisible);
6400 buf.Printf("%.3f", g_fNavAidRadarRingsStep);
6401 pNavAidRadarRingsStep->SetValue(buf);
6402 m_itemRadarRingsUnits->SetSelection(g_pNavAidRadarRingsStepUnits);
6403 m_colourOwnshipRangeRingColour->SetColour(g_colourOwnshipRangeRingsColour);
6404
6405 pScaMinChckB->SetValue(g_bUseWptScaMin);
6406 m_pText_ScaMin->SetValue(wxString::Format("%i", g_iWpt_ScaMin));
6407 m_pText_ScaMax->SetValue(wxString::Format("%i", g_iWpt_ScaMax));
6408 pScaMinOverruleChckB->SetValue(g_bOverruleScaMin);
6409
6410 OnRadarringSelect(eDummy);
6411
6412 if (g_iWaypointRangeRingsNumber > 10) g_iWaypointRangeRingsNumber = 10;
6413 pWaypointRangeRingsNumber->SetSelection(g_iWaypointRangeRingsNumber);
6414 buf.Printf("%.3f", g_fWaypointRangeRingsStep);
6415 pWaypointRangeRingsStep->SetValue(buf);
6416 m_itemWaypointRangeRingsUnits->SetSelection(g_iWaypointRangeRingsStepUnits);
6417 m_colourWaypointRangeRingsColour->SetColour(g_colourWaypointRangeRingsColour);
6418 OnWaypointRangeRingSelect(eDummy);
6419 pShowshipToActive->SetValue(g_bShowShipToActive);
6420 m_shipToActiveStyle->SetSelection(g_shipToActiveStyle);
6421 m_shipToActiveColor->SetSelection(g_shipToActiveColor);
6422
6423 pWayPointPreventDragging->SetValue(g_bWayPointPreventDragging);
6424 pConfirmObjectDeletion->SetValue(g_bConfirmObjectDelete);
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 (top_frame::Get()->GetWxGlCanvas()) {
6925 g_GLOptions.m_bUseAcceleratedPanning =
6926 g_bGLexpert ? dlg.GetAcceleratedPanning()
6927 : top_frame::Get()
6928 ->GetAbstractPrimaryCanvas()
6929 ->CanAccelerateGlPanning();
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 (top_frame::Get()->GetWxGlCanvas()) {
6953 ::wxBeginBusyCursor();
6954 top_frame::Get()->GetAbstractPrimaryCanvas()->SetupGlCompression();
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 m_callbacks.prepare_close(this, m_returnChanges);
7124 if (!(m_returnChanges & FONT_CHANGED_SAFE))
7125 top_frame::Get()->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 top_frame::Get()->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_iWpt_ScaMax = wxAtoi(m_pText_ScaMax->GetValue());
7199 g_bOverruleScaMin = pScaMinOverruleChckB->GetValue();
7200
7201 // Any Font changes?
7202 if (m_bfontChanged) {
7203#ifdef ocpnUSE_GL
7204 if (top_frame::Get()->GetWxGlCanvas()) {
7205 top_frame::Get()->GetAbstractPrimaryCanvas()->ResetGridFont();
7206 }
7207#endif
7208 if (top_frame::Get()->GetAbstractPrimaryCanvas()) {
7209 top_frame::Get()->GetAbstractPrimaryCanvas()->ResetGridFont();
7210 }
7211
7212 m_returnChanges |= FONT_CHANGED;
7213
7214 // If the font element changed was not "Dialog", then we don't need a full
7215 // reload
7216 if (m_font_element_array.Index("Dialog") == wxNOT_FOUND)
7217 m_returnChanges |= FONT_CHANGED_SAFE;
7218 }
7219
7220 // Handle Chart Tab
7221 UpdateWorkArrayFromDisplayPanel();
7222
7223 groupsPanel->SetDBDirs(*m_pWorkDirList); // update the Groups tab
7224 groupsPanel->m_treespopulated = FALSE;
7225
7226 int k_force = FORCE_UPDATE;
7227 if (pUpdateCheckBox) {
7228 if (!pUpdateCheckBox->GetValue()) k_force = 0;
7229 pUpdateCheckBox->Enable();
7230 pUpdateCheckBox->SetValue(FALSE);
7231 } else {
7232 k_force = 0;
7233 }
7234
7235 m_returnChanges |= k_force;
7236
7237 int k_scan = SCAN_UPDATE;
7238 if (pScanCheckBox) {
7239 if (!pScanCheckBox->GetValue()) k_scan = 0;
7240 pScanCheckBox->Enable();
7241 pScanCheckBox->SetValue(FALSE);
7242 } else {
7243 k_scan = 0;
7244 }
7245
7246 m_returnChanges |= k_scan;
7247
7248 pConfig->UpdateChartDirs(*m_pWorkDirList);
7249
7250 // Chart Groups
7251
7252 if (groupsPanel->modified) {
7253 groupsPanel->EmptyChartGroupArray(g_pGroupArray);
7254 delete g_pGroupArray;
7255 g_pGroupArray = groupsPanel->CloneChartGroupArray(m_pGroupArray);
7256 m_returnChanges |= GROUPS_CHANGED;
7257 }
7258
7259 // Handle Settings Tab
7260 if (m_pConfig) {
7261 g_bShowStatusBar = pShowStatusBar->GetValue();
7262
7263#ifndef __WXOSX__
7264 bool bmenu_shown = g_bShowMenuBar;
7265 if (pShowMenuBar->GetValue() != bmenu_shown)
7266 m_returnChanges |= MENU_CHANGED;
7267 g_bShowMenuBar = pShowMenuBar->GetValue();
7268#endif
7269
7270 g_bShowCompassWin = pShowCompassWin->GetValue();
7271 }
7272
7273 g_bShowChartBar = pShowChartBar->GetValue();
7274
7275 wxString screenmm = pScreenMM->GetValue();
7276 wxStringTokenizer tkz(screenmm, ",");
7278 while (tkz.HasMoreTokens()) {
7279 wxString token = tkz.GetNextToken();
7280 long mm = -1;
7281 if (token.ToLong(&mm) && mm > 0) {
7282 g_config_display_size_mm.push_back(mm);
7283 } else {
7284 g_config_display_size_mm.push_back(0);
7285 }
7286 }
7287 g_config_display_size_manual = pRBSizeManual->GetValue();
7288
7289 // Connections page.
7290 comm_dialog->ApplySettings();
7291
7292 if (pCDOOutlines) g_bShowOutlines = pCDOOutlines->GetValue();
7293 if (pSDisplayGrid) g_bDisplayGrid = pSDisplayGrid->GetValue();
7294
7295 if (pCDOQuilting) {
7296 bool temp_bquilting = pCDOQuilting->GetValue();
7297 // if (!g_bQuiltEnable && temp_bquilting)
7298 // cc1->ReloadVP(); /* compose the quilt */
7299 g_bQuiltEnable = temp_bquilting;
7300 }
7301 // g_bFullScreenQuilt = !pFullScreenQuilt->GetValue();
7302
7303 if (pSDepthUnits) g_bShowDepthUnits = pSDepthUnits->GetValue();
7304 g_bskew_comp = pSkewComp->GetValue();
7305 g_btouch = pMobile->GetValue();
7306 g_bresponsive = pResponsive->GetValue();
7307 g_bRollover = pRollover->GetValue();
7308 g_bShowMuiZoomButtons = pZoomButtons->GetValue();
7309
7310 g_bAutoHideToolbar = pToolbarAutoHideCB->GetValue();
7311
7312 long hide_val = 10;
7313 pToolbarHideSecs->GetValue().ToLong(&hide_val);
7314 g_nAutoHideToolbar = wxMin(static_cast<int>(hide_val), 100);
7315 g_nAutoHideToolbar = wxMax(g_nAutoHideToolbar, 2);
7316
7317 // g_fog_overzoom = !pOverzoomEmphasis->GetValue();
7318 // g_oz_vector_scale = !pOZScaleVector->GetValue();
7319
7320 g_bsmoothpanzoom = pSmoothPanZoom->GetValue();
7321#ifdef __ANDROID__
7322 g_bsmoothpanzoom = false;
7323#endif
7324 if (pSmoothPanZoom) g_bsmoothpanzoom = pSmoothPanZoom->GetValue();
7325#ifdef __ANDROID__
7326 g_bsmoothpanzoom = false;
7327#endif
7328
7329 long update_val = 1;
7330 pCOGUPUpdateSecs->GetValue().ToLong(&update_val);
7331 g_COGAvgSec = wxMin(static_cast<int>(update_val), kMaxCogAverageSeconds);
7332
7333 // TODO if (g_bCourseUp != pCBCourseUp->GetValue()) gFrame->ToggleCourseUp();
7334
7335 if (pCBLookAhead) g_bLookAhead = pCBLookAhead->GetValue();
7336
7337 g_bShowTrue = pCBTrueShow->GetValue();
7338 g_bShowMag = pCBMagShow->GetValue();
7339
7340 auto loader = PluginLoader::GetInstance();
7341 b_haveWMM = loader && loader->IsPlugInAvailable("WMM");
7342 if (!b_haveWMM && !b_oldhaveWMM) {
7343 pMagVar->GetValue().ToDouble(&g_UserVar);
7344 gVar = g_UserVar;
7345 }
7346
7347 g_OwnShipmmsi = wxAtoi(m_pTxt_OwnMMSI->GetValue());
7348 m_pText_OSCOG_Predictor->GetValue().ToDouble(&g_ownship_predictor_minutes);
7349 m_pText_OSHDT_Predictor->GetValue().ToDouble(&g_ownship_HDTpredictor_miles);
7350
7351 double temp_dbl;
7352 g_iNavAidRadarRingsNumberVisible =
7353 pNavAidRadarRingsNumberVisible->GetSelection();
7354 g_bNavAidRadarRingsShown = g_iNavAidRadarRingsNumberVisible > 0;
7355 if (pNavAidRadarRingsStep->GetValue().ToDouble(&temp_dbl))
7356 g_fNavAidRadarRingsStep = temp_dbl;
7357 g_pNavAidRadarRingsStepUnits = m_itemRadarRingsUnits->GetSelection();
7358 g_iWaypointRangeRingsNumber = pWaypointRangeRingsNumber->GetSelection();
7359 if (pWaypointRangeRingsStep->GetValue().ToDouble(&temp_dbl))
7360 g_fWaypointRangeRingsStep = temp_dbl;
7361 g_iWaypointRangeRingsStepUnits =
7362 m_itemWaypointRangeRingsUnits->GetSelection();
7364 m_colourWaypointRangeRingsColour->GetColour();
7366 wxColour(g_colourWaypointRangeRingsColour.Red(),
7369 g_bWayPointPreventDragging = pWayPointPreventDragging->GetValue();
7370
7371 g_bConfirmObjectDelete = pConfirmObjectDeletion->GetValue();
7372
7373 if (pPreserveScale) g_bPreserveScaleOnX = pPreserveScale->GetValue();
7374
7375 if (pCmdSoundString) {
7376 g_CmdSoundString = pCmdSoundString->GetValue();
7377 if (wxIsEmpty(g_CmdSoundString)) {
7378 g_CmdSoundString = wxString(OCPN_SOUND_CMD);
7379 pCmdSoundString->SetValue(g_CmdSoundString);
7380 }
7381 }
7382
7383 g_bPlayShipsBells = pPlayShipsBells->GetValue();
7384 if (pSoundDeviceIndex)
7385 g_iSoundDeviceIndex = pSoundDeviceIndex->GetSelection();
7386 // g_bTransparentToolbar = pTransparentToolbar->GetValue();
7387 g_iSDMMFormat = pSDMMFormat->GetSelection();
7388 // Map dropdown selection index explicitly to DISTANCE_* enum.
7389 {
7390 int sel = pDistanceFormat->GetSelection();
7391 g_iDistanceFormat = GetDistanceFormatEnum(sel);
7392 }
7393 g_iSpeedFormat = pSpeedFormat->GetSelection();
7394 g_iWindSpeedFormat = pWindSpeedFormat->GetSelection();
7395 g_iTempFormat = pTempFormat->GetSelection();
7396 if (pHeightUnitSelect) g_iHeightFormat = pHeightUnitSelect->GetSelection();
7397
7398 // LIVE ETA OPTION
7399 if (pSLiveETA) g_bShowLiveETA = pSLiveETA->GetValue();
7400 if (pSDefaultBoatSpeed)
7401 pSDefaultBoatSpeed->GetValue().ToDouble(&g_defaultBoatSpeedUserUnit);
7402 g_defaultBoatSpeed = fromUsrSpeed(g_defaultBoatSpeedUserUnit);
7403 m_Text_def_boat_speed->SetLabel(_("Default Boat Speed ") + "(" +
7404 getUsrSpeedUnit() + ")");
7405
7406 g_bAdvanceRouteWaypointOnArrivalOnly =
7407 pAdvanceRouteWaypointOnArrivalOnly->GetValue();
7408
7409 g_colourTrackLineColour = m_colourTrackLineColour->GetColour();
7410 g_colourTrackLineColour =
7411 wxColour(g_colourTrackLineColour.Red(), g_colourTrackLineColour.Green(),
7412 g_colourTrackLineColour.Blue());
7413 g_nTrackPrecision = pTrackPrecision->GetSelection();
7414
7415 g_bTrackDaily = pTrackDaily->GetValue();
7416
7417 g_track_rotate_time = 0;
7418#if wxUSE_TIMEPICKCTRL
7419 int h, m, s;
7420 if (pTrackRotateTime && pTrackRotateTime->GetTime(&h, &m, &s))
7421 g_track_rotate_time = h * 3600 + m * 60 + s;
7422#endif
7423
7424 if (pTrackRotateUTC->GetValue())
7425 g_track_rotate_time_type = TIME_TYPE_UTC;
7426 else if (pTrackRotateLMT->GetValue())
7427 g_track_rotate_time_type = TIME_TYPE_LMT;
7428 else
7429 g_track_rotate_time_type = TIME_TYPE_COMPUTER;
7430
7431 g_bHighliteTracks = pTrackHighlite->GetValue();
7432
7433 if (pTimezoneUTC->GetValue())
7434 g_datetime_format = "UTC";
7435 else if (pTimezoneLocalTime->GetValue())
7436 g_datetime_format = "Local Time";
7437
7438 if (pEnableZoomToCursor)
7439 g_bEnableZoomToCursor = pEnableZoomToCursor->GetValue();
7440
7441 if (pEnableTenHertz) g_btenhertz = pEnableTenHertz->GetValue();
7442
7443#ifdef __ANDROID__
7444 g_bEnableZoomToCursor = false;
7445#endif
7446
7447 g_colourOwnshipRangeRingsColour = m_colourOwnshipRangeRingColour->GetColour();
7448 g_colourOwnshipRangeRingsColour =
7449 wxColour(g_colourOwnshipRangeRingsColour.Red(),
7450 g_colourOwnshipRangeRingsColour.Green(),
7451 g_colourOwnshipRangeRingsColour.Blue());
7452
7453 // Sounds
7454 g_bAIS_GCPA_Alert_Audio = m_soundPanelAIS->GetCheckBox()->GetValue();
7455 g_bAIS_SART_Alert_Audio = m_soundPanelSART->GetCheckBox()->GetValue();
7456 g_bAIS_DSC_Alert_Audio = m_soundPanelDSC->GetCheckBox()->GetValue();
7457 g_bAnchor_Alert_Audio = m_soundPanelAnchor->GetCheckBox()->GetValue();
7458
7459 // AIS Parameters
7460 // CPA Box
7461 g_bCPAMax = m_pCheck_CPA_Max->GetValue();
7462 m_pText_CPA_Max->GetValue().ToDouble(&g_CPAMax_NM);
7463 g_bCPAWarn = m_pCheck_CPA_Warn->GetValue();
7464 m_pText_CPA_Warn->GetValue().ToDouble(&g_CPAWarn_NM);
7465 g_bTCPA_Max = m_pCheck_CPA_WarnT->GetValue();
7466 m_pText_CPA_WarnT->GetValue().ToDouble(&g_TCPA_Max);
7467
7468 // Lost Targets
7469 g_bMarkLost = m_pCheck_Mark_Lost->GetValue();
7470 m_pText_Mark_Lost->GetValue().ToDouble(&g_MarkLost_Mins);
7471 g_bRemoveLost = m_pCheck_Remove_Lost->GetValue();
7472 m_pText_Remove_Lost->GetValue().ToDouble(&g_RemoveLost_Mins);
7473
7474 // Display
7475 g_bShowCOG = m_pCheck_Show_COG->GetValue();
7476 // If synchronized with own ship predictor
7477 g_bSyncCogPredictors = m_pCheck_Sync_OCOG_ACOG->GetValue();
7478 if (g_bSyncCogPredictors) {
7479 m_pText_COG_Predictor->SetValue(m_pText_OSCOG_Predictor->GetValue());
7480 }
7481 m_pText_COG_Predictor->GetValue().ToDouble(&g_ShowCOG_Mins);
7482
7483 g_bAISShowTracks = m_pCheck_Show_Tracks->GetValue();
7484 m_pText_Track_Length->GetValue().ToDouble(&g_AISShowTracks_Mins);
7485
7486 // Update all the current targets
7487 if (g_pAIS) {
7488 for (const auto& it : g_pAIS->GetTargetList()) {
7489 auto pAISTarget = it.second;
7490 if (NULL != pAISTarget) {
7491 pAISTarget->b_show_track = g_bAISShowTracks;
7492 // Check for exceptions in MMSI properties
7493 for (unsigned int i = 0; i < g_MMSI_Props_Array.GetCount(); i++) {
7494 if (pAISTarget->MMSI == g_MMSI_Props_Array[i]->MMSI) {
7496 if (TRACKTYPE_NEVER == props->TrackType) {
7497 pAISTarget->b_show_track = false;
7498 break;
7499 } else if (TRACKTYPE_ALWAYS == props->TrackType) {
7500 pAISTarget->b_show_track = true;
7501 break;
7502 } else
7503 break;
7504 }
7505 }
7506 // Check for any persistently tracked target, force b_show_track ON
7507 std::map<int, Track*>::iterator it;
7508 it = g_pAIS->m_persistent_tracks.find(pAISTarget->MMSI);
7509 if (it != g_pAIS->m_persistent_tracks.end())
7510 pAISTarget->b_show_track = true;
7511 pAISTarget->b_show_track_old = g_bAISShowTracks;
7512 }
7513 }
7514 }
7515
7516 g_bHideMoored = m_pCheck_Hide_Moored->GetValue();
7517 m_pText_Moored_Speed->GetValue().ToDouble(&g_ShowMoored_Kts);
7518
7519 g_bDrawAISRealtime = m_pCheck_Draw_Realtime_Prediction->GetValue();
7520 m_pText_RealtPred_Speed->GetValue().ToDouble(&g_AIS_RealtPred_Kts);
7521
7522 g_bAllowShowScaled = m_pCheck_Scale_Priority->GetValue();
7523 long l;
7524 m_pText_Scale_Priority->GetValue().ToLong(&l);
7525 g_ShowScaled_Num = (int)l;
7526
7527 g_bShowAreaNotices = m_pCheck_Show_Area_Notices->GetValue();
7528 g_bDrawAISSize = m_pCheck_Draw_Target_Size->GetValue();
7529 g_bShowAISName = m_pCheck_Show_Target_Name->GetValue();
7530 long ais_name_scale = 5000;
7531 m_pText_Show_Target_Name_Scale->GetValue().ToLong(&ais_name_scale);
7532 g_Show_Target_Name_Scale = (int)wxMax(5000, ais_name_scale);
7533 g_bWplUsePosition = m_pCheck_use_Wpl->GetValue();
7534 g_WplAction = m_pWplAction->GetSelection();
7535
7536 // Alert
7537 g_bAIS_CPA_Alert = m_pCheck_AlertDialog->GetValue();
7538 g_bAIS_CPA_Alert_Audio = m_pCheck_AlertAudio->GetValue();
7539 g_bAIS_CPA_Alert_Suppress_Moored = m_pCheck_Alert_Moored->GetValue();
7540
7541 g_bAIS_ACK_Timeout = m_pCheck_Ack_Timout->GetValue();
7542 m_pText_ACK_Timeout->GetValue().ToDouble(&g_AckTimeout_Mins);
7543
7544 // Rollover
7545 g_bAISRolloverShowClass = m_pCheck_Rollover_Class->GetValue();
7546 g_bAISRolloverShowCOG = m_pCheck_Rollover_COG->GetValue();
7547 g_bAISRolloverShowCPA = m_pCheck_Rollover_CPA->GetValue();
7548
7549 g_chart_zoom_modifier_raster = m_pSlider_Zoom_Raster->GetValue();
7550 g_chart_zoom_modifier_vector = m_pSlider_Zoom_Vector->GetValue();
7551 g_cm93_zoom_factor = m_pSlider_CM93_Zoom->GetValue();
7552 g_GUIScaleFactor = m_pSlider_GUI_Factor->GetValue();
7553
7554 bool bchange_scale = false;
7555 if (g_ChartScaleFactor != m_pSlider_Chart_Factor->GetValue())
7556 bchange_scale = true;
7557 g_ChartScaleFactor = m_pSlider_Chart_Factor->GetValue();
7558
7560 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
7561 g_MarkScaleFactorExp = g_Platform->GetMarkScaleFactorExp(g_ChartScaleFactor);
7562 g_ShipScaleFactor = m_pSlider_Ship_Factor->GetValue();
7563 g_ShipScaleFactorExp = g_Platform->GetChartScaleFactorExp(g_ShipScaleFactor);
7564 g_ENCSoundingScaleFactor = m_pSlider_Text_Factor->GetValue();
7565 g_ENCTextScaleFactor = m_pSlider_ENCText_Factor->GetValue();
7566
7567 g_mouse_zoom_sensitivity_ui = m_pMouse_Zoom_Slider->GetValue();
7568 g_mouse_zoom_sensitivity =
7569 MouseZoom::ui_to_config(g_mouse_zoom_sensitivity_ui);
7570
7571 // Only reload the icons if user has actually visted the UI page
7572 if (m_bVisitLang) {
7573 if (pWayPointMan) WayPointmanGui(*pWayPointMan).ReloadRoutepointIcons();
7574 }
7575
7576 // FIXME Move these two
7577 // g_NMEAAPBPrecision = m_choicePrecision->GetCurrentSelection();
7578 // g_TalkerIdText = m_TalkerIdText->GetValue().MakeUpper();
7579
7580#ifdef ocpnUSE_GL
7581 if (g_bopengl != pOpenGL->GetValue()) m_returnChanges |= GL_CHANGED;
7582 g_bopengl = pOpenGL->GetValue();
7583#endif
7584
7585 g_bChartBarEx = pChartBarEX->GetValue();
7586
7587 // Handle Vector Charts Tab
7588 int depthUnit = pDepthUnitSelect->GetSelection();
7589 g_nDepthUnitDisplay = depthUnit;
7590
7591 // Process the UserStandard display list, noting if any changes were made
7592 bool bUserStdChange = false;
7593
7594 int nOBJL = ps57CtlListBox->GetCount();
7595
7596 for (int iPtr = 0; iPtr < nOBJL; iPtr++) {
7597 int itemIndex = -1;
7598 for (size_t i = 0; i < marinersStdXref.size(); i++) {
7599 if (marinersStdXref[i] == iPtr) {
7600 itemIndex = i;
7601 break;
7602 }
7603 }
7604 assert(itemIndex >= 0);
7605 OBJLElement* pOLE = (OBJLElement*)(ps52plib->pOBJLArray->Item(itemIndex));
7606 if (pOLE->nViz != (int)(ps57CtlListBox->IsChecked(iPtr)))
7607 bUserStdChange = true;
7608 pOLE->nViz = ps57CtlListBox->IsChecked(iPtr);
7609 }
7610
7611 if (ps52plib) {
7612 // Take a snapshot of the S52 config right now,
7613 // for later comparison
7614 ps52plib->GenerateStateHash();
7615 long stateHash = ps52plib->GetStateHash();
7616
7617 if (m_returnChanges & GL_CHANGED) {
7618 // Do this now to handle the screen refresh that is automatically
7619 // generated on Windows at closure of the options dialog...
7620 ps52plib->FlushSymbolCaches(ChartCtxFactory());
7621 // some CNSY depends on renderer (e.g. CARC)
7622 ps52plib->ClearCNSYLUPArray();
7623 ps52plib->GenerateStateHash();
7624 }
7625
7626 if (pDispCat) {
7627 enum _DisCat nset = OTHER;
7628 switch (pDispCat->GetSelection()) {
7629 case 0:
7630 nset = DISPLAYBASE;
7631 break;
7632 case 1:
7633 nset = STANDARD;
7634 break;
7635 case 2:
7636 nset = OTHER;
7637 break;
7638 case 3:
7639 nset = MARINERS_STANDARD;
7640 break;
7641 }
7642 ps52plib->SetDisplayCategory(nset);
7643 }
7644
7645 if (pCheck_SOUNDG) ps52plib->m_bShowSoundg = pCheck_SOUNDG->GetValue();
7646 if (pCheck_ATONTEXT)
7647 ps52plib->m_bShowAtonText = pCheck_ATONTEXT->GetValue();
7648 if (pCheck_LDISTEXT)
7649 ps52plib->m_bShowLdisText = pCheck_LDISTEXT->GetValue();
7650 if (pCheck_XLSECTTEXT)
7651 ps52plib->m_bExtendLightSectors = pCheck_XLSECTTEXT->GetValue();
7652
7653 ps52plib->m_bShowMeta = pCheck_META->GetValue();
7654 ps52plib->m_bDeClutterText = pCheck_DECLTEXT->GetValue();
7655 ps52plib->m_bShowNationalTexts = pCheck_NATIONALTEXT->GetValue();
7656 ps52plib->m_bShowS57ImportantTextOnly = pCheck_SHOWIMPTEXT->GetValue();
7657 ps52plib->m_bUseSCAMIN = pCheck_SCAMIN->GetValue();
7658 ps52plib->m_bUseSUPER_SCAMIN = pCheck_SuperSCAMIN->GetValue();
7659
7660 ps52plib->m_nSymbolStyle =
7661 pPointStyle->GetSelection() == 0 ? PAPER_CHART : SIMPLIFIED;
7662
7663 ps52plib->m_nBoundaryStyle = pBoundStyle->GetSelection() == 0
7664 ? PLAIN_BOUNDARIES
7665 : SYMBOLIZED_BOUNDARIES;
7666 ps52plib->m_nSoundingFactor = m_pSlider_Text_Factor->GetValue();
7667 ps52plib->m_nTextFactor = m_pSlider_ENCText_Factor->GetValue();
7668
7669 S52_setMarinerParam(S52_MAR_TWO_SHADES,
7670 (p24Color->GetSelection() == 0) ? 1.0 : 0.0);
7671
7672 // Depths
7673 double dval;
7674 float conv = 1;
7675
7676 if (depthUnit == 0) // feet
7677 conv = 0.3048f; // international definiton of 1 foot is 0.3048 metres
7678 else if (depthUnit == 2) // fathoms
7679 conv = 0.3048f * 6; // 1 fathom is 6 feet
7680
7681 if (m_SafetyCtl->GetValue().ToDouble(&dval)) {
7682 S52_setMarinerParam(S52_MAR_SAFETY_DEPTH,
7683 dval * conv); // controls sounding display
7684 S52_setMarinerParam(S52_MAR_SAFETY_CONTOUR,
7685 dval * conv); // controls colour
7686 }
7687
7688 if (m_ShallowCtl->GetValue().ToDouble(&dval))
7689 S52_setMarinerParam(S52_MAR_SHALLOW_CONTOUR, dval * conv);
7690
7691 if (m_DeepCtl->GetValue().ToDouble(&dval))
7692 S52_setMarinerParam(S52_MAR_DEEP_CONTOUR, dval * conv);
7693
7694 ps52plib->UpdateMarinerParams();
7695 ps52plib->m_nDepthUnitDisplay = depthUnit;
7696 // Keep s52plib height display in sync with height preference
7697 ps52plib->m_nHeightUnitDisplay = g_iHeightFormat;
7698
7699 ps52plib->GenerateStateHash();
7700
7701 // Detect a change to S52 library config
7702 if ((stateHash != ps52plib->GetStateHash()) || bUserStdChange)
7703 m_returnChanges |= S52_CHANGED;
7704
7705 if (bchange_scale) m_returnChanges |= S52_CHANGED;
7706 }
7707
7708// User Interface Panel
7709#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
7710 if (m_bVisitLang) {
7711 wxString new_canon = "en_US";
7712 wxString lang_sel = m_itemLangListBox->GetStringSelection();
7713
7714 int nLang = sizeof(lang_list) / sizeof(int);
7715 for (int it = 0; it < nLang; it++) {
7716 const wxLanguageInfo* pli = wxLocale::GetLanguageInfo(lang_list[it]);
7717 if (pli) {
7718 wxString lang_canonical = pli->CanonicalName;
7719 wxString test_string = GetOCPNKnownLanguage(lang_canonical);
7720 if (lang_sel == test_string) {
7721 new_canon = lang_canonical;
7722 break;
7723 }
7724 }
7725 }
7726
7727 wxString locale_old = g_locale;
7728 g_locale = new_canon;
7729
7730 if (g_locale != locale_old) m_returnChanges |= LOCALE_CHANGED;
7731
7732 wxString oldStyle = g_StyleManager->GetCurrentStyle()->name;
7733 // g_StyleManager->SetStyleNextInvocation(
7734 // m_itemStyleListBox->GetStringSelection());
7735 if (g_StyleManager->GetStyleNextInvocation() != oldStyle) {
7736 m_returnChanges |= STYLE_CHANGED;
7737 }
7738 wxSizeEvent nullEvent;
7739 top_frame::Get()->OnSize(nullEvent);
7740 }
7741#endif
7742 if (g_bInlandEcdis != pInlandEcdis->GetValue()) { // InlandEcdis changed
7743 g_bInlandEcdis = pInlandEcdis->GetValue();
7744 SwitchInlandEcdisMode(g_bInlandEcdis);
7745 m_returnChanges |= TOOLBAR_CHANGED;
7746 }
7747 // PlugIn Manager Panel
7748
7749 // Pick up any changes to selections
7750 if (PluginLoader::GetInstance()->UpdatePlugIns())
7751 m_returnChanges |= TOOLBAR_CHANGED;
7752
7753 // And keep config in sync
7754 // if (m_pPlugInCtrl) m_pPlugInCtrl->UpdatePluginsOrder(); FIXME(leamas)
7755 g_pi_manager->UpdateConfig();
7756
7757 // PlugIns may have added panels
7758 if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxOK);
7759
7760 m_returnChanges |= GENERIC_CHANGED | k_vectorcharts | k_charts |
7761 m_groups_changed | k_plugins;
7762
7763 // Pick up all the entries in the Tide/current DataSelected control
7764 // and update the global static array if changed
7765 // Get signature of existing array
7766 wxString string_acc;
7767 for (wxString entry : TideCurrentDataSet) {
7768 string_acc += entry;
7769 }
7770 // Get signature for options control
7771 wxString string_acc_control;
7772 for (int i = 0; i < tcDataSelected->GetItemCount(); i++) {
7773 wxString setName = tcDataSelected->GetItemText(i);
7774 string_acc_control += setName;
7775 }
7776 // Any change?
7777 if (!string_acc.IsSameAs(string_acc_control)) {
7778 TideCurrentDataSet.clear();
7779 int nEntry = tcDataSelected->GetItemCount();
7780 for (int i = 0; i < nEntry; i++) {
7781 wxString setName = tcDataSelected->GetItemText(i);
7782 TideCurrentDataSet.push_back(setName.ToStdString());
7783 }
7784 m_returnChanges |= TIDES_CHANGED;
7785 }
7786
7787 if (g_canvasConfig != m_screenConfig) m_returnChanges |= CONFIG_CHANGED;
7788 g_canvasConfig = m_screenConfig;
7789
7790 UpdateWorkArrayFromDisplayPanel();
7791
7792 // Start a chartdbs update directly, if required
7793 if ((m_returnChanges & VISIT_CHARTS) &&
7794 ((m_returnChanges & CHANGE_CHARTS) || (m_returnChanges & SCAN_UPDATE))) {
7795 DoDBSUpdate((m_returnChanges & FORCE_UPDATE) == FORCE_UPDATE);
7796 } else {
7797 bool b_groupchange = ChartData->ScrubGroupArray();
7798 ChartData->ApplyGroupArray(g_pGroupArray);
7799 if (b_groupchange ||
7800 ((m_returnChanges & GROUPS_CHANGED) == GROUPS_CHANGED)) {
7801 pConfig->DestroyConfigGroups();
7802 pConfig->CreateConfigGroups(g_pGroupArray);
7803 }
7804 if ((m_returnChanges & GROUPS_CHANGED) == GROUPS_CHANGED)
7805 ChartData->ApplyGroupArray(g_pGroupArray);
7806 }
7807
7808 m_callbacks.process_dialog(m_returnChanges, m_pWorkDirList);
7809
7810 // We can clear a few flag bits on "Apply", so they won't be recognised at
7811 // the "Close" click. Their actions have already been accomplished once...
7812 m_returnChanges &= ~(CHANGE_CHARTS | FORCE_UPDATE | SCAN_UPDATE);
7813 k_charts = 0;
7814
7815 top_frame::Get()->RefreshAllCanvas();
7816
7817 // Some layout changes requiring a new options instance?
7818 if (m_bneedNew) m_returnChanges |= NEED_NEW_OPTIONS;
7819
7820 if (m_bVisitPlugins) m_returnChanges |= FORCE_RELOAD;
7821
7822 // Record notice of any changes to last applied template
7823 UpdateTemplateTitleText();
7824
7825 if (::wxIsBusy()) // FIXME: Not sure why this is needed here
7826 ::wxEndBusyCursor();
7827}
7828
7829void options::OnXidOkClick(wxCommandEvent& event) {
7830 // When closing the form with Ctrl-Enter sometimes we get double events, the
7831 // second is empty??
7832 if (event.GetEventObject() == NULL) return;
7833
7834 ApplyChanges(event);
7835
7836 // Complete processing
7837 m_callbacks.prepare_close(this, m_returnChanges);
7838
7839 // If we had a config change, then do it now
7840 if ((m_returnChanges & CONFIG_CHANGED) || (m_returnChanges & GL_CHANGED))
7841 top_frame::Get()->ScheduleReconfigAndSettingsReload(false, false);
7842
7843 // Special case for "Dialog" font edit
7844 if ((m_returnChanges & FONT_CHANGED) &&
7845 !(m_returnChanges & FONT_CHANGED_SAFE))
7846 top_frame::Get()->ScheduleDeleteSettingsDialog();
7847
7848 // And for locale change
7849 if (m_returnChanges & LOCALE_CHANGED)
7850 top_frame::Get()->ScheduleDeleteSettingsDialog();
7851
7852 // Also for FORCE_RELOAD
7853 if (m_returnChanges & FORCE_RELOAD) top_frame::Get()->ScheduleReloadCharts();
7854
7855 Finish();
7856 Hide();
7857}
7858
7859void options::Finish() {
7860 // Required to avoid intermittent crash on wxGTK
7861 m_pListbook->ChangeSelection(0);
7862 for (size_t i = 0; i < m_pListbook->GetPageCount(); i++) {
7863 wxNotebookPage* pg = m_pListbook->GetPage(i);
7864 wxNotebook* nb = dynamic_cast<wxNotebook*>(pg);
7865 if (nb) nb->ChangeSelection(0);
7866 }
7867
7868 lastWindowPos = GetPosition();
7869 lastWindowSize = GetSize();
7870
7871 pConfig->SetPath("/Settings");
7872 pConfig->Write("OptionsSizeX", lastWindowSize.x);
7873 pConfig->Write("OptionsSizeY", lastWindowSize.y);
7874}
7875
7876ArrayOfCDI options::GetSelectedChartDirs() {
7877 ArrayOfCDI rv;
7878 for (size_t i = 0; i < panelVector.size(); i++) {
7879 if (panelVector[i]->IsSelected()) {
7880 rv.Add(panelVector[i]->GetCDI());
7881 }
7882 }
7883
7884 return rv;
7885}
7886
7887ArrayOfCDI options::GetUnSelectedChartDirs() {
7888 ArrayOfCDI rv;
7889 for (size_t i = 0; i < panelVector.size(); i++) {
7890 if (!panelVector[i]->IsSelected()) {
7891 rv.Add(panelVector[i]->GetCDI());
7892 }
7893 }
7894
7895 return rv;
7896}
7897
7898void options::SetDirActionButtons() {
7899 ArrayOfCDI selArray = GetSelectedChartDirs();
7900 if (selArray.GetCount())
7901 m_removeBtn->Enable();
7902 else
7903 m_removeBtn->Disable();
7904}
7905
7906void options::OnButtondeleteClick(wxCommandEvent& event) {
7907 ArrayOfCDI unselArray = GetUnSelectedChartDirs();
7908 ActiveChartArray.Clear();
7909 for (size_t i = 0; i < unselArray.GetCount(); i++) {
7910 ActiveChartArray.Add(unselArray[i]);
7911 }
7912
7913 UpdateChartDirList();
7914
7915 UpdateWorkArrayFromDisplayPanel();
7916
7917#if 0
7918 if (m_pWorkDirList) {
7919 pActiveChartsList->DeleteAllItems();
7920 for (size_t id = 0; id < m_pWorkDirList->GetCount(); id++) {
7921 wxString dirname = m_pWorkDirList->Item(id).fullpath;
7922 wxListItem li;
7923 li.SetId(id);
7924 li.SetAlign(wxLIST_FORMAT_LEFT);
7925 li.SetText(dirname);
7926 li.SetColumn(0);
7927 long idx = pActiveChartsList->InsertItem(li);
7928 }
7929 }
7930#endif
7931
7932 k_charts |= CHANGE_CHARTS;
7933
7934 pScanCheckBox->Disable();
7935
7936 event.Skip();
7937}
7938
7939void options::DoDBSUpdate(bool force_full) {
7940 wxString longmsg = _("OpenCPN Chart Update");
7941 longmsg +=
7942 ".................................................................."
7943 "........";
7944
7945 m_pCBDSprog = new wxGenericProgressDialog();
7946
7947 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
7948 m_pCBDSprog->SetFont(*qFont);
7949
7950 //
7951 m_pCBDSprog->Create(_("OpenCPN Chart Update"), longmsg, 100, nullptr,
7952 wxPD_SMOOTH);
7953
7954 DimeControl(m_pCBDSprog);
7955 m_pCBDSprog->Show();
7956
7957 ChartData->PurgeCache();
7958
7959 // Disable texture compression cacheing
7960 m_bTextureCacheingSave = g_GLOptions.m_bTextureCompressionCaching;
7961 g_GLOptions.m_bTextureCompressionCaching = false;
7962
7963 ChartData->UpdateChartDatabaseInplace(*m_pWorkDirList, force_full,
7964 m_pCBDSprog);
7965}
7966
7967void options::OnButtonRebuildChartDb(wxCommandEvent& event) {
7968 DoDBSUpdate(true); // Force full update
7969}
7970
7971void options::OnButtonParseENC(wxCommandEvent& event) {
7972 top_frame::Get()->GetAbstractPrimaryCanvas()->EnablePaint(false);
7973
7974 extern void ParseAllENC(wxWindow * parent);
7975
7976 ParseAllENC(g_pOptions);
7977
7978 ViewPort vp;
7979 top_frame::Get()->ChartsRefresh();
7980
7981 top_frame::Get()->GetAbstractPrimaryCanvas()->EnablePaint(true);
7982}
7983
7984#ifdef OCPN_USE_LZMA
7985#include <lzma.h>
7986
7987static bool compress(lzma_stream* strm, FILE* infile, FILE* outfile) {
7988 // This will be LZMA_RUN until the end of the input file is reached.
7989 // This tells lzma_code() when there will be no more input.
7990 lzma_action action = LZMA_RUN;
7991
7992 // Buffers to temporarily hold uncompressed input
7993 // and compressed output.
7994 uint8_t inbuf[BUFSIZ];
7995 uint8_t outbuf[BUFSIZ];
7996
7997 // Initialize the input and output pointers. Initializing next_in
7998 // and avail_in isn't really necessary when we are going to encode
7999 // just one file since LZMA_STREAM_INIT takes care of initializing
8000 // those already. But it doesn't hurt much and it will be needed
8001 // if encoding more than one file like we will in 02_decompress.c.
8002 //
8003 // While we don't care about strm->total_in or strm->total_out in this
8004 // example, it is worth noting that initializing the encoder will
8005 // always reset total_in and total_out to zero. But the encoder
8006 // initialization doesn't touch next_in, avail_in, next_out, or
8007 // avail_out.
8008 strm->next_in = NULL;
8009 strm->avail_in = 0;
8010 strm->next_out = outbuf;
8011 strm->avail_out = sizeof(outbuf);
8012
8013 // Loop until the file has been successfully compressed or until
8014 // an error occurs.
8015 while (true) {
8016 // Fill the input buffer if it is empty.
8017 if (strm->avail_in == 0 && !feof(infile)) {
8018 strm->next_in = inbuf;
8019 strm->avail_in = fread(inbuf, 1, sizeof(inbuf), infile);
8020
8021 if (ferror(infile)) {
8022 fprintf(stderr, "Read error: %s\n", strerror(errno));
8023 return false;
8024 }
8025
8026 // Once the end of the input file has been reached,
8027 // we need to tell lzma_code() that no more input
8028 // will be coming and that it should finish the
8029 // encoding.
8030 if (feof(infile)) action = LZMA_FINISH;
8031 }
8032
8033 // Tell liblzma do the actual encoding.
8034 //
8035 // This reads up to strm->avail_in bytes of input starting
8036 // from strm->next_in. avail_in will be decremented and
8037 // next_in incremented by an equal amount to match the
8038 // number of input bytes consumed.
8039 //
8040 // Up to strm->avail_out bytes of compressed output will be
8041 // written starting from strm->next_out. avail_out and next_out
8042 // will be incremented by an equal amount to match the number
8043 // of output bytes written.
8044 //
8045 // The encoder has to do internal buffering, which means that
8046 // it may take quite a bit of input before the same data is
8047 // available in compressed form in the output buffer.
8048 lzma_ret ret = lzma_code(strm, action);
8049
8050 // If the output buffer is full or if the compression finished
8051 // successfully, write the data from the output bufffer to
8052 // the output file.
8053 if (strm->avail_out == 0 || ret == LZMA_STREAM_END) {
8054 // When lzma_code() has returned LZMA_STREAM_END,
8055 // the output buffer is likely to be only partially
8056 // full. Calculate how much new data there is to
8057 // be written to the output file.
8058 size_t write_size = sizeof(outbuf) - strm->avail_out;
8059
8060 if (fwrite(outbuf, 1, write_size, outfile) != write_size) {
8061 fprintf(stderr, "Write error: %s\n", strerror(errno));
8062 return false;
8063 }
8064
8065 // Reset next_out and avail_out.
8066 strm->next_out = outbuf;
8067 strm->avail_out = sizeof(outbuf);
8068 }
8069
8070 // Normally the return value of lzma_code() will be LZMA_OK
8071 // until everything has been encoded.
8072 if (ret != LZMA_OK) {
8073 // Once everything has been encoded successfully, the
8074 // return value of lzma_code() will be LZMA_STREAM_END.
8075 //
8076 // It is important to check for LZMA_STREAM_END. Do not
8077 // assume that getting ret != LZMA_OK would mean that
8078 // everything has gone well.
8079 if (ret == LZMA_STREAM_END) return true;
8080
8081 // It's not LZMA_OK nor LZMA_STREAM_END,
8082 // so it must be an error code. See lzma/base.h
8083 // (src/liblzma/api/lzma/base.h in the source package
8084 // or e.g. /usr/include/lzma/base.h depending on the
8085 // install prefix) for the list and documentation of
8086 // possible values. Most values listen in lzma_ret
8087 // enumeration aren't possible in this example.
8088 const char* msg;
8089 switch (ret) {
8090 case LZMA_MEM_ERROR:
8091 msg = "Memory allocation failed";
8092 break;
8093
8094 case LZMA_DATA_ERROR:
8095 // This error is returned if the compressed
8096 // or uncompressed size get near 8 EiB
8097 // (2^63 bytes) because that's where the .xz
8098 // file format size limits currently are.
8099 // That is, the possibility of this error
8100 // is mostly theoretical unless you are doing
8101 // something very unusual.
8102 //
8103 // Note that strm->total_in and strm->total_out
8104 // have nothing to do with this error. Changing
8105 // those variables won't increase or decrease
8106 // the chance of getting this error.
8107 msg = "File size limits exceeded";
8108 break;
8109
8110 default:
8111 // This is most likely LZMA_PROG_ERROR, but
8112 // if this program is buggy (or liblzma has
8113 // a bug), it may be e.g. LZMA_BUF_ERROR or
8114 // LZMA_OPTIONS_ERROR too.
8115 //
8116 // It is inconvenient to have a separate
8117 // error message for errors that should be
8118 // impossible to occur, but knowing the error
8119 // code is important for debugging. That's why
8120 // it is good to print the error code at least
8121 // when there is no good error message to show.
8122 msg = "Unknown error, possibly a bug";
8123 break;
8124 }
8125
8126 wxLogMessage("LZMA Encoder error: %s (error code %u)\n", msg, ret);
8127 return false;
8128 }
8129 }
8130}
8131#endif
8132
8133static bool CompressChart(wxString in, wxString out) {
8134#ifdef OCPN_USE_LZMA
8135 FILE* infile = fopen(in.mb_str(), "rb");
8136 if (!infile) return false;
8137
8138 FILE* outfile = fopen(out.mb_str(), "wb");
8139 if (!outfile) {
8140 fclose(infile);
8141 return false;
8142 }
8143
8144 lzma_stream strm = LZMA_STREAM_INIT;
8145 bool success = false;
8146 if (lzma_easy_encoder(&strm, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64) ==
8147 LZMA_OK)
8148 success = compress(&strm, infile, outfile);
8149
8150 lzma_end(&strm);
8151 fclose(infile);
8152 fclose(outfile);
8153
8154 return success;
8155#endif
8156 return false;
8157}
8158
8159void options::OnButtonmigrateClick(wxCommandEvent& event) {
8160#ifdef __ANDROID__
8161
8162 // Run the chart migration assistant
8163 g_migrateDialog =
8164 // skip Folder scan
8165 new MigrateAssistantDialog(wxTheApp->GetTopWindow(), true);
8166 g_migrateDialog->SetSize(top_frame::Get()->GetSize());
8167 g_migrateDialog->Centre();
8168 g_migrateDialog->Raise();
8169 g_migrateDialog->ShowModal();
8170#endif
8171}
8172
8173void options::OnButtonEcdisHelp(wxCommandEvent& event) {
8174 wxString testFile = "/doc/iECDIS/index.html";
8175
8176 if (!::wxFileExists(testFile)) {
8177 wxString msg = _("The Inland ECDIS Manual is not available locally.");
8178 msg += "\n";
8179 msg +=
8180 _("Would you like to visit the iECDIS Manual website for more "
8181 "information?");
8182
8183 if (wxID_YES == OCPNMessageBox(NULL, msg, _("Inland ECDIS Manual"),
8184 wxYES_NO | wxCENTER, 60)) {
8185 wxLaunchDefaultBrowser("https://opencpn-manuals.github.io/inland-ecdis");
8186 }
8187 } else {
8188#ifdef __WXMSW__
8189 wxLaunchDefaultBrowser("file:///" + *GetpSharedDataLocation() + testFile);
8190#else
8191 wxLaunchDefaultBrowser("file://" + *GetpSharedDataLocation() + testFile);
8192#endif
8193 }
8194}
8195
8196void options::OnButtoncompressClick(wxCommandEvent& event) {
8197#if 0
8198 wxArrayInt pListBoxSelections;
8199 long item = -1;
8200 for (;;) {
8201 item = pActiveChartsList->GetNextItem(item, wxLIST_NEXT_ALL,
8202 wxLIST_STATE_SELECTED);
8203 if (item == -1) break;
8204 //pListBoxSelections.Add((int)item);
8205 item = -1; // Restart
8206 }
8207
8208 if (OCPNMessageBox(this, _("Compression will alter chart files on disk.\n\
8209This may make them incompatible with other programs or older versions of OpenCPN.\n\
8210Compressed charts may take slightly longer to load and display on some systems.\n\
8211They can be decompressed again using unxz or 7 zip programs."),
8212 _("OpenCPN Warning"),
8213 wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING) !=
8214 wxID_YES)
8215 return;
8216
8217 wxArrayString filespecs;
8218 filespecs.Add("*.kap");
8219 filespecs.Add("*.KAP");
8220 filespecs.Add("*.000");
8221
8222 // should we verify we are in a cm93 directory for these?
8223 filespecs.Add("*.A"), filespecs.Add("*.B"), filespecs.Add("*.C"),
8224 filespecs.Add("*.D");
8225 filespecs.Add("*.E"), filespecs.Add("*.F"), filespecs.Add("*.G"),
8226 filespecs.Add("*.Z");
8227
8228 wxGenericProgressDialog prog1(
8229 _("OpenCPN Compress Charts"), wxEmptyString,
8230 filespecs.GetCount() * pListBoxSelections.GetCount() + 1, this,
8231 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
8232 wxPD_REMAINING_TIME | wxPD_CAN_SKIP);
8233
8234 // Make sure the dialog is big enough to be readable
8235 wxSize sz = prog1.GetSize();
8236 sz.x = top_frame::Get()->GetClientSize().x * 8 / 10;
8237 prog1.SetSize(sz);
8238
8239 wxArrayString charts;
8240 for (unsigned int i = 0; i < pListBoxSelections.GetCount(); i++) {
8241 wxString dirname = pActiveChartsList->GetItemText(pListBoxSelections[i]);
8242 if (dirname.IsEmpty()) continue;
8243 // This is a fix for OSX, which appends EOL to results of
8244 // GetLineText()
8245 while ((dirname.Last() == wxChar(_T('\n'))) ||
8246 (dirname.Last() == wxChar(_T('\r'))))
8247 dirname.RemoveLast();
8248
8249 if (!wxDir::Exists(dirname)) continue;
8250
8251 wxDir dir(dirname);
8252 wxArrayString FileList;
8253 for (unsigned int j = 0; j < filespecs.GetCount(); j++) {
8254 dir.GetAllFiles(dirname, &FileList, filespecs[j]);
8255 bool skip = false;
8256 prog1.Update(i * filespecs.GetCount() + j, dirname + filespecs[j], &skip);
8257 if (skip) return;
8258 }
8259
8260 for (unsigned int j = 0; j < FileList.GetCount(); j++)
8261 charts.Add(FileList[j]);
8262 }
8263 prog1.Hide();
8264
8265 if (charts.GetCount() == 0) {
8266 OCPNMessageBox(this, _("No charts found to compress."), _("OpenCPN Info"));
8267 return;
8268 }
8269
8270 // TODO: make this use threads
8271 unsigned long total_size = 0, total_compressed_size = 0, count = 0;
8272 wxGenericProgressDialog prog(
8273 _("OpenCPN Compress Charts"), wxEmptyString, charts.GetCount() + 1, this,
8274 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
8275 wxPD_REMAINING_TIME | wxPD_CAN_SKIP);
8276
8277 prog.SetSize(sz);
8278
8279 for (unsigned int i = 0; i < charts.GetCount(); i++) {
8280 bool skip = false;
8281 prog.Update(i, charts[i], &skip);
8282 if (skip) break;
8283
8284 wxString compchart = charts[i] + ".xz";
8285 if (CompressChart(charts[i], compchart)) {
8286 total_size += wxFileName::GetSize(charts[i]).ToULong();
8287 total_compressed_size += wxFileName::GetSize(compchart).ToULong();
8288 wxRemoveFile(charts[i]);
8289 count++;
8290 }
8291 }
8292
8293 // report statistics
8294 double total_size_mb = total_size / 1024.0 / 1024.0;
8295 double total_compressed_size_mb = total_compressed_size / 1024.0 / 1024.0;
8296 OCPNMessageBox(
8297 this,
8298 wxString::Format(_("compressed %ld charts\nfrom %.1fMB to %.1fMB\nsaved "
8299 "%.1fMB (%.1f%%)"),
8300 count, total_size_mb, total_compressed_size_mb,
8301 total_size_mb - total_compressed_size_mb,
8302 (1 - total_compressed_size_mb / total_size_mb) * 100.0),
8303 _("OpenCPN Info"));
8304
8305 UpdateWorkArrayFromTextCtl();
8306
8307 if (m_pWorkDirList) {
8308 pActiveChartsList->DeleteAllItems();
8309 for (size_t id = 0; id < m_pWorkDirList->GetCount(); id++) {
8310 wxString dirname = m_pWorkDirList->Item(id).fullpath;
8311 wxListItem li;
8312 li.SetId(id);
8313 li.SetAlign(wxLIST_FORMAT_LEFT);
8314 li.SetText(dirname);
8315 li.SetColumn(0);
8316 long idx = pActiveChartsList->InsertItem(li);
8317 }
8318 }
8319
8320 k_charts |= CHANGE_CHARTS;
8321
8322 pScanCheckBox->Disable();
8323
8324 event.Skip();
8325#endif
8326}
8327
8328void options::OnDebugcheckbox1Click(wxCommandEvent& event) { event.Skip(); }
8329
8330void options::OnCancelClick(wxCommandEvent& event) {
8331 m_pListbook->ChangeSelection(0);
8332 comm_dialog->CancelSettings();
8333
8334 lastWindowPos = GetPosition();
8335 lastWindowSize = GetSize();
8336
8337 if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxCANCEL);
8338
8339 pConfig->SetPath("/Settings");
8340 pConfig->Write("OptionsSizeX", lastWindowSize.x);
8341 pConfig->Write("OptionsSizeY", lastWindowSize.y);
8342
8343#ifdef __ANDROID__
8344 androidEnableBackButton(true);
8345 androidEnableRotation();
8346 androidEnableOptionItems(true);
8347#endif
8348
8349 top_frame::Get()->ThawCharts();
8350 Hide();
8351 top_frame::Get()->EnableSettingsTool(true);
8352}
8353
8354void options::OnClose(wxCloseEvent& event) {
8355 // PlugIns may have added panels
8356 if (g_pi_manager) g_pi_manager->CloseAllPlugInPanels((int)wxOK);
8357
8358 m_pListbook->ChangeSelection(0);
8359
8360 lastWindowPos = GetPosition();
8361 lastWindowSize = GetSize();
8362
8363 pConfig->SetPath("/Settings");
8364 pConfig->Write("OptionsSizeX", lastWindowSize.x);
8365 pConfig->Write("OptionsSizeY", lastWindowSize.y);
8366
8367 m_callbacks.prepare_close(this, m_returnChanges);
8368 Hide();
8369}
8370
8371void options::OnFontChoice(wxCommandEvent& event) {
8372 wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8373 m_font_element_array.Add(sel_text_element);
8374
8375 wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8376 wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8377
8378 m_textSample->SetFont(*pif);
8379 m_textSample->SetForegroundColour(init_color);
8380 m_itemBoxSizerFontPanel->Layout();
8381 event.Skip();
8382}
8383
8384void options::OnChooseFont(wxCommandEvent& event) {
8385#ifdef __ANDROID__
8386 androidDisableRotation();
8387#endif
8388
8389 wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8390 m_font_element_array.Add(sel_text_element);
8391 wxFontData font_data;
8392
8393 wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8394 wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8395
8396 wxFontData init_font_data;
8397 if (pif) init_font_data.SetInitialFont(*pif);
8398 init_font_data.SetColour(init_color);
8399
8400#ifdef __WXGTK__
8401 if (g_Platform->getDisplaySize().y < 800) {
8402 ocpnGenericFontDialog dg(this, init_font_data);
8403 wxFont* qFont = dialogFont;
8404 dg.SetFont(*qFont);
8405
8406 int retval = dg.ShowModal();
8407 if (wxID_CANCEL != retval) {
8408 font_data = dg.GetFontData();
8409 wxFont font = font_data.GetChosenFont();
8410 wxFont* psfont = new wxFont(font);
8411 wxColor color = font_data.GetColour();
8412 FontMgr::Get().SetFont(sel_text_element, psfont, color);
8413 top_frame::Get()->UpdateAllFonts();
8414 m_bfontChanged = true;
8415 OnFontChoice(event);
8416 }
8417 } else
8418#endif
8419 {
8420#ifdef __WXGTK__
8421 wxFontDialog dg(this, init_font_data);
8422#else
8423 wxFontDialog dg(pParent, init_font_data);
8424#endif
8425
8426 wxFont* qFont = dialogFont;
8427 dg.SetFont(*qFont);
8428
8429#ifdef __WXQT__
8430 // Make sure that font dialog will fit on the screen without scrolling
8431 // We do this by setting the dialog font size "small enough" to show "n"
8432 // lines
8433 wxSize proposed_size = GetSize();
8434 float n_lines = 30;
8435 float font_size = dialogFont->GetPointSize();
8436
8437 if ((proposed_size.y / font_size) < n_lines) {
8438 float new_font_size = proposed_size.y / n_lines;
8439 wxFont* smallFont = new wxFont(*dialogFont);
8440 smallFont->SetPointSize(new_font_size);
8441 dg.SetFont(*smallFont);
8442 }
8443#endif
8444
8445 if (g_bresponsive) {
8446 dg.SetSize(GetSize());
8447 dg.Centre();
8448 }
8449
8450 int retval = dg.ShowModal();
8451 if (wxID_CANCEL != retval) {
8452 font_data = dg.GetFontData();
8453 wxFont font = font_data.GetChosenFont();
8454 wxFont* psfont = new wxFont(font);
8455 wxColor color = font_data.GetColour();
8456 FontMgr::Get().SetFont(sel_text_element, psfont, color);
8457 top_frame::Get()->UpdateAllFonts();
8458 m_bfontChanged = true;
8459 OnFontChoice(event);
8460 }
8461 }
8462
8463#ifdef __ANDROID__
8464 androidEnableRotation();
8465#endif
8466
8467 event.Skip();
8468}
8469
8470#if defined(__WXGTK__) || defined(__WXQT__)
8471void options::OnChooseFontColor(wxCommandEvent& event) {
8472 wxString sel_text_element = m_itemFontElementListBox->GetStringSelection();
8473 m_font_element_array.Add(sel_text_element);
8474
8475 wxColourData colour_data;
8476
8477 wxFont* pif = FontMgr::Get().GetFont(sel_text_element);
8478 wxColour init_color = FontMgr::Get().GetFontColor(sel_text_element);
8479
8480#ifdef __ANDROID__
8481 androidDisableRotation();
8482
8483 unsigned int cco = 0;
8484 cco |= 0xff;
8485 cco = cco << 8;
8486 cco |= init_color.Red();
8487 cco = cco << 8;
8488 cco |= init_color.Green();
8489 cco = cco << 8;
8490 cco |= init_color.Blue();
8491 unsigned int cc = androidColorPicker(cco);
8492
8493 wxColor cn;
8494 unsigned char blue = (unsigned char)cc % 256;
8495 unsigned char green = (unsigned char)(cc >> 8) % 256;
8496 ;
8497 unsigned char red = (unsigned char)(cc >> 16) % 256;
8498 cn.Set(red, green, blue);
8499
8500 FontMgr::Get().SetFont(sel_text_element, pif, cn);
8501
8502 top_frame::Get()->UpdateAllFonts();
8503 m_bfontChanged = true;
8504
8505 androidEnableRotation();
8506#else
8507 wxScrolledWindow* sw =
8508 new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(400, 400));
8509
8510 wxColourData init_colour_data;
8511 init_colour_data.SetColour(init_color);
8512
8513 wxColourDialog dg(sw, &init_colour_data);
8514
8515 int retval = dg.ShowModal();
8516 if (wxID_CANCEL != retval) {
8517 colour_data = dg.GetColourData();
8518
8519 wxColor color = colour_data.GetColour();
8520 FontMgr::Get().SetFont(sel_text_element, pif, color);
8521
8522 top_frame::Get()->UpdateAllFonts();
8523 m_bfontChanged = true;
8524 OnFontChoice(event);
8525 }
8526
8527 sw->Destroy();
8528#endif
8529 event.Skip();
8530}
8531#endif
8532
8533void options::OnChartsPageChange(wxListbookEvent& event) {
8534 unsigned int i = event.GetSelection();
8535
8536 UpdateChartDirList();
8537
8538 // User selected Chart Groups Page?
8539 // If so, build the remaining UI elements
8540 if (2 == i) { // 2 is the index of "Chart Groups" page
8541 if (!groupsPanel->m_UIcomplete) groupsPanel->CompletePanel();
8542
8543 // Make sure any recently added chart dirs appear in the
8544 // Groups panel, making them available for addition to groups.
8545 UpdateWorkArrayFromDisplayPanel();
8546 groupsPanel->SetDBDirs(*m_pWorkDirList); // update the Groups tab
8547 groupsPanel->m_treespopulated = FALSE;
8548
8549 if (!groupsPanel->m_settingscomplete) {
8550 ::wxBeginBusyCursor();
8551 groupsPanel->CompleteInitialSettings();
8552 ::wxEndBusyCursor();
8553 } else if (!groupsPanel->m_treespopulated) {
8554 groupsPanel->PopulateTrees();
8555 groupsPanel->m_treespopulated = TRUE;
8556 }
8557 } else if (1 == i) { // Vector charts panel
8558 LoadS57();
8559 if (!m_bVectorInit) {
8560 SetInitialVectorSettings();
8561 UpdateOptionsUnits(); // sets depth values, overriding defaults
8562 }
8563 }
8564
8565 event.Skip(); // Allow continued event processing
8566}
8567
8568void options::OnPageChange(wxListbookEvent& event) {
8569 DoOnPageChange(event.GetSelection());
8570}
8571
8572void options::OnSubNBPageChange(wxNotebookEvent& event) {
8573 // In the case where wxNotebooks are nested, we need to identify the subpage
8574 // But otherwise do nothing
8575 if (event.GetEventObject()) {
8576 if (dynamic_cast<wxWindow*>(event.GetEventObject())) {
8577 wxWindow* win = dynamic_cast<wxWindow*>(event.GetEventObject());
8578 wxWindow* parent = dynamic_cast<wxWindow*>(win->GetParent());
8579 if (dynamic_cast<wxNotebook*>(parent)) {
8580 lastSubPage = event.GetSelection();
8581 return;
8582 }
8583 if (dynamic_cast<wxListbook*>(parent)) {
8584 lastSubPage = event.GetSelection();
8585 return;
8586 }
8587 }
8588 }
8589}
8590
8591void options::OnTopNBPageChange(wxNotebookEvent& event) {
8592 DoOnPageChange(event.GetSelection());
8593}
8594
8595void options::DoOnPageChange(size_t page) {
8596 unsigned int i = page;
8597
8598 // Sometimes there is a (-1) page selected.
8599 if (page > 10) return;
8600
8601 lastSubPage = 0; // Reset sub-page
8602
8603 lastPage = i;
8604
8605#ifndef __ANDROID__
8606 if (0 == i) { // Display
8607 if (m_sconfigSelect_single) m_sconfigSelect_single->Refresh(true);
8608 if (m_sconfigSelect_twovertical) m_sconfigSelect_twovertical->Refresh(true);
8609 }
8610#endif
8611 // User selected Chart Page?
8612 // If so, build the "Charts" page variants
8613 if (1 == i) { // 2 is the index of "Charts" page
8614 k_charts = VISIT_CHARTS;
8615 UpdateChartDirList();
8616 }
8617
8618 else if (m_pageConnections == i) {
8619 // Only required on some Windows hosts, but should not hurt. See #4570
8620 wxWindow* w = m_pListbook->GetCurrentPage();
8621 comm_dialog->OnResize(w ? w->GetClientSize() : wxSize());
8622 }
8623
8624 else if (m_pageUI == i) { // 5 is the index of "User Interface" page
8625 if (!m_itemLangListBox) return;
8626#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
8627
8628 if (!m_bVisitLang) {
8629 ::wxBeginBusyCursor();
8630
8631 int current_language = plocale_def_lang->GetLanguage();
8632 wxString current_sel = wxLocale::GetLanguageName(current_language);
8633
8634 current_sel = GetOCPNKnownLanguage(g_locale);
8635
8636 int nLang = sizeof(lang_list) / sizeof(int);
8637#ifdef __WXMSW__
8638 // always add us english
8639 m_itemLangListBox->Append("English (U.S.)");
8640
8641 wxString lang_dir = g_Platform->GetSharedDataDir() + "share/locale/";
8642 for (int it = 1; it < nLang; it++) {
8643 if (wxLocale::IsAvailable(lang_list[it])) {
8644 wxLocale ltest(lang_list[it], 0);
8645 ltest.AddCatalog("opencpn");
8646 if (!ltest.IsLoaded("opencpn")) continue;
8647
8648 // Defaults
8649 wxString loc_lang_name = wxLocale::GetLanguageName(lang_list[it]);
8650 wxString widgets_lang_name = loc_lang_name;
8651 wxString lang_canonical =
8652 wxLocale::GetLanguageInfo(lang_list[it])->CanonicalName;
8653
8654 // Make opencpn substitutions
8655 wxString lang_suffix;
8656 loc_lang_name = GetOCPNKnownLanguage(lang_canonical, lang_suffix);
8657
8658 // Look explicitely to see if .mo is available
8659 wxString test_dir = lang_dir + lang_suffix;
8660 if (!wxDir::Exists(test_dir)) continue;
8661
8662 m_itemLangListBox->Append(loc_lang_name);
8663 }
8664 }
8665#else
8666 wxArrayString lang_array;
8667
8668 // always add us english
8669 lang_array.Add("en_US");
8670 for (int it = 0; it < nLang; it++) {
8671 {
8672 wxLog::EnableLogging(
8673 FALSE); // avoid "Cannot set locale to..." log message
8674
8675 wxLocale ltest(lang_list[it], 0);
8676#if wxCHECK_VERSION(2, 9, 0)
8677#ifdef __WXGTK__
8678 ltest.AddCatalogLookupPathPrefix(
8679 wxStandardPaths::Get().GetInstallPrefix() + "/share/locale");
8680#endif
8681#endif
8682 ltest.AddCatalog("opencpn");
8683
8684 wxLog::EnableLogging(TRUE);
8685 if (ltest.IsLoaded("opencpn")) {
8686 auto x = wxLocale::GetLanguageInfo(lang_list[it]);
8687 wxString s0;
8688 if (x)
8689 s0 = x->CanonicalName;
8690 else
8691 continue;
8692 wxString sl = wxLocale::GetLanguageName(lang_list[it]);
8693 if (wxNOT_FOUND == lang_array.Index(s0)) {
8694 lang_array.Add(s0);
8695 }
8696 }
8697 }
8698 }
8699
8700 for (unsigned int i = 0; i < lang_array.GetCount(); i++) {
8701 // Make opencpn substitutions
8702 wxString loc_lang_name = GetOCPNKnownLanguage(lang_array[i]);
8703 m_itemLangListBox->Append(loc_lang_name);
8704 }
8705#endif
8706 // BUGBUG
8707 // Remember that wxLocale ctor has the effect of changing the system
8708 // locale, including the "C" libraries.
8709 // It should then also happen that the locale should be switched back to
8710 // ocpn initial load setting
8711 // upon the dtor of the above wxLocale instantiations....
8712 // wxWidgets may do so internally, but there seems to be no effect upon
8713 // the system libraries, so that
8714 // functions like strftime() do not revert to the correct locale setting.
8715 // Also, the catalog for the application is not reloaded by the ctor, so
8716 // we must reload them directly
8717 // So as workaround, we reset the locale explicitely.
8718
8719 delete plocale_def_lang;
8720 plocale_def_lang = new wxLocale(current_language);
8721
8722 setlocale(LC_NUMERIC, "C");
8723 plocale_def_lang->AddCatalog("opencpn");
8724
8725 m_itemLangListBox->SetStringSelection(current_sel);
8726
8727 // Initialize Language tab
8728 const wxLanguageInfo* pli = wxLocale::FindLanguageInfo(g_locale);
8729 if (pli) {
8730 wxString clang = pli->Description;
8731 // m_itemLangListBox->SetValue(clang);
8732 }
8733
8734 m_bVisitLang = TRUE;
8735
8736 ::wxEndBusyCursor();
8737 }
8738#endif
8739 } else if (m_pagePlugins == i) { // 7 is the index of "Plugins" page
8740 m_bVisitPlugins = TRUE;
8741 top_frame::Get()->FreezeCharts();
8742
8743 // load the disabled plugins finally because the user might want to enable
8744 // them
8745 auto loader = PluginLoader::GetInstance();
8746 if (LoadAllPlugIns(false)) {
8747 delete m_pPlugInCtrl;
8748 m_pPlugInCtrl = NULL;
8749 delete m_PluginCatalogMgrPanel;
8750 m_PluginCatalogMgrPanel = NULL;
8751 itemBoxSizerPanelPlugins->Clear();
8752 }
8753
8754 if (!m_pPlugInCtrl) {
8755 // Build the PlugIn Manager Panel
8756 ::wxBeginBusyCursor();
8757
8758 m_pPlugInCtrl = new PluginListPanel(itemPanelPlugins, ID_PANELPIM,
8759 wxDefaultPosition, wxDefaultSize);
8760 m_pPlugInCtrl->SetScrollRate(m_scrollRate, m_scrollRate);
8761 itemBoxSizerPanelPlugins->Add(m_pPlugInCtrl, 01,
8762 wxEXPAND | wxGROW | wxALL, 4);
8763 if (g_pi_manager) g_pi_manager->SetListPanelPtr(m_pPlugInCtrl);
8764
8765 m_PluginCatalogMgrPanel = new CatalogMgrPanel(itemPanelPlugins);
8766 m_PluginCatalogMgrPanel->SetListPanelPtr(m_pPlugInCtrl);
8767
8768 itemBoxSizerPanelPlugins->Add(m_PluginCatalogMgrPanel, 0,
8769 wxEXPAND | wxALL, 4);
8770 itemBoxSizerPanelPlugins->Layout();
8771
8772 // Update the PlugIn page to reflect the state of individual selections
8773 m_pPlugInCtrl->UpdateSelections();
8774
8775 ::wxEndBusyCursor();
8776
8777 wxDEFINE_EVENT(EVT_COMPAT_OS_CHANGE, wxCommandEvent);
8778 GlobalVar<wxString> compat_os(&g_compatOS);
8779 }
8780 k_plugins = TOOLBAR_CHANGED;
8781 // TODO Only if o-charts is touched?
8782 k_plugins |= FORCE_RELOAD;
8783 }
8784}
8785
8786wxString options::SelectSoundFile() {
8787 wxString sound_dir = g_Platform->GetSharedDataDir();
8788 sound_dir.Append("sounds");
8789 wxString sel_file;
8790 int response;
8791
8792#ifndef __ANDROID__
8793 wxFileDialog* popenDialog = new wxFileDialog(
8794 NULL, _("Select Sound File"), sound_dir, wxEmptyString,
8795 "WAV files (*.wav)|*.wav|All files (*.*)|*.*", wxFD_OPEN);
8796 if (g_bresponsive)
8797 popenDialog = g_Platform->AdjustFileDialogFont(this, popenDialog);
8798
8799 response = popenDialog->ShowModal();
8800 sel_file = popenDialog->GetPath();
8801 delete popenDialog;
8802
8803#else
8804 response = g_Platform->DoFileSelectorDialog(
8805 this, &sel_file, _("Select Sound File"), sound_dir, wxEmptyString, "*.*");
8806#endif
8807
8808 if (response == wxID_OK)
8809 return g_Platform->NormalizePath(sel_file);
8810 else
8811 return "";
8812}
8813
8814void options::OnButtonSelectSound(wxCommandEvent& event) {
8815 wxString sel_file = SelectSoundFile();
8816
8817 if (!sel_file.IsEmpty()) {
8818 g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(sel_file);
8819 }
8820}
8821
8822void options::OnButtonTestSound(wxCommandEvent& event) {
8823 auto sound = o_sound::Factory();
8824 auto cmd_sound = dynamic_cast<o_sound::SystemCmdSound*>(sound);
8825 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str());
8826 sound->SetFinishedCallback([&](void* snd) { m_on_sound_done.Notify(snd); });
8827 sound->Load(m_soundPanelAIS->GetSoundFile(), g_iSoundDeviceIndex);
8828 sound->Play();
8829}
8830
8831wxString GetOCPNKnownLanguage(wxString lang_canonical, wxString& lang_dir) {
8832 wxString return_string;
8833 wxString dir_suffix;
8834
8835#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
8836
8837 if (lang_canonical == "en_US") {
8838 dir_suffix = "en";
8839 return_string = wxString("English (U.S.)", wxConvUTF8);
8840
8841 } else if ((lang_canonical == "cs_CZ") || (lang_canonical == "cs")) {
8842 dir_suffix = "cs";
8843 return_string = wxString("Čeština", wxConvUTF8);
8844
8845 } else if ((lang_canonical == "da_DK") || (lang_canonical == "da")) {
8846 dir_suffix = "da";
8847 return_string = wxString("Dansk", wxConvUTF8);
8848
8849 } else if ((lang_canonical == "de_DE") || (lang_canonical == "de")) {
8850 dir_suffix = "de";
8851 return_string = wxString("Deutsch", wxConvUTF8);
8852
8853 } else if ((lang_canonical == "et_EE") || (lang_canonical == "et")) {
8854 dir_suffix = "et";
8855 return_string = wxString("Eesti", wxConvUTF8);
8856
8857 } else if ((lang_canonical == "es_ES") || (lang_canonical == "es")) {
8858 dir_suffix = "es";
8859 return_string = wxString("Español", wxConvUTF8);
8860
8861 } else if ((lang_canonical == "fr_FR") || (lang_canonical == "fr")) {
8862 dir_suffix = "fr";
8863 return_string = wxString("Français", wxConvUTF8);
8864
8865 } else if ((lang_canonical == "it_IT") || (lang_canonical == "it")) {
8866 dir_suffix = "it";
8867 return_string = wxString("Italiano", wxConvUTF8);
8868
8869 } else if ((lang_canonical == "nl_NL") || (lang_canonical == "nl")) {
8870 dir_suffix = "nl";
8871 return_string = wxString("Nederlands", wxConvUTF8);
8872
8873 } else if ((lang_canonical == "pl_PL") || (lang_canonical == "pl")) {
8874 dir_suffix = "pl";
8875 return_string = wxString("Polski", wxConvUTF8);
8876
8877 } else if ((lang_canonical == "pt_PT") || (lang_canonical == "pt")) {
8878 dir_suffix = "pt_PT";
8879 return_string = wxString("Português", wxConvUTF8);
8880
8881 } else if ((lang_canonical == "pt_BR") || (lang_canonical == "pt_BR")) {
8882 dir_suffix = "pt_BR";
8883 return_string = wxString("Português Brasileiro", wxConvUTF8);
8884
8885 } else if ((lang_canonical == "ru_RU") || (lang_canonical == "ru")) {
8886 dir_suffix = "ru";
8887 return_string = wxString("Русский", wxConvUTF8);
8888
8889 } else if ((lang_canonical == "sv_SE") || (lang_canonical == "sv")) {
8890 dir_suffix = "sv";
8891 return_string = wxString("Svenska", wxConvUTF8);
8892
8893 } else if ((lang_canonical == "fi_FI") || (lang_canonical == "fi")) {
8894 dir_suffix = "fi_FI";
8895 return_string = wxString("Suomi", wxConvUTF8);
8896
8897 } else if ((lang_canonical == "nb_NO") || (lang_canonical == "nb")) {
8898 dir_suffix = "nb_NO";
8899 return_string = wxString("Norsk", wxConvUTF8);
8900
8901 } else if ((lang_canonical == "tr_TR") || (lang_canonical == "tr")) {
8902 dir_suffix = "tr_TR";
8903 return_string = wxString("Türkçe", wxConvUTF8);
8904
8905 } else if ((lang_canonical == "el_GR") || (lang_canonical == "el")) {
8906 dir_suffix = "el_GR";
8907 return_string = wxString("Ελληνικά", wxConvUTF8);
8908
8909 } else if ((lang_canonical == "hu_HU") || (lang_canonical == "hu")) {
8910 dir_suffix = "hu_HU";
8911 return_string = wxString("Magyar", wxConvUTF8);
8912
8913 } else if ((lang_canonical == "zh_TW") || (lang_canonical == "zh_TW")) {
8914 dir_suffix = "zh_TW";
8915 return_string = wxString("正體字", wxConvUTF8);
8916
8917 } else if ((lang_canonical == "zh_CN") || (lang_canonical == "zh_CN")) {
8918 dir_suffix = "zh_CN";
8919 return_string = wxString("Simplified Chinese", wxConvUTF8);
8920
8921 } else if ((lang_canonical == "ca_ES") || (lang_canonical == "ca")) {
8922 dir_suffix = "ca_ES";
8923 return_string = wxString("Catalan", wxConvUTF8);
8924
8925 } else if ((lang_canonical == "gl_ES") || (lang_canonical == "gl_ES")) {
8926 dir_suffix = "gl_ES";
8927 return_string = wxString("Galician", wxConvUTF8);
8928
8929 } else if ((lang_canonical == "ja_JP") || (lang_canonical == "ja_JP")) {
8930 dir_suffix = "ja_JP";
8931 return_string = wxString("Japanese", wxConvUTF8);
8932
8933 } else if ((lang_canonical == "vi_VN") || (lang_canonical == "vi_VN")) {
8934 dir_suffix = "vi_VN";
8935 return_string = wxString("Vietnamese", wxConvUTF8);
8936
8937 } else {
8938 dir_suffix = lang_canonical;
8939 const wxLanguageInfo* info = wxLocale::FindLanguageInfo(lang_canonical);
8940 if (info)
8941 return_string = info->Description;
8942 else
8943 return_string = lang_canonical;
8944 }
8945
8946 lang_dir = dir_suffix;
8947#endif
8948 return return_string;
8949}
8950
8951wxString GetOCPNKnownLanguage(const wxString lang_canonical) {
8952 wxString lang_dir;
8953 return GetOCPNKnownLanguage(lang_canonical, lang_dir);
8954}
8955
8956ChartGroupArray* ChartGroupsUI::CloneChartGroupArray(ChartGroupArray* s) {
8957 ChartGroupArray* d = new ChartGroupArray;
8958 for (unsigned int i = 0; i < s->GetCount(); i++) {
8959 ChartGroup* psg = s->Item(i);
8960 ChartGroup* pdg = new ChartGroup;
8961 pdg->m_group_name = psg->m_group_name;
8962 pdg->m_element_array.reserve(psg->m_element_array.size());
8963
8964 for (auto& elem : psg->m_element_array)
8965 pdg->m_element_array.push_back(elem);
8966
8967 d->Add(pdg);
8968 }
8969 return d;
8970}
8971
8972void ChartGroupsUI::EmptyChartGroupArray(ChartGroupArray* s) {
8973 if (!s) return;
8974
8975 // ChartGroups don't need anything special for delete, just calling the
8976 // destructor is enough.
8977 WX_CLEAR_ARRAY(*s);
8978}
8979
8980// Chart Groups dialog implementation
8981BEGIN_EVENT_TABLE(ChartGroupsUI, wxEvtHandler)
8982EVT_TREE_ITEM_EXPANDED(wxID_TREECTRL, ChartGroupsUI::OnNodeExpanded)
8983EVT_NOTEBOOK_PAGE_CHANGED(
8984 wxID_ANY,
8985 ChartGroupsUI::OnGroupPageChange) // This should work under Windows :-(
8986END_EVENT_TABLE()
8987
8988ChartGroupsUI::ChartGroupsUI(wxWindow* parent) : wxScrolledWindow(parent) {
8989 m_GroupSelectedPage = -1;
8990 m_pActiveChartsTree = 0;
8991 pParent = parent;
8992 lastSelectedCtl = NULL;
8993 allAvailableCtl = NULL;
8994 defaultAllCtl = NULL;
8995 iFont = NULL;
8996 m_pAddButton = NULL;
8997 m_pRemoveButton = NULL;
8998 m_pDeleteGroupButton = NULL;
8999 m_pNewGroupButton = NULL;
9000 m_pGroupArray = NULL;
9001 m_GroupNB = NULL;
9002 modified = false;
9003 m_UIcomplete = false;
9004 m_treespopulated = false;
9005 dialogFont = GetOCPNScaledFont(_("Dialog"));
9006}
9007
9008ChartGroupsUI::~ChartGroupsUI() {
9009 m_DirCtrlArray.Clear();
9010 m_GroupNB->Disconnect(
9011 wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
9012 wxNotebookEventHandler(ChartGroupsUI::OnGroupPageChange), NULL, this);
9013
9014 delete iFont;
9015}
9016
9017void ChartGroupsUI::SetInitialSettings() {
9018 m_settingscomplete = FALSE;
9019 m_treespopulated = FALSE;
9020}
9021
9022void ChartGroupsUI::PopulateTrees() {
9023 // Fill in the "Active chart" tree control
9024 // from the options dialog "Active Chart Directories" list
9025 wxArrayString dir_array;
9026 int nDir = m_db_dirs.GetCount();
9027 for (int i = 0; i < nDir; i++) {
9028 wxString dirname = m_db_dirs[i].fullpath;
9029 if (!dirname.IsEmpty()) dir_array.Add(dirname);
9030 }
9031
9032 PopulateTreeCtrl(allAvailableCtl->GetTreeCtrl(), dir_array,
9033 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),
9034 dialogFont);
9035 m_pActiveChartsTree = allAvailableCtl->GetTreeCtrl();
9036
9037 // Fill in the Page 0 tree control
9038 // from the options dialog "Active Chart Directories" list
9039 wxArrayString dir_array0;
9040 int nDir0 = m_db_dirs.GetCount();
9041 for (int i = 0; i < nDir0; i++) {
9042 wxString dirname = m_db_dirs[i].fullpath;
9043 if (!dirname.IsEmpty()) dir_array0.Add(dirname);
9044 }
9045 PopulateTreeCtrl(defaultAllCtl->GetTreeCtrl(), dir_array0,
9046 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), iFont);
9047}
9048
9049void ChartGroupsUI::CompleteInitialSettings() {
9050 PopulateTrees();
9051
9052 BuildNotebookPages(m_pGroupArray);
9053
9054 m_panel->GetSizer()->Layout();
9055
9056 m_settingscomplete = TRUE;
9057 m_treespopulated = TRUE;
9058}
9059
9060void ChartGroupsUI::PopulateTreeCtrl(wxTreeCtrl* ptc,
9061 const wxArrayString& dir_array,
9062 const wxColour& col, wxFont* pFont) {
9063 ptc->DeleteAllItems();
9064
9065 wxDirItemData* rootData = new wxDirItemData("Dummy", "Dummy", TRUE);
9066 wxString rootName;
9067 rootName = "Dummy";
9068 wxTreeItemId m_rootId = ptc->AddRoot(rootName, 3, -1, rootData);
9069 ptc->SetItemHasChildren(m_rootId);
9070
9071 wxString dirname;
9072 int nDir = dir_array.GetCount();
9073 for (int i = 0; i < nDir; i++) {
9074 wxString dirname = dir_array[i];
9075 if (!dirname.IsEmpty()) {
9076 wxDirItemData* dir_item = new wxDirItemData(dirname, dirname, TRUE);
9077 wxTreeItemId id = ptc->AppendItem(m_rootId, dirname, 0, -1, dir_item);
9078
9079 // wxWidgets bug workaraound (Ticket #10085)
9080 ptc->SetItemText(id, dirname);
9081 if (pFont) ptc->SetItemFont(id, *pFont);
9082
9083#ifndef __WXOSX__
9084 // On MacOS, use the default system dialog color, to honor Dark mode.
9085 ptc->SetItemTextColour(id, col);
9086#endif
9087 ptc->SetItemHasChildren(id);
9088 }
9089 }
9090}
9091
9092void ChartGroupsUI::OnInsertChartItem(wxCommandEvent& event) {
9093 wxString insert_candidate = allAvailableCtl->GetPath();
9094 if (!insert_candidate.IsEmpty()) {
9095 if (m_DirCtrlArray.GetCount()) {
9096 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9097 ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9098 if (pDirCtrl) {
9099 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9100 if (ptree) {
9101 if (ptree->IsEmpty()) {
9102 wxDirItemData* rootData =
9103 new wxDirItemData(wxEmptyString, wxEmptyString, TRUE);
9104 wxString rootName = "Dummy";
9105 wxTreeItemId rootId = ptree->AddRoot(rootName, 3, -1, rootData);
9106
9107 ptree->SetItemHasChildren(rootId);
9108 }
9109
9110 wxTreeItemId root_Id = ptree->GetRootItem();
9111 wxDirItemData* dir_item =
9112 new wxDirItemData(insert_candidate, insert_candidate, TRUE);
9113 wxTreeItemId id =
9114 ptree->AppendItem(root_Id, insert_candidate, 0, -1, dir_item);
9115 if (wxDir::Exists(insert_candidate)) ptree->SetItemHasChildren(id);
9116 }
9117
9118 pGroup->m_element_array.push_back({insert_candidate});
9119 }
9120 }
9121 }
9122 modified = TRUE;
9123 allAvailableCtl->GetTreeCtrl()->UnselectAll();
9124 m_pAddButton->Disable();
9125
9126 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9127 if (pDirCtrl) {
9128 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9129 if (ptree) ptree->Refresh();
9130 }
9131}
9132
9133void ChartGroupsUI::OnRemoveChartItem(wxCommandEvent& event) {
9134 if (m_DirCtrlArray.GetCount()) {
9135 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9136 ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9137
9138 if (pDirCtrl) {
9139 wxString sel_item = pDirCtrl->GetPath();
9140
9141 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9142 if (ptree && ptree->GetCount()) {
9143 wxTreeItemId id = ptree->GetSelection();
9144 lastDeletedItem = id;
9145 if (id.IsOk()) {
9146 wxString branch_adder;
9147 int group_item_index =
9148 FindGroupBranch(pGroup, ptree, id, &branch_adder);
9149 if (group_item_index >= 0) {
9150 ChartGroupElement& pelement =
9151 pGroup->m_element_array[group_item_index];
9152 bool b_duplicate = FALSE;
9153 for (unsigned int k = 0; k < pelement.m_missing_name_array.size();
9154 k++) {
9155 if (pelement.m_missing_name_array[k] == sel_item) {
9156 b_duplicate = TRUE;
9157 break;
9158 }
9159 }
9160 if (!b_duplicate) {
9161 pelement.m_missing_name_array.Add(sel_item);
9162 }
9163
9164 // Special case...
9165 // If the selection is a branch itself,
9166 // Then delete from the tree, and delete from the group
9167 if (branch_adder == "") {
9168 ptree->Delete(id);
9169 pGroup->m_element_array.erase(pGroup->m_element_array.begin() +
9170 group_item_index);
9171 } else {
9172 ptree->SetItemTextColour(id, wxColour(128, 128, 128));
9173 // what about toggle back?
9174 }
9175 }
9176 }
9177 modified = TRUE;
9178 lastSelectedCtl->Unselect();
9179 lastSelectedCtl = 0;
9180 m_pRemoveButton->Disable();
9181
9182 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9183 if (pDirCtrl) {
9184 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9185 if (ptree) ptree->Refresh();
9186 }
9187 }
9188 }
9189 }
9190 event.Skip();
9191}
9192
9193void ChartGroupsUI::OnGroupPageChange(wxNotebookEvent& event) {
9194 m_GroupSelectedPage = event.GetSelection();
9195 allAvailableCtl->GetTreeCtrl()->UnselectAll();
9196 if (lastSelectedCtl) {
9197 lastSelectedCtl->UnselectAll();
9198 lastSelectedCtl = 0;
9199 }
9200 m_pRemoveButton->Disable();
9201 m_pAddButton->Disable();
9202
9203 // Disable delete option for "All Charts" group
9204 if (m_GroupSelectedPage == 0) {
9205 if (m_pDeleteGroupButton) m_pDeleteGroupButton->Disable();
9206 } else {
9207 if (m_pDeleteGroupButton) m_pDeleteGroupButton->Enable();
9208 }
9209}
9210
9211void ChartGroupsUI::OnAvailableSelection(wxTreeEvent& event) {
9212 wxObject* evtObj = event.GetEventObject();
9213 if (allAvailableCtl && (evtObj == allAvailableCtl->GetTreeCtrl())) {
9214 wxTreeItemId item = allAvailableCtl->GetTreeCtrl()->GetSelection();
9215 if (item && item.IsOk() && m_GroupSelectedPage > 0) {
9216 m_pAddButton->Enable();
9217 } else {
9218 m_pAddButton->Disable();
9219 }
9220 } else {
9221 lastSelectedCtl = dynamic_cast<wxTreeCtrl*>(evtObj);
9222 if (!lastSelectedCtl) goto out;
9223 wxTreeItemId item = lastSelectedCtl->GetSelection();
9224 if (item && item.IsOk() && m_GroupSelectedPage > 0) {
9225 // We need a trick for wxGTK here, since it gives us a Selection
9226 // event with the just deleted element after OnRemoveChartItem()
9227 wxGenericDirCtrl* dirCtrl =
9228 dynamic_cast<wxGenericDirCtrl*>(lastSelectedCtl->GetParent());
9229 if (!dirCtrl) goto out;
9230 wxString itemPath = dirCtrl->GetPath();
9231 if (!itemPath.IsEmpty()) m_pRemoveButton->Enable();
9232 } else {
9233 m_pRemoveButton->Disable();
9234 }
9235 }
9236
9237out:
9238 event.Skip();
9239}
9240
9241void ChartGroupsUI::OnNewGroup(wxCommandEvent& event) {
9242 wxTextEntryDialog* pd = new wxTextEntryDialog();
9243 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
9244 pd->SetFont(*qFont);
9245
9246 pd->Create(m_panel, _("Enter Group Name"), _("New Chart Group"));
9247
9248#ifdef __ANDROID__
9249 androidDisableRotation();
9250#endif
9251
9252 if (pd->ShowModal() == wxID_OK) {
9253 if (pd->GetValue().Length()) {
9254 AddEmptyGroupPage(pd->GetValue());
9255 ChartGroup* pGroup = new ChartGroup;
9256 pGroup->m_group_name = pd->GetValue();
9257 m_pGroupArray->Add(pGroup);
9258
9259 m_GroupSelectedPage =
9260 m_GroupNB->GetPageCount() - 1; // select the new page
9261 m_GroupNB->ChangeSelection(m_GroupSelectedPage);
9262 m_pDeleteGroupButton->Enable();
9263 modified = TRUE;
9264 }
9265 }
9266 delete pd;
9267
9268#ifdef __ANDROID__
9269 androidEnableRotation();
9270#endif
9271}
9272
9273void ChartGroupsUI::OnDeleteGroup(wxCommandEvent& event) {
9274 if (0 != m_GroupSelectedPage) {
9275 m_DirCtrlArray.RemoveAt(m_GroupSelectedPage);
9276 if (m_pGroupArray) m_pGroupArray->RemoveAt(m_GroupSelectedPage - 1);
9277 m_GroupNB->DeletePage(m_GroupSelectedPage);
9278 modified = TRUE;
9279 }
9280 if (m_GroupSelectedPage <= 0) {
9281 m_pAddButton->Disable();
9282 m_pDeleteGroupButton->Disable();
9283 }
9284}
9285
9286int ChartGroupsUI::FindGroupBranch(ChartGroup* pGroup, wxTreeCtrl* ptree,
9287 wxTreeItemId item, wxString* pbranch_adder) {
9288 wxString branch_name;
9289 wxString branch_adder;
9290
9291 wxTreeItemId current_node = item;
9292 while (current_node.IsOk()) {
9293 wxTreeItemId parent_node = ptree->GetItemParent(current_node);
9294 if (!parent_node) break;
9295
9296 if (parent_node == ptree->GetRootItem()) {
9297 branch_name = ptree->GetItemText(current_node);
9298 break;
9299 }
9300
9301 branch_adder.Prepend(ptree->GetItemText(current_node));
9302 branch_adder.Prepend(wxString(wxFILE_SEP_PATH));
9303
9304 current_node = ptree->GetItemParent(current_node);
9305 }
9306
9307 // Find the index and element pointer of the target branch in the Group
9308 unsigned int target_item_index = -1;
9309
9310 for (unsigned int i = 0; i < pGroup->m_element_array.size(); i++) {
9311 const wxString& target = pGroup->m_element_array[i].m_element_name;
9312 if (branch_name == target) {
9313 target_item_index = i;
9314 break;
9315 }
9316 }
9317
9318 if (pbranch_adder) *pbranch_adder = branch_adder;
9319
9320 return target_item_index;
9321}
9322
9323void ChartGroupsUI::OnNodeExpanded(wxTreeEvent& event) {
9324 wxTreeItemId node = event.GetItem();
9325
9326 if (m_GroupSelectedPage <= 0) return;
9327 wxGenericDirCtrl* pDirCtrl = (m_DirCtrlArray[m_GroupSelectedPage]);
9328 ChartGroup* pGroup = m_pGroupArray->Item(m_GroupSelectedPage - 1);
9329 if (!pDirCtrl) return;
9330
9331 wxTreeCtrl* ptree = pDirCtrl->GetTreeCtrl();
9332 wxString branch_adder;
9333 int target_item_index = FindGroupBranch(pGroup, ptree, node, &branch_adder);
9334 if (target_item_index < 0) return;
9335 const ChartGroupElement& target_element =
9336 pGroup->m_element_array[target_item_index];
9337 const wxString& branch_name = target_element.m_element_name;
9338
9339 // Walk the children of the expanded node, marking any items which appear in
9340 // the "missing" list
9341 if (!target_element.m_missing_name_array.GetCount()) return;
9342 wxString full_root = branch_name;
9343 full_root += branch_adder;
9344 full_root += wxString(wxFILE_SEP_PATH);
9345
9346 wxTreeItemIdValue cookie;
9347 wxTreeItemId child = ptree->GetFirstChild(node, cookie);
9348 while (child.IsOk()) {
9349 wxString target_string = full_root;
9350 target_string += ptree->GetItemText(child);
9351
9352 for (unsigned int k = 0; k < target_element.m_missing_name_array.GetCount();
9353 k++) {
9354 if (target_element.m_missing_name_array[k] == target_string) {
9355 ptree->SetItemTextColour(child, wxColour(128, 128, 128));
9356 break;
9357 }
9358 }
9359 child = ptree->GetNextChild(node, cookie);
9360 }
9361}
9362
9363void ChartGroupsUI::BuildNotebookPages(ChartGroupArray* pGroupArray) {
9364 ClearGroupPages();
9365
9366 for (unsigned int i = 0; i < pGroupArray->GetCount(); i++) {
9367 ChartGroup* pGroup = pGroupArray->Item(i);
9368 wxTreeCtrl* ptc = AddEmptyGroupPage(pGroup->m_group_name);
9369
9370 wxString itemname;
9371 int nItems = pGroup->m_element_array.size();
9372 for (int i = 0; i < nItems; i++) {
9373 const wxString& itemname = pGroup->m_element_array[i].m_element_name;
9374 if (!itemname.IsEmpty()) {
9375 wxDirItemData* dir_item = new wxDirItemData(itemname, itemname, TRUE);
9376 wxTreeItemId id =
9377 ptc->AppendItem(ptc->GetRootItem(), itemname, 0, -1, dir_item);
9378
9379 if (wxDir::Exists(itemname)) ptc->SetItemHasChildren(id);
9380 }
9381 }
9382 }
9383}
9384
9385wxTreeCtrl* ChartGroupsUI::AddEmptyGroupPage(const wxString& label) {
9386 wxGenericDirCtrl* GroupDirCtl =
9387 new wxGenericDirCtrl(m_GroupNB, wxID_ANY, "TESTDIR");
9388 m_GroupNB->AddPage(GroupDirCtl, label);
9389
9390 wxTreeCtrl* ptree = GroupDirCtl->GetTreeCtrl();
9391 ptree->DeleteAllItems();
9392
9393 wxDirItemData* rootData =
9394 new wxDirItemData(wxEmptyString, wxEmptyString, TRUE);
9395 wxString rootName = "Dummy";
9396 wxTreeItemId rootId = ptree->AddRoot(rootName, 3, -1, rootData);
9397 ptree->SetItemHasChildren(rootId);
9398
9399 m_DirCtrlArray.Add(GroupDirCtl);
9400
9401 return ptree;
9402}
9403
9404void ChartGroupsUI::ClearGroupPages() {
9405 if (m_GroupNB->GetPageCount() == 0) return;
9406
9407 for (unsigned int i = m_GroupNB->GetPageCount() - 1; i > 0; i--) {
9408 m_DirCtrlArray.RemoveAt(i);
9409 m_GroupNB->DeletePage(i);
9410 }
9411}
9412
9413void options::OnInsertTideDataLocation(wxCommandEvent& event) {
9414 wxString sel_file;
9415 int response = wxID_CANCEL;
9416
9417#ifndef __ANDROID__
9418 wxFileDialog* popenDialog = new wxFileDialog(
9419 NULL, _("Select Tide/Current Data"), g_TCData_Dir, "",
9420 "Tide/Current Data files (*.IDX; *.TCD)|*.IDX;*.idx;*.TCD;*.tcd|All "
9421 "files (*.*)|*.*",
9422 wxFD_OPEN);
9423 if (g_bresponsive)
9424 popenDialog = g_Platform->AdjustFileDialogFont(this, popenDialog);
9425
9426 response = popenDialog->ShowModal();
9427 sel_file = popenDialog->GetPath();
9428 delete popenDialog;
9429
9430#else
9431 wxString path;
9432 response = g_Platform->DoFileSelectorDialog(
9433 this, &path, _("Select Tide/Current Data"), g_TCData_Dir, "", "*.*");
9434 sel_file = path;
9435#endif
9436
9437 if (response == wxID_OK) {
9438 wxListItem li;
9439 int id = tcDataSelected->GetItemCount(); // next index
9440 li.SetId(id);
9441 long idx = tcDataSelected->InsertItem(li);
9442 tcDataSelected->SetItem(id, 0, g_Platform->NormalizePath(sel_file));
9443
9444 // Record the currently selected directory for later use
9445 wxFileName fn(sel_file);
9446 wxString data_dir = fn.GetPath();
9447 g_TCData_Dir = g_Platform->NormalizePath(data_dir);
9448 }
9449}
9450
9451void options::OnRemoveTideDataLocation(wxCommandEvent& event) {
9452 long item = -1;
9453 for (;;) {
9454 item = tcDataSelected->GetNextItem(item, wxLIST_NEXT_ALL,
9455 wxLIST_STATE_SELECTED);
9456 if (item == -1) break;
9457 tcDataSelected->DeleteItem(item);
9458 item = -1; // Restart
9459 }
9460}
9461
9462// OpenGLOptionsDlg
9463enum { ID_BUTTON_REBUILD, ID_BUTTON_CLEAR };
9464
9465#ifdef ocpnUSE_GL
9466BEGIN_EVENT_TABLE(OpenGLOptionsDlg, wxDialog)
9467EVT_BUTTON(ID_BUTTON_REBUILD, OpenGLOptionsDlg::OnButtonRebuild)
9468EVT_BUTTON(ID_BUTTON_CLEAR, OpenGLOptionsDlg::OnButtonClear)
9469END_EVENT_TABLE()
9470
9471OpenGLOptionsDlg::OpenGLOptionsDlg(wxWindow* parent)
9472 : wxDialog(parent, wxID_ANY, "OpenGL Options", wxDefaultPosition,
9473 wxDefaultSize,
9474 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER
9475#ifdef __WXOSX__
9476 | wxSTAY_ON_TOP
9477#endif
9478 ),
9479 m_brebuild_cache(FALSE) {
9480
9481 wxFont* dialogFont = GetOCPNScaledFont(_("Dialog"));
9482 SetFont(*dialogFont);
9483
9484 wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
9485 wxFlexGridSizer* flexSizer = new wxFlexGridSizer(2);
9486
9487 m_cbTextureCompression =
9488 new wxCheckBox(this, wxID_ANY,
9489 g_bGLexpert ? _("Texture Compression")
9490 : _("Texture Compression with Caching"));
9491 m_cbTextureCompressionCaching =
9492 new wxCheckBox(this, wxID_ANY, _("Texture Compression Caching"));
9493 m_memorySize =
9494 new wxStaticText(this, wxID_ANY, _("Texture Memory Size (MB)"));
9495 m_sTextureMemorySize = new wxSpinCtrl(this);
9496 m_sTextureMemorySize->SetRange(1, 16384);
9497 m_cacheSize =
9498 new wxStaticText(this, wxID_ANY, _("Size: ") + GetTextureCacheSize());
9499 wxButton* btnRebuild =
9500 new wxButton(this, ID_BUTTON_REBUILD, _("Rebuild Texture Cache"));
9501 wxButton* btnClear =
9502 new wxButton(this, ID_BUTTON_CLEAR, _("Clear Texture Cache"));
9503 btnRebuild->Enable(g_GLOptions.m_bTextureCompressionCaching);
9504 if (!g_bopengl || g_raster_format == GL_RGB) btnRebuild->Disable();
9505 btnClear->Enable(g_GLOptions.m_bTextureCompressionCaching);
9506 m_cbPolygonSmoothing = new wxCheckBox(this, wxID_ANY, _("Polygon Smoothing"));
9507 m_cbLineSmoothing = new wxCheckBox(this, wxID_ANY, _("Line Smoothing"));
9508 m_cbSoftwareGL =
9509 new wxCheckBox(this, wxID_ANY, _("Software OpenGL (restart OpenCPN)"));
9510 m_cbUseAcceleratedPanning =
9511 new wxCheckBox(this, wxID_ANY, _("Use Accelerated Panning"));
9512
9513 flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Texture Settings")), 0,
9514 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9515 flexSizer->Add(m_cbTextureCompression, 0, wxALL | wxEXPAND, 5);
9516 flexSizer->AddSpacer(0);
9517 flexSizer->Add(m_cbTextureCompressionCaching, 0, wxALL | wxEXPAND, 5);
9518 flexSizer->Add(m_memorySize, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9519 flexSizer->Add(m_sTextureMemorySize, 0, wxALL | wxEXPAND, 5);
9520 flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Texture Cache")), 0,
9521 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9522 flexSizer->Add(m_cacheSize, 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, 5);
9523 flexSizer->AddSpacer(0);
9524 flexSizer->Add(btnRebuild, 0, wxALL | wxEXPAND, 5);
9525 flexSizer->AddSpacer(0);
9526 flexSizer->Add(btnClear, 0, wxALL | wxEXPAND, 5);
9527 flexSizer->Add(new wxStaticText(this, wxID_ANY, _("Miscellaneous")), 0,
9528 wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
9529 flexSizer->Add(m_cbPolygonSmoothing, 0, wxALL | wxEXPAND, 5);
9530 flexSizer->AddSpacer(0);
9531 flexSizer->Add(m_cbLineSmoothing, 0, wxALL | wxEXPAND, 5);
9532 flexSizer->AddSpacer(0);
9533 flexSizer->AddSpacer(0);
9534 flexSizer->Add(m_cbSoftwareGL, 0, wxALL | wxEXPAND, 5);
9535 flexSizer->AddSpacer(0);
9536 flexSizer->Add(m_cbUseAcceleratedPanning, 0, wxALL | wxEXPAND, 5);
9537 flexSizer->AddGrowableCol(1);
9538 mainSizer->Add(flexSizer, 0, wxALL | wxEXPAND, 5);
9539
9540 wxStdDialogButtonSizer* btnSizer = new wxStdDialogButtonSizer();
9541 btnSizer->AddButton(new wxButton(this, wxID_OK));
9542 btnSizer->AddButton(new wxButton(this, wxID_CANCEL, _("Cancel")));
9543 btnSizer->Realize();
9544
9545 mainSizer->AddStretchSpacer();
9546 mainSizer->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
9547
9548 Populate();
9549
9550 SetSizer(mainSizer);
9551 mainSizer->SetSizeHints(this);
9552 Centre();
9553}
9554
9555bool OpenGLOptionsDlg::GetAcceleratedPanning() const {
9556 return m_cbUseAcceleratedPanning->GetValue();
9557}
9558
9559bool OpenGLOptionsDlg::GetTextureCompression() const {
9560 return m_cbTextureCompression->GetValue();
9561}
9562
9563bool OpenGLOptionsDlg::GetPolygonSmoothing() const {
9564 return m_cbPolygonSmoothing->GetValue();
9565}
9566
9567bool OpenGLOptionsDlg::GetLineSmoothing() const {
9568 return m_cbLineSmoothing->GetValue();
9569}
9570
9571bool OpenGLOptionsDlg::GetSoftwareGL() const {
9572 return m_cbSoftwareGL->GetValue();
9573}
9574
9575bool OpenGLOptionsDlg::GetTextureCompressionCaching() const {
9576 return m_cbTextureCompressionCaching->GetValue();
9577}
9578
9579bool OpenGLOptionsDlg::GetRebuildCache() const { return m_brebuild_cache; }
9580
9581int OpenGLOptionsDlg::GetTextureMemorySize() const {
9582 return m_sTextureMemorySize->GetValue();
9583}
9584
9585void OpenGLOptionsDlg::Populate() {
9586 m_cbTextureCompression->SetValue(g_GLOptions.m_bTextureCompression);
9587 /* disable caching if unsupported */
9588 // if (b_glEntryPointsSet && !s_glCompressedTexImage2D) {
9589 // g_GLOptions.m_bTextureCompressionCaching = FALSE;
9590 // m_cbTextureCompression->Disable();
9591 // m_cbTextureCompression->SetValue(FALSE);
9592 // }
9593
9594 m_cbTextureCompressionCaching->Show(g_bGLexpert);
9595 m_memorySize->Show(g_bGLexpert);
9596 m_sTextureMemorySize->Show(g_bGLexpert);
9597 if (g_bGLexpert) {
9598 m_cbTextureCompressionCaching->SetValue(
9599 g_GLOptions.m_bTextureCompressionCaching);
9600 m_sTextureMemorySize->SetValue(g_GLOptions.m_iTextureMemorySize);
9601 }
9602 m_cbPolygonSmoothing->SetValue(g_GLOptions.m_GLPolygonSmoothing);
9603 m_cbLineSmoothing->SetValue(g_GLOptions.m_GLLineSmoothing);
9604
9605#if defined(__UNIX__) && !defined(__ANDROID__) && !defined(__WXOSX__)
9606 if (top_frame::Get()->GetWxGlCanvas()) {
9607 if (top_frame::Get()->GetGlVersionString().Upper().Find("MESA") !=
9608 wxNOT_FOUND)
9609 m_cbSoftwareGL->SetValue(g_bSoftwareGL);
9610 }
9611#else
9612 m_cbSoftwareGL->Hide();
9613#endif
9614
9615 wxFont* dialogFont = GetOCPNScaledFont(_("Dialog"));
9616 SetFont(*dialogFont);
9617
9618 if (g_bGLexpert) {
9619 if (top_frame::Get()->GetWxGlCanvas()) {
9620 if (top_frame::Get()
9621 ->GetAbstractPrimaryCanvas()
9622 ->CanAccelerateGlPanning()) {
9623 m_cbUseAcceleratedPanning->Enable();
9624 m_cbUseAcceleratedPanning->SetValue(
9625 g_GLOptions.m_bUseAcceleratedPanning);
9626 } else {
9627 m_cbUseAcceleratedPanning->SetValue(FALSE);
9628 m_cbUseAcceleratedPanning->Disable();
9629 }
9630 } else {
9631 m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
9632 }
9633 } else {
9634 m_cbUseAcceleratedPanning->SetValue(g_GLOptions.m_bUseAcceleratedPanning);
9635 m_cbUseAcceleratedPanning->Disable();
9636 }
9637}
9638
9639void OpenGLOptionsDlg::OnButtonRebuild(wxCommandEvent& event) {
9640 if (g_GLOptions.m_bTextureCompressionCaching) {
9641 m_brebuild_cache = TRUE;
9642 EndModal(wxID_CANCEL);
9643 }
9644}
9645
9646void OpenGLOptionsDlg::OnButtonClear(wxCommandEvent& event) {
9647 if (g_bopengl && g_glTextureManager) {
9648 ::wxBeginBusyCursor();
9649 g_glTextureManager->ClearAllRasterTextures();
9650
9651 wxString path = g_Platform->GetPrivateDataDir();
9652 appendOSDirSlash(&path);
9653 path.append("raster_texture_cache");
9654
9655 if (::wxDirExists(path)) {
9656 wxArrayString files;
9657 size_t nfiles = wxDir::GetAllFiles(path, &files);
9658 for (unsigned int i = 0; i < files.GetCount(); i++)
9659 ::wxRemoveFile(files[i]);
9660 }
9661
9662 m_cacheSize->SetLabel(_("Size: ") + GetTextureCacheSize());
9663 ::wxEndBusyCursor();
9664 }
9665}
9666
9667wxString OpenGLOptionsDlg::GetTextureCacheSize() {
9668 wxString path = g_Platform->GetPrivateDataDir();
9669 appendOSDirSlash(&path);
9670 path.append("raster_texture_cache");
9671 long long total = 0;
9672
9673 if (::wxDirExists(path)) {
9674 wxArrayString files;
9675 size_t nfiles = wxDir::GetAllFiles(path, &files);
9676 for (unsigned int i = 0; i < files.GetCount(); i++)
9677 total += wxFile(files[i]).Length();
9678 }
9679 double mb = total / (1024.0 * 1024.0);
9680 if (mb < 10000.0) return wxString::Format("%.1f MB", mb);
9681 mb = mb / 1024.0;
9682 return wxString::Format("%.1f GB", mb);
9683}
9684#endif
9685//-------------------------------------------------------------------------------------------------
9686// CanvasConfig selection panel
9687//-------------------------------------------------------------------------------------------------
9688
9689BEGIN_EVENT_TABLE(CanvasConfigSelect, wxPanel)
9690EVT_PAINT(CanvasConfigSelect::OnPaint)
9691END_EVENT_TABLE()
9692
9693CanvasConfigSelect::CanvasConfigSelect(wxWindow* parent, options* parentOptions,
9694 wxWindowID id, wxBitmap& bmp,
9695 const wxPoint& pos, const wxSize& size)
9696 : wxPanel(parent, id, pos, size, wxBORDER_NONE) {
9697 m_parentOptions = parentOptions;
9698 m_bmpNormal = bmp;
9699 m_borderWidth = 5;
9700 SetSelected(false);
9701
9702 int refHeight = GetCharHeight();
9703 // SetMinSize(wxSize(-1, 5 * refHeight));
9704 SetMinSize(wxSize(bmp.GetSize().x + m_borderWidth * 2,
9705 bmp.GetSize().y + m_borderWidth * 2));
9706
9707 Connect(wxEVT_LEFT_DOWN,
9708 wxMouseEventHandler(CanvasConfigSelect::OnMouseSelected), NULL, this);
9709}
9710
9711CanvasConfigSelect::~CanvasConfigSelect() {}
9712
9713void CanvasConfigSelect::OnMouseSelected(wxMouseEvent& event) {
9714 if (!m_bSelected) {
9715 SetSelected(true);
9716 } else {
9717 SetSelected(false);
9718 }
9719 if (m_parentOptions)
9720 m_parentOptions->OnCanvasConfigSelectClick(GetId(), GetSelected());
9721}
9722
9723void CanvasConfigSelect::SetSelected(bool selected) {
9724 m_bSelected = selected;
9725
9726 if (selected) {
9727 m_boxColour =
9728 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT);
9729 } else {
9730 m_boxColour =
9731 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_WINDOW);
9732 }
9733
9734 Refresh(true);
9735}
9736
9737void CanvasConfigSelect::OnPaint(wxPaintEvent& event) {
9738 int width, height;
9739 GetSize(&width, &height);
9740 wxPaintDC dc(this);
9741
9742 dc.SetBackground(*wxLIGHT_GREY);
9743
9744 dc.SetPen(*wxTRANSPARENT_PEN);
9745 dc.SetBrush(wxBrush(GetBackgroundColour()));
9746 dc.DrawRectangle(GetVirtualSize());
9747
9748 if (m_bSelected) {
9749 dc.SetBrush(wxBrush(m_boxColour));
9750 dc.SetPen(wxPen(
9751 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT),
9752 3));
9753 dc.DrawRoundedRectangle(0, 0, width - 1, height - 1, height / 10);
9754 } else {
9755 dc.SetBrush(wxBrush(m_boxColour));
9756 dc.SetPen(wxPen(
9757 wxSystemSettings::GetColour(wxSystemColour::wxSYS_COLOUR_HIGHLIGHT),
9758 3));
9759 dc.DrawRoundedRectangle(0, 0, width - 1, height - 1, height / 10);
9760 }
9761
9762 dc.DrawBitmap(m_bmpNormal, m_borderWidth, m_borderWidth, false);
9763}
ArrayOfMmsiProperties g_MMSI_Props_Array
Global instance.
unsigned g_OwnShipmmsi
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
AIS target definitions.
Wrapper for creating a ChartCtx based on global vars.
ChartDB * ChartData
Global instance.
Definition chartdb.cpp:71
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:61
Basic chart info storage.
arrayofCanvasPtr g_canvasArray
Global instance.
Definition chcanv.cpp:173
Generic Chart canvas base.
double GetDisplayDIPMult(wxWindow *win)
Get the display scaling factor for DPI-aware rendering.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:173
Represents an individual component within a ChartGroup.
Definition chartdbs.h:465
Represents a user-defined collection of logically related charts.
Definition chartdbs.h:485
Represents a panel for displaying and editing a configuration.
Definition config_mgr.h:92
Generic event handling between MVC Model and Controller based on a shared EventVar variable.
void Notify() override
Notify all listeners, no data supplied.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
Definition font_mgr.cpp:110
bool SetFont(const wxString &TextElement, wxFont *pFont, wxColour color)
Sets the default font properties for a UI element.
Definition font_mgr.cpp:302
wxArrayString GetDialogStrings(const wxString &locale=wxEmptyString) const
Gets the list of unique dialog strings.
Definition font_mgr.cpp:336
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Definition font_mgr.cpp:193
Wrapper for global variable, supports notification events when value changes.
Process incoming AIS messages.
Definition ais_decoder.h:74
static double ui_to_config(int slider_pos)
Convert a slider scale 1-100 value to configuration value 1.02..3.0.
Definition navutil.h:156
Custom combobox for selecting waypoint icons.
Definition mark_info.h:149
wxSize getDisplaySize()
Get the display size in logical pixels.
double GetDisplaySizeMM()
Get the width of the screen in millimeters.
EventVar m_on_sp_sound_done
Notified with a OCPN_Sound* pointer when sound has completed.
Definition options.cpp: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:443
EventVar m_on_sound_done
Notified with a OCPN_Sound* pointer when sound has completed.
Definition options.h:639
wxRadioButton * pTimezoneLocalTime
Specify date/time should be formatted in timezone as configured in the operating system.
Definition options.h:441
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
Communication drivers factory and support.
Misc driver utilities.
Config file user configuration interface.
wxString g_datetime_format
Date/time format to use when formatting date/time strings.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
int g_iTempFormat
User-selected temperature unit format for display and input.
int g_nDepthUnitDisplay
User-selected depth (below surface) unit format for display and input.
bool g_bRollover
enable/disable mouse rollover GUI effects
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iSpeedFormat
User-selected speed unit format for display and input.
int g_iHeightFormat
User-selected height (vertical, above reference datum) unit format for display and input.
std::vector< size_t > g_config_display_size_mm
Size of pysical screen in millimeters.
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
bool g_bDisplayGrid
Should lat/lon grid be displayed ?
Global variables stored in configuration file.
Panel for editing a connection.
Options | Connections GUI tab managing connections
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
Definition displays.cpp:45
Display utilities.
Font list manager.
GLuint g_raster_format
Global instance.
OpenGL chart rendering canvas.
Platform independent GL includes.
glTextureManager * g_glTextureManager
Global instance.
Misc GUI event vars, a singleton.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:61
size_t g_current_monitor
Current monitor displaying main application frame.
Definition gui_vars.cpp:75
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
GUI constant definitions.
Waypoint properties maintenance dialog.
Multiplexer class and helpers.
MyConfig * pConfig
Global instance.
Definition navutil.cpp:118
Utility functions.
Navigation Utility Functions without GUI dependencies.
A common variable shared between producer and consumer which supports Listen() and Notify().
Global variables Listen()/Notify() wrapper.
Generic font dialog for OpenCPN.
OpenCPN Platform specific support utilities.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
wxString * GetpSharedDataLocation()
Gets shared application data location.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
ArrayOfMmsiProperties g_MMSI_Props_Array
Global instance.
options * g_options
Global instance.
Definition options.cpp:183
Options dialog.
double gVar
Magnetic variation in degrees.
Definition own_ship.cpp:32
Position, course, speed, etc.
PlugInManager * g_pi_manager
Global instance.
wxColour g_colourWaypointRangeRingsColour
Global instance.
float g_ChartScaleFactorExp
Global instance.
Definition routeman.cpp:68
Route Manager.
Serial ports support, notably enumeration.
wxArrayString * EnumerateSerialPorts(void)
Enumerate all serial ports.
Chart Symbols.
wxBitmap LoadSVG(const wxString filename, const unsigned int width, const unsigned int height, wxBitmap *default_bitmap, bool use_cache)
Load SVG file and return it's bitmap representation of requested size In case file can't be loaded an...
Definition svg_utils.cpp:59
SVG utilities.
Abstract gFrame/MyFrame interface.
Access checks for comm devices and dongle.
Low-level USB device management.
WaypointMan drawing stuff.