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