OpenCPN Partial API docs
Loading...
Searching...
No Matches
ocpn_frame.cpp
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, see <https://www.gnu.org/licenses/ *
16 **************************************************************************/
17
18/*
19 * \file
20 *
21 * OpenCPN top window
22 */
23#include "config.h"
24#include "gl_headers.h" // Must be included before anything using GL stuff
25
26#ifdef __MINGW32__
27#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
28#include <windows.h>
29#endif
30
31#include <wx/wxprec.h>
32
33#ifndef WX_PRECOMP
34#include <wx/wx.h>
35#endif // precompiled headers
36
37#ifdef __WXMSW__
38// #include "c:\\Program Files\\visual leak detector\\include\\vld.h"
39#endif
40
41#ifdef __WXMSW__
42#include <math.h>
43#include <psapi.h>
44#include <stdlib.h>
45#include <time.h>
46#endif
47
48#ifdef OCPN_HAVE_X11
49#include <X11/Xatom.h>
50#include <X11/Xlib.h>
51#endif
52
53#include <wx/stdpaths.h>
54#include <wx/tokenzr.h>
55#include <wx/display.h>
56#include <wx/jsonreader.h>
57
58#include "o_sound/o_sound.h"
59
60#include "model/ais_decoder.h"
64#include "model/cmdline.h"
65#include "model/comm_bridge.h"
66#include "model/comm_drv_factory.h" //FIXME(dave) this one goes away
70#include "model/comm_vars.h"
71#include "model/config_vars.h"
72#include "model/cutil.h"
73#include "model/georef.h"
74#include "model/gui.h"
75#include "model/gui_vars.h"
76#include "model/gui_events.h"
77#include "model/gui_vars.h"
78#include "model/idents.h"
79#include "model/local_api.h"
80#include "model/logger.h"
81#include "model/multiplexer.h"
82#include "model/navobj_db.h"
83#include "model/nav_object_database.h"
84#include "model/navutil_base.h"
86#include "model/own_ship.h"
87#include "model/ocpn_utils.h"
88#include "model/plugin_comm.h"
89#include "model/plugin_loader.h"
90#include "model/routeman.h"
91#include "model/select.h"
92#include "model/std_icon.h"
93#include "model/sys_events.h"
94#include "model/track.h"
96
97#include "ais_info_gui.h"
98#include "dialog_alert.h"
99#include "about_frame_impl.h"
100#include "about.h"
101#include "ais.h"
102#include "ais_info_gui.h"
103#include "ais_target_alert_dlg.h"
104#include "ais_target_list_dlg.h"
105#include "ais_target_query_dlg.h"
106#include "canvas_config.h"
107#include "chartbase.h"
108#include "chart_ctx_factory.h"
109#include "chartdb.h"
110#include "chcanv.h"
111#include "tc_win.h"
112#include "cm93.h"
113#include "color_handler.h"
114#include "compass.h"
115#include "concanv.h"
116#include "connections_dlg.h"
117#include "config_mgr.h"
118#include "data_monitor.h"
119#include "dychart.h"
120#include "font_mgr.h"
121#include "gl_chart_canvas.h"
122#include "go_to_position_dlg.h"
123#include "gui_lib.h"
124#include "ienc_toolbar.h"
125#include "layer.h"
126#include "load_errors_dlg.h"
127#include "mark_info.h"
128#include "mui_bar.h"
129#include "N2KParser.h"
130#include "navutil.h"
131#include "ocpn_aui_manager.h"
132#include "ocpn_frame.h"
133#include "ocpn_platform.h"
134#include "ocpn_plugin.h"
135#include "o_senc.h"
136#include "options.h"
137#include "pluginmanager.h"
138#include "print_dialog.h"
139#include "printout_chart.h"
140#include "routemanagerdialog.h"
141#include "routeman_gui.h"
142#include "route_point_gui.h"
143#include "route_prop_dlg_impl.h"
144#include "s52plib.h"
145#include "s57chart.h"
146#include "s57_load.h"
147#include "s57_query_dlg.h"
148#include "tcmgr.h"
149#include "timers.h"
150#include "toolbar.h"
151#include "track_prop_dlg.h"
152#include "user_colors.h"
153#include "waypointman_gui.h"
154#include "canvas_options.h"
155#include "udev_rule_mgr.h"
156
157#ifdef __ANDROID__
158#include "androidUTIL.h"
159#endif
160
161// For Windows and GTK, provide the expected application Minimize/Close bar
162static constexpr long kFrameStyle = wxDEFAULT_FRAME_STYLE | wxWANTS_CHARS;
163
164//------------------------------------------------------------------------------
165// Static variable definition
166//------------------------------------------------------------------------------
167//
168
169extern options *g_pOptions; // FIXME (leamas) same as g_options, merge
170MyFrame *gFrame;
171
172#ifdef ocpnUSE_GL
173GLenum g_texture_rectangle_format;
174#endif
175
176#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
177extern wxLocale *plocale_def_lang;
178#endif
179
180#ifdef ocpnUSE_GL
181extern bool g_b_EnableVBO;
182extern GLenum g_texture_rectangle_format;
183extern OCPN_GLCaps *GL_Caps;
184#endif
185
186static int g_last_ChartScaleFactor;
187static char nmea_tick_chars[] = {'|', '/', '-', '\\', '|', '/', '-', '\\'};
188static int options_subpage = 0;
189static bool b_reloadForPlugins;
190
191static wxSize options_lastWindowSize(0, 0);
192static wxPoint options_lastWindowPos(0, 0);
193
194// Values returned from WMM_PI for variation computation request.
195// Initialize to invalid so we don't use it if WMM hasn't updated yet
196static double gQueryVar = 361.0;
197
198static char bells_sound_file_name[2][12] = {"1bells.wav", "2bells.wav"};
199static o_sound::Sound *_bells_sounds[] = {o_sound::Factory(),
200 o_sound::Factory()};
201static std::vector<o_sound::Sound *> bells_sound(_bells_sounds,
202 _bells_sounds + 2);
203
204#ifdef __WXMSW__
205// System color control support
206
207typedef DWORD(WINAPI *SetSysColors_t)(DWORD, DWORD *, DWORD *);
208typedef DWORD(WINAPI *GetSysColor_t)(DWORD);
209
210static SetSysColors_t pSetSysColors;
211static GetSysColor_t pGetSysColor;
212
213void SaveSystemColors();
214void RestoreSystemColors();
215
216DWORD color_3dface;
217DWORD color_3dhilite;
218DWORD color_3dshadow;
219DWORD color_3ddkshadow;
220DWORD color_3dlight;
221DWORD color_activecaption;
222DWORD color_gradientactivecaption;
223DWORD color_captiontext;
224DWORD color_windowframe;
225DWORD color_inactiveborder;
226
227#endif
228
229#ifdef __VISUALC__
230#include <wx/msw/msvcrt.h>
231#endif
232
233#if !defined(NAN)
234static const long long lNaN = 0xfff8000000000000;
235#define NAN (*(double *)&lNaN)
236#endif
237
238// Latest "ground truth" fix, and auxiliaries
239static double gLat_gt, gLon_gt;
240static double gLat_gt_m1, gLon_gt_m1;
241static uint64_t fix_time_gt;
242static uint64_t fix_time_gt_last;
243
244static double gSog_gt, gHdt_gt;
245static double gCog_gt_m1, gHdt_gt_m1;
246static uint64_t hdt_time_gt;
247static double cog_rate_gt, hdt_rate_gt;
248
249void InitializeUserColors();
250void DeInitializeUserColors();
251void SetSystemColors(ColorScheme cs);
252
253static bool LoadAllPlugIns(bool load_enabled) {
254 AbstractPlatform::ShowBusySpinner();
255 bool b = PluginLoader::GetInstance()->LoadAllPlugIns(load_enabled);
256 AbstractPlatform::HideBusySpinner();
257 return b;
258}
259
260static void LaunchLocalHelp() {
261#ifdef __ANDROID__
262 androidLaunchHelpView();
263#else
264 wxString def_lang_canonical = "en_US";
265
266#if wxUSE_XLOCALE
267 if (plocale_def_lang)
268 def_lang_canonical = plocale_def_lang->GetCanonicalName();
269#endif
270
271 wxString help_locn = g_Platform->GetSharedDataDir() + "doc/help_";
272
273 wxString help_try = help_locn + def_lang_canonical + ".html";
274
275 if (!::wxFileExists(help_try)) {
276 help_try = help_locn + "en_US" + ".html";
277
278 if (!::wxFileExists(help_try)) {
279 help_try = help_locn + "web" + ".html";
280 }
281
282 if (!::wxFileExists(help_try)) return;
283 }
284
285 wxLaunchDefaultBrowser(wxString("file:///") + help_try);
286#endif
287}
288
289// Helper to create menu label + hotkey string when registering menus
290static wxString _menuText(wxString name, wxString shortcut) {
291 wxString menutext;
292 menutext << name;
293#ifndef __ANDROID__
294 menutext << "\t" << shortcut;
295#endif
296 return menutext;
297}
298
299static void DoHelpDialog() {
300#ifndef __ANDROID__
301 if (!g_pAboutDlg) {
302 g_pAboutDlg = new AboutFrameImpl(gFrame);
303 } else {
304 g_pAboutDlg->SetFocus();
305 }
306 g_pAboutDlg->Show();
307
308#else
310 g_pAboutDlgLegacy = new About(gFrame, g_Platform->GetSharedDataDir(),
311 [] { LaunchLocalHelp(); });
312 else
313 g_pAboutDlgLegacy->SetFocus();
314 g_pAboutDlgLegacy->Show();
315
316#endif
317}
318
319//------------------------------------------------------------------------------
320// PNG Icon resources
321//------------------------------------------------------------------------------
322
323#if defined(__WXGTK__) || defined(__WXQT__)
324#include "bitmaps/opencpn.xpm"
325#endif
326
327//------------------------------------------------------------------------------
328// Local constants
329//------------------------------------------------------------------------------
330// enum {
331// ID_PIANO_DISABLE_QUILT_CHART = 32000, ID_PIANO_ENABLE_QUILT_CHART
332// };
333
334//------------------------------------------------------------------------------
335// Fwd Refs
336//------------------------------------------------------------------------------
337
338void BuildiENCToolbar(bool bnew, ToolbarDlgCallbacks callbacks) {
339 if (g_bInlandEcdis) {
340 if (bnew) {
341 if (g_iENCToolbar) {
342 wxPoint locn = g_iENCToolbar->GetToolbarPosition();
343 wxPoint tbp_incanvas =
344 locn; // gFrame->GetPrimaryCanvas()->ScreenToClient(locn);
345
346 g_iENCToolbarPosY = tbp_incanvas.y;
347 g_iENCToolbarPosX = tbp_incanvas.x;
348
349 delete g_iENCToolbar;
350 g_iENCToolbar = 0;
351 }
352 }
353
354 if (!g_iENCToolbar) {
355 wxPoint posn(g_iENCToolbarPosX, g_iENCToolbarPosY);
356
357 // Overlapping main toolbar?
358 if (g_MainToolbar) {
359 if ((g_iENCToolbarPosY > g_maintoolbar_y) &&
360 (g_iENCToolbarPosY <
361 g_maintoolbar_y + g_MainToolbar->GetToolSize().y))
362 g_iENCToolbarPosY = -1; // force a reposition
363 }
364
365 if ((g_iENCToolbarPosX < 0) || (g_iENCToolbarPosY < 0)) {
366 posn.x = 0;
367 posn.y = 100;
368
369 if (g_MainToolbar)
370 posn =
371 wxPoint(g_maintoolbar_x + g_MainToolbar->GetToolbarSize().x + 4,
372 g_maintoolbar_y);
373 }
374
375 double tool_scale_factor =
376 g_Platform->GetToolbarScaleFactor(g_GUIScaleFactor);
377 g_iENCToolbar = new iENCToolbar(gFrame, posn, wxTB_HORIZONTAL,
378 tool_scale_factor, callbacks);
379 g_iENCToolbar->SetColorScheme(global_color_scheme);
380 g_iENCToolbar->EnableSubmerge(false);
381 }
382 } else {
383 delete g_iENCToolbar;
384 g_iENCToolbar = NULL;
385 }
386}
387
388#if defined(__WXGTK__) && defined(OCPN_HAVE_X11)
389
390// Note: use XFree to free this pointer. Use unique_ptr in the future.
391static char *get_X11_property(Display *disp, Window win, Atom xa_prop_type,
392 const char *prop_name) {
393 Atom xa_prop_name;
394 Atom xa_ret_type;
395 int ret_format;
396 unsigned long ret_nitems;
397 unsigned long ret_bytes_after;
398 unsigned char *ret_prop;
399
400 xa_prop_name = XInternAtom(disp, prop_name, False);
401
402 // For XGetWindowProperty source see
403 // https://github.com/mirror/libX11/blob/master/src/GetProp.c#L107
404 // it is quite tricky. Some notes.
405 // + Results are already NULL terminated.
406 // + 32 as a ret_format means sizeof(long) in the API...
407 // + but as xlib does the null termination we can just ignore the sizes.
408 if (XGetWindowProperty(disp, win, xa_prop_name, 0, 1024, False, xa_prop_type,
409 &xa_ret_type, &ret_format, &ret_nitems,
410 &ret_bytes_after, &ret_prop) != Success)
411 return NULL;
412
413 if (xa_ret_type != xa_prop_type) {
414 XFree(ret_prop);
415 return NULL;
416 }
417 return (char *)ret_prop;
418}
419#endif
420
421// Determine if a transparent toolbar is possible under linux with opengl
422static bool isTransparentToolbarInOpenGLOK() {
423#ifdef __WXOSX__
424 return true;
425#else
426 bool status = false;
427#ifndef __WXQT__
428#ifdef OCPN_HAVE_X11
429 if (!g_bdisable_opengl) {
430 Display *disp = XOpenDisplay(NULL);
431 Window *sup_window;
432 if ((sup_window = (Window *)get_X11_property(disp, DefaultRootWindow(disp),
433 XA_WINDOW,
434 "_NET_SUPPORTING_WM_CHECK")) ||
435 (sup_window = (Window *)get_X11_property(disp, DefaultRootWindow(disp),
436 XA_CARDINAL,
437 "_WIN_SUPPORTING_WM_CHECK"))) {
438 /* WM_NAME */
439 char *wm_name;
440 if ((wm_name = get_X11_property(disp, *sup_window,
441 XInternAtom(disp, "UTF8_STRING", False),
442 "_NET_WM_NAME")) ||
443 (wm_name = get_X11_property(disp, *sup_window, XA_STRING,
444 "_NET_WM_NAME"))) {
445 // we know it works in xfce4, add other checks as we can validate them
446 if (strstr(wm_name, "Xfwm4") || strstr(wm_name, "Compiz"))
447 status = true;
448
449 XFree(wm_name);
450 }
451 XFree(sup_window);
452 }
453 XCloseDisplay(disp);
454 }
455#endif
456#endif
457 return status;
458#endif
459}
460
461wxFont *MyFrame::GetFont(wxFont *font, double scale) {
462 return FindOrCreateFont_PlugIn(font->GetPointSize() / scale,
463 font->GetFamily(), font->GetStyle(),
464 font->GetWeight(), false, font->GetFaceName());
465}
466
467//------------------------------------------------------------------------------
468// MyFrame
469//------------------------------------------------------------------------------
470
471// Frame implementation
472// NOLINTBEGIN
473wxDEFINE_EVENT(BELLS_PLAYED_EVTYPE, wxCommandEvent);
474
475BEGIN_EVENT_TABLE(MyFrame, wxFrame)
476EVT_CLOSE(MyFrame::OnCloseWindow)
477EVT_MENU(wxID_EXIT, MyFrame::OnExit)
478EVT_SIZE(MyFrame::OnSize)
479EVT_MOVE(MyFrame::OnMove)
480EVT_ICONIZE(MyFrame::OnIconize)
481EVT_MENU(-1, MyFrame::OnToolLeftClick)
482EVT_TIMER(INIT_TIMER, MyFrame::OnInitTimer)
483EVT_TIMER(FRAME_TIMER_1, MyFrame::OnFrameTimer1)
484EVT_TIMER(FRAME_TC_TIMER, MyFrame::OnFrameTCTimer)
485EVT_TIMER(FRAME_COG_TIMER, MyFrame::OnFrameCOGTimer)
486EVT_TIMER(MEMORY_FOOTPRINT_TIMER, MyFrame::OnMemFootTimer)
487EVT_TIMER(FRANE_TENHZ_TIMER, MyFrame::OnFrameTenHzTimer)
488EVT_MAXIMIZE(MyFrame::OnMaximize)
489EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_TOOL_RCLICKED,
490 MyFrame::RequestNewToolbarArgEvent)
491EVT_ERASE_BACKGROUND(MyFrame::OnEraseBackground)
492// EVT_TIMER(RESIZE_TIMER, MyFrame::OnResizeTimer)
493EVT_TIMER(RECAPTURE_TIMER, MyFrame::OnRecaptureTimer)
494EVT_TIMER(TOOLBAR_ANIMATE_TIMER, MyFrame::OnToolbarAnimateTimer)
495EVT_COMMAND(wxID_ANY, BELLS_PLAYED_EVTYPE, MyFrame::OnBellsFinished)
496
497#ifdef wxHAS_POWER_EVENTS
498EVT_POWER_SUSPENDING(MyFrame::OnSuspending)
499EVT_POWER_SUSPENDED(MyFrame::OnSuspended)
500EVT_POWER_SUSPEND_CANCEL(MyFrame::OnSuspendCancel)
501EVT_POWER_RESUME(MyFrame::OnResume)
502#endif // wxHAS_POWER_EVENTS
503
504END_EVENT_TABLE()
505
506// NOLINTEND
507
508/*
509 * Direct callback from completed sound, possibly in an interrupt
510 * context. Just post an event to be processed in main thread.
511 */
512static void onBellsFinishedCB(void *ptr) {
513 auto framePtr = static_cast<MyFrame *>(ptr);
514 if (framePtr) {
515 wxCommandEvent ev(BELLS_PLAYED_EVTYPE);
516 wxPostEvent(framePtr, ev);
517 }
518}
519
520static void OnDriverMsg(const ObservedEvt &ev) {
521 auto msg = ev.GetString().ToStdString();
522 auto &noteman = NotificationManager::GetInstance();
523 noteman.AddNotification(NotificationSeverity::kInformational, msg, 60);
524}
525
526static NmeaLog *GetDataMonitor() {
527 auto w = wxWindow::FindWindowByName(kDataMonitorWindowName);
528 return dynamic_cast<NmeaLog *>(w);
529}
530
531MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size,
532 RestServer &rest_server, wxAuiDefaultDockArt *pauidockart,
533 OpenFileFunc open_gpx_file)
534 : AbstractTopFrame(nullptr, title, pos, size, kFrameStyle),
535 m_connections_dlg(nullptr),
536 m_data_monitor(new DataMonitor(this)),
537 m_pauidockart(pauidockart),
538 m_rest_server(rest_server),
539 m_open_gpx_file(open_gpx_file) {
540 g_current_monitor = wxDisplay::GetFromWindow(this);
541#ifdef __WXOSX__
542 // On retina displays there is a difference between the physical size of the
543 // OpenGL canvas and the DIP This is not observed anywhere else so far, so
544 // g_current_monitor_dip_px_ratio cna be kept 1.0 everywhere else
545 if (g_bopengl) {
549 }
550#endif
551 m_ulLastNMEATicktime = 0;
552 m_data_monitor->Hide();
553 m_pStatusBar = NULL;
554 m_StatusBarFieldCount = g_Platform->GetStatusBarFieldCount();
555
556 m_pMenuBar = NULL;
557 g_options = NULL;
558 m_load_errors_dlg_ctrl = std::make_unique<LoadErrorsDlgCtrl>(this);
559
560 // Redirect the initialization timer to this frame
561 InitTimer.SetOwner(this, INIT_TIMER);
562 m_iInitCount = 0;
563 m_initializing = false;
564 m_toolbar_callbacks.render_gl_textures =
565#ifdef ocpnUSE_GL
566 [&](ocpnDC &dc, float *coords, float *uv) {
567 GetPrimaryCanvas()->GetglCanvas()->RenderTextures(
568 dc, coords, uv, 4, &GetPrimaryCanvas()->GetVP());
569 };
570#else
571 [&](ocpnDC &dc, float *coords, float *uv) {};
572#endif
573
574 // Redirect the global heartbeat timer to this frame
575 FrameTimer1.SetOwner(this, FRAME_TIMER_1);
576
577 // Redirect the Tide/Current update timer to this frame
578 FrameTCTimer.SetOwner(this, FRAME_TC_TIMER);
579
580 // Redirect the COG Averager timer to this frame
581 FrameCOGTimer.SetOwner(this, FRAME_COG_TIMER);
582
583 // Redirect the Memory Footprint Management timer to this frame
584 MemFootTimer.SetOwner(this, MEMORY_FOOTPRINT_TIMER);
585
586 // Direct the Toolbar Animation timer to this frame
587 ToolbarAnimateTimer.SetOwner(this, TOOLBAR_ANIMATE_TIMER);
588
589 FrameTenHzTimer.SetOwner(this, FRANE_TENHZ_TIMER);
590
591#ifdef __ANDROID__
592// m_PrefTimer.SetOwner( this, ANDROID_PREF_TIMER );
593// Connect( m_PrefTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(
594// MyFrame::OnPreferencesResultTimer ), NULL, this );
595#endif
596
597 // Set up some assorted member variables
598 m_bTimeIsSet = false;
599 m_bdefer_resize = false;
600
601 // Clear the NMEA Filter tables
602 for (int i = 0; i < kMaxCogsogFilterSeconds; i++) {
603 COGFilterTable[i] = NAN;
604 SOGFilterTable[i] = NAN;
605 }
606 m_last_bGPSValid = false;
607 m_last_bVelocityValid = false;
608
609 gHdt = NAN;
610 gHdm = NAN;
611 gVar = NAN;
612 gSog = NAN;
613 gCog = NAN;
614 gHdt_gt = NAN;
615 gCog_gt = NAN;
616
617 for (int i = 0; i < kMaxCogAverageSeconds; i++) COGTable[i] = NAN;
618
619 m_fixtime = -1;
620
621 double dt = 2.0; // Time interval
622 double process_noise_std = 1.0; // Process noise standard deviation
623 double measurement_noise_std = 0.5; // Measurement noise standard deviation
624
625 SetUtils(this);
626
627 m_ChartUpdatePeriod = 1; // set the default (1 sec.) period
628 initIXNetSystem();
629
630 // Establish my children
631 struct MuxLogCallbacks log_callbacks;
632 log_callbacks.log_is_active = [&]() {
633 auto log = GetDataMonitor();
634 return log && log->IsVisible();
635 };
636 log_callbacks.log_message = [&](Logline ll) {
637 NmeaLog *monitor = GetDataMonitor();
638 if (monitor && monitor->IsVisible()) monitor->Add(ll);
639 };
640 g_pMUX = new Multiplexer(log_callbacks, g_b_legacy_input_filter_behaviour);
641
642 struct AisDecoderCallbacks ais_callbacks;
643 ais_callbacks.confirm_stop_track = []() {
644 int r = OCPNMessageBox(
645 NULL,
646 _("This AIS target has Persistent tracking selected by MMSI "
647 "properties\n"
648 "A Persistent track recording will therefore be restarted for this "
649 "target.\n\n"
650 "Do you instead want to stop Persistent tracking for this target?"),
651 _("OpenCPN Info"), wxYES_NO | wxCENTER, 60);
652 return r == wxID_YES;
653 };
654 ais_callbacks.get_target_mmsi = []() {
655 auto alert_dlg_active =
656 dynamic_cast<AISTargetAlertDialog *>(g_pais_alert_dialog_active);
657 assert(alert_dlg_active);
658 return alert_dlg_active->Get_Dialog_MMSI();
659 };
660
661 g_pAIS = new AisDecoder(ais_callbacks);
662
663 g_pAISGUI = new AisInfoGui();
664
665 // Create/connect a dynamic event handler slot
666 wxLogMessage(" **** Connect stuff");
667
668 b_autofind = false;
669
670 // Create/connect a dynamic event handler slot for OCPN_MsgEvent(s) coming
671 // from PlugIn system
672 Connect(wxEVT_OCPN_MSG,
673 (wxObjectEventFunction)(wxEventFunction)&MyFrame::OnEvtPlugInMessage);
674
675 // FIXME (dave)
676 // Connect(wxEVT_OCPN_THREADMSG,
677 // (wxObjectEventFunction)(wxEventFunction)&MyFrame::OnEvtTHREADMSG);
678
679 // And from the thread SENC creator
681 (wxObjectEventFunction)(wxEventFunction)&MyFrame::OnSENCEvtThread);
682 // Establish the system icons for the frame.
683
684#ifdef __WXMSW__
685 SetIcon(wxICON(
686 0)); // this grabs the first icon in the integrated MSW resource file
687#endif
688
689#if defined(__WXGTK__) || defined(__WXQT__)
690 wxIcon app_icon(opencpn); // This comes from opencpn.xpm inclusion above
691 SetIcon(app_icon);
692#endif
693
694#ifdef __WXMSW__
695
696 // Establish the entry points in USER32.DLL for system color control
697
698 wxDynamicLibrary dllUser32("user32.dll");
699
700 pSetSysColors = (SetSysColors_t)dllUser32.GetSymbol("SetSysColors");
701 pGetSysColor = (GetSysColor_t)dllUser32.GetSymbol("GetSysColor");
702
703 SaveSystemColors();
704#endif
705
706 m_next_available_plugin_tool_id = ID_PLUGIN_BASE;
707
708 g_sticky_chart = -1;
709 m_BellsToPlay = 0;
710
711 m_resizeTimer.SetOwner(this, RESIZE_TIMER);
712 m_recaptureTimer.SetOwner(this, RECAPTURE_TIMER);
713 m_tick_idx = 0;
714 assert(g_pRouteMan != 0 && "g_pRouteMan not available");
715 m_routes_update_listener.Init(GuiEvents::GetInstance().on_routes_update,
716 [&](wxCommandEvent) { Refresh(); });
717 m_evt_drv_msg_listener.Init(CommDriverRegistry::GetInstance().evt_driver_msg,
718 [&](ObservedEvt &ev) { OnDriverMsg(ev); });
719 m_update_statusbar_listener.Init(
720 GuiEvents::GetInstance().gframe_update_status_bar,
721 [&](ObservedEvt &) { UpdateStatusBar(); });
722 m_center_aistarget_listener.Init(
723 GuiEvents::GetInstance().on_center_ais_target, [&](ObservedEvt &ev) {
724 auto ais_target = UnpackEvtPointer<AisTargetData>(ev);
725 CenterAisTarget(ais_target);
726 });
727 m_reload_charts_listener.Init(
728 GuiEvents::GetInstance().on_finalize_chartdbs,
729 [&](ObservedEvt &ev) { FinalizeChartDBUpdate(); });
730
731#ifdef __WXOSX__
732 // Enable native fullscreen on macOS
733 EnableFullScreenView();
734#endif
735 int is_day = user_colors::GetColorScheme() == GLOBAL_COLOR_SCHEME_DAY ? 1 : 0;
736 GuiEvents::GetInstance().color_scheme_change.Notify(is_day, "");
737}
738
739MyFrame::~MyFrame() {
740 FrameTimer1.Stop();
741 FrameTenHzTimer.Stop();
743
744 delete ChartData;
745 // delete pCurrentStack;
746
747 // Free the Route List
748 for (Route *pRouteDelete : *pRouteList) {
749 delete pRouteDelete;
750 }
751 delete pRouteList;
752 pRouteList = NULL;
753
754 Disconnect(
755 wxEVT_OCPN_MSG,
756 (wxObjectEventFunction)(wxEventFunction)&MyFrame::OnEvtPlugInMessage);
757 // FIXME (dave) Was in some datastream file?
758 // Disconnect(wxEVT_OCPN_THREADMSG,
759 // (wxObjectEventFunction)(wxEventFunction)&MyFrame::OnEvtTHREADMSG);
760}
761
762void MyFrame::FreezeCharts() {
763 // ..For each canvas,
764#ifndef __WXMAC__
765 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
766 ChartCanvas *cc = g_canvasArray.Item(i);
767 if (cc && !cc->IsFrozen()) cc->Freeze();
768 }
769#endif
770}
771void MyFrame::CenterAisTarget(
772 const std::shared_ptr<const AisTargetData> &ais_target) {
773 double scale = GetFocusCanvas()->GetVPScale();
774 if (1) {
775 JumpToPosition(GetFocusCanvas(), ais_target->Lat, ais_target->Lon, scale);
776 } else {
777 // Set a reasonable (1:5000) chart scale to see the target.
778 if (scale < 0.7) { // Don't zoom if already close.
779 ChartCanvas *cc = gFrame->GetFocusCanvas();
780 double factor = cc->GetScaleValue() / 5000.0;
781 JumpToPosition(GetFocusCanvas(), ais_target->Lat, ais_target->Lon,
782 scale * factor);
783 }
784 }
785}
786
787void MyFrame::ThawCharts() {
788 // ..For each canvas,
789#ifndef __WXMAC__
790 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
791 ChartCanvas *cc = g_canvasArray.Item(i);
792 if (cc && cc->IsFrozen()) cc->Thaw();
793 }
794#endif
795}
796
797void MyFrame::OnSENCEvtThread(OCPN_BUILDSENC_ThreadEvent &event) {
798 s57chart *chart;
799 switch (event.type) {
800 case SENC_BUILD_STARTED:
801 // printf("Myframe SENC build started\n");
802 break;
803 case SENC_BUILD_DONE_NOERROR:
804 // printf("Myframe SENC build done no error\n");
805 chart = event.m_ticket->m_chart;
806 if (chart) {
807 chart->PostInit(FULL_INIT, global_color_scheme);
808 // ..For each canvas, force an S52PLIB reconfig...
809 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
810 ChartCanvas *cc = g_canvasArray.Item(i);
811 if (cc) cc->ClearS52PLIBStateHash(); // Force a S52 PLIB re-configure
812 }
813 }
814
815 ReloadAllVP();
816 delete event.m_ticket;
817 break;
818 case SENC_BUILD_DONE_ERROR:
819 // printf("Myframe SENC build done ERROR\n");
820 break;
821 default:
822 break;
823 }
824}
825
826void MyFrame::RebuildChartDatabase() {
827 bool b_SetInitialPoint = false;
828
829 // Build the initial chart dir array
830 ArrayOfCDI ChartDirArray;
831 pConfig->LoadChartDirArray(ChartDirArray);
832
833 if (ChartDirArray.GetCount()) {
834 // Create and Save a new Chart Database based on the hints
835 // given in the config file
836 if (g_NeedDBUpdate == 1) {
837 wxString msg1(
838 _("OpenCPN needs to update the chart database from config file "
839 "entries...."));
840
841 OCPNMessageDialog mdlg(gFrame, msg1, wxString(_("OpenCPN Info")),
842 wxICON_INFORMATION | wxOK);
843 mdlg.ShowModal();
844 }
845
846 delete ChartData;
847 ChartData = new ChartDB();
848
849 wxString line(
850 _("Rebuilding chart database from configuration file entries..."));
851 /* The following 3 strings are embeded in wxProgressDialog but must be
852 * included by xgettext to be localized properly. See
853 * {wxWidgets}src/generic/progdlgg.cpp:190 */
854 wxString dummy1 = _("Elapsed time : ");
855 wxString dummy2 = _("Estimated time : ");
856 wxString dummy3 = _("Remaining time : ");
857 wxGenericProgressDialog *pprog = new wxGenericProgressDialog(
858 _("OpenCPN Chart Update"), line, 100, NULL,
859 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
860 wxPD_REMAINING_TIME);
861
862 ChartData->Create(ChartDirArray, nullptr);
863 ChartData->SaveBinary(ChartListFileName);
864
865 delete pprog;
866
867 // Apply the inital Group Array structure to the chart database
868 ChartData->ApplyGroupArray(g_pGroupArray);
869 }
870}
871
872// play an arbitrary number of bells by using 1 and 2 bell sounds
873void MyFrame::OnBellsFinished(wxCommandEvent &event) {
874 int bells = wxMin(m_BellsToPlay, 2);
875 if (bells <= 0) return;
876
877 wxString soundfile = "sounds";
878 appendOSDirSlash(&soundfile);
879 soundfile += wxString(bells_sound_file_name[bells - 1], wxConvUTF8);
880 soundfile.Prepend(g_Platform->GetSharedDataDir());
881 wxLogMessage("Using bells sound file: " + soundfile);
882
883 o_sound::Sound *sound = bells_sound[bells - 1];
884 sound->SetFinishedCallback(onBellsFinishedCB, this);
885 auto cmd_sound = dynamic_cast<o_sound::SystemCmdSound *>(sound);
886 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
887 sound->Load(soundfile);
888 if (!sound->IsOk()) {
889 wxLogMessage("Failed to load bells sound file: " + soundfile);
890 return;
891 }
892 sound->Play();
893 m_BellsToPlay -= bells;
894}
895
896void MyFrame::OnEraseBackground(wxEraseEvent &event) {}
897
898void MyFrame::OnMaximize(wxMaximizeEvent &event) {
899 g_click_stop = 0;
900#ifdef __WXOSX__
901 event.Skip();
902#endif
903}
904
905void MyFrame::ReloadAllVP() {
906 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
907 ChartCanvas *cc = g_canvasArray.Item(i);
908 if (cc) cc->ReloadVP();
909 }
910}
911
912void MyFrame::SetAndApplyColorScheme(ColorScheme cs) {
913 int is_day = cs == GLOBAL_COLOR_SCHEME_DAY ? 1 : 0;
914 GuiEvents::GetInstance().color_scheme_change.Notify(is_day, "");
915
916 global_color_scheme = cs;
917 wxString SchemeName;
918 switch (cs) {
919 case GLOBAL_COLOR_SCHEME_DAY:
920 SchemeName = "DAY";
921 break;
922 case GLOBAL_COLOR_SCHEME_DUSK:
923 SchemeName = "DUSK";
924 break;
925 case GLOBAL_COLOR_SCHEME_NIGHT:
926 SchemeName = "NIGHT";
927 break;
928 default:
929 SchemeName = "DAY";
930 break;
931 }
932
933 m_pauidockart->SetMetric(wxAUI_DOCKART_GRADIENT_TYPE, wxAUI_GRADIENT_NONE);
934
935 m_pauidockart->SetColour(wxAUI_DOCKART_BORDER_COLOUR, wxColour(0, 0, 0));
936 m_pauidockart->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 1);
937 m_pauidockart->SetColour(wxAUI_DOCKART_SASH_COLOUR, wxColour(0, 0, 0));
938 m_pauidockart->SetMetric(wxAUI_DOCKART_SASH_SIZE, 0);
939 m_pauidockart->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR,
940 wxColour(0, 0, 0));
941 m_pauidockart->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR, wxColour(0, 0, 0));
942
943 // if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT )
944 // {
945 // m_pauidockart->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 0);
946 // m_pauidockart->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR,
947 // wxColour(0,0,0));
948 // m_pauidockart->SetColour(wxAUI_DOCKART_BORDER_COLOUR,
949 // wxColour(0,0,0));
950 // }
951
952 // else{
953 // m_pauidockart->SetMetric(wxAUI_DOCKART_GRADIENT_TYPE,
954 // g_grad_default);
955 // m_pauidockart->SetColour(wxAUI_DOCKART_BORDER_COLOUR,
956 // g_border_color_default);
957 // m_pauidockart->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE,
958 // g_border_size_default);
959 // m_pauidockart->SetColour(wxAUI_DOCKART_SASH_COLOUR,
960 // g_sash_color_default);
961 // m_pauidockart->SetMetric(wxAUI_DOCKART_SASH_SIZE,
962 // g_sash_size_default);
963 // m_pauidockart->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR,
964 // g_caption_color_default);
965 // m_pauidockart->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR,
966 // g_background_color_default);
967 //
968 // }
969
970 m_pauidockart->SetColour(wxAUI_DOCKART_SASH_COLOUR, wxColour(0, 0, 0));
971 m_pauidockart->SetMetric(wxAUI_DOCKART_SASH_SIZE, 6);
972
973 g_pauimgr->Update();
974
975 g_StyleManager->GetCurrentStyle()->SetColorScheme(cs);
976
977 if (ps52plib) ps52plib->SetPLIBColorScheme(SchemeName, ChartCtxFactory());
978
979 // Set up a pointer to the proper hash table
981 user_colors::GetMapByScheme(SchemeName.ToStdString());
982
983 SetSystemColors(cs);
984
985 // ..For each canvas...
986 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
987 ChartCanvas *cc = g_canvasArray.Item(i);
988 if (cc) {
989 cc->SetColorScheme(cs);
990 cc->GetWorldBackgroundChart()->SetColorScheme(cs);
991 cc->HideChartInfoWindow();
992 cc->SetQuiltChartHiLiteIndex(-1);
993 }
994 }
995
996 if (pWayPointMan)
997 WayPointmanGui(*pWayPointMan)
998 .SetColorScheme(cs, g_Platform->GetDisplayDPmm());
999 if (ChartData) ChartData->ApplyColorSchemeToCachedCharts(cs);
1000
1001 if (g_options) {
1002 g_options->SetColorScheme(cs);
1003 }
1004
1005 if (console) {
1006 console->SetColorScheme(cs);
1007 }
1008
1009 if (g_pRouteMan) {
1010 g_pRouteMan->SetColorScheme(cs, g_Platform->GetDisplayDPmm());
1011 }
1012
1013 if (g_pMarkInfoDialog) {
1014 g_pMarkInfoDialog->SetColorScheme(cs);
1015 }
1016
1017 if (pRoutePropDialog) {
1018 pRoutePropDialog->SetColorScheme(cs);
1019 }
1020
1021 // For the AIS target query dialog, we must rebuild it to incorporate the
1022 // style desired for the colorscheme selected
1023 if (g_pais_query_dialog_active) {
1024 bool b_isshown = g_pais_query_dialog_active->IsShown();
1025 int n_mmsi = g_pais_query_dialog_active->GetMMSI();
1026 if (b_isshown) g_pais_query_dialog_active->Show(false); // dismiss it
1027
1028 g_pais_query_dialog_active->Close();
1029
1030 g_pais_query_dialog_active = new AISTargetQueryDialog();
1031 g_pais_query_dialog_active->Create(
1032 this, -1, _("AIS Target Query"),
1033 wxPoint(g_ais_query_dialog_x, g_ais_query_dialog_y));
1034 g_pais_query_dialog_active->SetMMSI(n_mmsi);
1035 g_pais_query_dialog_active->UpdateText();
1036 if (b_isshown) g_pais_query_dialog_active->Show();
1037 }
1038
1039 if (pRouteManagerDialog) pRouteManagerDialog->SetColorScheme();
1040
1041 if (g_pAISTargetList) g_pAISTargetList->SetColorScheme();
1042
1043 if (g_pObjectQueryDialog) g_pObjectQueryDialog->SetColorScheme();
1044
1045 ApplyGlobalColorSchemetoStatusBar();
1046
1047 UpdateAllToolbars(cs);
1048
1049 if (g_MainToolbar) {
1050 if (g_MainToolbar->GetColorScheme() != cs) {
1051 // capture the current toolbar collapse state
1052 bool btoolbarFull = g_bmasterToolbarFull;
1053
1054 g_MainToolbar->SetColorScheme(cs);
1055 // g_MainToolbar->DestroyToolBar();
1056 // CreateMasterToolbar();
1057
1058 if (!btoolbarFull) {
1059 // g_MainToolbar->Hide();
1060 RequestNewMasterToolbar();
1061 g_MainToolbar->SetColorScheme(cs);
1062 CollapseGlobalToolbar();
1063 // g_MainToolbar->Show();
1064 } else {
1065 RequestNewMasterToolbar();
1066 g_MainToolbar->SetColorScheme(cs);
1067 }
1068 }
1069 }
1070
1071 if (g_pi_manager) g_pi_manager->SetColorSchemeForAllPlugIns(cs);
1072}
1073
1074void MyFrame::ApplyGlobalColorSchemetoStatusBar() {
1075 if (m_pStatusBar != NULL) {
1076 m_pStatusBar->SetBackgroundColour(GetGlobalColor("UIBDR")); // UINFF
1077 m_pStatusBar->ClearBackground();
1078 }
1079}
1080
1081ChartCanvas *MyFrame::GetPrimaryCanvas() {
1082 if (g_canvasArray.GetCount() > 0)
1083 return g_canvasArray.Item(0);
1084 else
1085 return NULL;
1086}
1087
1088void MyFrame::CancelAllMouseRoute() {
1089 // ..For each canvas...
1090 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1091 ChartCanvas *cc = g_canvasArray.Item(i);
1092 if (cc) cc->CancelMouseRoute();
1093 }
1094}
1095
1096void MyFrame::CreateCanvasLayout(bool b_useStoredSize) {
1097 // Clear the cache, and thus close all charts to avoid memory leaks
1098 if (ChartData) ChartData->PurgeCache();
1099
1100 // If it exists, hide the console, in preparation for re-creation
1101 if (console) console->Show(false);
1102
1103 // Detach all canvases from AUI manager
1104 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1105 ChartCanvas *cc = g_canvasArray[i];
1106 if (cc) {
1107 g_pauimgr->DetachPane(cc);
1108 }
1109 }
1110
1111 // Destroy any existing canvases, except for Primary canvas
1112 for (unsigned int i = 1; i < g_canvasArray.GetCount(); i++) {
1113 ChartCanvas *cc = g_canvasArray.Item(i);
1114 if (cc) {
1115 // pthumbwin = NULL; // TODO
1116 // cc->DestroyToolbar();
1117 cc->Destroy();
1118 }
1119 }
1120
1121 auto &config_array = ConfigMgr::Get().GetCanvasConfigArray();
1122
1123 // Canvas pointers in config array are now invalid
1124 for (unsigned int i = 1; i < config_array.GetCount(); i++) {
1125 config_array.Item(i)->canvas = NULL;
1126 }
1127
1128 // g_canvasArray.Clear();
1129
1130 // Clear the canvas Array, except for Primary canvas
1131 for (unsigned int i = 1; i < g_canvasArray.GetCount(); i++) {
1132 g_canvasArray.RemoveAt(i);
1133 }
1134
1135 ChartCanvas *cc = NULL;
1136 switch (g_canvasConfig) {
1137 default:
1138 case 0: // a single canvas
1139 if (!g_canvasArray.GetCount() || !config_array.Item(0)) {
1140 cc = new ChartCanvas(this, 0,
1141 m_data_monitor); // the chart display canvas
1142 g_canvasArray.Add(cc);
1143 } else {
1144 cc = g_canvasArray[0];
1145 }
1146
1147#ifdef ocpnUSE_GL
1148 // Verify that glCanvas is ready, if necessary
1149 if (g_bopengl) {
1150 if (!cc->GetglCanvas()) cc->SetupGlCanvas();
1151 cc->GetglCanvas()->Show();
1152 }
1153#endif
1154 config_array.Item(0)->canvas = cc;
1155
1157
1158 cc->ApplyCanvasConfig(config_array.Item(0));
1159
1160 // cc->SetToolbarPosition(wxPoint( g_maintoolbar_x,
1161 // g_maintoolbar_y ));
1162 cc->ConfigureChartBar();
1163 cc->SetColorScheme(global_color_scheme);
1164 cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
1165 cc->SetShowGPS(true);
1166
1167 g_pauimgr->AddPane(cc);
1168 g_pauimgr->GetPane(cc).Name("ChartCanvas");
1169 g_pauimgr->GetPane(cc).Fixed();
1170 g_pauimgr->GetPane(cc).CaptionVisible(false);
1171 g_pauimgr->GetPane(cc).CenterPane();
1172
1173 break;
1174
1175 case 1: { // two canvas, horizontal
1176 if (!g_canvasArray.GetCount() || !g_canvasArray[0]) {
1177 cc = new ChartCanvas(this, 0, m_data_monitor); // chart display canvas
1178 g_canvasArray.Add(cc);
1179 } else {
1180 cc = g_canvasArray[0];
1181 }
1182
1183 // Verify that glCanvas is ready, if not already built
1184#ifdef ocpnUSE_GL
1185 if (g_bopengl) {
1186 if (!cc->GetglCanvas()) cc->SetupGlCanvas();
1187 }
1188#endif
1189 config_array.Item(0)->canvas = cc;
1190
1191 cc->ApplyCanvasConfig(config_array.Item(0));
1192
1194 cc->ConfigureChartBar();
1195 cc->SetColorScheme(global_color_scheme);
1196 cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
1197 cc->SetShowGPS(false);
1198
1199 g_pauimgr->AddPane(cc);
1200 g_pauimgr->GetPane(cc).Name("ChartCanvas");
1201 g_pauimgr->GetPane(cc)
1202 .CaptionVisible(false)
1203 .PaneBorder(false)
1204 .CloseButton(false);
1205
1206 g_pauimgr->GetPane(cc).CenterPane();
1207
1208 cc = new ChartCanvas(this, 1, m_data_monitor); // chart display canvas
1209 g_canvasArray.Add(cc);
1210
1211 // There is not yet a config descriptor for canvas 2, so create one by
1212 // copy ctor from canvas {0}.
1213 if (config_array.GetCount() < 2) {
1214 canvasConfig *pcc = new canvasConfig(*config_array.Item(0));
1215 pcc->configIndex = 1;
1216
1217 // Arbitrarily establish the initial size of the new canvas to be
1218 // half the screen width.
1219 pcc->canvasSize = wxSize(GetClientSize().x / 2, GetClientSize().y);
1220 config_array.Add(pcc);
1221 }
1222
1223 config_array.Item(1)->canvas = cc;
1224
1225 cc->ApplyCanvasConfig(config_array.Item(1));
1226
1228 cc->ConfigureChartBar();
1229 cc->SetColorScheme(global_color_scheme);
1230 cc->SetShowGPS(true);
1231 cc->CreateMUIBar();
1232
1233 g_pauimgr->AddPane(cc);
1234 g_pauimgr->GetPane(cc).Name("ChartCanvas2");
1235 g_pauimgr->GetPane(cc)
1236 .CaptionVisible(false)
1237 .PaneBorder(false)
1238 .CloseButton(false);
1239 g_pauimgr->GetPane(cc).RightDockable(true);
1240 g_pauimgr->GetPane(cc).Right();
1241
1242#ifdef __ANDROID__
1243 config_array.Item(1)->canvasSize =
1244 wxSize(GetClientSize().x / 2, GetClientSize().y);
1245 g_pauimgr->GetPane(cc).BestSize(GetClientSize().x / 2, GetClientSize().y);
1246#endif
1247
1248 // If switching fromsingle canvas to 2-canvas mode dynamically,
1249 // try to use the latest persisted size for the new second canvas.
1250 if (b_useStoredSize) {
1251 int ccw = config_array.Item(1)->canvasSize.x;
1252 int cch = config_array.Item(1)->canvasSize.y;
1253
1254 // Check for undefined size, and set a nice default size if necessary.
1255 if (ccw < GetClientSize().x / 10) {
1256 ccw = GetClientSize().x / 2;
1257 cch = GetClientSize().y;
1258 }
1259
1260 g_pauimgr->GetPane(cc).BestSize(ccw, cch);
1261 cc->SetSize(ccw, cch);
1262 }
1263
1264 break;
1265 }
1266
1267 case 2: // two canvas, vertical
1268
1269 break;
1270 }
1271
1272 g_focusCanvas = GetPrimaryCanvas();
1273
1274 delete console;
1275 if (g_canvasArray.size() > 1)
1276 console = new APConsole(g_canvasArray.Item(1)); // the console
1277 else
1278 console = new APConsole(g_canvasArray.Item(0));
1279 console->SetColorScheme(global_color_scheme);
1280
1281 // Draw console if persisted route is active
1282 if (g_pRouteMan) {
1283 if (g_pRouteMan->IsAnyRouteActive()) {
1284 g_pRouteMan->GetDlgContext().show_with_fresh_fonts();
1285 }
1286 }
1287 PositionConsole();
1288}
1289
1290void MyFrame::RequestNewToolbars(bool bforcenew) {
1291 if (b_inCloseWindow) {
1292 return;
1293 }
1294
1295 BuildiENCToolbar(bforcenew, m_toolbar_callbacks);
1296 PositionIENCToolbar();
1297
1298#ifdef __ANDROID__
1299 DoChartUpdate();
1300#endif
1301}
1302
1303// Update inplace the various controls with bitmaps corresponding to the
1304// current color scheme
1305void MyFrame::UpdateAllToolbars(ColorScheme cs) {
1306 if (g_iENCToolbar) g_iENCToolbar->SetColorScheme(cs);
1307
1308 return;
1309}
1310
1311void MyFrame::SetAllToolbarScale() {
1312 g_toolbar_scalefactor = g_Platform->GetToolbarScaleFactor(g_GUIScaleFactor);
1313}
1314
1315void MyFrame::SetGPSCompassScale() {
1316 g_compass_scalefactor = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
1317}
1318
1319ChartCanvas *MyFrame::GetCanvasUnderMouse() {
1320 wxPoint screenPoint = ::wxGetMousePosition();
1321 canvasConfig *cc;
1322
1323 switch (g_canvasConfig) {
1324 case 1:
1325 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(0);
1326 if (cc) {
1327 ChartCanvas *canvas = cc->canvas;
1328 if (canvas->GetScreenRect().Contains(
1329 /*canvas->ScreenToClient*/ (screenPoint)))
1330 return canvas;
1331 }
1332 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(1);
1333 if (cc) {
1334 ChartCanvas *canvas = cc->canvas;
1335 if (canvas->GetScreenRect().Contains(
1336 /*canvas->ScreenToClient*/ (screenPoint)))
1337 return canvas;
1338 }
1339 break;
1340
1341 default:
1342 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(0);
1343 if (cc) {
1344 ChartCanvas *canvas = cc->canvas;
1345 if (canvas->GetScreenRect().Contains(
1346 canvas->ScreenToClient(screenPoint)))
1347 return canvas;
1348 }
1349 }
1350
1351 return NULL;
1352}
1353
1354int MyFrame::GetCanvasIndexUnderMouse() {
1355 wxPoint screenPoint = ::wxGetMousePosition();
1356 canvasConfig *cc;
1357
1358 switch (g_canvasConfig) {
1359 case 1:
1360 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(0);
1361 if (cc) {
1362 ChartCanvas *canvas = cc->canvas;
1363 if (canvas->GetScreenRect().Contains(
1364 /*canvas->ScreenToClient*/ (screenPoint)))
1365 return 0;
1366 }
1367 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(1);
1368 if (cc) {
1369 ChartCanvas *canvas = cc->canvas;
1370 if (canvas->GetScreenRect().Contains(
1371 /*canvas->ScreenToClient*/ (screenPoint)))
1372 return 1;
1373 }
1374 break;
1375
1376 default:
1377 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(0);
1378 if (cc) {
1379 ChartCanvas *canvas = cc->canvas;
1380 if (canvas->GetScreenRect().Contains(
1381 canvas->ScreenToClient(screenPoint)))
1382 return 0;
1383 }
1384 }
1385
1386 return -1;
1387}
1388
1389bool MyFrame::DropMarker(bool atOwnShip) {
1390 double lat, lon;
1391 ChartCanvas *canvas = GetCanvasUnderMouse();
1392 if (atOwnShip) {
1393 lat = gLat;
1394 lon = gLon;
1395 } else {
1396 if (!canvas) return false;
1397
1398 lat = canvas->m_cursor_lat;
1399 lon = canvas->m_cursor_lon;
1400 }
1401
1402 RoutePoint *pWP =
1403 new RoutePoint(lat, lon, g_default_wp_icon, wxEmptyString, wxEmptyString);
1404 pWP->m_bIsolatedMark = true; // This is an isolated mark
1405 pSelect->AddSelectableRoutePoint(lat, lon, pWP);
1406 // pConfig->AddNewWayPoint(pWP, -1); // use auto next num
1407 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1408
1409 if (canvas)
1410 if (!RoutePointGui(*pWP).IsVisibleSelectable(canvas))
1411 RoutePointGui(*pWP).ShowScaleWarningMessage(canvas);
1412 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1413 pRouteManagerDialog->UpdateWptListCtrl();
1414 // undo->BeforeUndoableAction( Undo_CreateWaypoint, pWP, Undo_HasParent,
1415 // NULL ); undo->AfterUndoableAction( NULL );
1416
1417 InvalidateAllGL();
1418 RefreshAllCanvas(false);
1419
1420 return true;
1421}
1422
1423void MyFrame::SwitchKBFocus(ChartCanvas *pCanvas) {
1424 if (g_canvasConfig != 0) { // multi-canvas?
1425 canvasConfig *cc;
1426 int nTarget = -1;
1427 int nTargetGTK = -1;
1428 ChartCanvas *target;
1429 wxWindow *source = FindFocus();
1430 auto test = dynamic_cast<ChartCanvas *>(source);
1431 if (!test) return;
1432
1433 // On linux(GTK), the TAB key causes a loss of focus immediately
1434 // So the logic needs a switch
1435 switch (g_canvasConfig) {
1436 case 1:
1437 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(0);
1438 if (cc) {
1439 ChartCanvas *canvas = cc->canvas;
1440 if (canvas && (canvas == test)) {
1441 nTarget = 1;
1442 nTargetGTK = 0;
1443 }
1444 }
1445 cc = ConfigMgr::Get().GetCanvasConfigArray().Item(1);
1446 if (cc) {
1447 ChartCanvas *canvas = cc->canvas;
1448 if (canvas && (canvas == test)) {
1449 nTarget = 0;
1450 nTargetGTK = 1;
1451 }
1452 }
1453
1454 if (nTarget >= 0) {
1455 // printf("sw %d\n", nTarget);
1456 int nfinalTarget = nTarget;
1457#ifdef __WXGTK__
1458 nfinalTarget = nTargetGTK;
1459#endif
1460 target = ConfigMgr::Get()
1461 .GetCanvasConfigArray()
1462 .Item(nfinalTarget)
1463 ->canvas;
1464 if (target) {
1465 target->SetFocus();
1466 target->Refresh(true);
1467 }
1468 }
1469 break;
1470
1471 default:
1472 break;
1473 }
1474 }
1475}
1476
1477void MyFrame::FastClose() {
1478 FrameTimer1.Stop();
1479 FrameTenHzTimer.Stop();
1480 quitflag++; // signal to the timer loop
1481 FrameTimer1.Start(1); // real quick now...
1482}
1483
1484// Intercept menu commands
1485void MyFrame::OnExit(wxCommandEvent &event) {
1486 quitflag++; // signal to the timer loop
1487}
1488
1489void MyFrame::OnCloseWindow(wxCloseEvent &event) {
1490 // It is possible that double clicks on application exit box could cause
1491 // re-entrance here Not good, and don't need it anyway, so simply return.
1492 if (b_inCloseWindow) {
1493 // wxLogMessage(_T("opencpn::MyFrame re-entering
1494 // OnCloseWindow"));
1495 return;
1496 }
1497
1498 // The Options dialog, and other deferred init items, are not fully
1499 // initialized. Best to just cancel the close request. This is probably only
1500 // reachable on slow hardware, or on Android life-cycle events...
1501#ifndef __ANDROID__
1502 if (!g_bDeferredInitDone) return;
1503#endif
1504
1505#ifndef __WXOSX__
1506 if (g_options) {
1507 delete g_options;
1508 g_options = NULL;
1509 g_pOptions = NULL;
1510 }
1511#endif
1512
1513 // If the multithread chart compressor engine is running, cancel the close
1514 // command
1516 return;
1517 }
1518
1519 if (bDBUpdateInProgress) return;
1520
1521 b_inCloseWindow = true;
1522
1523 ::wxSetCursor(wxCURSOR_WAIT);
1524
1525 // If we happen to have the measure tool open on Ctrl-Q quit
1526 // ..For each canvas...
1527 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1528 ChartCanvas *cc = g_canvasArray.Item(i);
1529 if (cc && cc->IsMeasureActive()) {
1530 cc->CancelMeasureRoute();
1531 }
1532 }
1533
1534 // Give any requesting plugins a PreShutdownHook call
1535 SendPreShutdownHookToPlugins();
1536
1537 // We save perspective before closing to restore position next time
1538 // Pane is not closed so the child is not notified (OnPaneClose)
1539 if (g_pAISTargetList) {
1540 wxAuiPaneInfo &pane = g_pauimgr->GetPane(g_pAISTargetList);
1541 g_AisTargetList_perspective = g_pauimgr->SavePaneInfo(pane);
1542 g_pauimgr->DetachPane(g_pAISTargetList);
1543 }
1544
1545 // Make sure the saved perspective minimum canvas sizes are essentially
1546 // undefined
1547 // for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
1548 // ChartCanvas *cc = g_canvasArray.Item(i);
1549 // if(cc)
1550 // g_pauimgr->GetPane( cc ).MinSize(10,10);
1551 // }
1552
1553 pConfig->SetPath("/AUI");
1554 pConfig->Write("AUIPerspective", g_pauimgr->SavePerspective());
1555
1556 g_bquiting = true;
1557
1558#ifdef ocpnUSE_GL
1559 // cancel compression jobs
1560 if (g_bopengl) {
1561 if (g_glTextureManager) {
1562 g_glTextureManager->PurgeJobList();
1563
1564 if (g_glTextureManager->GetRunningJobCount()) g_bcompression_wait = true;
1565 }
1566 }
1567#endif
1568
1569 SetCursor(wxCURSOR_WAIT);
1570
1571 RefreshAllCanvas(true);
1572
1573 // This yield is not necessary, since the Update() proceeds syncronously...
1574 // wxYield();
1575
1576 // Save the saved Screen Brightness
1577 RestoreScreenBrightness();
1578
1579 // Persist the toolbar locations
1580 // if (g_MainToolbar) {
1581 // g_MainToolbar->GetFrameRelativePosition(&g_maintoolbar_x,
1582 // &g_maintoolbar_y);
1583 // }
1584
1585#if 0
1586 if (g_iENCToolbar) {
1587 wxPoint locn = g_iENCToolbar->GetPosition();
1588 wxPoint tbp_incanvas = GetPrimaryCanvas()->ScreenToClient(locn);
1589 g_iENCToolbarPosY = tbp_incanvas.y;
1590 g_iENCToolbarPosX = tbp_incanvas.x;
1591 }
1592#endif
1593
1594 g_bframemax = IsMaximized();
1595
1596 FrameTimer1.Stop();
1597 FrameTenHzTimer.Stop();
1598
1599 FrameCOGTimer.Stop();
1600
1601 TrackOff();
1602
1603 /*
1604 Automatically drop an anchorage waypoint, if enabled
1605 On following conditions:
1606 1. In "Cruising" mode, meaning that speed has at some point exceeded 3.0 kts.
1607 2. Current speed is less than 0.5 kts.
1608 3. Opencpn has been up at least 30 minutes
1609 4. And, of course, opencpn is going down now.
1610 5. And if there is no anchor watch set on "anchor..." icon mark //
1611 pjotrc 2010.02.15
1612 */
1613 if (g_bAutoAnchorMark) {
1614 bool watching_anchor = false; // pjotrc 2010.02.15
1615 if (pAnchorWatchPoint1) // pjotrc 2010.02.15
1616 watching_anchor = (pAnchorWatchPoint1->GetIconName().StartsWith(
1617 "anchor")); // pjotrc 2010.02.15
1618 if (pAnchorWatchPoint2) // pjotrc 2010.02.15
1619 watching_anchor |= (pAnchorWatchPoint2->GetIconName().StartsWith(
1620 "anchor")); // pjotrc 2010.02.15
1621
1622 wxDateTime now = wxDateTime::Now();
1623 wxTimeSpan uptime = now.Subtract(g_start_time);
1624
1625 if (!watching_anchor && (g_bCruising) && (gSog < 0.5) &&
1626 (uptime.IsLongerThan(wxTimeSpan(0, 30, 0, 0)))) // pjotrc 2010.02.15
1627 {
1628 // First, if enabled, delete any single anchorage waypoints closer
1629 // than 0.25 NM from this point
1630 // This will prevent screen clutter and database congestion.
1631 if (g_declutter_anchorage) {
1632 for (RoutePoint *pr : *pWayPointMan->GetWaypointList()) {
1633 if (pr->GetName().StartsWith("Anchorage")) {
1634 double a = gLat - pr->m_lat;
1635 double b = gLon - pr->m_lon;
1636 double l = sqrt((a * a) + (b * b));
1637
1638 // caveat: this is accurate only on the Equator
1639 if ((l * 60. * 1852.) < (.25 * 1852.)) {
1640 // pConfig->DeleteWayPoint(pr);
1641 NavObj_dB::GetInstance().DeleteRoutePoint(pr);
1642 pSelect->DeleteSelectablePoint(pr, SELTYPE_ROUTEPOINT);
1643 delete pr;
1644 break;
1645 }
1646 }
1647 }
1648 }
1649
1650 wxString name = now.Format();
1651 name.Prepend(_("Anchorage created "));
1652 RoutePoint *pWP =
1653 new RoutePoint(gLat, gLon, "anchorage", name, wxEmptyString);
1654 pWP->m_bShowName = false;
1655 pWP->m_bIsolatedMark = true;
1656
1657 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1658 }
1659 }
1660
1661 // Provisionally save all settings before deactivating plugins
1662 pConfig->UpdateSettings();
1663
1664 // Deactivate the PlugIns
1665 PluginLoader::GetInstance()->DeactivateAllPlugIns();
1666 wxLogMessage("opencpn::MyFrame exiting cleanly.");
1667
1668 quitflag++;
1669
1670 NavObj_dB::GetInstance().Close();
1671
1672 // Remove any leftover Routes and Waypoints from config file as they were
1673 // saved to navobj before
1674 pConfig->DeleteGroup("/Routes");
1675 pConfig->DeleteGroup("/Marks");
1676 pConfig->Flush();
1677
1678 if (g_pAboutDlg) g_pAboutDlg->Destroy();
1679 if (g_pAboutDlgLegacy) g_pAboutDlgLegacy->Destroy();
1680
1681 // Explicitely Close some children, especially the ones with event
1682 // handlers or that call GUI methods
1683
1684 if (g_pCM93OffsetDialog) {
1685 g_pCM93OffsetDialog->Destroy();
1686 g_pCM93OffsetDialog = NULL;
1687 }
1688
1689#ifndef __ANDROID__
1690 // if (g_MainToolbar) g_MainToolbar->Destroy();
1691 // g_MainToolbar = NULL;
1692#endif
1693
1694 if (g_iENCToolbar) {
1695 // wxPoint locn = g_iENCToolbar->GetPosition();
1696 // g_iENCToolbarPosY = locn.y;
1697 // g_iENCToolbarPosX = locn.x;
1698 // g_iENCToolbar->Destroy();
1699 }
1700
1701 if (g_pAISTargetList) {
1702 g_pAISTargetList->Disconnect_decoder();
1703 g_pAISTargetList->Destroy();
1704 }
1705
1706#ifndef __WXQT__
1707 SetStatusBar(NULL);
1708#endif
1709
1710 if (RouteManagerDialog::getInstanceFlag()) {
1711 if (pRouteManagerDialog) {
1712 pRouteManagerDialog->Destroy();
1713 pRouteManagerDialog = NULL;
1714 }
1715 }
1716
1717 // Clear the cache, and thus close all charts to avoid memory leaks
1718 if (ChartData) ChartData->PurgeCache();
1719
1720 // pthumbwin is a canvas child
1721 // pthumbwin = NULL;
1722
1723 // Finally ready to destroy the canvases
1724 g_focusCanvas = NULL;
1725
1726 // ..For each canvas...
1727 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1728 ChartCanvas *cc = g_canvasArray.Item(i);
1729 if (cc) cc->Destroy();
1730 }
1731
1732 g_canvasArray.Clear();
1733
1734 g_pauimgr->UnInit();
1735 delete g_pauimgr;
1736 g_pauimgr = NULL;
1737
1738 // Unload the PlugIns
1739 // Note that we are waiting until after the canvas is destroyed,
1740 // since some PlugIns may have created children of canvas.
1741 // Such a PlugIn must stay intact for the canvas dtor to call
1742 // DestoryChildren()
1743
1744 if (ChartData) ChartData->PurgeCachePlugins();
1745
1746 PluginLoader::GetInstance()->UnLoadAllPlugIns();
1747
1748 if (g_pi_manager) {
1749 delete g_pi_manager;
1750 g_pi_manager = NULL;
1751 }
1752
1753 CommBridge::GetInstance().SaveConfig();
1754
1755 delete pConfig; // All done
1756 pConfig = NULL;
1757 InitBaseConfig(0);
1758
1759 if (g_pAIS) {
1760 delete g_pAIS;
1761 g_pAIS = NULL;
1762 }
1763
1764 if (g_pAISGUI) {
1765 delete g_pAISGUI;
1766 g_pAISGUI = NULL;
1767 }
1768
1769 delete g_pMUX;
1770 g_pMUX = NULL;
1771
1772 // Close and delete all comm drivers
1773 auto &registry = CommDriverRegistry::GetInstance();
1774 registry.CloseAllDrivers();
1775
1776 // Clear some global arrays, lists, and hash maps...
1777 for (auto *cp : TheConnectionParams()) {
1778 delete cp;
1779 }
1780
1781 if (pLayerList) {
1782 while (pLayerList->size()) delete *pLayerList->begin();
1783 // automatically removes the layer from list, see Layer dtor
1784 }
1785
1786 ReleaseApiListeners();
1787
1788 g_MainToolbar = NULL;
1789 g_bTempShowMenuBar = false;
1790
1791#define THREAD_WAIT_SECONDS 5
1792#ifdef ocpnUSE_GL
1793 // The last thing we do is finish the compression threads.
1794 // This way the main window is already invisible and to the user
1795 // it appears to have finished rather than hanging for several seconds
1796 // while the compression threads exit
1797 if (g_bopengl && g_glTextureManager &&
1798 g_glTextureManager->GetRunningJobCount()) {
1799 g_glTextureManager->ClearAllRasterTextures();
1800
1801 wxLogMessage("Starting compressor pool drain");
1802 wxDateTime now = wxDateTime::Now();
1803 time_t stall = now.GetTicks();
1804 time_t end = stall + THREAD_WAIT_SECONDS;
1805
1806 int n_comploop = 0;
1807 while (stall < end) {
1808 wxDateTime later = wxDateTime::Now();
1809 stall = later.GetTicks();
1810
1811 wxString msg;
1812 msg.Printf("Time: %d Job Count: %d", n_comploop,
1813 g_glTextureManager->GetRunningJobCount());
1814 wxLogMessage(msg);
1815 if (!g_glTextureManager->GetRunningJobCount()) break;
1816 wxYield();
1817 wxSleep(1);
1818 }
1819
1820 wxString fmsg;
1821 fmsg.Printf("Finished compressor pool drain..Time: %d Job Count: %d",
1822 n_comploop, g_glTextureManager->GetRunningJobCount());
1823 wxLogMessage(fmsg);
1824 }
1825 delete g_glTextureManager;
1826#endif
1827 uninitIXNetSystem();
1828 this->Destroy();
1829 gFrame = NULL;
1830
1831 wxLogMessage("gFrame destroyed.");
1832
1833#ifdef __ANDROID__
1834#ifndef USE_ANDROID_GLES2
1835 qDebug() << "Calling OnExit()";
1836 wxTheApp->OnExit();
1837#endif
1838#endif
1839 wxTheApp->ExitMainLoop();
1840}
1841
1842void MyFrame::OnMove(wxMoveEvent &event) {
1843 auto idx = wxDisplay::GetFromWindow(this);
1844 if (idx != wxNOT_FOUND && g_current_monitor != static_cast<size_t>(idx) &&
1845 static_cast<size_t>(idx) < g_monitor_info.size()) {
1846 g_current_monitor = idx;
1847#ifdef __WXOSX__
1848 // On retina displays there is a difference between the physical size of the
1849 // OpenGL canvas and the DIP This is not observed anywhere else so far, so
1850 // g_current_monitor_dip_px_ratio cna be kept 1.0 everywhere else
1851 if (g_bopengl) {
1853 g_monitor_info[idx].width_px / g_monitor_info[idx].width;
1854 }
1855#endif
1856 DEBUG_LOG << "Moved to " << idx
1857#if wxCHECK_VERSION(3, 1, 6)
1858 << " PPI: " << wxDisplay(idx).GetPPI().GetX() << "x"
1859 << wxDisplay(idx).GetPPI().GetY()
1860 << " SF wxDisplay: " << wxDisplay(idx).GetScaleFactor()
1861#endif
1862 << " Size wxDisplay: " << wxDisplay(idx).GetGeometry().GetWidth()
1863 << "x" << wxDisplay(idx).GetGeometry().GetHeight()
1864 << " MM wxDisplay: " << wxGetDisplaySizeMM().GetX() << "x"
1865 << wxGetDisplaySizeMM().GetY()
1866 << " Name wxDisplay: " << wxDisplay(idx).GetName().c_str()
1867 << " Real: " << g_monitor_info[idx].width_mm << "x"
1868 << g_monitor_info[idx].height_mm << "mm "
1869 << g_monitor_info[idx].width_mm << "x"
1870 << g_monitor_info[idx].height_mm << "mm "
1871 << g_monitor_info[idx].width << "x" << g_monitor_info[idx].height
1872 << "DIP " << g_monitor_info[idx].width_px << "x"
1873 << g_monitor_info[idx].height_px << "px"
1874 << g_monitor_info[idx].scale << "%";
1875 if (g_config_display_size_manual) {
1876 if (g_config_display_size_mm.size() > static_cast<size_t>(idx)) {
1878 } // Do nothing if the user did not set any value for this monitor
1879 } else {
1880 g_display_size_mm = g_monitor_info[idx].width_mm;
1881 }
1882 }
1883 // ..For each canvas...
1884 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1885 ChartCanvas *cc = g_canvasArray.Item(i);
1886 if (cc) {
1887 cc->SetMUIBarPosition();
1889 }
1890 }
1891
1892#ifdef __WXOSX__
1893 SendSizeEvent();
1894#endif
1895
1896 UpdateGPSCompassStatusBoxes();
1897
1898 if (console && console->IsShown()) PositionConsole();
1899
1900 // If global toolbar is shown, reposition it...
1901 // if (g_MainToolbar) {
1902 // g_MainToolbar->RestoreRelativePosition(g_maintoolbar_x, g_maintoolbar_y);
1903 // g_MainToolbar->Realize();
1904 //}
1905
1906 PositionIENCToolbar();
1907
1908 // Somehow, this method does not work right on Windows....
1909 // g_nframewin_posx = event.GetPosition().x;
1910 // g_nframewin_posy = event.GetPosition().y;
1911
1912 g_nframewin_posx = GetPosition().x;
1913 g_nframewin_posy = GetPosition().y;
1914}
1915
1916void MyFrame::ProcessCanvasResize() {
1917 UpdateGPSCompassStatusBoxes(true);
1918
1919 if (console && console->IsShown()) PositionConsole();
1920
1921 PositionIENCToolbar();
1922
1923#ifndef __ANDROID__
1924 TriggerRecaptureTimer();
1925#endif
1926}
1927
1928void MyFrame::TriggerRecaptureTimer() {
1929 m_recaptureTimer.Start(
1930 1000, wxTIMER_ONE_SHOT); // One second seems enough, on average
1931}
1932
1933void MyFrame::OnRecaptureTimer(wxTimerEvent &event) { /*Raise();*/ }
1934
1935void MyFrame::SetCanvasSizes(wxSize frameSize) {
1936 if (!g_canvasArray.GetCount()) return;
1937
1938#if 0
1939 int cccw = frameSize.x;
1940 int ccch = frameSize.y;
1941#endif
1942
1943 // .. for each canvas...
1944 switch (g_canvasConfig) {
1945 default:
1946 case 0:
1947#if 0
1948 cc = g_canvasArray.Item(0);
1949 if( cc ) {
1950 cc->GetSize( &cur_width, &cur_height );
1951 if( ( cur_width != cccw ) || ( cur_height != ccch ) ) {
1952 if( g_pauimgr->GetPane( cc ).IsOk() )
1953 g_pauimgr->GetPane( cc ).BestSize( cccw, ccch );
1954 else
1955 cc->SetSize( 0, 0, cccw, ccch );
1956 }
1957 }
1958#endif
1959 break;
1960
1961 case 1:
1962#if 0
1963 cc = g_canvasArray.Item(1);
1964 if( cc ) {
1965 int ccw = g_canvasConfigArray.Item(1)->canvasSize.x;
1966 int cch = g_canvasConfigArray.Item(1)->canvasSize.y;
1967
1968 ccw = wxMin(ccw, cccw * 8 / 10);
1969 ccw = wxMax(ccw, cccw * 2 / 10);
1970 if(cccw < 100)
1971 ccw = 20;
1972
1973 g_canvasConfigArray.Item(1)->canvasSize = wxSize(ccw, cch);
1974// g_pauimgr->GetPane(cc).MinSize(cccw * 2 / 10, ccch);
1975
1976#if 1 // ndef __WXMSW__
1977 // wxAUI hack: This is needed to explicietly set a docked pane size
1978 // Set MinSize to desired value, then call wxAuiPaneInfo::Fixed() to
1979 // apply it
1980 g_pauimgr->GetPane(cc).MinSize(ccw, cch);
1981 g_pauimgr->GetPane(cc).Fixed();
1982 g_pauimgr->Update();
1983
1984 //now make resizable again
1985 g_pauimgr->GetPane(cc).Resizable();
1987 //g_pauimgr->Update(); //Deferred
1988 //g_pauimgr->GetPane( cc ).BestSize( ccw, cch );
1989#endif
1990 }
1991#endif
1992
1993 break;
1994 }
1995}
1996
1997void MyFrame::OnIconize(wxIconizeEvent &event) {
1998#if 0
1999 if (g_MainToolbar) {
2000 g_MainToolbar->Show(!event.IsIconized());
2001 }
2002 if (g_iENCToolbar) {
2003 g_iENCToolbar->Show(!event.IsIconized());
2004 }
2005
2006 // .. for each canvas...
2007 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2008 ChartCanvas *cc = g_canvasArray.Item(i);
2009 if (cc && cc->GetMUIBar()) {
2010 if (cc->GetMUIBar()->GetCanvasOptions()) {
2011 if (cc->GetMUIBar()->GetCanvasOptions()->IsShown()) {
2012 cc->GetMUIBar()->PushCanvasOptions(); // hide it
2013 }
2014 }
2015 }
2016 }
2017
2018#endif
2019}
2020
2021void MyFrame::OnSize(wxSizeEvent &event) { ODoSetSize(); }
2022
2023void MyFrame::ODoSetSize() {
2024 int x, y;
2025 GetClientSize(&x, &y);
2026 // Resize the children
2027
2028 if (m_pStatusBar != NULL) {
2029 m_StatusBarFieldCount = g_Platform->GetStatusBarFieldCount();
2030 int currentCount = m_pStatusBar->GetFieldsCount();
2031 if (currentCount != m_StatusBarFieldCount) {
2032 if ((currentCount > 0) && (currentCount < 7)) {
2033 // reset the widths very small to avoid auto-resizing of the frame
2034 // The sizes will be reset later in this method
2035 int widths[] = {2, 2, 2, 2, 2, 2};
2036 m_pStatusBar->SetStatusWidths(currentCount, widths);
2037 }
2038
2039 m_pStatusBar->SetFieldsCount(m_StatusBarFieldCount);
2040 }
2041
2042 if (m_StatusBarFieldCount) {
2043 // If the status bar layout is "complex", meaning more than two columns,
2044 // then use custom crafted relative widths for the fields.
2045 // Otherwise, just split the frame client width into equal spaces
2046
2047 if (m_StatusBarFieldCount > 2) {
2048 int widths[] = {-6, -5, -5, -6, -4};
2049 m_pStatusBar->SetStatusWidths(m_StatusBarFieldCount, widths);
2050 } else if (m_StatusBarFieldCount == 2) {
2051 int cwidth = x * 90 / 100;
2052 int widths[] = {100, 100};
2053 widths[0] = cwidth * 6.4 / 10.0;
2054 widths[1] = cwidth * 3.6 / 10.0;
2055 m_pStatusBar->SetStatusWidths(m_StatusBarFieldCount, widths);
2056 } else {
2057 int widths[] = {100, 100};
2058 widths[0] = x * 90 / 100;
2059 m_pStatusBar->SetStatusWidths(m_StatusBarFieldCount, widths);
2060 }
2061
2062 int styles[] = {wxSB_FLAT, wxSB_FLAT, wxSB_FLAT,
2063 wxSB_FLAT, wxSB_FLAT, wxSB_FLAT};
2064 m_pStatusBar->SetStatusStyles(m_StatusBarFieldCount, styles);
2065
2066 wxString sogcog("SOG --- " + getUsrSpeedUnit() + +" " +
2067 " COG ---\u00B0");
2068 m_pStatusBar->SetStatusText(sogcog, STAT_FIELD_SOGCOG);
2069 }
2070 }
2071
2072 if (m_pStatusBar) {
2073 // Maybe resize the font so the text fits in the boxes
2074
2075 wxRect stat_box;
2076 m_pStatusBar->GetFieldRect(0, stat_box);
2077 // maximum size is 1/28 of the box width, or the box height - whicever is
2078 // less
2079 int max_font_size = wxMin((stat_box.width / 28), (stat_box.height));
2080
2081 wxFont sys_font = *wxNORMAL_FONT;
2082 int try_font_size = sys_font.GetPointSize();
2083
2084#ifdef __WXOSX__
2085 int min_font_size = 10; // much less than 10pt is unreadably small on OS X
2086 try_font_size += 1; // default to 1pt larger than system UI font
2087#else
2088 int min_font_size =
2089 7; // on Win/Linux the text does not shrink quite so fast
2090 try_font_size += 2; // default to 2pt larger than system UI font
2091#endif
2092
2093 // get the user's preferred font, or if none set then the system default
2094 // with the size overridden
2095 wxFont *statusBarFont =
2096 FontMgr::Get().GetFont(_("StatusBar"), try_font_size);
2097 int font_size = statusBarFont->GetPointSize();
2098
2099 font_size = wxMin(font_size,
2100 max_font_size); // maximum to fit in the statusbar boxes
2101 font_size =
2102 wxMax(font_size, min_font_size); // minimum to stop it being unreadable
2103
2104#ifdef __ANDROID__
2105 font_size = statusBarFont->GetPointSize();
2106#endif
2107
2108 // Accomodate HDPI displays
2109 font_size /= OCPN_GetDisplayContentScaleFactor();
2110
2111 wxFont *pstat_font = FontMgr::Get().FindOrCreateFont(
2112 font_size, statusBarFont->GetFamily(), statusBarFont->GetStyle(),
2113 statusBarFont->GetWeight(), false, statusBarFont->GetFaceName());
2114
2115 int min_height = stat_box.height;
2116
2117 m_pStatusBar->SetFont(*pstat_font);
2118 m_pStatusBar->SetForegroundColour(
2119 FontMgr::Get().GetFontColor(_("StatusBar")));
2120#ifdef __ANDROID__
2121 min_height = (pstat_font->GetPointSize() * getAndroidDisplayDensity()) + 10;
2122 min_height =
2123 (min_height >> 1) * 2; // force even number, makes GLCanvas happier...
2124 m_pStatusBar->SetMinHeight(min_height);
2125// qDebug() <<"StatusBar min height:" << min_height << "StatusBar font
2126// points:" << pstat_font->GetPointSize();
2127#endif
2128 // wxString msg;
2129 // msg.Printf(_T("StatusBar min height: %d StatusBar font points:
2130 // %d"), min_height, pstat_font->GetPointSize()); wxLogMessage(msg);
2131 }
2132
2133 SetCanvasSizes(GetClientSize());
2134
2135 UpdateGPSCompassStatusBoxes(true);
2136
2137 if (console) PositionConsole();
2138
2139 // .. for each canvas...
2140 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2141 ChartCanvas *cc = g_canvasArray.Item(i);
2142 if (cc) cc->FormatPianoKeys();
2143 }
2144
2145 // If global toolbar is shown, resize it...
2146 if (g_MainToolbar) {
2147 wxSize szBefore = g_MainToolbar->GetToolbarSize();
2148 g_MainToolbar->SetGeometry(GetPrimaryCanvas()->GetCompass()->IsShown(),
2149 GetPrimaryCanvas()->GetCompass()->GetRect());
2150 g_MainToolbar->Realize();
2151
2152 if (szBefore != g_MainToolbar->GetToolbarSize())
2153 g_MainToolbar->RefreshToolbar();
2154 }
2155
2156 // Update the stored window size
2157 GetSize(&x, &y);
2158 g_nframewin_x = x;
2159 g_nframewin_y = y;
2160
2161 // Inform the PlugIns
2162 if (g_pi_manager) g_pi_manager->SendResizeEventToAllPlugIns(x, y);
2163
2164 // Force redraw if in lookahead mode
2165 // TODO is this all right?
2166 // if( g_bLookAhead ) {
2167 // DoCOGSet();
2168 // DoChartUpdate();
2169 // }
2170
2171 // FIXME (dave) Thumbwins are gone...
2172 // if (pthumbwin) pthumbwin->SetMaxSize(GetClientSize());
2173
2174 // Reset the options dialog size logic
2175 options_lastWindowSize = wxSize(0, 0);
2176 options_lastWindowPos = wxPoint(0, 0);
2177
2178#ifdef __ANDROID__
2179 // If the options dialog is displayed, this will have the effect of
2180 // raising the dialog above the main and canvas-GUI toolbars.
2181 // If the dialog is not shown, no harm done
2182
2183 if (!b_inCloseWindow) {
2184 if (g_options) g_options->Raise();
2185
2186 resizeAndroidPersistents();
2187 }
2188
2189#endif
2190 if (GetPrimaryCanvas() && GetPrimaryCanvas()->GetNotificationsList()) {
2191 GetPrimaryCanvas()->GetNotificationsList()->RecalculateSize();
2192 }
2193
2194 if (g_pauimgr) g_pauimgr->Update();
2195}
2196
2197void MyFrame::PositionConsole() {
2198#if defined(__WXMSW__) || defined(__WXMAC__)
2199 if (NULL == GetPrimaryCanvas()) return;
2200 // Reposition console based on its size and chartcanvas size
2201 int ccx, ccy, ccsx, ccsy, consx, consy;
2202 ChartCanvas *consoleHost = GetPrimaryCanvas();
2203 if (g_canvasConfig > 0) consoleHost = g_canvasArray[1];
2204
2205 if (consoleHost) {
2206 consoleHost->GetSize(&ccsx, &ccsy);
2207 consoleHost->GetPosition(&ccx, &ccy);
2208 } else {
2209 GetPrimaryCanvas()->GetSize(&ccsx, &ccsy);
2210 GetPrimaryCanvas()->GetPosition(&ccx, &ccy);
2211 consoleHost = GetPrimaryCanvas();
2212 }
2213
2214 int yOffset = 60;
2215 if (consoleHost) {
2216 if (consoleHost->GetCompass()) {
2217 wxRect compass_rect = consoleHost->GetCompass()->GetRect();
2218 // Compass is normal upper right position.
2219 if (compass_rect.y < 100)
2220 yOffset = compass_rect.y + compass_rect.height + 45;
2221 }
2222 }
2223
2224 wxSize csz = console->GetSize();
2225 consx = csz.x;
2226 consy = csz.y;
2227
2228 wxPoint screen_pos =
2229 ClientToScreen(wxPoint(ccx + ccsx - consx - 2, ccy + yOffset));
2230 console->Move(screen_pos);
2231#else
2232 if (NULL == GetPrimaryCanvas()) return;
2233 // Reposition console based on its size and chartcanvas size
2234 int ccx, ccy, ccsx, ccsy, consx, consy;
2235 ChartCanvas *consoleHost = GetPrimaryCanvas();
2236 if (g_canvasConfig > 0) consoleHost = g_canvasArray[1];
2237
2238 if (consoleHost) {
2239 consoleHost->GetSize(&ccsx, &ccsy);
2240 consoleHost->GetPosition(&ccx, &ccy);
2241 } else {
2242 GetPrimaryCanvas()->GetSize(&ccsx, &ccsy);
2243 GetPrimaryCanvas()->GetPosition(&ccx, &ccy);
2244 consoleHost = GetPrimaryCanvas();
2245 }
2246
2247 int yTopOffset = 60;
2248 int yBottomOffset = 0;
2249 if (consoleHost) {
2250 if (consoleHost->GetCompass()) {
2251 wxRect compass_rect = consoleHost->GetCompass()->GetRect();
2252 // Compass is normal upper right position.
2253 if (compass_rect.y < 100)
2254 yTopOffset = compass_rect.y + compass_rect.height;
2255 }
2256 if (consoleHost->GetMUIBar()) {
2257 wxRect mui_rect = consoleHost->GetMUIBarRect();
2258 yBottomOffset = ccsy - mui_rect.y;
2259 }
2260 }
2261
2262 wxSize csz = console->GetSize();
2263 consx = csz.x;
2264 consy = csz.y;
2265 int yAvail = ccsy - (yTopOffset + yBottomOffset);
2266 int yFinal = 30;
2267 if (consy < yAvail) {
2268 yFinal = (yAvail - consy) / 2;
2269 yFinal += yTopOffset;
2270 } else if (console->GetCDI()->IsShown()) {
2271 int cdi_height = console->GetCDI()->GetSize().y;
2272 int consy_no_cdi = consy - cdi_height;
2273 yFinal = (yAvail - consy_no_cdi) / 2;
2274 yFinal += yTopOffset;
2275 console->ToggleShowHighway();
2276 }
2277
2278 wxPoint in_canvas_pos = wxPoint(ccsx - consx - 2, yFinal);
2279 console->Move(in_canvas_pos);
2280#endif
2281}
2282
2283void MyFrame::UpdateAllFonts() {
2284 if (console) {
2285 console->UpdateFonts();
2286 // Reposition console
2287 PositionConsole();
2288 }
2289
2290 // Close and destroy any persistent dialogs, so that new fonts will be
2291 // utilized
2292 DestroyPersistentDialogs();
2293
2294 if (pWayPointMan) pWayPointMan->ClearRoutePointFonts();
2295
2296 RefreshAllCanvas();
2297}
2298
2299void MyFrame::DestroyPersistentDialogs() {
2300 if (g_pais_query_dialog_active) {
2301 g_pais_query_dialog_active->Hide();
2302 g_pais_query_dialog_active->Destroy();
2303 g_pais_query_dialog_active = NULL;
2304 }
2305
2306 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog) {
2307 pRoutePropDialog->Hide();
2308 pRoutePropDialog->Destroy();
2309 pRoutePropDialog = NULL;
2310 }
2311
2312 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog) {
2313 pTrackPropDialog->Hide();
2314 pTrackPropDialog->Destroy();
2315 pTrackPropDialog = NULL;
2316 }
2317
2318 if (g_pMarkInfoDialog) {
2319 g_pMarkInfoDialog->Hide();
2320 g_pMarkInfoDialog->Destroy();
2321 g_pMarkInfoDialog = NULL;
2322 }
2323
2325 g_pObjectQueryDialog->Hide();
2326 g_pObjectQueryDialog->Destroy();
2327 g_pObjectQueryDialog = NULL;
2328 }
2329}
2330
2331void MyFrame::RefreshGroupIndices() {
2332 // ..For each canvas...
2333 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2334 ChartCanvas *cc = g_canvasArray.Item(i);
2335 if (cc) cc->canvasRefreshGroupIndex();
2336 }
2337}
2338
2339void MyFrame::OnToolLeftClick(wxCommandEvent &event) {
2340 if (g_MainToolbar) g_MainToolbar->HideTooltip();
2341
2342 switch (event.GetId()) {
2343 case ID_MENU_SCALE_OUT:
2344 DoStackDelta(GetPrimaryCanvas(), 1);
2345 DoChartUpdate();
2346 break;
2347
2348 case ID_MENU_SCALE_IN:
2349 DoStackDelta(GetPrimaryCanvas(), -1);
2350 DoChartUpdate();
2351 break;
2352
2353 case ID_MENU_ZOOM_IN: {
2354 if (GetFocusCanvas()) {
2355 GetFocusCanvas()->ZoomCanvas(g_plus_minus_zoom_factor, false);
2356 }
2357 break;
2358 }
2359
2360 case ID_MENU_ZOOM_OUT: {
2361 if (GetFocusCanvas()) {
2362 GetFocusCanvas()->ZoomCanvas(1.0 / g_plus_minus_zoom_factor, false);
2363 }
2364 break;
2365 }
2366
2367 case ID_MENU_ROUTE_NEW: {
2368 if (GetFocusCanvas()) {
2369 if (0 == GetFocusCanvas()->m_routeState) {
2370 GetFocusCanvas()->StartRoute();
2371 } else {
2372 GetFocusCanvas()->FinishRoute();
2373 }
2374 }
2375 break;
2376 }
2377
2378 case ID_MENU_TOOL_MEASURE: {
2379 GetPrimaryCanvas()->StartMeasureRoute();
2380 break;
2381 }
2382
2383 case ID_MENU_TOOL_NMEA_DBG_LOG:
2384 m_data_monitor->Show();
2385 m_data_monitor->Raise();
2386 break;
2387
2388 case ID_MENU_TOOL_IO_MONITOR:
2389 m_data_monitor->Show();
2390 break;
2391
2392 case ID_MENU_MARK_BOAT: {
2393 DropMarker(true);
2394 break;
2395 }
2396
2397 case ID_MENU_MARK_CURSOR: {
2398 DropMarker(false);
2399 break;
2400 }
2401
2402 case ID_MENU_NAV_FOLLOW: {
2403 if (gFrame->GetPrimaryCanvas())
2404 gFrame->GetPrimaryCanvas()->TogglebFollow();
2405 break;
2406 }
2407
2408 case ID_MENU_CHART_OUTLINES: {
2409 ToggleChartOutlines(GetFocusCanvas());
2410 break;
2411 }
2412
2413 case ID_MENU_CHART_QUILTING: {
2414 ToggleQuiltMode(GetFocusCanvas());
2415 break;
2416 }
2417
2418 case ID_MENU_UI_CHARTBAR: {
2419 ToggleChartBar(GetFocusCanvas());
2420 break;
2421 }
2422
2423 case ID_MENU_ENC_TEXT:
2424 case ID_ENC_TEXT: {
2425 ToggleENCText(GetFocusCanvas());
2426 break;
2427 }
2428 case ID_MENU_ENC_LIGHTS: {
2429 ToggleLights(GetFocusCanvas());
2430 break;
2431 }
2432 case ID_MENU_ENC_SOUNDINGS: {
2433 ToggleSoundings(GetFocusCanvas());
2434 break;
2435 }
2436 case ID_MENU_ENC_ANCHOR: {
2437 ToggleAnchor(GetFocusCanvas());
2438 break;
2439 }
2440 case ID_MENU_ENC_DATA_QUALITY: {
2441 ToggleDataQuality(GetFocusCanvas());
2442 break;
2443 }
2444 case ID_MENU_SHOW_NAVOBJECTS: {
2445 ToggleNavobjects(GetFocusCanvas());
2446 break;
2447 }
2448
2449 case ID_MENU_AIS_TARGETS: {
2450 ToggleAISDisplay(GetFocusCanvas());
2451 break;
2452 }
2453 case ID_MENU_AIS_MOORED_TARGETS: {
2454 g_bHideMoored = !g_bHideMoored;
2455 break;
2456 }
2457 case ID_MENU_AIS_SCALED_TARGETS: {
2458 ToggleAISMinimizeTargets(GetFocusCanvas());
2459 break;
2460 }
2461
2462 case ID_MENU_AIS_TARGETLIST: {
2463 if (GetPrimaryCanvas()) GetPrimaryCanvas()->ShowAISTargetList();
2464 break;
2465 }
2466
2467 case ID_MENU_AIS_TRACKS: {
2468 g_bAISShowTracks = !g_bAISShowTracks;
2469 SetMenubarItemState(ID_MENU_AIS_TRACKS, g_bAISShowTracks);
2470 break;
2471 }
2472
2473 case ID_MENU_AIS_CPADIALOG: {
2474 g_bAIS_CPA_Alert = !g_bAIS_CPA_Alert;
2475 SetMenubarItemState(ID_MENU_AIS_CPADIALOG, g_bAIS_CPA_Alert);
2476 m_pMenuBar->Enable(ID_MENU_AIS_CPASOUND, g_bAIS_CPA_Alert);
2477 if (g_bAIS_CPA_Alert) {
2478 SetMenubarItemState(ID_MENU_AIS_CPASOUND, g_bAIS_CPA_Alert_Audio);
2479 }
2480 break;
2481 }
2482
2483 case ID_MENU_AIS_CPASOUND: {
2484 g_bAIS_CPA_Alert_Audio = !g_bAIS_CPA_Alert_Audio;
2485 SetMenubarItemState(ID_MENU_AIS_CPASOUND, g_bAIS_CPA_Alert_Audio);
2486 break;
2487 }
2488
2489 case ID_MENU_AIS_CPAWARNING: {
2490 if (GetPrimaryCanvas()) GetPrimaryCanvas()->ToggleCPAWarn();
2491 SetMenubarItemState(ID_MENU_AIS_CPAWARNING, g_bCPAWarn);
2492 break;
2493 }
2494
2495 case wxID_PREFERENCES:
2496 case ID_SETTINGS: {
2497 g_MainToolbar->HideTooltip();
2498 DoSettings();
2499 break;
2500 }
2501
2502 case ID_SETTINGS_NEW: {
2503 DoSettingsNew();
2504 break;
2505 }
2506
2507 case ID_SETTINGS_DELETE: {
2508 delete g_options;
2509 g_options = nullptr;
2510 g_pOptions = nullptr;
2511 break;
2512 }
2513
2514 case ID_RELOAD_CHARTS: {
2515 ReloadAllVP();
2516 break;
2517 }
2518
2519 case ID_MENU_SETTINGS_BASIC: {
2520#ifdef __ANDROID__
2521 androidDisableFullScreen();
2522 g_MainToolbar->HideTooltip();
2523 DoAndroidPreferences();
2524#else
2525 DoSettings();
2526#endif
2527 break;
2528 }
2529
2530 case ID_MENU_UI_FULLSCREEN: {
2531 ToggleFullScreen();
2532 break;
2533 }
2534
2535 case ID_MENU_SHOW_CURRENTS: {
2536 GetFocusCanvas()->ShowCurrents(!GetFocusCanvas()->GetbShowCurrent());
2537 GetFocusCanvas()->ReloadVP();
2538 GetFocusCanvas()->Refresh(false);
2539 break;
2540 }
2541
2542 case ID_MENU_SHOW_TIDES: {
2543 GetFocusCanvas()->ShowTides(!GetFocusCanvas()->GetbShowTide());
2544 GetFocusCanvas()->ReloadVP();
2545 GetFocusCanvas()->Refresh(false);
2546 break;
2547 }
2548
2549 case wxID_ABOUT:
2550 case ID_ABOUT: {
2551 DoHelpDialog();
2552 break;
2553 }
2554
2555 case wxID_HELP: {
2556 LaunchLocalHelp();
2557 break;
2558 }
2559
2560 case ID_PRINT: {
2561 DoPrint();
2562 break;
2563 }
2564
2565 case ID_MENU_UI_COLSCHEME:
2566 case ID_COLSCHEME: {
2567 ToggleColorScheme();
2568 break;
2569 }
2570
2571 case ID_TBEXIT: {
2572 Close();
2573 break;
2574 }
2575
2576 case ID_MENU_OQUIT: {
2577 Close();
2578 break;
2579 }
2580
2581 case ID_MENU_ROUTE_MANAGER:
2582 case ID_ROUTEMANAGER: {
2583 pRouteManagerDialog = RouteManagerDialog::getInstance(
2584 this); // There is one global instance of the Dialog
2585
2586 if (pRouteManagerDialog->IsShown())
2587 pRouteManagerDialog->Hide();
2588 else {
2589 pRouteManagerDialog->UpdateRouteListCtrl();
2590 pRouteManagerDialog->UpdateTrkListCtrl();
2591 pRouteManagerDialog->UpdateWptListCtrl();
2592 pRouteManagerDialog->UpdateLayListCtrl();
2593
2594 pRouteManagerDialog->Show();
2595
2596 // Required if RMDialog is not STAY_ON_TOP
2597#ifdef __WXOSX__
2598 pRouteManagerDialog->Centre();
2599 pRouteManagerDialog->Raise();
2600#endif
2601 }
2602 break;
2603 }
2604
2605 case ID_MENU_NAV_TRACK:
2606 case ID_TRACK: {
2607 if (!g_bTrackActive) {
2608 TrackOn();
2609 g_bTrackCarryOver = true;
2610 } else {
2611 TrackOff(true); // catch the last point
2612 g_bTrackCarryOver = false;
2613 RefreshAllCanvas(true);
2614 }
2615 break;
2616 }
2617
2618 case ID_MENU_CHART_NORTHUP: {
2619 SetUpMode(GetPrimaryCanvas(), NORTH_UP_MODE);
2620 break;
2621 }
2622 case ID_MENU_CHART_COGUP: {
2623 SetUpMode(GetPrimaryCanvas(), COURSE_UP_MODE);
2624 break;
2625 }
2626 case ID_MENU_CHART_HEADUP: {
2627 SetUpMode(GetPrimaryCanvas(), HEAD_UP_MODE);
2628 break;
2629 }
2630
2631 case ID_MENU_MARK_MOB:
2632 case ID_MOB: {
2633 ActivateMOB();
2634 break;
2635 }
2636
2637 case ID_MASTERTOGGLE: {
2638 if (g_MainToolbar) {
2639 wxString tip = _("Show Toolbar");
2640 if (!g_bmasterToolbarFull) tip = _("Hide Toolbar");
2641 if (g_MainToolbar->GetToolbar())
2642 g_MainToolbar->GetToolbar()->SetToolShortHelp(ID_MASTERTOGGLE, tip);
2643
2644 g_bmasterToolbarFull = !g_bmasterToolbarFull;
2645
2646#ifdef __WXOSX__
2647 if (g_bmasterToolbarFull)
2648 m_nMasterToolCountShown =
2649 g_MainToolbar->GetToolCount() -
2650 1; // TODO disable animation on OSX. Maybe use fade effect?
2651 else
2652 m_nMasterToolCountShown = 2;
2653#else
2654 m_nMasterToolCountShown =
2655 g_MainToolbar->GetToolShowCount(); // Current state
2656#endif
2657 ToolbarAnimateTimer.Start(10, wxTIMER_ONE_SHOT);
2658 }
2659 break;
2660 }
2661
2662 // Various command events coming from (usually) other threads,
2663 // used to control OCPN modes in a thread-safe way.
2664
2665 case ID_CMD_SELECT_CHART_TYPE: {
2666 selectChartDisplay(event.GetExtraLong(), -1);
2667 break;
2668 }
2669
2670 case ID_CMD_SELECT_CHART_FAMILY: {
2671 selectChartDisplay(-1, event.GetExtraLong());
2672 break;
2673 }
2674
2675 case ID_CMD_APPLY_SETTINGS: {
2676 applySettingsString(event.GetString());
2677#ifdef __ANDROID__
2678 androidRestoreFullScreen();
2679#endif
2680
2681 break;
2682 }
2683
2684 case ID_CMD_NULL_REFRESH: {
2685 Refresh(true);
2686 break;
2687 }
2688
2689 case ID_CMD_SETVP: {
2690 setStringVP(event.GetString());
2691 break;
2692 }
2693
2694 case ID_CMD_INVALIDATE: {
2695 InvalidateAllGL();
2696 Refresh(true);
2697 break;
2698 }
2699
2700 case ID_CMD_POST_JSON_TO_PLUGINS: {
2701 // Extract the Message ID which is embedded in the JSON string passed in
2702 // the event
2703 wxJSONValue root;
2704 wxJSONReader reader;
2705
2706 int numErrors = reader.Parse(event.GetString(), &root);
2707 if (numErrors == 0) {
2708 if (root["MessageID"].IsString()) {
2709 wxString MsgID = root["MessageID"].AsString();
2710 SendPluginMessage(MsgID, event.GetString()); // Send to all PlugIns
2711 }
2712 }
2713
2714 break;
2715 }
2716
2717 case ID_DENSITY:
2718 case ID_RMINUS:
2719 case ID_RPLUS: {
2720 if (g_iENCToolbar) {
2721 g_iENCToolbar->OnToolLeftClick(event);
2722 }
2723 break;
2724 }
2725
2726 default: {
2727 // Look for PlugIn tools
2728 // If found, make the callback.
2729 // TODO Modify this to allow multiple tools per plugin
2730 if (g_pi_manager) {
2731 g_MainToolbar->HideTooltip();
2732
2733 ArrayOfPlugInToolbarTools tool_array =
2734 g_pi_manager->GetPluginToolbarToolArray();
2735 for (unsigned int i = 0; i < tool_array.size(); i++) {
2736 PlugInToolbarToolContainer *pttc = tool_array[i];
2737 if (event.GetId() == pttc->id) {
2738 if (pttc->m_pplugin)
2739 pttc->m_pplugin->OnToolbarToolCallback(pttc->id);
2740 return; // required to prevent event.Skip() being called
2741 }
2742 }
2743 }
2744
2745 // If we didn't handle the event, allow it to bubble up to other handlers.
2746 // This is required for the system menu items (Hide, etc.) on OS X to
2747 // work. This must only be called if we did NOT handle the event,
2748 // otherwise it stops the menu items from working on Windows.
2749 event.Skip();
2750
2751 break;
2752 }
2753
2754 } // switch
2755
2756 // Finally, force a refresh of the main toolbar
2757 if (g_MainToolbar) g_MainToolbar->Realize();
2758}
2759
2760bool MyFrame::SetGlobalToolbarViz(bool viz) {
2761 bool viz_now = g_bmasterToolbarFull;
2762
2763 g_MainToolbar->HideTooltip();
2764 wxString tip = _("Show Toolbar");
2765 if (viz) {
2766 tip = _("Hide Toolbar");
2767 if (g_MainToolbar->GetToolbar())
2768 g_MainToolbar->GetToolbar()->SetToolShortHelp(ID_MASTERTOGGLE, tip);
2769 }
2770
2771 bool toggle = false;
2772 if (viz && !g_bmasterToolbarFull)
2773 toggle = true;
2774
2775 else if (!viz && g_bmasterToolbarFull)
2776 toggle = true;
2777
2778 if (toggle) {
2779 g_bmasterToolbarFull = !g_bmasterToolbarFull;
2780
2781#ifdef __WXOSX__
2782 if (g_bmasterToolbarFull)
2783 m_nMasterToolCountShown =
2784 g_MainToolbar->GetToolCount() -
2785 1; // TODO disable animation on OSX. Maybe use fade effect?
2786 else
2787 m_nMasterToolCountShown = 2;
2788#else
2789 m_nMasterToolCountShown =
2790 g_MainToolbar->GetToolShowCount(); // Current state
2791#endif
2792 ToolbarAnimateTimer.Start(10, wxTIMER_ONE_SHOT);
2793 }
2794
2795 return viz_now;
2796}
2797
2798void MyFrame::ScheduleReloadCharts() {
2799 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
2800 evt.SetId(ID_RELOAD_CHARTS);
2801 GetEventHandler()->AddPendingEvent(evt);
2802}
2803
2804void MyFrame::ScheduleDeleteSettingsDialog() {
2805 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
2806 evt.SetId(ID_SETTINGS_DELETE);
2807 GetEventHandler()->AddPendingEvent(evt);
2808}
2809
2810void MyFrame::ScheduleSettingsDialog() {
2811 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
2812 evt.SetId(ID_SETTINGS);
2813 GetEventHandler()->AddPendingEvent(evt);
2814}
2815
2816void MyFrame::ScheduleSettingsDialogNew() {
2817 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
2818 evt.SetId(ID_SETTINGS_NEW);
2819 GetEventHandler()->AddPendingEvent(evt);
2820}
2821
2822void MyFrame::ScheduleReconfigAndSettingsReload(bool reload, bool new_dialog) {
2823 UpdateCanvasConfigDescriptors();
2824
2825 if ((g_canvasConfig > 0) && (last_canvasConfig == 0))
2826 CreateCanvasLayout(true);
2827 else
2828 CreateCanvasLayout();
2829 SendSizeEvent();
2830 g_pauimgr->Update();
2831
2832 ConfigureStatusBar();
2833 wxSize lastOptSize = options_lastWindowSize;
2834 SendSizeEvent();
2835
2836 BuildMenuBar();
2837 SendSizeEvent();
2838 options_lastWindowSize = lastOptSize;
2839
2840 if (reload) {
2841 if (new_dialog)
2842 ScheduleSettingsDialogNew();
2843 else
2844 ScheduleSettingsDialog();
2845 }
2846 // Trying to reload the previously displayed chart by name as saved in
2847 // pathArray Also, restoring the previous chart VPScale, if possible
2848 // ..For each canvas...
2849 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2850 ChartCanvas *cc = g_canvasArray.Item(i);
2851 if (cc) {
2852 int index_hint = -1;
2853 if (i < pathArray.GetCount())
2854 index_hint = ChartData->FinddbIndex(pathArray.Item(i));
2855 cc->canvasChartsRefresh(index_hint);
2856 if (index_hint != -1) cc->SetVPScale(restoreScale[i]);
2857 }
2858 }
2859}
2860
2861ChartCanvas *MyFrame::GetFocusCanvas() {
2862 if ((g_canvasConfig != 0) && g_focusCanvas) // multi-canvas?
2863 return g_focusCanvas;
2864 else
2865 return GetPrimaryCanvas();
2866}
2867
2868void MyFrame::OnToolbarAnimateTimer(wxTimerEvent &event) {
2869 if (g_bmasterToolbarFull) {
2870#ifndef OCPN_TOOLBAR_ANIMATE
2871 m_nMasterToolCountShown = (int)g_MainToolbar->GetToolCount();
2872#endif
2873
2874 if (m_nMasterToolCountShown < (int)g_MainToolbar->GetToolCount()) {
2875 m_nMasterToolCountShown++;
2876 g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
2877 g_MainToolbar->Realize();
2878 g_MainToolbar->RefreshToolbar();
2879
2880 ToolbarAnimateTimer.Start(20, wxTIMER_ONE_SHOT);
2881 } else {
2882 g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
2883 g_MainToolbar->GetToolbar()->InvalidateBitmaps();
2884 g_MainToolbar->Realize();
2885 g_MainToolbar->RefreshToolbar();
2886 }
2887 } else {
2888#ifndef OCPN_TOOLBAR_ANIMATE
2889 m_nMasterToolCountShown = 1;
2890#endif
2891 if (m_nMasterToolCountShown > 1) {
2892 m_nMasterToolCountShown--;
2893 g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
2894 g_MainToolbar->Realize();
2895 g_MainToolbar->RefreshToolbar();
2896 ToolbarAnimateTimer.Start(10, wxTIMER_ONE_SHOT);
2897 } else {
2898 g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
2899 g_MainToolbar->GetToolbar()->InvalidateBitmaps();
2900 g_MainToolbar->Realize();
2901 g_MainToolbar->RefreshToolbar();
2902 }
2903 }
2904}
2905
2906void MyFrame::InvalidateAllGL() {
2907#ifdef ocpnUSE_GL
2908 // For each canvas
2909 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2910 ChartCanvas *cc = g_canvasArray.Item(i);
2911 if (cc) {
2912 cc->InvalidateGL();
2913 cc->Refresh();
2914 }
2915 }
2916#endif
2917}
2918
2919void MyFrame::RefreshAllCanvas(bool bErase) {
2920 // For each canvas
2921 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2922 ChartCanvas *cc = g_canvasArray.Item(i);
2923 if (cc) {
2924 cc->Refresh(bErase);
2925 }
2926 }
2927}
2928
2929void MyFrame::setStringVP(wxString VPS) {
2930 ChartCanvas *cc = GetPrimaryCanvas();
2931
2932 if (!cc) return;
2933
2934 wxStringTokenizer tkz(VPS, ";");
2935
2936 wxString token = tkz.GetNextToken();
2937 double lat = gLat;
2938 token.ToDouble(&lat);
2939
2940 token = tkz.GetNextToken();
2941 double lon = gLon;
2942 token.ToDouble(&lon);
2943
2944 token = tkz.GetNextToken();
2945 double scale_ppm = cc->GetVP().view_scale_ppm;
2946 token.ToDouble(&scale_ppm);
2947
2948 cc->SetViewPoint(lat, lon, scale_ppm, 0, cc->GetVPRotation());
2949}
2950
2951void MyFrame::DoSettingsNew() {
2952 delete g_options;
2953 g_options = nullptr;
2954
2955 DoSettings();
2956}
2957
2958void MyFrame::DoSettings() {
2959 LoadS57();
2960 DoOptionsDialog();
2961
2962 // Apply various system settings
2963 ApplyGlobalSettings(true);
2964
2965 // ..For each canvas...
2966 bool b_loadHarmonics = false;
2967 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
2968 ChartCanvas *cc = g_canvasArray.Item(i);
2969 if (cc) {
2970 if (cc->GetbShowCurrent() || cc->GetbShowTide()) b_loadHarmonics = true;
2971 }
2972 }
2973 if (b_loadHarmonics) LoadHarmonics();
2974
2975 // The chart display options may have changed, especially on S57 ENC,
2976 // So, flush the cache and redraw
2977 ReloadAllVP();
2978}
2979
2980void MyFrame::ToggleChartBar(ChartCanvas *cc) {
2981 g_bShowChartBar = !g_bShowChartBar;
2982
2983 if (g_bShowChartBar) cc->m_brepaint_piano = true;
2984
2985 cc->ReloadVP(); // needed to set VP.pix_height
2986 Refresh();
2987
2988 if (g_bShowChartBar) {
2989 DoChartUpdate();
2990 UpdateControlBar(cc);
2991 }
2992
2993 SetMenubarItemState(ID_MENU_UI_CHARTBAR, g_bShowChartBar);
2994}
2995
2996void MyFrame::ToggleColorScheme() {
2997 static bool lastIsNight;
2998 ColorScheme s = user_colors::GetColorScheme();
2999 int is = (int)s;
3000 is++;
3001 if (lastIsNight && is == 3) // Back from step 3
3002 {
3003 is = 1;
3004 lastIsNight = false;
3005 } // Goto to Day
3006 if (lastIsNight) is = 2; // Back to Dusk on step 3
3007 if (is == 3) lastIsNight = true; // Step 2 Night
3008 s = (ColorScheme)is;
3009 if (s == N_COLOR_SCHEMES) s = GLOBAL_COLOR_SCHEME_RGB;
3010
3011 SetAndApplyColorScheme(s);
3012}
3013
3014void MyFrame::ToggleFullScreen() {
3015 bool to = !IsFullScreen();
3016
3017#ifdef __WXOSX__
3018 ShowFullScreen(to);
3019#else
3020 long style = wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION;
3021 ; // | wxFULLSCREEN_NOMENUBAR;
3022 ShowFullScreen(to, style);
3023#endif
3024
3025 UpdateAllToolbars(global_color_scheme);
3026 // SurfaceAllCanvasToolbars();
3027 UpdateControlBar(GetPrimaryCanvas());
3028 Layout();
3029 TriggerRecaptureTimer();
3030}
3031
3032void MyFrame::ActivateMOB() {
3033 // The MOB point
3034 wxDateTime mob_time = wxDateTime::Now();
3035 wxString mob_label(_("MAN OVERBOARD"));
3036 mob_label += _(" on ");
3037 mob_label += ocpn::toUsrDateTimeFormat(mob_time);
3038
3039 RoutePoint *pWP_MOB =
3040 new RoutePoint(gLat, gLon, "mob", mob_label, wxEmptyString);
3041 pWP_MOB->SetShared(true);
3042 pWP_MOB->m_bIsolatedMark = true;
3043 pWP_MOB->SetWaypointArrivalRadius(
3044 -1.0); // Negative distance is code to signal "Never Arrive"
3045 pWP_MOB->SetUseSca(false); // Do not use scaled hiding for MOB
3046 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_MOB);
3047 NavObj_dB::GetInstance().InsertRoutePoint(pWP_MOB);
3048
3049 if (bGPSValid && !std::isnan(gCog) && !std::isnan(gSog)) {
3050 // Create a point that is one mile along the present course
3051 double zlat, zlon;
3052 ll_gc_ll(gLat, gLon, gCog, 1.0, &zlat, &zlon);
3053
3054 RoutePoint *pWP_src =
3055 new RoutePoint(zlat, zlon, g_default_wp_icon,
3056 wxString(_("1.0 NM along COG")), wxEmptyString);
3057 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP_src);
3058
3059 Route *temp_route = new Route();
3060 pRouteList->push_back(temp_route);
3061
3062 temp_route->AddPoint(pWP_src);
3063 temp_route->AddPoint(pWP_MOB);
3064
3065 pSelect->AddSelectableRouteSegment(gLat, gLon, zlat, zlon, pWP_src, pWP_MOB,
3066 temp_route);
3067
3068 temp_route->m_RouteNameString = _("Temporary MOB Route");
3069 temp_route->m_RouteStartString = _("Assumed 1 Mile Point");
3070 ;
3071 temp_route->m_RouteEndString = mob_label;
3072
3073 temp_route->m_bDeleteOnArrival = false;
3074
3075 temp_route->SetRouteArrivalRadius(-1.0); // never arrives
3076
3077 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
3078 g_pRouteMan->ActivateRoute(temp_route, pWP_MOB);
3079
3080 wxJSONValue v;
3081 v["GUID"] = temp_route->m_GUID;
3082 wxString msg_id("OCPN_MAN_OVERBOARD");
3083 SendJSONMessageToAllPlugins(msg_id, v);
3084 }
3085
3086 if (RouteManagerDialog::getInstanceFlag()) {
3087 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
3088 pRouteManagerDialog->UpdateRouteListCtrl();
3089 pRouteManagerDialog->UpdateWptListCtrl();
3090 }
3091 }
3092
3093 InvalidateAllGL();
3094 RefreshAllCanvas(false);
3095
3096 wxString mob_message(_("MAN OVERBOARD"));
3097 mob_message += _(" Time: ");
3098 mob_message += ocpn::toUsrDateTimeFormat(mob_time);
3099 mob_message += _(" Position: ");
3100 mob_message += toSDMM(1, gLat);
3101 mob_message += " ";
3102 mob_message += toSDMM(2, gLon);
3103 wxLogMessage(mob_message);
3104}
3105void MyFrame::TrackOn() {
3106 g_bTrackActive = true;
3108
3109 g_TrackList.push_back(g_pActiveTrack);
3110 NavObj_dB::GetInstance().InsertTrack(g_pActiveTrack);
3111 g_pActiveTrack->Start();
3112
3113 // The main toolbar may still be NULL here, and we will do nothing...
3114 SetMasterToolbarItemState(ID_TRACK, g_bTrackActive);
3115 if (g_MainToolbar)
3116 g_MainToolbar->SetToolShortHelp(ID_TRACK, _("Disable Tracking"));
3117
3118 SetMenubarItemState(ID_MENU_NAV_TRACK, g_bTrackActive);
3119
3120#ifdef __ANDROID__
3121 androidSetTrackTool(true);
3122#endif
3123
3124 if (RouteManagerDialog::getInstanceFlag()) {
3125 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
3126 pRouteManagerDialog->UpdateTrkListCtrl();
3127 pRouteManagerDialog->UpdateRouteListCtrl();
3128 }
3129 }
3130
3131 wxJSONValue v;
3132 wxString name = g_pActiveTrack->GetName();
3133 if (name.IsEmpty()) {
3134 TrackPoint *tp = g_pActiveTrack->GetPoint(0);
3135 if (tp->GetCreateTime().IsValid())
3136 name = tp->GetCreateTime().FormatISODate() + " " +
3137 tp->GetCreateTime().FormatISOTime();
3138 else
3139 name = _("(Unnamed Track)");
3140 }
3141 v["Name"] = name;
3142 v["GUID"] = g_pActiveTrack->m_GUID;
3143 wxString msg_id("OCPN_TRK_ACTIVATED");
3144 SendJSONMessageToAllPlugins(msg_id, v);
3145 g_FlushNavobjChangesTimeout =
3146 30; // Every thirty seconds, consider flushing navob changes
3147}
3148
3149Track *MyFrame::TrackOff(bool do_add_point) {
3150 Track *return_val = g_pActiveTrack;
3151
3152 if (g_pActiveTrack) {
3153 wxJSONValue v;
3154 wxString msg_id("OCPN_TRK_DEACTIVATED");
3155 v["GUID"] = g_pActiveTrack->m_GUID;
3156 SendJSONMessageToAllPlugins(msg_id, v);
3157
3158 g_pActiveTrack->Stop(do_add_point);
3159
3160 if (g_pActiveTrack->GetnPoints() < 2) {
3161 NavObj_dB::GetInstance().DeleteTrack(g_pActiveTrack);
3162 RoutemanGui(*g_pRouteMan).DeleteTrack(g_pActiveTrack);
3163 return_val = NULL;
3164 } else {
3165 if (g_bTrackDaily) {
3166 Track *pExtendTrack = g_pActiveTrack->DoExtendDaily();
3167 if (pExtendTrack) {
3168 NavObj_dB::GetInstance().DeleteTrack(g_pActiveTrack);
3169 RoutemanGui(*g_pRouteMan).DeleteTrack(g_pActiveTrack);
3170 NavObj_dB::GetInstance().UpdateTrack(pExtendTrack);
3171 return_val = pExtendTrack;
3172 }
3173 }
3174 }
3175 g_pActiveTrack = NULL;
3176 }
3177
3178 g_bTrackActive = false;
3179
3180 if (RouteManagerDialog::getInstanceFlag()) {
3181 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
3182 pRouteManagerDialog->UpdateTrkListCtrl();
3183 pRouteManagerDialog->UpdateRouteListCtrl();
3184 }
3185 }
3186
3187 SetMasterToolbarItemState(ID_TRACK, g_bTrackActive);
3188 if (g_MainToolbar)
3189 g_MainToolbar->SetToolShortHelp(ID_TRACK, _("Enable Tracking"));
3190 SetMenubarItemState(ID_MENU_NAV_TRACK, g_bTrackActive);
3191
3192#ifdef __ANDROID__
3193 androidSetTrackTool(false);
3194#endif
3195
3196 // Invalidate the rotate tiem
3197 m_target_rotate_time = wxInvalidDateTime;
3198
3199 return return_val;
3200}
3201
3202void MyFrame::InitializeTrackRestart() {
3203 if (!g_bTrackDaily) return;
3204 if (m_target_rotate_time.IsValid()) return;
3205
3206 int rotate_at = 0;
3207 switch (g_track_rotate_time_type) {
3208 case TIME_TYPE_LMT:
3209 rotate_at = g_track_rotate_time + wxRound(gLon * 3600. / 15.);
3210 break;
3211 case TIME_TYPE_COMPUTER:
3212 rotate_at = g_track_rotate_time;
3213 break;
3214 case TIME_TYPE_UTC:
3215 int utc_offset =
3216 wxDateTime::Now().GetTicks() - wxDateTime::Now().ToUTC().GetTicks();
3217 rotate_at = g_track_rotate_time + utc_offset;
3218 break;
3219 }
3220 if (rotate_at > 86400)
3221 rotate_at -= 86400;
3222 else if (rotate_at < 0)
3223 rotate_at += 86400;
3224
3225 wxTimeSpan rotate_seconds = wxTimeSpan(0, 0, rotate_at);
3226 m_target_rotate_time = wxDateTime::Today() + rotate_seconds;
3227
3228 // Avoid restarting immediately
3229 if (wxDateTime::Now().IsLaterThan(m_target_rotate_time)) {
3230 m_target_rotate_time += wxTimeSpan(24); // tomorrow, same time.
3231 }
3232}
3233
3234bool MyFrame::ShouldRestartTrack() {
3235 if (!g_pActiveTrack || !g_bTrackDaily) return false;
3236 InitializeTrackRestart();
3237
3238 if (wxDateTime::Now().IsLaterThan(m_target_rotate_time)) {
3239 m_target_rotate_time += wxTimeSpan(24); // tomorrow, same time.
3240 return true;
3241 }
3242 return false;
3243}
3244
3245void MyFrame::TrackDailyRestart() {
3246 if (!g_pActiveTrack) return;
3247 Track *pPreviousTrack = TrackOff(true);
3248 TrackOn();
3249
3250 // Set the restarted track's current state such that the current track
3251 // point's attributes match the attributes of the last point of the track
3252 // that was just stopped at midnight.
3253
3254 if (pPreviousTrack) {
3255 TrackPoint *pMidnightPoint = pPreviousTrack->GetLastPoint();
3256 g_pActiveTrack->AdjustCurrentTrackPoint(pMidnightPoint);
3257 }
3258
3259 if (RouteManagerDialog::getInstanceFlag()) {
3260 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
3261 pRouteManagerDialog->UpdateTrkListCtrl();
3262 pRouteManagerDialog->UpdateRouteListCtrl();
3263 }
3264 }
3265}
3266
3267void MyFrame::SetUpMode(ChartCanvas *cc, int mode) {
3268 if (cc) {
3269 cc->SetUpMode(mode);
3270
3271 SetMenubarItemState(ID_MENU_CHART_COGUP, mode == COURSE_UP_MODE);
3272 SetMenubarItemState(ID_MENU_CHART_NORTHUP, mode == NORTH_UP_MODE);
3273 SetMenubarItemState(ID_MENU_CHART_HEADUP, mode == HEAD_UP_MODE);
3274
3275 if (m_pMenuBar)
3276 m_pMenuBar->SetLabel(ID_MENU_CHART_NORTHUP, _("North Up Mode"));
3277 }
3278}
3279
3280void MyFrame::ToggleENCText(ChartCanvas *cc) {
3281 cc->SetShowENCText(!cc->GetShowENCText());
3282
3283 SetMenubarItemState(ID_MENU_ENC_TEXT, cc->GetShowENCText());
3284
3285 // if(g_pi_manager)
3286 // g_pi_manager->SendConfigToAllPlugIns();
3287
3288 ReloadAllVP();
3289}
3290
3291void MyFrame::SetENCDisplayCategory(ChartCanvas *cc, enum _DisCat nset) {
3292 if (ps52plib) {
3293 if (cc) {
3294 cc->SetENCDisplayCategory(nset);
3295
3296 UpdateGlobalMenuItems();
3297
3298 /* if(g_pi_manager)
3299 g_pi_manager->SendConfigToAllPlugIns();
3300 */
3301 ReloadAllVP();
3302 }
3303 }
3304}
3305
3306void MyFrame::ToggleSoundings(ChartCanvas *cc) {
3307 cc->SetShowENCDepth(!cc->GetShowENCDepth());
3308
3309 SetMenubarItemState(ID_MENU_ENC_SOUNDINGS, cc->GetShowENCDepth());
3310
3311 // if(g_pi_manager)
3312 // g_pi_manager->SendConfigToAllPlugIns();
3313
3314 ReloadAllVP();
3315}
3316
3317bool MyFrame::ToggleLights(ChartCanvas *cc) {
3318 cc->SetShowENCLights(!cc->GetShowENCLights());
3319
3320 SetMenubarItemState(ID_MENU_ENC_LIGHTS, cc->GetShowENCLights());
3321
3322 if (g_pi_manager) g_pi_manager->SendS52ConfigToAllPlugIns(true);
3323
3324 ReloadAllVP();
3325
3326 return true;
3327}
3328
3329#if 0
3330void MyFrame::ToggleRocks( void )
3331{
3332 if( ps52plib ) {
3333 int vis = 0;
3334 // Need to loop once for UWTROC, which is our "master", then for
3335 // other categories, since order is unknown?
3336 for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
3337 OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
3338 if( !strncmp( pOLE->OBJLName, "UWTROC", 6 ) ) {
3339 pOLE->nViz = !pOLE->nViz;
3340 vis = pOLE->nViz;
3341 }
3342 }
3343 for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
3344 OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
3345 if( !strncmp( pOLE->OBJLName, "OBSTRN", 6 ) ) {
3346 pOLE->nViz = vis;
3347 }
3348 if( !strncmp( pOLE->OBJLName, "WRECKS", 6 ) ) {
3349 pOLE->nViz = vis;
3350 }
3351 }
3352 ps52plib->GenerateStateHash();
3353 ReloadAllVP();
3354 }
3355}
3356#endif
3357
3358void MyFrame::ToggleAnchor(ChartCanvas *cc) {
3359 cc->SetShowENCAnchor(!cc->GetShowENCAnchor());
3360
3361 SetMenubarItemState(ID_MENU_ENC_ANCHOR, cc->GetShowENCAnchor());
3362
3363 if (g_pi_manager) g_pi_manager->SendS52ConfigToAllPlugIns();
3364
3365 ReloadAllVP();
3366}
3367
3368void MyFrame::ToggleDataQuality(ChartCanvas *cc) {
3369 cc->SetShowENCDataQual(!cc->GetShowENCDataQual());
3370
3371 SetMenubarItemState(ID_MENU_ENC_DATA_QUALITY, cc->GetShowENCDataQual());
3372
3373 if (g_pi_manager) g_pi_manager->SendS52ConfigToAllPlugIns();
3374
3375 ReloadAllVP();
3376}
3377
3378void MyFrame::TogglebFollow(ChartCanvas *cc) {
3379 if (!cc->m_bFollow)
3380 SetbFollow(cc);
3381 else
3382 ClearbFollow(cc);
3383}
3384
3385void MyFrame::ToggleNavobjects(ChartCanvas *cc) {
3386 cc->m_bShowNavobjects = !cc->m_bShowNavobjects;
3387 SetMenubarItemState(ID_MENU_SHOW_NAVOBJECTS, cc->m_bShowNavobjects);
3388 cc->Refresh();
3389}
3390
3391void MyFrame::ToggleAISDisplay(ChartCanvas *cc) {
3392 cc->SetShowAIS(!cc->GetShowAIS());
3393 SetMenubarItemState(ID_MENU_AIS_TARGETS, cc->GetShowAIS());
3394 cc->Refresh();
3395}
3396
3397void MyFrame::ToggleAISMinimizeTargets(ChartCanvas *cc) {
3398 cc->SetAttenAIS(!cc->GetAttenAIS());
3399 SetMenubarItemState(ID_MENU_AIS_SCALED_TARGETS, cc->GetAttenAIS());
3400 cc->Refresh();
3401}
3402
3403void MyFrame::SetbFollow(ChartCanvas *cc) {
3404 JumpToPosition(cc, gLat, gLon, cc->GetVPScale());
3405 cc->m_bFollow = true;
3406
3407 // cc->SetCanvasToolbarItemState(ID_FOLLOW, true);
3408 SetMenubarItemState(ID_MENU_NAV_FOLLOW, true);
3409
3410 DoChartUpdate();
3411 cc->ReloadVP();
3412 SetChartUpdatePeriod();
3413}
3414
3415void MyFrame::ClearbFollow(ChartCanvas *cc) {
3416 // Center the screen on the GPS position, for lack of a better place
3417 vLat = gLat;
3418 vLon = gLon;
3419
3420 cc->m_bFollow = false;
3421 // cc->SetCanvasToolbarItemState(ID_FOLLOW, false);
3422 SetMenubarItemState(ID_MENU_NAV_FOLLOW, false);
3423
3424 DoChartUpdate();
3425 cc->ReloadVP();
3426 SetChartUpdatePeriod();
3427}
3428
3429void MyFrame::ToggleChartOutlines(ChartCanvas *cc) {
3430 cc->SetShowOutlines(!cc->GetShowOutlines());
3431
3432 RefreshAllCanvas(false);
3433
3434#ifdef ocpnUSE_GL // opengl renders chart outlines as part of the chart this
3435 // needs a full refresh
3436 if (g_bopengl) InvalidateAllGL();
3437#endif
3438
3439 SetMenubarItemState(ID_MENU_CHART_OUTLINES, cc->GetShowOutlines());
3440}
3441
3442void MyFrame::ToggleTestPause() { g_bPauseTest = !g_bPauseTest; }
3443
3444void MyFrame::SetMenubarItemState(int item_id, bool state) {
3445 if (m_pMenuBar) {
3446 bool enabled = m_pMenuBar->IsEnabled(item_id);
3447 m_pMenuBar->Enable(item_id, false);
3448 m_pMenuBar->Check(item_id, state);
3449 m_pMenuBar->Enable(item_id, enabled);
3450 }
3451}
3452
3453void MyFrame::SetMasterToolbarItemState(int tool_id, bool state) {
3454 if (g_MainToolbar && g_MainToolbar->GetToolbar()) {
3455 g_MainToolbar->GetToolbar()->ToggleTool(tool_id, state);
3456 g_MainToolbar->Realize();
3457 }
3458}
3459
3460void MyFrame::SetToolbarItemBitmaps(int tool_id, wxBitmap *bmp,
3461 wxBitmap *bmpRollover) {
3462 if (g_MainToolbar && g_MainToolbar->GetToolbar()) {
3463 g_MainToolbar->GetToolbar()->SetToolBitmaps(tool_id, bmp, bmpRollover);
3464 g_MainToolbar->Realize();
3465 }
3466}
3467
3468void MyFrame::SetToolbarItemSVG(int tool_id, wxString normalSVGfile,
3469 wxString rolloverSVGfile,
3470 wxString toggledSVGfile) {
3471 if (g_MainToolbar && g_MainToolbar->GetToolbar()) {
3472 g_MainToolbar->GetToolbar()->SetToolBitmapsSVG(
3473 tool_id, normalSVGfile, rolloverSVGfile, toggledSVGfile);
3474 }
3475}
3476
3477void MyFrame::ConfigureStatusBar() {
3478 // ShowDebugWindow as a wxStatusBar
3479 m_StatusBarFieldCount = g_Platform->GetStatusBarFieldCount();
3480
3481#ifdef __WXMSW__
3482 UseNativeStatusBar(false); // better for MSW, undocumented in frame.cpp
3483#endif
3484
3485 if (g_bShowStatusBar) {
3486 if (!m_pStatusBar) {
3487 m_pStatusBar =
3488 CreateStatusBar(m_StatusBarFieldCount, 0); // No wxST_SIZEGRIP needed
3489 ApplyGlobalColorSchemetoStatusBar();
3490 }
3491
3492 } else {
3493 if (m_pStatusBar) {
3494 m_pStatusBar->Destroy();
3495 m_pStatusBar = NULL;
3496 SetStatusBar(NULL);
3497 }
3498 }
3499}
3500
3501void MyFrame::ApplyGlobalSettings(bool bnewtoolbar) {
3502 ConfigureStatusBar();
3503
3504 wxSize lastOptSize = options_lastWindowSize;
3505 SendSizeEvent();
3506
3507 BuildMenuBar();
3508
3509 SendSizeEvent();
3510 options_lastWindowSize = lastOptSize;
3511
3512 if (bnewtoolbar) UpdateAllToolbars(global_color_scheme);
3513}
3514
3515void MyFrame::BuildMenuBar() {
3516 /*
3517 * Menu Bar - add or remove it if necessary, and update the state of the menu
3518 * items
3519 */
3520#ifdef __WXOSX__
3521 bool showMenuBar = true; // the menu bar is always visible in OS X
3522#else
3523 bool showMenuBar = g_bShowMenuBar; // get visibility from options
3524
3525 if (!showMenuBar &&
3526 g_bTempShowMenuBar) // allows pressing alt to temporarily show
3527 showMenuBar = true;
3528#endif
3529
3530 if (showMenuBar) {
3531 // Menu bar has some dependencies on S52 PLIB, so be sure it is loaded.
3532 LoadS57();
3533
3534 if (!m_pMenuBar) { // add the menu bar if it is enabled
3535 m_pMenuBar = new wxMenuBar();
3536 RegisterGlobalMenuItems();
3537 SetMenuBar(m_pMenuBar); // must be after RegisterGlobalMenuItems for wx
3538 // to populate the OS X App Menu correctly
3539 }
3540
3541 UpdateGlobalMenuItems(); // update the state of the menu items (checkmarks
3542 // etc.)
3543 } else {
3544 if (m_pMenuBar) { // remove the menu bar if it is disabled
3545 SetMenuBar(NULL);
3546 m_pMenuBar->Destroy();
3547 m_pMenuBar = NULL;
3548 }
3549 }
3550}
3551
3552void MyFrame::RegisterGlobalMenuItems() {
3553 if (!m_pMenuBar) return; // if there isn't a menu bar
3554
3555 wxMenu *nav_menu = new wxMenu();
3556 nav_menu->AppendCheckItem(ID_MENU_NAV_FOLLOW,
3557 _menuText(_("Auto Follow"), "Ctrl-A"));
3558 nav_menu->AppendCheckItem(ID_MENU_NAV_TRACK, _("Enable Tracking"));
3559 nav_menu->AppendSeparator();
3560 nav_menu->AppendRadioItem(ID_MENU_CHART_NORTHUP, _("North Up Mode"));
3561 nav_menu->AppendRadioItem(ID_MENU_CHART_COGUP, _("Course Up Mode"));
3562 nav_menu->AppendRadioItem(ID_MENU_CHART_HEADUP, _("Head Up Mode"));
3563 nav_menu->AppendSeparator();
3564#ifndef __WXOSX__
3565 nav_menu->Append(ID_MENU_ZOOM_IN, _menuText(_("Zoom In"), "+"));
3566 nav_menu->Append(ID_MENU_ZOOM_OUT, _menuText(_("Zoom Out"), "-"));
3567#else
3568 nav_menu->Append(ID_MENU_ZOOM_IN, _menuText(_("Zoom In"), "Alt-+"));
3569 nav_menu->Append(ID_MENU_ZOOM_OUT, _menuText(_("Zoom Out"), "Alt--"));
3570#endif
3571 nav_menu->AppendSeparator();
3572 nav_menu->Append(ID_MENU_SCALE_IN,
3573 _menuText(_("Larger Scale Chart"), "Ctrl-Left"));
3574 nav_menu->Append(ID_MENU_SCALE_OUT,
3575 _menuText(_("Smaller Scale Chart"), "Ctrl-Right"));
3576#ifndef __WXOSX__
3577 nav_menu->AppendSeparator();
3578 nav_menu->Append(ID_MENU_OQUIT, _menuText(_("Exit OpenCPN"), "Ctrl-Q"));
3579#endif
3580 m_pMenuBar->Append(nav_menu, _("&Navigate"));
3581
3582 wxMenu *view_menu = new wxMenu();
3583#ifndef __WXOSX__
3584 view_menu->AppendCheckItem(ID_MENU_CHART_QUILTING,
3585 _menuText(_("Enable Chart Quilting"), "Q"));
3586 view_menu->AppendCheckItem(ID_MENU_CHART_OUTLINES,
3587 _menuText(_("Show Chart Outlines"), "O"));
3588#else
3589 view_menu->AppendCheckItem(ID_MENU_CHART_QUILTING,
3590 _menuText(_("Enable Chart Quilting"), "Alt-Q"));
3591 view_menu->AppendCheckItem(ID_MENU_CHART_OUTLINES,
3592 _menuText(_("Show Chart Outlines"), "Alt-O"));
3593#endif
3594 view_menu->AppendCheckItem(ID_MENU_UI_CHARTBAR,
3595 _menuText(_("Show Chart Bar"), "Ctrl-B"));
3596
3597 view_menu->AppendSeparator();
3598#ifndef __WXOSX__
3599 view_menu->AppendCheckItem(ID_MENU_ENC_TEXT,
3600 _menuText(_("Show ENC text"), "T"));
3601 view_menu->AppendCheckItem(ID_MENU_ENC_LIGHTS,
3602 _menuText(_("Show ENC Lights"), "L"));
3603 view_menu->AppendCheckItem(ID_MENU_ENC_SOUNDINGS,
3604 _menuText(_("Show ENC Soundings"), "S"));
3605 view_menu->AppendCheckItem(ID_MENU_ENC_ANCHOR,
3606 _menuText(_("Show ENC Anchoring Info"), "A"));
3607 view_menu->AppendCheckItem(ID_MENU_ENC_DATA_QUALITY,
3608 _menuText(_("Show ENC Data Quality"), "U"));
3609 view_menu->AppendCheckItem(ID_MENU_SHOW_NAVOBJECTS,
3610 _menuText(_("Show Navobjects"), "V"));
3611#else
3612 view_menu->AppendCheckItem(ID_MENU_ENC_TEXT,
3613 _menuText(_("Show ENC text"), "Alt-T"));
3614 view_menu->AppendCheckItem(ID_MENU_ENC_LIGHTS,
3615 _menuText(_("Show ENC Lights"), "Alt-L"));
3616 view_menu->AppendCheckItem(ID_MENU_ENC_SOUNDINGS,
3617 _menuText(_("Show ENC Soundings"), "Alt-S"));
3618 view_menu->AppendCheckItem(ID_MENU_ENC_ANCHOR,
3619 _menuText(_("Show ENC Anchoring Info"), "Alt-A"));
3620 view_menu->AppendCheckItem(ID_MENU_ENC_DATA_QUALITY,
3621 _menuText(_("Show ENC Data Quality"), "Alt-U"));
3622 view_menu->AppendCheckItem(ID_MENU_SHOW_NAVOBJECTS,
3623 _menuText(_("Show Navobjects"), "Alt-V"));
3624#endif
3625 view_menu->AppendSeparator();
3626 view_menu->AppendCheckItem(ID_MENU_SHOW_TIDES, _("Show Tides"));
3627 view_menu->AppendCheckItem(ID_MENU_SHOW_CURRENTS, _("Show Currents"));
3628 view_menu->AppendSeparator();
3629#ifndef __WXOSX__
3630 view_menu->Append(ID_MENU_UI_COLSCHEME,
3631 _menuText(_("Change Color Scheme"), "C"));
3632#else
3633 view_menu->Append(ID_MENU_UI_COLSCHEME,
3634 _menuText(_("Change Color Scheme"), "Alt-C"));
3635#endif
3636
3637 view_menu->AppendSeparator();
3638#ifndef __WXOSX__
3639 view_menu->Append(ID_MENU_UI_FULLSCREEN,
3640 _menuText(_("Toggle Full Screen"), "F11"));
3641#endif
3642 m_pMenuBar->Append(view_menu, _("&View"));
3643
3644 wxMenu *ais_menu = new wxMenu();
3645 ais_menu->AppendCheckItem(ID_MENU_AIS_TARGETS, _("Show AIS Targets"));
3646 ais_menu->AppendCheckItem(ID_MENU_AIS_SCALED_TARGETS,
3647 _("Attenuate less critical AIS targets"));
3648 ais_menu->AppendSeparator();
3649 ais_menu->AppendCheckItem(ID_MENU_AIS_MOORED_TARGETS,
3650 _("Hide Moored AIS Targets"));
3651 ais_menu->AppendCheckItem(ID_MENU_AIS_TRACKS, _("Show AIS Target Tracks"));
3652 ais_menu->AppendCheckItem(ID_MENU_AIS_CPADIALOG, _("Show CPA Alert Dialogs"));
3653 ais_menu->AppendCheckItem(ID_MENU_AIS_CPASOUND, _("Sound CPA Alarms"));
3654
3655#ifndef __WXOSX__
3656 ais_menu->AppendCheckItem(ID_MENU_AIS_CPAWARNING,
3657 _menuText(_("Show CPA Warnings"), "W"));
3658#else
3659 ais_menu->AppendCheckItem(ID_MENU_AIS_CPAWARNING,
3660 _menuText(_("Show CPA Warnings"), "Alt-W"));
3661#endif
3662
3663 ais_menu->AppendSeparator();
3664 ais_menu->Append(ID_MENU_AIS_TARGETLIST, _("AIS target list") + "...");
3665 m_pMenuBar->Append(ais_menu, _("&AIS"));
3666
3667 wxMenu *tools_menu = new wxMenu();
3668 tools_menu->Append(ID_MENU_TOOL_NMEA_DBG_LOG,
3669 _menuText(_("Data Monitor"), "E"));
3670#ifndef __WXOSX__
3671 tools_menu->Append(ID_MENU_TOOL_MEASURE,
3672 _menuText(_("Measure Distance"), "M"));
3673#else
3674 tools_menu->Append(ID_MENU_TOOL_MEASURE,
3675 _menuText(_("Measure Distance"), "Alt-M"));
3676#endif
3677
3678 tools_menu->AppendSeparator();
3679 tools_menu->Append(ID_MENU_ROUTE_MANAGER, _("Route && Mark Manager..."));
3680 tools_menu->Append(ID_MENU_ROUTE_NEW, _menuText(_("Create Route"), "Ctrl-R"));
3681 tools_menu->AppendSeparator();
3682 tools_menu->Append(ID_MENU_MARK_BOAT,
3683 _menuText(_("Drop Mark at Boat"), "Ctrl-O"));
3684 tools_menu->Append(ID_MENU_MARK_CURSOR,
3685 _menuText(_("Drop Mark at Cursor"), "Ctrl-M"));
3686 tools_menu->AppendSeparator();
3687#ifdef __WXOSX__
3688 tools_menu->Append(
3689 ID_MENU_MARK_MOB,
3690 _menuText(_("Drop MOB Marker"),
3691 "RawCtrl-Space")); // NOTE Cmd+Space is reserved for Spotlight
3692 tools_menu->AppendSeparator();
3693 tools_menu->Append(wxID_PREFERENCES,
3694 _menuText(_("Preferences") + "...", "Ctrl-,"));
3695#else
3696 tools_menu->Append(ID_MENU_MARK_MOB,
3697 _menuText(_("Drop MOB Marker"), "Ctrl-Space"));
3698 tools_menu->AppendSeparator();
3699 tools_menu->Append(wxID_PREFERENCES,
3700 _menuText(_("Options") + "...", "Ctrl-,"));
3701#endif
3702 m_pMenuBar->Append(tools_menu, _("&Tools"));
3703
3704#ifdef __WXOSX__
3705 wxMenu *window_menu = new wxMenu();
3706 m_pMenuBar->Append(window_menu, _("&Window"));
3707#endif
3708
3709 wxMenu *help_menu = new wxMenu();
3710 help_menu->Append(wxID_ABOUT, _("About OpenCPN"));
3711 help_menu->Append(wxID_HELP, _("OpenCPN Help"));
3712 m_pMenuBar->Append(help_menu, _("&Help"));
3713
3714 // Set initial values for menu check items and radio items
3715 UpdateGlobalMenuItems();
3716}
3717
3718void MyFrame::UpdateGlobalMenuItems() {
3719 if (!m_pMenuBar) return; // if there isn't a menu bar
3720
3721 m_pMenuBar->FindItem(ID_MENU_NAV_FOLLOW)
3722 ->Check(GetPrimaryCanvas()->m_bFollow);
3723 m_pMenuBar->FindItem(ID_MENU_CHART_NORTHUP)
3724 ->Check(GetPrimaryCanvas()->GetUpMode() == NORTH_UP_MODE);
3725 m_pMenuBar->FindItem(ID_MENU_CHART_COGUP)
3726 ->Check(GetPrimaryCanvas()->GetUpMode() == COURSE_UP_MODE);
3727 m_pMenuBar->FindItem(ID_MENU_CHART_HEADUP)
3728 ->Check(GetPrimaryCanvas()->GetUpMode() == HEAD_UP_MODE);
3729 m_pMenuBar->FindItem(ID_MENU_NAV_TRACK)->Check(g_bTrackActive);
3730 m_pMenuBar->FindItem(ID_MENU_CHART_OUTLINES)->Check(g_bShowOutlines);
3731 m_pMenuBar->FindItem(ID_MENU_CHART_QUILTING)->Check(g_bQuiltEnable);
3732 m_pMenuBar->FindItem(ID_MENU_UI_CHARTBAR)->Check(g_bShowChartBar);
3733 m_pMenuBar->FindItem(ID_MENU_AIS_TARGETS)->Check(g_bShowAIS);
3734 m_pMenuBar->FindItem(ID_MENU_AIS_MOORED_TARGETS)->Check(g_bHideMoored);
3735 m_pMenuBar->FindItem(ID_MENU_AIS_SCALED_TARGETS)->Check(g_bShowScaled);
3736 m_pMenuBar->FindItem(ID_MENU_AIS_SCALED_TARGETS)->Enable(g_bAllowShowScaled);
3737 m_pMenuBar->FindItem(ID_MENU_AIS_TRACKS)->Check(g_bAISShowTracks);
3738 m_pMenuBar->FindItem(ID_MENU_AIS_CPADIALOG)->Check(g_bAIS_CPA_Alert);
3739 if (g_bAIS_CPA_Alert) {
3740 m_pMenuBar->FindItem(ID_MENU_AIS_CPASOUND)->Check(g_bAIS_CPA_Alert_Audio);
3741 m_pMenuBar->Enable(ID_MENU_AIS_CPASOUND, true);
3742 } else {
3743 m_pMenuBar->FindItem(ID_MENU_AIS_CPASOUND)->Check(false);
3744 m_pMenuBar->Enable(ID_MENU_AIS_CPASOUND, false);
3745 }
3746
3747 m_pMenuBar->FindItem(ID_MENU_AIS_CPAWARNING)->Check(g_bCPAWarn);
3748 m_pMenuBar->FindItem(ID_MENU_SHOW_NAVOBJECTS)
3749 ->Check(GetPrimaryCanvas()->m_bShowNavobjects);
3750
3751 if (ps52plib) {
3752 m_pMenuBar->FindItem(ID_MENU_ENC_TEXT)->Check(ps52plib->GetShowS57Text());
3753 m_pMenuBar->FindItem(ID_MENU_ENC_SOUNDINGS)
3754 ->Check(ps52plib->GetShowSoundings());
3755
3756 bool light_state = false;
3757 if (ps52plib) {
3758 for (unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount();
3759 iPtr++) {
3760 OBJLElement *pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3761 if (!strncmp(pOLE->OBJLName, "LIGHTS", 6)) {
3762 light_state = (pOLE->nViz == 1);
3763 break;
3764 }
3765 }
3766 }
3767 m_pMenuBar->FindItem(ID_MENU_ENC_LIGHTS)
3768 ->Check((!ps52plib->IsObjNoshow("LIGHTS")) && light_state);
3769
3770 // Menu "Anchor Info" entry is only accessible in "All" or "User Standard"
3771 // categories
3772 DisCat nset = ps52plib->GetDisplayCategory();
3773 if ((nset == MARINERS_STANDARD) || (nset == OTHER)) {
3774 m_pMenuBar->FindItem(ID_MENU_ENC_ANCHOR)
3775 ->Check(!ps52plib->IsObjNoshow("SBDARE"));
3776 m_pMenuBar->Enable(ID_MENU_ENC_ANCHOR, true);
3777 m_pMenuBar->FindItem(ID_MENU_ENC_DATA_QUALITY)
3778 ->Check(!ps52plib->IsObjNoshow("M_QUAL"));
3779 m_pMenuBar->Enable(ID_MENU_ENC_DATA_QUALITY, true);
3780 } else {
3781 m_pMenuBar->FindItem(ID_MENU_ENC_ANCHOR)->Check(false);
3782 m_pMenuBar->Enable(ID_MENU_ENC_ANCHOR, false);
3783 m_pMenuBar->Enable(ID_MENU_ENC_DATA_QUALITY, false);
3784 }
3785 }
3786}
3787
3788void MyFrame::UpdateGlobalMenuItems(ChartCanvas *cc) {
3789 if (!m_pMenuBar) return; // if there isn't a menu bar
3790
3791 m_pMenuBar->FindItem(ID_MENU_NAV_FOLLOW)->Check(cc->m_bFollow);
3792
3793 if (cc->GetUpMode() == NORTH_UP_MODE)
3794 m_pMenuBar->FindItem(ID_MENU_CHART_NORTHUP)->Check(true);
3795 else if (cc->GetUpMode() == COURSE_UP_MODE)
3796 m_pMenuBar->FindItem(ID_MENU_CHART_COGUP)->Check(true);
3797 else
3798 m_pMenuBar->FindItem(ID_MENU_CHART_HEADUP)->Check(true);
3799
3800 m_pMenuBar->FindItem(ID_MENU_NAV_TRACK)->Check(g_bTrackActive);
3801 m_pMenuBar->FindItem(ID_MENU_CHART_OUTLINES)->Check(cc->GetShowOutlines());
3802 m_pMenuBar->FindItem(ID_MENU_CHART_QUILTING)->Check(cc->GetQuiltMode());
3803 m_pMenuBar->FindItem(ID_MENU_UI_CHARTBAR)->Check(cc->GetShowChartbar());
3804 m_pMenuBar->FindItem(ID_MENU_AIS_TARGETS)->Check(cc->GetShowAIS());
3805 m_pMenuBar->FindItem(ID_MENU_AIS_MOORED_TARGETS)->Check(g_bHideMoored);
3806 m_pMenuBar->FindItem(ID_MENU_AIS_SCALED_TARGETS)->Check(cc->GetAttenAIS());
3807 m_pMenuBar->FindItem(ID_MENU_AIS_SCALED_TARGETS)->Enable(g_bAllowShowScaled);
3808 m_pMenuBar->FindItem(ID_MENU_AIS_TRACKS)->Check(g_bAISShowTracks);
3809 m_pMenuBar->FindItem(ID_MENU_AIS_CPADIALOG)->Check(g_bAIS_CPA_Alert);
3810 m_pMenuBar->FindItem(ID_MENU_AIS_CPASOUND)->Check(g_bAIS_CPA_Alert_Audio);
3811 m_pMenuBar->FindItem(ID_MENU_AIS_CPAWARNING)->Check(g_bCPAWarn);
3812 m_pMenuBar->FindItem(ID_MENU_SHOW_NAVOBJECTS)->Check(cc->m_bShowNavobjects);
3813 m_pMenuBar->FindItem(ID_MENU_SHOW_TIDES)->Check(cc->GetbShowTide());
3814 m_pMenuBar->FindItem(ID_MENU_SHOW_CURRENTS)->Check(cc->GetbShowCurrent());
3815
3816 if (ps52plib) {
3817 m_pMenuBar->FindItem(ID_MENU_ENC_TEXT)->Check(cc->GetShowENCText());
3818 m_pMenuBar->FindItem(ID_MENU_ENC_SOUNDINGS)->Check(cc->GetShowENCDepth());
3819
3820 if (ps52plib) {
3821 for (unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount();
3822 iPtr++) {
3823 OBJLElement *pOLE = (OBJLElement *)(ps52plib->pOBJLArray->Item(iPtr));
3824 if (!strncmp(pOLE->OBJLName, "LIGHTS", 6)) {
3825 break;
3826 }
3827 }
3828 }
3829 m_pMenuBar->FindItem(ID_MENU_ENC_LIGHTS)->Check(cc->GetShowENCLights());
3830
3831 // Menu "Anchor Info" entry is only accessible in "All" or "UserStandard"
3832 // categories
3833 DisCat nset = (DisCat)cc->GetENCDisplayCategory();
3834 if ((nset == MARINERS_STANDARD) || (nset == OTHER)) {
3835 m_pMenuBar->FindItem(ID_MENU_ENC_ANCHOR)->Check(cc->GetShowENCAnchor());
3836 m_pMenuBar->Enable(ID_MENU_ENC_ANCHOR, true);
3837 m_pMenuBar->FindItem(ID_MENU_ENC_DATA_QUALITY)
3838 ->Check(cc->GetShowENCDataQual());
3839 m_pMenuBar->Enable(ID_MENU_ENC_DATA_QUALITY, true);
3840 } else {
3841 m_pMenuBar->FindItem(ID_MENU_ENC_ANCHOR)->Check(false);
3842 m_pMenuBar->Enable(ID_MENU_ENC_ANCHOR, false);
3843 m_pMenuBar->Enable(ID_MENU_ENC_DATA_QUALITY, false);
3844 }
3845 }
3846}
3847
3848void MyFrame::InvalidateAllCanvasUndo() {
3849 // .. for each canvas...
3850 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
3851 ChartCanvas *cc = g_canvasArray.Item(i);
3852 if (cc) cc->undo->InvalidateUndo();
3853 }
3854}
3855#if 0
3856void MyFrame::SubmergeAllCanvasToolbars() {
3857 // .. for each canvas...
3858 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
3859 ChartCanvas *cc = g_canvasArray.Item(i);
3860 if (cc) cc->SubmergeToolbar();
3861 }
3862}
3863
3864void MyFrame::SurfaceAllCanvasToolbars() {
3865 if (g_bshowToolbar) {
3866 // .. for each canvas...
3867 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
3868 ChartCanvas *cc = g_canvasArray.Item(i);
3869 if (cc && cc->GetToolbarEnable()) cc->SurfaceToolbar();
3870 }
3871 }
3872
3873}
3874#endif
3875
3876void MyFrame::JumpToPosition(ChartCanvas *cc, double lat, double lon,
3877 double scale) {
3878 if (lon > 180.0) lon -= 360.0;
3879 // XXX is vLat/vLon always equal to cc m_vLat, m_vLon after SetViewPoint? Does
3880 // it matter?
3881 vLat = lat;
3882 vLon = lon;
3883 cc->JumpToPosition(lat, lon, scale);
3884
3885 if (g_pi_manager) {
3886 g_pi_manager->SendViewPortToRequestingPlugIns(cc->GetVP());
3887 }
3888}
3889
3890void MyFrame::UpdateCanvasConfigDescriptors() {
3891 // ..For each canvas...
3892 for (unsigned int i = 0;
3893 i < ConfigMgr::Get().GetCanvasConfigArray().GetCount(); i++) {
3894 canvasConfig *cc = ConfigMgr::Get().GetCanvasConfigArray().Item(i);
3895 if (cc) {
3896 ChartCanvas *chart = cc->canvas;
3897 if (chart) {
3898 cc->iLat = chart->GetVP().clat;
3899 cc->iLon = chart->GetVP().clon;
3900 cc->iRotation = chart->GetVP().rotation;
3901 cc->iScale = chart->GetVP().view_scale_ppm;
3902 cc->DBindex = chart->GetQuiltReferenceChartIndex();
3903 cc->GroupID = chart->m_groupIndex;
3904 cc->canvasSize = chart->GetSize();
3905
3906 cc->bQuilt = chart->GetQuiltMode();
3907 cc->bShowTides = chart->GetbShowTide();
3908 cc->bShowCurrents = chart->GetbShowCurrent();
3909 cc->bShowGrid = chart->GetShowGrid();
3910 cc->bShowOutlines = chart->GetShowOutlines();
3911 cc->bShowDepthUnits = chart->GetShowDepthUnits();
3912
3913 cc->bFollow = chart->m_bFollow;
3914 cc->bLookahead = chart->m_bLookAhead;
3915 cc->bCourseUp = false;
3916 cc->bHeadUp = false;
3917 ;
3918 int upmode = chart->GetUpMode();
3919 if (upmode == COURSE_UP_MODE)
3920 cc->bCourseUp = true;
3921 else if (upmode == HEAD_UP_MODE)
3922 cc->bHeadUp = true;
3923 }
3924 }
3925 }
3926}
3927
3928void MyFrame::CenterView(ChartCanvas *cc, const LLBBox &RBBox) {
3929 if (!RBBox.GetValid()) return;
3930 // Calculate bbox center
3931 double clat = (RBBox.GetMinLat() + RBBox.GetMaxLat()) / 2;
3932 double clon = (RBBox.GetMinLon() + RBBox.GetMaxLon()) / 2;
3933 double ppm; // final ppm scale to use
3934
3935 if (RBBox.GetMinLat() == RBBox.GetMaxLat() &&
3936 RBBox.GetMinLon() == RBBox.GetMaxLon()) {
3937 // only one point, (should be a box?)
3938 ppm = cc->GetVPScale();
3939 } else {
3940 // Calculate ppm
3941 double rw, rh; // route width, height
3942 int ww, wh; // chart window width, height
3943 // route bbox width in nm
3944 DistanceBearingMercator(RBBox.GetMinLat(), RBBox.GetMinLon(),
3945 RBBox.GetMinLat(), RBBox.GetMaxLon(), NULL, &rw);
3946 // route bbox height in nm
3947 DistanceBearingMercator(RBBox.GetMinLat(), RBBox.GetMinLon(),
3948 RBBox.GetMaxLat(), RBBox.GetMinLon(), NULL, &rh);
3949
3950 cc->GetSize(&ww, &wh);
3951
3952 ppm = wxMin(ww / (rw * 1852), wh / (rh * 1852)) * (100 - fabs(clat)) / 90;
3953
3954 ppm = wxMin(ppm, 1.0);
3955 }
3956
3957 JumpToPosition(cc, clat, clon, ppm);
3958}
3959
3960void MyFrame::PrepareOptionsClose(options *settings,
3961 int settings_return_value) {
3962 // Capture som values from options dialog before closure
3963 options_lastPage = settings->lastPage;
3964#ifdef __ANDROID__
3965 // This is necessary to force a manual change to charts page,
3966 // in order to properly refresh the chart directory list.
3967 // Root cause: In Android, trouble with clearing the wxScrolledWindow
3968 if (options_lastPage == 1) options_lastPage = 0;
3969#endif
3970 options_subpage = settings->lastSubPage;
3971 options_lastWindowPos = settings->lastWindowPos;
3972 options_lastWindowSize = settings->lastWindowSize;
3973
3974#ifdef __ANDROID__
3975 androidEnableBackButton(true);
3976 androidEnableOptionsMenu(true);
3977 androidRestoreFullScreen();
3978 androidEnableRotation();
3979#endif
3980 ThawCharts();
3981 EnableSettingsTool(true);
3982}
3983
3984void MyFrame::DoOptionsDialog() {
3985 EnableSettingsTool(false);
3986
3987 if (NULL == g_options) {
3988 AbstractPlatform::ShowBusySpinner();
3989
3990 int sx, sy;
3991 pConfig->SetPath("/Settings");
3992 pConfig->Read("OptionsSizeX", &sx, -1);
3993 pConfig->Read("OptionsSizeY", &sy, -1);
3994
3995 wxWindow *optionsParent = this;
3996#ifdef __WXOSX__
3997 optionsParent = GetPrimaryCanvas();
3998#endif
3999 OptionsCallbacks callbacks;
4000 callbacks.prepare_close = [&](options *me, int changes) {
4001 PrepareOptionsClose(me, changes);
4002 };
4003 callbacks.process_dialog = [&](int changes, ArrayOfCDI *workdir_list) {
4004 ProcessOptionsDialog(changes, workdir_list);
4005 };
4006 g_options = new options(optionsParent, callbacks, -1, _("Options"),
4007 wxPoint(-1, -1), wxSize(sx, sy));
4008
4009 AbstractPlatform::HideBusySpinner();
4010 }
4011
4012 // Set initial Chart Dir
4013 g_options->SetInitChartDir(*pInit_Chart_Dir);
4014
4015 // Pass two working pointers for Chart Dir Dialog
4016 g_options->SetCurrentDirList(ChartData->GetChartDirArray());
4017 ArrayOfCDI *pWorkDirArray = new ArrayOfCDI;
4018 g_options->SetWorkDirListPtr(pWorkDirArray);
4019
4020 // Pass a ptr to MyConfig, for updates
4021 g_options->SetConfigPtr(pConfig);
4022 g_options->SetInitialSettings();
4023
4024 prev_locale = g_locale;
4025 g_options->SetInitialPage(options_lastPage, options_subpage);
4026
4027#ifndef __ANDROID__ // if(!g_bresponsive){
4028 g_options->lastWindowPos = options_lastWindowPos;
4029 if (options_lastWindowPos != wxPoint(0, 0)) {
4030 g_options->Move(options_lastWindowPos);
4031 g_options->SetSize(options_lastWindowSize);
4032 } else {
4033 g_options->CenterOnScreen();
4034 }
4035 if (options_lastWindowSize != wxSize(0, 0)) {
4036 g_options->SetSize(options_lastWindowSize);
4037 }
4038#endif
4039
4040#ifdef __ANDROID__
4041 androidEnableBackButton(false);
4042 androidEnableOptionsMenu(false);
4043 androidDisableFullScreen();
4044#endif
4045
4046 // Capture the full path names and VPScale of charts currently shown in all
4047 // canvases
4048 pathArray.Clear();
4049 // ..For each canvas.
4050 // TODO FIX ANDROID codepath..
4051 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4052 ChartCanvas *cc = g_canvasArray.Item(i);
4053 if (cc) {
4054 wxString chart_file_name;
4055 if (cc->GetQuiltMode()) {
4056 int dbi = cc->GetQuiltRefChartdbIndex();
4057 chart_file_name = ChartData->GetDBChartFileName(dbi);
4058 } else {
4059 if (cc->m_singleChart)
4060 chart_file_name = cc->m_singleChart->GetFullPath();
4061 }
4062
4063 pathArray.Add(chart_file_name);
4064 restoreScale[i] = cc->GetVPScale();
4065 }
4066 }
4067
4068 // Record current canvas config
4069 last_canvasConfig = g_canvasConfig;
4070
4071 // Record current chart scale factor
4072 g_last_ChartScaleFactor = g_ChartScaleFactor;
4073
4074 g_options->Show();
4075 return;
4076}
4077
4078void MyFrame::ProcessOptionsDialog(int rr, ArrayOfCDI *pNewDirArray) {
4079 bool b_need_refresh = false; // Do we need a full reload?
4080
4081#if 0
4082 if ((rr & VISIT_CHARTS) &&
4083 ((rr & CHANGE_CHARTS) || (rr & FORCE_UPDATE) || (rr & SCAN_UPDATE))) {
4084 if (pNewDirArray) {
4085 UpdateChartDatabaseInplace(*pNewDirArray,
4086 ((rr & FORCE_UPDATE) == FORCE_UPDATE), true,
4087 ChartListFileName);
4088
4089 b_need_refresh = true;
4090 }
4091 }
4092#endif
4093
4094 if (rr & STYLE_CHANGED) {
4095 OCPNMessageBox(
4096 NULL,
4097 _("Please restart OpenCPN to activate language or style changes."),
4098 _("OpenCPN Info"), wxOK | wxICON_INFORMATION);
4099 }
4100
4101 bool charts_updating =
4102 (rr & VISIT_CHARTS) && ((rr & CHANGE_CHARTS) || (rr & SCAN_UPDATE));
4103 if (!charts_updating) RefreshGroupIndices();
4104
4105 if (rr & TIDES_CHANGED) {
4106 LoadHarmonics();
4107 }
4108
4109 // S52_CHANGED is a byproduct of a change in the chart object render scale
4110 // So, applies to RoutePoint icons also
4111 if (rr & S52_CHANGED) {
4112 WayPointmanGui(*pWayPointMan).ReloadAllIcons(g_Platform->GetDisplayDPmm());
4113 }
4114
4115 pConfig->UpdateSettings();
4116
4117 if (g_pActiveTrack) {
4118 g_pActiveTrack->SetPrecision(g_nTrackPrecision);
4119 }
4120
4121 // reload pens and brushes
4122 g_pRouteMan->SetColorScheme(global_color_scheme,
4123 g_Platform->GetDisplayDPmm());
4124
4125 // Stuff the Filter tables
4126 double stuffcog = NAN;
4127 double stuffsog = NAN;
4128 if (!std::isnan(gCog)) stuffcog = gCog;
4129 if (!std::isnan(gSog)) stuffsog = gSog;
4130
4131 for (int i = 0; i < kMaxCogsogFilterSeconds; i++) {
4132 COGFilterTable[i] = stuffcog;
4133 SOGFilterTable[i] = stuffsog;
4134 }
4135
4136 SetChartUpdatePeriod(); // Pick up changes to skew compensator
4137
4138 if (rr & GL_CHANGED) {
4139 // Refresh the chart display, after flushing cache.
4140 // This will allow all charts to recognise new OpenGL configuration, if
4141 // any
4142 b_need_refresh = true;
4143 }
4144
4145 if (rr & S52_CHANGED) {
4146 b_need_refresh = true;
4147 }
4148
4149#ifdef ocpnUSE_GL
4150 if (rr & REBUILD_RASTER_CACHE) {
4151 if (g_glTextureManager) {
4152 GetPrimaryCanvas()->Disable();
4153 g_glTextureManager->BuildCompressedCache();
4154 GetPrimaryCanvas()->Enable();
4155 }
4156 }
4157#endif
4158
4159 if (g_config_display_size_manual &&
4163 } else {
4164 g_display_size_mm = wxMax(50, g_Platform->GetDisplaySizeMM());
4165 }
4166
4167 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4168 ChartCanvas *cc = g_canvasArray.Item(i);
4170 }
4171
4172 if (g_pi_manager) {
4173 g_pi_manager->SendBaseConfigToAllPlugIns();
4174 int rrt = rr & S52_CHANGED;
4175 g_pi_manager->SendS52ConfigToAllPlugIns(
4176 (rrt == S52_CHANGED) ||
4177 (g_last_ChartScaleFactor != g_ChartScaleFactor));
4178 }
4179
4180 if (g_MainToolbar) {
4181 g_MainToolbar->SetAutoHide(g_bAutoHideToolbar);
4182 g_MainToolbar->SetAutoHideTimer(g_nAutoHideToolbar);
4183 }
4184
4185 // update S52 PLIB scale factors
4186 if (ps52plib) {
4187 ps52plib->SetScaleFactorExp(
4188 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor));
4189 ps52plib->SetScaleFactorZoomMod(g_chart_zoom_modifier_vector);
4190 }
4191
4192 // Apply any needed updates to each canvas
4193 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4194 ChartCanvas *cc = g_canvasArray.Item(i);
4195 if (cc) cc->ApplyGlobalSettings();
4196 }
4197
4198#if 0
4199 // The zoom-scale factor may have changed
4200 // so, trigger a recalculation of the reference chart
4201 // This is needed to recognise changes in zoom-scale factors
4202 // Do not call if chartdbs update is underway.
4203 if (!charts_updating) {
4204 bool ztc = g_bEnableZoomToCursor; // record the present state
4205 g_bEnableZoomToCursor = false; // since we don't want to pan
4206 // to an unknown cursor position
4207 if (!GetPrimaryCanvas()->IsFrozen())
4208 GetPrimaryCanvas()->ZoomCanvasSimple(1.0001);
4209 g_bEnableZoomToCursor = ztc;
4210 }
4211#endif
4212
4213 // Pick up chart object icon size changes (g_ChartScaleFactorExp)
4214 if (g_last_ChartScaleFactor != g_ChartScaleFactor) {
4215 if (g_pMarkInfoDialog) {
4216 g_pMarkInfoDialog->Hide();
4217 g_pMarkInfoDialog->Destroy();
4218 g_pMarkInfoDialog = NULL;
4219 }
4220 }
4221
4222 // We set the compass size
4223 SetGPSCompassScale();
4224 // ..For each canvas...
4225 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4226 ChartCanvas *cc = g_canvasArray.Item(i);
4227 if (cc) {
4228 cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
4229 if (!charts_updating) cc->UpdateCanvasControlBar();
4230 }
4231 }
4232 UpdateGPSCompassStatusBoxes();
4233
4234 SetAllToolbarScale();
4235 RequestNewToolbars();
4236
4237 if ((rr & MENU_CHANGED) == MENU_CHANGED) BuildMenuBar();
4238
4239 // Rebuild cursors
4240 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4241 ChartCanvas *cc = g_canvasArray.Item(i);
4242 if (cc) {
4243 cc->RebuildCursors();
4244 }
4245 }
4246
4247 // Change of master toolbar scale?
4248 bool b_masterScaleChange = false;
4249 if (fabs(g_MainToolbar->GetScaleFactor() - g_toolbar_scalefactor) > 0.01f)
4250 b_masterScaleChange = true;
4251
4252 if ((rr & TOOLBAR_CHANGED) || b_masterScaleChange)
4253 RequestNewMasterToolbar(true);
4254
4255 bool bMuiChange = false;
4256#ifdef __ANDROID__
4257 bMuiChange = true; // to pick up possible "zoom" button visibility change
4258#endif
4259
4260 // Inform the canvases
4261 if (b_masterScaleChange || bMuiChange) {
4262 // ..For each canvas...
4263 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4264 ChartCanvas *cc = g_canvasArray.Item(i);
4265 if (cc) {
4266 cc->ProcessNewGUIScale();
4267 }
4268 }
4269 }
4270
4271#if wxUSE_XLOCALE
4272 if (rr & LOCALE_CHANGED) {
4273 g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
4274 ApplyLocale();
4275 rr |= NEED_NEW_OPTIONS;
4276 }
4277#endif
4278
4279#ifdef __ANDROID__
4280 if (g_pi_manager) g_pi_manager->NotifyAuiPlugIns();
4281#endif
4282
4283 // Reset chart scale factor trigger
4284 g_last_ChartScaleFactor = g_ChartScaleFactor;
4285
4286 return;
4287}
4288
4289bool MyFrame::CheckGroup(int igroup) {
4290 if (igroup == 0) return true; // "all charts" is always OK
4291
4292 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
4293
4294 if (!pGroup->m_element_array.size()) // truly empty group is OK
4295 return true;
4296
4297 for (const auto &elem : pGroup->m_element_array) {
4298 for (unsigned int ic = 0;
4299 ic < (unsigned int)ChartData->GetChartTableEntries(); ic++) {
4300 auto &cte = ChartData->GetChartTableEntry(ic);
4301 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
4302
4303 if (chart_full_path.StartsWith(elem.m_element_name)) return true;
4304 }
4305 }
4306
4307 return false; // this group is empty
4308}
4309
4310bool MyFrame::ScrubGroupArray() {
4311 // For each group,
4312 // make sure that each group element (dir or chart) references at least
4313 // oneitem in the database. If not, remove the element.
4314
4315 bool b_change = false;
4316 unsigned int igroup = 0;
4317 while (igroup < g_pGroupArray->GetCount()) {
4318 bool b_chart_in_element = false;
4319 ChartGroup *pGroup = g_pGroupArray->Item(igroup);
4320
4321 for (unsigned int j = 0; j < pGroup->m_element_array.size(); j++) {
4322 const wxString &element_root = pGroup->m_element_array[j].m_element_name;
4323
4324 for (unsigned int ic = 0;
4325 ic < (unsigned int)ChartData->GetChartTableEntries(); ic++) {
4326 auto &cte = ChartData->GetChartTableEntry(ic);
4327 wxString chart_full_path = cte.GetFullSystemPath();
4328
4329 if (chart_full_path.StartsWith(element_root)) {
4330 b_chart_in_element = true;
4331 break;
4332 }
4333 }
4334
4335 // Explicit check to avoid removing a group containing only GSHHS
4336 if (!b_chart_in_element) {
4337 wxString test_string = "GSHH";
4338 if (element_root.Upper().Contains(test_string))
4339 b_chart_in_element = true;
4340 }
4341
4342 if (!b_chart_in_element) // delete the element
4343 {
4344 pGroup->m_element_array.erase(pGroup->m_element_array.begin() + j);
4345 j--;
4346 b_change = true;
4347 }
4348 }
4349
4350 igroup++; // next group
4351 }
4352
4353 return b_change;
4354}
4355
4356void MyFrame::RefreshCanvasOther(ChartCanvas *ccThis) {
4357 // ..For each canvas...
4358 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4359 ChartCanvas *cc = g_canvasArray.Item(i);
4360 if (cc && (cc != ccThis)) cc->Refresh();
4361 }
4362}
4363
4364// Flav: This method reloads all charts for convenience
4365void MyFrame::ChartsRefresh() {
4366 if (!ChartData) return;
4367
4368 AbstractPlatform::ShowBusySpinner();
4369
4370 bool b_run = FrameTimer1.IsRunning();
4371
4372 FrameTimer1.Stop(); // stop other asynchronous activity
4373 FrameTenHzTimer.Stop();
4374
4375 // ..For each canvas...
4376 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4377 ChartCanvas *cc = g_canvasArray.Item(i);
4378 if (cc) {
4379 int currentIndex = cc->GetpCurrentStack()->GetCurrentEntrydbIndex();
4380 if (cc->GetQuiltMode()) {
4381 currentIndex = cc->GetQuiltReferenceChartIndex();
4382 }
4383 cc->canvasChartsRefresh(currentIndex);
4384 }
4385 }
4386
4387 if (b_run) FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
4388 if (b_run) FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
4389
4390 AbstractPlatform::HideBusySpinner();
4391}
4392
4393void MyFrame::InvalidateAllQuilts() {
4394 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4395 ChartCanvas *cc = g_canvasArray.Item(i);
4396 if (cc) {
4397 cc->InvalidateQuilt();
4398 cc->SetQuiltRefChart(-1);
4399 cc->m_singleChart = NULL;
4400 }
4401 }
4402}
4403
4404bool MyFrame::UpdateChartDatabaseInplace(ArrayOfCDI &DirArray, bool b_force,
4405 bool b_prog,
4406 const wxString &ChartListFileName) {
4407 bool b_run = FrameTimer1.IsRunning();
4408 FrameTimer1.Stop(); // stop other asynchronous activity
4409 FrameTenHzTimer.Stop();
4410
4411 bool b_runCOGTimer = FrameCOGTimer.IsRunning();
4412 FrameCOGTimer.Stop();
4413
4414 // ..For each canvas...
4415 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4416 ChartCanvas *cc = g_canvasArray.Item(i);
4417 if (cc) {
4418 cc->InvalidateQuilt();
4419 cc->SetQuiltRefChart(-1);
4420 cc->m_singleChart = NULL;
4421 }
4422 }
4423
4424 ChartData->PurgeCache();
4425
4426 // TODO
4427 // delete pCurrentStack;
4428 // pCurrentStack = NULL;
4429
4430 AbstractPlatform::ShowBusySpinner();
4431
4432 if (b_prog) {
4433 wxString longmsg = _("OpenCPN Chart Update");
4434 longmsg +=
4435 ".................................................................."
4436 "........";
4437
4438 Updateprog = new wxGenericProgressDialog();
4439
4440 wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
4441 Updateprog->SetFont(*qFont);
4442
4443 Updateprog->Create(_("OpenCPN Chart Update"), longmsg, 100, gFrame,
4444 wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
4445 wxPD_REMAINING_TIME);
4446
4447 DimeControl(Updateprog);
4448 Updateprog->Show();
4449 }
4450
4451 wxLogMessage(" ");
4452 wxLogMessage("Starting chart database Update...");
4453
4454 // The Update() function may set gWorldMapLocation if at least one of the
4455 // directories contains GSHHS files. Save current situation...
4456 m_gshhg_chart_loc = gWorldMapLocation;
4457 gWorldMapLocation = wxEmptyString;
4458
4459 ChartData->Update(DirArray, b_force, Updateprog);
4460
4461 AbstractPlatform::HideBusySpinner();
4462 return true;
4463}
4464
4465void MyFrame::FinalizeChartDBUpdate() {
4466 // Finalize chartdbs update after all async events finished.
4467 bool b_groupchange = ScrubGroupArray();
4468 ChartData->ApplyGroupArray(g_pGroupArray);
4469 RefreshGroupIndices();
4470
4471 if (b_groupchange) {
4472 pConfig->DestroyConfigGroups();
4473 pConfig->CreateConfigGroups(g_pGroupArray);
4474 }
4475 pConfig->UpdateSettings();
4476
4477 ScheduleReloadCharts();
4478}
4479
4480void MyFrame::ToggleQuiltMode(ChartCanvas *cc) {
4481 if (cc) {
4482 cc->ToggleCanvasQuiltMode();
4483#if 0
4484 bool cur_mode = cc->GetQuiltMode();
4485
4486 if( !cc->GetQuiltMode() )
4487 cc->SetQuiltMode( true );
4488 else
4489 if( cc->GetQuiltMode() ) {
4490 cc->SetQuiltMode( false );
4491 g_sticky_chart = cc->GetQuiltReferenceChartIndex();
4492 }
4493
4494
4495 if( cur_mode != cc->GetQuiltMode() ){
4496 //TODO >>SetupQuiltMode();
4497 DoChartUpdate();
4498 cc->InvalidateGL();
4499 Refresh();
4500 }
4501 g_bQuiltEnable = cc->GetQuiltMode();
4502
4503 // Recycle the S52 PLIB so that vector charts will flush caches and re-render
4504 if(ps52plib)
4505 ps52plib->GenerateStateHash();
4506#endif
4507 }
4508}
4509
4510void MyFrame::DoStackDown(AbstractChartCanvas *arg) {
4511 auto *cc = dynamic_cast<ChartCanvas *>(arg);
4512 assert(cc);
4513 DoStackDelta(cc, -1);
4514}
4515
4516void MyFrame::DoStackUp(AbstractChartCanvas *arg) {
4517 auto *cc = dynamic_cast<ChartCanvas *>(arg);
4518 assert(cc);
4519 DoStackDelta(cc, 1);
4520}
4521
4522void MyFrame::DoStackDown(ChartCanvas *cc) { DoStackDelta(cc, -1); }
4523
4524void MyFrame::DoStackUp(ChartCanvas *cc) { DoStackDelta(cc, 1); }
4525
4526void MyFrame::DoStackDelta(ChartCanvas *cc, int direction) {
4527 if (cc) {
4528 cc->DoCanvasStackDelta(direction);
4529 }
4530}
4531
4532void MyFrame::PositionIENCToolbar() {
4533#if 0
4534 if (g_iENCToolbar) {
4535 wxPoint posn;
4536 posn.x = (GetPrimaryCanvas()->GetSize().x - g_iENCToolbar->GetSize().x) / 2;
4537 posn.y = 4;
4538 g_iENCToolbar->Move(GetPrimaryCanvas()->ClientToScreen(posn));
4539 }
4540#endif
4541}
4542
4543// Defered initialization for anything that is not required to render the
4544// initial frame and takes a while to initialize. This gets opencpn up and
4545// running much faster.
4546void MyFrame::OnInitTimer(wxTimerEvent &event) {
4547 InitTimer.Stop();
4548 wxString msg;
4549 msg.Printf("OnInitTimer...%d", m_iInitCount);
4550 wxLogMessage(msg);
4551 // printf("init-%d\n", m_iInitCount);
4552
4553 wxLog::FlushActive();
4554
4555 switch (m_iInitCount++) {
4556 case 0: {
4557 EnableSettingsTool(false);
4558
4559 FontMgr::Get()
4560 .ScrubList(); // Clean the font list, removing nonsensical entries
4561
4562 if (g_bInlandEcdis) {
4563 double range = GetPrimaryCanvas()->GetCanvasRangeMeters();
4564 double range_set = 500.;
4565
4566 range = wxRound(range * 10) / 10.;
4567
4568 if (range > 4000.)
4569 range_set = 4000.;
4570 else if (range > 2000.)
4571 range_set = 2000.;
4572 else if (range > 1600.)
4573 range_set = 1600.;
4574 else if (range > 1200.)
4575 range_set = 1200.;
4576 else if (range > 800.)
4577 range_set = 800.;
4578 else
4579 range_set = 500.;
4580
4581 GetPrimaryCanvas()->SetCanvasRangeMeters(range_set);
4582 }
4583
4584 // Synchronize persistent Fullscreen mode
4585 g_Platform->SetFullscreen(g_bFullscreen);
4586
4587 // Rebuild chart database, if necessary
4588 if (g_NeedDBUpdate > 0) {
4589 RebuildChartDatabase();
4590 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4591 ChartCanvas *cc = g_canvasArray.Item(i);
4592 if (cc) {
4593 cc->SetGroupIndex(0, false); // all charts
4594 }
4595 }
4596
4597 // As a favor to new users, poll the database and
4598 // move the initial viewport so that a chart will come up.
4599
4600 double clat, clon;
4601 if (ChartData->GetCentroidOfLargestScaleChart(&clat, &clon,
4602 CHART_FAMILY_RASTER)) {
4603 gLat = clat;
4604 gLon = clon;
4605 gFrame->ClearbFollow(gFrame->GetPrimaryCanvas());
4606 } else {
4607 if (ChartData->GetCentroidOfLargestScaleChart(&clat, &clon,
4608 CHART_FAMILY_VECTOR)) {
4609 gLat = clat;
4610 gLon = clon;
4611 gFrame->ClearbFollow(gFrame->GetPrimaryCanvas());
4612 }
4613 }
4614
4615 g_NeedDBUpdate = 0;
4616 }
4617
4618#if 0
4619 // Load the waypoints. Both of these routines are very slow to execute
4620 // which is why they have been to defered until here
4621 auto colour_func = [](wxString c) { return GetGlobalColor(c); };
4622 pWayPointMan = new WayPointman(colour_func);
4623 WayPointmanGui(*pWayPointMan)
4624 .SetColorScheme(global_color_scheme, g_Platform->GetDisplayDPmm());
4625 // Reload the ownship icon from UserIcons, if present
4626 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4627 ChartCanvas *cc = g_canvasArray.Item(i);
4628 if (cc) {
4629 if (cc->SetUserOwnship()) cc->SetColorScheme(global_color_scheme);
4630 }
4631 }
4632
4633 NavObj_dB::GetInstance().ImportLegacyNavobj(this);
4634 NavObj_dB::GetInstance().LoadNavObjects();
4635
4636 // Re-enable anchor watches if set in config file
4637 if (!g_AW1GUID.IsEmpty()) {
4638 pAnchorWatchPoint1 = pWayPointMan->FindRoutePointByGUID(g_AW1GUID);
4639 }
4640 if (!g_AW2GUID.IsEmpty()) {
4641 pAnchorWatchPoint2 = pWayPointMan->FindRoutePointByGUID(g_AW2GUID);
4642 }
4643
4644 // Import Layer-wise any .gpx files from /layers directory
4645 wxString layerdir = g_Platform->GetPrivateDataDir();
4646 appendOSDirSlash(&layerdir);
4647 layerdir.Append("layers");
4648
4649 if (wxDir::Exists(layerdir)) {
4650 wxString laymsg;
4651 laymsg.Printf("Getting .gpx layer files from: %s", layerdir.c_str());
4652 wxLogMessage(laymsg);
4653 pConfig->LoadLayers(layerdir);
4654 }
4655#endif
4656
4657 break;
4658 }
4659 case 1:
4660 break;
4661
4662 case 2: {
4663 if (g_pi_manager->IsAnyPlugInChartEnabled()) b_reloadForPlugins = true;
4664 break;
4665 }
4666
4667 case 3: {
4668 if (g_MainToolbar) {
4669 g_MainToolbar->SetAutoHide(g_bAutoHideToolbar);
4670 g_MainToolbar->SetAutoHideTimer(g_nAutoHideToolbar);
4671 }
4672
4673#ifdef ANDROID
4674 if (g_MainToolbar)
4675 m_data_monitor->Move(g_MainToolbar->GetToolbarRect().x +
4676 g_MainToolbar->GetToolbarRect().width,
4677 3 * GetCharHeight());
4678#else
4679 m_data_monitor->Center();
4680#endif
4681
4682 break;
4683 }
4684
4685 case 4: {
4686 int sx, sy;
4687 pConfig->SetPath("/Settings");
4688 pConfig->Read("OptionsSizeX", &sx, -1);
4689 pConfig->Read("OptionsSizeY", &sy, -1);
4690
4691 wxWindow *optionsParent = this;
4692#ifdef __WXOSX__
4693 optionsParent = GetPrimaryCanvas();
4694#endif
4695 BuildiENCToolbar(true, m_toolbar_callbacks);
4696
4697 break;
4698 }
4699
4700 case 5: {
4701 // FIXME (leamas) Remove, delegate to CmdlineClient ctor
4702 if (!g_params.empty()) {
4703 for (size_t n = 0; n < g_params.size(); n++) {
4704 wxString path = g_params[n];
4705 if (::wxFileExists(path)) {
4707 pSet->load_file(path.fn_str());
4708 int wpt_dups;
4709
4710 pSet->LoadAllGPXObjects(
4711 !pSet->IsOpenCPN(), wpt_dups,
4712 true); // Import with full vizibility of names and objects
4713 LLBBox box = pSet->GetBBox();
4714 if (box.GetValid()) {
4715 CenterView(GetPrimaryCanvas(), box);
4716 }
4717 delete pSet;
4718 }
4719 }
4720 }
4721 break;
4722 }
4723 case 6: {
4724 InitAppMsgBusListener();
4726
4727 // if WMM is not in use..
4728 // set the Mag Variation to the user specified value
4729 auto loader = PluginLoader::GetInstance();
4730 bool b_haveWMM = loader && loader->IsPlugInAvailable("WMM");
4731 if (!b_haveWMM) gVar = g_UserVar;
4732
4733 break;
4734 }
4735
4736 case 7: {
4737 // Load the waypoints. Both of these routines are very slow to execute
4738 // which is why they have been to defered until here
4739 auto colour_func = [](wxString c) { return GetGlobalColor(c); };
4740 pWayPointMan = new WayPointman(colour_func);
4741 WayPointmanGui(*pWayPointMan)
4742 .SetColorScheme(global_color_scheme, g_Platform->GetDisplayDPmm());
4743 // Reload the ownship icon from UserIcons, if present
4744 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4745 ChartCanvas *cc = g_canvasArray.Item(i);
4746 if (cc) {
4747 if (cc->SetUserOwnship()) cc->SetColorScheme(global_color_scheme);
4748 }
4749 }
4750
4751 NavObj_dB::GetInstance().ImportLegacyNavobj(this);
4752 NavObj_dB::GetInstance().LoadNavObjects();
4753
4754 // Re-enable anchor watches if set in config file
4755 if (!g_AW1GUID.IsEmpty()) {
4756 pAnchorWatchPoint1 = pWayPointMan->FindRoutePointByGUID(g_AW1GUID);
4757 }
4758 if (!g_AW2GUID.IsEmpty()) {
4759 pAnchorWatchPoint2 = pWayPointMan->FindRoutePointByGUID(g_AW2GUID);
4760 }
4761
4762 // Import Layer-wise any .gpx files from /layers directory
4763 wxString layerdir = g_Platform->GetPrivateDataDir();
4764 appendOSDirSlash(&layerdir);
4765 layerdir.Append("layers");
4766
4767 if (wxDir::Exists(layerdir)) {
4768 wxString laymsg;
4769 laymsg.Printf("Getting .gpx layer files from: %s", layerdir.c_str());
4770 wxLogMessage(laymsg);
4771 pConfig->LoadLayers(layerdir);
4772 }
4773 break;
4774 }
4775 case 8: {
4776 if (!g_kiosk_startup) {
4777 AbstractPlatform::ShowBusySpinner();
4778
4779 int sx, sy;
4780 pConfig->SetPath("/Settings");
4781 pConfig->Read("OptionsSizeX", &sx, -1);
4782 pConfig->Read("OptionsSizeY", &sy, -1);
4783
4784 wxWindow *optionsParent = this;
4785#ifdef __WXOSX__
4786 optionsParent = GetPrimaryCanvas();
4787#endif
4788 OptionsCallbacks callbacks;
4789 callbacks.prepare_close = [&](options *me, int changes) {
4790 PrepareOptionsClose(me, changes);
4791 };
4792 callbacks.process_dialog = [&](int changes, ArrayOfCDI *workdir_list) {
4793 ProcessOptionsDialog(changes, workdir_list);
4794 };
4795 g_options = new options(optionsParent, callbacks, -1, _("Options"),
4796 wxPoint(-1, -1), wxSize(sx, sy));
4797 AbstractPlatform::HideBusySpinner();
4798 }
4799 break;
4800 }
4801
4802 default: {
4803 // Last call....
4804 wxLogMessage("OnInitTimer...Last Call");
4805
4806 g_pi_manager->CallLateInit();
4807
4808 RequestNewMasterToolbar();
4809
4810 PositionIENCToolbar();
4811
4812 g_bDeferredInitDone = true;
4813
4814 gFrame->DoChartUpdate();
4815 FontMgr::Get()
4816 .ScrubList(); // Clean the font list, removing nonsensical entries
4817
4818 gFrame->ReloadAllVP(); // once more, and good to go
4819 // gFrame->Refresh(false);
4820 // gFrame->Raise();
4821
4822 GetPrimaryCanvas()->SetFocus();
4823 GetPrimaryCanvas()->Enable();
4824 g_focusCanvas = GetPrimaryCanvas();
4825
4826 if (b_reloadForPlugins) {
4827 // If any PlugIn implements PlugIn Charts, we need to re-run the
4828 // initial chart load logic to select the correct chart as saved from
4829 // the last run of the app. This will be triggered at the next
4830 // DoChartUpdate()
4831 if (g_pi_manager->IsAnyPlugInChartEnabled()) {
4832 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4833 ChartCanvas *cc = g_canvasArray.Item(i);
4834 if (cc) cc->SetFirstAuto(true);
4835 }
4836 }
4837
4838 DoChartUpdate();
4839 ChartsRefresh();
4840 }
4841
4842 wxLogMessage("OnInitTimer...Finalize Canvases");
4843
4844 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
4845 ChartCanvas *cc = g_canvasArray.Item(i);
4846 if (cc) {
4847 cc->CreateMUIBar();
4848 cc->CheckGroupValid();
4849 }
4850 }
4851
4852#ifdef __ANDROID__
4853 androidEnableBackButton(true);
4854 androidEnableRotation();
4855 androidEnableOptionItems(true);
4856 androidLastCall();
4857#endif
4858
4859 if (g_start_fullscreen && !IsFullScreen()) ToggleFullScreen();
4860
4861 UpdateStatusBar();
4862 SendSizeEvent();
4863
4864 // Start up the tickers....
4865 gFrame->FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
4866 // Start up the ViewPort Rotation angle Averaging Timer....
4867 gFrame->FrameCOGTimer.Start(2000, wxTIMER_CONTINUOUS);
4868 // Start up the Ten Hz timer....
4869 gFrame->FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
4870
4871 break;
4872 }
4873 } // switch
4874
4875 if (!g_bDeferredInitDone) InitTimer.Start(10, wxTIMER_ONE_SHOT);
4876
4877 wxLog::FlushActive();
4878
4879 RefreshAllCanvas(true);
4880 UsbWatchDaemon::GetInstance().Start();
4881 EnableSettingsTool(true);
4882}
4883
4884wxDEFINE_EVENT(EVT_BASIC_NAV_DATA, ObservedEvt);
4885wxDEFINE_EVENT(EVT_GPS_WATCHDOG, ObservedEvt);
4886
4887void MyFrame::InitAppMsgBusListener() {
4888 auto &msgbus = AppMsgBus::GetInstance();
4889
4890 // BasicNavData
4891 AppMsg msg_basic(AppMsg::Type::BasicNavData);
4892 listener_basic_navdata.Listen(msg_basic, this, EVT_BASIC_NAV_DATA);
4893
4894 Bind(EVT_BASIC_NAV_DATA, [&](ObservedEvt ev) {
4895 auto ptr = ev.GetSharedPtr();
4896 auto basicnav_msg = std::static_pointer_cast<const BasicNavDataMsg>(ptr);
4897 HandleBasicNavMsg(basicnav_msg);
4898 });
4899
4900 // GPS Watchdog expiry status
4901 AppMsg msg_watchdog(AppMsg::Type::GPSWatchdog);
4902 listener_gps_watchdog.Listen(msg_watchdog, this, EVT_GPS_WATCHDOG);
4903
4904 Bind(EVT_GPS_WATCHDOG, [&](ObservedEvt ev) {
4905 auto ptr = ev.GetSharedPtr();
4906 auto msg = std::static_pointer_cast<const GPSWatchdogMsg>(ptr);
4907 HandleGPSWatchdogMsg(msg);
4908 });
4909}
4910
4912#ifdef __ANDROID__
4914void MyFrame::ReleaseApiListeners() {}
4915
4916#else
4918 auto &server = LocalServerApi::GetInstance();
4919 m_on_raise_listener.Init(server.on_raise, [&](ObservedEvt) { Raise(); });
4920 m_on_quit_listener.Init(server.on_quit, [&](ObservedEvt) { FastClose(); });
4921 server.SetGetRestApiEndpointCb([&] { return m_rest_server.GetEndpoint(); });
4922 server.open_file_cb = [&](const std::string &path) {
4923 return m_open_gpx_file(path);
4924 };
4925}
4926
4927void MyFrame::ReleaseApiListeners() { LocalServerApi::ReleaseInstance(); }
4928#endif
4929
4930void MyFrame::HandleGPSWatchdogMsg(std::shared_ptr<const GPSWatchdogMsg> msg) {
4931 if (msg->gps_watchdog <= 0) {
4932 if (msg->wd_source == GPSWatchdogMsg::WDSource::position) {
4933 bool last_bGPSValid = bGPSValid;
4934 bGPSValid = false;
4935 m_fixtime = 0; // Invalidate fix time
4936 if (last_bGPSValid != bGPSValid) UpdateGPSCompassStatusBoxes(true);
4937
4938 // Possible notification on position watchdog timeout...
4939 // if fix has been valid for at least 5 minutes, and then lost,
4940 // then post a critical notification
4941 if (m_fix_start_time.IsValid()) {
4942 wxDateTime now = wxDateTime::Now();
4943 wxTimeSpan span = now - m_fix_start_time;
4944 if (span.IsLongerThan(wxTimeSpan(0, 5))) {
4945 auto &noteman = NotificationManager::GetInstance();
4946 wxString msg = _("GNSS Position fix lost");
4947 noteman.AddNotification(NotificationSeverity::kCritical,
4948 msg.ToStdString());
4949 m_fix_start_time = wxInvalidDateTime;
4950 }
4951 }
4952
4953 } else if (msg->wd_source == GPSWatchdogMsg::WDSource::velocity) {
4954 bool last_bVelocityValid = bVelocityValid;
4955 bVelocityValid = false;
4956 }
4957
4958 UpdateStatusBar();
4959 }
4960}
4961
4962void MyFrame::CalculateCOGAverage() {
4963 // Maintain average COG for Course Up Mode
4964 if (!std::isnan(gCog)) {
4965 if (g_COGAvgSec > 0) {
4966 // Make a hole
4967 for (int i = g_COGAvgSec - 1; i > 0; i--) COGTable[i] = COGTable[i - 1];
4968 COGTable[0] = gCog;
4969
4970 double sum = 0., count = 0;
4971 for (int i = 0; i < g_COGAvgSec; i++) {
4972 double adder = COGTable[i];
4973 if (std::isnan(adder)) continue;
4974
4975 if (fabs(adder - g_COGAvg) > 180.) {
4976 if ((adder - g_COGAvg) > 0.)
4977 adder -= 360.;
4978 else
4979 adder += 360.;
4980 }
4981
4982 sum += adder;
4983 count++;
4984 }
4985 sum /= count;
4986
4987 if (sum < 0.)
4988 sum += 360.;
4989 else if (sum >= 360.)
4990 sum -= 360.;
4991
4992 g_COGAvg = sum;
4993 } else
4994 g_COGAvg = gCog;
4995 }
4996}
4997
4998void MyFrame::HandleBasicNavMsg(std::shared_ptr<const BasicNavDataMsg> msg) {
4999 m_fixtime = msg->time;
5000 double hdt_data_interval = 0;
5001 double fix_time_interval = 0;
5002
5003 double msgtime = msg->set_time.tv_sec;
5004 double m1 = msg->set_time.tv_nsec / 1e9;
5005 msgtime += m1;
5006
5007 if (((msg->vflag & POS_UPDATE) == POS_UPDATE) &&
5008 ((msg->vflag & POS_VALID) == POS_VALID)) {
5009 // Maintain valid fix start time
5010 if (!m_fix_start_time.IsValid()) {
5011 m_fix_start_time = wxDateTime::Now();
5012 }
5013
5014 // Check the position change, looking for a valid new fix.
5015 double dist, brg;
5016 DistanceBearingMercator(gLat, gLon, gLat_gt, gLon_gt, &brg, &dist);
5017
5018 if (dist > .0001) { // Avoid duplicate position report
5019 fix_time_gt_last = fix_time_gt;
5020 uint64_t fix_time_gt_now =
5021 msg->set_time.tv_sec * 1e9 + msg->set_time.tv_nsec;
5022 fix_time_interval = (fix_time_gt_now - fix_time_gt_last) / (double)1e9;
5023 // printf("interval: %g\n", fix_time_interval);
5024
5025 // Calculate an implied SOG from the position change and time interval
5026 double implied_sog = dist / (fix_time_interval / 3600);
5027
5028 // printf ("Fix Interval: %g\n", fix_time_interval);
5029 // printf("SOG est: %g %g\n", gSog, implied_sog);
5030 // shuffle history data
5031 gLat_gt_m1 = gLat_gt;
5032 gLon_gt_m1 = gLon_gt;
5033 gLat_gt = gLat;
5034 gLon_gt = gLon;
5035
5036 fix_time_gt = fix_time_gt_now;
5037 }
5038 }
5039
5040 if (((msg->vflag & COG_UPDATE) == COG_UPDATE) &&
5041 ((msg->vflag & SOG_UPDATE) == SOG_UPDATE)) {
5042 gCog_gt_m1 = gCog_gt;
5043 gCog_gt = gCog;
5044 gSog_gt = gSog;
5045
5046 // In every case, if SOG is too slow, the COG is undefined.
5047 if (gSog < 0.1) {
5048 gCog_gt = NAN;
5049 gCog_gt_m1 = NAN;
5050 }
5051
5052 if (!std::isnan(gCog_gt_m1)) { // Startup
5053#if 0
5054 if ((fabs(gSog - implied_sog) / gSog) > 0.5) {
5055 // Probably a synthetic data stream, with multiple position sources.
5056 // Do not try to interpolate position at 10 Hz.
5057 gSog_gt = 0;
5058 cog_rate_gt = 0;
5059 } else
5060#endif
5061 if ((fix_time_gt - fix_time_gt_last) > .08) {
5062 // Calculate an estimated Rate-of-turn
5063 int dir = 0;
5064 double diff = 0;
5065 double difft = 0;
5066 if (gCog_gt > gCog_gt_m1) {
5067 if ((gCog_gt - gCog_gt_m1) > 180.)
5068 dir = 1; // left
5069 else
5070 dir = 2; // right
5071 } else {
5072 if ((gCog_gt_m1 - gCog_gt) > 180.)
5073 dir = 2; // right
5074 else
5075 dir = 1; // left
5076 }
5077 difft = fabs(gCog_gt - gCog_gt_m1);
5078 if (fabs(difft > 180.)) difft = fabs(difft - 360.);
5079 if (dir == 1)
5080 diff = -difft;
5081 else
5082 diff = difft;
5083
5084 // double diff = gCog_gt - gCog_gt_m1;
5085 // printf("diff %g %d\n", diff, dir);
5086 double tentative_cog_rate_gt = diff / (fix_time_gt - fix_time_gt_last);
5087 tentative_cog_rate_gt *= 1e9; // degrees / sec
5088 cog_rate_gt = tentative_cog_rate_gt;
5089 }
5090
5091 gCog = gCog_gt_m1;
5092 }
5093 // printf("cog_rate_gt %g %g\n", gCog, cog_rate_gt);
5094 }
5095
5096 if ((msg->vflag & HDT_UPDATE) == HDT_UPDATE) {
5097#if 0
5098// Lowpass filter, 10 samples
5099static double hdt_avg;
5100 double hdt_norm = gHdt;
5101 if(gHdt > 180) hdt_norm -= 360;
5102
5103 hdt_avg *= 0.9;
5104 hdt_avg += hdt_norm * 0.1;
5105 gHdt = hdt_avg;
5106 if( gHdt < 0) gHdt += 360.;
5107#endif
5108
5109 if (!std::isnan(gHdt)) {
5110 // Prepare to estimate the gHdt from prior ground truth measurements
5111 uint64_t hdt_time_gt_last = hdt_time_gt;
5112 hdt_time_gt = msg->set_time.tv_sec * 1e9 + msg->set_time.tv_nsec;
5113 hdt_data_interval = (hdt_time_gt - hdt_time_gt_last) / 1e9;
5114
5115 // Skip data reports that come too frequently
5116 if (hdt_data_interval > .09) {
5117 // shuffle points
5118 gHdt_gt_m1 = gHdt_gt;
5119 gHdt_gt = gHdt;
5120
5121 if (!std::isnan(gHdt_gt_m1)) { // startup
5122 // Calculate an estimated Rate-of-change of gHdt
5123 double tentative_hdt_rate_gt =
5124 (gHdt_gt - gHdt_gt_m1) / (hdt_time_gt - hdt_time_gt_last);
5125 tentative_hdt_rate_gt *= 1e9; // degrees / sec
5126 // Sanity check, and resolve the "phase" problem at +/- North
5127 if (fabs(tentative_hdt_rate_gt - hdt_rate_gt) < 180.)
5128 hdt_rate_gt = tentative_hdt_rate_gt;
5129
5130 gHdt = gHdt_gt_m1;
5131 }
5132 }
5133 }
5134 }
5135
5136 if (std::isnan(gHdt)) gHdt_gt = NAN; // Handle loss of signal
5137
5138 // Some housekeeping
5139 CalculateCOGAverage();
5140 FilterCogSog();
5141
5142 // Maintain the GPS position validity flag
5143 // Determined by source validity of RMC, GGA, GLL (N0183)
5144 // or PGNs 129029, 129025 (N2K)
5145 // Positions by sK and AIVDO are assumed valid
5146 bool last_bGPSValid = bGPSValid;
5147 if ((msg->vflag & POS_UPDATE) == POS_UPDATE) {
5148 if ((msg->vflag & POS_VALID) == POS_VALID)
5149 bGPSValid = true;
5150 else
5151 bGPSValid = false;
5152 }
5153 if (last_bGPSValid != bGPSValid) UpdateGPSCompassStatusBoxes(true);
5154
5155 bVelocityValid = true;
5156 UpdateStatusBar();
5157}
5158
5159void MyFrame::UpdateStatusBar() {
5160 // Show a little heartbeat tick in StatusWindow0 on NMEA events
5161 // But no faster than 10 hz.
5162 unsigned long uiCurrentTickCount;
5163 m_MMEAeventTime.SetToCurrent();
5164 uiCurrentTickCount =
5165 m_MMEAeventTime.GetMillisecond() / 100; // tenths of a second
5166 uiCurrentTickCount += m_MMEAeventTime.GetTicks() * 10;
5167 if (uiCurrentTickCount > m_ulLastNMEATicktime + 1) {
5168 m_ulLastNMEATicktime = uiCurrentTickCount;
5169
5170 if (m_tick_idx++ > 6) m_tick_idx = 0;
5171 }
5172
5173 // Show gLat/gLon in StatusWindow0
5174
5175 if (NULL != GetStatusBar()) {
5176 if (1 /*pos_valid*/) {
5177 char tick_buf[2];
5178 tick_buf[0] = nmea_tick_chars[m_tick_idx];
5179 tick_buf[1] = 0;
5180
5181 wxString s1(tick_buf, wxConvUTF8);
5182 s1 += _(" Ship ");
5183 s1 += toSDMM(1, gLat);
5184 s1 += " ";
5185 s1 += toSDMM(2, gLon);
5186
5187 if (STAT_FIELD_TICK >= 0) SetStatusText(s1, STAT_FIELD_TICK);
5188 }
5189
5190 wxString sogcog;
5191 if (!std::isnan(gSog))
5192 sogcog.Printf("SOG %2.2f " + getUsrSpeedUnit() + " ", toUsrSpeed(gSog));
5193 else
5194 sogcog.Printf("SOG --- ");
5195
5196 wxString cogs;
5197 // We show COG only if SOG is > 0.05
5198 if (!std::isnan(gCog) && !std::isnan(gSog) && (gSog > 0.05)) {
5199 if (g_bShowTrue)
5200 cogs << wxString::Format(wxString("COG %03d%c "), (int)gCog, 0x00B0);
5201 if (g_bShowMag)
5202 cogs << wxString::Format(wxString("COG %03d%c(M) "),
5203 (int)toMagnetic(gCog), 0x00B0);
5204 } else
5205 cogs.Printf(("COG ---%c"), 0x00B0);
5206
5207 sogcog.Append(cogs);
5208 SetStatusText(sogcog, STAT_FIELD_SOGCOG);
5209 }
5210}
5211
5212// Manage the application memory footprint on a periodic schedule
5213void MyFrame::OnMemFootTimer(wxTimerEvent &event) {
5214 MemFootTimer.Stop();
5215
5216 int memsize = GetApplicationMemoryUse();
5217
5218 g_MemFootMB = 100;
5219 printf("Memsize: %d \n", memsize);
5220 // The application memory usage has exceeded the target, so try to manage it
5221 // down....
5222 if (memsize > (g_MemFootMB * 1000)) {
5223 ChartCanvas *cc = GetPrimaryCanvas();
5224 if (ChartData && cc) {
5225 // Get a local copy of the cache info
5226 wxArrayPtrVoid *pCache = ChartData->GetChartCache();
5227 unsigned int nCache = pCache->GetCount();
5228 CacheEntry *pcea = new CacheEntry[nCache];
5229
5230 for (unsigned int i = 0; i < nCache; i++) {
5231 CacheEntry *pce = (CacheEntry *)(pCache->Item(i));
5232 pcea[i] = *pce; // ChartBase *Ch = (ChartBase *)pce->pChart;
5233 }
5234
5235 if (nCache > 1) {
5236 // Bubble Sort the local cache entry array
5237 bool b_cont = true;
5238 while (b_cont) {
5239 b_cont = false;
5240 for (unsigned int i = 0; i < nCache - 1; i++) {
5241 if (pcea[i].RecentTime > pcea[i + 1].RecentTime) {
5242 CacheEntry tmp = pcea[i];
5243 pcea[i] = pcea[i + 1];
5244 pcea[i + 1] = tmp;
5245 b_cont = true;
5246 break;
5247 }
5248 }
5249 }
5250
5251 // Free up some chart cache entries until the memory footprint target
5252 // is realized
5253
5254 unsigned int idelete = 0; // starting at top. which is oldest
5255 unsigned int idelete_max = pCache->GetCount();
5256
5257 // How many can be deleted?
5258 unsigned int minimum_cache = 1;
5259 if (cc->GetQuiltMode()) minimum_cache = cc->GetQuiltChartCount();
5260
5261 while ((memsize > (g_MemFootMB * 1000)) &&
5262 (pCache->GetCount() > minimum_cache) &&
5263 (idelete < idelete_max)) {
5264 int memsizeb = memsize;
5265
5266 ChartData->DeleteCacheChart((ChartBase *)pcea[idelete].pChart);
5267 idelete++;
5268 memsize = GetApplicationMemoryUse();
5269 printf("delete, before: %d after: %d\n", memsizeb, memsize);
5270 }
5271 }
5272
5273 delete[] pcea;
5274 }
5275 }
5276
5277 MemFootTimer.Start(9000, wxTIMER_CONTINUOUS);
5278}
5279
5280int ut_index;
5281
5282void MyFrame::CheckToolbarPosition() {
5283#ifdef __WXMAC__
5284 // Manage Full Screen mode on Mac Mojave 10.14
5285 static bool bMaximized;
5286
5287 if (IsMaximized() && !bMaximized) {
5288 bMaximized = true;
5289 if (g_MainToolbar) {
5290 g_MainToolbar->SetYAuxOffset(g_MainToolbar->GetToolSize().y * 15 / 10);
5291 g_MainToolbar->SetDefaultPosition();
5292 g_MainToolbar->Realize();
5293 }
5294 PositionIENCToolbar();
5295 } else if (!IsMaximized() && bMaximized) {
5296 bMaximized = false;
5297 if (g_MainToolbar) {
5298 g_MainToolbar->SetYAuxOffset(0);
5299 g_MainToolbar->SetDockY(-1);
5300 g_MainToolbar->SetDefaultPosition();
5301 g_MainToolbar->Realize();
5302 }
5303 PositionIENCToolbar();
5304 }
5305#endif
5306}
5307
5308void MyFrame::ProcessUnitTest() {
5309 if (!g_bPauseTest && (g_unit_test_1 || g_unit_test_2)) {
5310 // if((0 == ut_index) && GetQuiltMode())
5311 // ToggleQuiltMode();
5312
5313 // We use only one canvas for the unit tests, so far...
5314 ChartCanvas *cc = GetPrimaryCanvas();
5315
5316 cc->m_bFollow = false;
5317 if (g_MainToolbar && g_MainToolbar->GetToolbar())
5318 g_MainToolbar->GetToolbar()->ToggleTool(ID_FOLLOW, cc->m_bFollow);
5319 int ut_index_max = ((g_unit_test_1 > 0) ? (g_unit_test_1 - 1) : INT_MAX);
5320
5321 if (ChartData) {
5322 if (cc->m_groupIndex > 0) {
5323 while (ut_index < ChartData->GetChartTableEntries() &&
5324 !ChartData->IsChartInGroup(ut_index, cc->m_groupIndex)) {
5325 ut_index++;
5326 }
5327 }
5328 if (ut_index < ChartData->GetChartTableEntries()) {
5329 // printf("%d / %d\n", ut_index, ChartData->GetChartTableEntries());
5330 const ChartTableEntry *cte = &ChartData->GetChartTableEntry(ut_index);
5331
5332 double clat = (cte->GetLatMax() + cte->GetLatMin()) / 2;
5333 double clon = (cte->GetLonMax() + cte->GetLonMin()) / 2;
5334
5335 vLat = clat;
5336 vLon = clon;
5337
5338 cc->SetViewPoint(clat, clon);
5339
5340 if (cc->GetQuiltMode()) {
5341 if (cc->IsChartQuiltableRef(ut_index))
5342 cc->SelectQuiltRefdbChart(ut_index);
5343 } else
5344 cc->SelectdbChart(ut_index);
5345
5346 double ppm; // final ppm scale to use
5347 if (g_unit_test_1) {
5348 ppm = cc->GetCanvasScaleFactor() / cte->GetScale();
5349 ppm /= 2;
5350 } else {
5351 double rw, rh; // width, height
5352 int ww, wh; // chart window width, height
5353
5354 // width in nm
5355 DistanceBearingMercator(cte->GetLatMin(), cte->GetLonMin(),
5356 cte->GetLatMin(), cte->GetLonMax(), NULL,
5357 &rw);
5358
5359 // height in nm
5360 DistanceBearingMercator(cte->GetLatMin(), cte->GetLonMin(),
5361 cte->GetLatMax(), cte->GetLonMin(), NULL,
5362 &rh);
5363
5364 cc->GetSize(&ww, &wh);
5365 ppm = wxMin(ww / (rw * 1852), wh / (rh * 1852)) * (100 - fabs(clat)) /
5366 90;
5367 ppm = wxMin(ppm, 1.0);
5368 }
5369 cc->SetVPScale(ppm);
5370
5371 cc->ReloadVP();
5372
5373 ut_index++;
5374 if (ut_index > ut_index_max) exit(0);
5375 } else {
5376 _exit(0);
5377 }
5378 }
5379 }
5380}
5381double gCog_last;
5382
5383void MyFrame::OnFrameTenHzTimer(wxTimerEvent &event) {
5384 // Check to see if in non-North-Up mode
5385 bool b_rotate = false;
5386 for (ChartCanvas *cc : g_canvasArray) {
5387 if (cc) b_rotate |= (cc->GetUpMode() != NORTH_UP_MODE);
5388 }
5389
5390 if (!b_rotate && !g_btenhertz) return; // Nothing to do
5391
5392 bool b_update = false;
5393 if (g_btenhertz) {
5394 if (!std::isnan(gCog) && !std::isnan(gSog)) {
5395 // Estimate current state by extrapolating from last "ground truth" state
5396
5397 struct timespec now;
5398 clock_gettime(CLOCK_MONOTONIC, &now);
5399 uint64_t diff = 1e9 * (now.tv_sec) + now.tv_nsec - fix_time_gt;
5400 double diffc = diff / 1e9; // sec
5401
5402 // Set gCog as estimated from last two ground truth fixes
5403 double gCog_tentative = gCog_gt_m1 + (cog_rate_gt * diffc);
5404 if (gCog_tentative >= 360.) gCog_tentative -= 360.;
5405 if (gCog_tentative < 0.) gCog_tentative += 360.;
5406 gCog = gCog_tentative;
5407
5408 // printf(" cog: %g\n", gCog);
5409 // And the same for gHdt
5410 if (!std::isnan(gHdt_gt) && !std::isnan(gHdt_gt_m1)) {
5411 uint64_t diff = 1e9 * (now.tv_sec) + now.tv_nsec - hdt_time_gt;
5412 double diffc = diff / 1e9; // sec
5413 gHdt = gHdt_gt_m1 + (hdt_rate_gt * diffc);
5414 }
5415
5416 // Estimate lat/lon position
5417 if (gSog_gt && !std::isnan(gCog_gt)) {
5418 double delta_t = diffc / 3600; // hours
5419 double distance = gSog_gt * delta_t; // NMi
5420
5421 // spherical (close enough)
5422 double angr = gCog_gt / 180 * M_PI;
5423 double latr = gLat_gt * M_PI / 180;
5424 double D = distance / 3443; // earth radius in nm
5425 double sD = sin(D), cD = cos(D);
5426 double sy = sin(latr), cy = cos(latr);
5427 double sa = sin(angr), ca = cos(angr);
5428
5429 gLon = gLon_gt + asin(sa * sD / cy) * 180 / M_PI;
5430 gLat = asin(sy * cD + cy * sD * ca) * 180 / M_PI;
5431 }
5432 }
5433
5434 b_update = true;
5435 }
5436
5437 // In a valid rotation mode ?
5438 if (b_rotate) {
5439 for (ChartCanvas *cc : g_canvasArray) {
5440 if (cc) cc->DoCanvasCOGSet();
5441 }
5442 b_update = true;
5443 }
5444
5445 if (b_update) {
5446 for (ChartCanvas *cc : g_canvasArray) {
5447 if (cc) {
5448 if (g_bopengl) {
5449 if (cc->GetUpMode() != NORTH_UP_MODE || cc->m_bFollow) {
5450 cc->DoCanvasUpdate();
5451 } else
5452 cc->Refresh(false); // Process ownship motion at 10 Hz.
5453 }
5454 }
5455 }
5456 }
5457
5458 gCog_last = gCog;
5459 FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
5460}
5461
5462bool MyFrame::ProcessQuitFlag() {
5463 // Listen for quitflag to be set, requesting application close
5464 if (quitflag) {
5465 FrameTimer1.Stop();
5466 FrameTenHzTimer.Stop();
5467
5468 wxWindow *top = wxTheApp ? wxTheApp->GetTopWindow() : nullptr;
5469 if (top) top->Close(true);
5470
5471 return true;
5472 }
5473 return false;
5474}
5475
5476void MyFrame::ProcessDeferredTrackOn() {
5477 // If tracking carryover was found in config file, enable tracking as soon as
5478 // GPS become valid
5479 if (g_bDeferredStartTrack) {
5480 if (!g_bTrackActive) {
5481 if (bGPSValid) {
5482 gFrame->TrackOn();
5483 g_bDeferredStartTrack = false;
5484 }
5485 } else { // tracking has been manually activated
5486 g_bDeferredStartTrack = false;
5487 }
5488 }
5489}
5490
5491void MyFrame::ProcessAnchorWatch() {
5492 // Check for anchorwatch alarms // pjotrc
5493 // 2010.02.15
5494 if (pAnchorWatchPoint1) {
5495 double dist;
5496 double brg;
5497 DistanceBearingMercator(pAnchorWatchPoint1->m_lat,
5498 pAnchorWatchPoint1->m_lon, gLat, gLon, &brg, &dist);
5499 double d = g_nAWMax;
5500 (pAnchorWatchPoint1->GetName()).ToDouble(&d);
5501 d = ocpn::AnchorDistFix(d, AnchorPointMinDist, g_nAWMax);
5502 bool toofar = false;
5503 bool tooclose = false;
5504 if (d >= 0.0) toofar = (dist * 1852. > d);
5505 if (d < 0.0) tooclose = (dist * 1852 < -d);
5506
5507 if (tooclose || toofar)
5508 AnchorAlertOn1 = true;
5509 else
5510 AnchorAlertOn1 = false;
5511 } else
5512 AnchorAlertOn1 = false;
5513
5514 if (pAnchorWatchPoint2) {
5515 double dist;
5516 double brg;
5517 DistanceBearingMercator(pAnchorWatchPoint2->m_lat,
5518 pAnchorWatchPoint2->m_lon, gLat, gLon, &brg, &dist);
5519
5520 double d = g_nAWMax;
5521 (pAnchorWatchPoint2->GetName()).ToDouble(&d);
5522 d = ocpn::AnchorDistFix(d, AnchorPointMinDist, g_nAWMax);
5523 bool toofar = false;
5524 bool tooclose = false;
5525 if (d >= 0) toofar = (dist * 1852. > d);
5526 if (d < 0) tooclose = (dist * 1852 < -d);
5527
5528 if (tooclose || toofar)
5529 AnchorAlertOn2 = true;
5530 else
5531 AnchorAlertOn2 = false;
5532 } else
5533 AnchorAlertOn2 = false;
5534
5536 AnchorAlertOn1 = true;
5537}
5538
5539void MyFrame::SendFixToPlugins() {
5540 // Build and send a Position Fix event to PlugIns
5541 if (g_pi_manager) {
5542 GenericPosDatEx GPSData;
5543 GPSData.kLat = gLat;
5544 GPSData.kLon = gLon;
5545 GPSData.kCog = gCog;
5546 GPSData.kSog = gSog;
5547 GPSData.kVar = gVar;
5548 GPSData.kHdm = gHdm;
5549 GPSData.kHdt = gHdt;
5550 GPSData.nSats = g_SatsInView;
5551
5552 wxDateTime tCheck((time_t)m_fixtime);
5553 if (tCheck.IsValid()) {
5554 // As a special case, when no GNSS data is available, m_fixtime is set to
5555 // zero. Note wxDateTime(0) is valid, so the zero value is passed to the
5556 // plugins. The plugins should check for zero and not use the time in that
5557 // case.
5558 GPSData.FixTime = m_fixtime;
5559 } else {
5560 // Note: I don't think this is ever reached, as m_fixtime can never be set
5561 // to wxLongLong(wxINT64_MIN), which is the only way to get here.
5562 GPSData.FixTime = wxDateTime::Now().GetTicks();
5563 }
5564
5565 SendPositionFixToAllPlugIns(&GPSData);
5566 }
5567}
5568
5569void MyFrame::ProcessLogAndBells() {
5570 // Send current nav status data to log file on every half hour // pjotrc
5571 // 2010.02.09
5572 wxDateTime lognow = wxDateTime::Now(); // pjotrc 2010.02.09
5573 int hourLOC = lognow.GetHour();
5574 int minuteLOC = lognow.GetMinute();
5575 lognow.MakeGMT();
5576 int minuteUTC = lognow.GetMinute();
5577 int second = lognow.GetSecond();
5578
5579 wxTimeSpan logspan = lognow.Subtract(g_loglast_time);
5580 if ((logspan.IsLongerThan(wxTimeSpan(0, 30, 0, 0))) || (minuteUTC == 0) ||
5581 (minuteUTC == 30)) {
5582 if (logspan.IsLongerThan(wxTimeSpan(0, 1, 0, 0))) {
5583 wxString day = lognow.FormatISODate();
5584 wxString utc = lognow.FormatISOTime();
5585 wxString navmsg = "LOGBOOK: ";
5586 navmsg += day;
5587 navmsg += " ";
5588 navmsg += utc;
5589 navmsg += " UTC ";
5590
5591 if (bGPSValid) {
5592 wxString data;
5593 data.Printf(" GPS Lat %10.5f Lon %10.5f ", gLat, gLon);
5594 navmsg += data;
5595
5596 wxString cog;
5597 if (std::isnan(gCog))
5598 cog.Printf("COG ----- ");
5599 else
5600 cog.Printf("COG %10.5f ", gCog);
5601
5602 wxString sog;
5603 if (std::isnan(gSog))
5604 sog.Printf("SOG ----- ");
5605 else
5606 sog.Printf("SOG %6.2f " + getUsrSpeedUnit(), toUsrSpeed(gSog));
5607
5608 navmsg += cog;
5609 navmsg += sog;
5610 } else {
5611 wxString data;
5612 data.Printf(" DR Lat %10.5f Lon %10.5f", gLat, gLon);
5613 navmsg += data;
5614 }
5615 wxLogMessage(navmsg);
5616 g_loglast_time = lognow;
5617
5618 int bells = (hourLOC % 4) * 2; // 2 bells each hour
5619 if (minuteLOC != 0) bells++; // + 1 bell on 30 minutes
5620 if (!bells) bells = 8; // 0 is 8 bells
5621
5622 if (g_bPlayShipsBells && ((minuteLOC == 0) || (minuteLOC == 30))) {
5623 m_BellsToPlay = bells;
5624 wxCommandEvent ev(BELLS_PLAYED_EVTYPE);
5625 wxPostEvent(this, ev);
5626 }
5627 }
5628 }
5629}
5630
5631void MyFrame::OnFrameTimer1(wxTimerEvent &event) {
5632 CheckToolbarPosition();
5633
5634 ProcessUnitTest();
5635 g_tick++;
5636 if (ProcessQuitFlag()) return;
5637
5638 if (bDBUpdateInProgress) return;
5639
5640 FrameTimer1.Stop();
5641 FrameTenHzTimer.Stop();
5642
5643 ProcessDeferredTrackOn();
5644 SendFixToPlugins();
5645 ProcessAnchorWatch();
5646 ProcessLogAndBells();
5647
5648 if (ShouldRestartTrack()) TrackDailyRestart();
5649
5650 // If no alerts are on, then safe to resume sleeping
5651 if (g_bSleep && !AnchorAlertOn1 && !AnchorAlertOn2) {
5652 FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
5653 FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
5654 return;
5655 }
5656
5657 // If gSog is greater than some threshold,
5658 // we determine that we are"cruising"
5659 if (gSog > 3.0) g_bCruising = true;
5660
5661 // Update the Toolbar Status windows and lower status bar
5662 // just after start of ticks.
5663
5664 if (g_tick == 2) {
5665 wxString sogcog("SOG --- " + getUsrSpeedUnit() + +" " +
5666 " COG ---\u00B0");
5667 if (GetStatusBar()) SetStatusText(sogcog, STAT_FIELD_SOGCOG);
5668
5669 gCog = 0.0; // say speed is zero to kill ownship predictor
5670 }
5671
5672 // Update the chart database and displayed chart
5673 bool bnew_view = false;
5674 if (!g_btenhertz) bnew_view = DoChartUpdate();
5675
5676 g_blinker_tick++;
5677
5679
5680 // This call sends autopilot output strings to output ports.
5681 bool bactiveRouteUpdate = RoutemanGui(*g_pRouteMan).UpdateProgress();
5682
5683 // For each canvas....
5684 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5685 ChartCanvas *cc = g_canvasArray.Item(i);
5686 if (cc) {
5687 cc->DrawBlinkObjects();
5688
5689 // Update the active route, if any, as determined above
5690 if (bactiveRouteUpdate) {
5691 // This RefreshRect will cause any active routepoint to blink
5692 if (g_pRouteMan->GetpActiveRoute())
5693 cc->RefreshRect(g_blink_rect, false);
5694 }
5695
5696 // Force own-ship drawing parameters
5697 cc->SetOwnShipState(SHIP_NORMAL);
5698
5699 if (cc->GetQuiltMode()) {
5700 double erf = cc->GetQuiltMaxErrorFactor();
5701 if (erf > 0.02) cc->SetOwnShipState(SHIP_LOWACCURACY);
5702 } else {
5703 if (cc->m_singleChart) {
5704 if (cc->m_singleChart->GetChart_Error_Factor() > 0.02)
5705 cc->SetOwnShipState(SHIP_LOWACCURACY);
5706 }
5707 }
5708
5709 if (!bGPSValid) cc->SetOwnShipState(SHIP_INVALID);
5710
5711 if ((bGPSValid != m_last_bGPSValid) ||
5712 (bVelocityValid != m_last_bVelocityValid) ||
5713 (!isnan(gHdt) && (gHdt != m_last_hdt))) {
5714 if (!g_bopengl) cc->UpdateShips();
5715
5716 bnew_view = true; // force a full Refresh()
5717 }
5718 }
5719 }
5720
5721 m_last_bGPSValid = bGPSValid;
5722 m_last_bVelocityValid = bVelocityValid;
5723 m_last_hdt = gHdt;
5724
5725 // If any PlugIn requested dynamic overlay callbacks, force a full canvas
5726 // refresh thus, ensuring at least 1 Hz. callback.
5727 bool brq_dynamic = false;
5728 if (g_pi_manager) {
5729 auto *pplugin_array = PluginLoader::GetInstance()->GetPlugInArray();
5730 for (unsigned int i = 0; i < pplugin_array->GetCount(); i++) {
5731 PlugInContainer *pic = pplugin_array->Item(i);
5732 if (pic->m_enabled && pic->m_init_state) {
5733 if (pic->m_cap_flag & WANTS_DYNAMIC_OPENGL_OVERLAY_CALLBACK) {
5734 brq_dynamic = true;
5735 break;
5736 }
5737 }
5738 }
5739
5740 if (brq_dynamic) bnew_view = true;
5741 }
5742
5743 // Make sure we get a redraw and alert sound on AnchorWatch excursions.
5744 if (AnchorAlertOn1 || AnchorAlertOn2) bnew_view = true;
5745
5746 // For each canvas....
5747 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5748 ChartCanvas *cc = g_canvasArray.Item(i);
5749 if (cc) {
5750 if (g_bopengl) {
5751#ifdef ocpnUSE_GL
5752 if (cc->GetglCanvas()) {
5753 // Rotation is handled by 10Hz timer, do not duplicate here
5754 bool b_rotate = cc->GetUpMode() != NORTH_UP_MODE;
5755 if (!b_rotate) {
5756 if (!g_btenhertz) {
5757 if (cc->m_bFollow) {
5758 cc->DoCanvasUpdate();
5759 if (bnew_view)
5760 cc->Refresh(false); // honor ownship state update
5761 } else
5762 cc->Refresh(false);
5763 }
5764 }
5765 }
5766#endif
5767 } else {
5768 // Invalidate the ChartCanvas window appropriately
5769 // In non-follow mode, invalidate the rectangles containing the AIS
5770 // targets and the ownship, etc... In follow mode, if there has
5771 // already been a full screen refresh, there is no need to check
5772 // ownship or AIS,
5773 // since they will be always drawn on the full screen paint.
5774
5775 if ((!cc->m_bFollow) || (cc->GetUpMode() != NORTH_UP_MODE)) {
5776 cc->UpdateShips();
5777 cc->UpdateAIS();
5778 cc->UpdateAlerts();
5779 } else {
5780 if (!bnew_view) { // There has not been a Refresh() yet.....
5781 cc->UpdateAIS();
5782 cc->UpdateAlerts();
5783 }
5784 }
5785 }
5786 }
5787 }
5788
5789 if (g_pais_query_dialog_active && g_pais_query_dialog_active->IsShown())
5790 g_pais_query_dialog_active->UpdateText();
5791
5792 // Refresh AIS target list every 5 seconds to avoid blinking
5793 if (g_pAISTargetList && (0 == (g_tick % (5))))
5794 g_pAISTargetList->UpdateAISTargetList();
5795
5796 // Pick up any change Toolbar status displays
5797 UpdateGPSCompassStatusBoxes();
5798 UpdateAISTool();
5799
5800 if (console && console->IsShown()) {
5801 // console->Raise();
5802 console->RefreshConsoleData();
5803 }
5804
5805 // This little hack fixes a problem seen with some UniChrome OpenGL drivers
5806 // We need a deferred resize to get glDrawPixels() to work right.
5807 // So we set a trigger to generate a resize after 5 seconds....
5808 // See the "UniChrome" hack elsewhere
5809 if (m_bdefer_resize) {
5810 if (0 == (g_tick % (5))) {
5811 printf("___RESIZE\n");
5812 SetSize(m_defer_size);
5813 g_pauimgr->Update();
5814 m_bdefer_resize = false;
5815 }
5816 }
5817
5818 // Reset pending next AppMsgBus notification
5819
5820 if (g_unit_test_2)
5821 FrameTimer1.Start(TIMER_GFRAME_1 * 3, wxTIMER_CONTINUOUS);
5822 else {
5823 FrameTimer1.Start(TIMER_GFRAME_1, wxTIMER_CONTINUOUS);
5824 FrameTenHzTimer.Start(100, wxTIMER_CONTINUOUS);
5825 }
5826}
5827
5828double MyFrame::GetMag(double a, double lat, double lon) {
5829 double Variance = std::isnan(gVar) ? g_UserVar : gVar;
5830 auto loader = PluginLoader::GetInstance();
5831 if (loader && loader->IsPlugInAvailable("WMM")) {
5832 // Request variation at a specific lat/lon
5833
5834 // Note that the requested value is returned sometime later in the event
5835 // stream, so there may be invalid data returned on the first call to this
5836 // method. In the case of rollover windows, the value is requested
5837 // continuously, so will be correct very soon.
5838 wxDateTime now = wxDateTime::Now();
5839 SendJSON_WMM_Var_Request(lat, lon, now);
5840 if (fabs(gQueryVar) < 360.0) // Don't use WMM variance if not updated yet
5841 Variance = gQueryVar;
5842 }
5843 return toMagnetic(a, Variance);
5844}
5845
5846bool MyFrame::SendJSON_WMM_Var_Request(double lat, double lon,
5847 wxDateTime date) {
5848 if (g_pi_manager) {
5849 wxJSONValue v;
5850 v["Lat"] = lat;
5851 v["Lon"] = lon;
5852 v["Year"] = date.GetYear();
5853 v["Month"] = date.GetMonth();
5854 v["Day"] = date.GetDay();
5855
5856 SendJSONMessageToAllPlugins("WMM_VARIATION_REQUEST", v);
5857 return true;
5858 } else
5859 return false;
5860}
5861
5862void MyFrame::TouchAISActive() {
5863 // .. for each canvas...
5864 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5865 ChartCanvas *cc = g_canvasArray.Item(i);
5866 if (cc) cc->TouchAISToolActive();
5867 }
5868}
5869
5870void MyFrame::UpdateAISTool() {
5871 if (!g_pAIS) return;
5872
5873 // .. for each canvas...
5874 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5875 ChartCanvas *cc = g_canvasArray.Item(i);
5876 if (cc) cc->UpdateAISTBTool();
5877 }
5878}
5879
5880// Cause refresh of active Tide/Current data, if displayed
5881void MyFrame::OnFrameTCTimer(wxTimerEvent &event) {
5882 // ..For each canvas...
5883 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5884 ChartCanvas *cc = g_canvasArray.Item(i);
5885 if (cc) cc->SetbTCUpdate(true);
5886 }
5887
5888 RefreshAllCanvas(false);
5889}
5890
5891// Keep and update the Viewport rotation angle according to average COG for
5892// COGUP mode
5893void MyFrame::OnFrameCOGTimer(wxTimerEvent &event) {
5894 return;
5895
5896 // ..For each canvas...
5897 bool b_rotate = false;
5898 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5899 ChartCanvas *cc = g_canvasArray.Item(i);
5900 if (cc) b_rotate |= (cc->GetUpMode() != NORTH_UP_MODE);
5901 }
5902
5903 if (!b_rotate) {
5904 FrameCOGTimer.Stop();
5905 return;
5906 }
5907
5908 DoCOGSet();
5909
5910 // Restart the timer, max frequency is 10 hz.
5911 int period_ms = 100;
5912 // if (g_COGAvgSec > 0) period_ms = g_COGAvgSec * 1000;
5913 FrameCOGTimer.Start(period_ms, wxTIMER_CONTINUOUS);
5914}
5915
5916void MyFrame::DoCOGSet() {
5917 // ..For each canvas...
5918 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5919 ChartCanvas *cc = g_canvasArray.Item(i);
5920 if (cc) cc->DoCanvasCOGSet();
5921 }
5922}
5923
5924void RenderShadowText(wxDC *pdc, wxFont *pFont, wxString &str, int x, int y) {
5925#ifdef DrawText
5926#undef DrawText
5927#define FIXIT
5928#endif
5929
5930 wxFont oldfont = pdc->GetFont(); // save current font
5931
5932 pdc->SetFont(*pFont);
5933 pdc->SetTextForeground(GetGlobalColor("CHGRF"));
5934 pdc->SetBackgroundMode(wxTRANSPARENT);
5935
5936 pdc->DrawText(str, x, y + 1);
5937 pdc->DrawText(str, x, y - 1);
5938 pdc->DrawText(str, x + 1, y);
5939 pdc->DrawText(str, x - 1, y);
5940
5941 pdc->SetTextForeground(GetGlobalColor("CHBLK"));
5942
5943 pdc->DrawText(str, x, y);
5944
5945 pdc->SetFont(oldfont); // restore last font
5946}
5947
5948// TODO How does this relate to per-canvas rotation?
5949void MyFrame::UpdateRotationState(double rotation) {
5950 // If rotated manually, we switch to NORTHUP
5951 g_bCourseUp = false;
5952
5953 if (fabs(rotation) > .001) {
5954 SetMenubarItemState(ID_MENU_CHART_COGUP, false);
5955 SetMenubarItemState(ID_MENU_CHART_NORTHUP, true);
5956 if (m_pMenuBar) {
5957 m_pMenuBar->SetLabel(ID_MENU_CHART_NORTHUP, _("Rotated Mode"));
5958 }
5959 } else {
5960 SetMenubarItemState(ID_MENU_CHART_COGUP, g_bCourseUp);
5961 SetMenubarItemState(ID_MENU_CHART_NORTHUP, !g_bCourseUp);
5962 if (m_pMenuBar) {
5963 m_pMenuBar->SetLabel(ID_MENU_CHART_NORTHUP, _("North Up Mode"));
5964 }
5965 }
5966
5967 UpdateGPSCompassStatusBoxes(true);
5968 DoChartUpdate();
5969}
5970
5971void MyFrame::UpdateGPSCompassStatusBoxes(bool b_force_new) {
5972 // ..For each canvas...
5973 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
5974 ChartCanvas *cc = g_canvasArray.Item(i);
5975 if (cc) cc->UpdateGPSCompassStatusBox(b_force_new);
5976 }
5977}
5978
5979// Application memory footprint management
5980
5981int MyFrame::GetApplicationMemoryUse() {
5982 int memsize = -1;
5983#ifdef __linux__
5984
5985 // Use a contrived ps command to get the virtual memory size associated
5986 // with this process
5987 wxWindow *fWin = wxWindow::FindFocus();
5988
5989 wxArrayString outputArray;
5990 wxString cmd("ps --no-headers -o vsize ");
5991 unsigned long pid = wxGetProcessId();
5992 wxString cmd1;
5993 cmd1.Printf("%ld", pid);
5994 cmd += cmd1;
5995 wxExecute(cmd, outputArray);
5996
5997 if (outputArray.GetCount()) {
5998 wxString s = outputArray.Item(0);
5999 long vtmp;
6000 if (s.ToLong(&vtmp)) memsize = vtmp;
6001 }
6002
6003 if (fWin) fWin->SetFocus();
6004
6005#endif
6006
6007#ifdef __WXMSW__
6008 HANDLE hProcess;
6009 PROCESS_MEMORY_COUNTERS pmc;
6010
6011 unsigned long processID = wxGetProcessId();
6012
6013 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
6014 processID);
6015 if (NULL == hProcess) return 0;
6016
6017 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
6018 /*
6019 printf( "\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount );
6020 printf( "\tPeakWorkingSetSize: 0x%08X\n",
6021 pmc.PeakWorkingSetSize );
6022 printf( "\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize );
6023 printf( "\tQuotaPeakPagedPoolUsage: 0x%08X\n",
6024 pmc.QuotaPeakPagedPoolUsage );
6025 printf( "\tQuotaPagedPoolUsage: 0x%08X\n",
6026 pmc.QuotaPagedPoolUsage );
6027 printf( "\tQuotaPeakNonPagedPoolUsage: 0x%08X\n",
6028 pmc.QuotaPeakNonPagedPoolUsage );
6029 printf( "\tQuotaNonPagedPoolUsage: 0x%08X\n",
6030 pmc.QuotaNonPagedPoolUsage );
6031 printf( "\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage );
6032 printf( "\tPeakPagefileUsage: 0x%08X\n",
6033 pmc.PeakPagefileUsage );
6034 */
6035 memsize = pmc.WorkingSetSize / 1024;
6036 }
6037
6038 CloseHandle(hProcess);
6039
6040#endif
6041
6042 return memsize;
6043}
6044
6045double MyFrame::GetBestVPScale(ChartBase *pchart) {
6046 return GetPrimaryCanvas()->GetBestVPScale(pchart);
6047}
6048
6049void MyFrame::SetChartUpdatePeriod() {
6050 // Set the chart update period based upon chart skew and skew compensator
6051
6052 g_ChartUpdatePeriod = 0; // General default
6053
6054 // In non-GL, singlele-chart mode, rotation of skewed charts is very slow
6055 // So we need to use a slower update time constant to preserve adequate UI
6056 // performance
6057 bool bskewdc = false;
6058 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
6059 ChartCanvas *cc = g_canvasArray.Item(i);
6060 if (cc) {
6061 if (!g_bopengl && !cc->GetVP().b_quilt) {
6062 if (fabs(cc->GetVP().skew) > 0.0001) bskewdc = true;
6063 }
6064 if (cc->m_bFollow) g_ChartUpdatePeriod = 1;
6065 }
6066 }
6067
6068 if (bskewdc) g_ChartUpdatePeriod = g_SkewCompUpdatePeriod;
6069
6070 m_ChartUpdatePeriod = g_ChartUpdatePeriod;
6071}
6072
6073void MyFrame::UpdateControlBar(ChartCanvas *cc) {
6074 if (!cc) return;
6075 cc->UpdateCanvasControlBar();
6076}
6077
6078void MyFrame::selectChartDisplay(int type, int family) {
6079 // ..For each canvas...
6080 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
6081 ChartCanvas *cc = g_canvasArray.Item(i);
6082 if (cc) cc->selectCanvasChartDisplay(type, family);
6083 }
6084
6085 UpdateGlobalMenuItems(); // update the state of the menu items (checkmarks
6086 // etc.)
6087}
6088
6089//----------------------------------------------------------------------------------
6090// DoChartUpdate
6091// Create a chartstack based on current lat/lon.
6092// Return true if a Refresh(false) was called within.
6093//----------------------------------------------------------------------------------
6094bool MyFrame::DoChartUpdate() {
6095 bool return_val = false;
6096
6097 // ..For each canvas...
6098 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
6099 ChartCanvas *cc = g_canvasArray.Item(i);
6100 if (cc) return_val |= cc->DoCanvasUpdate();
6101 }
6102
6103 return return_val;
6104}
6105
6106void MyFrame::MouseEvent(wxMouseEvent &event) {
6107 int x, y;
6108 event.GetPosition(&x, &y);
6109}
6110
6111// Memory monitor support
6112#ifdef __WXMAC__
6113#include <mach/mach.h>
6114#include <mach/message.h> // for mach_msg_type_number_t
6115#include <mach/kern_return.h> // for kern_return_t
6116#include <mach/task_info.h>
6117#include <stdio.h>
6118#include <malloc/malloc.h>
6119#endif
6120
6121#ifdef __WXGTK__
6122#include <malloc.h>
6123#endif
6124
6125#if defined(__linux__)
6126#include "sys/types.h"
6127#include "sys/sysinfo.h"
6128#endif /* __linux__ */
6129
6130void MyFrame::DoPrint(void) {
6131 // avoid toolbars being printed
6132 g_PrintingInProgress = true;
6133#ifdef ocpnUSE_GL
6134 if (g_bopengl) {
6135 GetPrimaryCanvas()->GetglCanvas()->Render();
6136 GetPrimaryCanvas()->GetglCanvas()->SwapBuffers();
6137 } else
6138#endif
6139 Refresh();
6140
6141 ChartPrintout printout;
6142 if (g_bopengl) {
6143 printout.GenerateGLbmp();
6144 }
6145 auto &printer = PrintDialog::GetInstance();
6146 printer.Initialize(wxLANDSCAPE);
6147 printer.EnablePageNumbers(false);
6148 printer.Print(this, &printout);
6149
6150 // Pass two printout objects: for preview, and possible printing.
6151 /*
6152 wxPrintDialogData printDialogData(* g_printData);
6153 wxPrintPreview *preview = new wxPrintPreview(new MyPrintout, new
6154 MyPrintout, & printDialogData); if (!preview->Ok())
6155 {
6156 delete preview;
6157 OCPNMessageBox(_T("There was a problem previewing.\nPerhaps your current
6158 printer is not set correctly?"), "Previewing", wxOK); return;
6159 }
6160
6161 wxPreviewFrame *frame = new wxPreviewFrame(preview, this, _T("Demo Print
6162 Preview"), wxPoint(100, 100), wxSize(600, 650)); frame->Centre(wxBOTH);
6163 frame->Initialize();
6164 frame->Show();
6165 */
6166 g_PrintingInProgress = false;
6167 Refresh();
6168#ifdef __WXGTK__
6169 GetPrimaryCanvas()->SetFocus();
6170 // Raise(); // I dunno why...
6171#endif
6172}
6173
6174void MyFrame::OnEvtPlugInMessage(OCPN_MsgEvent &event) {
6175 wxString message_ID = event.GetID();
6176 wxString message_JSONText = event.GetJSONText();
6177
6178 // We are free to use or ignore any or all of the PlugIn messages flying
6179 // through this pipe tee.
6180
6181 // We can possibly use the estimated magnetic variation if WMM_pi is
6182 // present, active, and we have no other source of Variation
6183 if (!g_bVAR_Rx) {
6184 if (message_ID == "WMM_VARIATION_BOAT") {
6185 // construct the JSON root object
6186 wxJSONValue root;
6187 // construct a JSON parser
6188 wxJSONReader reader;
6189
6190 // now read the JSON text and store it in the 'root' structure
6191 // check for errors before retreiving values...
6192 int numErrors = reader.Parse(message_JSONText, &root);
6193 if (numErrors > 0) {
6194 // const wxArrayString& errors = reader.GetErrors();
6195 return;
6196 }
6197
6198 // get the DECL value from the JSON message
6199 wxString decl = root["Decl"].AsString();
6200 double decl_val;
6201 decl.ToDouble(&decl_val);
6202
6203 gVar = decl_val;
6204 }
6205 }
6206
6207 if (message_ID == "WMM_VARIATION") {
6208 // construct the JSON root object
6209 wxJSONValue root;
6210 // construct a JSON parser
6211 wxJSONReader reader;
6212
6213 // now read the JSON text and store it in the 'root' structure
6214 // check for errors before retreiving values...
6215 int numErrors = reader.Parse(message_JSONText, &root);
6216 if (numErrors > 0) {
6217 // const wxArrayString& errors = reader.GetErrors();
6218 return;
6219 }
6220
6221 // get the DECL value from the JSON message
6222 wxString decl = root["Decl"].AsString();
6223 double decl_val;
6224 decl.ToDouble(&decl_val);
6225
6226 gQueryVar = decl_val;
6227 }
6228
6229 if (message_ID == "GRIB_TIMELINE") {
6230 wxJSONReader r;
6231 wxJSONValue v;
6232 int numErrors = r.Parse(message_JSONText, &v);
6233
6234 if (numErrors > 0) {
6235 wxLogMessage("GRIB_TIMELINE: JSON parse error");
6236 return;
6237 }
6238
6239 // Store old time source for comparison
6240 wxDateTime oldTimeSource = gTimeSource;
6241
6242 if (v["Day"].AsInt() == -1) {
6243 gTimeSource = wxInvalidDateTime;
6244 wxLogMessage("GRIB_TIMELINE: Reset to system time");
6245 } else {
6246 gTimeSource.Set(v["Day"].AsInt(), (wxDateTime::Month)v["Month"].AsInt(),
6247 v["Year"].AsInt(), v["Hour"].AsInt(), v["Minute"].AsInt(),
6248 v["Second"].AsInt());
6249 }
6250
6251 // Refresh tide displays if time source changed
6252 if (oldTimeSource != gTimeSource) {
6253 // Refresh all canvases that might show tide info
6254 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
6255 ChartCanvas *cc = g_canvasArray.Item(i);
6256 if (cc && (cc->GetbShowTide() || cc->GetbShowCurrent())) {
6257 cc->Refresh(false);
6258
6259 // Also refresh any open tide dialog windows
6260 if (cc->pCwin) { // pCwin is the tide window pointer
6261 cc->pCwin->Refresh(false);
6262 }
6263 }
6264 }
6265 }
6266 }
6267 if (message_ID == "OCPN_TRACK_REQUEST") {
6268 wxJSONValue root;
6269 wxJSONReader reader;
6270 wxString trk_id = wxEmptyString;
6271
6272 int numErrors = reader.Parse(message_JSONText, &root);
6273 if (numErrors > 0) return;
6274
6275 if (root.HasMember("Track_ID")) trk_id = root["Track_ID"].AsString();
6276
6277 wxJSONValue v;
6278 v["Track_ID"] = trk_id;
6279 for (Track *ptrack : g_TrackList) {
6280 wxString name = wxEmptyString;
6281 if (ptrack->m_GUID == trk_id) {
6282 name = ptrack->GetName();
6283 if (name.IsEmpty()) {
6284 TrackPoint *rp = ptrack->GetPoint(0);
6285 if (rp && rp->GetCreateTime().IsValid())
6286 name = rp->GetCreateTime().FormatISODate() + " " +
6287 rp->GetCreateTime().FormatISOTime();
6288 else
6289 name = _("(Unnamed Track)");
6290 }
6291
6292 /* To avoid memory problems send a single trackpoint.
6293 * It's up to the plugin to collect the data. */
6294 int i = 1;
6295 v["error"] = false;
6296 v["TotalNodes"] = ptrack->GetnPoints();
6297 for (int j = 0; j < ptrack->GetnPoints(); j++) {
6298 TrackPoint *tp = ptrack->GetPoint(j);
6299 v["lat"] = tp->m_lat;
6300 v["lon"] = tp->m_lon;
6301 v["NodeNr"] = i;
6302 i++;
6303 wxString msg_id("OCPN_TRACKPOINTS_COORDS");
6304 SendJSONMessageToAllPlugins(msg_id, v);
6305 }
6306 return;
6307 }
6308 v["error"] = true;
6309
6310 wxString msg_id("OCPN_TRACKPOINTS_COORDS");
6311 SendJSONMessageToAllPlugins(msg_id, v);
6312 }
6313 } else if (message_ID == "OCPN_ROUTE_REQUEST") {
6314 wxJSONValue root;
6315 wxJSONReader reader;
6316 wxString guid = wxEmptyString;
6317
6318 int numErrors = reader.Parse(message_JSONText, &root);
6319 if (numErrors > 0) {
6320 return;
6321 }
6322
6323 if (root.HasMember("GUID")) guid = root["GUID"].AsString();
6324
6325 wxJSONValue v;
6326 v["GUID"] = guid;
6327 for (auto it = pRouteList->begin(); it != pRouteList->end(); ++it) {
6328 wxString name = wxEmptyString;
6329
6330 if ((*it)->m_GUID == guid) {
6331 name = (*it)->m_RouteNameString;
6332 if (name.IsEmpty()) name = _("(Unnamed Route)");
6333
6334 v["Name"] = name;
6335 v["error"] = false;
6336 wxJSONValue w;
6337 int i = 0;
6338 for (RoutePointList::iterator itp = (*it)->pRoutePointList->begin();
6339 itp != (*it)->pRoutePointList->end(); itp++) {
6340 w[i]["lat"] = (*itp)->m_lat;
6341 w[i]["lon"] = (*itp)->m_lon;
6342 w[i]["Name"] = (*itp)->GetName();
6343 w[i]["Description"] = (*itp)->GetDescription();
6344 w[i]["GUID"] = (*itp)->m_GUID;
6345 w[i]["ArrivalRadius"] = (*itp)->GetWaypointArrivalRadius();
6346
6347 auto node = (*itp)->m_HyperlinkList->begin();
6348 if (node != (*itp)->m_HyperlinkList->end()) {
6349 int n = 1;
6350 while (node != (*itp)->m_HyperlinkList->end()) {
6351 Hyperlink *httpLink = *node;
6352 v[i]["WPLink" + wxString::Format("%d", n)] = httpLink->Link;
6353 v[i]["WPLinkDesciption" + wxString::Format("%d", n++)] =
6354 httpLink->DescrText;
6355 ++node;
6356 }
6357 }
6358 i++;
6359 }
6360 v["waypoints"] = w;
6361 wxString msg_id("OCPN_ROUTE_RESPONSE");
6362 SendJSONMessageToAllPlugins(msg_id, v);
6363 return;
6364 }
6365 }
6366
6367 v["error"] = true;
6368
6369 wxString msg_id("OCPN_ROUTE_RESPONSE");
6370 SendJSONMessageToAllPlugins(msg_id, v);
6371 } else if (message_ID == "OCPN_ROUTELIST_REQUEST") {
6372 wxJSONValue root;
6373 wxJSONReader reader;
6374 bool route = true;
6375
6376 int numErrors = reader.Parse(message_JSONText, &root);
6377 if (numErrors > 0) return;
6378
6379 if (root.HasMember("mode")) {
6380 wxString str = root["mode"].AsString();
6381 if (str == "Track") route = false;
6382
6383 wxJSONValue v;
6384 int i = 1;
6385 if (route) {
6386 for (RouteList::iterator it = pRouteList->begin();
6387 it != pRouteList->end(); it++) {
6388 wxString name = (*it)->m_RouteNameString;
6389 if (name.IsEmpty()) name = _("(Unnamed Route)");
6390
6391 v[i]["error"] = false;
6392 v[i]["name"] = name;
6393 v[i]["GUID"] = (*it)->m_GUID;
6394 v[i]["active"] = (*it)->IsActive();
6395 i++;
6396 }
6397 } else { // track
6398 for (Track *ptrack : g_TrackList) {
6399 wxString name = ptrack->GetName();
6400 if (name.IsEmpty()) {
6401 TrackPoint *tp = ptrack->GetPoint(0);
6402 if (tp && tp->GetCreateTime().IsValid())
6403 name = tp->GetCreateTime().FormatISODate() + " " +
6404 tp->GetCreateTime().FormatISOTime();
6405 else
6406 name = _("(Unnamed Track)");
6407 }
6408 v[i]["error"] = false;
6409 v[i]["name"] = name;
6410 v[i]["GUID"] = ptrack->m_GUID;
6411 v[i]["active"] = g_pActiveTrack == ptrack;
6412 i++;
6413 }
6414 }
6415 wxString msg_id("OCPN_ROUTELIST_RESPONSE");
6416 SendJSONMessageToAllPlugins(msg_id, v);
6417 } else {
6418 wxJSONValue v;
6419 v[0]["error"] = true;
6420 wxString msg_id("OCPN_ROUTELIST_RESPONSE");
6421 SendJSONMessageToAllPlugins(msg_id, v);
6422 }
6423 } else if (message_ID == "OCPN_ACTIVE_ROUTELEG_REQUEST") {
6424 wxJSONValue v;
6425 v[0]["error"] = true;
6426 if (g_pRouteMan->GetpActiveRoute()) {
6427 if (g_pRouteMan->m_bDataValid) {
6428 v[0]["error"] = false;
6429 v[0]["range"] = g_pRouteMan->GetCurrentRngToActivePoint();
6430 v[0]["bearing"] = g_pRouteMan->GetCurrentBrgToActivePoint();
6431 v[0]["XTE"] = g_pRouteMan->GetCurrentXTEToActivePoint();
6432 v[0]["active_route_GUID"] = g_pRouteMan->GetpActiveRoute()->GetGUID();
6433 v[0]["active_waypoint_lat"] =
6434 g_pRouteMan->GetpActiveRoute()->m_pRouteActivePoint->GetLatitude();
6435 v[0]["active_waypoint_lon"] =
6436 g_pRouteMan->GetpActiveRoute()->m_pRouteActivePoint->GetLongitude();
6437 }
6438 }
6439 wxString msg_id("OCPN_ACTIVE_ROUTELEG_RESPONSE");
6440 SendJSONMessageToAllPlugins(msg_id, v);
6441 }
6442}
6443
6444void MyFrame::FilterCogSog() {
6445 if (g_bfilter_cogsog) {
6446 // Simple averaging filter for COG
6447 double cog_last = gCog; // most recent reported value
6448
6449 // Make a hole in array
6450 for (int i = g_COGFilterSec - 1; i > 0; i--)
6451 COGFilterTable[i] = COGFilterTable[i - 1];
6452 COGFilterTable[0] = cog_last;
6453
6454 // If the lastest data is undefined, leave it
6455 if (!std::isnan(cog_last)) {
6456 //
6457 double sum = 0., count = 0;
6458 for (int i = 0; i < g_COGFilterSec; i++) {
6459 double adder = COGFilterTable[i];
6460 if (std::isnan(adder)) continue;
6461
6462 if (fabs(adder - cog_last) > 180.) {
6463 if ((adder - cog_last) > 0.)
6464 adder -= 360.;
6465 else
6466 adder += 360.;
6467 }
6468
6469 sum += adder;
6470 count++;
6471 }
6472 sum /= count;
6473
6474 if (sum < 0.)
6475 sum += 360.;
6476 else if (sum >= 360.)
6477 sum -= 360.;
6478
6479 gCog = sum;
6480 }
6481
6482 // Simple averaging filter for SOG
6483 double sog_last = gSog; // most recent reported value
6484
6485 // Make a hole in array
6486 for (int i = g_SOGFilterSec - 1; i > 0; i--)
6487 SOGFilterTable[i] = SOGFilterTable[i - 1];
6488 SOGFilterTable[0] = sog_last;
6489
6490 // If the data are undefined, leave the array intact
6491 if (!std::isnan(gSog)) {
6492 double sum = 0., count = 0;
6493 for (int i = 0; i < g_SOGFilterSec; i++) {
6494 if (std::isnan(SOGFilterTable[i])) continue;
6495
6496 sum += SOGFilterTable[i];
6497 count++;
6498 }
6499 sum /= count;
6500
6501 gSog = sum;
6502 }
6503 }
6504}
6505
6506void MyFrame::LoadHarmonics() {
6507 if (!ptcmgr) {
6508 ptcmgr = new TCMgr;
6509 ptcmgr->LoadDataSources(TideCurrentDataSet);
6510 } else {
6511 bool b_newdataset = false;
6512
6513 // Test both ways
6514 for (auto a : ptcmgr->GetDataSet()) {
6515 bool b_foundi = false;
6516 for (auto b : TideCurrentDataSet) {
6517 if (a == b) {
6518 b_foundi = true;
6519 break; // j loop
6520 }
6521 }
6522 if (!b_foundi) {
6523 b_newdataset = true;
6524 break; // i loop
6525 }
6526 }
6527
6528 for (auto a : TideCurrentDataSet) {
6529 bool b_foundi = false;
6530 for (auto b : ptcmgr->GetDataSet()) {
6531 if (a == b) {
6532 b_foundi = true;
6533 break; // j loop
6534 }
6535 }
6536 if (!b_foundi) {
6537 b_newdataset = true;
6538 break; // i loop
6539 }
6540 }
6541
6542 if (b_newdataset) ptcmgr->LoadDataSources(TideCurrentDataSet);
6543 }
6544}
6545
6546void MyFrame::ActivateAISMOBRoute(const AisTargetData *ptarget) {
6547 if (!ptarget) return;
6548
6549 // The MOB point
6550 wxDateTime mob_time = wxDateTime::Now();
6551 wxString mob_label(_("AIS MAN OVERBOARD"));
6552 mob_label += _(" on ");
6553 mob_label += ocpn::toUsrDateTimeFormat(mob_time);
6554
6555 RoutePoint *pWP_MOB = new RoutePoint(ptarget->Lat, ptarget->Lon, "mob",
6556 mob_label, wxEmptyString);
6557 pWP_MOB->SetShared(true);
6558 pWP_MOB->m_bIsolatedMark = true;
6559 pSelect->AddSelectableRoutePoint(ptarget->Lat, ptarget->Lon, pWP_MOB);
6560 // pConfig->AddNewWayPoint(pWP_MOB, -1); // use auto next num
6561 NavObj_dB::GetInstance().InsertRoutePoint(pWP_MOB);
6562
6563 pWP_MOB->SetUseSca(false); // Do not use scaled hiding for MOB
6564
6565 /* We want to start tracking any MOB in range (Which will trigger false alarms
6566 with messages received over the network etc., but will a) not discard nearby
6567 event even in case our GPS is momentarily unavailable and b) work even when
6568 the boat is stationary, in which case some GPS units do not provide COG) if(
6569 bGPSValid && !std::isnan(gCog) && !std::isnan(gSog) ) { */
6570 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
6571 wxString(_("Own ship")), wxEmptyString);
6572 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
6573 pWP_MOB->SetUseSca(false); // Do not use scaled hiding for MOB
6574 pAISMOBRoute = new Route();
6575 pRouteList->push_back(pAISMOBRoute);
6576
6577 pAISMOBRoute->AddPoint(pWP_src);
6578 pAISMOBRoute->AddPoint(pWP_MOB);
6579
6580 pSelect->AddSelectableRouteSegment(ptarget->Lat, ptarget->Lon, gLat, gLon,
6581 pWP_src, pWP_MOB, pAISMOBRoute);
6582
6583 pAISMOBRoute->m_RouteNameString = _("Temporary AISMOB Route");
6584 pAISMOBRoute->m_RouteStartString = _("Present own ship");
6585 pAISMOBRoute->m_RouteEndString = mob_label;
6586
6588
6589 pAISMOBRoute->SetRouteArrivalRadius(-1.0); // never arrives
6590
6591 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
6592 // g_pRouteMan->ActivateRoute( pAISMOBRoute, pWP_MOB );
6593
6594 wxJSONValue v;
6595 v["GUID"] = pAISMOBRoute->m_GUID;
6596 wxString msg_id("OCPN_MAN_OVERBOARD");
6597 SendJSONMessageToAllPlugins(msg_id, v);
6598 //}
6599
6600 if (RouteManagerDialog::getInstanceFlag()) {
6601 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
6602 pRouteManagerDialog->UpdateRouteListCtrl();
6603 pRouteManagerDialog->UpdateWptListCtrl();
6604 }
6605 }
6606
6607 RefreshAllCanvas(false);
6608
6609 wxString mob_message(_("AIS MAN OVERBOARD"));
6610 mob_message += _(" Time: ");
6611 mob_message += ocpn::toUsrDateTimeFormat(mob_time);
6612 mob_message += _(" Ownship Position: ");
6613 mob_message += toSDMM(1, gLat);
6614 mob_message += " ";
6615 mob_message += toSDMM(2, gLon);
6616 mob_message += _(" MOB Position: ");
6617 mob_message += toSDMM(1, ptarget->Lat);
6618 mob_message += " ";
6619 mob_message += toSDMM(2, ptarget->Lon);
6620 wxLogMessage(mob_message);
6621}
6622
6623void MyFrame::UpdateAISMOBRoute(const AisTargetData *ptarget) {
6624 if (pAISMOBRoute && ptarget) {
6625 // Update Current Ownship point
6626 RoutePoint *OwnPoint = pAISMOBRoute->GetPoint(1);
6627 OwnPoint->m_lat = gLat;
6628 OwnPoint->m_lon = gLon;
6629
6630 pSelect->DeleteSelectableRoutePoint(OwnPoint);
6631 pSelect->AddSelectableRoutePoint(gLat, gLon, OwnPoint);
6632
6633 // Update Current MOB point
6634 RoutePoint *MOB_Point = pAISMOBRoute->GetPoint(2);
6635 MOB_Point->m_lat = ptarget->Lat;
6636 MOB_Point->m_lon = ptarget->Lon;
6637
6638 pSelect->DeleteSelectableRoutePoint(MOB_Point);
6639 pSelect->AddSelectableRoutePoint(ptarget->Lat, ptarget->Lon, MOB_Point);
6640
6641 pSelect->UpdateSelectableRouteSegments(OwnPoint);
6642 pSelect->UpdateSelectableRouteSegments(MOB_Point);
6643 }
6644
6645 RefreshAllCanvas(false);
6646
6647 if (ptarget) {
6648 wxDateTime mob_time = wxDateTime::Now();
6649
6650 wxString mob_message(_("AIS MAN OVERBOARD UPDATE"));
6651 mob_message += _(" Time: ");
6652 mob_message += ocpn::toUsrDateTimeFormat(mob_time);
6653 mob_message += _(" Ownship Position: ");
6654 mob_message += toSDMM(1, gLat);
6655 mob_message += " ";
6656 mob_message += toSDMM(2, gLon);
6657 mob_message += _(" MOB Position: ");
6658 mob_message += toSDMM(1, ptarget->Lat);
6659 mob_message += " ";
6660 mob_message += toSDMM(2, ptarget->Lon);
6661
6662 wxLogMessage(mob_message);
6663 }
6664}
6665
6666void MyFrame::applySettingsString(wxString settings) {
6667 // Save some present values
6668 int last_UIScaleFactor = g_GUIScaleFactor;
6669 bool previous_expert = g_bUIexpert;
6670 g_last_ChartScaleFactor = g_ChartScaleFactor;
6671 ArrayOfCDI *pNewDirArray = new ArrayOfCDI;
6672
6673 int rr =
6674 g_Platform->platformApplyPrivateSettingsString(settings, pNewDirArray);
6675
6676 // And apply the changes
6677 pConfig->UpdateSettings();
6678
6679 // Might need to rebuild symbols
6680 if (g_last_ChartScaleFactor != g_ChartScaleFactor) rr |= S52_CHANGED;
6681
6682 if (rr & S52_CHANGED) {
6683 if (ps52plib) {
6684 ps52plib->FlushSymbolCaches(ChartCtxFactory());
6685 ps52plib
6686 ->ClearCNSYLUPArray(); // some CNSY depends on renderer (e.g. CARC)
6687 ps52plib->GenerateStateHash();
6688 }
6689 }
6690
6691 ProcessOptionsDialog(rr, pNewDirArray);
6692
6693 // Try to detect if the toolbar is changing, to avoid a rebuild if not
6694 // necessary.
6695
6696 bool b_newToolbar = false;
6697
6698 if (g_GUIScaleFactor != last_UIScaleFactor) b_newToolbar = true;
6699
6700 if (previous_expert != g_bUIexpert) b_newToolbar = true;
6701
6702 if (rr & TOOLBAR_CHANGED) {
6703 b_newToolbar = true;
6704 }
6705
6706 // We do this is one case only to remove an orphan recovery window
6707#ifdef __ANDROID__
6708 if (previous_expert && !g_bUIexpert) {
6709 androidForceFullRepaint();
6710 }
6711#endif
6712
6713 if (previous_expert != g_bUIexpert) g_Platform->applyExpertMode(g_bUIexpert);
6714
6715 // We set the compass size first, since that establishes the available space
6716 // for the toolbar.
6717 SetGPSCompassScale();
6718 // ..For each canvas...
6719 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
6720 ChartCanvas *cc = g_canvasArray.Item(i);
6721 if (cc) cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
6722 }
6723 UpdateGPSCompassStatusBoxes(true);
6724
6725 if (b_newToolbar) {
6726 AbstractPlatform::ShowBusySpinner();
6727
6728 SetAllToolbarScale();
6729 RequestNewToolbars(
6730 true); // Force rebuild, to pick up bGUIexpert and scale settings.
6731
6732 AbstractPlatform::HideBusySpinner();
6733
6734 RequestNewMasterToolbar(true);
6735 }
6736
6737 // gFrame->Raise();
6738
6739 InvalidateAllGL();
6740 DoChartUpdate();
6741 UpdateControlBar(GetPrimaryCanvas());
6742 Refresh();
6743
6744 if (console) console->Raise();
6745
6746 Refresh(false);
6747 if (m_data_monitor->IsVisible()) m_data_monitor->Raise();
6748}
6749
6750#ifdef wxHAS_POWER_EVENTS
6751void MyFrame::OnSuspending(wxPowerEvent &event) {
6752 // wxDateTime now = wxDateTime::Now();
6753 // printf("OnSuspending...%d\n", now.GetTicks());
6754
6755 wxLogMessage("System suspend starting...");
6756}
6757
6758void MyFrame::OnSuspended(wxPowerEvent &WXUNUSED(event)) {
6759 // wxDateTime now = wxDateTime::Now();
6760 // printf("OnSuspended...%d\n", now.GetTicks());
6761 wxLogMessage("System is going to suspend.");
6762}
6763
6764void MyFrame::OnSuspendCancel(wxPowerEvent &WXUNUSED(event)) {
6765 // wxDateTime now = wxDateTime::Now();
6766 // printf("OnSuspendCancel...%d\n", now.GetTicks());
6767 wxLogMessage("System suspend was cancelled.");
6768}
6769
6770int g_last_resume_ticks;
6771void MyFrame::OnResume(wxPowerEvent &WXUNUSED(event)) {
6772 wxDateTime now = wxDateTime::Now();
6773 wxLogMessage("System resumed from suspend.");
6774
6775 if ((now.GetTicks() - g_last_resume_ticks) > 5) {
6776 SystemEvents::GetInstance().evt_resume.Notify();
6777
6778 wxLogMessage("Restarting streams.");
6779 g_last_resume_ticks = now.GetTicks();
6780// FIXME (dave)
6781#if 0
6782 if (g_pMUX) {
6783 g_pMUX->ClearStreams();
6784
6785 g_pMUX->StartAllStreams();
6786 }
6787#endif
6788 }
6789
6790 // If OpenGL is enabled, Windows Resume does not properly refresh the
6791 // application GL context. We need to force a Resize event that actually does
6792 // something.
6793 if (g_bopengl) {
6794 if (IsMaximized()) { // This is not real pretty on-screen, but works
6795 Maximize(false);
6796 wxYield();
6797 Maximize(true);
6798 } else {
6799 wxSize sz = GetSize();
6800 SetSize(wxSize(sz.x - 1, sz.y));
6801 wxYield();
6802 SetSize(sz);
6803 }
6804 }
6805}
6806#endif // wxHAS_POWER_EVENTS
6807
6808//----------------------------------------------------------------------------------------------------------
6809// Master Toolbar support
6810//----------------------------------------------------------------------------------------------------------
6811
6812void MyFrame::RequestNewMasterToolbar(bool bforcenew) {
6813 bool btbRebuild = false;
6814
6815 bool b_reshow = true;
6816 if (g_MainToolbar) {
6817 b_reshow = true; // g_MainToolbar->IsShown();
6818 float ff = fabs(g_MainToolbar->GetScaleFactor() - g_toolbar_scalefactor);
6819 if ((ff > 0.01f) || bforcenew) {
6820 g_MainToolbar->DestroyToolBar();
6821 delete g_MainToolbar;
6822 g_MainToolbar = NULL;
6823 }
6824
6825 btbRebuild = true;
6826 }
6827
6828 if (!g_MainToolbar) {
6829 long orient = g_Platform->GetDefaultToolbarOrientation();
6830 wxWindow *toolbarParent = this;
6831#ifdef __WXOSX__
6832 toolbarParent = GetPrimaryCanvas();
6833#endif
6835 toolbarParent, wxPoint(-1, -1), orient, g_toolbar_scalefactor,
6836 m_toolbar_callbacks);
6837 g_MainToolbar->SetBackGroundColorString("GREY3");
6838 g_MainToolbar->SetToolbarHideMethod(TOOLBAR_HIDE_TO_FIRST_TOOL);
6839 g_MainToolbar->SetToolConfigString(g_toolbarConfig);
6840 g_MainToolbar->EnableRolloverBitmaps(false);
6841
6842 g_MainToolbar->CreateConfigMenu();
6843 g_MainToolbar->SetDefaultPosition();
6844
6845 g_bmasterToolbarFull = true;
6846 }
6847
6848 if (g_MainToolbar) {
6849 CreateMasterToolbar();
6850 {
6851 // g_MainToolbar->RestoreRelativePosition(g_maintoolbar_x,
6852 // g_maintoolbar_y);
6853 g_MainToolbar->SetColorScheme(global_color_scheme);
6854 // g_MainToolbar->Show(b_reshow && g_bshowToolbar);
6855 }
6856 }
6857
6858 if (btbRebuild) {
6859 g_MainToolbar->SetAutoHide(g_bAutoHideToolbar);
6860 g_MainToolbar->SetAutoHideTimer(g_nAutoHideToolbar);
6861 }
6862}
6863
6864bool MyFrame::CollapseGlobalToolbar() {
6865 if (g_MainToolbar) {
6866 m_nMasterToolCountShown = 1;
6867 g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
6868 g_MainToolbar->GetToolbar()->InvalidateBitmaps();
6869 g_MainToolbar->Realize();
6870 g_bmasterToolbarFull = false;
6871 return true;
6872 } else
6873 return false;
6874}
6875
6876ocpnToolBarSimple *MyFrame::CreateMasterToolbar() {
6877 ocpnToolBarSimple *tb = NULL;
6878
6879 if (g_MainToolbar) tb = g_MainToolbar->GetToolbar();
6880
6881 if (!tb) return 0;
6882
6883 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
6884
6886 ID_MASTERTOGGLE, style->GetToolIcon("MUI_menu", TOOLICON_NORMAL),
6887 wxITEM_NORMAL, _("Hide Toolbar"), "MUI_menu");
6888 tic->m_bRequired = true;
6889
6890 g_MainToolbar->AddToolItem(tic);
6891
6892 tic = new ToolbarItemContainer(
6893 ID_SETTINGS, style->GetToolIcon("MUI_settings", TOOLICON_NORMAL),
6894 wxITEM_NORMAL, _("Options"), "MUI_settings");
6895 g_MainToolbar->AddToolItem(tic);
6896
6897 tic = new ToolbarItemContainer(
6898 ID_MENU_ROUTE_NEW, style->GetToolIcon("MUI_route", TOOLICON_NORMAL),
6899 style->GetToolIcon("MUI_route", TOOLICON_TOGGLED), wxITEM_CHECK,
6900 wxString(_("Create Route")) << " (Ctrl-R)", "MUI_route");
6901
6902 g_MainToolbar->AddToolItem(tic);
6903
6904 tic = new ToolbarItemContainer(
6905 ID_ROUTEMANAGER, style->GetToolIcon("MUI_RMD", TOOLICON_NORMAL),
6906 wxITEM_NORMAL, _("Route & Mark Manager"), "MUI_RMD");
6907 g_MainToolbar->AddToolItem(tic);
6908
6909 tic = new ToolbarItemContainer(
6910 ID_TRACK, style->GetToolIcon("MUI_track", TOOLICON_NORMAL),
6911 style->GetToolIcon("MUI_track", TOOLICON_TOGGLED), wxITEM_CHECK,
6912 _("Enable Tracking"), "MUI_track");
6913 g_MainToolbar->AddToolItem(tic);
6914
6915 tic = new ToolbarItemContainer(
6916 ID_COLSCHEME, style->GetToolIcon("MUI_colorscheme", TOOLICON_NORMAL),
6917 wxITEM_NORMAL, _("Change Color Scheme"), "MUI_colorscheme");
6918 g_MainToolbar->AddToolItem(tic);
6919 // if( GetMasterToolItemShow(ID_COLSCHEME) ){
6920 // tb->AddTool( ID_COLSCHEME, "MUI_colorscheme", style->GetToolIcon(
6921 // "MUI_colorscheme", TOOLICON_NORMAL ),
6922 // tipString, wxITEM_NORMAL );
6923 // tb->SetToolTooltipHiViz( ID_COLSCHEME, true ); // cause the Tooltip to
6924 // always be visible, whatever
6925 // the colorscheme
6926 //}
6927
6928 tic = new ToolbarItemContainer(
6929 ID_PRINT, style->GetToolIcon("MUI_print", TOOLICON_NORMAL), wxITEM_NORMAL,
6930 _("Print Chart"), "MUI_print");
6931 g_MainToolbar->AddToolItem(tic);
6932
6933 tic = new ToolbarItemContainer(
6934 ID_ABOUT, style->GetToolIcon("MUI_help", TOOLICON_NORMAL), wxITEM_NORMAL,
6935 _("About OpenCPN"), "MUI_help");
6936 g_MainToolbar->AddToolItem(tic);
6937
6938 // Add any PlugIn toolbar tools that request default positioning
6939 AddDefaultPositionPlugInTools();
6940
6941 // And finally add the MOB tool
6942 tic = new ToolbarItemContainer(
6943 ID_MOB, style->GetToolIcon("mob_btn", TOOLICON_NORMAL), wxITEM_NORMAL,
6944 wxString(_("Drop MOB Marker")) << _(" (Ctrl-Space)"), "mob_btn");
6945 g_MainToolbar->AddToolItem(tic);
6946
6947 // Build the toolbar
6948 g_MainToolbar->RebuildToolbar();
6949
6950 // Realize() the toolbar for current geometry
6951 style->Unload();
6952 g_MainToolbar->Realize();
6953
6954 // Set PlugIn tool toggle states
6955 ArrayOfPlugInToolbarTools tool_array =
6956 g_pi_manager->GetPluginToolbarToolArray();
6957 for (unsigned int i = 0; i < tool_array.GetCount(); i++) {
6958 PlugInToolbarToolContainer *pttc = tool_array.Item(i);
6959 if (!pttc->b_viz) continue;
6960
6961 if (pttc->kind == wxITEM_CHECK) tb->ToggleTool(pttc->id, pttc->b_toggle);
6962 }
6963
6964 SetMasterToolbarItemState(ID_TRACK, g_bTrackActive);
6965 if (g_bTrackActive) {
6966 g_MainToolbar->SetToolShortHelp(ID_TRACK, _("Disable Tracking"));
6967 }
6968 g_MainToolbar->Realize();
6969
6970 return tb;
6971}
6972
6973bool MyFrame::CheckAndAddPlugInTool() {
6974 if (!g_pi_manager) return false;
6975
6976 bool bret = false;
6977 ocpnToolBarSimple *tb = NULL;
6978
6979 if (g_MainToolbar) tb = g_MainToolbar->GetToolbar();
6980
6981 if (!tb) return false;
6982
6983 int n_tools = tb->GetToolsCount();
6984
6985 // Walk the PlugIn tool spec array, checking the requested position
6986 // If a tool has been requested by a plugin at this position, add it
6987 ArrayOfPlugInToolbarTools tool_array =
6988 g_pi_manager->GetPluginToolbarToolArray();
6989
6990 for (unsigned int i = 0; i < tool_array.GetCount(); i++) {
6991 PlugInToolbarToolContainer *pttc = tool_array.Item(i);
6992 if (pttc->position == n_tools) {
6993 wxBitmap *ptool_bmp;
6994
6995 switch (global_color_scheme) {
6996 case GLOBAL_COLOR_SCHEME_DAY:
6997 ptool_bmp = pttc->bitmap_day;
6998 ;
6999 break;
7000 case GLOBAL_COLOR_SCHEME_DUSK:
7001 ptool_bmp = pttc->bitmap_dusk;
7002 break;
7003 case GLOBAL_COLOR_SCHEME_NIGHT:
7004 ptool_bmp = pttc->bitmap_night;
7005 break;
7006 default:
7007 ptool_bmp = pttc->bitmap_day;
7008 break;
7009 }
7010
7012 pttc->id, *(ptool_bmp), pttc->kind, pttc->shortHelp, "");
7013
7014 tic->m_NormalIconSVG = pttc->pluginNormalIconSVG;
7015 tic->m_RolloverIconSVG = pttc->pluginRolloverIconSVG;
7016 tic->m_ToggledIconSVG = pttc->pluginToggledIconSVG;
7017 tic->m_bPlugin = true;
7018
7019 bret = true;
7020 }
7021 }
7022
7023 // If we added a tool, call again (recursively) to allow for adding
7024 // adjacent tools
7025 if (bret)
7026 while (CheckAndAddPlugInTool()) { /* nothing to do */
7027 }
7028
7029 return bret;
7030}
7031
7032bool MyFrame::AddDefaultPositionPlugInTools() {
7033 if (!g_pi_manager) return false;
7034
7035 bool bret = false;
7036
7037 // Walk the PlugIn tool spec array, checking the requested position
7038 // If a tool has been requested by a plugin at this position, add it
7039 ArrayOfPlugInToolbarTools tool_array =
7040 g_pi_manager->GetPluginToolbarToolArray();
7041
7042 for (unsigned int i = 0; i < tool_array.GetCount(); i++) {
7043 PlugInToolbarToolContainer *pttc = tool_array.Item(i);
7044
7045 // Tool is currently tagged as invisible
7046 if (!pttc->b_viz) continue;
7047
7048 if (pttc->position == -1) // PlugIn has requested default positioning
7049 {
7050 wxBitmap *ptool_bmp;
7051
7052 switch (global_color_scheme) {
7053 case GLOBAL_COLOR_SCHEME_DAY:
7054 ptool_bmp = pttc->bitmap_day;
7055 break;
7056 case GLOBAL_COLOR_SCHEME_DUSK:
7057 ptool_bmp = pttc->bitmap_dusk;
7058 break;
7059 case GLOBAL_COLOR_SCHEME_NIGHT:
7060 ptool_bmp = pttc->bitmap_night;
7061 break;
7062 default:
7063 ptool_bmp = pttc->bitmap_day;
7064 break;
7065 }
7066
7068 pttc->id, *(ptool_bmp), pttc->kind, pttc->shortHelp, "");
7069
7070 tic->m_NormalIconSVG = pttc->pluginNormalIconSVG;
7071 tic->m_RolloverIconSVG = pttc->pluginRolloverIconSVG;
7072 tic->m_ToggledIconSVG = pttc->pluginToggledIconSVG;
7073 tic->m_bPlugin = true;
7074
7075 g_MainToolbar->AddToolItem(tic);
7076
7077 bret = true;
7078 }
7079 }
7080 return bret;
7081}
7082
7083/*************************************************************************
7084 * Global color management routines
7085 *
7086 *************************************************************************/
7087
7088#ifdef __WXMSW__
7089
7090#define NCOLORS 40
7091
7092typedef struct _MSW_COLOR_SPEC {
7093 int COLOR_NAME;
7094 wxString S52_RGB_COLOR;
7095 int SysRGB_COLOR;
7096} MSW_COLOR_SPEC;
7097
7098MSW_COLOR_SPEC color_spec[] = {{COLOR_MENU, "UIBCK", 0},
7099 {COLOR_MENUTEXT, "UITX1", 0},
7100 {COLOR_BTNSHADOW, "UIBCK", 0}, // Menu Frame
7101 {-1, "", 0}};
7102
7103void SaveSystemColors() {
7104 /*
7105 color_3dface = pGetSysColor(COLOR_3DFACE);
7106 color_3dhilite = pGetSysColor(COLOR_3DHILIGHT);
7107 color_3dshadow = pGetSysColor(COLOR_3DSHADOW);
7108 color_3ddkshadow = pGetSysColor(COLOR_3DDKSHADOW);
7109 color_3dlight = pGetSysColor(COLOR_3DLIGHT);
7110 color_activecaption = pGetSysColor(COLOR_ACTIVECAPTION);
7111 color_gradientactivecaption = pGetSysColor(27); //COLOR_3DLIGHT);
7112 color_captiontext = pGetSysColor(COLOR_CAPTIONTEXT);
7113 color_windowframe = pGetSysColor(COLOR_WINDOWFRAME);
7114 color_inactiveborder = pGetSysColor(COLOR_INACTIVEBORDER);
7115 */
7116 // Record the default system color in my substitution structure
7117 MSW_COLOR_SPEC *pcspec = &color_spec[0];
7118 while (pcspec->COLOR_NAME != -1) {
7119 pcspec->SysRGB_COLOR = pGetSysColor(pcspec->COLOR_NAME);
7120 pcspec++;
7121 }
7122}
7123
7124void RestoreSystemColors() {
7125 int element[NCOLORS];
7126 int rgbcolor[NCOLORS];
7127 int i = 0;
7128
7129 MSW_COLOR_SPEC *pcspec = &color_spec[0];
7130 while (pcspec->COLOR_NAME != -1) {
7131 element[i] = pcspec->COLOR_NAME;
7132 rgbcolor[i] = pcspec->SysRGB_COLOR;
7133
7134 pcspec++;
7135 i++;
7136 }
7137 if (pSetSysColors) {
7138 pSetSysColors(i, (unsigned long *)&element[0],
7139 (unsigned long *)&rgbcolor[0]);
7140 }
7141}
7142
7143#endif
7144
7145void SetSystemColors(ColorScheme cs) { //---------------
7146#ifdef __WXMSW__
7147 int element[NCOLORS];
7148 int rgbcolor[NCOLORS];
7149 int i = 0;
7150 if ((GLOBAL_COLOR_SCHEME_DUSK == cs) || (GLOBAL_COLOR_SCHEME_NIGHT == cs)) {
7151 MSW_COLOR_SPEC *pcspec = &color_spec[0];
7152 while (pcspec->COLOR_NAME != -1) {
7153 wxColour color = GetGlobalColor(pcspec->S52_RGB_COLOR);
7154 rgbcolor[i] = (color.Red() << 16) + (color.Green() << 8) + color.Blue();
7155 element[i] = pcspec->COLOR_NAME;
7156
7157 i++;
7158 pcspec++;
7159 }
7160
7161 pSetSysColors(i, (unsigned long *)&element[0],
7162 (unsigned long *)&rgbcolor[0]);
7163
7164 } else { // for daylight colors, use default windows colors as saved....
7165
7166 RestoreSystemColors();
7167 }
7168#endif
7169}
7170
7171// Console supporting printf functionality for Windows GUI app
7172#ifdef __WXMSW__
7173static const WORD MAX_CONSOLE_LINES =
7174 500; // maximum mumber of lines the output console should have
7175
7176// #ifdef _DEBUG
7177
7178void RedirectIOToConsole()
7179
7180{
7181 int hConHandle;
7182
7183 wxIntPtr lStdHandle;
7184
7185 CONSOLE_SCREEN_BUFFER_INFO coninfo;
7186
7187 FILE *fp;
7188
7189 // allocate a console for this app
7190
7191 AllocConsole();
7192
7193 // set the screen buffer to be big enough to let us scroll text
7194
7195 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
7196 coninfo.dwSize.Y = MAX_CONSOLE_LINES;
7197 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
7198
7199 // redirect unbuffered STDOUT to the console
7200
7201 lStdHandle = (wxIntPtr)GetStdHandle(STD_OUTPUT_HANDLE);
7202 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
7203 fp = _fdopen(hConHandle, "w");
7204 *stdout = *fp;
7205 setvbuf(stdout, NULL, _IONBF, 0);
7206
7207 // redirect unbuffered STDIN to the console
7208
7209 lStdHandle = (wxIntPtr)GetStdHandle(STD_INPUT_HANDLE);
7210 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
7211 fp = _fdopen(hConHandle, "r");
7212 *stdin = *fp;
7213 setvbuf(stdin, NULL, _IONBF, 0);
7214
7215 // redirect unbuffered STDERR to the console
7216
7217 lStdHandle = (wxIntPtr)GetStdHandle(STD_ERROR_HANDLE);
7218 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
7219 fp = _fdopen(hConHandle, "w");
7220 *stderr = *fp;
7221 setvbuf(stderr, NULL, _IONBF, 0);
7222
7223 // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console
7224 // as well
7225
7226 // ios::sync_with_stdio();
7227}
7228
7229#endif
7230
7231void ApplyLocale() {
7232 FontMgr::Get().SetLocale(g_locale);
7233 FontMgr::Get().ScrubList();
7234
7235 // Close and re-init various objects to allow new locale to show.
7236 // delete g_options;
7237 // g_options = NULL;
7238 // g_pOptions = NULL;
7239
7240 if (pRoutePropDialog) {
7241 pRoutePropDialog->Hide();
7242 pRoutePropDialog->Destroy();
7243 pRoutePropDialog = NULL;
7244 }
7245
7246 if (pRouteManagerDialog) {
7247 pRouteManagerDialog->Hide();
7248 pRouteManagerDialog->Destroy();
7249 pRouteManagerDialog = NULL;
7250 }
7251
7252 if (console) console->SetColorScheme(global_color_scheme);
7253 if (g_pais_query_dialog_active) {
7254 g_pais_query_dialog_active->Destroy();
7255 g_pais_query_dialog_active = NULL;
7256 }
7257
7258 auto alert_dlg_active =
7259 dynamic_cast<AISTargetAlertDialog *>(g_pais_alert_dialog_active);
7260 if (alert_dlg_active) {
7261 alert_dlg_active->Destroy();
7262 g_pais_alert_dialog_active = nullptr;
7263 }
7264
7265 if (g_pAISTargetList) {
7266 if (g_pauimgr) g_pauimgr->DetachPane(g_pAISTargetList);
7267 g_pAISTargetList->Disconnect_decoder();
7268 g_pAISTargetList->Destroy();
7269 g_pAISTargetList = NULL;
7270 }
7271
7272 // Process the menubar, if present.
7273 if (gFrame->m_pMenuBar) { // remove the menu bar if it is presently enabled
7274 gFrame->SetMenuBar(NULL);
7275 gFrame->m_pMenuBar->Destroy();
7276 gFrame->m_pMenuBar = NULL;
7277 }
7278 gFrame->BuildMenuBar();
7279
7280 // Give all canvas a chance to update, if needed
7281 for (unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
7282 ChartCanvas *cc = g_canvasArray.Item(i);
7283 if (cc) cc->CanvasApplyLocale();
7284 }
7285
7286 // Capture a copy of the current perspective
7287 // So that we may restore PlugIn window sizes, position, visibility, etc.
7288 wxString perspective;
7289 pConfig->SetPath("/AUI");
7290 pConfig->Read("AUIPerspective", &perspective);
7291
7292 // Compliant Plugins will reload their locale message catalog during the
7293 // Init() method. So it is sufficient to simply deactivate, and then
7294 // re-activate, all "active" plugins.
7295 PluginLoader::GetInstance()->DeactivateAllPlugIns();
7296 PluginLoader::GetInstance()->UpdatePlugIns();
7297
7298 // // Make sure the perspective saved in the config file is
7299 // "reasonable"
7300 // // In particular, the perspective should have an entry for every
7301 // // windows added to the AUI manager so far.
7302 // // If any are not found, then use the default layout
7303 //
7304 bool bno_load = false;
7305 wxAuiPaneInfoArray pane_array_val = g_pauimgr->GetAllPanes();
7306
7307 for (unsigned int i = 0; i < pane_array_val.GetCount(); i++) {
7308 wxAuiPaneInfo pane = pane_array_val[i];
7309 if (perspective.Find(pane.name) == wxNOT_FOUND) {
7310 bno_load = true;
7311 break;
7312 }
7313 }
7314
7315 if (!bno_load) g_pauimgr->LoadPerspective(perspective, false);
7316
7317 g_pauimgr->Update();
7318
7319 if (gFrame) {
7320 gFrame->RequestNewToolbars(true);
7321 gFrame->RequestNewMasterToolbar(true);
7322 }
7323}
7324
7325class ParseENCWorkerThread : public wxThread {
7326public:
7327 ParseENCWorkerThread(wxString filename, Extent &ext, int scale)
7328 : wxThread(wxTHREAD_JOINABLE) {
7329 m_filename = filename;
7330 m_ext = ext;
7331 m_scale = scale;
7332 Create();
7333 }
7334
7335 void *Entry() {
7336 // ChartBase *pchart = ChartData->OpenChartFromDB(m_filename,
7337 // FULL_INIT); ChartData->DeleteCacheChart(pchart);
7338 s57chart *newChart = new s57chart;
7339
7340 newChart->SetNativeScale(m_scale);
7341 newChart->SetFullExtent(m_ext);
7342
7343 newChart->FindOrCreateSenc(m_filename);
7344 delete newChart;
7345 return 0;
7346 }
7347
7348 wxString m_filename;
7349 Extent m_ext;
7350 int m_scale;
7351};
7352
7353// begin duplicated code
7354static double chart_dist(int index) {
7355 double d;
7356 float clon;
7357 float clat;
7358 const ChartTableEntry &cte = ChartData->GetChartTableEntry(index);
7359 // if the chart contains ownship position set the distance to 0
7360 if (cte.GetBBox().Contains(gLat, gLon))
7361 d = 0.;
7362 else {
7363 // find the nearest edge
7364 double t;
7365 clon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
7366 d = DistGreatCircle(cte.GetLatMax(), clon, gLat, gLon);
7367 t = DistGreatCircle(cte.GetLatMin(), clon, gLat, gLon);
7368 if (t < d) d = t;
7369
7370 clat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
7371 t = DistGreatCircle(clat, cte.GetLonMin(), gLat, gLon);
7372 if (t < d) d = t;
7373 t = DistGreatCircle(clat, cte.GetLonMax(), gLat, gLon);
7374 if (t < d) d = t;
7375 }
7376 return d;
7377}
7378
7379WX_DEFINE_SORTED_ARRAY_INT(int, MySortedArrayInt);
7380static int CompareInts(int n1, int n2) {
7381 double d1 = chart_dist(n1);
7382 double d2 = chart_dist(n2);
7383 return (int)(d1 - d2);
7384}
7385
7386class compress_target {
7387public:
7388 wxString chart_path;
7389 double distance;
7390};
7391
7392WX_DECLARE_OBJARRAY(compress_target, ArrayOfCompressTargets);
7393WX_DEFINE_OBJARRAY(ArrayOfCompressTargets);
7394
7395#include <wx/arrimpl.cpp>
7396// end duplicated code
7397
7398void ParseAllENC(wxWindow *parent) {
7399 MySortedArrayInt idx_sorted_by_distance(CompareInts);
7400
7401 // Building the cache may take a long time....
7402 // Be a little smarter.
7403 // Build a sorted array of chart database indices, sorted on distance from the
7404 // ownship currently. This way, a user may build a few chart SENCs for
7405 // immediate use, then "skip" or "cancel"out on the rest until later.
7406 int count = 0;
7407 for (int i = 0; i < ChartData->GetChartTableEntries(); i++) {
7408 /* skip if not ENC */
7409 const ChartTableEntry &cte = ChartData->GetChartTableEntry(i);
7410 if (CHART_TYPE_S57 != cte.GetChartType()) continue;
7411
7412 idx_sorted_by_distance.Add(i);
7413 count++;
7414 }
7415
7416 if (count == 0) return;
7417
7418 wxLogMessage(wxString::Format("ParseAllENC() count = %d", count));
7419
7420 // Build another array of sorted compression targets.
7421 // We need to do this, as the chart table will not be invariant
7422 // after the compression threads start, so our index array will be invalid.
7423
7424 ArrayOfCompressTargets ct_array;
7425 for (unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
7426 int i = idx_sorted_by_distance[j];
7427
7428 const ChartTableEntry &cte = ChartData->GetChartTableEntry(i);
7429 double distance = chart_dist(i);
7430
7431 wxString filename(cte.GetpFullPath(), wxConvUTF8);
7432
7434 pct->distance = distance;
7435 pct->chart_path = filename;
7436
7437 ct_array.push_back(pct);
7438 }
7439
7440 int thread_count = 0;
7441 ParseENCWorkerThread **workers = NULL;
7442
7443 if (g_nCPUCount > 0)
7444 thread_count = g_nCPUCount;
7445 else
7446 thread_count = wxThread::GetCPUCount();
7447
7448 if (thread_count < 1) {
7449 // obviously there's at least one CPU!
7450 thread_count = 1;
7451 }
7452
7453 // thread_count = 1; // for now because there is a problem with more than 1
7454
7455#if 0
7456 workers = new ParseENCWorkerThread*[thread_count];
7457 for(int t = 0; t < thread_count; t++)
7458 workers[t] = NULL;
7459#endif
7460
7461 wxGenericProgressDialog *prog = nullptr;
7462 wxSize csz = GetOCPNCanvasWindow()->GetClientSize();
7463
7464 if (1) {
7465 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
7466 wxPD_REMAINING_TIME | wxPD_CAN_SKIP;
7467
7468 prog = new wxGenericProgressDialog();
7469 wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
7470 prog->SetFont(*qFont);
7471
7472 prog->Create(_("OpenCPN ENC Prepare"), "Longgggggggggggggggggggggggggggg",
7473 count + 1, parent, style);
7474
7475 // make wider to show long filenames
7476 // wxSize sz = prog->GetSize();
7477 // sz.x = csz.x * 8 / 10;
7478 // prog->SetSize( sz );
7479
7480 DimeControl(prog);
7481#ifdef __WXOSX__
7482 prog->ShowWindowModal();
7483#else
7484 prog->Show();
7485#endif
7486 }
7487
7488 // parse targets
7489 bool skip = false;
7490 count = 0;
7491 for (unsigned int j = 0; j < ct_array.size(); j++) {
7492 wxString filename = ct_array[j].chart_path;
7493 double distance = ct_array[j].distance;
7494 int index = ChartData->FinddbIndex(filename);
7495 if (index < 0) continue;
7496 const ChartTableEntry &cte = ChartData->GetChartTableEntry(index);
7497 Extent ext;
7498 ext.NLAT = cte.GetLatMax();
7499 ext.SLAT = cte.GetLatMin();
7500 ext.WLON = cte.GetLonMin();
7501 ext.ELON = cte.GetLonMax();
7502
7503 int scale = cte.GetScale();
7504
7505 wxString msg;
7506 msg.Printf(_("Distance from Ownship: %4.0f NMi"), distance);
7507
7508 count++;
7509 if (wxThread::IsMain()) {
7510 if (prog) {
7511 wxSize sz = prog->GetSize();
7512 if (sz.x > 600) {
7513 msg += " Chart:";
7514 msg += filename;
7515 }
7516 prog->Update(count, msg, &skip);
7517#ifndef __WXMSW__
7518 prog->Raise();
7519#endif
7520 }
7521 if (skip) break;
7522 }
7523
7524#if 1
7525 if (ps52plib) {
7526 s57chart *newChart = new s57chart;
7527
7528 newChart->SetNativeScale(scale);
7529 newChart->SetFullExtent(ext);
7530 newChart->DisableBackgroundSENC();
7531
7532 newChart->FindOrCreateSenc(filename,
7533 false); // no progress dialog required
7534 delete newChart;
7535
7536 if (wxThread::IsMain()) {
7537 msg.Printf(_("ENC Completed."));
7538 if (prog) {
7539 prog->Update(count, msg, &skip);
7540#ifndef __WXMSW__
7541 prog->Raise();
7542#endif
7543 }
7544 if (skip) break;
7545 }
7546 }
7547
7548#else
7549 for (int t = 0;; t = (t + 1) % thread_count) {
7550 if (!workers[t]) {
7551 workers[t] = new ParseENCWorkerThread(filename);
7552 workers[t]->Run();
7553 break;
7554 }
7555
7556 if (!workers[t]->IsAlive()) {
7557 workers[t]->Wait();
7558 delete workers[t];
7559 workers[t] = NULL;
7560 }
7561 if (t == 0) {
7562 // ::wxYield(); // allow ChartCanvas main
7563 // message loop to run
7564 wxThread::Sleep(1); /* wait for a worker to finish */
7565 }
7566 }
7567#endif
7568
7569#if defined(__WXMSW__) || defined(__WXOSX__)
7570 ::wxSafeYield();
7571#endif
7572 }
7573
7574#if 0
7575 /* wait for workers to finish, and clean up after then */
7576 for(int t = 0; t<thread_count; t++) {
7577 if(workers[t]) {
7578 workers[t]->Wait();
7579 delete workers[t];
7580 }
7581 }
7582 delete [] workers;
7583#endif
7584
7585 delete prog;
7586}
AboutFrameImpl * g_pAboutDlg
Global instance.
Definition about.cpp:59
About * g_pAboutDlgLegacy
Global instance.
Definition about.cpp:58
class About
Class AboutFrameImpl.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
AisInfoGui * g_pAISGUI
Global instance.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
AIS target definitions.
Class AISTargetListDialog.
Class AISTargetQueryDialog.
bool SendNoRouteRmbRmc(Routeman &routeman)
Send RMC + a faked RMB when there is no active route.
Autopilot output support.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
Wrapper for creating a ChartCtx based on global vars.
General chart base definitions.
ChartDB * ChartData
Global instance.
Definition chartdb.cpp:71
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:61
ChartCanvas * g_focusCanvas
Global instance.
Definition chcanv.cpp:1315
arrayofCanvasPtr g_canvasArray
Global instance.
Definition chcanv.cpp:173
Generic Chart canvas base.
Dialog for displaying AIS target alerts.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Extends AboutFrame, providing implementation for various event handlers and additional methods.
The OpenCPN About dialog displaying information including version, authors, license,...
Definition about.h:61
Minimal ChartCAnvas interface with very little dependencies.
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
Represents an active track that is currently being recorded.
Definition track.h:227
Handles the AIS information GUI and sound alerts.
Base class for all chart types.
Definition chartbase.h:126
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:173
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
Definition chcanv.h:805
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
Definition chcanv.h:511
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
Definition chcanv.cpp:2343
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
Definition chcanv.cpp:4628
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
Definition chcanv.cpp:5359
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:183
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
Definition chcanv.h:789
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
Definition chcanv.cpp:4634
bool SetViewPoint(double lat, double lon)
Centers the view on a specific lat/lon position.
Definition chcanv.cpp:5378
Manages the chart database and provides access to chart data.
Definition chartdb.h:95
bool Create(ArrayOfCDI &dir_array, wxGenericProgressDialog *pprog)
Creates a new chart database from a list of directories.
bool Update(ArrayOfCDI &dir_array, bool bForce, wxGenericProgressDialog *pprog)
Updates the chart database.
Represents a user-defined collection of logically related charts.
Definition chartdbs.h:485
void GenerateGLbmp()
In OpenGL mode, make the bitmap capture of the screen before the print method starts as to be sure th...
Overall logging handler, outputs to screen and log file.
bool IsVisible() const override
Return true if log is visible i.e., if it's any point using Add().
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
Definition font_mgr.cpp:442
void ScrubList()
Cleans up stale font entries after a locale change.
Definition font_mgr.cpp:557
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Definition font_mgr.cpp:193
EventVar color_scheme_change
Notified when the day/dusk/night color scheme changes.
Definition gui_events.h:45
static void ReleaseInstance()
Release Instance.
static LocalServerApi & GetInstance()
Handle logging and forwarding of incoming n0183/n2k messages.
Definition multiplexer.h:56
Main application frame.
Definition ocpn_frame.h:108
void OnFrameTimer1(wxTimerEvent &event)
Main application timer handler called approximately once per second.
void InitApiListeners()
Setup handling of events from the local ipc/dbus API.
void OnFrameTenHzTimer(wxTimerEvent &event)
High-frequency timer handler running at 10Hz for smooth navigation updates.
NMEA Log Interface.
Definition nmea_log.h:70
virtual bool IsVisible() const =0
Return true if log is visible i.e., if it's any point using Add().
virtual void Add(const Logline &l)=0
Add a formatted string to log output.
double GetDisplaySizeMM()
Get the width of the screen in millimeters.
void Init(const KeyProvider &kp, const std::function< void(ObservedEvt &ev)> &action)
Initiate an object yet not listening.
Definition observable.h:295
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
Custom event class for OpenCPN's notification system.
std::shared_ptr< const void > GetSharedPtr() const
Gets the event's payload data.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
bool LoadAllPlugIns(bool enabled_plugins, bool keep_orphans=false)
Update catalog with imported metadata and load all plugin library files.
bool UnLoadAllPlugIns()
Unload allplugins i.
bool UpdatePlugIns()
Update the GetPlugInArray() list by reloading all plugins from disk.
const ArrayOfPlugIns * GetPlugInArray()
Return list of currently loaded plugins.
bool DeactivateAllPlugIns()
Deactivate all plugins.
static PrintDialog & GetInstance()
Get instance to handle the print process,.
AbstractRestServer implementation and interface to underlying IO thread.
std::string GetEndpoint() override
Return HTTPS url to local rest server.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
Represents a navigational route in the navigation system.
Definition route.h:99
wxString m_RouteStartString
Name or description of the route's starting point.
Definition route.h:252
bool m_bDeleteOnArrival
Flag indicating whether the route should be deleted once navigation reaches the end.
Definition route.h:268
wxString m_RouteEndString
Name or description of the route's ending point.
Definition route.h:257
RoutePoint * m_pRouteActivePoint
Pointer to the currently active waypoint within this route.
Definition route.h:214
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:247
wxString m_GUID
Globally unique identifier for this route.
Definition route.h:273
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:222
EventVar evt_resume
Notified when resuming from hibernate.
Definition sys_events.h:39
Definition tcmgr.h:89
Container for toolbar item properties.
Definition toolbar.h:46
Represents a single point in a track.
Definition track.h:59
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
Definition track.cpp:138
Represents a track, which is a series of connected track points.
Definition track.h:117
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
Definition viewport.h:204
double rotation
Rotation angle of the viewport in radians.
Definition viewport.h:214
double skew
Angular distortion (shear transform) applied to the viewport in radians.
Definition viewport.h:212
double clon
Center longitude of the viewport in degrees.
Definition viewport.h:199
double clat
Center latitude of the viewport in degrees.
Definition viewport.h:197
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
wxSize canvasSize
Canvas dimensions.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowGrid
Display coordinate grid.
ChartCanvas * canvas
Pointer to associated chart canvas.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
Floating toolbar for iENC (International Electronic Navigational Chart) functionality.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
Definition compass.h:63
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:60
Floating toolbar dialog for OpenCPN.
Definition toolbar.h:395
Generic toolbar implementation in pure wxWidgets adapted from wxToolBarSimple (deprecated).
Definition toolbar.h:109
virtual void OnToolbarToolCallback(int id)
Handles toolbar tool clicks.
Represents an S57 format electronic navigational chart in OpenCPN.
Definition s57chart.h:90
The JSON parser.
Definition jsonreader.h:50
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
Definition jsonval.h:84
bool HasMember(unsigned index) const
Return TRUE if the object contains an element at the specified index.
Definition jsonval.cpp:1298
wxString AsString() const
Return the stored value as a wxWidget's string.
Definition jsonval.cpp:872
CM93OffsetDialog * g_pCM93OffsetDialog
Global instance.
Definition cm93.cpp:73
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
wxColorHashMap * pcurrent_user_color_hash
Global instance.
Global color handling by name.
CommBridge class and helpers.
Communication drivers factory and support.
Driver registration container, a singleton.
NMEA Data Multiplexer Object.
Raw messages layer, supports sending and recieving navmsg messages.
Variables maintained by comm stack, read-only access for others.
APConsole * console
Global instance.
Definition concanv.cpp:55
Primary navigation console display for route and vessel tracking.
Config file user configuration interface.
bool g_always_send_rmb_rmc
Always send RMB and RMC n0183 messages even if there is no active route.
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
std::vector< size_t > g_config_display_size_mm
Size of pysical screen in millimeters.
double g_display_size_mm
Physical display width (mm)
Global variables stored in configuration file.
Options | Connections GUI tab managing connections
Extern C linked utilities.
New NMEA Debugger successor main window.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
Definition displays.cpp:45
Font list manager.
OpenCPN Georef utility.
OpenGL chart rendering canvas.
Platform independent GL includes.
glTextureManager * g_glTextureManager
Global instance.
Go to position dialog...
Hooks into gui available in model.
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
General purpose GUI support.
size_t g_current_monitor
Current monitor displaying main application frame.
Definition gui_vars.cpp:75
double vLat
Virtual lat from chcanv popup.
Definition gui_vars.cpp:72
double vLon
Virtual lon from chcanv popup.
Definition gui_vars.cpp:73
bool b_inCompressAllCharts
Flag to control adaptive UI scaling.
Definition gui_vars.cpp:35
int g_NeedDBUpdate
0 - No update needed, 1 - Update needed because there is no chart database, inform user 2 - Start upd...
Definition gui_vars.cpp:96
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
Definition gui_vars.cpp:69
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
GUI constant definitions.
iENCToolbar * g_iENCToolbar
Global instance.
iENC specific chart operations floating toolbar extension
Chart object layer.
The local API has a server side handling commands and a client part issuing commands.
Enhanced logging interface on top of wx/log.h.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Definition mark_info.cpp:76
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
double AnchorDistFix(double const d, double const AnchorPointMinDist, double const AnchorPointMaxDist)
Return constrained value of d so that AnchorPointMinDist < abs(d) < AnchorPointMaxDist.
MySQL based storage for routes, tracks, etc.
MyConfig * pConfig
Global instance.
Definition navutil.cpp:118
Utility functions.
Navigation Utility Functions without GUI dependencies.
User notifications manager.
S57 SENC File Object.
OCPN_AUIManager * g_pauimgr
Global instance.
OCPN_AUIManager.
OpenCPN top window.
MyFrame * gFrame
Global instance.
OpenCPN Platform specific support utilities.
PlugIn Object Definition/API.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
wxFont * FindOrCreateFont_PlugIn(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline, const wxString &facename, wxFontEncoding encoding)
Creates or finds a font in the font cache.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
void JumpToPosition(double lat, double lon, double scale)
Centers chart display on specified position at given scale.
wxWindow * GetCanvasUnderMouse()
Gets canvas window under mouse cursor.
void SendPluginMessage(wxString message_id, wxString message_body)
Sends message to other plugins.
Miscellaneous utilities, many of which string related.
options * g_options
Global instance.
Definition options.cpp:183
Options dialog.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
Definition own_ship.cpp:34
double gHdm
Magnetic heading in degrees (0-359.99).
Definition own_ship.cpp:31
double gVar
Magnetic variation in degrees.
Definition own_ship.cpp:32
double gHdt
True heading in degrees (0-359.99).
Definition own_ship.cpp:30
double gLat
Vessel's current latitude in decimal degrees.
Definition own_ship.cpp:26
double gCog
Course over ground in degrees (0-359.99).
Definition own_ship.cpp:28
double gSog
Speed over ground in knots.
Definition own_ship.cpp:29
double gLon
Vessel's current longitude in decimal degrees.
Definition own_ship.cpp:27
Position, course, speed, etc.
Tools to send data to plugins.
Low level code to load plugins from disk, notably the PluginLoader class.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Generic, styled prit dialog.
Print chart canvas mix-in.
wxRect g_blink_rect
Global instance.
Purpose: Track and Trackpoint drawing stuff.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
Route properties dialog.
RoutePoint * pAnchorWatchPoint2
Global instance.
Definition routeman.cpp:64
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
RouteList * pRouteList
Global instance.
Definition routeman.cpp:66
RoutePoint * pAnchorWatchPoint1
Global instance.
Definition routeman.cpp:63
Route * pAISMOBRoute
Global instance.
Definition routeman.cpp:61
Route Manager.
Routeman drawing stuff.
RouteManagerDialog * pRouteManagerDialog
Global instance.
Manage routes dialog.
S57QueryDialog * g_pObjectQueryDialog
Global instance.
S57 object query result window.
S57 Chart Object.
Select * pSelect
Global instance.
Definition select.cpp:36
Selected route, segment, waypoint, etc.
const wxEventType wxEVT_OCPN_BUILDSENCTHREAD
Global instance.
Class StdIcon, typically a small monochrome svg icon.
Represents an entry in the chart table, containing information about a single chart.
Definition chartdbs.h:187
A generic position and navigation data structure.
Definition ocpn_types.h:68
double kCog
Course over ground in degrees.
Definition ocpn_types.h:86
double kHdt
True heading in degrees.
Definition ocpn_types.h:111
int nSats
Number of satellites used in the fix.
Definition ocpn_types.h:126
double kHdm
Magnetic heading in degrees.
Definition ocpn_types.h:104
time_t FixTime
UTC time of fix.
Definition ocpn_types.h:118
double kLat
Latitude in decimal degrees.
Definition ocpn_types.h:75
double kSog
Speed over ground in knots.
Definition ocpn_types.h:92
double kVar
Magnetic variation in degrees.
Definition ocpn_types.h:98
double kLon
Longitude in decimal degrees.
Definition ocpn_types.h:83
Item in the log window.
Definition nmea_log.h:32
Suspend/resume and new devices events exchange point.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Definition tcmgr.cpp:42
Tide and Current Manager @TODO Add original author copyright.
Timer identification constants.
ocpnFloatingToolbarDialog * g_MainToolbar
Global instance.
Definition toolbar.cpp:66
OpenCPN Toolbar.
ActiveTrack * g_pActiveTrack
global instance
Definition track.cpp:99
std::vector< Track * > g_TrackList
Global instance.
Definition track.cpp:96
Recorded track abstraction.
TrackPropDlg * pTrackPropDialog
Global instance.
Track Properties Dialog.
void DestroyDeviceNotFoundDialogs()
Destroy all open "Device not found" dialog windows.
Access checks for comm devices and dongle.
Generic hardware events interface.
WaypointMan drawing stuff.