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