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