1 /***************************************************************************
2  *
3  * Project:  OpenCPN
4  * Purpose:  OpenCPN Main wxWidgets Program
5  * Author:   David Register
6  *
7  ***************************************************************************
8  *   Copyright (C) 2010 by David S. Register                               *
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program; if not, write to the                         *
22  *   Free Software Foundation, Inc.,                                       *
23  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
24  **************************************************************************/
25 #include <memory>
26 
27 #ifdef __MINGW32__
28 #undef IPV6STRICT    // mingw FTBS fix:  missing struct ip_mreq
29 #include <windows.h>
30 #endif
31 
32 #include "wx/wxprec.h"
33 
34 #ifndef  WX_PRECOMP
35 #include "wx/wx.h"
36 #endif //precompiled headers
37 #ifdef __WXMSW__
38 //#include "c:\\Program Files\\visual leak detector\\include\\vld.h"
39 #endif
40 
41 
42 #include <wx/settings.h>
43 #include <wx/print.h>
44 #include <wx/printdlg.h>
45 #include <wx/artprov.h>
46 #include <wx/stdpaths.h>
47 #include <wx/intl.h>
48 #include <wx/listctrl.h>
49 #include <wx/aui/aui.h>
50 #include <wx/dialog.h>
51 #include <wx/progdlg.h>
52 #include <wx/clrpicker.h>
53 #include <wx/tokenzr.h>
54 #include <wx/dir.h>
55 #include <wx/dialog.h>
56 
57 #include "dychart.h"
58 
59 #include <limits.h>
60 #include <algorithm>
61 
62 #ifdef __WXMSW__
63 #include <stdlib.h>
64 #include <math.h>
65 #include <time.h>
66 #include <psapi.h>
67 #endif
68 
69 #ifndef __WXMSW__
70 #include <signal.h>
71 #include <setjmp.h>
72 #endif
73 
74 #ifdef OCPN_HAVE_X11
75 #include <X11/Xlib.h>
76 #include <X11/Xatom.h>
77 #endif
78 
79 #include "config.h"
80 #include "chart1.h"
81 #include "chcanv.h"
82 #include "chartdb.h"
83 #include "logger.h"
84 #include "navutil.h"
85 #include "styles.h"
86 #include "routeman.h"
87 #include "piano.h"
88 #include "concanv.h"
89 #include "options.h"
90 #include "AboutFrameImpl.h"
91 #include "about.h"
92 #include "safe_mode.h"
93 #include "thumbwin.h"
94 #include "tcmgr.h"
95 #include "ais.h"
96 #include "chartimg.h"               // for ChartBaseBSB
97 #include "MarkInfo.h"
98 #include "RoutePropDlgImpl.h"
99 #include "toolbar.h"
100 #include "compass.h"
101 #include "datastream.h"
102 #ifdef __WXMSW__
103 #include "GarminProtocolHandler.h"  // Used for port probing on Windows
104 #endif
105 
106 #include "OCPN_DataStreamEvent.h"
107 #include "OCPN_SignalKEvent.h"
108 #include "multiplexer.h"
109 #include "routeprintout.h"
110 #include "Select.h"
111 #include "FontMgr.h"
112 #include "NMEALogWindow.h"
113 #include "Layer.h"
114 #include "NavObjectCollection.h"
115 #include "AISTargetListDialog.h"
116 #include "AISTargetAlertDialog.h"
117 #include "AIS_Decoder.h"
118 #include "OCP_DataStreamInput_Thread.h"
119 #include "TrackPropDlg.h"
120 #include "gshhs.h"
121 #include "cutil.h"
122 #include "routemanagerdialog.h"
123 #include "pluginmanager.h"
124 #include "AIS_Target_Data.h"
125 #include "OCPNPlatform.h"
126 #include "AISTargetQueryDialog.h"
127 #include "S57QueryDialog.h"
128 #include "glTexCache.h"
129 #include "Track.h"
130 #include "iENCToolbar.h"
131 #include "Quilt.h"
132 #include "Route.h"
133 #include "OCPN_AUIManager.h"
134 #include "CanvasConfig.h"
135 #include "ConfigMgr.h"
136 #include "MUIBar.h"
137 #include "OCPN_Sound.h"
138 #include "SoundFactory.h"
139 #include "PluginHandler.h"
140 #include "SignalKEventHandler.h"
141 
142 #ifdef ocpnUSE_GL
143 #include "glChartCanvas.h"
144 #endif
145 
146 #include <wx/image.h>
147 #include "wx/apptrait.h"
148 
149 #ifdef __WXOSX__
150 #include "macutils.h"
151 #endif
152 
153 #include "cm93.h"
154 #include "s52plib.h"
155 #include "s57chart.h"
156 #include "gdal/cpl_csv.h"
157 #include "s52utils.h"
158 
159 #ifdef __WXMSW__
160 //#define __MSVC__LEAK
161 #ifdef __MSVC__LEAK
162 #include "Stackwalker.h"
163 #endif
164 #endif
165 
166 #include <wx/jsonreader.h>
167 
168 #ifdef __OCPN__ANDROID__
169 #include "androidUTIL.h"
170 #endif
171 
172 #ifdef LINUX_CRASHRPT
173 #include "crashprint.h"
174 #endif
175 
176 #ifdef __WXOSX__
177 #include "DarkMode.h"
178 #endif
179 
180 #ifdef OCPN_USE_NEWSERIAL
181 #include "serial/serial.h"
182 #endif
183 
184 #include <wx/arrimpl.cpp>
185 WX_DEFINE_OBJARRAY( ArrayOfCDI );
186 
187 #ifdef __WXMSW__
188 void RedirectIOToConsole();
189 #endif
190 
191 #include "wx/ipc.h"
192 
193 //------------------------------------------------------------------------------
194 //      Fwd Declarations
195 //------------------------------------------------------------------------------
196 
197 
198 //------------------------------------------------------------------------------
199 //      Static variable definition
200 //------------------------------------------------------------------------------
201 
202 OCPNPlatform              *g_Platform;
203 wxString                  g_vs;
204 bool                      g_bFirstRun;
205 bool                      g_bUpgradeInProcess;
206 
207 bool                      g_bPauseTest;
208 
209 wxString                  g_compatOS;
210 wxString                  g_compatOsVersion;
211 
212 int                       g_unit_test_1;
213 int                       g_unit_test_2;
214 bool                      g_start_fullscreen;
215 bool                      g_rebuild_gl_cache;
216 bool                      g_parse_all_enc;
217 
218 // Files specified on the command line, if any.
219 wxVector<wxString> g_params;
220 
221 
222 MyFrame                   *gFrame;
223 
224 ConsoleCanvas             *console;
225 
226 MyConfig                  *pConfig;
227 
228 ChartBase                 *Current_Vector_Ch;
229 ChartDB                   *ChartData;
230 wxString                  *pdir_list[20];
231 int                       g_restore_stackindex;
232 int                       g_restore_dbindex;
233 double                    g_ChartNotRenderScaleFactor;
234 int                       g_nDepthUnitDisplay;
235 
236 RouteList                 *pRouteList;
237 TrackList                 *pTrackList;
238 LayerList                 *pLayerList;
239 bool                      g_bIsNewLayer;
240 int                       g_LayerIdx;
241 bool                      g_bLayerViz;
242 
243 Select                    *pSelect;
244 Select                    *pSelectTC;
245 Select                    *pSelectAIS;
246 
247 Routeman                  *g_pRouteMan;
248 WayPointman               *pWayPointMan;
249 MarkInfoDlg               *g_pMarkInfoDialog;
250 RoutePropDlgImpl          *pRoutePropDialog;
251 TrackPropDlg              *pTrackPropDialog;
252 RouteManagerDialog        *pRouteManagerDialog;
253 GoToPositionDialog        *pGoToPositionDialog;
254 
255 double                    gLat, gLon, gCog, gSog, gHdt, gHdm, gVar;
256 wxString                  gRmcDate, gRmcTime;
257 double                    vLat, vLon;
258 double                    initial_scale_ppm, initial_rotation;
259 
260 int                       g_nbrightness = 100;
261 
262 bool                      bDBUpdateInProgress;
263 
264 ThumbWin                  *pthumbwin;
265 TCMgr                     *ptcmgr;
266 
267 bool                      g_bshowToolbar = true;
268 bool                      g_bexpert = true;
269 bool                      g_bBasicMenus = false;;
270 
271 bool                      bDrawCurrentValues;
272 
273 wxString                  ChartListFileName;
274 wxString                  AISTargetNameFileName;
275 wxString                  gWorldMapLocation, gDefaultWorldMapLocation;
276 wxString                  *pInit_Chart_Dir;
277 wxString                  g_winPluginDir;    // Base plugin directory on Windows.
278 wxString                  g_csv_locn;
279 wxString                  g_SENCPrefix;
280 wxString                  g_UserPresLibData;
281 wxString                  g_VisibleLayers;
282 wxString                  g_InvisibleLayers;
283 wxString                  g_VisiNameinLayers;
284 wxString                  g_InVisiNameinLayers;
285 
286 bool                      g_bcompression_wait;
287 bool                      g_FlushNavobjChanges;
288 int                       g_FlushNavobjChangesTimeout;
289 
290 wxString                  g_uploadConnection;
291 
292 int                       user_user_id;
293 int                       file_user_id;
294 
295 int                       quitflag;
296 int                       g_tick = 0;
297 int                       g_mem_total, g_mem_used, g_mem_initial;
298 
299 bool                      s_bSetSystemTime;
300 
301 wxString                  *phost_name;
302 
303 static unsigned int       malloc_max;
304 
305 wxArrayOfConnPrm          *g_pConnectionParams;
306 
307 wxDateTime                g_start_time;
308 wxDateTime                g_loglast_time;
309 static OcpnSound* _bells_sounds[]  = {SoundFactory(), SoundFactory()};
310 std::vector<OcpnSound*>   bells_sound(_bells_sounds, _bells_sounds + 2  );
311 
312 OcpnSound*                g_anchorwatch_sound = SoundFactory();
313 
314 RoutePoint                *pAnchorWatchPoint1;
315 RoutePoint                *pAnchorWatchPoint2;
316 double                    AnchorPointMinDist;
317 bool                      AnchorAlertOn1, AnchorAlertOn2;
318 bool                      g_bCruising;
319 
320 ChartDummy                *pDummyChart;
321 
322 ocpnStyle::StyleManager*  g_StyleManager;
323 
324 
325 // Global print data, to remember settings during the session
326 wxPrintData               *g_printData = (wxPrintData*) NULL ;
327 
328 // Global page setup data
329 wxPageSetupData*          g_pageSetupData = (wxPageSetupData*) NULL;
330 
331 bool                      g_bShowOutlines;
332 bool                      g_bShowDepthUnits;
333 bool                      g_bDisplayGrid;  // Flag indicating weather the lat/lon grid should be displayed
334 bool                      g_bShowChartBar;
335 bool                      g_bShowActiveRouteHighway;
336 int                       g_nNMEADebug;
337 int                       g_nAWDefault;
338 int                       g_nAWMax;
339 bool                      g_bPlayShipsBells;
340 bool                      g_bFullscreenToolbar;
341 bool                      g_bShowLayers;
342 bool                      g_bTransparentToolbar;
343 bool                      g_bTransparentToolbarInOpenGLOK;
344 int                       g_nAutoHideToolbar;
345 bool                      g_bAutoHideToolbar;
346 
347 bool                      g_bPermanentMOBIcon;
348 bool                      g_bTempShowMenuBar;
349 
350 int                       g_iSDMMFormat;
351 int                       g_iDistanceFormat;
352 int                       g_iSpeedFormat;
353 
354 int                       g_iNavAidRadarRingsNumberVisible;
355 float                     g_fNavAidRadarRingsStep;
356 int                       g_pNavAidRadarRingsStepUnits;
357 int                       g_iWaypointRangeRingsNumber;
358 float                     g_fWaypointRangeRingsStep;
359 int                       g_iWaypointRangeRingsStepUnits;
360 wxColour                  g_colourWaypointRangeRingsColour;
361 bool                      g_bWayPointPreventDragging;
362 bool                      g_bConfirmObjectDelete;
363 wxColour                  g_colourOwnshipRangeRingsColour;
364 int                       g_iWpt_ScaMin;
365 bool                      g_bUseWptScaMin;
366 bool                      g_bShowWptName;
367 
368 // Set default color scheme
369 ColorScheme               global_color_scheme = GLOBAL_COLOR_SCHEME_DAY;
370 
371 static int                Usercolortable_index;
372 
373 static wxArrayPtrVoid     *UserColorTableArray;
374 static wxArrayPtrVoid     *UserColourHashTableArray;
375 
376 static wxColorHashMap     *pcurrent_user_color_hash;
377 
378 int                       gps_watchdog_timeout_ticks;
379 int                       sat_watchdog_timeout_ticks;
380 
381 int                       gGPS_Watchdog;
382 bool                      bGPSValid;
383 
384 int                       gHDx_Watchdog;
385 int                       gHDT_Watchdog;
386 int                       gVAR_Watchdog;
387 bool                      g_bHDT_Rx;
388 bool                      g_bVAR_Rx;
389 
390 int                       gSAT_Watchdog;
391 int                       g_SatsInView;
392 bool                      g_bSatValid;
393 
394 bool                      g_bDebugCM93;
395 bool                      g_bDebugS57;
396 
397 bool                      g_bfilter_cogsog;
398 int                       g_COGFilterSec = 1;
399 int                       g_SOGFilterSec;
400 
401 int                       g_ChartUpdatePeriod;
402 int                       g_SkewCompUpdatePeriod;
403 
404 int                       g_lastClientRectx;
405 int                       g_lastClientRecty;
406 int                       g_lastClientRectw;
407 int                       g_lastClientRecth;
408 double                    g_display_size_mm;
409 double                    g_config_display_size_mm;
410 bool                      g_config_display_size_manual;
411 float                     g_selection_radius_mm = 2.0;
412 float                     g_selection_radius_touch_mm = 10.0;
413 
414 int                       g_GUIScaleFactor;
415 int                       g_ChartScaleFactor;
416 float                     g_ChartScaleFactorExp;
417 int                       g_last_ChartScaleFactor;
418 int                       g_ShipScaleFactor;
419 float                     g_ShipScaleFactorExp;
420 int                       g_ENCSoundingScaleFactor;
421 
422 
423 bool                      g_bShowTide;
424 bool                      g_bShowCurrent;
425 
426 s52plib                   *ps52plib;
427 S57ClassRegistrar         *g_poRegistrar;
428 s57RegistrarMgr           *m_pRegistrarMan;
429 
430 CM93OffsetDialog          *g_pCM93OffsetDialog;
431 
432 #ifdef __WXOSX__
433 #include "macutils.h"
434 #endif
435 
436 // begin rms
437 #ifdef __WXOSX__
438 #ifdef __WXMSW__
439 #ifdef USE_GLU_TESS
440 #ifdef USE_GLU_DLL
441 // end rms
442 extern bool               s_glu_dll_ready;
443 extern HINSTANCE          s_hGLU_DLL; // Handle to DLL
444 #endif
445 #endif
446 #endif
447 #endif
448 
449 double                    g_ownship_predictor_minutes;
450 double                    g_ownship_HDTpredictor_miles;
451 
452 bool                      g_own_ship_sog_cog_calc;
453 int                       g_own_ship_sog_cog_calc_damp_sec;
454 wxDateTime                last_own_ship_sog_cog_calc_ts;
455 double                    last_own_ship_sog_cog_calc_lat, last_own_ship_sog_cog_calc_lon;
456 
457 Multiplexer               *g_pMUX;
458 
459 AIS_Decoder               *g_pAIS;
460 bool                      g_bAIS_CPA_Alert;
461 bool                      g_bAIS_CPA_Alert_Audio;
462 AISTargetAlertDialog      *g_pais_alert_dialog_active;
463 AISTargetQueryDialog      *g_pais_query_dialog_active;
464 int                       g_iSoundDeviceIndex;
465 
466 int                       g_ais_alert_dialog_x, g_ais_alert_dialog_y;
467 int                       g_ais_alert_dialog_sx, g_ais_alert_dialog_sy;
468 int                       g_ais_query_dialog_x, g_ais_query_dialog_y;
469 
470 int                       g_S57_dialog_sx, g_S57_dialog_sy;
471 
472 int                       g_nframewin_x;
473 int                       g_nframewin_y;
474 int                       g_nframewin_posx;
475 int                       g_nframewin_posy;
476 bool                      g_bframemax;
477 
478 bool                      g_bAutoAnchorMark;
479 
480 wxRect                    g_blink_rect;
481 double                    g_PlanSpeed;
482 wxDateTime                g_StartTime;
483 int                       g_StartTimeTZ;
484 IDX_entry                 *gpIDX;
485 int                       gpIDXn;
486 long                      gStart_LMT_Offset;
487 
488 wxArrayString             *pMessageOnceArray;
489 
490 FILE                      *s_fpdebug;
491 bool                      bAutoOpen;
492 
493 bool                      g_bUseGLL = true;
494 
495 int                       g_nCacheLimit;
496 int                       g_memCacheLimit;
497 bool                      g_bGDAL_Debug;
498 
499 double                    g_VPRotate; // Viewport rotation angle, used on "Course Up" mode
500 bool                      g_bCourseUp;
501 int                       g_COGAvgSec = 15; // COG average period (sec.) for Course Up Mode
502 double                    g_COGAvg;
503 bool                      g_bLookAhead;
504 bool                      g_bskew_comp;
505 bool                      g_bopengl;
506 bool                      g_bSoftwareGL;
507 bool                      g_bShowFPS;
508 bool                      g_bsmoothpanzoom;
509 bool                      g_fog_overzoom;
510 double                    g_overzoom_emphasis_base;
511 bool                      g_oz_vector_scale;
512 double                    g_plus_minus_zoom_factor;
513 
514 int                       g_nCOMPortCheck = 32;
515 
516 bool                      g_b_legacy_input_filter_behaviour;  // Support original input filter process or new process
517 
518 bool                      g_bbigred;
519 
520 PlugInManager             *g_pi_manager;
521 
522 bool                      g_bAISRolloverShowClass;
523 bool                      g_bAISRolloverShowCOG;
524 bool                      g_bAISRolloverShowCPA;
525 
526 bool                      g_bDebugGPSD;
527 
528 bool                      g_bFullScreenQuilt = true;
529 bool                      g_bQuiltEnable;
530 bool                      g_bQuiltStart;
531 
532 bool                      g_bportable;
533 
534 bool                      g_bdisable_opengl;
535 
536 ChartGroupArray           *g_pGroupArray;
537 
538 wxString                  g_GPS_Ident;
539 
540 S57QueryDialog            *g_pObjectQueryDialog;
541 
542 wxArrayString             TideCurrentDataSet;
543 wxString                  g_TCData_Dir;
544 
545 
546 bool                      g_boptionsactive;
547 options                   *g_options;
548 bool                      g_bDeferredInitDone;
549 int                       options_lastPage = 0;
550 int                       options_subpage = 0;
551 
552 wxPoint                   options_lastWindowPos( 0,0 );
553 wxSize                    options_lastWindowSize( 0,0 );
554 
555 bool                      g_bSleep;
556 bool                      g_bsimplifiedScalebar;
557 
558 int                       g_grad_default;
559 wxColour                  g_border_color_default;
560 int                       g_border_size_default;
561 int                       g_sash_size_default;
562 wxColour                  g_caption_color_default;
563 wxColour                  g_sash_color_default;
564 wxColour                  g_background_color_default;
565 
566 int                       osMajor, osMinor;
567 
568 bool GetMemoryStatus(int *mem_total, int *mem_used);
569 
570 #ifdef __WXMSW__
571 // System color control support
572 
573 typedef DWORD (WINAPI *SetSysColors_t)(DWORD, DWORD *, DWORD *);
574 typedef DWORD (WINAPI *GetSysColor_t)(DWORD);
575 
576 SetSysColors_t            pSetSysColors;
577 GetSysColor_t             pGetSysColor;
578 
579 void SaveSystemColors(void);
580 void RestoreSystemColors(void);
581 
582 DWORD                     color_3dface;
583 DWORD                     color_3dhilite;
584 DWORD                     color_3dshadow;
585 DWORD                     color_3ddkshadow;
586 DWORD                     color_3dlight;
587 DWORD                     color_activecaption;
588 DWORD                     color_gradientactivecaption;
589 DWORD                     color_captiontext;
590 DWORD                     color_windowframe;
591 DWORD                     color_inactiveborder;
592 
593 #endif
594 
595 // AIS Global configuration
596 bool                      g_bShowAIS;
597 bool                      g_bCPAMax;
598 double                    g_CPAMax_NM;
599 bool                      g_bCPAWarn;
600 double                    g_CPAWarn_NM;
601 bool                      g_bTCPA_Max;
602 double                    g_TCPA_Max;
603 bool                      g_bMarkLost;
604 double                    g_MarkLost_Mins;
605 bool                      g_bRemoveLost;
606 double                    g_RemoveLost_Mins;
607 bool                      g_bShowCOG;
608 double                    g_ShowCOG_Mins;
609 bool                      g_bAISShowTracks;
610 double                    g_AISShowTracks_Mins;
611 double                    g_AISShowTracks_Limit;
612 bool                      g_bHideMoored;
613 bool                      g_bAllowShowScaled;
614 double                    g_ShowMoored_Kts;
615 wxString                  g_sAIS_Alert_Sound_File;
616 bool                      g_bAIS_CPA_Alert_Suppress_Moored;
617 bool                      g_bAIS_ACK_Timeout;
618 double                    g_AckTimeout_Mins;
619 bool                      g_bShowScaled;
620 bool                      g_bShowAreaNotices;
621 bool                      g_bDrawAISSize;
622 bool                      g_bDrawAISRealtime;
623 double                    g_AIS_RealtPred_Kts;
624 bool                      g_bShowAISName;
625 int                       g_Show_Target_Name_Scale;
626 bool                      g_bWplIsAprsPosition;
627 
628 int                       g_nAIS_activity_timer;
629 
630 DummyTextCtrl             *g_pDummyTextCtrl;
631 bool                      g_bEnableZoomToCursor;
632 
633 bool                      g_bTrackActive;
634 bool                      g_bTrackCarryOver;
635 bool                      g_bDeferredStartTrack;
636 bool                      g_bTrackDaily;
637 int                       g_track_rotate_time;
638 int                       g_track_rotate_time_type;
639 bool                      g_bHighliteTracks;
640 int                       g_route_line_width;
641 int                       g_track_line_width;
642 wxColour                  g_colourTrackLineColour;
643 wxString                  g_default_wp_icon;
644 wxString                  g_default_routepoint_icon;
645 
646 ActiveTrack              *g_pActiveTrack;
647 double                    g_TrackIntervalSeconds;
648 double                    g_TrackDeltaDistance;
649 int                       g_nTrackPrecision;
650 
651 int                       g_total_NMEAerror_messages;
652 
653 int                       g_cm93_zoom_factor;
654 PopUpDSlide                *pPopupDetailSlider;
655 bool                      g_bShowDetailSlider;
656 int                       g_detailslider_dialog_x, g_detailslider_dialog_y;
657 
658 bool                      g_bUseGreenShip;
659 
660 wxString                  g_AW1GUID;
661 wxString                  g_AW2GUID;
662 
663 bool                      g_b_overzoom_x = true; // Allow high overzoom
664 
665 int                       g_OwnShipIconType;
666 double                    g_n_ownship_length_meters;
667 double                    g_n_ownship_beam_meters;
668 double                    g_n_gps_antenna_offset_y;
669 double                    g_n_gps_antenna_offset_x;
670 int                       g_n_ownship_min_mm;
671 
672 double                    g_n_arrival_circle_radius;
673 
674 bool                      g_bNeedDBUpdate;
675 bool                      g_bPreserveScaleOnX;
676 
677 AboutFrameImpl            *g_pAboutDlg;
678 about                     *g_pAboutDlgLegacy;
679 
680 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3,0,0)
681 wxLocale                  *plocale_def_lang;
682 #endif
683 
684 wxString                  g_locale;
685 wxString                  g_localeOverride;
686 bool                      g_b_assume_azerty;
687 
688 bool                      g_bUseRaster;
689 bool                      g_bUseVector;
690 bool                      g_bUseCM93;
691 
692 int                       g_click_stop;
693 
694 int                       g_MemFootSec;
695 int                       g_MemFootMB;
696 
697 wxStaticBitmap            *g_pStatBoxTool;
698 bool                      g_bShowStatusBar;
699 
700 bool                      g_bquiting;
701 int                       g_BSBImgDebug;
702 
703 AISTargetListDialog       *g_pAISTargetList;
704 wxString                  g_AisTargetList_perspective;
705 int                       g_AisTargetList_range;
706 int                       g_AisTargetList_sortColumn;
707 bool                      g_bAisTargetList_sortReverse;
708 wxString                  g_AisTargetList_column_spec;
709 wxString                  g_AisTargetList_column_order;
710 int                       g_AisTargetList_count;
711 bool                      g_bAisTargetList_autosort;
712 
713 bool                      g_bGarminHostUpload;
714 bool                      g_bFullscreen;
715 
716 OCPN_AUIManager           *g_pauimgr;
717 wxAuiDefaultDockArt       *g_pauidockart;
718 
719 wxString                  g_toolbarConfig = _T("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
720 wxString                  g_toolbarConfigSecondary = _T("....XX..X........XXXXXXXXXXXX");
721 
722 ocpnFloatingToolbarDialog *g_MainToolbar;
723 int                       g_maintoolbar_x;
724 int                       g_maintoolbar_y;
725 long                      g_maintoolbar_orient;
726 float                     g_toolbar_scalefactor;
727 
728 float                     g_compass_scalefactor;
729 bool                      g_bShowMenuBar;
730 bool                      g_bShowCompassWin;
731 
732 bool                      g_benable_rotate;
733 
734 bool                      g_bShowTrue = true;
735 bool                      g_bShowMag;
736 
737 double                    g_UserVar;
738 bool                      g_bMagneticAPB;
739 
740 bool                      g_bInlandEcdis;
741 
742 bool                      g_bDarkDecorations;
743 
744 //                        OpenGL Globals
745 int                       g_GPU_MemSize;
746 
747 bool                      g_bserial_access_checked;
748 wxString                  g_uiStyle;
749 
750 //      Values returned from WMM_PI for variation computation request
751 //      Initialize to invalid value so we don't use if if WMM hasn't updated yet
752 double                    gQueryVar = 361.0;
753 
754 
755 char bells_sound_file_name[2][12] = { "1bells.wav", "2bells.wav" };
756 
757 int                       portaudio_initialized;
758 
759 static char nmea_tick_chars[] = { '|', '/', '-', '\\', '|', '/', '-', '\\' };
760 static int tick_idx;
761 
762 int               g_sticky_chart;
763 int               g_sticky_projection;
764 
765 bool              g_benableUDPNullHeader;
766 
767 extern options          *g_pOptions;
768 
769 int n_NavMessageShown;
770 wxString g_config_version_string;
771 
772 wxString g_CmdSoundString;
773 
774 bool             g_btouch;
775 bool             g_bresponsive;
776 bool             g_bRollover;
777 
778 bool             b_inCompressAllCharts;
779 bool             g_bGLexpert;
780 bool             g_bUIexpert;
781 
782 int              g_chart_zoom_modifier;
783 int              g_chart_zoom_modifier_vector;
784 
785 int              g_NMEAAPBPrecision;
786 
787 wxString         g_TalkerIdText;
788 int              g_maxWPNameLength;
789 
790 bool             g_bAdvanceRouteWaypointOnArrivalOnly;
791 
792 bool             g_bSpaceDropMark;
793 
794 wxArrayString    g_locale_catalog_array;
795 bool             b_reloadForPlugins;
796 bool             g_btrackContinuous;
797 
798 unsigned int     g_canvasConfig;
799 bool             g_useMUI;
800 bool             g_bmasterToolbarFull = true;
801 
802 int              g_AndroidVersionCode;
803 
804 int              g_memUsed;
805 SENCThreadManager *g_SencThreadManager;
806 
807 WX_DEFINE_ARRAY_PTR(ChartCanvas*, arrayofCanvasPtr);
808 
809 arrayofCanvasPtr   g_canvasArray;
810 arrayofCanvasConfigPtr g_canvasConfigArray;
811 wxString         g_lastAppliedTemplateGUID;
812 
813 ChartCanvas      *g_focusCanvas;
814 ChartCanvas      *g_overlayCanvas;
815 
816 bool              b_inCloseWindow;
817 
818 #ifdef LINUX_CRASHRPT
819 wxCrashPrint g_crashprint;
820 #endif
821 
822 #ifndef __WXMSW__
823 sigjmp_buf env;                    // the context saved by sigsetjmp();
824 #endif
825 
826 // {2C9C45C2-8E7D-4C08-A12D-816BBAE722C0}
827 #ifdef  __WXMSW__
828 DEFINE_GUID( GARMIN_DETECT_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0xba, 0xe7,
829         0x22, 0xc0 );
830 #endif
831 
832 #ifdef __MSVC__
833 #define _CRTDBG_MAP_ALLOC
834 #include <stdlib.h>
835 #include <crtdbg.h>
836 #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__ )
837 #define new DEBUG_NEW
838 #endif
839 
840 #if !defined(NAN)
841 static const long long lNaN = 0xfff8000000000000;
842 #define NAN (*(double*)&lNaN)
843 #endif
844 
845 //    Some static helpers
846 void appendOSDirSlash( wxString* pString );
847 
848 static void InitializeUserColors( void );
849 static void DeInitializeUserColors( void );
850 static void SetSystemColors( ColorScheme cs );
851 
852 extern "C" bool CheckSerialAccess( void );
853 
854 #if 0
855 // Refresh the Piano Bar
856 static void refresh_Piano()
857 {
858 //     int idx = pCurrentStack->GetCurrentEntrydbIndex();
859 //     if (idx < 0)
860 //         return;
861 //
862 //     std::vector<int> piano_active_chart_index_array;
863 //     piano_active_chart_index_array.push_back( pCurrentStack->GetCurrentEntrydbIndex() );
864 //     g_Piano->SetActiveKeyArray( piano_active_chart_index_array );
865 }
866 #endif
867 
868 #ifndef __OCPN__ANDROID__
869 // Connection class, for use by both communicating instances
870 class stConnection : public wxConnection
871 {
872 public:
stConnection()873     stConnection() {}
~stConnection()874     ~stConnection() {}
875     bool OnExec(const wxString& topic, const wxString& data);
876 };
877 
878 // Opens a file passed from another instance
OnExec(const wxString & topic,const wxString & data)879 bool stConnection::OnExec(const wxString& topic, const wxString& data)
880 {
881     // not setup yet
882     if (!gFrame)
883         return false;
884 
885     wxString path(data);
886     if (path.IsEmpty()) {
887        gFrame->InvalidateAllGL();
888        gFrame->RefreshAllCanvas( false );
889        gFrame->Raise();
890     }
891     else {
892         NavObjectCollection1 *pSet = new NavObjectCollection1;
893         pSet->load_file(path.fn_str());
894         int wpt_dups;
895         pSet->LoadAllGPXObjects( !pSet->IsOpenCPN(), wpt_dups, true ); // Import with full vizibility of names and objects
896         if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
897             pRouteManagerDialog->UpdateLists();
898 
899         LLBBox box = pSet->GetBBox();
900         if (box.GetValid()) {
901             gFrame->CenterView(gFrame->GetPrimaryCanvas(), box);
902         }
903         delete pSet;
904         return true;
905     }
906     return true;
907 }
908 
909 // Server class, for listening to connection requests
910 class stServer: public wxServer
911 {
912 public:
913     wxConnectionBase *OnAcceptConnection(const wxString& topic);
914 };
915 
916 // Accepts a connection from another instance
OnAcceptConnection(const wxString & topic)917 wxConnectionBase *stServer::OnAcceptConnection(const wxString& topic)
918 {
919     if (topic.Lower() == wxT("opencpn"))
920     {
921         // Check that there are no modal dialogs active
922 	wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
923 	while (node) {
924 	    wxDialog* dialog = wxDynamicCast(node->GetData(), wxDialog);
925 	    if (dialog && dialog->IsModal()) {
926 	        return 0;
927             }
928             node = node->GetNext();
929         }
930         return new stConnection();
931     }
932     return 0;
933 }
934 
935 
936 // Client class, to be used by subsequent instances in OnInit
937 class stClient: public wxClient
938 {
939 public:
stClient()940     stClient() {};
OnMakeConnection()941     wxConnectionBase *OnMakeConnection() { return new stConnection; }
942 };
943 
944 #endif
945 
946 //------------------------------------------------------------------------------
947 //    PNG Icon resources
948 //------------------------------------------------------------------------------
949 
950 #if defined(__WXGTK__) || defined(__WXQT__)
951 #include "bitmaps/opencpn.xpm"
952 #endif
953 
954 //------------------------------------------------------------------------------
955 //              Local constants
956 //------------------------------------------------------------------------------
957 // enum {
958 //     ID_PIANO_DISABLE_QUILT_CHART = 32000, ID_PIANO_ENABLE_QUILT_CHART
959 // };
960 
961 //------------------------------------------------------------------------------
962 //              Fwd Refs
963 //------------------------------------------------------------------------------
964 
965 iENCToolbar *g_iENCToolbar;
966 int g_iENCToolbarPosX;
967 int g_iENCToolbarPosY;
968 
BuildiENCToolbar(bool bnew)969 void BuildiENCToolbar( bool bnew )
970 {
971     if(g_bInlandEcdis){
972         if(bnew){
973             if(g_iENCToolbar){
974                 wxPoint locn = g_iENCToolbar->GetPosition();
975                 wxPoint tbp_incanvas = gFrame->GetPrimaryCanvas()->ScreenToClient( locn );
976 
977                 g_iENCToolbarPosY = tbp_incanvas.y;
978                 g_iENCToolbarPosX = tbp_incanvas.x;
979 
980                 delete g_iENCToolbar;
981                 g_iENCToolbar = 0;
982             }
983         }
984 
985         if( !g_iENCToolbar ) {
986 
987             wxPoint posn(g_iENCToolbarPosX, g_iENCToolbarPosY);
988 
989             // Overlapping main toolbar?
990             if(g_MainToolbar){
991                 if((g_iENCToolbarPosY > g_maintoolbar_y) && (g_iENCToolbarPosY < g_maintoolbar_y + g_MainToolbar->GetSize().y) )
992                     g_iENCToolbarPosY = -1;         // force a reposition
993             }
994 
995             if((g_iENCToolbarPosX < 0) || (g_iENCToolbarPosY < 0)){
996                 posn.x = 0;
997                 posn.y = 100;
998 
999                 if(g_MainToolbar)
1000                     posn = wxPoint(g_maintoolbar_x + g_MainToolbar->GetSize().x + 4, g_maintoolbar_y );
1001             }
1002 
1003             double tool_scale_factor = g_Platform->GetToolbarScaleFactor( g_GUIScaleFactor );
1004 
1005             g_iENCToolbar = new iENCToolbar( gFrame,  posn, wxTB_HORIZONTAL, tool_scale_factor );
1006             g_iENCToolbar->SetColorScheme(global_color_scheme);
1007             g_iENCToolbar->EnableSubmerge( false );
1008         }
1009     }
1010     else{
1011         delete g_iENCToolbar;
1012         g_iENCToolbar = NULL;
1013     }
1014 
1015 }
1016 
ShowNavWarning()1017 int ShowNavWarning()
1018 {
1019     wxString msg0(
1020             _("\n\
1021 OpenCPN is distributed in the hope that it will be useful, \
1022 but WITHOUT ANY WARRANTY; without even the implied \
1023 warranty of MERCHANTABILITY or FITNESS FOR A \
1024 PARTICULAR PURPOSE.\n\n\
1025 See the GNU General Public License for more details.\n\n\
1026 OpenCPN must only be used in conjunction with approved \
1027 paper charts and traditional methods of navigation.\n\n\
1028 DO NOT rely upon OpenCPN for safety of life or property.\n\n\
1029 Please click \"OK\" to agree and proceed, \"Cancel\" to quit.\n") );
1030 
1031     wxString vs =
1032         wxString::Format(wxT(" .. Version %s"),
1033             VERSION_FULL);
1034 
1035 #ifdef __OCPN__ANDROID__
1036     androidShowDisclaimer( _("OpenCPN for Android") + vs, msg0 );
1037     return true;
1038 #else
1039         wxColor fg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
1040         wxString msg1;
1041         msg1.Printf(_T("<html><body><font color=#%02x%02x%02x><hr />"), fg.Red(), fg.Green(), fg.Blue());
1042 
1043         for(unsigned int i=0 ; i < msg0.Length() ; i++){
1044             if(msg0[i] == '\n')
1045                 msg1 +=  _T("<br>");
1046             else
1047                 msg1 += msg0[i];
1048         }
1049 
1050         msg1 <<  _T("<hr /></font></body></html>");
1051 
1052         OCPN_TimedHTMLMessageDialog infoDlg( gFrame, msg1, _("Welcome to OpenCPN") + vs, -1, wxCANCEL | wxOK);
1053 
1054         infoDlg.ShowModal();
1055 
1056         return (infoDlg.GetReturnCode() );
1057 #endif
1058 }
1059 
newPrivateFileName(wxString home_locn,const char * name,const char * windowsName)1060 wxString newPrivateFileName(wxString home_locn, const char *name, const char *windowsName)
1061 {
1062     wxString fname = wxString::FromUTF8(name);
1063     wxString fwname = wxString::FromUTF8(windowsName);
1064     wxString filePathAndName;
1065 
1066     filePathAndName = g_Platform->GetPrivateDataDir();
1067     if (filePathAndName.Last() != wxFileName::GetPathSeparator())
1068        filePathAndName.Append(wxFileName::GetPathSeparator());
1069 
1070 #ifdef __WXMSW__
1071      filePathAndName.Append( fwname );
1072 #else
1073      filePathAndName.Append( fname );
1074 #endif
1075 
1076      return filePathAndName;
1077 }
1078 
isSingleChart(ChartBase * chart)1079 bool isSingleChart(ChartBase *chart)
1080 {
1081    if (chart == nullptr)
1082        return false;
1083 
1084    // ..For each canvas...
1085    for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
1086       ChartCanvas *cc = g_canvasArray.Item(i);
1087       if(cc && cc->m_singleChart == chart){
1088          return true;
1089       }
1090    }
1091    return false;
1092 }
1093 
1094 
1095 // `Main program' equivalent, creating windows and returning main app frame
1096 //------------------------------------------------------------------------------
1097 // MyApp
1098 //------------------------------------------------------------------------------
1099 IMPLEMENT_APP( MyApp )
1100 
BEGIN_EVENT_TABLE(MyApp,wxApp)1101 BEGIN_EVENT_TABLE(MyApp, wxApp)
1102 EVT_ACTIVATE_APP(MyApp::OnActivateApp)
1103 END_EVENT_TABLE()
1104 
1105 #include "wx/dynlib.h"
1106 
1107 #if wxUSE_CMDLINE_PARSER
1108 void MyApp::OnInitCmdLine( wxCmdLineParser& parser )
1109 {
1110     //    Add some OpenCPN specific command line options
1111     parser.AddSwitch( _T("h"), _T("help"), _("Show usage syntax."), wxCMD_LINE_OPTION_HELP );
1112     parser.AddSwitch( _T("p"), wxEmptyString, _("Run in portable mode.") );
1113     parser.AddSwitch( _T("fullscreen"), wxEmptyString, _("Switch to full screen mode on start.") );
1114     parser.AddSwitch( _T("no_opengl"), wxEmptyString, _("Disable OpenGL video acceleration. This setting will be remembered.") );
1115     parser.AddSwitch( _T("rebuild_gl_raster_cache"), wxEmptyString, _T("Rebuild OpenGL raster cache on start.") );
1116     parser.AddSwitch( _T("parse_all_enc"), wxEmptyString, _T("Convert all S-57 charts to OpenCPN's internal format on start.") );
1117     parser.AddOption( _T("l"), _T("loglevel"), _("Amount of logging: error, warning, message, info, debug or trace"));
1118     parser.AddOption( _T("unit_test_1"), wxEmptyString, _("Display a slideshow of <num> charts and then exit. Zero or negative <num> specifies no limit."), wxCMD_LINE_VAL_NUMBER );
1119     parser.AddSwitch( _T("unit_test_2") );
1120     parser.AddParam("import GPX files",
1121                         wxCMD_LINE_VAL_STRING,
1122                         wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
1123     parser.AddLongSwitch( "unit_test_2" );
1124     parser.AddSwitch("safe_mode");
1125 }
1126 
1127 /** Parse --loglevel and set up logging, falling back to defaults. */
ParseLoglevel(wxCmdLineParser & parser)1128 static void ParseLoglevel(wxCmdLineParser& parser)
1129 {
1130     const char* strLevel = std::getenv("OPENCPN_LOGLEVEL");
1131     strLevel = strLevel ? strLevel : "info";
1132     wxString wxLevel;
1133     if (parser.Found("l", &wxLevel)) {
1134         strLevel = wxLevel.c_str();
1135     }
1136     wxLogLevel level = OcpnLog::str2level(strLevel);
1137     if (level == OcpnLog::LOG_BADLEVEL) {
1138         fprintf(stderr, "Bad loglevel %s, using \"info\"", strLevel);
1139         strLevel = "info";
1140         level = wxLOG_Info;
1141     }
1142     wxLog::SetLogLevel(level);
1143 }
1144 
OnCmdLineParsed(wxCmdLineParser & parser)1145 bool MyApp::OnCmdLineParsed( wxCmdLineParser& parser )
1146 {
1147     long number;
1148     wxString repo;
1149     wxString plugin;
1150 
1151     g_unit_test_2 = parser.Found( _T("unit_test_2") );
1152     g_bportable = parser.Found( _T("p") );
1153     g_start_fullscreen = parser.Found( _T("fullscreen") );
1154     g_bdisable_opengl = parser.Found( _T("no_opengl") );
1155     g_rebuild_gl_cache = parser.Found( _T("rebuild_gl_raster_cache") );
1156     g_parse_all_enc = parser.Found( _T("parse_all_enc") );
1157     if( parser.Found( _T("unit_test_1"), &number ) )
1158     {
1159         g_unit_test_1 = static_cast<int>( number );
1160         if( g_unit_test_1 == 0 )
1161             g_unit_test_1 = -1;
1162     }
1163     safe_mode::set_mode(parser.Found("safe_mode"));
1164     ParseLoglevel(parser);
1165 
1166     for (size_t paramNr=0; paramNr < parser.GetParamCount(); ++paramNr)
1167             g_params.push_back(parser.GetParam(paramNr));
1168 
1169     return true;
1170 }
1171 #endif
1172 
1173 #ifdef __WXMSW__
1174     //  Handle any exception not handled by CrashRpt
1175     //  Most probable:  Malloc/new failure
1176 
OnExceptionInMainLoop()1177 bool MyApp::OnExceptionInMainLoop()
1178 {
1179     wxLogWarning(_T("Caught MainLoopException, continuing..."));
1180     return true;
1181 }
1182 #endif
1183 
OnActivateApp(wxActivateEvent & event)1184 void MyApp::OnActivateApp( wxActivateEvent& event )
1185 {
1186     return;
1187 //    Code carefully in this method.
1188 //    It is called in some unexpected places,
1189 //    such as on closure of dialogs, etc.
1190 
1191     if( !event.GetActive() ) {
1192 
1193         //  Remove a temporary Menubar when the application goes inactive
1194         //  This is one way to handle properly ALT-TAB navigation on the Windows desktop
1195         //  without accidentally leaving an unwanted Menubar shown.
1196 #ifdef __WXMSW__
1197         if( g_bTempShowMenuBar ) {
1198             g_bTempShowMenuBar = false;
1199             if(gFrame)
1200                 gFrame->ApplyGlobalSettings(false);
1201         }
1202 #endif
1203 
1204 
1205     }
1206     event.Skip();
1207 }
1208 
LoadS57()1209 void LoadS57()
1210 {
1211     if(ps52plib) // already loaded?
1212         return;
1213 
1214     //  Start a SENC Thread manager
1215     g_SencThreadManager = new SENCThreadManager();
1216 
1217 //      Set up a useable CPL library error handler for S57 stuff
1218     CPLSetErrorHandler( MyCPLErrorHandler );
1219 
1220 //      Init the s57 chart object, specifying the location of the required csv files
1221     g_csv_locn = g_Platform->GetSharedDataDir();
1222     g_csv_locn.Append( _T("s57data") );
1223 
1224     if( g_bportable ) {
1225         g_csv_locn = _T(".");
1226         appendOSDirSlash( &g_csv_locn );
1227         g_csv_locn.Append( _T("s57data") );
1228     }
1229 
1230 //      If the config file contains an entry for SENC file prefix, use it.
1231 //      Otherwise, default to PrivateDataDir
1232     if( g_SENCPrefix.IsEmpty() ) {
1233         g_SENCPrefix = g_Platform->GetPrivateDataDir();
1234         appendOSDirSlash(&g_SENCPrefix);
1235         g_SENCPrefix.Append( _T("SENC") );
1236     }
1237 
1238     if( g_bportable ) {
1239         wxFileName f( g_SENCPrefix );
1240         if( f.MakeRelativeTo( g_Platform->GetPrivateDataDir() ) )
1241             g_SENCPrefix = f.GetFullPath();
1242         else
1243             g_SENCPrefix = _T("SENC");
1244     }
1245 
1246 //      If the config file contains an entry for PresentationLibraryData, use it.
1247 //      Otherwise, default to conditionally set spot under g_pcsv_locn
1248     wxString plib_data;
1249     bool b_force_legacy = false;
1250 
1251     if( g_UserPresLibData.IsEmpty() ) {
1252         plib_data = g_csv_locn;
1253         appendOSDirSlash( &plib_data );
1254         plib_data.Append( _T("S52RAZDS.RLE") );
1255     } else {
1256         plib_data = g_UserPresLibData;
1257         b_force_legacy = true;
1258     }
1259 
1260     ps52plib = new s52plib( plib_data, b_force_legacy );
1261 
1262     //  If the library load failed, try looking for the s57 data elsewhere
1263 
1264     //  First, look in UserDataDir
1265     /*    From wxWidgets documentation
1266 
1267      wxStandardPaths::GetUserDataDir
1268      wxString GetUserDataDir() const
1269      Return the directory for the user-dependent application data files:
1270      * Unix: ~/.appname
1271      * Windows: C:\Documents and Settings\username\Application Data\appname
1272      * Mac: ~/Library/Application Support/appname
1273      */
1274 
1275     if( !ps52plib->m_bOK ) {
1276         delete ps52plib;
1277 
1278         wxStandardPaths& std_path = g_Platform->GetStdPaths();
1279 
1280         wxString look_data_dir;
1281         look_data_dir.Append( std_path.GetUserDataDir() );
1282         appendOSDirSlash( &look_data_dir );
1283         wxString tentative_SData_Locn = look_data_dir;
1284         look_data_dir.Append( _T("s57data") );
1285 
1286         plib_data = look_data_dir;
1287         appendOSDirSlash( &plib_data );
1288         plib_data.Append( _T("S52RAZDS.RLE") );
1289 
1290         wxLogMessage( _T("Looking for s57data in ") + look_data_dir );
1291         ps52plib = new s52plib( plib_data );
1292 
1293         if( ps52plib->m_bOK ) {
1294             g_csv_locn = look_data_dir;
1295 ///???            g_SData_Locn = tentative_SData_Locn;
1296         }
1297     }
1298 
1299     //  And if that doesn't work, look again in the original SData Location
1300     //  This will cover the case in which the .ini file entry is corrupted or moved
1301 
1302     if( !ps52plib->m_bOK ) {
1303         delete ps52plib;
1304 
1305         wxString look_data_dir;
1306         look_data_dir = g_Platform->GetSharedDataDir();
1307         look_data_dir.Append( _T("s57data") );
1308 
1309         plib_data = look_data_dir;
1310         appendOSDirSlash( &plib_data );
1311         plib_data.Append( _T("S52RAZDS.RLE") );
1312 
1313         wxLogMessage( _T("Looking for s57data in ") + look_data_dir );
1314         ps52plib = new s52plib( plib_data );
1315 
1316         if( ps52plib->m_bOK ) g_csv_locn = look_data_dir;
1317     }
1318 
1319     if( ps52plib->m_bOK ) {
1320         wxLogMessage( _T("Using s57data in ") + g_csv_locn );
1321         m_pRegistrarMan = new s57RegistrarMgr( g_csv_locn, g_Platform->GetLogFilePtr() );
1322 
1323 
1324             //    Preset some object class visibilites for "User Standard" disply category
1325             //  They may be overridden in LoadS57Config
1326         for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
1327             OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
1328             if( !strncmp( pOLE->OBJLName, "DEPARE", 6 ) ) pOLE->nViz = 1;
1329             if( !strncmp( pOLE->OBJLName, "LNDARE", 6 ) ) pOLE->nViz = 1;
1330             if( !strncmp( pOLE->OBJLName, "COALNE", 6 ) ) pOLE->nViz = 1;
1331         }
1332 
1333         pConfig->LoadS57Config();
1334         ps52plib->SetPLIBColorScheme( global_color_scheme );
1335 
1336         if(gFrame->GetPrimaryCanvas() )
1337             ps52plib->SetPPMM( gFrame->GetPrimaryCanvas()->GetPixPerMM() );
1338 
1339 #ifdef ocpnUSE_GL
1340 
1341         // Setup PLIB OpenGL options, if enabled
1342         extern bool g_b_EnableVBO;
1343         extern GLenum  g_texture_rectangle_format;
1344         if(g_bopengl )
1345             ps52plib->SetGLOptions(glChartCanvas::s_b_useStencil,
1346                                    glChartCanvas::s_b_useStencilAP,
1347                                    glChartCanvas::s_b_useScissorTest,
1348                                    glChartCanvas::s_b_useFBO,
1349                                    g_b_EnableVBO,
1350                                    g_texture_rectangle_format);
1351 #endif
1352 
1353 
1354     } else {
1355         wxLogMessage( _T("   S52PLIB Initialization failed, disabling Vector charts.") );
1356         delete ps52plib;
1357         ps52plib = NULL;
1358     }
1359 }
1360 
1361 #if defined(__WXGTK__) && defined(OCPN_HAVE_X11)
1362 
1363 // Note: use XFree to free this pointer. Use unique_ptr in the future.
get_X11_property(Display * disp,Window win,Atom xa_prop_type,const char * prop_name)1364 static char *get_X11_property (Display *disp, Window win,
1365                             Atom xa_prop_type, const char *prop_name) {
1366     Atom xa_prop_name;
1367     Atom xa_ret_type;
1368     int ret_format;
1369     unsigned long ret_nitems;
1370     unsigned long ret_bytes_after;
1371     unsigned char *ret_prop;
1372 
1373     xa_prop_name = XInternAtom(disp, prop_name, False);
1374 
1375     // For XGetWindowProperty source see
1376     // https://github.com/mirror/libX11/blob/master/src/GetProp.c#L107
1377     // it is quite tricky. Some notes.
1378     // + Results are already NULL terminated.
1379     // + 32 as a ret_format means sizeof(long) in the API...
1380     // + but as xlib does the null termination we can just ignore the sizes.
1381     if (XGetWindowProperty(disp, win, xa_prop_name, 0, 1024, False,
1382                            xa_prop_type, &xa_ret_type, &ret_format,
1383                            &ret_nitems, &ret_bytes_after, &ret_prop) != Success)
1384         return NULL;
1385 
1386     if (xa_ret_type != xa_prop_type) {
1387        XFree(ret_prop);
1388        return NULL;
1389     }
1390     return (char*)ret_prop;
1391 }
1392 #endif
1393 
1394 // Determine if a transparent toolbar is possible under linux with opengl
isTransparentToolbarInOpenGLOK(void)1395 static bool isTransparentToolbarInOpenGLOK(void) {
1396 #ifdef __WXOSX__
1397     return true;
1398 #else
1399     bool status = false;
1400 #ifndef __WXQT__
1401 #ifdef OCPN_HAVE_X11
1402     if(!g_bdisable_opengl) {
1403         Display *disp = XOpenDisplay(NULL);
1404         Window *sup_window;
1405         if ((sup_window = (Window *)get_X11_property(disp, DefaultRootWindow(disp),
1406                                                  XA_WINDOW, "_NET_SUPPORTING_WM_CHECK")) ||
1407             (sup_window = (Window *)get_X11_property(disp, DefaultRootWindow(disp),
1408                                                  XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK"))) {
1409             /* WM_NAME */
1410             char *wm_name;
1411             if ((wm_name = get_X11_property(disp, *sup_window,
1412                                         XInternAtom(disp, "UTF8_STRING", False), "_NET_WM_NAME")) ||
1413                 (wm_name = get_X11_property(disp, *sup_window,
1414                                         XA_STRING, "_NET_WM_NAME"))) {
1415                 // we know it works in xfce4, add other checks as we can validate them
1416                 if(strstr(wm_name, "Xfwm4") || strstr(wm_name, "Compiz"))
1417                     status = true;
1418 
1419                 XFree(wm_name);
1420             }
1421             XFree(sup_window);
1422         }
1423         XCloseDisplay(disp);
1424     }
1425 #endif
1426 #endif
1427     return status;
1428 #endif
1429 }
1430 
1431 static wxStopWatch init_sw;
1432 class ParseENCWorkerThread : public wxThread
1433 {
1434 public:
ParseENCWorkerThread(wxString filename,Extent & ext,int scale)1435     ParseENCWorkerThread(wxString filename, Extent &ext, int scale)
1436         : wxThread(wxTHREAD_JOINABLE)
1437         {
1438             m_filename = filename;
1439             m_ext = ext;
1440             m_scale = scale;
1441             Create();
1442         }
1443 
Entry()1444     void *Entry() {
1445 //         ChartBase *pchart = ChartData->OpenChartFromDB(m_filename, FULL_INIT);
1446 //         ChartData->DeleteCacheChart(pchart);
1447         s57chart *newChart = new s57chart;
1448 
1449         newChart->SetNativeScale(m_scale);
1450         newChart->SetFullExtent(m_ext);
1451 
1452         newChart->FindOrCreateSenc(m_filename);
1453         delete newChart;
1454         return 0;
1455     }
1456 
1457     wxString m_filename;
1458     Extent m_ext;
1459     int m_scale;
1460 };
1461 
1462 // begin duplicated code
chart_dist(int index)1463 static double chart_dist(int index)
1464 {
1465     double d;
1466     float  clon;
1467     float  clat;
1468     const ChartTableEntry &cte = ChartData->GetChartTableEntry(index);
1469     // if the chart contains ownship position set the distance to 0
1470     if (cte.GetBBox().Contains(gLat, gLon))
1471         d = 0.;
1472     else {
1473         // find the nearest edge
1474         double t;
1475         clon = (cte.GetLonMax() + cte.GetLonMin())/2;
1476         d = DistGreatCircle(cte.GetLatMax(), clon, gLat, gLon);
1477         t = DistGreatCircle(cte.GetLatMin(), clon, gLat, gLon);
1478         if (t < d)
1479             d = t;
1480 
1481         clat = (cte.GetLatMax() + cte.GetLatMin())/2;
1482         t = DistGreatCircle(clat, cte.GetLonMin(), gLat, gLon);
1483         if (t < d)
1484             d = t;
1485         t = DistGreatCircle(clat, cte.GetLonMax(), gLat, gLon);
1486         if (t < d)
1487             d = t;
1488     }
1489     return d;
1490 }
1491 
1492 WX_DEFINE_SORTED_ARRAY_INT(int, MySortedArrayInt);
CompareInts(int n1,int n2)1493 static int CompareInts(int n1, int n2)
1494 {
1495     double d1 = chart_dist(n1);
1496     double d2 = chart_dist(n2);
1497     return (int)(d1 - d2);
1498 }
1499 
1500 class compress_target
1501 {
1502 public:
1503     wxString chart_path;
1504     double distance;
1505 };
1506 
1507 WX_DECLARE_OBJARRAY(compress_target, ArrayOfCompressTargets);
1508 WX_DEFINE_OBJARRAY(ArrayOfCompressTargets);
1509 
1510 #include <wx/arrimpl.cpp>
1511 // end duplicated code
1512 
ParseAllENC(wxWindow * parent)1513 void ParseAllENC(wxWindow* parent)
1514 {
1515     MySortedArrayInt idx_sorted_by_distance(CompareInts);
1516 
1517     // Building the cache may take a long time....
1518     // Be a little smarter.
1519     // Build a sorted array of chart database indices, sorted on distance from the ownship currently.
1520     // This way, a user may build a few chart SENCs for immediate use, then "skip" or "cancel"out on the rest until later.
1521     int count = 0;
1522     for(int i = 0; i<ChartData->GetChartTableEntries(); i++) {
1523         /* skip if not ENC */
1524         const ChartTableEntry &cte = ChartData->GetChartTableEntry(i);
1525         if(CHART_TYPE_S57 != cte.GetChartType())
1526             continue;
1527 
1528         idx_sorted_by_distance.Add(i);
1529         count++;
1530     }
1531 
1532 
1533     if(count == 0)
1534         return;
1535 
1536     wxLogMessage(wxString::Format(_T("ParseAllENC() count = %d"), count ));
1537 
1538     //  Build another array of sorted compression targets.
1539     //  We need to do this, as the chart table will not be invariant
1540     //  after the compression threads start, so our index array will be invalid.
1541 
1542     ArrayOfCompressTargets ct_array;
1543     for(unsigned int j = 0; j<idx_sorted_by_distance.GetCount(); j++) {
1544 
1545         int i = idx_sorted_by_distance[j];
1546 
1547         const ChartTableEntry &cte = ChartData->GetChartTableEntry(i);
1548         double distance = chart_dist(i);
1549 
1550         wxString filename(cte.GetpFullPath(), wxConvUTF8);
1551 
1552         compress_target *pct = new compress_target;
1553         pct->distance = distance;
1554         pct->chart_path = filename;
1555 
1556         ct_array.push_back(pct);
1557     }
1558 
1559     int thread_count = 0;
1560     ParseENCWorkerThread **workers = NULL;
1561 
1562     extern int              g_nCPUCount;
1563     if(g_nCPUCount > 0)
1564         thread_count = g_nCPUCount;
1565     else
1566         thread_count = wxThread::GetCPUCount();
1567 
1568     if (thread_count < 1) {
1569         // obviously there's a least one CPU!
1570         thread_count = 1;
1571     }
1572 
1573     //thread_count = 1; // for now because there is a problem with more than 1
1574 
1575     #if 0
1576     workers = new ParseENCWorkerThread*[thread_count];
1577     for(int t = 0; t < thread_count; t++)
1578         workers[t] = NULL;
1579     #endif
1580 
1581     wxGenericProgressDialog *prog = nullptr;
1582     wxSize csz = GetOCPNCanvasWindow()->GetClientSize();
1583 
1584     if(1){
1585         long style =  wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_SKIP ;
1586 
1587         prog = new wxGenericProgressDialog();
1588         wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
1589         prog->SetFont( *qFont );
1590 
1591         prog->Create(_("OpenCPN ENC Prepare"), _T("Longgggggggggggggggggggggggggggg"), count+1, parent, style );
1592 
1593         // make wider to show long filenames
1594         //wxSize sz = prog->GetSize();
1595         //sz.x = csz.x * 8 / 10;
1596         //prog->SetSize( sz );
1597 
1598         DimeControl( prog );
1599         prog->Show();
1600     }
1601 
1602         // parse targets
1603         bool skip = false;
1604         count = 0;
1605         for(unsigned int j = 0; j<ct_array.size(); j++) {
1606             wxString filename = ct_array[j].chart_path;
1607             double distance = ct_array[j].distance;
1608             int index = ChartData->FinddbIndex(filename);
1609             if (index < 0)
1610                 continue;
1611             const ChartTableEntry &cte = ChartData->GetChartTableEntry(index);
1612             Extent ext;
1613             ext.NLAT = cte.GetLatMax();
1614             ext.SLAT = cte.GetLatMin();
1615             ext.WLON = cte.GetLonMin();
1616             ext.ELON = cte.GetLonMax();
1617 
1618             int scale = cte.GetScale();
1619 
1620             wxString msg;
1621             msg.Printf( _("Distance from Ownship:  %4.0f NMi"), distance);
1622 
1623             count++;
1624             if(wxThread::IsMain()){
1625                 if(prog){
1626                     wxSize sz = prog->GetSize();
1627                     if(sz.x > 600){
1628                         msg += _T("   Chart:");
1629                         msg += filename;
1630                     }
1631                     prog->Update(count, msg, &skip );
1632 #ifndef __WXMSW__
1633                     prog->Raise();
1634 #endif
1635                 }
1636                 if(skip)
1637                     break;
1638             }
1639 
1640             #if 1
1641             if(ps52plib){
1642                 s57chart *newChart = new s57chart;
1643 
1644                 newChart->SetNativeScale(scale);
1645                 newChart->SetFullExtent(ext);
1646                 newChart->DisableBackgroundSENC();
1647 
1648                 newChart->FindOrCreateSenc(filename, false);    // no progress dialog required
1649                 delete newChart;
1650 
1651                 if(wxThread::IsMain()){
1652                     msg.Printf( _("ENC Completed.") );
1653                     if(prog){
1654                         prog->Update(count, msg, &skip );
1655 #ifndef __WXMSW__
1656                         prog->Raise();
1657 #endif
1658                     }
1659                     if(skip)
1660                         break;
1661                 }
1662 
1663 
1664             }
1665 
1666 
1667             #else
1668             for(int t = 0;; t=(t+1)%thread_count) {
1669                 if(!workers[t]) {
1670                     workers[t] = new ParseENCWorkerThread(filename);
1671                     workers[t]->Run();
1672                     break;
1673                 }
1674 
1675                 if(!workers[t]->IsAlive()) {
1676                     workers[t]->Wait();
1677                     delete workers[t];
1678                     workers[t] = NULL;
1679                 }
1680                 if(t == 0) {
1681                     //                ::wxYield();                // allow ChartCanvas main message loop to run
1682                     wxThread::Sleep(1); /* wait for a worker to finish */
1683                 }
1684             }
1685             #endif
1686 
1687 #if defined(__WXMSW__) || defined (__WXOSX__)
1688             ::wxSafeYield();
1689 #endif
1690         }
1691 
1692         #if 0
1693         /* wait for workers to finish, and clean up after then */
1694         for(int t = 0; t<thread_count; t++) {
1695                         if(workers[t]) {
1696                             workers[t]->Wait();
1697                             delete workers[t];
1698                         }
1699         }
1700         delete [] workers;
1701         #endif
1702 
1703         delete prog;
1704 }
1705 
1706 
OnInit()1707 bool MyApp::OnInit()
1708 {
1709     if( !wxApp::OnInit() ) return false;
1710 #ifdef __OCPN__ANDROID__
1711     androidEnableBackButton( false );
1712 #endif
1713 
1714     GpxDocument::SeedRandom();
1715     safe_mode::set_mode(false);
1716 
1717     last_own_ship_sog_cog_calc_ts = wxInvalidDateTime;
1718 
1719 #if defined(__WXGTK__)  && defined(ocpnUSE_GLES) && defined(__ARM_ARCH)
1720     // There is a race condition between cairo which is used for text rendering
1721     // by gtk and EGL which without the below code causes a bus error and the
1722     // program aborts before startup
1723     // this hack forces cairo to load right now by rendering some text
1724 
1725     wxBitmap bmp( 10, 10, -1 );
1726     wxMemoryDC dc;
1727     dc.SelectObject( bmp );
1728     dc.DrawText( _T("X"), 0, 0 );
1729 #endif
1730     m_checker = 0;
1731 
1732     // Instantiate the global OCPNPlatform class
1733     g_Platform = new OCPNPlatform;
1734 
1735 
1736 #ifndef __OCPN__ANDROID__
1737     //  On Windows
1738     //  We allow only one instance unless the portable option is used
1739     if(!g_bportable) {
1740         wxChar separator = wxFileName::GetPathSeparator();
1741         wxString service_name = g_Platform->GetPrivateDataDir() + separator + _T("opencpn-ipc");
1742 
1743         m_checker = new wxSingleInstanceChecker(_T("_OpenCPN_SILock"), g_Platform->GetPrivateDataDir());
1744         if ( !m_checker->IsAnotherRunning() )
1745         {
1746             stServer *m_server = new stServer;
1747             if ( !m_server->Create(service_name) ) {
1748 		wxLogDebug(wxT("Failed to create an IPC service."));
1749             }
1750         }
1751         else {
1752     	    wxLogNull logNull;
1753     	    stClient* client = new stClient;
1754     	    // ignored under DDE, host name in TCP/IP based classes
1755     	    wxString hostName = wxT("localhost");
1756     	    // Create the connection service, topic
1757     	    wxConnectionBase* connection = client->MakeConnection(hostName, service_name, _T("OpenCPN"));
1758     	    if (connection) {
1759     	        // Ask the other instance to open a file or raise itself
1760     	        if ( !g_params.empty() ) {
1761                     for ( size_t n = 0; n < g_params.size(); n++ )
1762                     {
1763                         wxString path = g_params[n];
1764                         if( ::wxFileExists( path ) )
1765                         {
1766                             connection->Execute(path);
1767                         }
1768                     }
1769                 }
1770                 connection->Execute(wxT(""));
1771     	        connection->Disconnect();
1772     	        delete connection;
1773             }
1774             else {
1775                 //  If we get here, it means that the wxWidgets single-instance-detect logic found the lock file,
1776                 //  And so thinks another instance is running. But that instance is not reachable, for some reason.
1777                 //  So, the safe thing to do is delete the lockfile, and exit.  Next start will proceed normally.
1778                 //  This may leave a zombie OpenCPN, but at least O starts.
1779                 wxString lockFile = wxString(g_Platform->GetPrivateDataDir() + separator + _T("_OpenCPN_SILock"));
1780                 if(wxFileExists(lockFile))
1781                     wxRemoveFile(lockFile);
1782 
1783                 wxMessageBox(_("Sorry, an existing instance of OpenCPN may be too busy too respond.\nPlease retry."),
1784                     wxT("OpenCPN"), wxICON_INFORMATION|wxOK);
1785             }
1786             delete client;
1787             return false;               // exit quietly
1788         }
1789     }
1790 #endif  // __OCPN__ANDROID__
1791 
1792     if (getenv("OPENCPN_FATAL_ERROR") != 0) {
1793         wxLogFatalError(getenv("OPENCPN_FATAL_ERROR"));
1794     }
1795 
1796     // Check if last run failed, set up safe_mode.
1797     if (!safe_mode::get_mode()) {
1798         safe_mode::check_last_start();
1799     }
1800 
1801     //  Perform first stage initialization
1802     OCPNPlatform::Initialize_1( );
1803 
1804 #if wxCHECK_VERSION(3,0,0)
1805     // Set the name of the app as displayed to the user.
1806     // This is necessary at least on OS X, for the capitalisation to be correct in the system menus.
1807     MyApp::SetAppDisplayName("OpenCPN");
1808 #endif
1809 
1810 
1811     //  Seed the random number generator
1812     wxDateTime x = wxDateTime::UNow();
1813     long seed = x.GetMillisecond();
1814     seed *= x.GetTicks();
1815     srand(seed);
1816 
1817 
1818 //Fulup: force floating point to use dot as separation.
1819 // This needs to be set early to catch numerics in config file.
1820     setlocale( LC_NUMERIC, "C" );
1821 
1822 
1823 
1824     g_start_time = wxDateTime::Now();
1825 
1826     g_loglast_time = g_start_time;
1827     g_loglast_time.MakeGMT();
1828     g_loglast_time.Subtract( wxTimeSpan( 0, 29, 0, 0 ) ); // give 1 minute for GPS to get a fix
1829 
1830     AnchorPointMinDist = 5.0;
1831 
1832 
1833 //      Init the private memory manager
1834     malloc_max = 0;
1835 
1836     //      Record initial memory status
1837     GetMemoryStatus( &g_mem_total, &g_mem_initial );
1838 
1839 
1840 // Set up default FONT encoding, which should have been done by wxWidgets some time before this......
1841     wxFont temp_font( 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, FALSE, wxString( _T("") ),
1842             wxFONTENCODING_SYSTEM );
1843     temp_font.SetDefaultEncoding( wxFONTENCODING_SYSTEM );
1844 
1845 
1846     //      Establish Log File location
1847     if(!g_Platform->InitializeLogFile())
1848         return false;
1849 
1850 
1851 #ifdef __WXMSW__
1852 
1853     //  Un-comment the following to establish a separate console window as a target for printf() in Windows
1854     //     RedirectIOToConsole();
1855 
1856 #endif
1857 
1858 //      Send init message
1859     wxLogMessage( _T("\n\n________\n") );
1860 
1861 
1862     g_vs = wxString(VERSION_FULL).Trim(true).Trim(false);
1863     wxDateTime now = wxDateTime::Now();
1864     LOG_INFO("------- OpenCPN version %s restarted at %s -------\n",
1865              VERSION_FULL, now.FormatISODate().mb_str().data());
1866     wxLogLevel level = wxLog::GetLogLevel();
1867     LOG_INFO("Using loglevel %s", OcpnLog::level2str(level).c_str());
1868 
1869     wxString wxver(wxVERSION_STRING);
1870     wxver.Prepend( _T("wxWidgets version: ") );
1871 
1872     wxPlatformInfo platforminfo = wxPlatformInfo::Get();
1873 
1874     wxString os_name;
1875 #ifndef __OCPN__ANDROID__
1876     os_name = platforminfo.GetOperatingSystemIdName();
1877 #else
1878     os_name = platforminfo.GetOperatingSystemFamilyName();
1879 #endif
1880 
1881     wxString platform = os_name + _T(" ") +
1882     platforminfo.GetArchName()+ _T(" ") +
1883     platforminfo.GetPortIdName();
1884 
1885     wxLogMessage( wxver + _T(" ") + platform );
1886 
1887     ::wxGetOsVersion(&osMajor, &osMinor);
1888     wxString osVersionMsg;
1889     osVersionMsg.Printf(_T("OS Version reports as:  %d.%d"), osMajor, osMinor);
1890     wxLogMessage(osVersionMsg);
1891 
1892     wxLogMessage( _T("MemoryStatus:  mem_total: %d mb,  mem_initial: %d mb"), g_mem_total / 1024,
1893             g_mem_initial / 1024 );
1894 
1895     //    Initialize embedded PNG icon graphics
1896     ::wxInitAllImageHandlers();
1897 
1898 
1899     wxString imsg = _T("SData_Locn is ");
1900     imsg += g_Platform->GetSharedDataDir();
1901     wxLogMessage( imsg );
1902 
1903 #ifdef __WXQT__
1904     //  Now we can configure the Qt StyleSheets, if present
1905     prepareAndroidStyleSheets();
1906 #endif
1907 
1908     //      Create some static strings
1909     pInit_Chart_Dir = new wxString();
1910 
1911     //  Establish an empty ChartCroupArray
1912     g_pGroupArray = new ChartGroupArray;
1913 
1914 
1915     imsg = _T("PrivateDataDir is ");
1916     imsg += g_Platform->GetPrivateDataDir();
1917     wxLogMessage( imsg );
1918 
1919 
1920 //      Create an array string to hold repeating messages, so they don't
1921 //      overwhelm the log
1922     pMessageOnceArray = new wxArrayString;
1923 
1924 //      Init the Route Manager
1925     g_pRouteMan = new Routeman( this );
1926 
1927     //      Init the Selectable Route Items List
1928     pSelect = new Select();
1929     pSelect->SetSelectPixelRadius( 12 );
1930 
1931     //      Init the Selectable Tide/Current Items List
1932     pSelectTC = new Select();
1933     //  Increase the select radius for tide/current stations
1934     pSelectTC->SetSelectPixelRadius( 25 );
1935 
1936     //      Init the Selectable AIS Target List
1937     pSelectAIS = new Select();
1938     pSelectAIS->SetSelectPixelRadius( 12 );
1939 
1940 //      Initially AIS display is always on
1941     g_bShowAIS = true;
1942     g_pais_query_dialog_active = NULL;
1943 
1944 //      Who am I?
1945     phost_name = new wxString( ::wxGetHostName() );
1946 
1947 //      Initialize connection parameters array
1948     g_pConnectionParams = new wxArrayOfConnPrm();
1949 
1950 //      Initialize some lists
1951     //    Layers
1952     pLayerList = new LayerList;
1953     //  Routes
1954     pRouteList = new RouteList;
1955     // Tracks
1956     pTrackList = new TrackList;
1957 
1958 
1959 //      (Optionally) Capture the user and file(effective) ids
1960 //  Some build environments may need root privileges for hardware
1961 //  port I/O, as in the NMEA data input class.  Set that up here.
1962 
1963 #ifndef __WXMSW__
1964 #ifdef PROBE_PORTS__WITH_HELPER
1965     user_user_id = getuid ();
1966     file_user_id = geteuid ();
1967 #endif
1968 #endif
1969 
1970 
1971     bool b_initial_load = false;
1972 
1973     wxFileName config_test_file_name( g_Platform->GetConfigFileName() );
1974     if( config_test_file_name.FileExists() ) wxLogMessage(
1975         _T("Using existing Config_File: ") + g_Platform->GetConfigFileName() );
1976     else {
1977         {
1978             wxLogMessage( _T("Creating new Config_File: ") + g_Platform->GetConfigFileName() );
1979 
1980             b_initial_load = true;
1981 
1982             if( true != config_test_file_name.DirExists( config_test_file_name.GetPath() ) )
1983                 if( !config_test_file_name.Mkdir(config_test_file_name.GetPath() ) )
1984                     wxLogMessage( _T("Cannot create config file directory for ") + g_Platform->GetConfigFileName() );
1985         }
1986     }
1987 
1988     //      Open/Create the Config Object
1989     pConfig = g_Platform->GetConfigObject();
1990     pConfig->LoadMyConfig();
1991 
1992     //  Override for some safe and nice default values if the config file was created from scratch
1993     if(b_initial_load)
1994         g_Platform->SetDefaultOptions();
1995 
1996     g_Platform->SetUpgradeOptions(g_vs, g_config_version_string);
1997 
1998     g_Platform->applyExpertMode(g_bUIexpert);
1999 
2000     // Now initialize UI Style.
2001     g_StyleManager = new ocpnStyle::StyleManager();
2002 
2003 //     if(g_useMUI)
2004 //         g_uiStyle = _T("MUI_flat");
2005 
2006     g_StyleManager->SetStyle( _T("MUI_flat") );
2007     if( !g_StyleManager->IsOK() ) {
2008         wxString msg = _("Failed to initialize the user interface. ");
2009         msg << _("OpenCPN cannot start. ");
2010         msg << _("The necessary configuration files were not found. ");
2011         msg << _("See the log file at ") << g_Platform->GetLogFileName() << _(" for details.") << _T("\n\n");
2012         msg << g_Platform->GetSharedDataDir();
2013 
2014         wxMessageDialog w( NULL, msg, _("Failed to initialize the user interface. "),
2015                            wxCANCEL | wxICON_ERROR );
2016         w.ShowModal();
2017         exit( EXIT_FAILURE );
2018     }
2019 
2020     if(g_useMUI){
2021         ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
2022         style->chartStatusWindowTransparent = true;
2023     }
2024 
2025 
2026     //      Init the WayPoint Manager
2027     pWayPointMan = NULL;
2028 
2029     g_display_size_mm = wxMax(100, g_Platform->GetDisplaySizeMM());
2030     wxString msg;
2031     msg.Printf(_T("Detected display size (horizontal): %d mm"), (int) g_display_size_mm);
2032     wxLogMessage(msg);
2033 
2034     // User override....
2035     if((g_config_display_size_mm > 0) &&(g_config_display_size_manual)){
2036         g_display_size_mm = g_config_display_size_mm;
2037         wxString msg;
2038         msg.Printf(_T("Display size (horizontal) config override: %d mm"), (int) g_display_size_mm);
2039         wxLogMessage(msg);
2040         g_Platform->SetDisplaySizeMM(g_display_size_mm);
2041     }
2042 
2043     g_display_size_mm = wxMax(80, g_display_size_mm);
2044 
2045     if(g_btouch){
2046         int SelectPixelRadius = 50;
2047 
2048         pSelect->SetSelectPixelRadius(SelectPixelRadius);
2049         pSelectTC->SetSelectPixelRadius( wxMax(25, SelectPixelRadius) );
2050         pSelectAIS->SetSelectPixelRadius(SelectPixelRadius);
2051     }
2052 
2053 
2054     //        Is this the first run after a clean install?
2055     if( !n_NavMessageShown ) g_bFirstRun = true;
2056 
2057     //  Now we can set the locale
2058     //    using wxWidgets/gettext methodology....
2059 
2060 
2061 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3,0,0)
2062 
2063     //  Where are the opencpn.mo files?
2064     g_Platform->SetLocaleSearchPrefixes();
2065 
2066     wxString def_lang_canonical = g_Platform->GetDefaultSystemLocale();
2067 
2068     imsg = _T("System default Language:  ") + def_lang_canonical;
2069     wxLogMessage( imsg );
2070 
2071     wxString cflmsg = _T("Config file language:  ") + g_locale;
2072     wxLogMessage( cflmsg );
2073 
2074     //  Make any adjustments necessary
2075     g_locale = g_Platform->GetAdjustedAppLocale();
2076     cflmsg = _T("Adjusted App language:  ") + g_locale;
2077     wxLogMessage( cflmsg );
2078 
2079 
2080     // Set the desired locale
2081     g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
2082 
2083     imsg = _T("Opencpn language set to:  ");
2084     imsg += g_locale;
2085     wxLogMessage( imsg );
2086 
2087     //  French language locale is assumed to include the AZERTY keyboard
2088     //  This applies to either the system language, or to OpenCPN language selection
2089     if( g_locale == _T("fr_FR") ) g_b_assume_azerty = true;
2090 #else
2091     wxLogMessage( _T("wxLocale support not available") );
2092 #endif
2093 
2094     // Instantiate and initialize the Config Manager
2095     ConfigMgr::Get();
2096 
2097     // Is this an upgrade?
2098     wxString vs =
2099         wxString("Version ") +  VERSION_FULL + " Build " + VERSION_DATE;
2100     g_bUpgradeInProcess = (vs != g_config_version_string);
2101 
2102     //  log deferred log restart message, if it exists.
2103     if( !g_Platform->GetLargeLogMessage().IsEmpty() )
2104         wxLogMessage( g_Platform->GetLargeLogMessage() );
2105 
2106     //  Validate OpenGL functionality, if selected
2107 #ifdef ocpnUSE_GL
2108 
2109 #ifdef __WXMSW__
2110 #if !wxCHECK_VERSION(2, 9, 0)           // The OpenGL test app only runs on wx 2.8, unavailable on wx3.x
2111 
2112     if( /*g_bopengl &&*/ !g_bdisable_opengl ) {
2113         wxFileName fn(g_Platform->GetExePath());
2114         bool b_test_result = TestGLCanvas(fn.GetPathWithSep() );
2115 
2116         if( !b_test_result )
2117             wxLogMessage( _T("OpenGL disabled due to test app failure.") );
2118 
2119         g_bdisable_opengl = !b_test_result;
2120     }
2121 #endif
2122 #endif
2123 
2124 #else
2125     g_bdisable_opengl = true;;
2126 #endif
2127 
2128     if(g_bdisable_opengl)
2129         g_bopengl = false;
2130 
2131 #if defined(__UNIX__) && !defined(__OCPN__ANDROID__) && !defined(__WXOSX__)
2132     if(g_bSoftwareGL)
2133         setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
2134 #endif
2135 
2136     g_bTransparentToolbarInOpenGLOK = isTransparentToolbarInOpenGLOK();
2137 
2138     // On Windows platforms, establish a default cache managment policy
2139     // as allowing OpenCPN a percentage of available physical memory,
2140     // not to exceed 1 GB
2141     // Note that this logic implies that Windows platforms always use
2142     // the memCacheLimit policy, and never use the fallback nCacheLimit policy
2143 #ifdef __WXMSW__
2144     if( 0 == g_memCacheLimit )
2145         g_memCacheLimit = (int) ( g_mem_total * 0.5 );
2146     g_memCacheLimit = wxMin(g_memCacheLimit, 1024 * 1024); // math in kBytes, Max is 1 GB
2147 #else
2148     if( 0 ==  g_nCacheLimit && 0 == g_memCacheLimit ){
2149         g_memCacheLimit = (int) ( (g_mem_total - g_mem_initial) * 0.5 );
2150         g_memCacheLimit = wxMin(g_memCacheLimit, 1024 * 1024); // Max is 1 GB if unspecified
2151 #ifdef __WXMAC__
2152         if( g_mem_total > 8192 * 1024) {
2153             g_memCacheLimit = 1024 * 1024;
2154         } else if( g_mem_total > 4096 * 1024) {
2155             g_memCacheLimit = 600 * 1024;
2156         } else {
2157             g_memCacheLimit = 400 * 1024;
2158         }
2159 #endif
2160     }
2161 #endif
2162     if( 0 ==  g_nCacheLimit)
2163         g_nCacheLimit = CACHE_N_LIMIT_DEFAULT;
2164 #ifdef __OCPN__ANDROID__
2165     g_memCacheLimit = 100 * 1024;
2166 #endif
2167 
2168 //      Establish location and name of chart database
2169     ChartListFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(), "chartlist.dat", "CHRTLIST.DAT");
2170 
2171 //      Establish location and name of AIS MMSI -> Target Name mapping
2172     AISTargetNameFileName = newPrivateFileName(g_Platform->GetPrivateDataDir(), "mmsitoname.csv", "MMSINAME.CSV");
2173 
2174 //      Establish guessed location of chart tree
2175     if( pInit_Chart_Dir->IsEmpty() ) {
2176         wxStandardPaths& std_path = g_Platform->GetStdPaths();
2177 
2178         if( !g_bportable )
2179 #ifndef __OCPN__ANDROID__
2180         pInit_Chart_Dir->Append( std_path.GetDocumentsDir() );
2181 #else
2182         pInit_Chart_Dir->Append( androidGetExtStorageDir() );
2183 #endif
2184     }
2185 
2186 //      Establish the GSHHS Dataset location
2187     gDefaultWorldMapLocation = "gshhs";
2188     gDefaultWorldMapLocation.Prepend( g_Platform->GetSharedDataDir() );
2189     gDefaultWorldMapLocation.Append( wxFileName::GetPathSeparator() );
2190     if( gWorldMapLocation == wxEmptyString ) {
2191         gWorldMapLocation = gDefaultWorldMapLocation;
2192     }
2193 
2194     //  Check the global Tide/Current data source array
2195     //  If empty, preset one default (US) Ascii data source
2196     wxString default_tcdata =  ( g_Platform->GetSharedDataDir() + _T("tcdata") +
2197              wxFileName::GetPathSeparator() + _T("HARMONIC.IDX"));
2198 
2199     if(!TideCurrentDataSet.GetCount()) {
2200         TideCurrentDataSet.Add(g_Platform->NormalizePath(default_tcdata) );
2201     }
2202     else {
2203         wxString first_tide = TideCurrentDataSet[0];
2204         wxFileName ft(first_tide);
2205         if(!ft.FileExists()){
2206             TideCurrentDataSet.RemoveAt(0);
2207             TideCurrentDataSet.Insert(g_Platform->NormalizePath(default_tcdata), 0 );
2208         }
2209     }
2210 
2211 
2212     //  Check the global AIS alarm sound file
2213     //  If empty, preset default
2214     if(g_sAIS_Alert_Sound_File.IsEmpty()) {
2215         wxString default_sound =  ( g_Platform->GetSharedDataDir() + _T("sounds") +
2216         wxFileName::GetPathSeparator() +
2217         _T("2bells.wav"));
2218         g_sAIS_Alert_Sound_File = g_Platform->NormalizePath(default_sound);
2219     }
2220 
2221     gpIDX = NULL;
2222     gpIDXn = 0;
2223 
2224     g_Platform->Initialize_2();
2225 
2226 //  Set up the frame initial visual parameters
2227 //      Default size, resized later
2228     wxSize new_frame_size( -1, -1 );
2229     int cx, cy, cw, ch;
2230     ::wxClientDisplayRect( &cx, &cy, &cw, &ch );
2231 
2232     InitializeUserColors();
2233 
2234     if( ( g_nframewin_x > 100 ) && ( g_nframewin_y > 100 ) && ( g_nframewin_x <= cw )
2235             && ( g_nframewin_y <= ch ) ) new_frame_size.Set( g_nframewin_x, g_nframewin_y );
2236     else
2237         new_frame_size.Set( cw * 7 / 10, ch * 7 / 10 );
2238 
2239     //  Try to detect any change in physical screen configuration
2240     //  This can happen when drivers are changed, for instance....
2241     //  and can confuse the WUI layout perspective stored in the config file.
2242     //  If detected, force a nominal window size and position....
2243     if( ( g_lastClientRectx != cx ) || ( g_lastClientRecty != cy ) || ( g_lastClientRectw != cw )
2244             || ( g_lastClientRecth != ch ) ) {
2245         new_frame_size.Set( cw * 7 / 10, ch * 7 / 10 );
2246         g_bframemax = false;
2247     }
2248 
2249     g_lastClientRectx = cx;
2250     g_lastClientRecty = cy;
2251     g_lastClientRectw = cw;
2252     g_lastClientRecth = ch;
2253 
2254     //  Validate config file position
2255     wxPoint position( 0, 0 );
2256     wxSize dsize = wxGetDisplaySize();
2257 
2258 #ifdef __WXMAC__
2259     g_nframewin_posy = wxMax(g_nframewin_posy, 22);
2260 #endif
2261 
2262     if( ( g_nframewin_posx < dsize.x ) && ( g_nframewin_posy < dsize.y ) ) position = wxPoint(
2263             g_nframewin_posx, g_nframewin_posy );
2264 
2265 #ifdef __WXMSW__
2266     //  Support MultiMonitor setups which an allow negative window positions.
2267     RECT frame_rect;
2268     frame_rect.left = position.x;
2269     frame_rect.top = position.y;
2270     frame_rect.right = position.x + new_frame_size.x;
2271     frame_rect.bottom = position.y + new_frame_size.y;
2272 
2273     //  If the requested frame window does not intersect any installed monitor,
2274     //  then default to simple primary monitor positioning.
2275     if( NULL == MonitorFromRect( &frame_rect, MONITOR_DEFAULTTONULL ) ) position = wxPoint( 10,
2276             10 );
2277 #endif
2278 
2279 #ifdef __OCPN__ANDROID__
2280     wxSize asz = getAndroidDisplayDimensions();
2281     ch = asz.y;
2282     cw = asz.x;
2283 //    qDebug() << cw << ch;
2284 
2285     if((cw > 200) && (ch > 200) )
2286         new_frame_size.Set( cw, ch );
2287     else
2288         new_frame_size.Set( 800, 400 );
2289 #endif
2290 
2291     //  For Windows and GTK, provide the expected application Minimize/Close bar
2292     long app_style = wxDEFAULT_FRAME_STYLE;
2293     app_style |= wxWANTS_CHARS;
2294 
2295 // Create the main frame window
2296     wxString myframe_window_title = wxString::Format(wxT("OpenCPN %s"),
2297             VERSION_FULL); //Gunther
2298 
2299     if( g_bportable ) {
2300         myframe_window_title += _(" -- [Portable(-p) executing from ");
2301         myframe_window_title += g_Platform->GetHomeDir();
2302         myframe_window_title += _T("]");
2303     }
2304 
2305     wxString fmsg;
2306     fmsg.Printf(_T("Creating MyFrame...size(%d, %d)  position(%d, %d)"), new_frame_size.x, new_frame_size.y, position.x, position.y);
2307     wxLogMessage(fmsg);
2308 
2309     gFrame = new MyFrame( NULL, myframe_window_title, position, new_frame_size, app_style ); //Gunther
2310 
2311     //  Do those platform specific initialization things that need gFrame
2312     g_Platform->Initialize_3();
2313 
2314 
2315 //  Initialize the Plugin Manager
2316     g_pi_manager = new PlugInManager( gFrame );
2317 
2318     //g_pauimgr = new wxAuiManager;
2319     g_pauimgr = new OCPN_AUIManager;
2320     g_pauidockart= new wxAuiDefaultDockArt;
2321     g_pauimgr->SetArtProvider(g_pauidockart);
2322     g_pauimgr->SetDockSizeConstraint(.9, .9);
2323 
2324     //g_pauimgr->SetFlags(g_pauimgr->GetFlags() | wxAUI_MGR_LIVE_RESIZE);
2325 
2326     g_grad_default = g_pauidockart->GetMetric(wxAUI_DOCKART_GRADIENT_TYPE);
2327     g_border_color_default = g_pauidockart->GetColour(wxAUI_DOCKART_BORDER_COLOUR );
2328     g_border_size_default = g_pauidockart->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE );
2329     g_sash_size_default = g_pauidockart->GetMetric(wxAUI_DOCKART_SASH_SIZE);
2330     g_caption_color_default = g_pauidockart->GetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR);
2331     g_sash_color_default = g_pauidockart->GetColour(wxAUI_DOCKART_SASH_COLOUR );
2332     g_background_color_default = g_pauidockart->GetColour(wxAUI_DOCKART_BACKGROUND_COLOUR );
2333 
2334 
2335 
2336 // tell wxAuiManager to manage the frame
2337     g_pauimgr->SetManagedWindow( gFrame );
2338 
2339     gFrame->CreateCanvasLayout();
2340 
2341     //gFrame->RequestNewMasterToolbar( true );
2342 
2343     gFrame->SetChartUpdatePeriod();             // Reasonable default
2344 
2345     gFrame->Enable();
2346 
2347     gFrame->GetPrimaryCanvas()->SetFocus();
2348 
2349     pthumbwin = new ThumbWin( gFrame->GetPrimaryCanvas() );
2350 
2351     gFrame->ApplyGlobalSettings( false );               // done once on init with resize
2352 
2353 
2354     gFrame->SetAllToolbarScale();
2355 
2356 
2357 // Show the frame
2358 
2359     gFrame->Show( TRUE );
2360 
2361     gFrame->SetAndApplyColorScheme( global_color_scheme );
2362 
2363     if( g_bframemax ) gFrame->Maximize( true );
2364 
2365     if( g_bresponsive  && ( gFrame->GetPrimaryCanvas()->GetPixPerMM() > 4.0))
2366         gFrame->Maximize( true );
2367 
2368     //  Yield to pick up the OnSize() calls that result from Maximize()
2369     Yield();
2370 
2371     //   Build the initial chart dir array
2372     ArrayOfCDI ChartDirArray;
2373     pConfig->LoadChartDirArray( ChartDirArray );
2374 
2375     //  Windows installer may have left hints regarding the initial chart dir selection
2376 #ifdef __WXMSW__
2377     if( g_bFirstRun && (ChartDirArray.GetCount() == 0) ) {
2378         int ndirs = 0;
2379 
2380         wxRegKey RegKey( wxString( _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN") ) );
2381         if( RegKey.Exists() ) {
2382             wxLogMessage( _("Retrieving initial Chart Directory set from Windows Registry") );
2383             wxString dirs;
2384             RegKey.QueryValue( wxString( _T("ChartDirs") ), dirs );
2385 
2386             wxStringTokenizer tkz( dirs, _T(";") );
2387             while( tkz.HasMoreTokens() ) {
2388                 wxString token = tkz.GetNextToken();
2389 
2390                 ChartDirInfo cdi;
2391                 cdi.fullpath = token.Trim();
2392                 cdi.magic_number = _T("");
2393 
2394                 ChartDirArray.Add( cdi );
2395                 ndirs++;
2396             }
2397 
2398         }
2399 
2400 		if (g_bportable)
2401 		{
2402 			ChartDirInfo cdi;
2403 			cdi.fullpath =_T("charts");
2404 			cdi.fullpath.Prepend(g_Platform->GetSharedDataDir());
2405 			cdi.magic_number = _T("");
2406 			ChartDirArray.Add(cdi);
2407 			ndirs++;
2408 		}
2409 
2410         if( ndirs ) pConfig->UpdateChartDirs( ChartDirArray );
2411 
2412     }
2413 #endif
2414 
2415 //    If the ChartDirArray is empty at this point, any existing chart database file must be declared invalid,
2416 //    So it is best to simply delete it if present.
2417 //    TODO  There is a possibility of recreating the dir list from the database itself......
2418 
2419     if( !ChartDirArray.GetCount() )
2420         if(::wxFileExists( ChartListFileName ))
2421             ::wxRemoveFile( ChartListFileName );
2422 
2423 //      Try to load the current chart list Data file
2424     ChartData = new ChartDB( );
2425     if (!ChartData->LoadBinary(ChartListFileName, ChartDirArray)) {
2426         g_bNeedDBUpdate = true;
2427     }
2428 
2429 
2430     //  Verify any saved chart database startup index
2431     if(g_restore_dbindex >= 0){
2432         if(ChartData->GetChartTableEntries() == 0)
2433             g_restore_dbindex = -1;
2434 
2435         else if(g_restore_dbindex > (ChartData->GetChartTableEntries()-1))
2436             g_restore_dbindex = 0;
2437     }
2438 
2439     //  Apply the inital Group Array structure to the chart data base
2440     ChartData->ApplyGroupArray( g_pGroupArray );
2441 
2442 //      All set to go.....
2443 
2444     // Process command line option to rebuild cache
2445 #ifdef ocpnUSE_GL
2446 extern ocpnGLOptions g_GLOptions;
2447 
2448     if(g_rebuild_gl_cache && g_bopengl &&
2449         g_GLOptions.m_bTextureCompression && g_GLOptions.m_bTextureCompressionCaching ) {
2450 
2451         gFrame->ReloadAllVP();                  //  Get a nice chart background loaded
2452 
2453         //      Turn off the toolbar as a clear signal that the system is busy right now.
2454         // Note: I commented this out because the toolbar never comes back for me
2455         // and is unusable until I restart opencpn without generating the cache
2456 //        if( g_MainToolbar )
2457 //            g_MainToolbar->Hide();
2458 
2459         if(g_glTextureManager)
2460             g_glTextureManager->BuildCompressedCache();
2461 
2462     }
2463 #endif
2464 
2465     if(g_parse_all_enc )
2466         ParseAllENC(gFrame);
2467 
2468 //      establish GPS timeout value as multiple of frame timer
2469 //      This will override any nonsense or unset value from the config file
2470     if( ( gps_watchdog_timeout_ticks > 60 ) || ( gps_watchdog_timeout_ticks <= 0 ) ) gps_watchdog_timeout_ticks =
2471             ( GPS_TIMEOUT_SECONDS * 1000 ) / TIMER_GFRAME_1;
2472 
2473     wxString dogmsg;
2474     dogmsg.Printf( _T("GPS Watchdog Timeout is: %d sec."), gps_watchdog_timeout_ticks );
2475     wxLogMessage( dogmsg );
2476 
2477     sat_watchdog_timeout_ticks = 12;
2478 
2479     gGPS_Watchdog = 2;
2480     gHDx_Watchdog = 2;
2481     gHDT_Watchdog = 2;
2482     gSAT_Watchdog = 2;
2483     gVAR_Watchdog = 2;
2484 
2485     //  Most likely installations have no ownship heading information
2486     g_bHDT_Rx = false;
2487     g_bVAR_Rx = false;
2488 
2489 //  Start up a new track if enabled in config file
2490     if( g_bTrackCarryOver )
2491         g_bDeferredStartTrack = true;
2492 
2493     pAnchorWatchPoint1 = NULL;
2494     pAnchorWatchPoint2 = NULL;
2495 
2496     Yield();
2497 
2498     gFrame->DoChartUpdate();
2499 
2500     FontMgr::Get().ScrubList(); // Clean the font list, removing nonsensical entries
2501 
2502 
2503     gFrame->ReloadAllVP();                  // once more, and good to go
2504 
2505 
2506     gFrame->Refresh( false );
2507     gFrame->Raise();
2508 
2509     gFrame->GetPrimaryCanvas()->Enable();
2510     gFrame->GetPrimaryCanvas()->SetFocus();
2511 
2512     //  This little hack fixes a problem seen with some UniChrome OpenGL drivers
2513     //  We need a deferred resize to get glDrawPixels() to work right.
2514     //  So we set a trigger to generate a resize after 5 seconds....
2515     //  See the "UniChrome" hack elsewhere
2516 #ifdef ocpnUSE_GL
2517     if ( !g_bdisable_opengl )
2518     {
2519         glChartCanvas *pgl = (glChartCanvas *) gFrame->GetPrimaryCanvas()->GetglCanvas();
2520         if( pgl && ( pgl->GetRendererString().Find( _T("UniChrome") ) != wxNOT_FOUND ) )
2521         {
2522             gFrame->m_defer_size = gFrame->GetSize();
2523             gFrame->SetSize( gFrame->m_defer_size.x - 10, gFrame->m_defer_size.y );
2524             g_pauimgr->Update();
2525             gFrame->m_bdefer_resize = true;
2526         }
2527     }
2528 #endif
2529 
2530     if ( g_start_fullscreen )
2531         gFrame->ToggleFullScreen();
2532 
2533 #ifdef __OCPN__ANDROID__
2534     //  We need a resize to pick up height adjustment after building android ActionBar
2535         gFrame->SetSize(getAndroidDisplayDimensions());
2536     androidSetFollowTool(gFrame->GetPrimaryCanvas()->m_bFollow? 1:0, true);
2537 #endif
2538 
2539     gFrame->Raise();
2540     gFrame->GetPrimaryCanvas()->Enable();
2541     gFrame->GetPrimaryCanvas()->SetFocus();
2542 
2543 #ifdef __WXQT__
2544     if(gFrame->GetPrimaryCanvas() && gFrame->GetPrimaryCanvas()->GetToolbar())
2545         gFrame->GetPrimaryCanvas()->GetToolbar()->Raise();
2546 #endif
2547 
2548     // Setup Tides/Currents to settings present at last shutdown
2549 // TODO
2550 //     gFrame->ShowTides( g_bShowTide );
2551 //     gFrame->ShowCurrents( g_bShowCurrent );
2552 
2553 //      Start up the ticker....
2554     gFrame->FrameTimer1.Start( TIMER_GFRAME_1, wxTIMER_CONTINUOUS );
2555 
2556 //      Start up the ViewPort Rotation angle Averaging Timer....
2557     gFrame->FrameCOGTimer.Start( 10, wxTIMER_CONTINUOUS );
2558 
2559 //    wxLogMessage( wxString::Format(_T("OpenCPN Initialized in %ld ms."), init_sw.Time() ) );
2560 
2561     OCPNPlatform::Initialize_4( );
2562 
2563 #ifdef __OCPN__ANDROID__
2564     androidHideBusyIcon();
2565 #endif
2566     wxLogMessage( wxString::Format(_("OpenCPN Initialized in %ld ms."), init_sw.Time() ) );
2567 
2568     wxMilliSleep(500);
2569 
2570 #ifdef __OCPN__ANDROID__
2571         //  We defer the startup message to here to allow the app frame to be contructed,
2572         //  thus avoiding a dialog with NULL parent which might not work on some devices.
2573     if( !n_NavMessageShown || ( vs != g_config_version_string ) || (g_AndroidVersionCode != androidGetVersionCode()) )
2574     {
2575             //qDebug() << "Showing NavWarning";
2576         wxMilliSleep(500);
2577         if( wxID_CANCEL == ShowNavWarning() ) {
2578               qDebug() << "Closing due to NavWarning Cancel";
2579               gFrame->Close();
2580               androidTerminate();
2581               return true;
2582         }
2583         n_NavMessageShown = 1;
2584 
2585     }
2586 
2587         // Finished with upgrade checking, so persist the currect Version Code
2588     g_AndroidVersionCode = androidGetVersionCode();
2589     qDebug() << "Persisting Version Code: " << g_AndroidVersionCode;
2590 #else
2591 //  Send the Welcome/warning message if it has never been sent before,
2592 //  or if the version string has changed at all
2593 //  We defer until here to allow for localization of the message
2594     if( !n_NavMessageShown || ( vs != g_config_version_string ) ) {
2595         if( wxID_CANCEL == ShowNavWarning() )
2596             return false;
2597         n_NavMessageShown = 1;
2598     }
2599 #endif
2600 
2601     g_config_version_string = vs;
2602 
2603     //The user accepted the "not for navigation" nag, so persist it here...
2604     pConfig->UpdateSettings();
2605 
2606     // Start delayed initialization chain after some milliseconds
2607     gFrame->InitTimer.Start( 5, wxTIMER_CONTINUOUS );
2608 
2609     g_pauimgr->Update();
2610 
2611     return TRUE;
2612 }
2613 
OnExit()2614 int MyApp::OnExit()
2615 {
2616     wxLogMessage( _T("opencpn::MyApp starting exit.") );
2617 
2618     //  Send current nav status data to log file   // pjotrc 2010.02.09
2619 
2620     wxDateTime lognow = wxDateTime::Now();
2621     lognow.MakeGMT();
2622     wxString day = lognow.FormatISODate();
2623     wxString utc = lognow.FormatISOTime();
2624     wxString navmsg = _T("LOGBOOK:  ");
2625     navmsg += day;
2626     navmsg += _T(" ");
2627     navmsg += utc;
2628     navmsg += _T(" UTC ");
2629 
2630     if( bGPSValid ) {
2631         wxString data;
2632         data.Printf( _T("OFF: Lat %10.5f Lon %10.5f "), gLat, gLon );
2633         navmsg += data;
2634 
2635         wxString cog;
2636         if( std::isnan(gCog) ) cog.Printf( _T("COG ----- ") );
2637         else
2638             cog.Printf( _T("COG %10.5f "), gCog );
2639 
2640         wxString sog;
2641         if( std::isnan(gSog) ) sog.Printf( _T("SOG -----  ") );
2642         else
2643             sog.Printf( _T("SOG %6.2f ") + getUsrSpeedUnit(), toUsrSpeed( gSog ) );
2644 
2645         navmsg += cog;
2646         navmsg += sog;
2647 
2648     } else {
2649         wxString data;
2650         data.Printf( _T("OFF: Lat %10.5f Lon %10.5f"), gLat, gLon );
2651         navmsg += data;
2652     }
2653     wxLogMessage( navmsg );
2654     g_loglast_time = lognow;
2655 
2656     if( ptcmgr ) delete ptcmgr;
2657 
2658     delete pConfig;
2659     delete pSelect;
2660     delete pSelectTC;
2661     delete pSelectAIS;
2662 
2663     delete ps52plib;
2664 
2665     if(g_pGroupArray){
2666         for(unsigned int igroup = 0; igroup < g_pGroupArray->GetCount(); igroup++){
2667             delete g_pGroupArray->Item(igroup);
2668         }
2669 
2670         g_pGroupArray->Clear();
2671         delete g_pGroupArray;
2672     }
2673 
2674     delete pDummyChart;
2675 
2676     wxLogMessage( _T("opencpn::MyApp exiting cleanly...\n") );
2677     wxLog::FlushActive();
2678 
2679     g_Platform->CloseLogFile();
2680 
2681     delete phost_name;
2682     delete pInit_Chart_Dir;
2683 
2684     if (pTrackList)
2685     {
2686         pTrackList->DeleteContents(true);
2687         pTrackList->Clear();
2688         delete pTrackList;
2689         pTrackList = NULL;
2690     }
2691 
2692     delete g_pRouteMan;
2693     delete pWayPointMan;
2694 
2695     delete pMessageOnceArray;
2696 
2697     DeInitializeUserColors();
2698 
2699     delete pLayerList;
2700 
2701     delete m_pRegistrarMan;
2702     CSVDeaccess( NULL );
2703 
2704     delete g_StyleManager;
2705 
2706 #ifdef __WXMSW__
2707 #ifdef USE_GLU_TESS
2708 #ifdef USE_GLU_DLL
2709     if(s_glu_dll_ready)
2710     FreeLibrary(s_hGLU_DLL);           // free the glu32.dll
2711 #endif
2712 #endif
2713 #endif
2714 
2715     //      Restore any changed system colors
2716 #ifdef __WXMSW__
2717     RestoreSystemColors();
2718 #endif
2719 
2720 #ifdef __MSVC__LEAK
2721     DeInitAllocCheck();
2722 #endif
2723 
2724 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3,0,0)
2725     delete plocale_def_lang;
2726 #endif
2727 
2728     FontMgr::Shutdown();
2729 
2730     delete m_checker;
2731 
2732     g_Platform->OnExit_2();
2733     safe_mode::clear_check();
2734 
2735     return TRUE;
2736 }
2737 
2738 #ifdef LINUX_CRASHRPT
OnFatalException()2739 void MyApp::OnFatalException () {
2740     g_crashprint.Report();
2741 }
2742 #endif
2743 
TrackOff(void)2744 void MyApp::TrackOff( void )
2745 {
2746     if( gFrame ) gFrame->TrackOff();
2747 }
2748 
2749 
2750 
2751 
2752 #include <wx/power.h>
2753 
2754 //------------------------------------------------------------------------------
2755 // MyFrame
2756 //------------------------------------------------------------------------------
2757 
2758 //      Frame implementation
2759 wxDEFINE_EVENT(BELLS_PLAYED_EVTYPE, wxCommandEvent);
2760 
BEGIN_EVENT_TABLE(MyFrame,wxFrame)2761 BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_CLOSE(MyFrame::OnCloseWindow)
2762 EVT_MENU(wxID_EXIT, MyFrame::OnExit)
2763 EVT_SIZE(MyFrame::OnSize)
2764 EVT_MOVE(MyFrame::OnMove)
2765 EVT_ICONIZE(MyFrame::OnIconize)
2766 EVT_MENU(-1, MyFrame::OnToolLeftClick)
2767 EVT_TIMER(INIT_TIMER, MyFrame::OnInitTimer)
2768 EVT_TIMER(FRAME_TIMER_1, MyFrame::OnFrameTimer1)
2769 EVT_TIMER(FRAME_TC_TIMER, MyFrame::OnFrameTCTimer)
2770 EVT_TIMER(FRAME_COG_TIMER, MyFrame::OnFrameCOGTimer)
2771 EVT_TIMER(MEMORY_FOOTPRINT_TIMER, MyFrame::OnMemFootTimer)
2772 EVT_MAXIMIZE(MyFrame::OnMaximize)
2773 EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_TOOL_RCLICKED, MyFrame::RequestNewToolbarArgEvent)
2774 EVT_ERASE_BACKGROUND(MyFrame::OnEraseBackground)
2775 //EVT_TIMER(RESIZE_TIMER, MyFrame::OnResizeTimer)
2776 EVT_TIMER(RECAPTURE_TIMER, MyFrame::OnRecaptureTimer)
2777 EVT_TIMER(TOOLBAR_ANIMATE_TIMER, MyFrame::OnToolbarAnimateTimer)
2778 EVT_COMMAND(wxID_ANY, BELLS_PLAYED_EVTYPE, MyFrame::OnBellsFinished)
2779 #ifdef wxHAS_POWER_EVENTS
2780 EVT_POWER_SUSPENDING(MyFrame::OnSuspending)
2781 EVT_POWER_SUSPENDED(MyFrame::OnSuspended)
2782 EVT_POWER_SUSPEND_CANCEL(MyFrame::OnSuspendCancel)
2783 EVT_POWER_RESUME(MyFrame::OnResume)
2784 #endif // wxHAS_POWER_EVENTS
2785 
2786 END_EVENT_TABLE()
2787 
2788 
2789 /*
2790  * Direct callback from completed sound, possibly in an interrupt
2791  * context. Just post an event to be processed in main thread.
2792  */
2793 static void onBellsFinishedCB(void* ptr)
2794 {
2795    auto framePtr  = static_cast<MyFrame*>(ptr);
2796    wxCommandEvent ev(BELLS_PLAYED_EVTYPE);
2797    wxPostEvent(framePtr, ev);
2798 }
2799 
2800 
2801 // My frame constructor
MyFrame(wxFrame * frame,const wxString & title,const wxPoint & pos,const wxSize & size,long style)2802 MyFrame::MyFrame( wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size,
2803         long style ) :
2804         wxFrame( frame, -1, title, pos, size, style ), //wxSIMPLE_BORDER | wxCLIP_CHILDREN | wxRESIZE_BORDER)
2805 //wxCAPTION | wxSYSTEM_MENU | wxRESIZE_BORDER
2806         m_signalKHandler(this)
2807 {
2808     m_last_track_rotation_ts = 0;
2809     m_ulLastNMEATicktime = 0;
2810 
2811     m_pStatusBar = NULL;
2812     m_StatusBarFieldCount = g_Platform->GetStatusBarFieldCount();
2813 
2814     m_pMenuBar = NULL;
2815     g_options = NULL;
2816     piano_ctx_menu = NULL;
2817 
2818     //      Redirect the initialization timer to this frame
2819     InitTimer.SetOwner( this, INIT_TIMER );
2820     m_iInitCount = 0;
2821     m_initializing = false;
2822 
2823     //      Redirect the global heartbeat timer to this frame
2824     FrameTimer1.SetOwner( this, FRAME_TIMER_1 );
2825 
2826     //      Redirect the Tide/Current update timer to this frame
2827     FrameTCTimer.SetOwner( this, FRAME_TC_TIMER );
2828 
2829     //      Redirect the COG Averager timer to this frame
2830     FrameCOGTimer.SetOwner( this, FRAME_COG_TIMER );
2831 
2832     //      Redirect the Memory Footprint Management timer to this frame
2833     MemFootTimer.SetOwner( this, MEMORY_FOOTPRINT_TIMER );
2834 
2835     //      Direct the Toolbar Animation timer to this frame
2836     ToolbarAnimateTimer.SetOwner( this, TOOLBAR_ANIMATE_TIMER );
2837 
2838 #ifdef __OCPN__ANDROID__
2839 //    m_PrefTimer.SetOwner( this, ANDROID_PREF_TIMER );
2840 //    Connect( m_PrefTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler( MyFrame::OnPreferencesResultTimer ), NULL, this );
2841 #endif
2842 
2843     //      Set up some assorted member variables
2844     m_bTimeIsSet = false;
2845     nBlinkerTick = 0;
2846 
2847     m_bdefer_resize = false;
2848 
2849     //    Clear the NMEA Filter tables
2850     for( int i = 0; i < MAX_COGSOG_FILTER_SECONDS; i++ ) {
2851         COGFilterTable[i] = NAN;
2852         SOGFilterTable[i] = NAN;
2853     }
2854     m_last_bGPSValid = false;
2855 
2856     gHdt = NAN;
2857     gHdm = NAN;
2858     gVar = NAN;
2859     gSog = NAN;
2860     gCog = NAN;
2861 
2862     for (int i = 0; i < MAX_COG_AVERAGE_SECONDS; i++ )
2863         COGTable[i] = NAN;
2864 
2865     m_fixtime = 0;
2866 
2867     m_bpersistent_quilt = false;
2868 
2869     m_ChartUpdatePeriod = 1;                  // set the default (1 sec.) period
2870 
2871 //    Establish my children
2872     g_pMUX = new Multiplexer();
2873 
2874     g_pAIS = new AIS_Decoder( this );
2875 
2876     g_pMUX->SetAISHandler(g_pAIS);
2877     g_pMUX->SetGPSHandler(this);
2878     //  Create/connect a dynamic event handler slot
2879     wxLogMessage(" **** Connect stuff");
2880     Connect( wxEVT_OCPN_DATASTREAM, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtOCPN_NMEA );
2881     Connect( EVT_OCPN_SIGNALKSTREAM, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtOCPN_SignalK );
2882 
2883     b_autofind = false;
2884 
2885     //  Create/connect a dynamic event handler slot for OCPN_MsgEvent(s) coming from PlugIn system
2886     Connect( wxEVT_OCPN_MSG, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtPlugInMessage );
2887 
2888     Connect( wxEVT_OCPN_THREADMSG, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtTHREADMSG );
2889 
2890     //  And from the thread SENC creator
2891     Connect( wxEVT_OCPN_BUILDSENCTHREAD, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnSENCEvtThread );
2892     //        Establish the system icons for the frame.
2893 
2894 #ifdef __WXMSW__
2895     SetIcon( wxICON(0) );           // this grabs the first icon in the integrated MSW resource file
2896 #endif
2897 
2898 #if defined(__WXGTK__) || defined(__WXQT__)
2899     wxIcon app_icon(opencpn);          // This comes from opencpn.xpm inclusion above
2900     SetIcon(app_icon);
2901 #endif
2902 
2903 #ifdef __WXMSW__
2904 
2905 //    Establish the entry points in USER32.DLL for system color control
2906 
2907     wxDynamicLibrary dllUser32( _T("user32.dll") );
2908 
2909     pSetSysColors = (SetSysColors_t) dllUser32.GetSymbol( wxT("SetSysColors") );
2910     pGetSysColor = (GetSysColor_t) dllUser32.GetSymbol( wxT("GetSysColor") );
2911 
2912     SaveSystemColors();
2913 #endif
2914 
2915     m_next_available_plugin_tool_id = ID_PLUGIN_BASE;
2916 
2917     g_sticky_chart = -1;
2918     g_sticky_projection = -1;
2919     m_BellsToPlay = 0;
2920 
2921     m_resizeTimer.SetOwner(this, RESIZE_TIMER);
2922     m_recaptureTimer.SetOwner(this, RECAPTURE_TIMER);
2923 
2924 }
2925 
~MyFrame()2926 MyFrame::~MyFrame()
2927 {
2928     FrameTimer1.Stop();
2929     delete ChartData;
2930     //delete pCurrentStack;
2931 
2932 //      Free the Route List
2933     wxRouteListNode *node = pRouteList->GetFirst();
2934 
2935     while( node ) {
2936         Route *pRouteDelete = node->GetData();
2937         delete pRouteDelete;
2938 
2939         node = node->GetNext();
2940     }
2941     delete pRouteList;
2942     pRouteList = NULL;
2943 
2944     Disconnect( wxEVT_OCPN_DATASTREAM, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtOCPN_NMEA );
2945     Disconnect( wxEVT_OCPN_MSG, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtPlugInMessage );
2946     Disconnect( wxEVT_OCPN_THREADMSG, (wxObjectEventFunction) (wxEventFunction) &MyFrame::OnEvtTHREADMSG );
2947 
2948 
2949 }
2950 
OnSENCEvtThread(OCPN_BUILDSENC_ThreadEvent & event)2951 void MyFrame::OnSENCEvtThread( OCPN_BUILDSENC_ThreadEvent & event)
2952 {
2953     s57chart *chart;
2954     switch(event.type){
2955        case SENC_BUILD_STARTED:
2956             //printf("Myframe SENC build started\n");
2957             break;
2958         case SENC_BUILD_DONE_NOERROR:
2959             //printf("Myframe SENC build done no error\n");
2960             chart = event.m_ticket->m_chart;
2961             if(chart){
2962                 chart->PostInit(FULL_INIT, global_color_scheme);
2963                // ..For each canvas, force an S52PLIB reconfig...
2964                 for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
2965                     ChartCanvas *cc = g_canvasArray.Item(i);
2966                         if(cc)
2967                             cc->ClearS52PLIBStateHash();         // Force a S52 PLIB re-configure
2968                 }
2969             }
2970 
2971             ReloadAllVP();
2972             break;
2973         case SENC_BUILD_DONE_ERROR:
2974             //printf("Myframe SENC build done ERROR\n");
2975             break;
2976         default:
2977             break;
2978     }
2979 }
2980 
RebuildChartDatabase()2981 void MyFrame::RebuildChartDatabase()
2982 {
2983     bool b_SetInitialPoint = false;
2984 
2985     //   Build the initial chart dir array
2986     ArrayOfCDI ChartDirArray;
2987     pConfig->LoadChartDirArray( ChartDirArray );
2988 
2989 
2990 
2991         if( ChartDirArray.GetCount() ) {
2992 //              Create and Save a new Chart Database based on the hints given in the config file
2993 
2994             wxString msg1(_("OpenCPN needs to update the chart database from config file entries...."));
2995 
2996             OCPNMessageDialog mdlg(gFrame, msg1, wxString(_("OpenCPN Info")),wxICON_INFORMATION | wxOK );
2997             int dlg_ret;
2998             dlg_ret = mdlg.ShowModal();
2999 
3000             delete ChartData;
3001             ChartData = new ChartDB( );
3002 
3003             wxString line( _("Rebuilding chart database from configuration file entries...") );
3004             /* The following 3 strings are embeded in wxProgressDialog but must be included by xgettext
3005              * to be localized properly. See {wxWidgets}src/generic/progdlgg.cpp:190 */
3006             wxString dummy1 = _("Elapsed time : ");
3007             wxString dummy2 = _("Estimated time : ");
3008             wxString dummy3 = _("Remaining time : ");
3009             wxGenericProgressDialog *pprog = new wxGenericProgressDialog( _("OpenCPN Chart Update"), line, 100,
3010                      NULL, wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME );
3011 
3012             ChartData->Create( ChartDirArray, pprog );
3013             ChartData->SaveBinary(ChartListFileName);
3014 
3015             delete pprog;
3016 
3017             //  Apply the inital Group Array structure to the chart data base
3018             ChartData->ApplyGroupArray( g_pGroupArray );
3019         }
3020 }
3021 
3022 
3023 // play an arbitrary number of bells by using 1 and 2 bell sounds
OnBellsFinished(wxCommandEvent & event)3024 void MyFrame::OnBellsFinished( wxCommandEvent& event )
3025 {
3026     int bells = wxMin(m_BellsToPlay, 2);
3027     if(bells <= 0)
3028         return;
3029 
3030     wxString soundfile = _T("sounds");
3031     appendOSDirSlash( &soundfile );
3032     soundfile += wxString( bells_sound_file_name[bells - 1], wxConvUTF8 );
3033     soundfile.Prepend( g_Platform->GetSharedDataDir() );
3034     wxLogMessage( _T("Using bells sound file: ") + soundfile );
3035 
3036     OcpnSound* sound = bells_sound[bells - 1];
3037     sound->SetFinishedCallback(onBellsFinishedCB, this);
3038     sound->SetCmd( g_CmdSoundString.mb_str( wxConvUTF8 ) );
3039     sound->Load( soundfile );
3040     if( !sound->IsOk() ) {
3041         wxLogMessage( _T("Failed to load bells sound file: ") + soundfile );
3042         return;
3043     }
3044     sound->Play();
3045     m_BellsToPlay -= bells;
3046 }
3047 
3048 
OnEraseBackground(wxEraseEvent & event)3049 void MyFrame::OnEraseBackground( wxEraseEvent& event )
3050 {
3051 }
3052 
OnMaximize(wxMaximizeEvent & event)3053 void MyFrame::OnMaximize( wxMaximizeEvent& event )
3054 {
3055     g_click_stop = 0;
3056 #ifdef __WXOSX__
3057     event.Skip();
3058 #endif
3059 }
3060 
GetColorScheme()3061 ColorScheme GetColorScheme()
3062 {
3063     return global_color_scheme;
3064 }
3065 
GetColorScheme()3066 ColorScheme MyFrame::GetColorScheme()
3067 {
3068     return global_color_scheme;
3069 }
3070 
ReloadAllVP()3071 void MyFrame::ReloadAllVP()
3072 {
3073     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3074         ChartCanvas *cc = g_canvasArray.Item(i);
3075         if(cc)
3076             cc->ReloadVP();
3077     }
3078 }
3079 
SetAndApplyColorScheme(ColorScheme cs)3080 void MyFrame::SetAndApplyColorScheme( ColorScheme cs )
3081 {
3082     global_color_scheme = cs;
3083 
3084     wxString SchemeName;
3085     switch( cs ){
3086         case GLOBAL_COLOR_SCHEME_DAY:
3087             SchemeName = _T("DAY");
3088             break;
3089         case GLOBAL_COLOR_SCHEME_DUSK:
3090             SchemeName = _T("DUSK");
3091             break;
3092         case GLOBAL_COLOR_SCHEME_NIGHT:
3093             SchemeName = _T("NIGHT");
3094             break;
3095         default:
3096             SchemeName = _T("DAY");
3097             break;
3098     }
3099 
3100 #if defined(__WXOSX__) && defined(OCPN_USE_DARKMODE)
3101     bool darkMode = (cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT || g_bDarkDecorations);
3102 
3103     if (wxPlatformInfo::Get().CheckOSVersion(10, 14)) {
3104         setAppLevelDarkMode(darkMode);
3105     }
3106     else if (wxPlatformInfo::Get().CheckOSVersion(10, 12)) {
3107         setWindowLevelDarkMode(MacGetTopLevelWindowRef(), darkMode);
3108     }
3109 #endif
3110 
3111     g_pauidockart->SetMetric(wxAUI_DOCKART_GRADIENT_TYPE, wxAUI_GRADIENT_NONE);
3112 
3113     g_pauidockart->SetColour(wxAUI_DOCKART_BORDER_COLOUR, wxColour(0,0,0));
3114     g_pauidockart->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 1);
3115     g_pauidockart->SetColour(wxAUI_DOCKART_SASH_COLOUR, wxColour(0,0,0));
3116     g_pauidockart->SetMetric(wxAUI_DOCKART_SASH_SIZE, 0);
3117     g_pauidockart->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR, wxColour(0,0,0));
3118     g_pauidockart->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR, wxColour(0,0,0));
3119 
3120 //    if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT )
3121 //    {
3122 //        g_pauidockart->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 0);
3123 //        g_pauidockart->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR, wxColour(0,0,0));
3124 //        g_pauidockart->SetColour(wxAUI_DOCKART_BORDER_COLOUR, wxColour(0,0,0));
3125 //    }
3126 
3127 //      else{
3128 //          g_pauidockart->SetMetric(wxAUI_DOCKART_GRADIENT_TYPE, g_grad_default);
3129 //          g_pauidockart->SetColour(wxAUI_DOCKART_BORDER_COLOUR, g_border_color_default);
3130 //          g_pauidockart->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, g_border_size_default);
3131 //          g_pauidockart->SetColour(wxAUI_DOCKART_SASH_COLOUR, g_sash_color_default);
3132 //          g_pauidockart->SetMetric(wxAUI_DOCKART_SASH_SIZE, g_sash_size_default);
3133 //          g_pauidockart->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR, g_caption_color_default);
3134 //          g_pauidockart->SetColour(wxAUI_DOCKART_BACKGROUND_COLOUR, g_background_color_default);
3135 //
3136 //      }
3137 
3138     g_pauidockart->SetColour(wxAUI_DOCKART_SASH_COLOUR, wxColour(0,0,0));
3139     g_pauidockart->SetMetric(wxAUI_DOCKART_SASH_SIZE, 6);
3140 
3141     g_pauimgr->Update();
3142 
3143     g_StyleManager->GetCurrentStyle()->SetColorScheme( cs );
3144 
3145     //Search the user color table array to find the proper hash table
3146     Usercolortable_index = 0;
3147     for( unsigned int i = 0; i < UserColorTableArray->GetCount(); i++ ) {
3148         colTable *ct = (colTable *) UserColorTableArray->Item( i );
3149         if( SchemeName.IsSameAs( *ct->tableName ) ) {
3150             Usercolortable_index = i;
3151             break;
3152         }
3153     }
3154 
3155     if( ps52plib ) ps52plib->SetPLIBColorScheme( SchemeName );
3156 
3157     //    Set up a pointer to the proper hash table
3158     pcurrent_user_color_hash = (wxColorHashMap *) UserColourHashTableArray->Item(
3159             Usercolortable_index );
3160 
3161     SetSystemColors( cs );
3162 
3163     // ..For each canvas...
3164     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3165         ChartCanvas *cc = g_canvasArray.Item(i);
3166         if(cc){
3167             cc->SetColorScheme( cs );
3168             cc->GetWorldBackgroundChart()->SetColorScheme( cs );
3169             cc->HideChartInfoWindow();
3170             cc->SetQuiltChartHiLiteIndex( -1 );
3171         }
3172 
3173     }
3174 
3175 
3176     if( pWayPointMan )
3177         pWayPointMan->SetColorScheme( cs );
3178 
3179     if( ChartData )
3180         ChartData->ApplyColorSchemeToCachedCharts( cs );
3181 
3182     SetChartThumbnail( -1 );
3183 
3184 
3185     if( g_options ) {
3186         g_options->SetColorScheme( cs );
3187     }
3188 
3189     if( console ) {
3190         console->SetColorScheme( cs );
3191     }
3192 
3193     if( g_pRouteMan ) {
3194         g_pRouteMan->SetColorScheme( cs );
3195     }
3196 
3197     if( g_pMarkInfoDialog ) {
3198         g_pMarkInfoDialog->SetColorScheme( cs );
3199     }
3200 
3201     if( pRoutePropDialog ) {
3202         pRoutePropDialog->SetColorScheme( cs );
3203     }
3204 
3205     //    For the AIS target query dialog, we must rebuild it to incorporate the style desired for the colorscheme selected
3206     if( g_pais_query_dialog_active ) {
3207         bool b_isshown = g_pais_query_dialog_active->IsShown();
3208         int n_mmsi = g_pais_query_dialog_active->GetMMSI();
3209         if( b_isshown ) g_pais_query_dialog_active->Show( false );              // dismiss it
3210 
3211         g_pais_query_dialog_active->Close();
3212 
3213         g_pais_query_dialog_active = new AISTargetQueryDialog();
3214         g_pais_query_dialog_active->Create( this, -1, _( "AIS Target Query" ),
3215                 wxPoint( g_ais_query_dialog_x, g_ais_query_dialog_y ) );
3216         g_pais_query_dialog_active->SetMMSI( n_mmsi );
3217         g_pais_query_dialog_active->UpdateText();
3218         if( b_isshown ) g_pais_query_dialog_active->Show();
3219     }
3220 
3221     if( pRouteManagerDialog ) pRouteManagerDialog->SetColorScheme();
3222 
3223     if( g_pAISTargetList ) g_pAISTargetList->SetColorScheme();
3224 
3225     if( g_pObjectQueryDialog ) g_pObjectQueryDialog->SetColorScheme();
3226 
3227     ApplyGlobalColorSchemetoStatusBar();
3228 
3229     UpdateAllToolbars( cs );
3230 
3231     if(g_MainToolbar){
3232         if(g_MainToolbar->GetColorScheme() != cs){
3233 
3234             // capture the current toolbar collapse state
3235             bool btoolbarFull = g_bmasterToolbarFull;
3236 
3237             g_MainToolbar->SetColorScheme( cs );
3238             //g_MainToolbar->DestroyToolBar();
3239             //CreateMasterToolbar();
3240 
3241             if(!btoolbarFull){
3242                 g_MainToolbar->Hide();
3243                 RequestNewMasterToolbar();
3244                 g_MainToolbar->SetColorScheme( cs );
3245                 CollapseGlobalToolbar();
3246                 g_MainToolbar->Show();
3247             }
3248             else{
3249                 RequestNewMasterToolbar();
3250                 g_MainToolbar->SetColorScheme( cs );
3251             }
3252         }
3253     }
3254 
3255     if( g_pi_manager ) g_pi_manager->SetColorSchemeForAllPlugIns( cs );
3256 
3257 
3258 }
3259 
ApplyGlobalColorSchemetoStatusBar(void)3260 void MyFrame::ApplyGlobalColorSchemetoStatusBar( void )
3261 {
3262     if( m_pStatusBar != NULL ) {
3263         m_pStatusBar->SetBackgroundColour(GetGlobalColor(_T("UIBDR")));    //UINFF
3264         m_pStatusBar->ClearBackground();
3265 
3266     }
3267 }
3268 
GetPrimaryCanvas()3269 ChartCanvas *MyFrame::GetPrimaryCanvas()
3270 {
3271     if(g_canvasArray.GetCount() > 0)
3272         return g_canvasArray.Item(0);
3273     else
3274         return NULL;
3275 }
CancelAllMouseRoute()3276 void MyFrame::CancelAllMouseRoute()
3277 {
3278 // ..For each canvas...
3279     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3280         ChartCanvas *cc = g_canvasArray.Item(i);
3281         if(cc)
3282             cc->CancelMouseRoute();
3283     }
3284 }
3285 
NotifyChildrenResize()3286 void MyFrame::NotifyChildrenResize()
3287 {
3288 //    // ..For each canvas...
3289 //    for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3290 //        ChartCanvas *cc = g_canvasArray.Item(i);
3291 //         if(cc)
3292 //             cc->DestroyMuiBar();                // A new one will automatically be recreated.
3293 //    }
3294 }
3295 
CreateCanvasLayout(bool b_useStoredSize)3296 void MyFrame::CreateCanvasLayout( bool b_useStoredSize )
3297 {
3298     //  Clear the cache, and thus close all charts to avoid memory leaks
3299     if(ChartData)
3300         ChartData->PurgeCache();
3301 
3302     // Detach all canvases from AUI manager
3303     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3304         ChartCanvas *cc = g_canvasArray[i];
3305         if(cc){
3306             g_pauimgr->DetachPane(cc);
3307         }
3308     }
3309 
3310     //Destroy any existing canvases, except for Primary canvas
3311     for(unsigned int i=1 ; i < g_canvasArray.GetCount() ; i++){
3312         ChartCanvas *cc = g_canvasArray.Item(i);
3313         if(cc){
3314             pthumbwin = NULL;           // TODO
3315             cc->DestroyToolbar();
3316             cc->Destroy();
3317         }
3318     }
3319 
3320     // Canvas pointers in config array are now invalid
3321     for(unsigned int i=1 ; i < g_canvasConfigArray.GetCount() ; i++){
3322         g_canvasConfigArray.Item(i)->canvas = NULL;
3323     }
3324 
3325 //    g_canvasArray.Clear();
3326 
3327     // Clear the canvas Array, except for Primary canvas
3328     for(unsigned int i=1 ; i < g_canvasArray.GetCount() ; i++){
3329         g_canvasArray.RemoveAt(i);
3330     }
3331 
3332     ChartCanvas *cc = NULL;
3333     switch(g_canvasConfig){
3334         default:
3335         case 0:                                                 // a single canvas
3336             if(!g_canvasArray.GetCount() || !g_canvasConfigArray.Item(0)){
3337                 cc = new ChartCanvas( this, 0 );                         // the chart display canvas
3338                 g_canvasArray.Add(cc);
3339             }
3340             else{
3341                 cc = g_canvasArray[0];
3342             }
3343 
3344             // Verify that glCanvas is ready, if necessary
3345             if(g_bopengl){
3346                 if(!cc->GetglCanvas())
3347                     cc->SetupGlCanvas();
3348             }
3349 
3350             g_canvasConfigArray.Item(0)->canvas = cc;
3351 
3352             cc->SetDisplaySizeMM(g_display_size_mm);
3353 
3354             cc->ApplyCanvasConfig(g_canvasConfigArray.Item(0));
3355 
3356 //            cc->SetToolbarPosition(wxPoint( g_maintoolbar_x, g_maintoolbar_y ));
3357             cc->ConfigureChartBar();
3358             cc->SetColorScheme( global_color_scheme );
3359             cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
3360             cc->SetShowGPS( true );
3361 
3362             g_pauimgr->AddPane( cc );
3363             g_pauimgr->GetPane( cc ).Name( _T("ChartCanvas") );
3364             g_pauimgr->GetPane( cc ).Fixed();
3365             g_pauimgr->GetPane( cc ).CaptionVisible( false );
3366             g_pauimgr->GetPane( cc ).CenterPane();
3367 
3368             break;
3369 
3370         case 1:{                                                 // two canvas, horizontal
3371             if(!g_canvasArray.GetCount() || !g_canvasArray[0]){
3372                 cc = new ChartCanvas( this, 0 );                         // the chart display canvas
3373                 g_canvasArray.Add(cc);
3374            }
3375             else{
3376                 cc = g_canvasArray[0];
3377            }
3378 
3379            // Verify that glCanvas is ready, if not already built
3380            if(g_bopengl){
3381                 if(!cc->GetglCanvas())
3382                     cc->SetupGlCanvas();
3383            }
3384 
3385            g_canvasConfigArray.Item(0)->canvas = cc;
3386 
3387            cc->ApplyCanvasConfig(g_canvasConfigArray.Item(0));
3388 
3389            cc->SetDisplaySizeMM(g_display_size_mm);
3390            cc->ConfigureChartBar();
3391            cc->SetColorScheme( global_color_scheme );
3392            cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
3393            cc->SetShowGPS( false );
3394 
3395            g_pauimgr->AddPane( cc );
3396            g_pauimgr->GetPane( cc ).Name( _T("ChartCanvas") );
3397            g_pauimgr->GetPane( cc ).CaptionVisible( false ).PaneBorder(false).CloseButton(false);
3398 
3399            g_pauimgr->GetPane( cc ).CenterPane();
3400 
3401            cc = new ChartCanvas( this, 1 );                         // the chart display canvas
3402            g_canvasArray.Add(cc);
3403 
3404            //  There is not yet a config descriptor for canvas 2, so create one by copy ctor from canvas {0}.
3405            if(g_canvasConfigArray.GetCount() < 2){
3406                canvasConfig *pcc = new canvasConfig(*g_canvasConfigArray.Item(0));
3407                pcc->configIndex = 1;
3408 
3409                // Arbitrarily establish the initial size of the new canvas to be
3410                // half the screen width.
3411                pcc->canvasSize = wxSize(GetClientSize().x / 2, GetClientSize().y);
3412                g_canvasConfigArray.Add(pcc);
3413            }
3414 
3415            g_canvasConfigArray.Item(1)->canvas = cc;
3416 
3417            cc->ApplyCanvasConfig(g_canvasConfigArray.Item(1));
3418 
3419            cc->SetDisplaySizeMM(g_display_size_mm);
3420            cc->SetToolbarOrientation( g_maintoolbar_orient);
3421            cc->ConfigureChartBar();
3422            cc->SetColorScheme( global_color_scheme );
3423            cc->SetShowGPS( true );
3424 
3425            g_pauimgr->AddPane( cc );
3426            g_pauimgr->GetPane( cc ).Name( _T("ChartCanvas2") );
3427            g_pauimgr->GetPane( cc ).CaptionVisible( false ).PaneBorder(false).CloseButton(false);
3428            g_pauimgr->GetPane( cc ).RightDockable(true);
3429            g_pauimgr->GetPane( cc ).Right();
3430 
3431 #ifdef __OCPN__ANDROID__
3432            g_canvasConfigArray.Item(1)->canvasSize = wxSize(GetClientSize().x / 2, GetClientSize().y);
3433            g_pauimgr->GetPane( cc ).BestSize( GetClientSize().x / 2, GetClientSize().y );
3434 //           cc->SetSize(GetClientSize().x / 2, GetClientSize().y);
3435 #endif
3436 
3437            // If switching fromsingle canvas to 2-canvas mode dynamically,
3438            //  try to use the latest persisted size for the new second canvas.
3439            if(b_useStoredSize){
3440                 int ccw = g_canvasConfigArray.Item(1)->canvasSize.x;
3441                 int cch = g_canvasConfigArray.Item(1)->canvasSize.y;
3442 
3443                 // Check for undefined size, and set a nice default size if necessary.
3444                 if( ccw < GetClientSize().x / 10){
3445                     ccw = GetClientSize().x / 2;
3446                     cch = GetClientSize().y;
3447                 }
3448 
3449                 g_pauimgr->GetPane( cc ).BestSize( ccw, cch );
3450                 cc->SetSize(ccw, cch);
3451             }
3452 
3453            break;
3454         }
3455 
3456         case 2:                                                 // two canvas, vertical
3457 
3458             break;
3459     }
3460 
3461     g_focusCanvas = GetPrimaryCanvas();
3462 
3463 }
3464 
3465 
3466 
3467 
3468 
3469 
3470 
RequestNewToolbars(bool bforcenew)3471 void MyFrame::RequestNewToolbars(bool bforcenew)
3472 {
3473     if( b_inCloseWindow ) {
3474         return;
3475     }
3476 
3477     // ..For each canvas...
3478     if(0){
3479         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3480             ChartCanvas *cc = g_canvasArray.Item(i);
3481             if(cc)
3482                 cc->RequestNewCanvasToolbar( bforcenew );
3483         }
3484     }
3485 
3486 
3487     BuildiENCToolbar(bforcenew);
3488     PositionIENCToolbar();
3489 
3490 #ifdef __OCPN__ANDROID__
3491     DoChartUpdate();
3492 #endif
3493 
3494 
3495 }
3496 
3497 //      Update inplace the various controls with bitmaps corresponding to the current color scheme
UpdateAllToolbars(ColorScheme cs)3498 void MyFrame::UpdateAllToolbars( ColorScheme cs )
3499 {
3500 
3501     if(g_iENCToolbar)
3502         g_iENCToolbar->SetColorScheme( cs );
3503 
3504 
3505     return;
3506 }
3507 
3508 
SetAllToolbarScale()3509 void MyFrame::SetAllToolbarScale()
3510 {
3511     double scale_factor = g_Platform->GetToolbarScaleFactor( g_GUIScaleFactor );
3512     g_toolbar_scalefactor = g_Platform->GetToolbarScaleFactor( g_GUIScaleFactor );
3513 
3514     //  Round to the nearest "quarter", to avoid rendering artifacts
3515     scale_factor = wxRound( scale_factor * 4.0 )/ 4.0;
3516 
3517     // ..For each canvas...
3518     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3519         ChartCanvas *cc = g_canvasArray.Item(i);
3520         if(cc)
3521             cc->SetToolbarScaleFactor(scale_factor);
3522     }
3523 
3524 }
3525 
SetGPSCompassScale()3526 void MyFrame::SetGPSCompassScale()
3527 {
3528     g_compass_scalefactor = g_Platform->GetCompassScaleFactor( g_GUIScaleFactor );
3529 
3530 }
3531 
GetCanvasUnderMouse()3532 ChartCanvas *MyFrame::GetCanvasUnderMouse()
3533 {
3534     wxPoint screenPoint = ::wxGetMousePosition();
3535     canvasConfig *cc;
3536 
3537     switch(g_canvasConfig){
3538         case 1:
3539             cc = g_canvasConfigArray.Item(0);
3540             if(cc ){
3541                 ChartCanvas *canvas = cc->canvas;
3542                 if(canvas->GetScreenRect().Contains(/*canvas->ScreenToClient*/(screenPoint)))
3543                     return canvas;
3544             }
3545             cc = g_canvasConfigArray.Item(1);
3546             if(cc ){
3547                 ChartCanvas *canvas = cc->canvas;
3548                 if(canvas->GetScreenRect().Contains(/*canvas->ScreenToClient*/(screenPoint)))
3549                     return canvas;
3550             }
3551             break;
3552 
3553         default:
3554             cc = g_canvasConfigArray.Item(0);
3555             if(cc ){
3556                 ChartCanvas *canvas = cc->canvas;
3557                 if(canvas->GetScreenRect().Contains(canvas->ScreenToClient(screenPoint)))
3558                     return canvas;
3559             }
3560     }
3561 
3562     return NULL;
3563 }
3564 
GetCanvasIndexUnderMouse()3565 int MyFrame::GetCanvasIndexUnderMouse()
3566 {
3567     wxPoint screenPoint = ::wxGetMousePosition();
3568     canvasConfig *cc;
3569 
3570     switch(g_canvasConfig){
3571         case 1:
3572             cc = g_canvasConfigArray.Item(0);
3573             if(cc ){
3574                 ChartCanvas *canvas = cc->canvas;
3575                 if(canvas->GetScreenRect().Contains(/*canvas->ScreenToClient*/(screenPoint)))
3576                     return 0;
3577             }
3578             cc = g_canvasConfigArray.Item(1);
3579             if(cc ){
3580                 ChartCanvas *canvas = cc->canvas;
3581                 if(canvas->GetScreenRect().Contains(/*canvas->ScreenToClient*/(screenPoint)))
3582                     return 1;
3583             }
3584             break;
3585 
3586         default:
3587             cc = g_canvasConfigArray.Item(0);
3588             if(cc ){
3589                 ChartCanvas *canvas = cc->canvas;
3590                 if(canvas->GetScreenRect().Contains(canvas->ScreenToClient(screenPoint)))
3591                     return 0;
3592             }
3593     }
3594 
3595     return -1;
3596 }
3597 
3598 
DropMarker(bool atOwnShip)3599 bool MyFrame::DropMarker( bool atOwnShip )
3600 {
3601     double lat, lon;
3602     if(atOwnShip){
3603         lat = gLat;
3604         lon = gLon;
3605     }
3606     else{
3607         ChartCanvas *canvas = GetCanvasUnderMouse();
3608         if(!canvas)
3609             return false;
3610 
3611         lat = canvas->m_cursor_lat;
3612         lon = canvas->m_cursor_lon;
3613     }
3614 
3615     RoutePoint *pWP = new RoutePoint( lat, lon, g_default_wp_icon, wxEmptyString, wxEmptyString );
3616     pWP->m_bIsolatedMark = true;                      // This is an isolated mark
3617     pSelect->AddSelectableRoutePoint( lat, lon, pWP );
3618     pConfig->AddNewWayPoint( pWP, -1 );    // use auto next num
3619     if( !pWP->IsVisibleSelectable( GetCanvasUnderMouse() ) )
3620         pWP->ShowScaleWarningMessage(GetCanvasUnderMouse());
3621     if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
3622         pRouteManagerDialog->UpdateWptListCtrl();
3623 //     undo->BeforeUndoableAction( Undo_CreateWaypoint, pWP, Undo_HasParent, NULL );
3624 //     undo->AfterUndoableAction( NULL );
3625 
3626     InvalidateAllGL();
3627     RefreshAllCanvas( false );
3628 
3629     return true;
3630 }
3631 
SwitchKBFocus(ChartCanvas * pCanvas)3632 void MyFrame::SwitchKBFocus( ChartCanvas *pCanvas )
3633 {
3634     if(g_canvasConfig != 0){             // multi-canvas?
3635         canvasConfig *cc;
3636         int nTarget = -1;
3637         int nTargetGTK = -1;
3638         ChartCanvas *target;
3639         wxWindow *source = FindFocus();
3640         ChartCanvas *test = wxDynamicCast(source, ChartCanvas);
3641         if(!test)
3642             return;
3643 
3644         // On linux(GTK), the TAB key causes a loss of focus immediately
3645         //  So the logic needs a switch
3646         switch(g_canvasConfig){
3647             case 1:
3648                 cc = g_canvasConfigArray.Item(0);
3649                 if(cc ){
3650                     ChartCanvas *canvas = cc->canvas;
3651                     if(canvas && (canvas == test)){
3652                         nTarget = 1;
3653                         nTargetGTK = 0;
3654                     }
3655                 }
3656                 cc = g_canvasConfigArray.Item(1);
3657                 if(cc ){
3658                     ChartCanvas *canvas = cc->canvas;
3659                     if(canvas && (canvas == test)){
3660                         nTarget = 0;
3661                         nTargetGTK = 1;
3662                     }
3663                 }
3664 
3665                 if(nTarget >= 0){
3666                     //printf("sw %d\n", nTarget);
3667                     int nfinalTarget = nTarget;
3668 #ifdef __WXGTK__
3669                     nfinalTarget = nTargetGTK;
3670 #endif
3671                     target = g_canvasConfigArray.Item(nfinalTarget)->canvas;
3672                     if(target){
3673                         wxWindow *win = wxDynamicCast(target, wxWindow);
3674                         win->SetFocus();
3675                         target->Refresh(true);
3676                     }
3677                 }
3678                 break;
3679 
3680             default:
3681                 break;
3682 
3683         }
3684     }
3685 }
3686 
FastClose()3687 void MyFrame::FastClose(){
3688 
3689     FrameTimer1.Stop();
3690     quitflag++;                             // signal to the timer loop
3691     FrameTimer1.Start(1);                    // real quick now...
3692 }
3693 
3694 // Intercept menu commands
OnExit(wxCommandEvent & event)3695 void MyFrame::OnExit( wxCommandEvent& event )
3696 {
3697     quitflag++;                             // signal to the timer loop
3698 
3699 }
3700 
OnCloseWindow(wxCloseEvent & event)3701 void MyFrame::OnCloseWindow( wxCloseEvent& event )
3702 {
3703     //    It is possible that double clicks on application exit box could cause re-entrance here
3704     //    Not good, and don't need it anyway, so simply return.
3705     if( b_inCloseWindow ) {
3706 //            wxLogMessage(_T("opencpn::MyFrame re-entering OnCloseWindow"));
3707         return;
3708     }
3709 
3710     // The Options dialog, and other deferred init items, are not fully initialized.
3711     // Best to just cancel the close request.
3712     // This is probably only reachable on slow hardware, or on Android life-cycle events...
3713 #ifndef __OCPN__ANDROID__
3714     if(!g_bDeferredInitDone)
3715         return;
3716 #endif
3717 
3718 
3719     if(g_options){
3720         delete g_options;
3721         g_options = NULL;
3722         g_pOptions = NULL;
3723     }
3724 
3725     //  If the multithread chart compressor engine is running, cancel the close command
3726     if( b_inCompressAllCharts ) {
3727         return;
3728     }
3729 
3730     if( bDBUpdateInProgress )
3731         return;
3732 
3733     b_inCloseWindow = true;
3734 
3735     ::wxSetCursor( wxCURSOR_WAIT );
3736 
3737     // If we happen to have the measure tool open on Ctrl-Q quit
3738     // ..For each canvas...
3739     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3740         ChartCanvas *cc = g_canvasArray.Item(i);
3741         if(cc && cc->IsMeasureActive()){
3742             cc->CancelMeasureRoute();
3743         }
3744     }
3745 
3746 
3747     // We save perspective before closing to restore position next time
3748     // Pane is not closed so the child is not notified (OnPaneClose)
3749     if( g_pAISTargetList ) {
3750         wxAuiPaneInfo &pane = g_pauimgr->GetPane( g_pAISTargetList );
3751         g_AisTargetList_perspective = g_pauimgr->SavePaneInfo( pane );
3752         g_pauimgr->DetachPane( g_pAISTargetList );
3753     }
3754 
3755 
3756     // Make sure the saved perspective minimum canvas sizes are essentially undefined
3757 //     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3758 //         ChartCanvas *cc = g_canvasArray.Item(i);
3759 //         if(cc)
3760 //             g_pauimgr->GetPane( cc ).MinSize(10,10);
3761 //     }
3762 
3763     pConfig->SetPath( _T ( "/AUI" ) );
3764     pConfig->Write( _T ( "AUIPerspective" ), g_pauimgr->SavePerspective() );
3765 
3766     g_bquiting = true;
3767 
3768 #ifdef ocpnUSE_GL
3769     // cancel compression jobs
3770     if(g_bopengl){
3771         if(g_glTextureManager){
3772             g_glTextureManager->PurgeJobList();
3773 
3774             if(g_glTextureManager->GetRunningJobCount())
3775                 g_bcompression_wait = true;
3776         }
3777     }
3778 #endif
3779 
3780     SetCursor( wxCURSOR_WAIT );
3781 
3782     RefreshAllCanvas( true );
3783 
3784     //  This yield is not necessary, since the Update() proceeds syncronously...
3785     //wxYield();
3786 
3787     //   Save the saved Screen Brightness
3788     RestoreScreenBrightness();
3789 
3790     // Persist the toolbar locations
3791     if( g_MainToolbar ) {
3792         wxPoint tbp_incanvas = GetPrimaryCanvas()->GetToolbarPosition();
3793         g_maintoolbar_x = tbp_incanvas.x;
3794         g_maintoolbar_y = tbp_incanvas.y;
3795         g_maintoolbar_orient = GetPrimaryCanvas()->GetToolbarOrientation();
3796         //g_toolbarConfig = GetPrimaryCanvas()->GetToolbarConfigString();
3797         if (g_MainToolbar) {
3798             g_MainToolbar->GetScreenPosition(&g_maintoolbar_x, &g_maintoolbar_y);
3799         }
3800     }
3801 
3802     if(g_iENCToolbar){
3803         wxPoint locn = g_iENCToolbar->GetPosition();
3804         wxPoint tbp_incanvas = GetPrimaryCanvas()->ScreenToClient( locn );
3805         g_iENCToolbarPosY = tbp_incanvas.y;
3806         g_iENCToolbarPosX = tbp_incanvas.x;
3807     }
3808 
3809     g_bframemax = IsMaximized();
3810 
3811     FrameTimer1.Stop();
3812     FrameCOGTimer.Stop();
3813     TrackOff();
3814 
3815      /*
3816      Automatically drop an anchorage waypoint, if enabled
3817      On following conditions:
3818      1.  In "Cruising" mode, meaning that speed has at some point exceeded 3.0 kts.
3819      2.  Current speed is less than 0.5 kts.
3820      3.  Opencpn has been up at least 30 minutes
3821      4.  And, of course, opencpn is going down now.
3822      5.  And if there is no anchor watch set on "anchor..." icon mark           // pjotrc 2010.02.15
3823      */
3824     if( g_bAutoAnchorMark ) {
3825         bool watching_anchor = false;                                           // pjotrc 2010.02.15
3826         if( pAnchorWatchPoint1 )                                               // pjotrc 2010.02.15
3827         watching_anchor = ( pAnchorWatchPoint1->GetIconName().StartsWith( _T("anchor") ) ); // pjotrc 2010.02.15
3828         if( pAnchorWatchPoint2 )                                               // pjotrc 2010.02.15
3829         watching_anchor |= ( pAnchorWatchPoint2->GetIconName().StartsWith( _T("anchor") ) ); // pjotrc 2010.02.15
3830 
3831         wxDateTime now = wxDateTime::Now();
3832         wxTimeSpan uptime = now.Subtract( g_start_time );
3833 
3834         if( !watching_anchor && ( g_bCruising ) && ( gSog < 0.5 )
3835                 && ( uptime.IsLongerThan( wxTimeSpan( 0, 30, 0, 0 ) ) ) )     // pjotrc 2010.02.15
3836                 {
3837             //    First, delete any single anchorage waypoint closer than 0.25 NM from this point
3838             //    This will prevent clutter and database congestion....
3839 
3840             wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
3841             while( node ) {
3842                 RoutePoint *pr = node->GetData();
3843                 if( pr->GetName().StartsWith( _T("Anchorage") ) ) {
3844                     double a = gLat - pr->m_lat;
3845                     double b = gLon - pr->m_lon;
3846                     double l = sqrt( ( a * a ) + ( b * b ) );
3847 
3848                     // caveat: this is accurate only on the Equator
3849                     if( ( l * 60. * 1852. ) < ( .25 * 1852. ) ) {
3850                         pConfig->DeleteWayPoint( pr );
3851                         pSelect->DeleteSelectablePoint( pr, SELTYPE_ROUTEPOINT );
3852                         delete pr;
3853                         break;
3854                     }
3855                 }
3856 
3857                 node = node->GetNext();
3858             }
3859 
3860             wxString name = now.Format();
3861             name.Prepend( _("Anchorage created ") );
3862             RoutePoint *pWP = new RoutePoint( gLat, gLon, _T("anchorage"), name, wxEmptyString );
3863             pWP->m_bShowName = false;
3864             pWP->m_bIsolatedMark = true;
3865 
3866             pConfig->AddNewWayPoint( pWP, -1 );       // use auto next num
3867         }
3868     }
3869 
3870 
3871 
3872     // Provisionally save all settings before deactivating plugins
3873     pConfig->UpdateSettings();
3874 
3875     //    Deactivate the PlugIns
3876     if( g_pi_manager ) {
3877         g_pi_manager->DeactivateAllPlugIns();
3878     }
3879 
3880     wxLogMessage( _T("opencpn::MyFrame exiting cleanly.") );
3881 
3882     quitflag++;
3883 
3884     pConfig->UpdateNavObj();
3885 
3886 //    pConfig->m_pNavObjectChangesSet->Clear();
3887     delete pConfig->m_pNavObjectChangesSet;
3888 
3889     //Remove any leftover Routes and Waypoints from config file as they were saved to navobj before
3890     pConfig->DeleteGroup( _T ( "/Routes" ) );
3891     pConfig->DeleteGroup( _T ( "/Marks" ) );
3892     pConfig->Flush();
3893 
3894 
3895     delete g_printData;
3896     delete g_pageSetupData;
3897 
3898     if( g_pAboutDlg ) g_pAboutDlg->Destroy();
3899     if( g_pAboutDlgLegacy ) g_pAboutDlgLegacy->Destroy();
3900 
3901 //      Explicitely Close some children, especially the ones with event handlers
3902 //      or that call GUI methods
3903 
3904     if( g_pCM93OffsetDialog ) {
3905         g_pCM93OffsetDialog->Destroy();
3906         g_pCM93OffsetDialog = NULL;
3907     }
3908 
3909 #ifndef __OCPN__ANDROID__
3910     // .. for each canvas...
3911     // ..For each canvas...
3912     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3913         ChartCanvas *cc = g_canvasArray.Item(i);
3914         if(cc)
3915             cc->DestroyToolbar();
3916     }
3917 
3918     if(g_MainToolbar)
3919         g_MainToolbar->Destroy();
3920     g_MainToolbar = NULL;
3921 #endif
3922 
3923 
3924     if(g_iENCToolbar){
3925         wxPoint locn = g_iENCToolbar->GetPosition();
3926         g_iENCToolbarPosY = locn.y;
3927         g_iENCToolbarPosX = locn.x;
3928         g_iENCToolbar->Destroy();
3929     }
3930 
3931     if( g_pAISTargetList ) {
3932         g_pAISTargetList->Disconnect_decoder();
3933         g_pAISTargetList->Destroy();
3934     }
3935 
3936 
3937 #ifndef __WXQT__
3938     SetStatusBar( NULL );
3939 #endif
3940 
3941     if(RouteManagerDialog::getInstanceFlag()){
3942         if( pRouteManagerDialog ) {
3943             pRouteManagerDialog->Destroy();
3944             pRouteManagerDialog = NULL;
3945         }
3946     }
3947 
3948     //  Clear the cache, and thus close all charts to avoid memory leaks
3949     if(ChartData)
3950         ChartData->PurgeCache();
3951 
3952     // pthumbwin is a canvas child
3953     pthumbwin = NULL;
3954 
3955     // Finally ready to destroy the canvases
3956     g_focusCanvas = NULL;
3957 
3958     // ..For each canvas...
3959     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
3960         ChartCanvas *cc = g_canvasArray.Item(i);
3961         if(cc)
3962             cc->Destroy();
3963     }
3964 
3965     g_canvasArray.Clear();
3966 
3967 
3968     g_pauimgr->UnInit();
3969     delete g_pauimgr;
3970     g_pauimgr = NULL;
3971 
3972     //    Unload the PlugIns
3973     //      Note that we are waiting until after the canvas is destroyed,
3974     //      since some PlugIns may have created children of canvas.
3975     //      Such a PlugIn must stay intact for the canvas dtor to call DestoryChildren()
3976 
3977     if(ChartData)
3978         ChartData->PurgeCachePlugins();
3979 
3980     if( g_pi_manager ) {
3981         g_pi_manager->UnLoadAllPlugIns();
3982         delete g_pi_manager;
3983         g_pi_manager = NULL;
3984     }
3985 
3986     delete pConfig;             // All done
3987     pConfig = NULL;
3988 
3989     if( g_pAIS ) {
3990         if(g_pMUX)
3991             g_pMUX->SetAISHandler(NULL);
3992         delete g_pAIS;
3993         g_pAIS = NULL;
3994     }
3995 
3996     delete g_pMUX;
3997     g_pMUX = NULL;
3998 
3999 
4000     //  Clear some global arrays, lists, and hash maps...
4001     for ( size_t i = 0; i < g_pConnectionParams->Count(); i++ )
4002     {
4003         ConnectionParams *cp = g_pConnectionParams->Item(i);
4004         delete cp;
4005     }
4006     delete g_pConnectionParams;
4007 
4008     if(pLayerList){
4009         LayerList::iterator it;
4010         while(pLayerList->GetCount()){
4011             Layer *lay = pLayerList->GetFirst()->GetData();
4012             delete lay;                 // automatically removes the layer from list, see Layer dtor
4013         }
4014     }
4015 
4016     MsgPriorityHash::iterator it;
4017     for( it = NMEA_Msg_Hash.begin(); it != NMEA_Msg_Hash.end(); ++it ){
4018         NMEA_Msg_Container *pc = it->second;
4019         delete pc;
4020     }
4021     NMEA_Msg_Hash.clear();
4022 
4023 
4024     NMEALogWindow::Shutdown();
4025 
4026     g_MainToolbar = NULL;
4027     g_bTempShowMenuBar = false;
4028 
4029 
4030     #define THREAD_WAIT_SECONDS  5
4031 #ifdef ocpnUSE_GL
4032     // The last thing we do is finish the compression threads.
4033     // This way the main window is already invisible and to the user
4034     // it appears to have finished rather than hanging for several seconds
4035     // while the compression threads exit
4036     if(g_bopengl && g_glTextureManager && g_glTextureManager->GetRunningJobCount()){
4037         g_glTextureManager->ClearAllRasterTextures();
4038 
4039         wxLogMessage(_T("Starting compressor pool drain"));
4040         wxDateTime now = wxDateTime::Now();
4041         time_t stall = now.GetTicks();
4042         time_t end = stall + THREAD_WAIT_SECONDS;
4043 
4044         int n_comploop = 0;
4045         while(stall < end ) {
4046             wxDateTime later = wxDateTime::Now();
4047             stall = later.GetTicks();
4048 
4049             wxString msg;
4050             msg.Printf(_T("Time: %d  Job Count: %d"), n_comploop, g_glTextureManager->GetRunningJobCount());
4051             wxLogMessage(msg);
4052             if(!g_glTextureManager->GetRunningJobCount())
4053                 break;
4054             wxYield();
4055             wxSleep(1);
4056         }
4057 
4058         wxString fmsg;
4059         fmsg.Printf(_T("Finished compressor pool drain..Time: %d  Job Count: %d"),
4060                     n_comploop, g_glTextureManager->GetRunningJobCount());
4061         wxLogMessage(fmsg);
4062     }
4063     delete g_glTextureManager;
4064 #endif
4065 
4066     this->Destroy();
4067     gFrame = NULL;
4068 
4069 #ifdef __OCPN__ANDROID__
4070 #ifndef USE_ANDROID_GLES2
4071     qDebug() << "Calling OnExit()";
4072     wxTheApp->OnExit();
4073 #endif
4074 #endif
4075 
4076 }
4077 
OnMove(wxMoveEvent & event)4078 void MyFrame::OnMove( wxMoveEvent& event )
4079 {
4080     // ..For each canvas...
4081     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
4082         ChartCanvas *cc = g_canvasArray.Item(i);
4083         if( cc && cc->GetToolbar()) {
4084             cc->GetToolbar()->RePosition();
4085             cc->ReloadVP();
4086         }
4087         if(cc)
4088             cc->SetMUIBarPosition();
4089     }
4090 
4091     UpdateGPSCompassStatusBoxes( );
4092 
4093     if( console && console->IsShown() )
4094         PositionConsole();
4095 
4096     //  If global toolbar is shown, reposition it...
4097     if( g_MainToolbar){
4098         g_MainToolbar->RePosition();
4099         g_MainToolbar->Realize();
4100     }
4101 
4102     PositionIENCToolbar();
4103 
4104 //    Somehow, this method does not work right on Windows....
4105 //      g_nframewin_posx = event.GetPosition().x;
4106 //      g_nframewin_posy = event.GetPosition().y;
4107 
4108     g_nframewin_posx = GetPosition().x;
4109     g_nframewin_posy = GetPosition().y;
4110 }
4111 
ProcessCanvasResize(void)4112 void MyFrame::ProcessCanvasResize( void )
4113 {
4114     UpdateGPSCompassStatusBoxes( true );
4115 
4116     if( console && console->IsShown() )
4117         PositionConsole();
4118 
4119     PositionIENCToolbar();
4120 
4121 #ifndef __OCPN__ANDROID__
4122     TriggerRecaptureTimer();
4123 #endif
4124 }
4125 
TriggerRecaptureTimer()4126 void MyFrame::TriggerRecaptureTimer()
4127 {
4128     m_recaptureTimer.Start(1000, wxTIMER_ONE_SHOT);     //One second seems enough, on average
4129 }
4130 
OnRecaptureTimer(wxTimerEvent & event)4131 void MyFrame::OnRecaptureTimer(wxTimerEvent &event)
4132 {
4133     Raise();
4134 }
4135 
4136 
4137 
4138 
4139 
SetCanvasSizes(wxSize frameSize)4140 void MyFrame::SetCanvasSizes( wxSize frameSize )
4141 {
4142     if(!g_canvasArray.GetCount())
4143         return;
4144 
4145 #if 0
4146     int cccw = frameSize.x;
4147     int ccch = frameSize.y;
4148 #endif
4149 
4150     // .. for each canvas...
4151     switch( g_canvasConfig){
4152         default:
4153         case 0:
4154 #if 0
4155             cc = g_canvasArray.Item(0);
4156             if( cc ) {
4157                 cc->GetSize( &cur_width, &cur_height );
4158                 if( ( cur_width != cccw ) || ( cur_height != ccch ) ) {
4159                     if( g_pauimgr->GetPane( cc ).IsOk() )
4160                         g_pauimgr->GetPane( cc ).BestSize( cccw, ccch );
4161                     else
4162                         cc->SetSize( 0, 0, cccw, ccch );
4163                 }
4164             }
4165 #endif
4166             break;
4167 
4168 
4169         case 1:
4170 #if 0
4171             cc = g_canvasArray.Item(1);
4172             if( cc ) {
4173                int ccw = g_canvasConfigArray.Item(1)->canvasSize.x;
4174                int cch = g_canvasConfigArray.Item(1)->canvasSize.y;
4175 
4176                ccw = wxMin(ccw, cccw * 8 / 10);
4177                ccw = wxMax(ccw, cccw * 2 / 10);
4178                if(cccw < 100)
4179                    ccw = 20;
4180 
4181                g_canvasConfigArray.Item(1)->canvasSize = wxSize(ccw, cch);
4182 //               g_pauimgr->GetPane(cc).MinSize(cccw * 2 / 10, ccch);
4183 
4184 
4185 #if 1 //ndef __WXMSW__
4186                //wxAUI hack: This is needed to explicietly set a docked pane size
4187                //Set MinSize to desired value, then call wxAuiPaneInfo::Fixed() to apply it
4188                 g_pauimgr->GetPane(cc).MinSize(ccw, cch);
4189                 g_pauimgr->GetPane(cc).Fixed();
4190                 g_pauimgr->Update();
4191 
4192                 //now make resizable again
4193                 g_pauimgr->GetPane(cc).Resizable();
4194                 ///g_pauimgr->GetPane(cc).MinSize(cccw * 2 / 10, ccch);
4195                 //g_pauimgr->Update();  //Deferred
4196                 //g_pauimgr->GetPane( cc ).BestSize( ccw, cch );
4197 #endif
4198             }
4199 #endif
4200 
4201             break;
4202 
4203     }
4204 
4205 }
4206 
OnIconize(wxIconizeEvent & event)4207 void MyFrame::OnIconize( wxIconizeEvent& event )
4208 {
4209 #ifdef __WXOSX__
4210     if(g_MainToolbar) {
4211         g_MainToolbar->Show(!event.IsIconized());
4212     }
4213     if(g_iENCToolbar) {
4214         g_iENCToolbar->Show(!event.IsIconized());
4215     }
4216     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++) {
4217         ChartCanvas *cc = g_canvasArray.Item(i);
4218         if(cc && cc->GetMUIBar()) {
4219             cc->GetMUIBar()->Show(!event.IsIconized());
4220         }
4221     }
4222 #endif
4223 }
4224 
OnSize(wxSizeEvent & event)4225 void MyFrame::OnSize( wxSizeEvent& event )
4226 {
4227     ODoSetSize();
4228 }
4229 
ODoSetSize(void)4230 void MyFrame::ODoSetSize( void )
4231 {
4232     int x, y;
4233     GetClientSize( &x, &y );
4234 //      Resize the children
4235 
4236         if( m_pStatusBar != NULL ) {
4237             m_StatusBarFieldCount = g_Platform->GetStatusBarFieldCount();
4238             int currentCount = m_pStatusBar->GetFieldsCount();
4239             if(currentCount != m_StatusBarFieldCount){
4240                 if( (currentCount > 0) && (currentCount < 7)){
4241 
4242                     // reset the widths very small to avoid auto-resizing of the frame
4243                     // The sizes will be reset later in this method
4244                     int widths[] = { 2,2,2,2,2,2 };
4245                     m_pStatusBar->SetStatusWidths( currentCount, widths );
4246                 }
4247 
4248             m_pStatusBar->SetFieldsCount(m_StatusBarFieldCount);
4249             }
4250 
4251             if(m_StatusBarFieldCount){
4252 
4253                 //  If the status bar layout is "complex", meaning more than two columns,
4254                 //  then use custom crafted relative widths for the fields.
4255                 //  Otherwise, just split the frame client width into equal spaces
4256 
4257                 if(m_StatusBarFieldCount > 2){
4258                     int widths[] = { -6, -5, -5, -6, -4 };
4259                     m_pStatusBar->SetStatusWidths( m_StatusBarFieldCount, widths );
4260                 }
4261                 else if(m_StatusBarFieldCount == 2){
4262                     int cwidth = x * 90 / 100;
4263                     int widths[] = { 100, 100 };
4264                     widths[0] = cwidth * 6.4 / 10.0;
4265                     widths[1] = cwidth * 3.6 /  10.0;
4266                     m_pStatusBar->SetStatusWidths( m_StatusBarFieldCount, widths );
4267                 }
4268                 else{
4269                     int widths[] = { 100, 100 };
4270                     widths[0] = x * 90 / 100 ;
4271                     m_pStatusBar->SetStatusWidths( m_StatusBarFieldCount, widths );
4272                 }
4273 
4274                 int styles[] = { wxSB_FLAT, wxSB_FLAT, wxSB_FLAT, wxSB_FLAT, wxSB_FLAT, wxSB_FLAT };
4275                 m_pStatusBar->SetStatusStyles( m_StatusBarFieldCount, styles );
4276 
4277                 wxString sogcog( _T("SOG --- ") + getUsrSpeedUnit() + + _T("     ") + _T(" COG ---\u00B0") );
4278                 m_pStatusBar->SetStatusText( sogcog, STAT_FIELD_SOGCOG );
4279 
4280             }
4281         }
4282 
4283 
4284 
4285     if( m_pStatusBar ) {
4286         //  Maybe resize the font so the text fits in the boxes
4287 
4288         wxRect stat_box;
4289         m_pStatusBar->GetFieldRect( 0, stat_box );
4290         // maximum size is 1/28 of the box width, or the box height - whicever is less
4291         int max_font_size = wxMin( (stat_box.width / 28), (stat_box.height) );
4292 
4293         wxFont sys_font = *wxNORMAL_FONT;
4294         int try_font_size = sys_font.GetPointSize();
4295 
4296 #ifdef __WXOSX__
4297         int min_font_size = 10; // much less than 10pt is unreadably small on OS X
4298         try_font_size += 1;     // default to 1pt larger than system UI font
4299 #else
4300         int min_font_size = 7;  // on Win/Linux the text does not shrink quite so fast
4301         try_font_size += 2;     // default to 2pt larger than system UI font
4302 #endif
4303 
4304         // get the user's preferred font, or if none set then the system default with the size overridden
4305         wxFont* statusBarFont = FontMgr::Get().GetFont( _("StatusBar"), try_font_size );
4306         int font_size = statusBarFont->GetPointSize();
4307 
4308         font_size = wxMin( font_size, max_font_size );  // maximum to fit in the statusbar boxes
4309         font_size = wxMax( font_size, min_font_size );  // minimum to stop it being unreadable
4310 
4311 #ifdef __OCPN__ANDROID__
4312         font_size = statusBarFont->GetPointSize();
4313 #endif
4314 
4315         wxFont *pstat_font = FontMgr::Get().FindOrCreateFont(font_size, statusBarFont->GetFamily(),
4316             statusBarFont->GetStyle(), statusBarFont->GetWeight(), false, statusBarFont->GetFaceName());
4317 
4318         int min_height = stat_box.height;
4319 
4320         m_pStatusBar->SetFont( *pstat_font );
4321         m_pStatusBar->SetForegroundColour(FontMgr::Get().GetFontColor(_("StatusBar")));
4322 #ifdef __OCPN__ANDROID__
4323         min_height = ( pstat_font->GetPointSize() * getAndroidDisplayDensity() ) + 10;
4324         min_height = (min_height>>1) * 2;       // force even number, makes GLCanvas happier...
4325         m_pStatusBar->SetMinHeight( min_height );
4326 //        qDebug() <<"StatusBar min height:" << min_height << "StatusBar font points:" << pstat_font->GetPointSize();
4327 #endif
4328 //        wxString msg;
4329 //        msg.Printf(_T("StatusBar min height: %d    StatusBar font points: %d"), min_height, pstat_font->GetPointSize());
4330 //        wxLogMessage(msg);
4331 
4332     }
4333 
4334     SetCanvasSizes( GetClientSize() );
4335 
4336     // ..For each canvas...
4337     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
4338         ChartCanvas *cc = g_canvasArray.Item(i);
4339         if( cc && cc->GetToolbar()) {
4340             wxSize oldSize = cc->GetToolbar()->GetSize();
4341             cc->GetToolbar()->RePosition();
4342             cc->GetToolbar()->SetGeometry(cc->GetCompass()->IsShown(), cc->GetCompass()->GetRect());
4343             cc->GetToolbar()->Realize();
4344 
4345             if( oldSize != cc->GetToolbar()->GetSize() )
4346                 cc->GetToolbar()->Refresh( false );
4347 
4348             cc->GetToolbar()->RePosition();
4349         }
4350     }
4351 
4352     UpdateGPSCompassStatusBoxes( true );
4353 
4354     if( console )
4355         PositionConsole();
4356 
4357     // .. for each canvas...
4358     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
4359         ChartCanvas *cc = g_canvasArray.Item(i);
4360         if(cc)
4361             cc->FormatPianoKeys();
4362     }
4363 
4364     //  If global toolbar is shown, reposition it...
4365     if( g_MainToolbar){
4366         bool bShow = g_MainToolbar->IsShown();
4367         wxSize szBefore = g_MainToolbar->GetSize();
4368 #ifdef __WXGTK__
4369         // For large vertical size changes on some platforms, it is necessary to hide the toolbar
4370         // in order to correctly set its rounded-rectangle shape
4371         // It will be shown again before exit of this method.
4372         double deltay = g_nframewin_y - GetSize().y;
4373         if((fabs(deltay) > (g_Platform->getDisplaySize().y / 5)))
4374             g_MainToolbar->Hide();
4375 #endif
4376         g_MainToolbar->RePosition();
4377         //g_MainToolbar->SetGeometry(false, wxRect());
4378         g_MainToolbar->SetGeometry(GetPrimaryCanvas()->GetCompass()->IsShown(), GetPrimaryCanvas()->GetCompass()->GetRect());
4379 
4380         g_MainToolbar->Realize();
4381 
4382         if(szBefore != g_MainToolbar->GetSize())
4383             g_MainToolbar->Refresh(true);
4384         g_MainToolbar->Show( bShow);
4385 
4386     }
4387 
4388 //  Update the stored window size
4389     GetSize( &x, &y );
4390     g_nframewin_x = x;
4391     g_nframewin_y = y;
4392 
4393 //  Inform the PlugIns
4394     if( g_pi_manager ) g_pi_manager->SendResizeEventToAllPlugIns( x, y );
4395 
4396 //  Force redraw if in lookahead mode
4397     // TODO is this all right?
4398 //     if( g_bLookAhead ) {
4399 //         DoCOGSet();
4400 //         DoChartUpdate();
4401 //     }
4402 
4403     if( pthumbwin )
4404         pthumbwin->SetMaxSize( GetClientSize() );
4405 
4406     //  Reset the options dialog size logic
4407     options_lastWindowSize = wxSize(0,0);
4408     options_lastWindowPos = wxPoint(0,0);
4409 
4410 #ifdef __OCPN__ANDROID__
4411     // If the options dialog is displayed, this will have the effect of
4412     // raising the dialog above the main and canvas-GUI toolbars.
4413     // If the dialog is not shown, no harm done
4414 
4415     if( !b_inCloseWindow ) {
4416         if(g_options)
4417             g_options->Raise();
4418 
4419         resizeAndroidPersistents();
4420     }
4421 
4422 #endif
4423 
4424     if(g_pauimgr)
4425         g_pauimgr->Update();
4426 
4427 }
4428 
PositionConsole(void)4429 void MyFrame::PositionConsole( void )
4430 {
4431     if( NULL == GetPrimaryCanvas() ) return;
4432     //    Reposition console based on its size and chartcanvas size
4433     int ccx, ccy, ccsx, ccsy, consx, consy;
4434     ChartCanvas *consoleHost = GetPrimaryCanvas();
4435     if(g_canvasConfig > 0)
4436         consoleHost = g_canvasArray[1];
4437 
4438     if(consoleHost){
4439         consoleHost->GetSize( &ccsx, &ccsy );
4440         consoleHost->GetPosition( &ccx, &ccy );
4441     }
4442     else{
4443         GetPrimaryCanvas()->GetSize( &ccsx, &ccsy );
4444         GetPrimaryCanvas()->GetPosition( &ccx, &ccy );
4445     }
4446 
4447     console->GetSize( &consx, &consy );
4448 
4449     int yOffset = 60;
4450 //  TODO    if(g_Compass){
4451 //         if(g_Compass->GetRect().y < 100)        // Compass is is normal upper right position.
4452 //             yOffset = g_Compass->GetRect().y + g_Compass->GetRect().height + 45;
4453 //     }
4454 
4455     wxPoint screen_pos = ClientToScreen( wxPoint( ccx + ccsx - consx - 2, ccy + yOffset ) );
4456     console->Move( screen_pos );
4457 }
4458 
UpdateAllFonts()4459 void MyFrame::UpdateAllFonts()
4460 {
4461     if( console ) {
4462         console->UpdateFonts();
4463         //    Reposition console
4464         PositionConsole();
4465     }
4466 
4467     //  Close and destroy any persistent dialogs, so that new fonts will be utilized
4468     DestroyPersistentDialogs();
4469 
4470     if( pWayPointMan ) pWayPointMan->ClearRoutePointFonts();
4471 
4472     RefreshAllCanvas();
4473 }
4474 
DestroyPersistentDialogs()4475 void MyFrame::DestroyPersistentDialogs()
4476 {
4477     if( g_pais_query_dialog_active ) {
4478         g_pais_query_dialog_active->Hide();
4479         g_pais_query_dialog_active->Destroy();
4480         g_pais_query_dialog_active = NULL;
4481     }
4482 
4483     if( RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog ) {
4484         pRoutePropDialog->Hide();
4485         pRoutePropDialog->Destroy();
4486         pRoutePropDialog = NULL;
4487     }
4488 
4489     if( TrackPropDlg::getInstanceFlag() && pTrackPropDialog ) {
4490         pTrackPropDialog->Hide();
4491         pTrackPropDialog->Destroy();
4492         pTrackPropDialog = NULL;
4493     }
4494 
4495     if( g_pMarkInfoDialog ) {
4496         g_pMarkInfoDialog->Hide();
4497         g_pMarkInfoDialog->Destroy();
4498         g_pMarkInfoDialog = NULL;
4499     }
4500 
4501     if( g_pObjectQueryDialog ) {
4502         g_pObjectQueryDialog->Hide();
4503         g_pObjectQueryDialog->Destroy();
4504         g_pObjectQueryDialog = NULL;
4505     }
4506 
4507 }
4508 
4509 
RefreshGroupIndices(void)4510 void MyFrame::RefreshGroupIndices( void )
4511 {
4512     // ..For each canvas...
4513     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
4514         ChartCanvas *cc = g_canvasArray.Item(i);
4515         if(cc)
4516             cc->canvasRefreshGroupIndex();
4517     }
4518 }
4519 
OnToolLeftClick(wxCommandEvent & event)4520 void MyFrame::OnToolLeftClick( wxCommandEvent& event )
4521 {
4522     if(g_MainToolbar)
4523         g_MainToolbar->HideTooltip();
4524 
4525     switch( event.GetId() ){
4526         case ID_MENU_SCALE_OUT:
4527             DoStackDelta( GetPrimaryCanvas(), 1 );
4528             DoChartUpdate();
4529             break;
4530 
4531         case ID_MENU_SCALE_IN:
4532             DoStackDelta( GetPrimaryCanvas(), -1 );
4533             DoChartUpdate();
4534             break;
4535 
4536         case ID_MENU_ZOOM_IN:{
4537             if(GetFocusCanvas()){
4538                 GetFocusCanvas()->ZoomCanvas( g_plus_minus_zoom_factor, false );
4539             }
4540             break;
4541         }
4542 
4543         case ID_MENU_ZOOM_OUT:{
4544             if(GetFocusCanvas()){
4545                 GetFocusCanvas()->ZoomCanvas( 1.0 / g_plus_minus_zoom_factor, false );
4546             }
4547             break;
4548         }
4549 
4550         case ID_MENU_ROUTE_NEW: {
4551             if(GetFocusCanvas()){
4552                 if( 0 == GetFocusCanvas()->m_routeState ){
4553                     GetFocusCanvas()->StartRoute();
4554                 }
4555                 else {
4556                     GetFocusCanvas()->FinishRoute();
4557                 }
4558             }
4559             break;
4560         }
4561 
4562         case ID_MENU_TOOL_MEASURE: {
4563             GetPrimaryCanvas()->StartMeasureRoute();
4564             break;
4565         }
4566 
4567         case ID_MENU_MARK_BOAT: {
4568             DropMarker(true);
4569             break;
4570         }
4571 
4572         case ID_MENU_MARK_CURSOR: {
4573             DropMarker(false);
4574             break;
4575         }
4576 
4577         case ID_MENU_NAV_FOLLOW:{
4578             if(gFrame->GetPrimaryCanvas())
4579                 gFrame->GetPrimaryCanvas()->TogglebFollow();
4580             break;
4581         }
4582 
4583         case ID_MENU_CHART_OUTLINES: {
4584             ToggleChartOutlines(GetFocusCanvas());
4585             break;
4586         }
4587 
4588         case ID_MENU_CHART_QUILTING: {
4589             ToggleQuiltMode(GetFocusCanvas());
4590             break;
4591         }
4592 
4593         case ID_MENU_UI_CHARTBAR: {
4594             ToggleChartBar(GetFocusCanvas());
4595             break;
4596         }
4597 
4598         case ID_MENU_ENC_TEXT:
4599         case ID_ENC_TEXT: {
4600             ToggleENCText(GetFocusCanvas());
4601             break;
4602         }
4603         case ID_MENU_ENC_LIGHTS: {
4604             ToggleLights(GetFocusCanvas());
4605             break;
4606         }
4607         case ID_MENU_ENC_SOUNDINGS: {
4608             ToggleSoundings(GetFocusCanvas());
4609             break;
4610         }
4611         case ID_MENU_ENC_ANCHOR: {
4612             ToggleAnchor( GetFocusCanvas() );
4613             break;
4614         }
4615         case ID_MENU_ENC_DATA_QUALITY: {
4616             ToggleDataQuality( GetFocusCanvas() );
4617             break;
4618         }
4619         case ID_MENU_SHOW_NAVOBJECTS : {
4620             ToggleNavobjects( GetFocusCanvas() );
4621             break;
4622         }
4623 
4624         case ID_MENU_AIS_TARGETS: {
4625             ToggleAISDisplay( GetFocusCanvas() );
4626             break;
4627         }
4628          case ID_MENU_AIS_MOORED_TARGETS: {
4629             g_bHideMoored = !g_bHideMoored;
4630             break;
4631         }
4632          case ID_MENU_AIS_SCALED_TARGETS: {
4633             ToggleAISMinimizeTargets( GetFocusCanvas() );
4634             break;
4635         }
4636 
4637         case ID_MENU_AIS_TARGETLIST: {
4638             if ( GetPrimaryCanvas() ) GetPrimaryCanvas()->ShowAISTargetList();
4639             break;
4640         }
4641 
4642         case ID_MENU_AIS_TRACKS: {
4643             g_bAISShowTracks = !g_bAISShowTracks;
4644             SetMenubarItemState(ID_MENU_AIS_TRACKS, g_bAISShowTracks);
4645             break;
4646         }
4647 
4648         case ID_MENU_AIS_CPADIALOG: {
4649             g_bAIS_CPA_Alert = !g_bAIS_CPA_Alert;
4650             SetMenubarItemState(ID_MENU_AIS_CPADIALOG, g_bAIS_CPA_Alert);
4651             break;
4652         }
4653 
4654         case ID_MENU_AIS_CPASOUND: {
4655             g_bAIS_CPA_Alert_Audio = !g_bAIS_CPA_Alert_Audio;
4656             SetMenubarItemState(ID_MENU_AIS_CPASOUND, g_bAIS_CPA_Alert_Audio);
4657             break;
4658         }
4659 
4660         case wxID_PREFERENCES:
4661         case ID_SETTINGS: {
4662             g_MainToolbar->HideTooltip();
4663             DoSettings();
4664             break;
4665         }
4666 
4667 
4668         case ID_MENU_SETTINGS_BASIC:
4669         {
4670  #ifdef __OCPN__ANDROID__
4671             ///LoadS57();
4672             androidDisableFullScreen();
4673             g_MainToolbar->HideTooltip();
4674             DoAndroidPreferences();
4675  #else
4676             DoSettings();
4677  #endif
4678             break;
4679         }
4680 
4681         case ID_MENU_UI_FULLSCREEN: {
4682             ToggleFullScreen();
4683             break;
4684         }
4685 
4686         case ID_MENU_SHOW_CURRENTS:
4687         {
4688             GetFocusCanvas()->ShowCurrents( !GetFocusCanvas()->GetbShowCurrent() );
4689             GetFocusCanvas()->ReloadVP();
4690             GetFocusCanvas()->Refresh( false );
4691             break;
4692 
4693         }
4694 
4695         case ID_MENU_SHOW_TIDES:
4696         {
4697             GetFocusCanvas()->ShowTides( !GetFocusCanvas()->GetbShowTide() );
4698             GetFocusCanvas()->ReloadVP();
4699             GetFocusCanvas()->Refresh( false );
4700             break;
4701 
4702         }
4703 
4704         case wxID_ABOUT:
4705         case ID_ABOUT: {
4706             g_Platform->DoHelpDialog();
4707             break;
4708         }
4709 
4710         case wxID_HELP: {
4711             g_Platform->LaunchLocalHelp();
4712             break;
4713         }
4714 
4715         case ID_PRINT: {
4716             DoPrint();
4717             break;
4718         }
4719 
4720         case ID_MENU_UI_COLSCHEME:
4721         case ID_COLSCHEME: {
4722             ToggleColorScheme();
4723             break;
4724         }
4725 
4726         case ID_TBEXIT: {
4727             Close();
4728             break;
4729         }
4730 
4731         case ID_MENU_OQUIT: {
4732             Close();
4733             break;
4734         }
4735 
4736         case ID_MENU_ROUTE_MANAGER:
4737         case ID_ROUTEMANAGER: {
4738 
4739             pRouteManagerDialog = RouteManagerDialog::getInstance( this ); // There is one global instance of the Dialog
4740 
4741             if( pRouteManagerDialog->IsShown() )
4742                 pRouteManagerDialog->Hide();
4743             else {
4744                 pRouteManagerDialog->UpdateRouteListCtrl();
4745                 pRouteManagerDialog->UpdateTrkListCtrl();
4746                 pRouteManagerDialog->UpdateWptListCtrl();
4747                 pRouteManagerDialog->UpdateLayListCtrl();
4748 
4749                 pRouteManagerDialog->Show();
4750 
4751             //    Required if RMDialog is not STAY_ON_TOP
4752 #ifdef __WXOSX__
4753                 pRouteManagerDialog->Centre();
4754                 pRouteManagerDialog->Raise();
4755 #endif
4756             }
4757             break;
4758         }
4759 
4760         case ID_MENU_NAV_TRACK:
4761         case ID_TRACK: {
4762             if( !g_bTrackActive ) {
4763                 TrackOn();
4764                 g_bTrackCarryOver = true;
4765             } else {
4766                 TrackOff( true );
4767                 g_bTrackCarryOver = false;
4768                 RefreshAllCanvas( true );
4769             }
4770             break;
4771         }
4772 
4773         case ID_MENU_CHART_NORTHUP:{
4774             SetUpMode(GetPrimaryCanvas(), NORTH_UP_MODE);
4775             break;
4776         }
4777         case ID_MENU_CHART_COGUP:{
4778             SetUpMode(GetPrimaryCanvas(), COURSE_UP_MODE);
4779             break;
4780         }
4781          case ID_MENU_CHART_HEADUP:{
4782             SetUpMode(GetPrimaryCanvas(), HEAD_UP_MODE);
4783             break;
4784         }
4785 
4786         case ID_MENU_MARK_MOB:
4787         case ID_MOB: {
4788             ActivateMOB();
4789             break;
4790         }
4791 
4792 
4793         case ID_MASTERTOGGLE:{
4794             if(g_MainToolbar){
4795             wxString tip = _("Show Toolbar");
4796             if(!g_bmasterToolbarFull)
4797                 tip = _("Hide Toolbar");
4798             if( g_MainToolbar->GetToolbar() )
4799                 g_MainToolbar->GetToolbar()->SetToolShortHelp( ID_MASTERTOGGLE, tip );
4800 
4801 
4802             g_bmasterToolbarFull = !g_bmasterToolbarFull;
4803 
4804 #ifdef __WXOSX__
4805             if(g_bmasterToolbarFull)
4806                 m_nMasterToolCountShown = g_MainToolbar->GetToolCount() - 1;        //TODO disable animation on OSX. Maybe use fade effect?
4807             else
4808                 m_nMasterToolCountShown = 2;
4809 #else
4810             m_nMasterToolCountShown = g_MainToolbar->GetToolShowCount();        // Current state
4811 #endif
4812             ToolbarAnimateTimer.Start( 10, wxTIMER_ONE_SHOT );
4813             }
4814             break;
4815         }
4816 
4817         //  Various command events coming from (usually) other threads,
4818         //  used to control OCPN modes in a thread-safe way.
4819 
4820         case ID_CMD_SELECT_CHART_TYPE:{
4821             selectChartDisplay( event.GetExtraLong(), -1);
4822             break;
4823         }
4824 
4825         case ID_CMD_SELECT_CHART_FAMILY:{
4826             selectChartDisplay( -1, event.GetExtraLong());
4827             break;
4828         }
4829 
4830         case ID_CMD_APPLY_SETTINGS:{
4831             applySettingsString(event.GetString());
4832 #ifdef __OCPN__ANDROID__
4833             androidRestoreFullScreen( );
4834 #endif
4835 
4836             break;
4837         }
4838 
4839         case ID_CMD_NULL_REFRESH:{
4840             Refresh(true);
4841             break;
4842         }
4843 
4844         case ID_CMD_SETVP:{
4845             setStringVP(event.GetString());
4846             break;
4847         }
4848 
4849         case ID_CMD_INVALIDATE:{
4850             InvalidateAllGL();
4851             Refresh(true);
4852             break;
4853         }
4854 
4855         case ID_CMD_POST_JSON_TO_PLUGINS:{
4856 
4857             // Extract the Message ID which is embedded in the JSON string passed in the event
4858             wxJSONValue  root;
4859             wxJSONReader reader;
4860 
4861             int numErrors = reader.Parse( event.GetString(), &root );
4862             if ( numErrors == 0 )  {
4863                 if(root[_T("MessageID")].IsString()){
4864                     wxString MsgID = root[_T("MessageID")].AsString();
4865                     SendPluginMessage( MsgID, event.GetString() );  // Send to all PlugIns
4866                 }
4867             }
4868 
4869             break;
4870         }
4871 
4872         default: {
4873             //        Look for PlugIn tools
4874             //        If found, make the callback.
4875             //        TODO Modify this to allow multiple tools per plugin
4876             if( g_pi_manager ) {
4877                 g_MainToolbar->HideTooltip();
4878 
4879                 ArrayOfPlugInToolbarTools tool_array = g_pi_manager->GetPluginToolbarToolArray();
4880                 for( unsigned int i = 0; i < tool_array.size(); i++ ) {
4881                     PlugInToolbarToolContainer *pttc = tool_array[i];
4882                     if( event.GetId() == pttc->id ) {
4883                         if( pttc->m_pplugin ) pttc->m_pplugin->OnToolbarToolCallback( pttc->id );
4884                         return; // required to prevent event.Skip() being called
4885                     }
4886                 }
4887             }
4888 
4889             // If we didn't handle the event, allow it to bubble up to other handlers.
4890             // This is required for the system menu items (Hide, etc) on OS X to work.
4891             // This must only be called if we did NOT handle the event, otherwise it
4892             // stops the menu items from working on Windows.
4893             event.Skip();
4894 
4895             break;
4896         }
4897 
4898     }         // switch
4899 
4900 }
4901 
SetGlobalToolbarViz(bool viz)4902 bool MyFrame::SetGlobalToolbarViz( bool viz )
4903 {
4904     bool viz_now = g_bmasterToolbarFull;
4905 
4906     g_MainToolbar->HideTooltip();
4907     wxString tip = _("Show Toolbar");
4908     if(viz){
4909         tip = _("Hide Toolbar");
4910         if( g_MainToolbar->GetToolbar() )
4911             g_MainToolbar->GetToolbar()->SetToolShortHelp( ID_MASTERTOGGLE, tip );
4912     }
4913 
4914     bool toggle = false;
4915     if(viz && !g_bmasterToolbarFull)
4916         toggle = true;
4917 
4918     else if(!viz && g_bmasterToolbarFull)
4919         toggle = true;
4920 
4921     if(toggle){
4922             g_bmasterToolbarFull = !g_bmasterToolbarFull;
4923 
4924 #ifdef __WXOSX__
4925             if(g_bmasterToolbarFull)
4926                 m_nMasterToolCountShown = g_MainToolbar->GetToolCount() - 1;        //TODO disable animation on OSX. Maybe use fade effect?
4927             else
4928                 m_nMasterToolCountShown = 2;
4929 #else
4930             m_nMasterToolCountShown = g_MainToolbar->GetToolShowCount();        // Current state
4931 #endif
4932             ToolbarAnimateTimer.Start( 10, wxTIMER_ONE_SHOT );
4933     }
4934 
4935     return viz_now;
4936 }
4937 
4938 
ScheduleSettingsDialog()4939 void MyFrame::ScheduleSettingsDialog()
4940 {
4941     wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
4942     evt.SetId( ID_SETTINGS/*ID_MENU_SETTINGS_BASIC*/ );
4943     GetEventHandler()->AddPendingEvent(evt);
4944 }
4945 
GetFocusCanvas()4946 ChartCanvas *MyFrame::GetFocusCanvas()
4947 {
4948     return g_focusCanvas;
4949 }
4950 
OnToolbarAnimateTimer(wxTimerEvent & event)4951 void MyFrame::OnToolbarAnimateTimer( wxTimerEvent& event )
4952 {
4953     if(g_bmasterToolbarFull){
4954         if(m_nMasterToolCountShown < (int)g_MainToolbar->GetToolCount()){
4955             m_nMasterToolCountShown++;
4956             g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
4957             g_MainToolbar->Realize();
4958 
4959             ToolbarAnimateTimer.Start( 20, wxTIMER_ONE_SHOT );
4960         }
4961         else{
4962             //  One last "Realize()" to establish the final toolbar shape
4963             g_MainToolbar->GetToolbar()->InvalidateBitmaps();
4964             g_MainToolbar->Realize();
4965             g_MainToolbar->Show();
4966         }
4967     }
4968     else{
4969         if(m_nMasterToolCountShown > 1){
4970             m_nMasterToolCountShown--;
4971             g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
4972             g_MainToolbar->Realize();
4973             ToolbarAnimateTimer.Start( 10, wxTIMER_ONE_SHOT );
4974         }
4975         else{
4976             g_MainToolbar->GetToolbar()->InvalidateBitmaps();
4977             g_MainToolbar->Realize();
4978             g_MainToolbar->Show();
4979         }
4980     }
4981 }
4982 
4983 
InvalidateAllGL()4984 void MyFrame::InvalidateAllGL()
4985 {
4986 #ifdef ocpnUSE_GL
4987     // For each canvas
4988     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
4989         ChartCanvas *cc = g_canvasArray.Item(i);
4990         if(cc){
4991             cc->InvalidateGL();
4992             cc->Refresh();
4993         }
4994     }
4995 #endif
4996 }
4997 
RefreshAllCanvas(bool bErase)4998 void MyFrame::RefreshAllCanvas( bool bErase)
4999 {
5000     // For each canvas
5001     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
5002         ChartCanvas *cc = g_canvasArray.Item(i);
5003         if(cc){
5004             cc->Refresh( bErase );
5005         }
5006     }
5007 }
5008 
5009 
SetAISDisplayStyle(ChartCanvas * cc,int StyleIndx)5010 void MyFrame::SetAISDisplayStyle(ChartCanvas *cc, int StyleIndx)
5011 {
5012     cc->SetAISCanvasDisplayStyle(StyleIndx);
5013 
5014     UpdateGlobalMenuItems();
5015     ReloadAllVP();
5016 }
5017 
setStringVP(wxString VPS)5018 void MyFrame::setStringVP(wxString VPS)
5019 {
5020     ChartCanvas *cc = GetPrimaryCanvas();
5021 
5022     if(!cc)
5023         return;
5024 
5025     wxStringTokenizer tkz(VPS, _T(";"));
5026 
5027     wxString token = tkz.GetNextToken();
5028     double lat = gLat;
5029     token.ToDouble(&lat);
5030 
5031     token = tkz.GetNextToken();
5032     double lon = gLon;
5033     token.ToDouble(&lon);
5034 
5035     token = tkz.GetNextToken();
5036     double scale_ppm = cc->GetVP().view_scale_ppm;
5037     token.ToDouble(&scale_ppm);
5038 
5039     cc->SetViewPoint( lat, lon, scale_ppm, 0, cc->GetVPRotation() );
5040 
5041 }
5042 
DoSettings()5043 void MyFrame::DoSettings()
5044 {
5045     if (g_boptionsactive)
5046         return;
5047 
5048     bool bnewtoolbar = !( DoOptionsDialog() == 0 );
5049 
5050     //              Apply various system settings
5051     ApplyGlobalSettings( bnewtoolbar );
5052 
5053     if( g_MainToolbar )
5054         g_MainToolbar->RefreshFadeTimer();
5055 
5056         // ..For each canvas...
5057     bool b_loadHarmonics = false;
5058     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
5059         ChartCanvas *cc = g_canvasArray.Item(i);
5060         if(cc){
5061             if( cc->GetbShowCurrent() || cc->GetbShowTide() )
5062                 b_loadHarmonics = true;
5063         }
5064     }
5065     if( b_loadHarmonics )
5066         LoadHarmonics();
5067 
5068     //  The chart display options may have changed, especially on S57 ENC,
5069     //  So, flush the cache and redraw
5070     ReloadAllVP();
5071 
5072 }
5073 
ToggleChartBar(ChartCanvas * cc)5074 void MyFrame::ToggleChartBar( ChartCanvas *cc)
5075 {
5076     g_bShowChartBar = !g_bShowChartBar;
5077 
5078     if(g_bShowChartBar)
5079         cc->m_brepaint_piano = true;
5080 
5081     cc->ReloadVP(); // needed to set VP.pix_height
5082     Refresh();
5083 
5084     if(g_bShowChartBar) {
5085         DoChartUpdate();
5086         UpdateControlBar(cc);
5087     }
5088 
5089     SetMenubarItemState( ID_MENU_UI_CHARTBAR, g_bShowChartBar );
5090 }
5091 
ToggleColorScheme()5092 void MyFrame::ToggleColorScheme()
5093 {
5094     static bool lastIsNight;
5095     ColorScheme s = GetColorScheme();
5096     int is = (int) s;
5097     is++;
5098     if (lastIsNight && is == 3)         // Back from step 3
5099         { is = 1; lastIsNight = false; }//      Goto to Day
5100     if (lastIsNight) is = 2;            // Back to Dusk on step 3
5101     if ( is == 3 ) lastIsNight = true;  // Step 2 Night
5102     s = (ColorScheme) is;
5103     if (s == N_COLOR_SCHEMES) s = GLOBAL_COLOR_SCHEME_RGB;
5104 
5105     SetAndApplyColorScheme( s );
5106 }
5107 
ToggleFullScreen()5108 void MyFrame::ToggleFullScreen()
5109 {
5110     bool to = !IsFullScreen();
5111     long style = wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION;; // | wxFULLSCREEN_NOMENUBAR;
5112 
5113     ShowFullScreen( to, style );
5114     UpdateAllToolbars( global_color_scheme );
5115     SurfaceAllCanvasToolbars();
5116     UpdateControlBar( GetPrimaryCanvas());
5117     Layout();
5118     TriggerRecaptureTimer();
5119 }
5120 
ActivateMOB(void)5121 void MyFrame::ActivateMOB( void )
5122 {
5123     //    The MOB point
5124     wxDateTime mob_time = wxDateTime::Now();
5125     wxString mob_label( _( "MAN OVERBOARD" ) );
5126     mob_label += _(" at ");
5127     mob_label += mob_time.FormatTime();
5128     mob_label += _(" on ");
5129     mob_label += mob_time.FormatISODate();
5130 
5131     RoutePoint *pWP_MOB = new RoutePoint( gLat, gLon, _T ( "mob" ), mob_label, wxEmptyString );
5132     pWP_MOB->m_bKeepXRoute = true;
5133     pWP_MOB->m_bIsolatedMark = true;
5134     pWP_MOB->SetWaypointArrivalRadius( -1.0 ); // Negative distance is code to signal "Never Arrive"
5135     pWP_MOB->SetUseSca(false); //Do not use scaled hiding for MOB
5136     pSelect->AddSelectableRoutePoint( gLat, gLon, pWP_MOB );
5137     pConfig->AddNewWayPoint( pWP_MOB, -1 );       // use auto next num
5138 
5139 
5140     if( bGPSValid && !std::isnan(gCog) && !std::isnan(gSog) ) {
5141         //    Create a point that is one mile along the present course
5142         double zlat, zlon;
5143         ll_gc_ll( gLat, gLon, gCog, 1.0, &zlat, &zlon );
5144 
5145         RoutePoint *pWP_src = new RoutePoint( zlat, zlon, g_default_wp_icon,
5146                 wxString( _( "1.0 NM along COG" ) ), wxEmptyString );
5147         pSelect->AddSelectableRoutePoint( zlat, zlon, pWP_src );
5148 
5149         Route *temp_route = new Route();
5150         pRouteList->Append( temp_route );
5151 
5152         temp_route->AddPoint( pWP_src );
5153         temp_route->AddPoint( pWP_MOB );
5154 
5155         pSelect->AddSelectableRouteSegment( gLat, gLon, zlat, zlon, pWP_src, pWP_MOB, temp_route );
5156 
5157         temp_route->m_RouteNameString = _("Temporary MOB Route");
5158         temp_route->m_RouteStartString = _("Assumed 1 Mile Point");
5159         ;
5160         temp_route->m_RouteEndString = mob_label;
5161 
5162         temp_route->m_bDeleteOnArrival = false;
5163 
5164         temp_route->SetRouteArrivalRadius( -1.0 );                    // never arrives
5165 
5166         if( g_pRouteMan->GetpActiveRoute() ) g_pRouteMan->DeactivateRoute();
5167         g_pRouteMan->ActivateRoute( temp_route, pWP_MOB );
5168 
5169         wxJSONValue v;
5170         v[_T("GUID")] = temp_route->m_GUID;
5171         wxString msg_id( _T("OCPN_MAN_OVERBOARD") );
5172         g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
5173     }
5174 
5175     if(RouteManagerDialog::getInstanceFlag()){
5176     if( pRouteManagerDialog && pRouteManagerDialog->IsShown() ) {
5177         pRouteManagerDialog->UpdateRouteListCtrl();
5178         pRouteManagerDialog->UpdateWptListCtrl();
5179     }
5180     }
5181 
5182     InvalidateAllGL();
5183     RefreshAllCanvas( false );
5184 
5185     wxString mob_message( _( "MAN OVERBOARD" ) );
5186     mob_message += _(" Time: ");
5187     mob_message += mob_time.Format();
5188     mob_message += _("  Position: ");
5189     mob_message += toSDMM( 1, gLat );
5190     mob_message += _T("   ");
5191     mob_message += toSDMM( 2, gLon );
5192     wxLogMessage( mob_message );
5193 
5194 }
TrackOn(void)5195 void MyFrame::TrackOn( void )
5196 {
5197     g_bTrackActive = true;
5198     g_pActiveTrack = new ActiveTrack();
5199 
5200     pTrackList->Append( g_pActiveTrack );
5201     if(pConfig)
5202         pConfig->AddNewTrack( g_pActiveTrack );
5203 
5204     g_pActiveTrack->Start();
5205 
5206     SetMasterToolbarItemState( ID_TRACK, g_bTrackActive );
5207     if( g_MainToolbar )
5208         g_MainToolbar->SetToolShortHelp( ID_TRACK, _("Disable Tracking") );
5209 
5210     SetMenubarItemState( ID_MENU_NAV_TRACK, g_bTrackActive );
5211 
5212     #ifdef __OCPN__ANDROID__
5213     androidSetTrackTool(true);
5214     #endif
5215 
5216     if(RouteManagerDialog::getInstanceFlag()){
5217         if( pRouteManagerDialog && pRouteManagerDialog->IsShown() ){
5218         pRouteManagerDialog->UpdateTrkListCtrl();
5219         pRouteManagerDialog->UpdateRouteListCtrl();
5220     }
5221     }
5222 
5223     wxJSONValue v;
5224     wxDateTime now;
5225     now = now.Now().ToUTC();
5226     wxString name = g_pActiveTrack->GetName();
5227     if(name.IsEmpty())
5228     {
5229         TrackPoint *tp = g_pActiveTrack->GetPoint( 0 );
5230         if( tp->GetCreateTime().IsValid() )
5231             name = tp->GetCreateTime().FormatISODate() + _T(" ") + tp->GetCreateTime().FormatISOTime();
5232         else
5233             name = _("(Unnamed Track)");
5234     }
5235     v[_T("Name")] = name;
5236     v[_T("GUID")] = g_pActiveTrack->m_GUID;
5237     wxString msg_id( _T("OCPN_TRK_ACTIVATED") );
5238     g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
5239     g_FlushNavobjChangesTimeout = 30;           //Every thirty seconds, consider flushing navob changes
5240 }
5241 
TrackOff(bool do_add_point)5242 Track *MyFrame::TrackOff( bool do_add_point )
5243 {
5244     Track *return_val = g_pActiveTrack;
5245 
5246     if( g_pActiveTrack )
5247     {
5248         wxJSONValue v;
5249         wxString msg_id( _T("OCPN_TRK_DEACTIVATED") );
5250         v[_T("GUID")] = g_pActiveTrack->m_GUID;
5251         g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
5252 
5253         g_pActiveTrack->Stop( do_add_point );
5254 
5255         if( g_pActiveTrack->GetnPoints() < 2 ) {
5256             g_pRouteMan->DeleteTrack( g_pActiveTrack );
5257             return_val = NULL;
5258         }
5259         else {
5260             if( g_bTrackDaily ) {
5261                 Track *pExtendTrack = g_pActiveTrack->DoExtendDaily();
5262                 if(pExtendTrack) {
5263                     g_pRouteMan->DeleteTrack( g_pActiveTrack );
5264                     return_val = pExtendTrack;
5265                 }
5266             }
5267         }
5268     }
5269 
5270     g_pActiveTrack = NULL;
5271 
5272     g_bTrackActive = false;
5273 
5274     if(RouteManagerDialog::getInstanceFlag()){
5275         if( pRouteManagerDialog && pRouteManagerDialog->IsShown() ){
5276             pRouteManagerDialog->UpdateTrkListCtrl();
5277             pRouteManagerDialog->UpdateRouteListCtrl();
5278         }
5279     }
5280 
5281     SetMasterToolbarItemState( ID_TRACK, g_bTrackActive );
5282     if( g_MainToolbar )
5283         g_MainToolbar->SetToolShortHelp( ID_TRACK, _("Enable Tracking") );
5284     SetMenubarItemState( ID_MENU_NAV_TRACK, g_bTrackActive );
5285 
5286     #ifdef __OCPN__ANDROID__
5287     androidSetTrackTool(false);
5288     #endif
5289 
5290     g_FlushNavobjChangesTimeout = 600;           //Revert to checking/flushing navob changes every 5 minutes
5291 
5292     return return_val;
5293 }
5294 
ShouldRestartTrack(void)5295 bool MyFrame::ShouldRestartTrack( void )
5296 {
5297     if( !g_pActiveTrack || !g_bTrackDaily)
5298         return false;
5299     time_t now = wxDateTime::Now().GetTicks();
5300     time_t today = wxDateTime::Today().GetTicks();
5301     int rotate_at = 0;
5302     switch( g_track_rotate_time_type )
5303     {
5304         case TIME_TYPE_LMT:
5305             rotate_at = g_track_rotate_time + wxRound(gLon * 3600. / 15.);
5306             break;
5307         case TIME_TYPE_COMPUTER:
5308             rotate_at = g_track_rotate_time;
5309             break;
5310         case TIME_TYPE_UTC:
5311             int utc_offset = wxDateTime::Now().GetTicks() - wxDateTime::Now().ToUTC().GetTicks();
5312             rotate_at = g_track_rotate_time + utc_offset;
5313             break;
5314     }
5315     if( rotate_at > 86400 )
5316         rotate_at -= 86400;
5317     else if (rotate_at < 0 )
5318         rotate_at += 86400;
5319     if( now >= m_last_track_rotation_ts + 86400 - 3600 &&
5320         now - today >= rotate_at )
5321     {
5322         if( m_last_track_rotation_ts == 0 )
5323         {
5324             if( now - today > rotate_at)
5325                 m_last_track_rotation_ts = today + rotate_at;
5326             else
5327                 m_last_track_rotation_ts = today + rotate_at - 86400;
5328             return false;
5329         }
5330         m_last_track_rotation_ts = now;
5331         return true;
5332     }
5333     return false;
5334 }
5335 
TrackDailyRestart(void)5336 void MyFrame::TrackDailyRestart( void )
5337 {
5338     if( !g_pActiveTrack )
5339         return;
5340 
5341     Track *pPreviousTrack = TrackOff( true );
5342     TrackOn();
5343 
5344     //  Set the restarted track's current state such that the current track point's attributes match the
5345     //  attributes of the last point of the track that was just stopped at midnight.
5346 
5347     if( pPreviousTrack ) {
5348         TrackPoint *pMidnightPoint = pPreviousTrack->GetLastPoint();
5349         g_pActiveTrack->AdjustCurrentTrackPoint(pMidnightPoint);
5350     }
5351 
5352     if(RouteManagerDialog::getInstanceFlag()){
5353     if( pRouteManagerDialog && pRouteManagerDialog->IsShown() ) {
5354         pRouteManagerDialog->UpdateTrkListCtrl();
5355         pRouteManagerDialog->UpdateRouteListCtrl();
5356     }
5357 }
5358 }
5359 
SetUpMode(ChartCanvas * cc,int mode)5360 void MyFrame::SetUpMode( ChartCanvas *cc, int mode )
5361 {
5362     if(cc){
5363         cc->SetUpMode( mode );
5364 
5365         SetMenubarItemState( ID_MENU_CHART_COGUP, mode == COURSE_UP_MODE );
5366         SetMenubarItemState( ID_MENU_CHART_NORTHUP, mode == NORTH_UP_MODE );
5367         SetMenubarItemState( ID_MENU_CHART_HEADUP, mode == HEAD_UP_MODE );
5368 
5369         if(m_pMenuBar)
5370             m_pMenuBar->SetLabel( ID_MENU_CHART_NORTHUP, _("North Up Mode") );
5371     }
5372 }
5373 
5374 
ToggleENCText(ChartCanvas * cc)5375 void MyFrame::ToggleENCText( ChartCanvas *cc )
5376 {
5377     cc->SetShowENCText( !cc->GetShowENCText());
5378 
5379     SetMenubarItemState( ID_MENU_ENC_TEXT, cc->GetShowENCText() );
5380 
5381 //     if(g_pi_manager)
5382 //         g_pi_manager->SendConfigToAllPlugIns();
5383 
5384     ReloadAllVP();
5385 }
5386 
SetENCDisplayCategory(ChartCanvas * cc,enum _DisCat nset)5387 void MyFrame::SetENCDisplayCategory( ChartCanvas *cc, enum _DisCat nset )
5388 {
5389     if( ps52plib ) {
5390 
5391        if(cc){
5392             cc->SetENCDisplayCategory(nset);
5393 
5394             UpdateGlobalMenuItems();
5395 
5396 /*            if(g_pi_manager)
5397                 g_pi_manager->SendConfigToAllPlugIns();
5398  */
5399        ReloadAllVP();
5400        }
5401     }
5402 }
5403 
ToggleSoundings(ChartCanvas * cc)5404 void MyFrame::ToggleSoundings( ChartCanvas *cc )
5405 {
5406     cc->SetShowENCDepth( !cc->GetShowENCDepth());
5407 
5408     SetMenubarItemState( ID_MENU_ENC_SOUNDINGS, cc->GetShowENCDepth() );
5409 
5410 //     if(g_pi_manager)
5411 //         g_pi_manager->SendConfigToAllPlugIns();
5412 
5413     ReloadAllVP();
5414 }
5415 
ToggleLights(ChartCanvas * cc)5416 bool MyFrame::ToggleLights( ChartCanvas *cc )
5417 {
5418     cc->SetShowENCLights( !cc->GetShowENCLights());
5419 
5420     SetMenubarItemState( ID_MENU_ENC_LIGHTS, cc->GetShowENCLights() );
5421 
5422     if(g_pi_manager)
5423         g_pi_manager->SendS52ConfigToAllPlugIns( true );
5424 
5425     ReloadAllVP();
5426 
5427     return true;
5428 }
5429 
5430 #if 0
5431 void MyFrame::ToggleRocks( void )
5432 {
5433     if( ps52plib ) {
5434         int vis =  0;
5435         // Need to loop once for UWTROC, which is our "master", then for
5436         // other categories, since order is unknown?
5437         for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
5438             OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
5439             if( !strncmp( pOLE->OBJLName, "UWTROC", 6 ) ) {
5440                 pOLE->nViz = !pOLE->nViz;
5441                 vis = pOLE->nViz;
5442             }
5443         }
5444         for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
5445             OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
5446             if( !strncmp( pOLE->OBJLName, "OBSTRN", 6 ) ) {
5447                 pOLE->nViz = vis;
5448             }
5449             if( !strncmp( pOLE->OBJLName, "WRECKS", 6 ) ) {
5450                 pOLE->nViz = vis;
5451             }
5452         }
5453         ps52plib->GenerateStateHash();
5454         ReloadAllVP();
5455     }
5456 }
5457 #endif
5458 
ToggleAnchor(ChartCanvas * cc)5459 void MyFrame::ToggleAnchor( ChartCanvas *cc )
5460 {
5461     cc->SetShowENCAnchor( !cc->GetShowENCAnchor());
5462 
5463     SetMenubarItemState( ID_MENU_ENC_ANCHOR, cc->GetShowENCAnchor() );
5464 
5465     if(g_pi_manager)
5466         g_pi_manager->SendS52ConfigToAllPlugIns();
5467 
5468     ReloadAllVP();
5469 }
5470 
ToggleDataQuality(ChartCanvas * cc)5471 void MyFrame::ToggleDataQuality( ChartCanvas *cc )
5472 {
5473     cc->SetShowENCDataQual( !cc->GetShowENCDataQual());
5474 
5475     SetMenubarItemState( ID_MENU_ENC_DATA_QUALITY, cc->GetShowENCDataQual() );
5476 
5477     if(g_pi_manager)
5478         g_pi_manager->SendS52ConfigToAllPlugIns();
5479 
5480     ReloadAllVP();
5481 }
5482 
TogglebFollow(ChartCanvas * cc)5483 void MyFrame::TogglebFollow( ChartCanvas *cc )
5484 {
5485     if( !cc->m_bFollow ) SetbFollow( cc );
5486     else
5487         ClearbFollow( cc );
5488 
5489 }
5490 
ToggleNavobjects(ChartCanvas * cc)5491 void MyFrame::ToggleNavobjects( ChartCanvas *cc )
5492 {
5493     cc->m_bShowNavobjects = !cc->m_bShowNavobjects;
5494     SetMenubarItemState( ID_MENU_SHOW_NAVOBJECTS, cc->m_bShowNavobjects );
5495     cc->Refresh();
5496 }
5497 
ToggleAISDisplay(ChartCanvas * cc)5498 void MyFrame::ToggleAISDisplay( ChartCanvas *cc )
5499 {
5500     cc->SetShowAIS(!cc->GetShowAIS());
5501     SetMenubarItemState( ID_MENU_AIS_TARGETS, cc->GetShowAIS() );
5502     cc->Refresh();
5503 
5504 }
5505 
ToggleAISMinimizeTargets(ChartCanvas * cc)5506 void MyFrame::ToggleAISMinimizeTargets( ChartCanvas *cc )
5507 {
5508     cc->SetAttenAIS(!cc->GetAttenAIS());
5509     SetMenubarItemState( ID_MENU_AIS_SCALED_TARGETS, cc->GetAttenAIS() );
5510     cc->Refresh();
5511 }
5512 
5513 
SetbFollow(ChartCanvas * cc)5514 void MyFrame::SetbFollow( ChartCanvas *cc )
5515 {
5516     JumpToPosition(cc, gLat, gLon, cc->GetVPScale());
5517     cc->m_bFollow = true;
5518 
5519     cc->SetCanvasToolbarItemState( ID_FOLLOW, true );
5520     SetMenubarItemState( ID_MENU_NAV_FOLLOW, true );
5521 
5522     DoChartUpdate();
5523     cc->ReloadVP();
5524     SetChartUpdatePeriod( );
5525 }
5526 
ClearbFollow(ChartCanvas * cc)5527 void MyFrame::ClearbFollow( ChartCanvas *cc )
5528 {
5529     //    Center the screen on the GPS position, for lack of a better place
5530     vLat = gLat;
5531     vLon = gLon;
5532 
5533     cc->m_bFollow = false;
5534     cc->SetCanvasToolbarItemState(ID_FOLLOW, false );
5535     SetMenubarItemState( ID_MENU_NAV_FOLLOW, false );
5536 
5537     DoChartUpdate();
5538     cc->ReloadVP();
5539     SetChartUpdatePeriod();
5540 }
5541 
ToggleChartOutlines(ChartCanvas * cc)5542 void MyFrame::ToggleChartOutlines( ChartCanvas *cc )
5543 {
5544     cc->SetShowOutlines( !cc->GetShowOutlines() );
5545 
5546     RefreshAllCanvas( false );
5547 
5548 #ifdef ocpnUSE_GL         // opengl renders chart outlines as part of the chart this needs a full refresh
5549     if( g_bopengl )
5550         InvalidateAllGL();
5551 #endif
5552 
5553     SetMenubarItemState( ID_MENU_CHART_OUTLINES, cc->GetShowOutlines() );
5554 }
5555 
ToggleTestPause(void)5556 void MyFrame::ToggleTestPause( void )
5557 {
5558     g_bPauseTest = !g_bPauseTest;
5559 }
5560 
SetMenubarItemState(int item_id,bool state)5561 void MyFrame::SetMenubarItemState( int item_id, bool state )
5562 {
5563     if( m_pMenuBar ) {
5564         bool enabled = m_pMenuBar->IsEnabled( item_id );
5565         m_pMenuBar->Enable( item_id, false );
5566         m_pMenuBar->Check( item_id, state );
5567         m_pMenuBar->Enable( item_id, enabled );
5568      }
5569 }
5570 
SetMasterToolbarItemState(int tool_id,bool state)5571 void MyFrame::SetMasterToolbarItemState( int tool_id, bool state )
5572 {
5573     if( g_MainToolbar && g_MainToolbar->GetToolbar() )
5574         g_MainToolbar->GetToolbar()->ToggleTool( tool_id, state );
5575 }
5576 
5577 
SetToolbarItemBitmaps(int tool_id,wxBitmap * bmp,wxBitmap * bmpRollover)5578 void MyFrame::SetToolbarItemBitmaps( int tool_id, wxBitmap *bmp, wxBitmap *bmpRollover )
5579 {
5580     if( g_MainToolbar && g_MainToolbar->GetToolbar() ) {
5581         g_MainToolbar->GetToolbar()->SetToolBitmaps( tool_id, bmp, bmpRollover );
5582         wxRect rect = g_MainToolbar->GetToolbar()->GetToolRect( tool_id );
5583         g_MainToolbar->GetToolbar()->RefreshRect( rect );
5584     }
5585 }
5586 
SetToolbarItemSVG(int tool_id,wxString normalSVGfile,wxString rolloverSVGfile,wxString toggledSVGfile)5587 void MyFrame::SetToolbarItemSVG( int tool_id, wxString normalSVGfile, wxString rolloverSVGfile, wxString toggledSVGfile )
5588 {
5589     if( g_MainToolbar && g_MainToolbar->GetToolbar() ) {
5590         g_MainToolbar->GetToolbar()->SetToolBitmapsSVG( tool_id, normalSVGfile, rolloverSVGfile, toggledSVGfile );
5591         wxRect rect = g_MainToolbar->GetToolbar()->GetToolRect( tool_id );
5592         g_MainToolbar->GetToolbar()->RefreshRect( rect );
5593     }
5594 }
5595 
5596 
ApplyGlobalSettings(bool bnewtoolbar)5597 void MyFrame::ApplyGlobalSettings( bool bnewtoolbar )
5598 {
5599     //             ShowDebugWindow as a wxStatusBar
5600     m_StatusBarFieldCount = g_Platform->GetStatusBarFieldCount();
5601 
5602 #ifdef __WXMSW__
5603     UseNativeStatusBar( false );              // better for MSW, undocumented in frame.cpp
5604 #endif
5605 
5606     if( g_bShowStatusBar ) {
5607         if( !m_pStatusBar ) {
5608             m_pStatusBar = CreateStatusBar( m_StatusBarFieldCount, 0 );   // No wxST_SIZEGRIP needed
5609             ApplyGlobalColorSchemetoStatusBar();
5610         }
5611 
5612     } else {
5613         if( m_pStatusBar ) {
5614             m_pStatusBar->Destroy();
5615             m_pStatusBar = NULL;
5616             SetStatusBar( NULL );
5617         }
5618     }
5619 
5620     wxSize lastOptSize = options_lastWindowSize;
5621     SendSizeEvent();
5622 
5623     BuildMenuBar();
5624 
5625     SendSizeEvent();
5626     options_lastWindowSize = lastOptSize;
5627 
5628 
5629     if( bnewtoolbar )
5630         UpdateAllToolbars( global_color_scheme );
5631 
5632 }
5633 
5634 
_menuText(wxString name,wxString shortcut)5635 wxString _menuText( wxString name, wxString shortcut ) {
5636     wxString menutext;
5637     menutext << name;
5638 #ifndef __OCPN__ANDROID__
5639     menutext << _T("\t") << shortcut;
5640 #endif
5641     return menutext;
5642 }
5643 
BuildMenuBar(void)5644 void MyFrame::BuildMenuBar( void )
5645 {
5646     /*
5647      * Menu Bar - add or remove it if necessary, and update the state of the menu items
5648      */
5649 #ifdef __WXOSX__
5650     bool showMenuBar = true;    // the menu bar is always visible in OS X
5651 #else
5652     bool showMenuBar = g_bShowMenuBar; // get visibility from options
5653 
5654     if (!showMenuBar && g_bTempShowMenuBar)     // allows pressing alt to temporarily show
5655         showMenuBar = true;
5656 #endif
5657 
5658     if ( showMenuBar ) {
5659         //  Menu bar has some dependencies on S52 PLIB, so be sure it is loaded.
5660         LoadS57();
5661 
5662         if ( !m_pMenuBar ) {    // add the menu bar if it is enabled
5663             m_pMenuBar = new wxMenuBar();
5664             RegisterGlobalMenuItems();
5665             SetMenuBar(m_pMenuBar); // must be after RegisterGlobalMenuItems for wx to populate the OS X App Menu correctly
5666         }
5667 
5668         UpdateGlobalMenuItems(); // update the state of the menu items (checkmarks etc)
5669     } else {
5670         if ( m_pMenuBar ) {     // remove the menu bar if it is disabled
5671             SetMenuBar( NULL );
5672             m_pMenuBar->Destroy();
5673             m_pMenuBar = NULL;
5674         }
5675     }
5676 }
5677 
RegisterGlobalMenuItems()5678 void MyFrame::RegisterGlobalMenuItems()
5679 {
5680     if ( !m_pMenuBar ) return;  // if there isn't a menu bar
5681 
5682 
5683     wxMenu *nav_menu = new wxMenu();
5684     nav_menu->AppendCheckItem( ID_MENU_NAV_FOLLOW, _menuText(_("Auto Follow"), _T("Ctrl-A")) );
5685     nav_menu->AppendCheckItem( ID_MENU_NAV_TRACK, _("Enable Tracking") );
5686     nav_menu->AppendSeparator();
5687     nav_menu->AppendRadioItem( ID_MENU_CHART_NORTHUP, _("North Up Mode") );
5688     nav_menu->AppendRadioItem( ID_MENU_CHART_COGUP, _("Course Up Mode") );
5689     nav_menu->AppendRadioItem( ID_MENU_CHART_HEADUP, _("Head Up Mode") );
5690     nav_menu->AppendSeparator();
5691 #ifndef __WXOSX__
5692     nav_menu->Append( ID_MENU_ZOOM_IN, _menuText(_("Zoom In"), _T("+")) );
5693     nav_menu->Append( ID_MENU_ZOOM_OUT, _menuText(_("Zoom Out"), _T("-")) );
5694 #else
5695     nav_menu->Append( ID_MENU_ZOOM_IN, _menuText(_("Zoom In"), _T("Alt-+")) );
5696     nav_menu->Append( ID_MENU_ZOOM_OUT, _menuText(_("Zoom Out"), _T("Alt--")) );
5697 #endif
5698     nav_menu->AppendSeparator();
5699     nav_menu->Append( ID_MENU_SCALE_IN, _menuText(_("Larger Scale Chart"), _T("Ctrl-Left")) );
5700     nav_menu->Append( ID_MENU_SCALE_OUT, _menuText(_("Smaller Scale Chart"), _T("Ctrl-Right")) );
5701 #ifndef __WXOSX__
5702     nav_menu->AppendSeparator();
5703     nav_menu->Append( ID_MENU_OQUIT, _menuText(_("Exit OpenCPN"), _T("Ctrl-Q")) );
5704 #endif
5705     m_pMenuBar->Append( nav_menu, _("&Navigate") );
5706 
5707 
5708     wxMenu* view_menu = new wxMenu();
5709 #ifndef __WXOSX__
5710     view_menu->AppendCheckItem( ID_MENU_CHART_QUILTING, _menuText(_("Enable Chart Quilting"), _T("Q")) );
5711     view_menu->AppendCheckItem( ID_MENU_CHART_OUTLINES, _menuText(_("Show Chart Outlines"), _T("O")) );
5712 #else
5713     view_menu->AppendCheckItem( ID_MENU_CHART_QUILTING, _menuText(_("Enable Chart Quilting"), _T("Alt-Q")) );
5714     view_menu->AppendCheckItem( ID_MENU_CHART_OUTLINES, _menuText(_("Show Chart Outlines"), _T("Alt-O")) );
5715 #endif
5716     view_menu->AppendCheckItem( ID_MENU_UI_CHARTBAR, _menuText(_("Show Chart Bar"), _T("Ctrl-B")) );
5717 
5718     view_menu->AppendSeparator();
5719 #ifndef __WXOSX__
5720     view_menu->AppendCheckItem( ID_MENU_ENC_TEXT, _menuText(_("Show ENC text"), _T("T")) );
5721     view_menu->AppendCheckItem( ID_MENU_ENC_LIGHTS, _menuText(_("Show ENC Lights"), _T("L")) );
5722     view_menu->AppendCheckItem( ID_MENU_ENC_SOUNDINGS, _menuText(_("Show ENC Soundings"), _T("S")) );
5723     view_menu->AppendCheckItem( ID_MENU_ENC_ANCHOR, _menuText(_("Show ENC Anchoring Info"), _T("A")) );
5724     view_menu->AppendCheckItem( ID_MENU_ENC_DATA_QUALITY, _menuText(_("Show ENC Data Quality"), _T("U")) );
5725     view_menu->AppendCheckItem( ID_MENU_SHOW_NAVOBJECTS, _menuText(_("Show Navobjects"), _T("V")) );
5726 #else
5727     view_menu->AppendCheckItem( ID_MENU_ENC_TEXT, _menuText(_("Show ENC text"), _T("Alt-T")) );
5728     view_menu->AppendCheckItem( ID_MENU_ENC_LIGHTS, _menuText(_("Show ENC Lights"), _T("Alt-L")) );
5729     view_menu->AppendCheckItem( ID_MENU_ENC_SOUNDINGS, _menuText(_("Show ENC Soundings"), _T("Alt-S")) );
5730     view_menu->AppendCheckItem( ID_MENU_ENC_ANCHOR, _menuText(_("Show ENC Anchoring Info"), _T("Alt-A")) );
5731     view_menu->AppendCheckItem( ID_MENU_ENC_DATA_QUALITY, _menuText(_("Show ENC Data Quality"), _T("Alt-U")) );
5732     view_menu->AppendCheckItem( ID_MENU_SHOW_NAVOBJECTS, _menuText(_("Show Navobjects"), _T("Alt-V")) );
5733 #endif
5734     view_menu->AppendSeparator();
5735     view_menu->AppendCheckItem( ID_MENU_SHOW_TIDES, _("Show Tides") );
5736     view_menu->AppendCheckItem( ID_MENU_SHOW_CURRENTS, _("Show Currents") );
5737     view_menu->AppendSeparator();
5738 #ifndef __WXOSX__
5739     view_menu->Append( ID_MENU_UI_COLSCHEME, _menuText(_("Change Color Scheme"), _T("C")) );
5740 #else
5741     view_menu->Append( ID_MENU_UI_COLSCHEME, _menuText(_("Change Color Scheme"), _T("Alt-C")) );
5742 #endif
5743 
5744     view_menu->AppendSeparator();
5745 #ifdef __WXOSX__
5746     view_menu->Append(ID_MENU_UI_FULLSCREEN, _menuText(_("Enter Full Screen"), _T("RawCtrl-Ctrl-F")) );
5747 #else
5748     view_menu->Append(ID_MENU_UI_FULLSCREEN, _menuText(_("Enter Full Screen"), _T("F11")) );
5749 #endif
5750     m_pMenuBar->Append( view_menu, _("&View") );
5751 
5752 
5753     wxMenu* ais_menu = new wxMenu();
5754     ais_menu->AppendCheckItem( ID_MENU_AIS_TARGETS, _("Show AIS Targets") );
5755     ais_menu->AppendCheckItem( ID_MENU_AIS_SCALED_TARGETS, _("Attenuate less critical AIS targets") );
5756     ais_menu->AppendSeparator();
5757     ais_menu->AppendCheckItem( ID_MENU_AIS_MOORED_TARGETS, _("Hide Moored AIS Targets") );
5758     ais_menu->AppendCheckItem( ID_MENU_AIS_TRACKS, _("Show AIS Target Tracks") );
5759     ais_menu->AppendCheckItem( ID_MENU_AIS_CPADIALOG, _("Show CPA Alert Dialogs") );
5760     ais_menu->AppendCheckItem( ID_MENU_AIS_CPASOUND, _("Sound CPA Alarms") );
5761     ais_menu->AppendSeparator();
5762     ais_menu->Append( ID_MENU_AIS_TARGETLIST, _("AIS target list") + _T("...") );
5763     m_pMenuBar->Append( ais_menu, _("&AIS") );
5764 
5765     wxMenu* tools_menu = new wxMenu();
5766 #ifndef __WXOSX__
5767     tools_menu->Append( ID_MENU_TOOL_MEASURE, _menuText(_("Measure Distance"), _T("M")) );
5768 #else
5769     tools_menu->Append( ID_MENU_TOOL_MEASURE, _menuText(_("Measure Distance"), _T("Alt-M")) );
5770 #endif
5771 
5772     tools_menu->AppendSeparator();
5773     tools_menu->Append( ID_MENU_ROUTE_MANAGER, _("Route && Mark Manager...") );
5774     tools_menu->Append( ID_MENU_ROUTE_NEW, _menuText(_("Create Route"), _T("Ctrl-R")) );
5775     tools_menu->AppendSeparator();
5776     tools_menu->Append( ID_MENU_MARK_BOAT, _menuText(_("Drop Mark at Boat"), _T("Ctrl-O")) );
5777     tools_menu->Append( ID_MENU_MARK_CURSOR, _menuText(_("Drop Mark at Cursor"), _T("Ctrl-M")) );
5778     tools_menu->AppendSeparator();
5779 #ifdef __WXOSX__
5780     tools_menu->Append( ID_MENU_MARK_MOB, _menuText(_("Drop MOB Marker"), _T("RawCtrl-Space")) ); // NOTE Cmd+Space is reserved for Spotlight
5781     tools_menu->AppendSeparator();
5782     tools_menu->Append( wxID_PREFERENCES, _menuText(_("Preferences") + _T("..."), _T("Ctrl-,")) );
5783 #else
5784     tools_menu->Append( ID_MENU_MARK_MOB, _menuText(_("Drop MOB Marker"), _T("Ctrl-Space")) );
5785     tools_menu->AppendSeparator();
5786     tools_menu->Append( wxID_PREFERENCES, _menuText(_("Options") + _T("..."), _T("Ctrl-,")) );
5787 #endif
5788     m_pMenuBar->Append( tools_menu, _("&Tools") );
5789 
5790 #ifdef __WXOSX__
5791     wxMenu* window_menu = new wxMenu();
5792     m_pMenuBar->Append( window_menu, _("&Window") );
5793 #endif
5794 
5795     wxMenu* help_menu = new wxMenu();
5796     help_menu->Append( wxID_ABOUT, _("About OpenCPN") );
5797     help_menu->Append( wxID_HELP, _("OpenCPN Help") );
5798     m_pMenuBar->Append( help_menu, _("&Help") );
5799 
5800 
5801     // Set initial values for menu check items and radio items
5802     UpdateGlobalMenuItems();
5803 }
5804 
UpdateGlobalMenuItems()5805 void MyFrame::UpdateGlobalMenuItems()
5806 {
5807     if ( !m_pMenuBar ) return;  // if there isn't a menu bar
5808 
5809     m_pMenuBar->FindItem( ID_MENU_NAV_FOLLOW )->Check( GetPrimaryCanvas()->m_bFollow );
5810     m_pMenuBar->FindItem( ID_MENU_CHART_NORTHUP )->Check( GetPrimaryCanvas()->GetUpMode() == NORTH_UP_MODE );
5811     m_pMenuBar->FindItem( ID_MENU_CHART_COGUP )->Check( GetPrimaryCanvas()->GetUpMode() == COURSE_UP_MODE );
5812     m_pMenuBar->FindItem( ID_MENU_CHART_HEADUP )->Check( GetPrimaryCanvas()->GetUpMode() == HEAD_UP_MODE );
5813     m_pMenuBar->FindItem( ID_MENU_NAV_TRACK )->Check( g_bTrackActive );
5814     m_pMenuBar->FindItem( ID_MENU_CHART_OUTLINES )->Check( g_bShowOutlines );
5815     m_pMenuBar->FindItem( ID_MENU_CHART_QUILTING )->Check( g_bQuiltEnable );
5816     m_pMenuBar->FindItem( ID_MENU_UI_CHARTBAR )->Check( g_bShowChartBar );
5817     m_pMenuBar->FindItem( ID_MENU_AIS_TARGETS )->Check( g_bShowAIS );
5818     m_pMenuBar->FindItem( ID_MENU_AIS_MOORED_TARGETS )->Check( g_bHideMoored );
5819     m_pMenuBar->FindItem( ID_MENU_AIS_SCALED_TARGETS )->Check( g_bShowScaled );
5820     m_pMenuBar->FindItem( ID_MENU_AIS_SCALED_TARGETS )->Enable(g_bAllowShowScaled);
5821     m_pMenuBar->FindItem( ID_MENU_AIS_TRACKS )->Check( g_bAISShowTracks );
5822     m_pMenuBar->FindItem( ID_MENU_AIS_CPADIALOG )->Check( g_bAIS_CPA_Alert );
5823     m_pMenuBar->FindItem( ID_MENU_AIS_CPASOUND )->Check( g_bAIS_CPA_Alert_Audio );
5824     m_pMenuBar->FindItem( ID_MENU_SHOW_NAVOBJECTS )->Check( GetPrimaryCanvas()->m_bShowNavobjects );
5825 
5826     if( ps52plib ) {
5827         m_pMenuBar->FindItem( ID_MENU_ENC_TEXT )->Check( ps52plib->GetShowS57Text() );
5828         m_pMenuBar->FindItem( ID_MENU_ENC_SOUNDINGS )->Check( ps52plib->GetShowSoundings() );
5829 
5830         bool light_state = false;
5831         if( ps52plib ) {
5832             for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
5833                 OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
5834                 if( !strncmp( pOLE->OBJLName, "LIGHTS", 6 ) ) {
5835                     light_state = (pOLE->nViz == 1);
5836                     break;
5837                 }
5838             }
5839         }
5840         m_pMenuBar->FindItem( ID_MENU_ENC_LIGHTS )->Check( (!ps52plib->IsObjNoshow("LIGHTS")) && light_state );
5841 
5842         // Menu "Anchor Info" entry is only accessible in "All" or "User Standard" categories
5843         DisCat nset = ps52plib->GetDisplayCategory();
5844         if((nset == MARINERS_STANDARD) || (nset == OTHER) ){
5845             m_pMenuBar->FindItem( ID_MENU_ENC_ANCHOR )->Check( !ps52plib->IsObjNoshow("SBDARE") );
5846             m_pMenuBar->Enable( ID_MENU_ENC_ANCHOR, true);
5847             m_pMenuBar->FindItem( ID_MENU_ENC_DATA_QUALITY )->Check( !ps52plib->IsObjNoshow("M_QUAL")  );
5848             m_pMenuBar->Enable( ID_MENU_ENC_DATA_QUALITY, true);
5849         }
5850         else{
5851             m_pMenuBar->FindItem( ID_MENU_ENC_ANCHOR )->Check( false );
5852             m_pMenuBar->Enable( ID_MENU_ENC_ANCHOR, false);
5853             m_pMenuBar->Enable( ID_MENU_ENC_DATA_QUALITY, false);
5854         }
5855 
5856     }
5857 }
5858 
UpdateGlobalMenuItems(ChartCanvas * cc)5859 void MyFrame::UpdateGlobalMenuItems( ChartCanvas *cc)
5860 {
5861     if ( !m_pMenuBar ) return;  // if there isn't a menu bar
5862 
5863     m_pMenuBar->FindItem( ID_MENU_NAV_FOLLOW )->Check( cc->m_bFollow );
5864 
5865     if(cc->GetUpMode() == NORTH_UP_MODE)
5866         m_pMenuBar->FindItem( ID_MENU_CHART_NORTHUP )->Check( true  );
5867     else if (cc->GetUpMode() == COURSE_UP_MODE)
5868         m_pMenuBar->FindItem( ID_MENU_CHART_COGUP )->Check( true );
5869     else
5870         m_pMenuBar->FindItem( ID_MENU_CHART_HEADUP )->Check( true );
5871 
5872     m_pMenuBar->FindItem( ID_MENU_NAV_TRACK )->Check( g_bTrackActive );
5873     m_pMenuBar->FindItem( ID_MENU_CHART_OUTLINES )->Check( cc->GetShowOutlines() );
5874     m_pMenuBar->FindItem( ID_MENU_CHART_QUILTING )->Check( cc->GetQuiltMode() );
5875     m_pMenuBar->FindItem( ID_MENU_UI_CHARTBAR )->Check( cc->GetShowChartbar() );
5876     m_pMenuBar->FindItem( ID_MENU_AIS_TARGETS )->Check( cc->GetShowAIS() );
5877     m_pMenuBar->FindItem( ID_MENU_AIS_MOORED_TARGETS )->Check( g_bHideMoored );
5878     m_pMenuBar->FindItem( ID_MENU_AIS_SCALED_TARGETS )->Check( cc->GetAttenAIS() );
5879     m_pMenuBar->FindItem( ID_MENU_AIS_SCALED_TARGETS )->Enable(g_bAllowShowScaled);
5880     m_pMenuBar->FindItem( ID_MENU_AIS_TRACKS )->Check( g_bAISShowTracks );
5881     m_pMenuBar->FindItem( ID_MENU_AIS_CPADIALOG )->Check( g_bAIS_CPA_Alert );
5882     m_pMenuBar->FindItem( ID_MENU_AIS_CPASOUND )->Check( g_bAIS_CPA_Alert_Audio );
5883     m_pMenuBar->FindItem( ID_MENU_SHOW_NAVOBJECTS )->Check( cc->m_bShowNavobjects );
5884     m_pMenuBar->FindItem( ID_MENU_SHOW_TIDES )->Check( cc->GetbShowTide() );
5885     m_pMenuBar->FindItem( ID_MENU_SHOW_CURRENTS )->Check( cc->GetbShowCurrent() );
5886 
5887     if( ps52plib ) {
5888         m_pMenuBar->FindItem( ID_MENU_ENC_TEXT )->Check( cc->GetShowENCText() );
5889         m_pMenuBar->FindItem( ID_MENU_ENC_SOUNDINGS )->Check( cc->GetShowENCDepth() );
5890 
5891         if( ps52plib ) {
5892             for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
5893                 OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
5894                 if( !strncmp( pOLE->OBJLName, "LIGHTS", 6 ) ) {
5895                     break;
5896                 }
5897             }
5898         }
5899         m_pMenuBar->FindItem( ID_MENU_ENC_LIGHTS )->Check( cc->GetShowENCLights() );
5900 
5901         // Menu "Anchor Info" entry is only accessible in "All" or "UserStandard" categories
5902         DisCat nset = (DisCat)cc->GetENCDisplayCategory();
5903         if((nset == MARINERS_STANDARD) || (nset == OTHER) ){
5904             m_pMenuBar->FindItem( ID_MENU_ENC_ANCHOR )->Check( cc->GetShowENCAnchor());
5905             m_pMenuBar->Enable( ID_MENU_ENC_ANCHOR, true);
5906             m_pMenuBar->FindItem( ID_MENU_ENC_DATA_QUALITY )->Check( cc->GetShowENCDataQual()  );
5907             m_pMenuBar->Enable( ID_MENU_ENC_DATA_QUALITY, true);
5908         }
5909         else{
5910             m_pMenuBar->FindItem( ID_MENU_ENC_ANCHOR )->Check( false );
5911             m_pMenuBar->Enable( ID_MENU_ENC_ANCHOR, false);
5912             m_pMenuBar->Enable( ID_MENU_ENC_DATA_QUALITY, false);
5913         }
5914 
5915     }
5916 }
5917 
InvalidateAllCanvasUndo()5918 void MyFrame::InvalidateAllCanvasUndo()
5919 {
5920     // .. for each canvas...
5921     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
5922         ChartCanvas *cc = g_canvasArray.Item(i);
5923         if(cc)
5924             cc->undo->InvalidateUndo( );
5925     }
5926 }
5927 
5928 
5929 
SubmergeAllCanvasToolbars(void)5930 void MyFrame::SubmergeAllCanvasToolbars( void )
5931 {
5932     // .. for each canvas...
5933     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
5934         ChartCanvas *cc = g_canvasArray.Item(i);
5935         if(cc)
5936             cc->SubmergeToolbar( );
5937     }
5938 }
5939 
SurfaceAllCanvasToolbars(void)5940 void MyFrame::SurfaceAllCanvasToolbars( void )
5941 {
5942     if(g_bshowToolbar){
5943         // .. for each canvas...
5944         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
5945             ChartCanvas *cc = g_canvasArray.Item(i);
5946             if(cc && cc->GetToolbarEnable())
5947                 cc->SurfaceToolbar( );
5948         }
5949     }
5950 
5951 #ifndef __WXQT__
5952        //  removed to show MUIBars on MSVC
5953        ///Raise();
5954 #endif
5955 }
5956 
ToggleAllToolbars(bool b_smooth)5957 void MyFrame::ToggleAllToolbars( bool b_smooth )
5958 {
5959     // .. for each canvas...
5960     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
5961         ChartCanvas *cc = g_canvasArray.Item(i);
5962         if(cc)
5963             cc->ToggleToolbar( b_smooth );
5964     }
5965 }
5966 
5967 
JumpToPosition(ChartCanvas * cc,double lat,double lon,double scale)5968 void MyFrame::JumpToPosition( ChartCanvas *cc, double lat, double lon, double scale )
5969 {
5970     if (lon > 180.0)
5971         lon -= 360.0;
5972     // XXX is vLat/vLon always equal to cc m_vLat, m_vLon after SetViewPoint? Does it matter?
5973     vLat = lat;
5974     vLon = lon;
5975     cc->JumpToPosition(lat, lon, scale);
5976 
5977     if( g_pi_manager ) {
5978         g_pi_manager->SendViewPortToRequestingPlugIns( cc->GetVP() );
5979     }
5980 }
5981 
UpdateCanvasConfigDescriptors()5982 void MyFrame::UpdateCanvasConfigDescriptors()
5983 {
5984     // ..For each canvas...
5985     for(unsigned int i=0 ; i < g_canvasConfigArray.GetCount() ; i++){
5986         canvasConfig *cc = g_canvasConfigArray.Item(i);
5987         if(cc ){
5988             ChartCanvas *chart = cc->canvas;
5989             if(chart){
5990                 cc->iLat = chart->GetVP().clat;
5991                 cc->iLon = chart->GetVP().clon;
5992                 cc->iRotation = chart->GetVP().rotation;
5993                 cc->iScale = chart->GetVP().view_scale_ppm;
5994                 cc->DBindex = chart->GetQuiltReferenceChartIndex();
5995                 cc->GroupID = chart->m_groupIndex;
5996                 cc->canvasSize = chart->GetSize();
5997             }
5998 
5999         }
6000     }
6001 }
6002 
6003 
6004 
6005 
6006 
6007 
CenterView(ChartCanvas * cc,const LLBBox & RBBox)6008 void MyFrame::CenterView(ChartCanvas *cc, const LLBBox& RBBox)
6009 {
6010     if ( !RBBox.GetValid() )
6011         return;
6012     // Calculate bbox center
6013     double clat = (RBBox.GetMinLat() + RBBox.GetMaxLat()) / 2;
6014     double clon = (RBBox.GetMinLon() + RBBox.GetMaxLon()) / 2;
6015     double ppm; // final ppm scale to use
6016 
6017     if (RBBox.GetMinLat() == RBBox.GetMaxLat() && RBBox.GetMinLon() == RBBox.GetMaxLon() )
6018     {
6019         // only one point, (should be a box?)
6020         ppm = cc->GetVPScale();
6021     }
6022     else
6023     {
6024         // Calculate ppm
6025         double rw, rh; // route width, height
6026         int ww, wh; // chart window width, height
6027         // route bbox width in nm
6028         DistanceBearingMercator( RBBox.GetMinLat(), RBBox.GetMinLon(), RBBox.GetMinLat(),
6029                                  RBBox.GetMaxLon(), NULL, &rw );
6030                              // route bbox height in nm
6031         DistanceBearingMercator( RBBox.GetMinLat(), RBBox.GetMinLon(), RBBox.GetMaxLat(),
6032                                 RBBox.GetMinLon(), NULL, &rh );
6033 
6034         cc->GetSize( &ww, &wh );
6035 
6036         ppm = wxMin(ww/(rw*1852), wh/(rh*1852)) * ( 100 - fabs( clat ) ) / 90;
6037 
6038         ppm = wxMin(ppm, 1.0);
6039     }
6040 
6041     JumpToPosition(cc, clat, clon, ppm );
6042 }
6043 
DoOptionsDialog()6044 int MyFrame::DoOptionsDialog()
6045 {
6046     if (g_boptionsactive)
6047         return 0;
6048 
6049     g_boptionsactive = true;
6050     g_last_ChartScaleFactor = g_ChartScaleFactor;
6051 
6052 
6053     if(NULL == g_options) {
6054         g_Platform->ShowBusySpinner();
6055         g_options = new options( this, -1, _("Options") );
6056         //g_options->SetColorScheme(global_color_scheme);
6057         //applyDarkAppearanceToWindow(g_options->MacGetTopLevelWindowRef());
6058 
6059         g_Platform->HideBusySpinner();
6060     }
6061 
6062 //    Set initial Chart Dir
6063     g_options->SetInitChartDir( *pInit_Chart_Dir );
6064 
6065 //      Pass two working pointers for Chart Dir Dialog
6066     g_options->SetCurrentDirList( ChartData->GetChartDirArray() );
6067     ArrayOfCDI *pWorkDirArray = new ArrayOfCDI;
6068     g_options->SetWorkDirListPtr( pWorkDirArray );
6069 
6070 //      Pass a ptr to MyConfig, for updates
6071     g_options->SetConfigPtr( pConfig );
6072 
6073     g_options->SetInitialSettings();
6074 
6075     bPrevQuilt = g_bQuiltEnable;
6076     bPrevFullScreenQuilt = g_bFullScreenQuilt;
6077     bPrevOGL = g_bopengl;
6078 
6079     prev_locale = g_locale;
6080 
6081     bool b_sub = false;
6082     if( g_MainToolbar && g_MainToolbar->IsShown() ) {
6083         wxRect bx_rect = g_options->GetScreenRect();
6084         wxRect tb_rect = g_MainToolbar->GetScreenRect();
6085         if( tb_rect.Intersects( bx_rect ) ) b_sub = true;
6086 
6087         if( b_sub ) g_MainToolbar->Submerge();
6088     }
6089 
6090 #if defined(__WXOSX__) || defined(__WXQT__)
6091     bool b_restoreAIS = false;
6092     if( g_pAISTargetList  && g_pAISTargetList->IsShown() ){
6093         b_restoreAIS = true;
6094         g_pAISTargetList->Shutdown();
6095         g_pAISTargetList = NULL;
6096     }
6097 #endif
6098 
6099 #ifdef __WXOSX__
6100        // ..For each canvas...
6101     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6102         ChartCanvas *cc = g_canvasArray.Item(i);
6103         if(cc && cc->GetMUIBar())
6104             cc->GetMUIBar()->Hide();
6105     }
6106 
6107     SubmergeAllCanvasToolbars();
6108     g_MainToolbar->Submerge();
6109 #endif
6110 
6111     g_options->SetInitialPage(options_lastPage, options_subpage );
6112 
6113 
6114 #ifndef __OCPN__ANDROID__  //    if(!g_bresponsive){
6115         g_options->lastWindowPos = options_lastWindowPos;
6116         if( options_lastWindowPos != wxPoint(0,0) ) {
6117             g_options->Move( options_lastWindowPos );
6118             g_options->SetSize( options_lastWindowSize );
6119         } else {
6120             g_options->Center();
6121         }
6122         if( options_lastWindowSize != wxSize(0,0) ) {
6123             g_options->SetSize( options_lastWindowSize );
6124         }
6125 
6126       // Correct some fault in Options dialog layout logic on GTK3 by forcing a re-layout to new slightly reduced size.
6127 #ifdef __WXGTK3__
6128         if( options_lastWindowSize != wxSize(0,0) )
6129             g_options->SetSize( options_lastWindowSize.x - 1, options_lastWindowSize.y );
6130 #endif
6131 
6132 #endif
6133 
6134     if( g_MainToolbar)
6135         g_MainToolbar->DisableTooltips();
6136 
6137 #ifdef __OCPN__ANDROID__
6138     androidEnableBackButton( false );
6139     androidEnableOptionsMenu( false );
6140     androidDisableFullScreen();
6141 #endif
6142 
6143     // Record current canvas config
6144     unsigned int last_canvasConfig = g_canvasConfig;
6145     wxSize cc1SizeBefore;
6146     if( g_canvasConfig > 0 ){
6147         canvasConfig *cc = g_canvasConfigArray.Item(0);
6148         if(cc )
6149             cc1SizeBefore = g_canvasArray.Item(0)->GetSize();
6150     }
6151 
6152     //  Capture the full path names of charts currently shown in all canvases
6153     wxArrayString pathArray;
6154     // ..For each canvas...
6155     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6156         ChartCanvas *cc = g_canvasArray.Item(i);
6157         if(cc){
6158             wxString chart_file_name;
6159             if( cc->GetQuiltMode() ) {
6160                 int dbi = cc->GetQuiltRefChartdbIndex();
6161                 chart_file_name = ChartData->GetDBChartFileName( dbi );
6162             } else{
6163                 if( cc->m_singleChart )
6164                     chart_file_name =  cc->m_singleChart->GetFullPath();
6165             }
6166 
6167             pathArray.Add(chart_file_name);
6168         }
6169     }
6170 
6171     int rr = g_options->ShowModal();
6172 
6173     #ifdef __OCPN__ANDROID__
6174     androidEnableBackButton( true );
6175     androidEnableOptionsMenu( true );
6176     androidRestoreFullScreen();
6177     androidEnableRotation();
6178     #endif
6179 
6180 
6181     if( g_MainToolbar)
6182         g_MainToolbar->EnableTooltips();
6183 
6184     options_lastPage = g_options->lastPage;
6185     options_subpage = g_options->lastSubPage;
6186 
6187     options_lastWindowPos = g_options->lastWindowPos;
6188     options_lastWindowSize = g_options->lastWindowSize;
6189 
6190     if( 1/*b_sub*/ ) {          // always surface toolbar, and restart the timer if needed
6191 #ifdef __OCPN__ANDROID__
6192       g_MainToolbar-> SetDockX( -1 );
6193       g_MainToolbar-> SetDockY( -1 );
6194 #endif
6195         g_MainToolbar->Surface();
6196         SurfaceAllCanvasToolbars();
6197         GetPrimaryCanvas()->SetFocus();
6198     }
6199 
6200 #ifdef __WXGTK__
6201     Raise();                      // I dunno why...
6202 #endif
6203 
6204 
6205     bool ret_val = false;
6206     rr = g_options->GetReturnCode();
6207 
6208     if(g_last_ChartScaleFactor != g_ChartScaleFactor)
6209         rr |= S52_CHANGED;
6210 
6211     bool b_refresh = true;
6212 
6213 #if 0
6214     bool ccRightSizeChanged = false;
6215     if( g_canvasConfig > 0 ){
6216         canvasConfig *cc = g_canvasConfigArray.Item(0);
6217         if(cc ){
6218             wxSize cc1Size = cc->canvasSize;
6219             if(cc1Size.x != cc1SizeBefore.x)
6220                 ccRightSizeChanged = true;
6221         }
6222     }
6223 #endif
6224 
6225     if( (g_canvasConfig != last_canvasConfig) || ( rr & GL_CHANGED) ){
6226         UpdateCanvasConfigDescriptors();
6227 
6228         if( (g_canvasConfig > 0) && (last_canvasConfig == 0) )
6229             CreateCanvasLayout(true);
6230         else
6231             CreateCanvasLayout();
6232 
6233         SendSizeEvent();
6234 
6235         g_pauimgr->Update();
6236 
6237         // We need a yield() here to pick up the size event
6238         // so that the toolbars will be sized correctly
6239         wxYield();
6240 
6241         // ..For each canvas...
6242         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6243             ChartCanvas *cc = g_canvasArray.Item(i);
6244             if(cc)
6245                 cc->CreateMUIBar();
6246         }
6247 
6248         rr |= GENERIC_CHANGED;
6249 
6250         if(g_bopengl)           // Force mark/waypoint icon reload
6251             rr |= S52_CHANGED;
6252 
6253         b_refresh = true;
6254     }
6255 
6256     // Here check for the case wherein the relative sizes of a multicanvas layout have been changed.
6257     // We do not need to reqbuild the canvases, we just need to resize whichever one is docked.
6258 
6259 //     if( (g_canvasConfig > 0)  && ccRightSizeChanged ){
6260 //         canvasConfig *cc = g_canvasConfigArray.Item(1);
6261 //         if(cc ){
6262 //             wxAuiPaneInfo& p = g_pauimgr->GetPane(g_canvasArray.Item(1));
6263 //             wxAuiDockInfo *dockRight = g_pauimgr->FindDock(p);
6264 //             if(dockRight)
6265 //                 g_pauimgr->SetDockSize(dockRight, cc->canvasSize.x);
6266 //         }
6267 //     }
6268 
6269     if( rr & CONFIG_CHANGED){
6270         // Apply the changed canvas configs to each canvas
6271         // ..For each canvas...
6272         for(unsigned int i=0 ; i < g_canvasConfigArray.GetCount() ; i++){
6273             canvasConfig *cc = g_canvasConfigArray.Item(i);
6274             if(cc ){
6275                 ChartCanvas *chartCanvas = cc->canvas;
6276                 if(chartCanvas){
6277                     chartCanvas->ApplyCanvasConfig(cc);
6278                 }
6279             }
6280         }
6281     }
6282 
6283 
6284     if( rr ) {
6285         bDBUpdateInProgress = true;
6286         b_refresh |= ProcessOptionsDialog( rr,  g_options->GetWorkDirListPtr() );
6287         ChartData->GetChartDirArray() = *(g_options->GetWorkDirListPtr()); // Perform a deep copy back to main database.
6288         bDBUpdateInProgress = false;
6289         ret_val = true;
6290     }
6291 
6292     delete pWorkDirArray;
6293 
6294 
6295     gFrame->Raise();
6296     DoChartUpdate();
6297 
6298     //  We set the compass size first, since that establishes the available space for the toolbar.
6299     SetGPSCompassScale();
6300     // ..For each canvas...
6301     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6302         ChartCanvas *cc = g_canvasArray.Item(i);
6303         if(cc){
6304             cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
6305             cc->UpdateCanvasControlBar();
6306         }
6307     }
6308     UpdateGPSCompassStatusBoxes();
6309 
6310     SetAllToolbarScale();
6311     RequestNewToolbars();
6312 
6313     // Change of master toolbar scale?
6314     bool b_masterScaleChange = false;
6315     if(fabs(g_MainToolbar->GetScaleFactor() - g_toolbar_scalefactor) > 0.01f)
6316         b_masterScaleChange = true;
6317 
6318 
6319     if((rr & TOOLBAR_CHANGED) || b_masterScaleChange )
6320         RequestNewMasterToolbar( true );
6321 
6322     bool bMuiChange = false;
6323 #ifdef __OCPN__ANDROID__
6324     bMuiChange = true;                  // to pick up possible "zoom" button visibility change
6325 #endif
6326 
6327     // Inform the canvases
6328     if( b_masterScaleChange  || bMuiChange ){
6329             // ..For each canvas...
6330         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6331             ChartCanvas *cc = g_canvasArray.Item(i);
6332             if(cc ){
6333                 cc->ProcessNewGUIScale();
6334             }
6335         }
6336     }
6337 
6338     if( g_MainToolbar ) {
6339         if( IsFullScreen() && !g_bFullscreenToolbar )
6340             g_MainToolbar->Submerge();
6341     }
6342 
6343 #if defined(__WXOSX__) || defined(__WXQT__)
6344     if( b_restoreAIS ){
6345         g_pAISTargetList = new AISTargetListDialog( this, g_pauimgr, g_pAIS );
6346         g_pAISTargetList->UpdateAISTargetList();
6347     }
6348 #endif
6349 
6350     if(console && console->IsShown())
6351         console->Raise();
6352 
6353 
6354     if(g_pais_alert_dialog_active)
6355         g_pais_alert_dialog_active->Raise();
6356 
6357     if (NMEALogWindow::Get().Active())
6358         NMEALogWindow::Get().GetTTYWindow()->Raise();
6359 
6360 #ifdef __OCPN__ANDROID__
6361     if(g_pi_manager)
6362         g_pi_manager->NotifyAuiPlugIns();
6363 #endif
6364 
6365     //  Force reload of options dialog to pick up font changes or other major layout changes
6366     if( (rr & FONT_CHANGED) || (rr & NEED_NEW_OPTIONS) ){
6367         delete g_options;
6368         g_options = NULL;
6369         g_pOptions = NULL;
6370     }
6371 
6372     //  Pick up chart object icon size changes (g_ChartScaleFactorExp)
6373     if( g_pMarkInfoDialog ) {
6374         g_pMarkInfoDialog->Hide();
6375         g_pMarkInfoDialog->Destroy();
6376         g_pMarkInfoDialog = NULL;
6377     }
6378 
6379 #if wxUSE_XLOCALE
6380     if(rr & LOCALE_CHANGED){
6381 
6382         g_Platform->ChangeLocale(g_locale, plocale_def_lang, &plocale_def_lang);
6383         ApplyLocale();
6384     }
6385 #endif
6386 
6387     // If needed, refresh each canvas,
6388     // trying to reload the previously displayed chart by name as saved in pathArray
6389     if(b_refresh){
6390     // ..For each canvas...
6391         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6392             ChartCanvas *cc = g_canvasArray.Item(i);
6393             if(cc ){
6394                 int index_hint = -1;
6395                 if( i < pathArray.GetCount())
6396                     index_hint = ChartData->FinddbIndex( pathArray.Item(i));
6397                 cc->canvasChartsRefresh( index_hint );
6398             }
6399         }
6400     }
6401 
6402 
6403 
6404     g_boptionsactive = false;
6405 
6406     //  If we had a config chamge, then schedule a re-entry to the settings dialog
6407     if(rr & CONFIG_CHANGED){
6408         options_subpage = 3;            // Back to the "templates" page
6409         ScheduleSettingsDialog();
6410     }
6411     else
6412         options_subpage = 0;
6413 
6414     return ret_val;
6415 }
6416 
ProcessOptionsDialog(int rr,ArrayOfCDI * pNewDirArray)6417 bool MyFrame::ProcessOptionsDialog( int rr, ArrayOfCDI *pNewDirArray )
6418 {
6419     bool b_need_refresh = false;                // Do we need a full reload?
6420 
6421     if( ( rr & VISIT_CHARTS )
6422             && ( ( rr & CHANGE_CHARTS ) || ( rr & FORCE_UPDATE ) || ( rr & SCAN_UPDATE ) ) ) {
6423         if(pNewDirArray){
6424             UpdateChartDatabaseInplace( *pNewDirArray, ( ( rr & FORCE_UPDATE ) == FORCE_UPDATE ),
6425                 true, ChartListFileName );
6426 
6427             b_need_refresh = true;
6428         }
6429     }
6430 
6431     if(  rr & STYLE_CHANGED  ) {
6432         OCPNMessageBox(NULL, _("Please restart OpenCPN to activate language or style changes."),
6433                 _("OpenCPN Info"), wxOK | wxICON_INFORMATION );
6434     }
6435 
6436     bool b_groupchange = false;
6437     if( ( ( rr & VISIT_CHARTS )
6438             && ( ( rr & CHANGE_CHARTS ) || ( rr & FORCE_UPDATE ) || ( rr & SCAN_UPDATE ) ) )
6439             || ( rr & GROUPS_CHANGED ) ) {
6440         b_groupchange = ScrubGroupArray();
6441         ChartData->ApplyGroupArray( g_pGroupArray );
6442         RefreshGroupIndices( );
6443     }
6444 
6445     if( rr & GROUPS_CHANGED || b_groupchange) {
6446         pConfig->DestroyConfigGroups();
6447         pConfig->CreateConfigGroups( g_pGroupArray );
6448     }
6449 
6450     if( rr & TIDES_CHANGED ) {
6451         LoadHarmonics();
6452     }
6453 
6454     //  S52_CHANGED is a byproduct of a change in the chart object render scale
6455     //  So, applies to RoutePoint icons also
6456     if( rr & S52_CHANGED){
6457         //  Reload Icons
6458         pWayPointMan->ReloadAllIcons( );
6459     }
6460 
6461     pConfig->UpdateSettings();
6462 
6463     if( g_pActiveTrack ) {
6464         g_pActiveTrack->SetPrecision( g_nTrackPrecision );
6465     }
6466 
6467 //     if( ( bPrevQuilt != g_bQuiltEnable ) || ( bPrevFullScreenQuilt != g_bFullScreenQuilt ) ) {
6468 //         GetPrimaryCanvas()->SetQuiltMode( g_bQuiltEnable );
6469 //         GetPrimaryCanvas()->SetupCanvasQuiltMode();
6470 //     }
6471 
6472 #if 0
6473 //TODO Not need with per-canvas CourseUp
6474     if( g_bCourseUp ) {
6475         //    Stuff the COGAvg table in case COGUp is selected
6476         double stuff = NAN;
6477         if( !std::isnan(gCog) ) stuff = gCog;
6478         if( g_COGAvgSec > 0 ) {
6479             for( int i = 0; i < g_COGAvgSec; i++ )
6480                 COGTable[i] = stuff;
6481         }
6482 
6483         g_COGAvg = stuff;
6484 
6485         DoCOGSet();
6486     }
6487 #endif
6488 
6489     g_pRouteMan->SetColorScheme(global_color_scheme);           // reloads pens and brushes
6490 
6491     //    Stuff the Filter tables
6492     double stuffcog = NAN;
6493     double stuffsog = NAN;
6494     if( !std::isnan(gCog) ) stuffcog = gCog;
6495     if( !std::isnan(gSog) ) stuffsog = gSog;
6496 
6497     for( int i = 0; i < MAX_COGSOG_FILTER_SECONDS; i++ ) {
6498         COGFilterTable[i] = stuffcog;
6499         SOGFilterTable[i] = stuffsog;
6500     }
6501 
6502     SetChartUpdatePeriod( );              // Pick up changes to skew compensator
6503 
6504     if(rr & GL_CHANGED){
6505         //    Refresh the chart display, after flushing cache.
6506         //      This will allow all charts to recognise new OpenGL configuration, if any
6507         b_need_refresh = true;
6508     }
6509 
6510     if(rr & S52_CHANGED){
6511         b_need_refresh = true;
6512     }
6513 
6514 #ifdef ocpnUSE_GL
6515     if(rr & REBUILD_RASTER_CACHE){
6516         if(g_glTextureManager) {
6517             GetPrimaryCanvas()->Disable();
6518             g_glTextureManager->BuildCompressedCache();
6519             GetPrimaryCanvas()->Enable();
6520         }
6521     }
6522 #endif
6523 
6524     if(g_config_display_size_mm > 0){
6525         g_display_size_mm = g_config_display_size_mm;
6526     }
6527     else{
6528         g_display_size_mm = wxMax(100, g_Platform->GetDisplaySizeMM());
6529     }
6530 
6531     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6532         ChartCanvas *cc = g_canvasArray.Item(i);
6533         if(cc)
6534             cc->SetDisplaySizeMM( g_display_size_mm );
6535     }
6536 
6537     if(g_pi_manager){
6538         g_pi_manager->SendBaseConfigToAllPlugIns();
6539         int rrt = rr & S52_CHANGED;
6540         g_pi_manager->SendS52ConfigToAllPlugIns( (rrt == S52_CHANGED) || (g_last_ChartScaleFactor != g_ChartScaleFactor));
6541     }
6542 
6543 
6544     if(g_MainToolbar){
6545         g_MainToolbar->SetAutoHide(g_bAutoHideToolbar);
6546         g_MainToolbar->SetAutoHideTimer(g_nAutoHideToolbar);
6547     }
6548 
6549     // Apply any needed updates to each canvas
6550     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6551         ChartCanvas *cc = g_canvasArray.Item(i);
6552         if(cc)
6553             cc->ApplyGlobalSettings();
6554     }
6555 
6556 
6557     //    Do a full Refresh, trying to open the last open chart
6558 //TODO  This got move up a level.  FIX ANDROID codepath
6559 #if 0
6560     if(b_need_refresh){
6561         int index_hint = ChartData->FinddbIndex( chart_file_name );
6562         if( -1 == index_hint )
6563             b_autofind = true;
6564         ChartsRefresh( );
6565     }
6566 #endif
6567 
6568     //  The zoom-scale factor may have changed
6569     //  so, trigger a recalculation of the reference chart
6570 
6571     bool ztc = g_bEnableZoomToCursor;     // record the present state
6572     g_bEnableZoomToCursor = false;        // since we don't want to pan to an unknown cursor position
6573 
6574     //  This is needed to recognise changes in zoom-scale factors
6575     GetPrimaryCanvas()->DoZoomCanvas(1.0001);
6576 
6577     g_bEnableZoomToCursor = ztc;
6578 
6579     g_last_ChartScaleFactor = g_ChartScaleFactor;
6580 
6581     return b_need_refresh;
6582 }
6583 
6584 
GetGroupName(int igroup)6585 wxString MyFrame::GetGroupName( int igroup )
6586 {
6587     ChartGroup *pGroup = g_pGroupArray->Item( igroup - 1 );
6588     return pGroup->m_group_name;
6589 }
6590 
CheckGroup(int igroup)6591 bool MyFrame::CheckGroup( int igroup )
6592 {
6593     if( igroup == 0 ) return true;              // "all charts" is always OK
6594 
6595     ChartGroup *pGroup = g_pGroupArray->Item( igroup - 1 );
6596 
6597     if( !pGroup->m_element_array.size() )   //  truly empty group is OK
6598         return true;
6599 
6600     for( auto& elem : pGroup->m_element_array ) {
6601 
6602         for( unsigned int ic = 0; ic < (unsigned int) ChartData->GetChartTableEntries(); ic++ ) {
6603             ChartTableEntry *pcte = ChartData->GetpChartTableEntry( ic );
6604             wxString chart_full_path( pcte->GetpFullPath(), wxConvUTF8 );
6605 
6606             if( chart_full_path.StartsWith( elem->m_element_name ) )
6607                 return true;
6608         }
6609     }
6610 
6611     return false;                           // this group is empty
6612 }
6613 
ScrubGroupArray()6614 bool MyFrame::ScrubGroupArray()
6615 {
6616     //    For each group,
6617     //    make sure that each group element (dir or chart) references at least oneitem in the database.
6618     //    If not, remove the element.
6619 
6620     bool b_change = false;
6621     unsigned int igroup = 0;
6622     while( igroup < g_pGroupArray->GetCount() ) {
6623         bool b_chart_in_element = false;
6624         ChartGroup *pGroup = g_pGroupArray->Item( igroup );
6625 
6626         for( unsigned int j = 0; j < pGroup->m_element_array.size(); j++ ) {
6627             wxString element_root = pGroup->m_element_array[j]->m_element_name;
6628 
6629             for( unsigned int ic = 0; ic < (unsigned int) ChartData->GetChartTableEntries();
6630                     ic++ ) {
6631                 ChartTableEntry *pcte = ChartData->GetpChartTableEntry( ic );
6632                 wxString chart_full_path = pcte->GetFullSystemPath();
6633 
6634                 if( chart_full_path.StartsWith( element_root ) ) {
6635                     b_chart_in_element = true;
6636                     break;
6637                 }
6638             }
6639 
6640             // Explicit check to avoid removing a group containing only GSHHS
6641             if(!b_chart_in_element){
6642                 wxString test_string = _T("GSHH");
6643                 if(element_root.Upper().Contains(test_string))
6644                     b_chart_in_element = true;
6645             }
6646 
6647             if( !b_chart_in_element )             // delete the element
6648             {
6649                 pGroup->m_element_array.erase(pGroup->m_element_array.begin() + j);
6650                 j--;
6651                 b_change = true;
6652             }
6653         }
6654 
6655         igroup++;                                 // next group
6656     }
6657 
6658     return b_change;
6659 }
6660 
RefreshCanvasOther(ChartCanvas * ccThis)6661 void MyFrame::RefreshCanvasOther( ChartCanvas *ccThis )
6662 {
6663     // ..For each canvas...
6664     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6665         ChartCanvas *cc = g_canvasArray.Item(i);
6666         if(cc && (cc != ccThis))
6667             cc->Refresh();
6668     }
6669 }
6670 
6671 
6672 
6673 // Flav: This method reloads all charts for convenience
ChartsRefresh()6674 void MyFrame::ChartsRefresh( )
6675 {
6676     if( !ChartData ) return;
6677 
6678     OCPNPlatform::ShowBusySpinner();
6679 
6680     bool b_run = FrameTimer1.IsRunning();
6681 
6682     FrameTimer1.Stop();                  // stop other asynchronous activity
6683 
6684     // ..For each canvas...
6685     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6686         ChartCanvas *cc = g_canvasArray.Item(i);
6687         if(cc ){
6688             int currentIndex = cc->GetpCurrentStack()->GetCurrentEntrydbIndex();
6689             if(cc->GetQuiltMode()){
6690                 currentIndex = cc->GetQuiltReferenceChartIndex();
6691                 }
6692             cc->canvasChartsRefresh( currentIndex );
6693         }
6694     }
6695 
6696 
6697     if( b_run ) FrameTimer1.Start( TIMER_GFRAME_1, wxTIMER_CONTINUOUS );
6698 
6699     OCPNPlatform::HideBusySpinner();
6700 
6701 }
6702 
InvalidateAllQuilts()6703 void MyFrame::InvalidateAllQuilts()
6704 {
6705      for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6706         ChartCanvas *cc = g_canvasArray.Item(i);
6707         if( cc ) {
6708             cc->InvalidateQuilt();
6709             cc->SetQuiltRefChart( -1 );
6710             cc->m_singleChart = NULL;
6711         }
6712     }
6713 }
6714 
UpdateChartDatabaseInplace(ArrayOfCDI & DirArray,bool b_force,bool b_prog,const wxString & ChartListFileName)6715 bool MyFrame::UpdateChartDatabaseInplace( ArrayOfCDI &DirArray, bool b_force, bool b_prog,
6716         const wxString &ChartListFileName )
6717 {
6718     bool b_run = FrameTimer1.IsRunning();
6719     FrameTimer1.Stop();                  // stop other asynchronous activity
6720 
6721     // ..For each canvas...
6722     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6723         ChartCanvas *cc = g_canvasArray.Item(i);
6724         if( cc ) {
6725             cc->InvalidateQuilt();
6726             cc->SetQuiltRefChart( -1 );
6727             cc->m_singleChart = NULL;
6728         }
6729     }
6730 
6731     ChartData->PurgeCache();
6732 
6733 //TODO
6734 //     delete pCurrentStack;
6735 //     pCurrentStack = NULL;
6736 
6737     OCPNPlatform::ShowBusySpinner();
6738 
6739     wxGenericProgressDialog *pprog = nullptr;
6740     if( b_prog ) {
6741         wxString longmsg = _("OpenCPN Chart Update");
6742         longmsg += _T("..........................................................................");
6743 
6744         pprog = new wxGenericProgressDialog();
6745 
6746         wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
6747         pprog->SetFont( *qFont );
6748 
6749         pprog->Create( _("OpenCPN Chart Update"), longmsg, 100,
6750                                           gFrame, wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME );
6751 
6752 
6753         DimeControl( pprog );
6754         pprog->Show();
6755     }
6756 
6757     wxLogMessage( _T("   ") );
6758     wxLogMessage( _T("Starting chart database Update...") );
6759     wxString gshhg_chart_loc = gWorldMapLocation;
6760     gWorldMapLocation = wxEmptyString;
6761     ChartData->Update( DirArray, b_force, pprog );
6762     ChartData->SaveBinary(ChartListFileName);
6763     wxLogMessage( _T("Finished chart database Update") );
6764     wxLogMessage( _T("   ") );
6765     if( gWorldMapLocation.empty() ) { //Last resort. User might have deleted all GSHHG data, but we still might have the default dataset distributed with OpenCPN or from the package repository...
6766        gWorldMapLocation = gDefaultWorldMapLocation;
6767        gshhg_chart_loc = wxEmptyString;
6768     }
6769 
6770     if( gWorldMapLocation != gshhg_chart_loc ){
6771     // ..For each canvas...
6772         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6773             ChartCanvas *cc = g_canvasArray.Item(i);
6774             if( cc )
6775                 cc->ResetWorldBackgroundChart();
6776         }
6777     }
6778 
6779 
6780     delete pprog;
6781 
6782     OCPNPlatform::HideBusySpinner();
6783 
6784     pConfig->UpdateChartDirs( DirArray );
6785 
6786     if( b_run ) FrameTimer1.Start( TIMER_GFRAME_1, wxTIMER_CONTINUOUS );
6787 
6788     return true;
6789 }
6790 
ToggleQuiltMode(ChartCanvas * cc)6791 void MyFrame::ToggleQuiltMode( ChartCanvas *cc )
6792 {
6793     if( cc ) {
6794         cc->ToggleCanvasQuiltMode();
6795 #if 0
6796         bool cur_mode = cc->GetQuiltMode();
6797 
6798         if( !cc->GetQuiltMode() )
6799             cc->SetQuiltMode( true );
6800         else
6801             if( cc->GetQuiltMode() ) {
6802                 cc->SetQuiltMode( false );
6803                 g_sticky_chart = cc->GetQuiltReferenceChartIndex();
6804             }
6805 
6806 
6807         if( cur_mode != cc->GetQuiltMode() ){
6808             //TODO >>SetupQuiltMode();
6809             DoChartUpdate();
6810             cc->InvalidateGL();
6811             Refresh();
6812         }
6813         g_bQuiltEnable = cc->GetQuiltMode();
6814 
6815         // Recycle the S52 PLIB so that vector charts will flush caches and re-render
6816         if(ps52plib)
6817             ps52plib->GenerateStateHash();
6818 #endif
6819     }
6820 }
6821 
6822 
ClearRouteTool()6823 void MyFrame::ClearRouteTool()
6824 {
6825     if( g_MainToolbar->GetToolbar() )
6826         g_MainToolbar->GetToolbar()->ToggleTool( ID_ROUTE, false );
6827 
6828 #ifdef __OCPN__ANDROID__
6829         androidSetRouteAnnunciator(false);
6830 #endif
6831 }
6832 
DoStackDown(ChartCanvas * cc)6833 void MyFrame::DoStackDown( ChartCanvas *cc )
6834 {
6835     DoStackDelta( cc, -1 );
6836 }
6837 
DoStackUp(ChartCanvas * cc)6838 void MyFrame::DoStackUp( ChartCanvas *cc )
6839 {
6840     DoStackDelta( cc, 1 );
6841 }
6842 
DoStackDelta(ChartCanvas * cc,int direction)6843 void MyFrame::DoStackDelta( ChartCanvas *cc, int direction )
6844 {
6845     if(cc){
6846         cc->DoCanvasStackDelta( direction );
6847     }
6848 }
6849 
PositionIENCToolbar()6850 void MyFrame::PositionIENCToolbar()
6851 {
6852     if(g_iENCToolbar){
6853         wxPoint posn;
6854         posn.x = (GetPrimaryCanvas()->GetSize().x - g_iENCToolbar->GetSize().x ) / 2;
6855         posn.y = 4;
6856         g_iENCToolbar->Move(GetPrimaryCanvas()->ClientToScreen(posn));
6857     }
6858     // take care of left docked instrument windows and don't blast the main toolbar on top of them, hinding instruments
6859     // this positions the main toolbar directly right of the left docked instruments onto the chart
6860     if (g_MainToolbar) {
6861       wxPoint posn;
6862       posn.x = 2;
6863       posn.y = 4;
6864       g_MainToolbar->Move(GetPrimaryCanvas()->ClientToScreen(posn));
6865     }
6866 }
6867 
6868 // Defered initialization for anything that is not required to render the initial frame
6869 // and takes a while to initialize.  This gets opencpn up and running much faster.
OnInitTimer(wxTimerEvent & event)6870 void MyFrame::OnInitTimer(wxTimerEvent& event)
6871 {
6872     InitTimer.Stop();
6873     wxString msg;
6874     msg.Printf(_T("OnInitTimer...%d"), m_iInitCount);
6875     wxLogMessage(msg);
6876 
6877     switch(m_iInitCount++) {
6878         case 0:
6879         {
6880             if( g_MainToolbar )
6881                 g_MainToolbar->EnableTool( ID_SETTINGS, false );
6882 
6883             if(g_bInlandEcdis){
6884                 double range = GetPrimaryCanvas()->GetCanvasRangeMeters();
6885                 double range_set = 500.;
6886 
6887                 range = wxRound(range * 10) / 10.;
6888 
6889                 if(range > 4000.)
6890                     range_set = 4000.;
6891                 else if(range > 2000.)
6892                     range_set = 2000.;
6893                 else if(range > 1600.)
6894                     range_set = 1600.;
6895                 else if(range > 1200.)
6896                     range_set = 1200.;
6897                 else if(range > 800.)
6898                     range_set = 800.;
6899                 else
6900                     range_set = 500.;
6901 
6902                 GetPrimaryCanvas()->SetCanvasRangeMeters(range_set);
6903 
6904             }
6905 
6906             // Set persistent Fullscreen mode
6907             g_Platform->SetFullscreen(g_bFullscreen);
6908 
6909             // Rebuild chart database, if necessary
6910             if(g_bNeedDBUpdate){
6911                 RebuildChartDatabase();
6912                 for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6913                     ChartCanvas *cc = g_canvasArray.Item(i);
6914                     if(cc){
6915                         cc->SetGroupIndex( 0, false );  //all charts
6916                     }
6917                 }
6918 
6919                 //    As a favor to new users, poll the database and
6920                 //    move the initial viewport so that a chart will come up.
6921 
6922                 double clat, clon;
6923                 if( ChartData->GetCentroidOfLargestScaleChart( &clat, &clon, CHART_FAMILY_RASTER ) ) {
6924                     gLat = clat;
6925                     gLon = clon;
6926                     gFrame->ClearbFollow(gFrame->GetPrimaryCanvas());
6927                 } else {
6928                     if( ChartData->GetCentroidOfLargestScaleChart( &clat, &clon, CHART_FAMILY_VECTOR ) ) {
6929                         gLat = clat;
6930                         gLon = clon;
6931                         gFrame->ClearbFollow(gFrame->GetPrimaryCanvas());
6932                     }
6933                 }
6934 
6935                 g_bNeedDBUpdate = false;
6936             }
6937 
6938             // Load the waypoints.. both of these routines are very slow to execute which is why
6939             // they have been to defered until here
6940             pWayPointMan = new WayPointman();
6941             pWayPointMan->SetColorScheme( global_color_scheme );
6942 
6943             // Reload the ownship icon from UserIcons, if present
6944             for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
6945                 ChartCanvas *cc = g_canvasArray.Item(i);
6946                 if(cc){
6947                     if(cc->SetUserOwnship())
6948                         cc->SetColorScheme(global_color_scheme);
6949                 }
6950             }
6951 
6952             pConfig->LoadNavObjects();
6953             //    Re-enable anchor watches if set in config file
6954             if( !g_AW1GUID.IsEmpty() ) {
6955                 pAnchorWatchPoint1 = pWayPointMan->FindRoutePointByGUID( g_AW1GUID );
6956             }
6957             if( !g_AW2GUID.IsEmpty() ) {
6958                 pAnchorWatchPoint2 = pWayPointMan->FindRoutePointByGUID( g_AW2GUID );
6959             }
6960 
6961             // Import Layer-wise any .gpx files from /Layers directory
6962             wxString layerdir = g_Platform->GetPrivateDataDir();
6963             appendOSDirSlash( &layerdir );
6964             layerdir.Append( _T("layers") );
6965 
6966             if( wxDir::Exists( layerdir ) ) {
6967                 wxString laymsg;
6968                 laymsg.Printf( wxT("Getting .gpx layer files from: %s"), layerdir.c_str() );
6969                 wxLogMessage( laymsg );
6970                 pConfig->LoadLayers(layerdir);
6971             }
6972 
6973             break;
6974         }
6975         case 1:
6976             // Connect Datastreams
6977 
6978 
6979             for ( size_t i = 0; i < g_pConnectionParams->Count(); i++ )
6980             {
6981                 ConnectionParams *cp = g_pConnectionParams->Item(i);
6982                 if( cp->bEnabled ) {
6983 
6984     #ifdef __unix__
6985                     if( cp->GetDSPort().Contains(_T("Serial"))) {
6986                         if( ! g_bserial_access_checked ){
6987                             if( !CheckSerialAccess() ){
6988                             }
6989                             g_bserial_access_checked = true;
6990                         }
6991                     }
6992     #endif
6993 
6994                     g_pMUX->AddStream(makeDataStream(g_pMUX, cp));
6995                     cp->b_IsSetup = TRUE;
6996                 }
6997             }
6998 
6999             console = new ConsoleCanvas( gFrame );                    // the console
7000             console->SetColorScheme( global_color_scheme );
7001             break;
7002 
7003         case 2:
7004         {
7005             if (m_initializing)
7006                 break;
7007             m_initializing = true;
7008             g_pi_manager->LoadAllPlugIns( true, false );
7009 
7010 //            RequestNewToolbars();
7011             RequestNewMasterToolbar();
7012             // A Plugin (e.g. Squiddio) may have redefined some routepoint icons...
7013             // Reload all icons, to be sure.
7014             if(pWayPointMan)
7015                 pWayPointMan->ReloadRoutepointIcons();
7016 
7017             if( g_MainToolbar )
7018                 g_MainToolbar->EnableTool( ID_SETTINGS, false );
7019 
7020             wxString perspective;
7021             pConfig->SetPath( _T ( "/AUI" ) );
7022             pConfig->Read( _T ( "AUIPerspective" ), &perspective );
7023 
7024             // Make sure the perspective saved in the config file is "reasonable"
7025             // In particular, the perspective should have an entry for every
7026             // windows added to the AUI manager so far.
7027             // If any are not found, then use the default layout
7028 
7029             bool bno_load = false;
7030 
7031             wxArrayString name_array;
7032             wxStringTokenizer st(perspective, _T("|;"));
7033             while( st.HasMoreTokens() )
7034             {
7035                 wxString s1 = st.GetNextToken();
7036                 if(s1.StartsWith(_T("name="))){
7037                     wxString sc = s1.AfterFirst('=');
7038                     name_array.Add(sc);
7039                 }
7040             }
7041 
7042             wxAuiPaneInfoArray pane_array_val = g_pauimgr->GetAllPanes();
7043             for( unsigned int i = 0; i < pane_array_val.GetCount(); i++ ) {
7044                 wxAuiPaneInfo pane = pane_array_val.Item( i );
7045 
7046                 // If we find a pane that is not in the perspective,
7047                 //  then we should not load the perspective at all
7048                 if(name_array.Index(pane.name) == wxNOT_FOUND) {
7049                     bno_load = true;
7050                     break;
7051                 }
7052             }
7053 
7054             if( !bno_load )
7055                 g_pauimgr->LoadPerspective( perspective, false );
7056 
7057 #if 0
7058             // Undefine the canvas sizes as expressed by the loaded perspective
7059             for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7060                 ChartCanvas *cc = g_canvasArray.Item(i);
7061                 if(cc)
7062                     g_pauimgr->GetPane(cc).MinSize(10,10);
7063             }
7064 
7065  #endif
7066 
7067             // Touch up the AUI manager
7068             //  Make sure that any pane width is reasonable default value
7069             for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7070                 ChartCanvas *cc = g_canvasArray.Item(i);
7071                 if(cc){
7072                     wxSize frameSize = GetClientSize();
7073                     wxSize minSize = g_pauimgr->GetPane(cc).min_size;
7074                     int width = wxMax(minSize.x, frameSize.x / 10);
7075                     g_pauimgr->GetPane(cc).MinSize(frameSize.x * 1 / 5, frameSize.y);
7076                 }
7077             }
7078             g_pauimgr->Update();
7079 
7080             //   Notify all the AUI PlugIns so that they may syncronize with the Perspective
7081             g_pi_manager->NotifyAuiPlugIns();
7082             g_pi_manager->ShowDeferredBlacklistMessages(); //  Give the use dialog on any blacklisted PlugIns
7083             g_pi_manager->CallLateInit();
7084 
7085             //  If any PlugIn implements PlugIn Charts, we need to re-run the initial chart load logic
7086             //  to select the correct chart as saved from the last run of the app.
7087             //  This will be triggered at the next DoChartUpdate()
7088             if( g_pi_manager->IsAnyPlugInChartEnabled() ){
7089 
7090                 for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7091                     ChartCanvas *cc = g_canvasArray.Item(i);
7092                     if(cc)
7093                         cc->SetFirstAuto(true);
7094                 }
7095 
7096                 b_reloadForPlugins = true;
7097             }
7098 
7099             break;
7100         }
7101 
7102         case 3:
7103         {
7104             if(g_MainToolbar){
7105                 g_MainToolbar->SetAutoHide(g_bAutoHideToolbar);
7106                 g_MainToolbar->SetAutoHideTimer(g_nAutoHideToolbar);
7107             }
7108 
7109 #if 0   // per-canvas toolbars deprecated in MUI
7110 
7111             // .. for each canvas...
7112             for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7113                 ChartCanvas *cc = g_canvasArray.Item(i);
7114                 cc->RequestNewCanvasToolbar( true );
7115 
7116                 if(cc && cc->GetToolbarEnable()){
7117                     cc->GetToolbar()->SetAutoHide(g_bAutoHideToolbar);
7118                     cc->GetToolbar()->SetAutoHideTimer(g_nAutoHideToolbar);
7119                 }
7120             }
7121 #endif
7122 
7123             break;
7124         }
7125 
7126         case 4:
7127         {
7128             g_options = new options( this, -1, _("Options") );
7129             //g_options->SetColorScheme(global_color_scheme);
7130             //applyDarkAppearanceToWindow(g_options->MacGetTopLevelWindowRef());
7131 
7132             // needed to ensure that the chart window starts with keyboard focus
7133             SurfaceAllCanvasToolbars();
7134 
7135             BuildiENCToolbar( true );
7136 
7137             break;
7138         }
7139 
7140         case 5:
7141         {
7142             if ( !g_params.empty() ) {
7143                 for ( size_t n = 0; n < g_params.size(); n++ )
7144                 {
7145                     wxString path = g_params[n];
7146                     if( ::wxFileExists( path ) )
7147                     {
7148                         NavObjectCollection1 *pSet = new NavObjectCollection1;
7149                         pSet->load_file(path.fn_str());
7150                         int wpt_dups;
7151 
7152                         pSet->LoadAllGPXObjects( !pSet->IsOpenCPN(),wpt_dups , true ); // Import with full vizibility of names and objects
7153                         LLBBox box = pSet->GetBBox();
7154                         if (box.GetValid()) {
7155                             CenterView(GetPrimaryCanvas(), box);
7156                         }
7157                         delete pSet;
7158                     }
7159                 }
7160             }
7161             break;
7162 
7163         }
7164         default:
7165         {
7166             // Last call....
7167             wxLogMessage(_T("OnInitTimer...Last Call"));
7168 
7169             PositionIENCToolbar();
7170 
7171             g_bDeferredInitDone = true;
7172 
7173             GetPrimaryCanvas()->SetFocus();
7174             g_focusCanvas = GetPrimaryCanvas();
7175 
7176 #ifndef __OCPN__ANDROID__
7177             gFrame->Raise();
7178 #endif
7179 
7180             if(b_reloadForPlugins){
7181                 DoChartUpdate();
7182                 ChartsRefresh();
7183             }
7184 
7185             wxLogMessage(_T("OnInitTimer...Finalize Canvases"));
7186 
7187             for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7188                 ChartCanvas *cc = g_canvasArray.Item(i);
7189                 if(cc){
7190                     cc->CreateMUIBar();
7191                     cc->CheckGroupValid();
7192                 }
7193             }
7194 
7195 #ifdef __OCPN__ANDROID__
7196             androidEnableBackButton( true );
7197             androidEnableRotation();
7198 #endif
7199 
7200             if( g_MainToolbar )
7201                 g_MainToolbar->EnableTool( ID_SETTINGS, true );
7202 
7203             break;
7204         }
7205     }   // switch
7206 
7207     if(!g_bDeferredInitDone)
7208         InitTimer.Start( 100, wxTIMER_ONE_SHOT );
7209 
7210     RefreshAllCanvas( true );
7211 }
7212 
7213 //    Manage the application memory footprint on a periodic schedule
OnMemFootTimer(wxTimerEvent & event)7214 void MyFrame::OnMemFootTimer( wxTimerEvent& event )
7215 {
7216     MemFootTimer.Stop();
7217 
7218     int memsize = GetApplicationMemoryUse();
7219 
7220     g_MemFootMB = 100;
7221     printf( "Memsize: %d  \n", memsize );
7222     // The application memory usage has exceeded the target, so try to manage it down....
7223     if( memsize > ( g_MemFootMB * 1000 ) ) {
7224         ChartCanvas *cc = GetPrimaryCanvas();
7225         if( ChartData && cc ) {
7226             //    Get a local copy of the cache info
7227             wxArrayPtrVoid *pCache = ChartData->GetChartCache();
7228             unsigned int nCache = pCache->GetCount();
7229             CacheEntry *pcea = new CacheEntry[nCache];
7230 
7231             for( unsigned int i = 0; i < nCache; i++ ) {
7232                 CacheEntry *pce = (CacheEntry *) ( pCache->Item( i ) );
7233                 pcea[i] = *pce;                  //ChartBase *Ch = (ChartBase *)pce->pChart;
7234             }
7235 
7236             if( nCache > 1 ) {
7237                 //    Bubble Sort the local cache entry array
7238                 bool b_cont = true;
7239                 while( b_cont ) {
7240                     b_cont = false;
7241                     for( unsigned int i = 0; i < nCache - 1; i++ ) {
7242                         if( pcea[i].RecentTime > pcea[i + 1].RecentTime ) {
7243                             CacheEntry tmp = pcea[i];
7244                             pcea[i] = pcea[i + 1];
7245                             pcea[i + 1] = tmp;
7246                             b_cont = true;
7247                             break;
7248                         }
7249                     }
7250                 }
7251 
7252                 //    Free up some chart cache entries until the memory footprint target is realized
7253 
7254                 unsigned int idelete = 0;                 // starting at top. which is oldest
7255                 unsigned int idelete_max = pCache->GetCount();
7256 
7257                 //    How many can be deleted?
7258                 unsigned int minimum_cache = 1;
7259                 if( cc->GetQuiltMode() ) minimum_cache = cc->GetQuiltChartCount();
7260 
7261                 while( ( memsize > ( g_MemFootMB * 1000 ) )
7262                         && ( pCache->GetCount() > minimum_cache ) && ( idelete < idelete_max ) ) {
7263                     int memsizeb = memsize;
7264 
7265                     ChartData->DeleteCacheChart( (ChartBase *) pcea[idelete].pChart );
7266                     idelete++;
7267                     memsize = GetApplicationMemoryUse();
7268                     printf( "delete, before: %d  after: %d\n", memsizeb, memsize );
7269                 }
7270 
7271             }
7272 
7273             delete[] pcea;
7274         }
7275 
7276     }
7277 
7278     MemFootTimer.Start( 9000, wxTIMER_CONTINUOUS );
7279 }
7280 
7281 int ut_index;
7282 
CheckToolbarPosition()7283 void MyFrame::CheckToolbarPosition()
7284 {
7285 #ifdef __WXMAC__
7286     // Manage Full Screen mode on Mac Mojave 10.14
7287     static bool bMaximized;
7288 
7289     if(IsMaximized() && !bMaximized){
7290         bMaximized = true;
7291         if(g_MainToolbar){
7292             g_MainToolbar->SetYAuxOffset(g_MainToolbar->GetToolSize().y * 15 / 10 );
7293             g_MainToolbar->RePosition();
7294             g_MainToolbar->Realize();
7295         }
7296         PositionIENCToolbar();
7297     }
7298     else if(!IsMaximized() && bMaximized){
7299          bMaximized = false;
7300          if(g_MainToolbar){
7301             g_MainToolbar->SetYAuxOffset(0);
7302             g_MainToolbar->SetDockY( -1 );
7303             g_MainToolbar->RePosition();
7304             g_MainToolbar->Realize();
7305         }
7306         PositionIENCToolbar();
7307     }
7308 #endif
7309 }
7310 
OnFrameTimer1(wxTimerEvent & event)7311 void MyFrame::OnFrameTimer1( wxTimerEvent& event )
7312 {
7313     CheckToolbarPosition();
7314 
7315     if( ! g_bPauseTest && (g_unit_test_1 || g_unit_test_2) ) {
7316 //            if((0 == ut_index) && GetQuiltMode())
7317 //                  ToggleQuiltMode();
7318 
7319         // We use only one canvas for the unit tests, so far...
7320         ChartCanvas *cc = GetPrimaryCanvas();
7321 
7322         cc->m_bFollow = false;
7323         if( g_MainToolbar && g_MainToolbar->GetToolbar() )
7324             g_MainToolbar->GetToolbar()->ToggleTool( ID_FOLLOW, cc->m_bFollow );
7325         int ut_index_max = ( ( g_unit_test_1 > 0 ) ? ( g_unit_test_1 - 1 ) : INT_MAX );
7326 
7327         if( ChartData ) {
7328             if( cc->m_groupIndex > 0 ) {
7329                 while (ut_index < ChartData->GetChartTableEntries() && !ChartData->IsChartInGroup( ut_index, cc->m_groupIndex ) ) {
7330                     ut_index++;
7331                 }
7332             }
7333             if( ut_index < ChartData->GetChartTableEntries() ) {
7334                 // printf("%d / %d\n", ut_index, ChartData->GetChartTableEntries());
7335                 const ChartTableEntry *cte = &ChartData->GetChartTableEntry( ut_index );
7336 
7337                 double clat = ( cte->GetLatMax() + cte->GetLatMin() ) / 2;
7338                 double clon = ( cte->GetLonMax() + cte->GetLonMin() ) / 2;
7339 
7340                 vLat = clat;
7341                 vLon = clon;
7342 
7343                 cc->SetViewPoint( clat, clon );
7344 
7345                 if( cc->GetQuiltMode() ) {
7346                     if( cc->IsChartQuiltableRef( ut_index ) )
7347                         cc->SelectQuiltRefdbChart( ut_index );
7348                 } else
7349                     cc->SelectdbChart( ut_index );
7350 
7351                 double ppm; // final ppm scale to use
7352                 if (g_unit_test_1) {
7353                     ppm = cc->GetCanvasScaleFactor() / cte->GetScale();
7354                     ppm /= 2;
7355                 }
7356                 else {
7357                     double rw, rh; // width, height
7358                     int ww, wh;    // chart window width, height
7359 
7360                     // width in nm
7361                     DistanceBearingMercator( cte->GetLatMin(), cte->GetLonMin(), cte->GetLatMin(),
7362                               cte->GetLonMax(), NULL, &rw );
7363 
7364                     // height in nm
7365                     DistanceBearingMercator( cte->GetLatMin(), cte->GetLonMin(), cte->GetLatMax(),
7366                              cte->GetLonMin(), NULL, &rh );
7367 
7368                     cc->GetSize( &ww, &wh );
7369                     ppm = wxMin(ww/(rw*1852), wh/(rh*1852)) * ( 100 - fabs( clat ) ) / 90;
7370                     ppm = wxMin(ppm, 1.0);
7371                 }
7372                 cc->SetVPScale( ppm );
7373 
7374                 cc->ReloadVP();
7375 
7376                 ut_index++;
7377                 if( ut_index > ut_index_max )
7378                     exit(0);
7379             }
7380             else {
7381                 _exit(0);
7382             }
7383         }
7384     }
7385     g_tick++;
7386 
7387 //      Listen for quitflag to be set, requesting application close
7388     if( quitflag ) {
7389         wxLogMessage( _T("Got quitflag from SIGNAL") );
7390         FrameTimer1.Stop();
7391         Close();
7392         return;
7393     }
7394 
7395     if( bDBUpdateInProgress ) return;
7396 
7397     FrameTimer1.Stop();
7398 
7399     //  If tracking carryover was found in config file, enable tracking as soon as
7400     //  GPS become valid
7401     if(g_bDeferredStartTrack){
7402         if(!g_bTrackActive){
7403             if(bGPSValid){
7404                 gFrame->TrackOn();
7405                 g_bDeferredStartTrack = false;
7406             }
7407         }
7408         else {                                  // tracking has been manually activated
7409             g_bDeferredStartTrack = false;
7410         }
7411     }
7412 
7413 //  Update and check watchdog timer for GPS data source
7414     gGPS_Watchdog--;
7415     if( gGPS_Watchdog <= 0 ) {
7416         bGPSValid = false;
7417         if( gGPS_Watchdog == 0  ){
7418             wxString msg;
7419             msg.Printf( _T("   ***GPS Watchdog timeout at Lat:%g   Lon: %g"), gLat, gLon );
7420             wxLogMessage(msg);
7421         }
7422         gSog = NAN;
7423         gCog = NAN;
7424         gRmcDate.Empty();
7425         gRmcTime.Empty();
7426     }
7427 
7428 //  Update and check watchdog timer for Mag Heading data source
7429     gHDx_Watchdog--;
7430     if( gHDx_Watchdog <= 0 ) {
7431         gHdm = NAN;
7432         if( g_nNMEADebug && ( gHDx_Watchdog == 0 ) ) wxLogMessage(
7433                 _T("   ***HDx Watchdog timeout...") );
7434     }
7435 
7436 //  Update and check watchdog timer for True Heading data source
7437     gHDT_Watchdog--;
7438     if( gHDT_Watchdog <= 0 ) {
7439         g_bHDT_Rx = false;
7440         gHdt = NAN;
7441         if( g_nNMEADebug && ( gHDT_Watchdog == 0 ) ) wxLogMessage(
7442                 _T("   ***HDT Watchdog timeout...") );
7443     }
7444 
7445     //  Update and check watchdog timer for Magnetic Variation data source
7446     gVAR_Watchdog--;
7447     if( gVAR_Watchdog <= 0 ) {
7448         g_bVAR_Rx = false;
7449         if( g_nNMEADebug && ( gVAR_Watchdog == 0 ) ) wxLogMessage(
7450             _T("   ***VAR Watchdog timeout...") );
7451     }
7452     //  Update and check watchdog timer for GSV (Satellite data)
7453     gSAT_Watchdog--;
7454     if( gSAT_Watchdog <= 0 ) {
7455         g_bSatValid = false;
7456         g_SatsInView = 0;
7457         if( g_nNMEADebug && ( gSAT_Watchdog == 0 ) ) wxLogMessage(
7458                 _T("   ***SAT Watchdog timeout...") );
7459     }
7460 
7461     //    Build and send a Position Fix event to PlugIns
7462     if( g_pi_manager )
7463     {
7464         GenericPosDatEx GPSData;
7465         GPSData.kLat = gLat;
7466         GPSData.kLon = gLon;
7467         GPSData.kCog = gCog;
7468         GPSData.kSog = gSog;
7469         GPSData.kVar = gVar;
7470         GPSData.kHdm = gHdm;
7471         GPSData.kHdt = gHdt;
7472         GPSData.nSats = g_SatsInView;
7473 
7474         GPSData.FixTime = m_fixtime;
7475 
7476         g_pi_manager->SendPositionFixToAllPlugIns( &GPSData );
7477     }
7478 
7479     //   Check for anchorwatch alarms                                 // pjotrc 2010.02.15
7480     if( pAnchorWatchPoint1 ) {
7481         double dist;
7482         double brg;
7483         DistanceBearingMercator( pAnchorWatchPoint1->m_lat, pAnchorWatchPoint1->m_lon, gLat, gLon,
7484                 &brg, &dist );
7485         double d = g_nAWMax;
7486         ( pAnchorWatchPoint1->GetName() ).ToDouble( &d );
7487         d = AnchorDistFix( d, AnchorPointMinDist, g_nAWMax );
7488         bool toofar = false;
7489         bool tooclose = false;
7490         if( d >= 0.0 ) toofar = ( dist * 1852. > d );
7491         if( d < 0.0 ) tooclose = ( dist * 1852 < -d );
7492 
7493         if( tooclose || toofar )
7494             AnchorAlertOn1 = true;
7495         else
7496             AnchorAlertOn1 = false;
7497     } else
7498         AnchorAlertOn1 = false;
7499 
7500     if( pAnchorWatchPoint2 ) {
7501         double dist;
7502         double brg;
7503         DistanceBearingMercator( pAnchorWatchPoint2->m_lat, pAnchorWatchPoint2->m_lon, gLat, gLon,
7504                 &brg, &dist );
7505 
7506         double d = g_nAWMax;
7507         ( pAnchorWatchPoint2->GetName() ).ToDouble( &d );
7508         d = AnchorDistFix( d, AnchorPointMinDist, g_nAWMax );
7509         bool toofar = false;
7510         bool tooclose = false;
7511         if( d >= 0 ) toofar = ( dist * 1852. > d );
7512         if( d < 0 ) tooclose = ( dist * 1852 < -d );
7513 
7514         if( tooclose || toofar ) AnchorAlertOn2 = true;
7515         else
7516             AnchorAlertOn2 = false;
7517     } else
7518         AnchorAlertOn2 = false;
7519 
7520     if( (pAnchorWatchPoint1 || pAnchorWatchPoint2) && !bGPSValid )
7521         AnchorAlertOn1 = true;
7522 
7523 //  Send current nav status data to log file on every half hour   // pjotrc 2010.02.09
7524 
7525     wxDateTime lognow = wxDateTime::Now();   // pjotrc 2010.02.09
7526     int hourLOC = lognow.GetHour();
7527     int minuteLOC = lognow.GetMinute();
7528     lognow.MakeGMT();
7529     int minuteUTC = lognow.GetMinute();
7530     int second = lognow.GetSecond();
7531 
7532     wxTimeSpan logspan = lognow.Subtract( g_loglast_time );
7533     if( ( logspan.IsLongerThan( wxTimeSpan( 0, 30, 0, 0 ) ) ) || ( minuteUTC == 0 )
7534             || ( minuteUTC == 30 ) ) {
7535         if( logspan.IsLongerThan( wxTimeSpan( 0, 1, 0, 0 ) ) ) {
7536             wxString day = lognow.FormatISODate();
7537             wxString utc = lognow.FormatISOTime();
7538             wxString navmsg = _T("LOGBOOK:  ");
7539             navmsg += day;
7540             navmsg += _T(" ");
7541             navmsg += utc;
7542             navmsg += _T(" UTC ");
7543 
7544             if( bGPSValid ) {
7545                 wxString data;
7546                 data.Printf( _T(" GPS Lat %10.5f Lon %10.5f "), gLat, gLon );
7547                 navmsg += data;
7548 
7549                 wxString cog;
7550                 if( std::isnan(gCog) ) cog.Printf( _T("COG ----- ") );
7551                 else
7552                     cog.Printf( _T("COG %10.5f "), gCog );
7553 
7554                 wxString sog;
7555                 if( std::isnan(gSog) ) sog.Printf( _T("SOG -----  ") );
7556                 else
7557                     sog.Printf( _T("SOG %6.2f ") + getUsrSpeedUnit(), toUsrSpeed( gSog ) );
7558 
7559                 navmsg += cog;
7560                 navmsg += sog;
7561             } else {
7562                 wxString data;
7563                 data.Printf( _T(" DR Lat %10.5f Lon %10.5f"), gLat, gLon );
7564                 navmsg += data;
7565             }
7566             wxLogMessage( navmsg );
7567             g_loglast_time = lognow;
7568 
7569             int bells = ( hourLOC % 4 ) * 2;     // 2 bells each hour
7570             if( minuteLOC != 0 ) bells++;       // + 1 bell on 30 minutes
7571             if( !bells ) bells = 8;     // 0 is 8 bells
7572 
7573             if( g_bPlayShipsBells && ( ( minuteLOC == 0 ) || ( minuteLOC == 30 ) ) ) {
7574                 m_BellsToPlay = bells;
7575                 wxCommandEvent ev(BELLS_PLAYED_EVTYPE);
7576                 wxPostEvent(this, ev);
7577             }
7578         }
7579     }
7580 
7581     if( ShouldRestartTrack() )
7582         TrackDailyRestart();
7583 
7584     // If no alerts are on, then safe to resume sleeping
7585     if(g_bSleep && !AnchorAlertOn1 && !AnchorAlertOn2){
7586         FrameTimer1.Start( TIMER_GFRAME_1, wxTIMER_CONTINUOUS );
7587         return;
7588     }
7589 
7590 //      Update the Toolbar Status windows and lower status bar the first time watchdog times out
7591     if( ( gGPS_Watchdog == 0 ) || ( gSAT_Watchdog == 0 ) ) {
7592         wxString sogcog( _T("SOG --- ") + getUsrSpeedUnit() + + _T("     ") + _T(" COG ---\u00B0") );
7593         if( GetStatusBar() ) SetStatusText( sogcog, STAT_FIELD_SOGCOG );
7594 
7595         gCog = 0.0;                                 // say speed is zero to kill ownship predictor
7596     }
7597 
7598 //TODO
7599 //  Not needed?
7600 #if 0
7601 #if !defined(__WXGTK__) && !defined(__WXQT__)
7602     {
7603         double cursor_lat, cursor_lon;
7604         GetPrimaryCanvas()->GetCursorLatLon( &cursor_lat, &cursor_lon );
7605         GetPrimaryCanvas()->SetCursorStatus(cursor_lat, cursor_lon);
7606     }
7607 #endif
7608 #endif
7609 
7610 //      Update the chart database and displayed chart
7611     bool bnew_view = false;
7612 
7613 //    Do the chart update based on the global update period currently set
7614 //    If in COG UP mode, the chart update is handled by COG Update timer
7615     if( /*!g_bCourseUp &&*/ (0 != g_ChartUpdatePeriod ) ) {
7616         if (0 == m_ChartUpdatePeriod--) {
7617             bnew_view = DoChartUpdate();
7618             m_ChartUpdatePeriod = g_ChartUpdatePeriod;
7619         }
7620     }
7621 
7622     nBlinkerTick++;
7623 
7624     // For each canvas....
7625     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7626         ChartCanvas *cc = g_canvasArray.Item(i);
7627         if(cc){
7628 
7629             cc->DrawBlinkObjects();
7630 
7631 //      Update the active route, if any
7632             if( g_pRouteMan->UpdateProgress() ) {
7633         //    This RefreshRect will cause any active routepoint to blink
7634                 if( g_pRouteMan->GetpActiveRoute() )
7635                     cc->RefreshRect( g_blink_rect, false );
7636             }
7637 
7638 //  Force own-ship drawing parameters
7639             cc->SetOwnShipState( SHIP_NORMAL );
7640 
7641             if( cc->GetQuiltMode() ) {
7642                 double erf = cc->GetQuiltMaxErrorFactor();
7643                 if( erf > 0.02 )
7644                     cc->SetOwnShipState( SHIP_LOWACCURACY );
7645             } else {
7646                 if( cc->m_singleChart ) {
7647                     if( cc->m_singleChart->GetChart_Error_Factor() > 0.02 )
7648                         cc->SetOwnShipState( SHIP_LOWACCURACY );
7649                 }
7650             }
7651 
7652             if( !bGPSValid )
7653                 cc->SetOwnShipState( SHIP_INVALID );
7654 
7655             if( bGPSValid != m_last_bGPSValid ) {
7656                 if(!g_bopengl)
7657                     cc->UpdateShips();
7658 
7659                 bnew_view = true;                  // force a full Refresh()
7660             }
7661         }
7662     }
7663 
7664     m_last_bGPSValid = bGPSValid;
7665 
7666     //    If any PlugIn requested dynamic overlay callbacks, force a full canvas refresh
7667     //    thus, ensuring at least 1 Hz. callback.
7668     bool brq_dynamic = false;
7669     if( g_pi_manager ) {
7670         ArrayOfPlugIns *pplugin_array = g_pi_manager->GetPlugInArray();
7671         for( unsigned int i = 0; i < pplugin_array->GetCount(); i++ ) {
7672             PlugInContainer *pic = pplugin_array->Item( i );
7673             if( pic->m_bEnabled && pic->m_bInitState ) {
7674                 if( pic->m_cap_flag & WANTS_DYNAMIC_OPENGL_OVERLAY_CALLBACK ) {
7675                     brq_dynamic = true;
7676                     break;
7677                 }
7678             }
7679         }
7680 
7681         if( brq_dynamic )
7682             bnew_view = true;
7683     }
7684 
7685 
7686     //  Make sure we get a redraw and alert sound on AnchorWatch excursions.
7687     if(AnchorAlertOn1 || AnchorAlertOn2)
7688         bnew_view = true;
7689 
7690     // For each canvas....
7691     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7692             ChartCanvas *cc = g_canvasArray.Item(i);
7693             if(cc){
7694 
7695                 if(g_bopengl) {
7696 #ifdef ocpnUSE_GL
7697 					if (cc->GetglCanvas()) {
7698 						if (m_fixtime - cc->GetglCanvas()->m_last_render_time > 0)
7699 							bnew_view = true;
7700 					}
7701 
7702                     if( AnyAISTargetsOnscreen( cc, cc->GetVP() ) )
7703                         bnew_view = true;
7704 
7705                     if(bnew_view) /* full frame in opengl mode */
7706                         cc->Refresh(false);
7707 #endif
7708                 } else {
7709 //  Invalidate the ChartCanvas window appropriately
7710 //    In non-follow mode, invalidate the rectangles containing the AIS targets and the ownship, etc...
7711 //    In follow mode, if there has already been a full screen refresh, there is no need to check ownship or AIS,
7712 //       since they will be always drawn on the full screen paint.
7713 
7714                 if( ( !cc->m_bFollow ) || (cc->GetUpMode() != NORTH_UP_MODE) ) {
7715                     cc->UpdateShips();
7716                     cc->UpdateAIS();
7717                     cc->UpdateAlerts();
7718                 } else {
7719                     if( !bnew_view ) {                   // There has not been a Refresh() yet.....
7720                         cc->UpdateAIS();
7721                         cc->UpdateAlerts();
7722                     }
7723                 }
7724             }
7725         }
7726     }
7727 
7728     if( g_pais_query_dialog_active && g_pais_query_dialog_active->IsShown() )
7729         g_pais_query_dialog_active->UpdateText();
7730 
7731     // Refresh AIS target list every 5 seconds to avoid blinking
7732     if( g_pAISTargetList && ( 0 == ( g_tick % ( 5 ) ) ) )
7733         g_pAISTargetList->UpdateAISTargetList();
7734 
7735     //  Pick up any change Toolbar status displays
7736     UpdateGPSCompassStatusBoxes();
7737     UpdateAISTool();
7738 
7739     if( console && console->IsShown() ) {
7740 //            console->Raise();
7741         console->RefreshConsoleData();
7742     }
7743 
7744     //  This little hack fixes a problem seen with some UniChrome OpenGL drivers
7745     //  We need a deferred resize to get glDrawPixels() to work right.
7746     //  So we set a trigger to generate a resize after 5 seconds....
7747     //  See the "UniChrome" hack elsewhere
7748     if( m_bdefer_resize ) {
7749         if( 0 == ( g_tick % ( 5 ) ) ) {
7750             printf( "___RESIZE\n" );
7751             SetSize( m_defer_size );
7752             g_pauimgr->Update();
7753             m_bdefer_resize = false;
7754         }
7755     }
7756 
7757 #ifdef __OCPN__ANDROID__
7758 
7759     // Update the navobj file on a fixed schedule (5 minutes)
7760     // This will do nothing if the navobj.changes file is empty and clean
7761     if(((g_tick % g_FlushNavobjChangesTimeout) == 0) || g_FlushNavobjChanges){
7762         if(pConfig && pConfig->IsChangesFileDirty()){
7763             androidShowBusyIcon();
7764             wxStopWatch update_sw;
7765             pConfig->UpdateNavObj( true );
7766             wxString msg = wxString::Format(_T("OpenCPN periodic navobj update took %ld ms."), update_sw.Time());
7767             wxLogMessage( msg );
7768             qDebug() << msg.mb_str();
7769             g_FlushNavobjChanges = false;
7770             androidHideBusyIcon();
7771         }
7772     }
7773 
7774 #endif
7775 
7776     if (g_unit_test_2)
7777         FrameTimer1.Start( TIMER_GFRAME_1*3, wxTIMER_CONTINUOUS );
7778     else
7779         FrameTimer1.Start( TIMER_GFRAME_1, wxTIMER_CONTINUOUS );
7780 }
7781 
GetMag(double a)7782 double MyFrame::GetMag(double a)
7783 {
7784     if(!std::isnan(gVar)){
7785         if((a - gVar) >360.)
7786             return (a - gVar - 360.);
7787         else
7788             return ((a - gVar) >= 0.) ? (a - gVar) : (a - gVar + 360.);
7789     }
7790     else{
7791         if((a - g_UserVar) >360.)
7792             return (a - g_UserVar - 360.);
7793         else
7794             return ((a - g_UserVar) >= 0.) ? (a - g_UserVar) : (a - g_UserVar + 360.);
7795     }
7796 }
7797 
GetMag(double a,double lat,double lon)7798 double MyFrame::GetMag(double a, double lat, double lon)
7799 {
7800     double Variance = std::isnan( gVar ) ? g_UserVar : gVar;
7801     if(g_pi_manager && g_pi_manager->IsPlugInAvailable(_T("WMM"))){
7802 
7803         // Request variation at a specific lat/lon
7804 
7805         // Note that the requested value is returned sometime later in the event stream,
7806         // so there may be invalid data returned on the first call to this method.
7807         // In the case of rollover windows, the value is requested continuously, so will be correct very soon.
7808         wxDateTime now = wxDateTime::Now();
7809         SendJSON_WMM_Var_Request(lat, lon, now);
7810         if ( fabs(gQueryVar) < 360.0 )   // Don't use WMM variance if not updated yet
7811             Variance = gQueryVar;
7812     }
7813     if((a - Variance ) > 360.)
7814         return (a - Variance - 360.);
7815     else
7816         return ((a - Variance) >= 0.) ? (a - Variance) : (a - Variance + 360.);
7817 }
7818 
SendJSON_WMM_Var_Request(double lat,double lon,wxDateTime date)7819 bool MyFrame::SendJSON_WMM_Var_Request(double lat, double lon, wxDateTime date)
7820 {
7821     if(g_pi_manager){
7822         wxJSONValue v;
7823         v[_T("Lat")] = lat;
7824         v[_T("Lon")] = lon;
7825         v[_T("Year")] = date.GetYear();
7826         v[_T("Month")] = date.GetMonth();
7827         v[_T("Day")] = date.GetDay();
7828 
7829         g_pi_manager->SendJSONMessageToAllPlugins(_T("WMM_VARIATION_REQUEST"), v);
7830         return true;
7831     }
7832     else
7833         return false;
7834 }
7835 
TouchAISActive(void)7836 void MyFrame::TouchAISActive( void )
7837 {
7838     // .. for each canvas...
7839     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7840         ChartCanvas *cc = g_canvasArray.Item(i);
7841         if(cc)
7842             cc->TouchAISToolActive();
7843     }
7844 }
7845 
UpdateAISTool(void)7846 void MyFrame::UpdateAISTool( void )
7847 {
7848     if(!g_pAIS) return;
7849 
7850     // .. for each canvas...
7851     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7852         ChartCanvas *cc = g_canvasArray.Item(i);
7853         if(cc)
7854             cc->UpdateAISTBTool();
7855     }
7856 }
7857 
7858 //    Cause refresh of active Tide/Current data, if displayed
OnFrameTCTimer(wxTimerEvent & event)7859 void MyFrame::OnFrameTCTimer( wxTimerEvent& event )
7860 {
7861     // ..For each canvas...
7862     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7863         ChartCanvas *cc = g_canvasArray.Item(i);
7864         if(cc)
7865             cc->SetbTCUpdate( true );
7866     }
7867 
7868     RefreshAllCanvas( false );
7869 }
7870 
7871 //    Keep and update the Viewport rotation angle according to average COG for COGUP mode
OnFrameCOGTimer(wxTimerEvent & event)7872 void MyFrame::OnFrameCOGTimer( wxTimerEvent& event )
7873 {
7874     // ..For each canvas...
7875     bool b_rotate = false;
7876     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7877         ChartCanvas *cc = g_canvasArray.Item(i);
7878         if(cc)
7879             b_rotate |= (cc->GetUpMode() != NORTH_UP_MODE);
7880     }
7881 
7882     if(!b_rotate){
7883         FrameCOGTimer.Stop();
7884         return;
7885     }
7886 
7887 
7888     DoCOGSet();
7889 
7890     //    Restart the timer, max frequency is 10 hz.
7891     int period_ms = 100;
7892     if( g_COGAvgSec > 0 )
7893         period_ms = g_COGAvgSec * 1000;
7894     FrameCOGTimer.Start( period_ms, wxTIMER_CONTINUOUS );
7895 }
7896 
DoCOGSet(void)7897 void MyFrame::DoCOGSet( void )
7898 {
7899     // ..For each canvas...
7900     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7901         ChartCanvas *cc = g_canvasArray.Item(i);
7902         if(cc)
7903             cc->DoCanvasCOGSet();
7904     }
7905 
7906 }
7907 
RenderShadowText(wxDC * pdc,wxFont * pFont,wxString & str,int x,int y)7908 void RenderShadowText( wxDC *pdc, wxFont *pFont, wxString& str, int x, int y )
7909 {
7910 #ifdef DrawText
7911 #undef DrawText
7912 #define FIXIT
7913 #endif
7914 
7915     wxFont oldfont = pdc->GetFont(); // save current font
7916 
7917     pdc->SetFont( *pFont );
7918     pdc->SetTextForeground( GetGlobalColor( _T("CHGRF") ) );
7919     pdc->SetBackgroundMode( wxTRANSPARENT );
7920 
7921     pdc->DrawText( str, x, y + 1 );
7922     pdc->DrawText( str, x, y - 1 );
7923     pdc->DrawText( str, x + 1, y );
7924     pdc->DrawText( str, x - 1, y );
7925 
7926     pdc->SetTextForeground( GetGlobalColor( _T("CHBLK") ) );
7927 
7928     pdc->DrawText( str, x, y );
7929 
7930     pdc->SetFont( oldfont );                  // restore last font
7931 
7932 }
7933 
7934 //TODO How does this relate to per-canvas rotation?
UpdateRotationState(double rotation)7935 void MyFrame::UpdateRotationState( double rotation )
7936 {
7937     //  If rotated manually, we switch to NORTHUP
7938     g_bCourseUp = false;
7939 
7940     if(fabs(rotation) > .001){
7941         SetMenubarItemState( ID_MENU_CHART_COGUP, false );
7942         SetMenubarItemState( ID_MENU_CHART_NORTHUP, true );
7943         if(m_pMenuBar){
7944             m_pMenuBar->SetLabel( ID_MENU_CHART_NORTHUP, _("Rotated Mode") );
7945         }
7946     }
7947     else{
7948         SetMenubarItemState( ID_MENU_CHART_COGUP, g_bCourseUp );
7949         SetMenubarItemState( ID_MENU_CHART_NORTHUP, !g_bCourseUp );
7950         if(m_pMenuBar){
7951             m_pMenuBar->SetLabel( ID_MENU_CHART_NORTHUP, _("North Up Mode") );
7952         }
7953     }
7954 
7955     UpdateGPSCompassStatusBoxes( true );
7956     DoChartUpdate();
7957 }
7958 
7959 
UpdateGPSCompassStatusBoxes(bool b_force_new)7960 void MyFrame::UpdateGPSCompassStatusBoxes( bool b_force_new )
7961 {
7962     // ..For each canvas...
7963     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
7964         ChartCanvas *cc = g_canvasArray.Item(i);
7965         if(cc)
7966             cc->UpdateGPSCompassStatusBox( b_force_new );
7967     }
7968 }
7969 
7970 //    Application memory footprint management
7971 
GetApplicationMemoryUse(void)7972 int MyFrame::GetApplicationMemoryUse( void )
7973 {
7974     int memsize = -1;
7975 #ifdef __linux__
7976 
7977     //    Use a contrived ps command to get the virtual memory size associated with this process
7978     wxWindow *fWin = wxWindow::FindFocus();
7979 
7980     wxArrayString outputArray;
7981     wxString cmd(_T("ps --no-headers -o vsize "));
7982     unsigned long pid = wxGetProcessId();
7983     wxString cmd1;
7984     cmd1.Printf(_T("%ld"), pid);
7985     cmd += cmd1;
7986     wxExecute(cmd, outputArray);
7987 
7988     if(outputArray.GetCount())
7989     {
7990         wxString s = outputArray.Item(0);
7991         long vtmp;
7992         if(s.ToLong(&vtmp))
7993         memsize = vtmp;
7994     }
7995 
7996     if(fWin)
7997     fWin->SetFocus();
7998 
7999 #endif
8000 
8001 #ifdef __WXMSW__
8002     HANDLE hProcess;
8003     PROCESS_MEMORY_COUNTERS pmc;
8004 
8005     unsigned long processID = wxGetProcessId();
8006 
8007     hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );
8008     if( NULL == hProcess ) return 0;
8009 
8010     if( GetProcessMemoryInfo( hProcess, &pmc, sizeof( pmc ) ) ) {
8011         /*
8012          printf( "\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount );
8013          printf( "\tPeakWorkingSetSize: 0x%08X\n",
8014          pmc.PeakWorkingSetSize );
8015          printf( "\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize );
8016          printf( "\tQuotaPeakPagedPoolUsage: 0x%08X\n",
8017          pmc.QuotaPeakPagedPoolUsage );
8018          printf( "\tQuotaPagedPoolUsage: 0x%08X\n",
8019          pmc.QuotaPagedPoolUsage );
8020          printf( "\tQuotaPeakNonPagedPoolUsage: 0x%08X\n",
8021          pmc.QuotaPeakNonPagedPoolUsage );
8022          printf( "\tQuotaNonPagedPoolUsage: 0x%08X\n",
8023          pmc.QuotaNonPagedPoolUsage );
8024          printf( "\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage );
8025          printf( "\tPeakPagefileUsage: 0x%08X\n",
8026          pmc.PeakPagefileUsage );
8027          */
8028         memsize = pmc.WorkingSetSize / 1024;
8029     }
8030 
8031     CloseHandle( hProcess );
8032 
8033 #endif
8034 
8035     return memsize;
8036 }
8037 
8038 
8039 
GetBestVPScale(ChartBase * pchart)8040 double MyFrame::GetBestVPScale( ChartBase *pchart )
8041 {
8042     return GetPrimaryCanvas()->GetBestVPScale( pchart );
8043 }
8044 
8045 
SetChartUpdatePeriod()8046 void MyFrame::SetChartUpdatePeriod( )
8047 {
8048     //    Set the chart update period based upon chart skew and skew compensator
8049 
8050     g_ChartUpdatePeriod = 0;            // General default
8051 
8052     // In non-GL, singlele-chart mode, rotation of skewed charts is very slow
8053     //  So we need to use a slower update time constant to preserve adequate UI performance
8054     bool bskewdc = false;
8055         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
8056             ChartCanvas *cc = g_canvasArray.Item(i);
8057             if(cc){
8058                 if( !g_bopengl && !cc->GetVP().b_quilt){
8059                     if ( fabs(cc->GetVP().skew) > 0.0001)
8060                         bskewdc = true;
8061                 }
8062                 if(cc->m_bFollow)
8063                     g_ChartUpdatePeriod = 1;
8064             }
8065         }
8066 
8067     if (bskewdc)
8068         g_ChartUpdatePeriod = g_SkewCompUpdatePeriod;
8069 
8070 
8071     m_ChartUpdatePeriod = g_ChartUpdatePeriod;
8072 }
8073 
SetChartThumbnail(int index)8074 void MyFrame::SetChartThumbnail( int index )
8075 {
8076     //TODO
8077 #if 0
8078     if( bDBUpdateInProgress ) return;
8079 
8080     if( NULL == pCurrentStack ) return;
8081     assert(ChartData != 0);
8082 
8083     if( NULL == pthumbwin ) return;
8084 
8085     if( NULL == cc1 ) return;
8086 
8087     bool bneedmove = false;
8088 
8089     if( index == -1 ) {
8090         wxRect thumb_rect_in_parent = pthumbwin->GetRect();
8091 
8092         pthumbwin->pThumbChart = NULL;
8093         pthumbwin->Show( false );
8094         cc1->RefreshRect( thumb_rect_in_parent, FALSE );
8095     }
8096 
8097 <<<<<<< HEAD
8098     //    Search the no-show array
8099     bool b_is_in_noshow = false;
8100     for( unsigned int i = 0; i < g_quilt_noshow_index_array.size(); i++ ) {
8101         if( g_quilt_noshow_index_array[i] == selected_dbIndex ) // chart is in the noshow list
8102 =======
8103     else
8104         if( index < pCurrentStack->nEntry ) {
8105             if( ( ChartData->GetCSChartType( pCurrentStack, index ) == CHART_TYPE_KAP )
8106                     || ( ChartData->GetCSChartType( pCurrentStack, index ) == CHART_TYPE_GEO )
8107                     || ( ChartData->GetCSChartType( pCurrentStack, index ) == CHART_TYPE_PLUGIN ) ) {
8108                 ChartBase *new_pThumbChart = ChartData->OpenChartFromStack( pCurrentStack, index );
8109                 if( new_pThumbChart )         // chart opened ok
8110 >>>>>>> multicanvas
8111                 {
8112 
8113                     ThumbData *pTD = new_pThumbChart->GetThumbData( 150, 150, gLat, gLon );
8114                     if( pTD ) {
8115                         pthumbwin->pThumbChart = new_pThumbChart;
8116 
8117                         pthumbwin->Resize();
8118                         pthumbwin->Show( true );
8119                         pthumbwin->Refresh( FALSE );
8120                         pthumbwin->Move( wxPoint( 4, 4 ) );
8121                         bneedmove = true;
8122                     }
8123 
8124                     else {
8125                         wxLogMessage(
8126                                 _T("    chart1.cpp:SetChartThumbnail...Could not create thumbnail") );
8127                         pthumbwin->pThumbChart = NULL;
8128                         pthumbwin->Show( false );
8129                         cc1->Refresh( FALSE );
8130                     }
8131 
8132                 } else                            // some problem opening chart
8133                 {
8134                     wxString fp = ChartData->GetFullPath( pCurrentStack, index );
8135                     fp.Prepend( _T("    chart1.cpp:SetChartThumbnail...Could not open chart ") );
8136                     wxLogMessage( fp );
8137                     pthumbwin->pThumbChart = NULL;
8138                     pthumbwin->Show( false );
8139                     cc1->Refresh( FALSE );
8140                 }
8141 
8142             } else {
8143                 ChartBase *new_pThumbChart = ChartData->OpenChartFromStack( pCurrentStack, index,
8144                         THUMB_ONLY );
8145 
8146                 pthumbwin->pThumbChart = new_pThumbChart;
8147 
8148                 if( new_pThumbChart ) {
8149                     ThumbData *pTD = new_pThumbChart->GetThumbData( 200, 200, gLat, gLon );
8150                     if( pTD ) {
8151                         pthumbwin->Resize();
8152                         pthumbwin->Show( true );
8153                         pthumbwin->Refresh( true );
8154                         pthumbwin->Move( wxPoint( 4, 4 ) );
8155                         bneedmove = true;
8156                     } else
8157                         pthumbwin->Show( false );
8158 
8159                     cc1->Refresh( FALSE );
8160                 }
8161             }
8162 
8163             if(bneedmove && pthumbwin){         // Adjust position to avoid bad overlap
8164                 wxPoint pos = wxPoint(4,4);
8165 
8166                 wxPoint tLocn = ClientToScreen(pos);
8167                 wxRect tRect = wxRect(tLocn.x, tLocn.y, pthumbwin->GetSize().x, pthumbwin->GetSize().y);
8168 
8169                 // Simplistic overlap avoidance works best when toolbar is horizontal near the top of screen.
8170                 // Other difficult cases simply center the thumbwin on the canvas....
8171                 if( g_MainToolbar && !g_MainToolbar->isSubmergedToGrabber()){
8172                     if( g_MainToolbar->GetScreenRect().Intersects( tRect ) ) {
8173                         wxPoint tbpos = cc1->ScreenToClient(g_MainToolbar->GetPosition());
8174                         pos = wxPoint(4, g_MainToolbar->GetSize().y + tbpos.y + 4);
8175                         tLocn = ClientToScreen(pos);
8176                     }
8177                 }
8178 
8179                 pthumbwin->Move( pos );
8180 
8181             }
8182 
8183         }
8184 #endif
8185 }
8186 
8187 void MyFrame::UpdateControlBar( ChartCanvas *cc )
8188 {
8189     if( !cc )
8190         return;
8191     cc->UpdateCanvasControlBar();
8192 }
8193 
8194 void MyFrame::selectChartDisplay( int type, int family)
8195 {
8196     // ..For each canvas...
8197     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
8198         ChartCanvas *cc = g_canvasArray.Item(i);
8199         if(cc)
8200             cc->selectCanvasChartDisplay( type, family );
8201     }
8202 
8203      UpdateGlobalMenuItems(); // update the state of the menu items (checkmarks etc)
8204 }
8205 
8206 //----------------------------------------------------------------------------------
8207 //      DoChartUpdate
8208 //      Create a chartstack based on current lat/lon.
8209 //      Return true if a Refresh(false) was called within.
8210 //----------------------------------------------------------------------------------
8211 bool MyFrame::DoChartUpdate( void )
8212 {
8213     bool return_val = false;
8214 
8215     // ..For each canvas...
8216     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
8217         ChartCanvas *cc = g_canvasArray.Item(i);
8218         if(cc)
8219             return_val |= cc->DoCanvasUpdate();
8220     }
8221 
8222     return return_val;
8223 
8224 }
8225 
8226 void MyFrame::MouseEvent( wxMouseEvent& event )
8227 {
8228     int x, y;
8229     event.GetPosition( &x, &y );
8230 
8231 }
8232 
8233 
8234 
8235 
8236 //      Memory monitor support
8237 #ifdef __WXMAC__
8238 #include <mach/mach.h>
8239 #include <mach/message.h>  // for mach_msg_type_number_t
8240 #include <mach/kern_return.h>  // for kern_return_t
8241 #include <mach/task_info.h>
8242 #include <stdio.h>
8243 #include <malloc/malloc.h>
8244 #endif
8245 
8246 #ifdef __WXGTK__
8247 #include <stdlib.h>
8248 #endif
8249 
8250 #if defined(__linux__)
8251 #include "sys/types.h"
8252 #include "sys/sysinfo.h"
8253 #endif /* __linux__ */
8254 
8255 int g_lastMemTick = -1;
8256 
8257 /* Return total system RAM and size of program */
8258 /* Values returned are in kilobytes            */
8259 bool
8260 GetMemoryStatus( int *mem_total, int *mem_used )
8261 {
8262 #ifdef __OCPN__ANDROID__
8263     return androidGetMemoryStatus( mem_total, mem_used );
8264 #endif
8265 
8266 #if defined(__linux__)
8267     // Use sysinfo to obtain total RAM
8268     if (mem_total)
8269     {
8270         *mem_total = 0;
8271         struct sysinfo sys_info;
8272         if ( sysinfo(&sys_info) != -1 )
8273             *mem_total = ( (uint64_t)sys_info.totalram * sys_info.mem_unit ) / 1024;
8274     }
8275 //      Use filesystem /proc/self/statm to determine memory status
8276 //	Provides information about memory usage, measured in pages.  The columns are:
8277 //	size       total program size (same as VmSize in /proc/[pid]/status)
8278 //	resident   resident set size (same as VmRSS in /proc/[pid]/status)
8279 //	share      shared pages (from shared mappings)
8280 //	text       text (code)
8281 //	lib        library (unused in Linux 2.6)
8282 //	data       data + stack
8283 //	dt         dirty pages (unused in Linux 2.6)
8284 
8285     if(mem_used)
8286     {
8287         *mem_used = 0;
8288         FILE* file = fopen ( "/proc/self/statm", "r");
8289         if ( file )
8290         {
8291             if (fscanf( file, "%d", mem_used) != 1) {
8292                 wxLogWarning("Cannot parse /proc/self/statm (!)");
8293             }
8294             *mem_used *= 4; // XXX assume 4K page
8295             fclose( file );
8296         }
8297     }
8298 
8299     return true;
8300 
8301 #endif /* __linux__ */
8302 
8303 #ifdef __WXMSW__
8304     HANDLE hProcess;
8305     PROCESS_MEMORY_COUNTERS pmc;
8306 
8307     unsigned long processID = wxGetProcessId();
8308 
8309     if( mem_used ) {
8310         hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );
8311 
8312         if( hProcess && GetProcessMemoryInfo( hProcess, &pmc, sizeof( pmc ) ) ) {
8313             /*
8314              printf( "\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount );
8315              printf( "\tPeakWorkingSetSize: 0x%08X\n",
8316              pmc.PeakWorkingSetSize );
8317              printf( "\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize );
8318              printf( "\tQuotaPeakPagedPoolUsage: 0x%08X\n",
8319              pmc.QuotaPeakPagedPoolUsage );
8320              printf( "\tQuotaPagedPoolUsage: 0x%08X\n",
8321              pmc.QuotaPagedPoolUsage );
8322              printf( "\tQuotaPeakNonPagedPoolUsage: 0x%08X\n",
8323              pmc.QuotaPeakNonPagedPoolUsage );
8324              printf( "\tQuotaNonPagedPoolUsage: 0x%08X\n",
8325              pmc.QuotaNonPagedPoolUsage );
8326              printf( "\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage );
8327              printf( "\tPeakPagefileUsage: 0x%08X\n",
8328              pmc.PeakPagefileUsage );
8329              */
8330             *mem_used = pmc.WorkingSetSize / 1024;
8331         }
8332 
8333         CloseHandle( hProcess );
8334     }
8335 
8336     if( mem_total ) {
8337         MEMORYSTATUSEX statex;
8338 
8339         statex.dwLength = sizeof( statex );
8340 
8341         GlobalMemoryStatusEx( &statex );
8342         /*
8343          _tprintf (TEXT("There is  %*ld percent of memory in use.\n"),
8344          WIDTH, statex.dwMemoryLoad);
8345          _tprintf (TEXT("There are %*I64d total Kbytes of physical memory.\n"),
8346          WIDTH, statex.ullTotalPhys/DIV);
8347          _tprintf (TEXT("There are %*I64d free Kbytes of physical memory.\n"),
8348          WIDTH, statex.ullAvailPhys/DIV);
8349          _tprintf (TEXT("There are %*I64d total Kbytes of paging file.\n"),
8350          WIDTH, statex.ullTotalPageFile/DIV);
8351          _tprintf (TEXT("There are %*I64d free Kbytes of paging file.\n"),
8352          WIDTH, statex.ullAvailPageFile/DIV);
8353          _tprintf (TEXT("There are %*I64d total Kbytes of virtual memory.\n"),
8354          WIDTH, statex.ullTotalVirtual/DIV);
8355          _tprintf (TEXT("There are %*I64d free Kbytes of virtual memory.\n"),
8356          WIDTH, statex.ullAvailVirtual/DIV);
8357          */
8358 
8359         *mem_total = statex.ullTotalPhys / 1024;
8360     }
8361     return true;
8362 #endif
8363 
8364 #ifdef __WXMAC__
8365 
8366     if(g_tick != g_lastMemTick){
8367       malloc_zone_pressure_relief(NULL, 0);
8368 
8369       int bytesInUse = 0;
8370       int blocksInUse = 0;
8371       int sizeAllocated = 0;
8372 
8373         malloc_statistics_t stats;
8374         stats.blocks_in_use = 0;
8375         stats.size_in_use = 0;
8376         stats.max_size_in_use = 0;
8377         stats.size_allocated = 0;
8378         malloc_zone_statistics(NULL, &stats);
8379         bytesInUse += stats.size_in_use;
8380         blocksInUse += stats.blocks_in_use;
8381         sizeAllocated += stats.size_allocated;
8382 
8383         g_memUsed = sizeAllocated >> 10;
8384 
8385         //printf("mem_used (Mb):  %d   %d \n", g_tick, g_memUsed / 1024);
8386         g_lastMemTick = g_tick;
8387     }
8388 
8389     if(mem_used)
8390        *mem_used = g_memUsed;
8391     if(mem_total) {
8392         *mem_total = 4000;
8393         FILE * fpIn = popen("sysctl -n hw.memsize", "r");
8394         if (fpIn)
8395         {
8396             double pagesUsed = 0.0, totalPages = 0.0;
8397             char buf[64];
8398             if(fgets(buf, sizeof(buf), fpIn) != NULL)
8399             {
8400                 *mem_total = atol(buf) >> 10;
8401             }
8402         }
8403     }
8404 
8405     return true;
8406 #endif
8407 
8408     if (mem_used)
8409 	*mem_used = 0;
8410     if (mem_total)
8411 	*mem_total = 0;
8412     return false;
8413 }
8414 
8415 void MyFrame::DoPrint( void )
8416 {
8417     if( NULL == g_printData ) {
8418         g_printData = new wxPrintData;
8419         g_printData->SetOrientation( wxLANDSCAPE );
8420         g_pageSetupData = new wxPageSetupDialogData;
8421     }
8422 
8423     wxPrintDialogData printDialogData( *g_printData );
8424     printDialogData.EnablePageNumbers( false );
8425 
8426     wxPrinter printer( &printDialogData );
8427 
8428     MyPrintout printout( wxT("Chart Print") );
8429 
8430     //  In OperGL mode, make the bitmap capture of the screen before the print method starts,
8431     //  so as to be sure the "Abort..." dialog does not appear on the image
8432     if(g_bopengl)
8433         printout.GenerateGLbmp( );
8434 
8435     if( !printer.Print( this, &printout, true ) ) {
8436         if( wxPrinter::GetLastError() == wxPRINTER_ERROR ) OCPNMessageBox(NULL,
8437                 _("There was a problem printing.\nPerhaps your current printer is not set correctly?"),
8438                 _T("OpenCPN"), wxOK );
8439 //        else
8440 //            OCPNMessageBox(_T("Print Cancelled"), _T("OpenCPN"), wxOK);
8441     } else {
8442         ( *g_printData ) = printer.GetPrintDialogData().GetPrintData();
8443     }
8444 
8445 // Pass two printout objects: for preview, and possible printing.
8446     /*
8447      wxPrintDialogData printDialogData(* g_printData);
8448      wxPrintPreview *preview = new wxPrintPreview(new MyPrintout, new MyPrintout, & printDialogData);
8449      if (!preview->Ok())
8450      {
8451      delete preview;
8452      OCPNMessageBox(_T("There was a problem previewing.\nPerhaps your current printer is not set correctly?"), _T("Previewing"), wxOK);
8453      return;
8454      }
8455 
8456      wxPreviewFrame *frame = new wxPreviewFrame(preview, this, _T("Demo Print Preview"), wxPoint(100, 100), wxSize(600, 650));
8457      frame->Centre(wxBOTH);
8458      frame->Initialize();
8459      frame->Show();
8460      */
8461 
8462     #ifdef __WXGTK__
8463     SurfaceAllCanvasToolbars();
8464     GetPrimaryCanvas()->SetFocus();
8465     Raise();                      // I dunno why...
8466     #endif
8467 }
8468 
8469 wxDateTime gTimeSource;
8470 
8471 void MyFrame::OnEvtPlugInMessage( OCPN_MsgEvent & event )
8472 {
8473     wxString message_ID = event.GetID();
8474     wxString message_JSONText = event.GetJSONText();
8475 
8476     //  We are free to use or ignore any or all of the PlugIn messages flying thru this pipe tee.
8477 
8478     //  We can possibly use the estimated magnetic variation if WMM_pi is present and active
8479     //  and we have no other source of Variation
8480     if(!g_bVAR_Rx)
8481     {
8482         if(message_ID == _T("WMM_VARIATION_BOAT"))
8483         {
8484 
8485         // construct the JSON root object
8486             wxJSONValue  root;
8487         // construct a JSON parser
8488             wxJSONReader reader;
8489 
8490         // now read the JSON text and store it in the 'root' structure
8491         // check for errors before retreiving values...
8492             int numErrors = reader.Parse( message_JSONText, &root );
8493             if ( numErrors > 0 )  {
8494 //              const wxArrayString& errors = reader.GetErrors();
8495                 return;
8496             }
8497 
8498             // get the DECL value from the JSON message
8499             wxString decl = root[_T("Decl")].AsString();
8500             double decl_val;
8501             decl.ToDouble(&decl_val);
8502 
8503             gVar = decl_val;
8504         }
8505     }
8506 
8507     if(message_ID == _T("WMM_VARIATION"))
8508     {
8509 
8510         // construct the JSON root object
8511         wxJSONValue  root;
8512         // construct a JSON parser
8513         wxJSONReader reader;
8514 
8515         // now read the JSON text and store it in the 'root' structure
8516         // check for errors before retreiving values...
8517         int numErrors = reader.Parse( message_JSONText, &root );
8518         if ( numErrors > 0 )  {
8519             //              const wxArrayString& errors = reader.GetErrors();
8520             return;
8521         }
8522 
8523         // get the DECL value from the JSON message
8524         wxString decl = root[_T("Decl")].AsString();
8525         double decl_val;
8526         decl.ToDouble(&decl_val);
8527 
8528         gQueryVar = decl_val;
8529     }
8530 
8531     if(message_ID == _T("GRIB_TIMELINE"))
8532     {
8533         wxJSONReader r;
8534         wxJSONValue v;
8535         r.Parse(message_JSONText, &v);
8536         if (v[_T("Day")].AsInt() == -1)
8537             gTimeSource = wxInvalidDateTime;
8538         else
8539             gTimeSource.Set (v[_T("Day")].AsInt(), (wxDateTime::Month)v[_T("Month")].AsInt(),
8540                     v[_T("Year")].AsInt(), v[_T("Hour")].AsInt(), v[_T("Minute")].AsInt(),
8541                     v[_T("Second")].AsInt());
8542     }
8543     if(message_ID == _T("OCPN_TRACK_REQUEST"))
8544     {
8545         wxJSONValue  root;
8546         wxJSONReader reader;
8547         wxString trk_id = wxEmptyString;
8548 
8549         int numErrors = reader.Parse( message_JSONText, &root );
8550         if ( numErrors > 0 )
8551             return;
8552 
8553         if(root.HasMember(_T("Track_ID")))
8554             trk_id = root[_T("Track_ID")].AsString();
8555 
8556         wxJSONValue v;
8557         v[_T("Track_ID")] = trk_id;
8558         for(TrackList::iterator it = pTrackList->begin(); it != pTrackList->end(); it++)
8559         {
8560             wxString name = wxEmptyString;
8561             if((*it)->m_GUID == trk_id)
8562             {
8563                 name = (*it)->GetName();
8564                 if(name.IsEmpty())
8565                 {
8566                     TrackPoint *rp = (*it)->GetPoint( 0 );
8567                     if( rp && rp->GetCreateTime().IsValid() )
8568                         name = rp->GetCreateTime().FormatISODate() + _T(" ") + rp->GetCreateTime().FormatISOTime();
8569                     else
8570                         name = _("(Unnamed Track)");
8571                 }
8572 
8573 /*                To avoid memory problems send a single trackpoint. It's up to the plugin to collect the data. */
8574                 int i = 1;
8575                 v[_T("error")] = false;
8576                 v[_T("TotalNodes")] = (*it)->GetnPoints();
8577                 for(int j = 0; j< (*it)->GetnPoints(); j++)
8578                 {
8579                     TrackPoint *tp = (*it)->GetPoint(j);
8580                     v[_T("lat")] = tp->m_lat;
8581                     v[_T("lon")] = tp->m_lon;
8582                     v[_T("NodeNr")] = i;
8583                     i++;
8584                     wxString msg_id( _T("OCPN_TRACKPOINTS_COORDS") );
8585                     g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8586                 }
8587                 return;
8588             }
8589             v[_T("error")] = true;
8590 
8591             wxString msg_id( _T("OCPN_TRACKPOINTS_COORDS") );
8592             g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8593         }
8594     }
8595     else if(message_ID == _T("OCPN_ROUTE_REQUEST"))
8596     {
8597         wxJSONValue  root;
8598         wxJSONReader reader;
8599         wxString guid = wxEmptyString;
8600 
8601         int numErrors = reader.Parse( message_JSONText, &root );
8602         if ( numErrors > 0 )  {
8603             return;
8604         }
8605 
8606         if(root.HasMember(_T("GUID")))
8607             guid = root[_T("GUID")].AsString();
8608 
8609         wxJSONValue v;
8610         v[_T("GUID")] = guid;
8611         for(RouteList::iterator it = pRouteList->begin(); it != pRouteList->end(); it++)
8612         {
8613             wxString name = wxEmptyString;
8614 
8615             if((*it)->m_GUID == guid)
8616             {
8617                 name = (*it)->m_RouteNameString;
8618                 if(name.IsEmpty())
8619                     name = _("(Unnamed Route)");
8620 
8621                 v[_T("Name")] = name;
8622                 v[_T("error")] = false;
8623                 wxJSONValue w;
8624                 int i = 0;
8625                 for(RoutePointList::iterator itp = (*it)->pRoutePointList->begin(); itp != (*it)->pRoutePointList->end(); itp++)
8626                 {
8627                     w[i][_T("lat")] = (*itp)->m_lat;
8628                     w[i][_T("lon")] = (*itp)->m_lon;
8629                     w[i][_T("Name")] = (*itp)->GetName();
8630                     w[i][_T("Description")] = (*itp)->GetDescription();
8631                     w[i][_T("GUID")] = (*itp)->m_GUID;
8632                     w[i][_T("ArrivalRadius")] = (*itp)->GetWaypointArrivalRadius();
8633                     wxHyperlinkListNode *node = (*itp)->m_HyperlinkList->GetFirst();
8634                     if(node)
8635                     {
8636                         int n = 1;
8637                         while(node)
8638                         {
8639                             Hyperlink *httpLink = node->GetData();
8640                             v[i][_T("WPLink")+wxString::Format(_T("%d"),n)] = httpLink->Link;
8641                             v[i][_T("WPLinkDesciption")+wxString::Format(_T("%d"),n++)] = httpLink->DescrText;
8642                             node = node->GetNext();
8643                         }
8644                     }
8645                     i++;
8646                 }
8647                 v[_T("waypoints")] = w;
8648                 wxString msg_id( _T("OCPN_ROUTE_RESPONSE") );
8649                 g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8650                 return;
8651             }
8652         }
8653 
8654         v[_T("error")] = true;
8655 
8656         wxString msg_id( _T("OCPN_ROUTE_RESPONSE") );
8657         g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8658     }
8659     else if(message_ID == _T("OCPN_ROUTELIST_REQUEST"))
8660     {
8661         wxJSONValue  root;
8662         wxJSONReader reader;
8663         bool route = true;
8664 
8665         int numErrors = reader.Parse( message_JSONText, &root );
8666         if ( numErrors > 0 )
8667             return;
8668 
8669         if(root.HasMember(_T("mode")))
8670         {
8671             wxString str = root[_T("mode")].AsString();
8672             if( str == _T("Track")) route = false;
8673 
8674             wxJSONValue v; int i = 1;
8675             if(route) {
8676                 for(RouteList::iterator it = pRouteList->begin(); it != pRouteList->end(); it++)
8677                 {
8678                     wxString name = (*it)->m_RouteNameString;
8679                     if(name.IsEmpty())
8680                         name = _("(Unnamed Route)");
8681 
8682                     v[i][_T("error")] = false;
8683                     v[i][_T("name")] = name;
8684                     v[i][_T("GUID")] = (*it)->m_GUID;
8685                     v[i][_T("active")] = (*it)->IsActive();
8686                     i++;
8687                 }
8688             } else { // track
8689                 for(TrackList::iterator it = pTrackList->begin(); it != pTrackList->end(); it++)
8690                 {
8691                     wxString name = (*it)->GetName();
8692                     if(name.IsEmpty())
8693                     {
8694                         TrackPoint *tp = (*it)->GetPoint( 0 );
8695                         if( tp && tp->GetCreateTime().IsValid() )
8696                             name = tp->GetCreateTime().FormatISODate() + _T(" ")
8697                                 + tp->GetCreateTime().FormatISOTime();
8698                         else
8699                             name = _("(Unnamed Track)");
8700                     }
8701                     v[i][_T("error")] = false;
8702                     v[i][_T("name")] = name;
8703                     v[i][_T("GUID")] = (*it)->m_GUID;
8704                     v[i][_T("active")] = g_pActiveTrack == (*it);
8705                     i++;
8706 
8707                 }
8708             }
8709             wxString msg_id( _T("OCPN_ROUTELIST_RESPONSE") );
8710             g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8711         }
8712         else
8713         {
8714             wxJSONValue v;
8715             v[0][_T("error")] = true;
8716             wxString msg_id( _T("OCPN_ROUTELIST_RESPONSE") );
8717             g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8718         }
8719     }
8720     else if(message_ID == _T("OCPN_ACTIVE_ROUTELEG_REQUEST"))
8721     {
8722         wxJSONValue v;
8723         v[0][_T("error")] = true;
8724         if( g_pRouteMan->GetpActiveRoute() )
8725         {
8726             if( g_pRouteMan->m_bDataValid )
8727             {
8728                 v[0][_T("error")] = false;
8729                 v[0][_T("range")] = g_pRouteMan->GetCurrentRngToActivePoint();
8730                 v[0][_T("bearing")] = g_pRouteMan->GetCurrentBrgToActivePoint();
8731                 v[0][_T("XTE")] = g_pRouteMan->GetCurrentXTEToActivePoint();
8732                 v[0][_T("active_route_GUID")] = g_pRouteMan->GetpActiveRoute()->GetGUID();
8733                 v[0][_T("active_waypoint_lat")] = g_pRouteMan->GetpActiveRoute()->m_pRouteActivePoint->GetLatitude();
8734                 v[0][_T("active_waypoint_lon")] = g_pRouteMan->GetpActiveRoute()->m_pRouteActivePoint->GetLongitude();
8735             }
8736         }
8737         wxString msg_id( _T("OCPN_ACTIVE_ROUTELEG_RESPONSE") );
8738         g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
8739     }
8740 
8741 }
8742 
8743 void MyFrame::OnEvtTHREADMSG( OCPN_ThreadMessageEvent & event )
8744 {
8745     wxLogMessage( wxString(event.GetSString().c_str(), wxConvUTF8 ));
8746 }
8747 
8748 
8749 bool MyFrame::EvalPriority(const wxString & message, DataStream *pDS )
8750 {
8751     bool bret = true;
8752     wxString msg_type = message.Mid(1, 5);
8753 
8754     wxString stream_name;
8755     int stream_priority = 0;
8756     if( pDS ){
8757         stream_priority = pDS->GetPriority();
8758         stream_name = pDS->GetPort();
8759     }
8760 
8761     //  If the message type has never been seen before...
8762     if( NMEA_Msg_Hash.find( msg_type ) == NMEA_Msg_Hash.end() ) {
8763         NMEA_Msg_Container *pcontainer = new NMEA_Msg_Container;
8764         pcontainer-> current_priority = -1;     //  guarantee to execute the next clause
8765         pcontainer->stream_name = stream_name;
8766         pcontainer->receipt_time = wxDateTime::Now();
8767 
8768         NMEA_Msg_Hash[msg_type] = pcontainer;
8769     }
8770 
8771     NMEA_Msg_Container *pcontainer = NMEA_Msg_Hash[msg_type];
8772     wxString old_port = pcontainer->stream_name;
8773 
8774     int old_priority = pcontainer->current_priority;
8775 
8776     //  If the message has been seen before, and the priority is greater than or equal to current priority,
8777     //  then simply update the record
8778     if( stream_priority >= pcontainer->current_priority )
8779     {
8780         pcontainer->receipt_time = wxDateTime::Now();
8781         pcontainer-> current_priority = stream_priority;
8782         pcontainer->stream_name = stream_name;
8783 
8784         bret = true;
8785     }
8786 
8787     //  If the message has been seen before, and the priority is less than the current priority,
8788     //  then if the time since the last recorded message is greater than GPS_TIMEOUT_SECONDS
8789     //  then update the record with the new priority and stream.
8790     //  Otherwise, ignore the message as too low a priority
8791     else
8792     {
8793         if( (wxDateTime::Now().GetTicks() - pcontainer->receipt_time.GetTicks()) > GPS_TIMEOUT_SECONDS )
8794         {
8795             pcontainer->receipt_time = wxDateTime::Now();
8796             pcontainer-> current_priority = stream_priority;
8797             pcontainer->stream_name = stream_name;
8798 
8799             bret = true;
8800         }
8801         else
8802             bret = false;
8803     }
8804 
8805     wxString new_port = pcontainer->stream_name;
8806 
8807     //  If the data source or priority has changed for this message type, emit a log entry
8808     if (pcontainer->current_priority != old_priority || new_port != old_port )
8809     {
8810          wxString logmsg = wxString::Format(_T("Changing NMEA Datasource for %s to %s (Priority: %i)"),
8811                                             msg_type.c_str(),
8812                                             new_port.c_str(),
8813                                             pcontainer->current_priority);
8814          wxLogMessage(logmsg );
8815 
8816          if (NMEALogWindow::Get().Active())
8817          {
8818              wxDateTime now = wxDateTime::Now();
8819              wxString ss = now.FormatISOTime();
8820              ss.Append( _T(" ") );
8821              ss.Append( logmsg );
8822              ss.Prepend( _T("<RED>") );
8823 
8824              NMEALogWindow::Get().Add(ss);
8825              NMEALogWindow::Get().Refresh(false);
8826          }
8827     }
8828     return bret;
8829 }
8830 
8831 static void UpdatePositionCalculatedSogCog()
8832 {
8833     wxDateTime now = wxDateTime::Now();
8834     if( last_own_ship_sog_cog_calc_ts.IsValid() ) {
8835         wxLongLong time_diff = now.Subtract(last_own_ship_sog_cog_calc_ts).GetMilliseconds();
8836         if( time_diff / 1000 >= g_own_ship_sog_cog_calc_damp_sec ) {
8837             double brg, dist;
8838             DistanceBearingMercator( gLat, gLon, last_own_ship_sog_cog_calc_lat, last_own_ship_sog_cog_calc_lon, &brg, &dist );
8839             double tSog = dist / (time_diff.ToDouble() / 3600000.);
8840 
8841             // Guard against really fast (i.e. non-sense VDR playback speed) data updates with slow averaging constant
8842             if(tSog < 100.){
8843                 gCog = brg;
8844                 gSog = tSog;
8845             }
8846 
8847             last_own_ship_sog_cog_calc_lat = gLat;
8848             last_own_ship_sog_cog_calc_lon = gLon;
8849             last_own_ship_sog_cog_calc_ts = now;
8850         }
8851     } else {
8852         last_own_ship_sog_cog_calc_lat = gLat;
8853         last_own_ship_sog_cog_calc_lon = gLon;
8854         last_own_ship_sog_cog_calc_ts = now;
8855     }
8856 }
8857 
8858 void MyFrame::setPosition(double lat, double lon)
8859 {
8860     gLat = lat;
8861     gLon = lon;
8862     if( g_own_ship_sog_cog_calc ) {
8863         UpdatePositionCalculatedSogCog();
8864     }
8865 
8866     gGPS_Watchdog = gps_watchdog_timeout_ticks;
8867     wxDateTime now = wxDateTime::Now();
8868     m_fixtime = now.GetTicks();
8869 
8870 }
8871 
8872 void MyFrame::setCourseOverGround(double cog)
8873 {
8874     if(!g_own_ship_sog_cog_calc) {
8875         wxLogDebug(wxString::Format(_T("COG: %f"), cog));
8876         gCog = cog;
8877     }
8878 }
8879 
8880 void MyFrame::setSpeedOverGround(double sog)
8881 {
8882     if(!g_own_ship_sog_cog_calc) {
8883         wxLogDebug(wxString::Format(_T("SOG: %f"), sog));
8884         gSog = sog;
8885     }
8886 }
8887 
8888 void MyFrame::setMagneticVariation(double var)
8889 {
8890     if (0.0 != var) {
8891         wxLogDebug(wxString::Format(_T("Var: %f"), var));
8892         gVar = var;
8893         g_bVAR_Rx = true;
8894         gVAR_Watchdog = gps_watchdog_timeout_ticks;
8895     }
8896 }
8897 
8898 void MyFrame::setSatelitesInView(int no)
8899 {
8900     wxLogDebug(wxString::Format(_T("SatsInView: %d"), no));
8901     g_SatsInView = no;
8902     gSAT_Watchdog = sat_watchdog_timeout_ticks;
8903     g_bSatValid = true;
8904 }
8905 
8906 void MyFrame::setHeadingTrue(double heading)
8907 {
8908     wxLogDebug(wxString::Format(_T("setHeadingTrue: %f"), heading));
8909     gHdt = heading;
8910     if (!std::isnan(heading)) {
8911         g_bHDT_Rx = true;
8912         gHDT_Watchdog = gps_watchdog_timeout_ticks;
8913     }
8914 
8915 }
8916 
8917 void MyFrame::setHeadingMagnetic(double heading)
8918 {
8919     wxLogDebug(wxString::Format(_T("setHeadingMagnetic: %f"), heading));
8920     gHdm = heading;
8921     if (!std::isnan(heading)) {
8922         gHDx_Watchdog = gps_watchdog_timeout_ticks;
8923     }
8924 
8925 }
8926 
8927 bool MyFrame::ParsePosition(const LATLONG &Position)
8928 {
8929     bool ll_valid = true;
8930     double llt = Position.Latitude.Latitude;
8931     double lat = gLat;
8932     double lon = gLon;
8933 
8934     if( !std::isnan(llt) )
8935     {
8936         int lat_deg_int = (int) ( llt / 100 );
8937         double lat_deg = lat_deg_int;
8938         double lat_min = llt - ( lat_deg * 100 );
8939 
8940         lat = lat_deg + (lat_min / 60. );
8941         if( Position.Latitude.Northing == South )
8942             lat = -lat;
8943     }
8944     else
8945         ll_valid = false;
8946 
8947     double lln = Position.Longitude.Longitude;
8948     if( !std::isnan(lln) )
8949     {
8950         int lon_deg_int = (int) ( lln / 100 );
8951         double lon_deg = lon_deg_int;
8952         double lon_min = lln - ( lon_deg * 100 );
8953 
8954         lon = lon_deg + (lon_min / 60. );
8955         if( Position.Longitude.Easting == West )
8956             lon = -lon;
8957     }
8958     else
8959         ll_valid = false;
8960 
8961     if( ll_valid ) {
8962         setPosition(lat, lon);
8963     }
8964 
8965     return ll_valid;
8966 }
8967 void MyFrame::OnEvtOCPN_SignalK(OCPN_SignalKEvent &event)
8968 {
8969     m_signalKHandler.OnEvtOCPN_SignalK(event);
8970 }
8971 
8972 void MyFrame::OnEvtOCPN_NMEA( OCPN_DataStreamEvent & event )
8973 {
8974     wxString sfixtime;
8975     bool pos_valid = false, cog_sog_valid = false;
8976     bool bis_recognized_sentence = true;
8977 
8978     wxString str_buf = event.ProcessNMEA4Tags();
8979 
8980     if( g_nNMEADebug && ( g_total_NMEAerror_messages < g_nNMEADebug ) )
8981     {
8982         g_total_NMEAerror_messages++;
8983         wxString msg( _T("MEH.NMEA Sentence received...") );
8984         msg.Append( str_buf );
8985         wxLogMessage( msg );
8986     }
8987 
8988     //  The message must be at least reasonably formed...
8989     if( (str_buf[0] != '$')  &&  (str_buf[0] != '!') )
8990         return;
8991 
8992     if( event.GetStream() )
8993     {
8994         if(!event.GetStream()->ChecksumOK(event.GetNMEAString()) )
8995         {
8996             if( g_nNMEADebug && ( g_total_NMEAerror_messages < g_nNMEADebug ) )
8997             {
8998                 g_total_NMEAerror_messages++;
8999                 wxString msg( _T(">>>>>>NMEA Sentence Checksum Bad...") );
9000                 msg.Append( str_buf );
9001                 wxLogMessage( msg );
9002             }
9003             return;
9004         }
9005     }
9006 
9007     bool b_accept = EvalPriority( str_buf, event.GetStream() );
9008     if( !b_accept )
9009         return;
9010 
9011     m_NMEA0183 << str_buf;
9012 
9013     if( m_NMEA0183.PreParse() )
9014     {
9015         wxString IDs[] = {_T("RMC"), _T("HDT"), _T("HDG"), _T("HDM"),
9016                           _T("VTG"), _T("GSV"), _T("GGA"), _T("GLL")};
9017         enum {RMC, HDT, HDG, HDM, VTG, GSV, GGA, GLL, ID_NUM };
9018 
9019         int id;
9020         int num = g_bUseGLL ? ID_NUM : GLL;
9021         for(id=0; id<num; id++)
9022             if( m_NMEA0183.LastSentenceIDReceived == IDs[id] )
9023                 break;
9024 
9025         if(id == num) // avoid parsing if we won't use it
9026             return;
9027 
9028         if( m_NMEA0183.Parse() )
9029         {
9030 #if 1
9031             switch(id)
9032             {
9033             case RMC:
9034                 if( m_NMEA0183.Rmc.IsDataValid == NTrue )
9035                 {
9036                     pos_valid = ParsePosition(m_NMEA0183.Rmc.Position);
9037 
9038                     // course is not valid in this case
9039                     // but also my gps occasionally outputs RMC
9040                     // messages with valid lat and lon but
9041                     // 0.0 for speed and course which messes up the filter
9042                     if(!g_own_ship_sog_cog_calc && m_NMEA0183.Rmc.SpeedOverGroundKnots > 0) {
9043                         gSog = m_NMEA0183.Rmc.SpeedOverGroundKnots;
9044                         gCog = m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue;
9045                         cog_sog_valid = true;
9046                     }
9047 
9048                     // Any device sending VAR=0.0 can be assumed to not really know
9049                     // what the actual variation is, so in this case we use WMM if available
9050                     if( (!std::isnan(m_NMEA0183.Rmc.MagneticVariation)) &&
9051                               0.0 != m_NMEA0183.Rmc.MagneticVariation )
9052                     {
9053                         if (m_NMEA0183.Rmc.MagneticVariationDirection == East)
9054                             gVar = m_NMEA0183.Rmc.MagneticVariation;
9055                         else
9056                             if (m_NMEA0183.Rmc.MagneticVariationDirection == West)
9057                                 gVar = -m_NMEA0183.Rmc.MagneticVariation;
9058 
9059                         g_bVAR_Rx = true;
9060                         gVAR_Watchdog = gps_watchdog_timeout_ticks;
9061                     }
9062 
9063                     sfixtime = m_NMEA0183.Rmc.UTCTime;
9064                     gRmcTime = sfixtime;
9065                     gRmcDate = m_NMEA0183.Rmc.Date;
9066                 }
9067                 break;
9068 
9069             case HDT:
9070                 gHdt = m_NMEA0183.Hdt.DegreesTrue;
9071                 if( !std::isnan(m_NMEA0183.Hdt.DegreesTrue) )
9072                 {
9073                     g_bHDT_Rx = true;
9074                     gHDT_Watchdog = gps_watchdog_timeout_ticks;
9075                 }
9076                 break;
9077 
9078             case HDG:
9079                 gHdm = m_NMEA0183.Hdg.MagneticSensorHeadingDegrees;
9080                 if( !std::isnan(m_NMEA0183.Hdg.MagneticSensorHeadingDegrees) )
9081                     gHDx_Watchdog = gps_watchdog_timeout_ticks;
9082 
9083                 // Any device sending VAR=0.0 can be assumed to not really know
9084                 // what the actual variation is, so in this case we use WMM if available
9085                 if( (!std::isnan(m_NMEA0183.Hdg.MagneticVariationDegrees)) &&
9086                      0.0 != m_NMEA0183.Hdg.MagneticVariationDegrees )
9087                 {
9088                     if( m_NMEA0183.Hdg.MagneticVariationDirection == East )
9089                         gVar = m_NMEA0183.Hdg.MagneticVariationDegrees;
9090                     else if( m_NMEA0183.Hdg.MagneticVariationDirection == West )
9091                         gVar = -m_NMEA0183.Hdg.MagneticVariationDegrees;
9092 
9093                     g_bVAR_Rx = true;
9094                     gVAR_Watchdog = gps_watchdog_timeout_ticks;
9095                 }
9096                 break;
9097 
9098             case HDM:
9099                 gHdm = m_NMEA0183.Hdm.DegreesMagnetic;
9100                 if( !std::isnan(m_NMEA0183.Hdm.DegreesMagnetic) )
9101                     gHDx_Watchdog = gps_watchdog_timeout_ticks;
9102                 break;
9103 
9104             case VTG:
9105                 // should we allow either Sog or Cog but not both to be valid?
9106                 if( !g_own_ship_sog_cog_calc && !std::isnan(m_NMEA0183.Vtg.SpeedKnots) )
9107                     gSog = m_NMEA0183.Vtg.SpeedKnots;
9108                 if( !g_own_ship_sog_cog_calc && !std::isnan(m_NMEA0183.Vtg.TrackDegreesTrue) )
9109                     gCog = m_NMEA0183.Vtg.TrackDegreesTrue;
9110                 if( !g_own_ship_sog_cog_calc && !std::isnan(m_NMEA0183.Vtg.SpeedKnots) &&
9111                     !std::isnan(m_NMEA0183.Vtg.TrackDegreesTrue) ) {
9112                     gCog = m_NMEA0183.Vtg.TrackDegreesTrue;
9113 #else  // balp, use new "setters"
9114             switch(id) {
9115                 case RMC:
9116                     if (m_NMEA0183.Rmc.IsDataValid == NTrue) {
9117                         pos_valid = ParsePosition(m_NMEA0183.Rmc.Position);
9118 
9119                         // course is not valid in this case
9120                         // but also my gps occasionally outputs RMC
9121                         // messages with valid lat and lon but
9122                         // 0.0 for speed and course which messes up the filter
9123                         if (!g_own_ship_sog_cog_calc && m_NMEA0183.Rmc.SpeedOverGroundKnots > 0) {
9124                             setSpeedOverGround(m_NMEA0183.Rmc.SpeedOverGroundKnots);
9125                             setCourseOverGround(m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue);
9126                             cog_sog_valid = true;
9127                         }
9128 
9129                         if (!wxIsNaN(m_NMEA0183.Rmc.MagneticVariation)) {
9130                             if (m_NMEA0183.Rmc.MagneticVariationDirection == East)
9131                                 setMagneticVariation(m_NMEA0183.Rmc.MagneticVariation);
9132                             else if (m_NMEA0183.Rmc.MagneticVariationDirection == West)
9133                                 setMagneticVariation(-m_NMEA0183.Rmc.MagneticVariation);
9134                         }
9135 
9136                         sfixtime = m_NMEA0183.Rmc.UTCTime;
9137                     }
9138                     break;
9139 
9140                 case HDT:
9141                     setHeadingTrue(m_NMEA0183.Hdt.DegreesTrue);
9142                     break;
9143 
9144                 case HDG:
9145                     setHeadingMagnetic(m_NMEA0183.Hdg.MagneticSensorHeadingDegrees);
9146 
9147                     if (m_NMEA0183.Hdg.MagneticVariationDirection == East)
9148                         setMagneticVariation(m_NMEA0183.Hdg.MagneticVariationDegrees);
9149                     else if (m_NMEA0183.Hdg.MagneticVariationDirection == West)
9150                         setMagneticVariation(-m_NMEA0183.Hdg.MagneticVariationDegrees);
9151                     break;
9152 
9153                 case HDM:
9154                     setHeadingMagnetic(m_NMEA0183.Hdm.DegreesMagnetic);
9155                     break;
9156 
9157                 case VTG:
9158                     // should we allow either Sog or Cog but not both to be valid?
9159                     if (!g_own_ship_sog_cog_calc && !wxIsNaN(m_NMEA0183.Vtg.SpeedKnots)) {
9160                         setSpeedOverGround(m_NMEA0183.Vtg.SpeedKnots);
9161                     }
9162                 if( !g_own_ship_sog_cog_calc && !wxIsNaN(m_NMEA0183.Vtg.TrackDegreesTrue) )
9163                     gCog = m_NMEA0183.Vtg.TrackDegreesTrue;
9164                 if( !g_own_ship_sog_cog_calc && !wxIsNaN(m_NMEA0183.Vtg.SpeedKnots) &&
9165                     !wxIsNaN(m_NMEA0183.Vtg.TrackDegreesTrue) ) {
9166                     setCourseOverGround(m_NMEA0183.Vtg.TrackDegreesTrue);
9167 >>>>>>> 1f7f17e0a7cd430bc7d73457a91958a3d01eecfa
9168 #endif
9169                     cog_sog_valid = true;
9170                 }
9171                 break;
9172 
9173             case GSV:
9174                 setSatelitesInView(m_NMEA0183.Gsv.SatsInView);
9175                 break;
9176 
9177             case GGA:
9178                 if( m_NMEA0183.Gga.GPSQuality > 0 )
9179                 {
9180                     pos_valid = ParsePosition(m_NMEA0183.Gga.Position);
9181                     sfixtime = m_NMEA0183.Gga.UTCTime;
9182                     setSatelitesInView(m_NMEA0183.Gga.NumberOfSatellitesInUse);
9183                 }
9184                 break;
9185 
9186             case GLL:
9187                 if( m_NMEA0183.Gll.IsDataValid == NTrue )
9188                 {
9189                     pos_valid = ParsePosition(m_NMEA0183.Gll.Position);
9190                     sfixtime = m_NMEA0183.Gll.UTCTime;
9191                 }
9192                 break;
9193             }
9194 
9195 
9196         } else if( g_nNMEADebug ) {
9197             wxString msg( _T("   ") );
9198             msg.Append( m_NMEA0183.ErrorMessage );
9199             msg.Append( _T(" : ") );
9200             msg.Append( str_buf );
9201             wxLogMessage( msg );
9202         }
9203     }
9204         //      Process ownship (AIVDO) messages from any source
9205     else if(str_buf.Mid( 1, 5 ).IsSameAs( _T("AIVDO") ) )
9206     {
9207         GenericPosDatEx gpd;
9208         AIS_Error nerr = AIS_GENERIC_ERROR;
9209         if(g_pAIS)
9210             nerr = g_pAIS->DecodeSingleVDO(str_buf, &gpd, &m_VDO_accumulator);
9211 
9212         if(nerr == AIS_NoError)
9213         {
9214             if( !std::isnan(gpd.kLat) )
9215                 gLat = gpd.kLat;
9216             if( !std::isnan(gpd.kLon) )
9217                 gLon = gpd.kLon;
9218 
9219             if( !g_own_ship_sog_cog_calc ) {
9220                 gCog = gpd.kCog;
9221                 gSog = gpd.kSog;
9222             } else {
9223                 UpdatePositionCalculatedSogCog();
9224             }
9225             cog_sog_valid = true;
9226 
9227             if( !std::isnan(gpd.kHdt) )
9228             {
9229                 gHdt = gpd.kHdt;
9230                 g_bHDT_Rx = true;
9231                 gHDT_Watchdog = gps_watchdog_timeout_ticks;
9232             }
9233 
9234             if( !std::isnan(gpd.kLat) && !std::isnan(gpd.kLon) )
9235             {
9236                 gGPS_Watchdog = gps_watchdog_timeout_ticks;
9237                 wxDateTime now = wxDateTime::Now();
9238                 m_fixtime = now.GetTicks();
9239 
9240                 pos_valid = true;
9241             }
9242         }
9243         else
9244         {
9245             if( g_nNMEADebug && ( g_total_NMEAerror_messages < g_nNMEADebug ) )
9246             {
9247                 g_total_NMEAerror_messages++;
9248                 wxString msg( _T("   Invalid AIVDO Sentence...") );
9249                 msg.Append( str_buf );
9250                 wxLogMessage( msg );
9251             }
9252         }
9253     }
9254     else
9255     {
9256         bis_recognized_sentence = false;
9257         if( g_nNMEADebug && ( g_total_NMEAerror_messages < g_nNMEADebug ) )
9258         {
9259             g_total_NMEAerror_messages++;
9260             wxString msg( _T("   Unrecognized NMEA Sentence...") );
9261             msg.Append( str_buf );
9262             wxLogMessage( msg );
9263         }
9264     }
9265 
9266     if( g_own_ship_sog_cog_calc )
9267         cog_sog_valid = true;
9268 
9269     if( bis_recognized_sentence ) PostProcessNMEA( pos_valid, cog_sog_valid, sfixtime );
9270 }
9271 
9272 void MyFrame::PostProcessNMEA( bool pos_valid, bool cog_sog_valid, const wxString &sfixtime )
9273 {
9274     if(cog_sog_valid) {
9275         //    Maintain average COG for Course Up Mode
9276         if( !std::isnan(gCog) ) {
9277             if( g_COGAvgSec > 0 ) {
9278                 //    Make a hole
9279                 for( int i = g_COGAvgSec - 1; i > 0; i-- )
9280                     COGTable[i] = COGTable[i - 1];
9281                 COGTable[0] = gCog;
9282 
9283                 double sum = 0., count=0;
9284                 for( int i = 0; i < g_COGAvgSec; i++ ) {
9285                     double adder = COGTable[i];
9286                     if(std::isnan(adder))
9287                         continue;
9288 
9289                     if( fabs( adder - g_COGAvg ) > 180. ) {
9290                         if( ( adder - g_COGAvg ) > 0. ) adder -= 360.;
9291                         else
9292                             adder += 360.;
9293                     }
9294 
9295                     sum += adder;
9296                     count++;
9297                 }
9298                 sum /= count;
9299 
9300                 if( sum < 0. ) sum += 360.;
9301                 else
9302                     if( sum >= 360. ) sum -= 360.;
9303 
9304                 g_COGAvg = sum;
9305             }
9306             else
9307                 g_COGAvg = gCog;
9308         }
9309 
9310         FilterCogSog();
9311     }
9312 
9313     //    If gSog is greater than some threshold, we determine that we are "cruising"
9314     if( gSog > 3.0 ) g_bCruising = true;
9315 
9316     //    Here is the one place we try to create gHdt from gHdm and gVar,
9317     //    but only if NMEA HDT sentence is not being received
9318 
9319     if( !g_bHDT_Rx ) {
9320         if( !std::isnan(gVar) && !std::isnan(gHdm)) {
9321             gHdt = gHdm + gVar;
9322             if (gHdt < 0)
9323                 gHdt += 360.0;
9324             else if (gHdt >= 360)
9325                 gHdt -= 360.0;
9326             gHDT_Watchdog = gps_watchdog_timeout_ticks;
9327         }
9328     }
9329 
9330     if( pos_valid ) {
9331         if( g_nNMEADebug ) {
9332             wxString msg( _T("PostProcess NMEA with valid position") );
9333             wxLogMessage( msg );
9334         }
9335 
9336         //      Maintain the validity flags
9337         bool last_bGPSValid = bGPSValid;
9338         bGPSValid = true;
9339         if( !last_bGPSValid ) UpdateGPSCompassStatusBoxes();
9340 
9341         //      Show a little heartbeat tick in StatusWindow0 on NMEA events
9342         //      But no faster than 10 hz.
9343         unsigned long uiCurrentTickCount;
9344         m_MMEAeventTime.SetToCurrent();
9345         uiCurrentTickCount = m_MMEAeventTime.GetMillisecond() / 100;           // tenths of a second
9346         uiCurrentTickCount += m_MMEAeventTime.GetTicks() * 10;
9347         if( uiCurrentTickCount > m_ulLastNMEATicktime + 1 ) {
9348             m_ulLastNMEATicktime = uiCurrentTickCount;
9349 
9350             if( tick_idx++ > 6 ) tick_idx = 0;
9351         }
9352     }
9353 
9354 //    Show gLat/gLon in StatusWindow0
9355 
9356     if( NULL != GetStatusBar() ) {
9357         if(pos_valid) {
9358             char tick_buf[2];
9359             tick_buf[0] = nmea_tick_chars[tick_idx];
9360             tick_buf[1] = 0;
9361 
9362             wxString s1( tick_buf, wxConvUTF8 );
9363             s1 += _(" Ship ");
9364             s1 += toSDMM( 1, gLat );
9365             s1 += _T("   ");
9366             s1 += toSDMM( 2, gLon );
9367 
9368             if(STAT_FIELD_TICK >= 0 )
9369                 SetStatusText( s1, STAT_FIELD_TICK );
9370 
9371         }
9372 
9373         if(cog_sog_valid) {
9374             wxString sogcog;
9375             if( std::isnan(gSog) ) sogcog.Printf( _T("SOG --- ") + getUsrSpeedUnit() + _T("     ") );
9376             else
9377                 sogcog.Printf( _T("SOG %2.2f ") + getUsrSpeedUnit() + _T("  "), toUsrSpeed( gSog ) );
9378 
9379             wxString cogs;
9380             if( std::isnan(gCog) )
9381                 cogs.Printf( wxString( "COG ---\u00B0", wxConvUTF8 ) );
9382             else {
9383                 if( g_bShowTrue )
9384                     cogs << wxString::Format( wxString("COG %03d°  ", wxConvUTF8 ), (int)gCog );
9385                 if( g_bShowMag )
9386                     cogs << wxString::Format( wxString("COG %03d°(M)  ", wxConvUTF8 ), (int)gFrame->GetMag( gCog ) );
9387             }
9388 
9389             sogcog.Append( cogs );
9390             SetStatusText( sogcog, STAT_FIELD_SOGCOG );
9391         }
9392 
9393 
9394     }
9395 
9396 #ifdef ocpnUPDATE_SYSTEM_TIME
9397 //      Use the fix time to update the local system clock, only once per session
9398     if( ( sfixtime.Len() ) && s_bSetSystemTime && ( m_bTimeIsSet == false ) ) {
9399         wxDateTime Fix_Time( wxDateTime::Now()) ;
9400 
9401         if( 6 == sfixtime.Len() || 6 == sfixtime.find('.') )       // perfectly recognised format?
9402                 {
9403             wxString a;
9404             long b;
9405             int hr = 0;
9406             int min = 0;
9407             int sec = 0;
9408 
9409             a = sfixtime.Mid( 0, 2 );
9410             if( a.ToLong( &b ) ) hr = b;
9411             a = sfixtime.Mid( 2, 2 );
9412             if( a.ToLong( &b ) ) min = b;
9413             a = sfixtime.Mid( 4, 2 );
9414             if( a.ToLong( &b ) ) sec = b;
9415 
9416             Fix_Time.Set( hr, min, sec );
9417         }
9418         wxString fix_time_format = Fix_Time.Format( _T("%Y-%m-%dT%H:%M:%S") ); // this should show as LOCAL
9419 
9420         //          Compare the server (fix) time to the current system time
9421         wxDateTime sdt;
9422         sdt.SetToCurrent();
9423         wxDateTime cwxft = Fix_Time;                  // take a copy
9424         wxTimeSpan ts;
9425         ts = cwxft.Subtract( sdt );
9426 
9427         int b = ( ts.GetSeconds() ).ToLong();
9428 
9429         //          Correct system time if necessary
9430         //      Only set the time if wrong by more than 1 minute, and less than 2 hours
9431         //      This should eliminate bogus times which may come from faulty GPS units
9432 
9433         if( ( abs( b ) > 60 ) && ( abs( b ) < ( 2 * 60 * 60 ) ) ) {
9434 
9435 #ifdef __WXMSW__
9436             //      Fix up the fix_time to convert to GMT
9437             Fix_Time = Fix_Time.ToGMT();
9438 
9439             //    Code snippet following borrowed from wxDateCtrl, MSW
9440 
9441             const wxDateTime::Tm tm( Fix_Time.GetTm() );
9442 
9443             SYSTEMTIME stm;
9444             stm.wYear = (WXWORD) tm.year;
9445             stm.wMonth = (WXWORD) ( tm.mon - wxDateTime::Jan + 1 );
9446             stm.wDay = tm.mday;
9447 
9448             stm.wDayOfWeek = 0;
9449             stm.wHour = Fix_Time.GetHour();
9450             stm.wMinute = tm.min;
9451             stm.wSecond = tm.sec;
9452             stm.wMilliseconds = 0;
9453 
9454             ::SetSystemTime( &stm );            // in GMT
9455 
9456 #else
9457 
9458             //      This contortion sets the system date/time on POSIX host
9459             //      Requires the following line in /etc/sudoers
9460             //          nav ALL=NOPASSWD:/bin/date -s *
9461 
9462             wxString msg;
9463             msg.Printf(_T("Setting system time, delta t is %d seconds"), b);
9464             wxLogMessage(msg);
9465 
9466             wxString sdate(Fix_Time.Format(_T("%D")));
9467             sdate.Prepend(_T("sudo /bin/date -s \""));
9468 
9469             wxString stime(Fix_Time.Format(_T("%T")));
9470             stime.Prepend(_T(" "));
9471             sdate.Append(stime);
9472             sdate.Append(_T("\""));
9473 
9474             msg.Printf(_T("Linux command is:"));
9475             msg += sdate;
9476             wxLogMessage(msg);
9477             wxExecute(sdate, wxEXEC_ASYNC);
9478 
9479 #endif      //__WXMSW__
9480             m_bTimeIsSet = true;
9481 
9482         }           // if needs correction
9483     }               // if valid time
9484 
9485 #endif            //ocpnUPDATE_SYSTEM_TIME
9486 }
9487 
9488 void MyFrame::FilterCogSog( void )
9489 {
9490     if( g_bfilter_cogsog && !g_own_ship_sog_cog_calc ) {
9491         //    Simple averaging filter for COG
9492         double cog_last = gCog;       // most recent reported value
9493 
9494         //    Make a hole in array
9495         for( int i = g_COGFilterSec - 1; i > 0; i-- )
9496             COGFilterTable[i] = COGFilterTable[i - 1];
9497         COGFilterTable[0] = cog_last;
9498 
9499         //    If the lastest data is undefined, leave it
9500         if( !std::isnan(cog_last) ) {
9501             //
9502             double sum = 0., count = 0;
9503             for( int i = 0; i < g_COGFilterSec; i++ ) {
9504                 double adder = COGFilterTable[i];
9505                 if(std::isnan(adder))
9506                     continue;
9507 
9508                 if( fabs( adder - cog_last ) > 180. ) {
9509                     if( ( adder - cog_last ) > 0. ) adder -= 360.;
9510                     else
9511                         adder += 360.;
9512                 }
9513 
9514                 sum += adder;
9515                 count++;
9516             }
9517             sum /= count;
9518 
9519             if( sum < 0. ) sum += 360.;
9520             else
9521                 if( sum >= 360. ) sum -= 360.;
9522 
9523             gCog = sum;
9524         }
9525 
9526         //    Simple averaging filter for SOG
9527         double sog_last = gSog;       // most recent reported value
9528 
9529         //    Make a hole in array
9530         for( int i = g_SOGFilterSec - 1; i > 0; i-- )
9531             SOGFilterTable[i] = SOGFilterTable[i - 1];
9532         SOGFilterTable[0] = sog_last;
9533 
9534 
9535         //    If the data are undefined, leave the array intact
9536         if( !std::isnan(gSog) ) {
9537             double sum = 0., count = 0;
9538             for( int i = 0; i < g_SOGFilterSec; i++ ) {
9539                 if(std::isnan(SOGFilterTable[i]))
9540                     continue;
9541 
9542                 sum += SOGFilterTable[i];
9543                 count++;
9544             }
9545             sum /= count;
9546 
9547             gSog = sum;
9548         }
9549     }
9550 }
9551 
9552 void MyFrame::StopSockets( void )
9553 {
9554 //TODO: Can be removed?
9555 }
9556 
9557 void MyFrame::ResumeSockets( void )
9558 {
9559 //TODO: Can be removed?
9560 }
9561 
9562 void MyFrame::LoadHarmonics()
9563 {
9564     if(!ptcmgr) {
9565         ptcmgr = new TCMgr;
9566         ptcmgr->LoadDataSources(TideCurrentDataSet);
9567     }
9568     else {
9569         bool b_newdataset = false;
9570 
9571         //      Test both ways
9572         wxArrayString test = ptcmgr->GetDataSet();
9573         for(unsigned int i=0 ; i < test.GetCount() ; i++) {
9574             bool b_foundi = false;
9575             for(unsigned int j=0 ; j < TideCurrentDataSet.GetCount() ; j++) {
9576                 if(TideCurrentDataSet[j] == test[i]) {
9577                     b_foundi = true;
9578                     break;              // j loop
9579                 }
9580             }
9581             if(!b_foundi) {
9582                 b_newdataset = true;
9583                 break;                  //  i loop
9584             }
9585         }
9586 
9587         test = TideCurrentDataSet;
9588         for(unsigned int i=0 ; i < test.GetCount() ; i++) {
9589             bool b_foundi = false;
9590             for(unsigned int j=0 ; j < ptcmgr->GetDataSet().GetCount() ; j++) {
9591                 if(ptcmgr->GetDataSet()[j] == test[i]) {
9592                     b_foundi = true;
9593                     break;              // j loop
9594                 }
9595             }
9596             if(!b_foundi) {
9597                 b_newdataset = true;
9598                 break;                  //  i loop
9599             }
9600         }
9601 
9602         if(b_newdataset)
9603             ptcmgr->LoadDataSources(TideCurrentDataSet);
9604     }
9605 }
9606 
9607 Route *pAISMOBRoute;
9608 
9609 void MyFrame::ActivateAISMOBRoute( AIS_Target_Data *ptarget )
9610 {
9611     if(!ptarget)
9612         return;
9613 
9614     //    The MOB point
9615     wxDateTime mob_time = wxDateTime::Now();
9616     wxString mob_label( _( "AIS MAN OVERBOARD" ) );
9617     mob_label += _(" at ");
9618     mob_label += mob_time.FormatTime();
9619     mob_label += _(" on ");
9620     mob_label += mob_time.FormatISODate();
9621 
9622     RoutePoint *pWP_MOB = new RoutePoint( ptarget->Lat, ptarget->Lon, _T ( "mob" ), mob_label, wxEmptyString );
9623     pWP_MOB->m_bKeepXRoute = true;
9624     pWP_MOB->m_bIsolatedMark = true;
9625     pSelect->AddSelectableRoutePoint( ptarget->Lat, ptarget->Lon, pWP_MOB );
9626     pConfig->AddNewWayPoint( pWP_MOB, -1 );       // use auto next num
9627     pWP_MOB->SetUseSca(false); //Do not use scaled hiding for MOB
9628 
9629     /* We want to start tracking any MOB in range (Which will trigger false alarms with messages received over the network etc., but will a) not discard nearby event even in case our GPS is momentarily unavailable and b) work even when the boat is stationary, in which case some GPS units do not provide COG)
9630     if( bGPSValid && !std::isnan(gCog) && !std::isnan(gSog) ) { */
9631         RoutePoint *pWP_src = new RoutePoint( gLat, gLon, g_default_wp_icon,
9632                                               wxString( _( "Own ship" ) ), wxEmptyString );
9633         pSelect->AddSelectableRoutePoint( gLat, gLon, pWP_src );
9634         pWP_MOB->SetUseSca(false); //Do not use scaled hiding for MOB
9635         pAISMOBRoute = new Route();
9636         pRouteList->Append( pAISMOBRoute );
9637 
9638         pAISMOBRoute->AddPoint( pWP_src );
9639         pAISMOBRoute->AddPoint( pWP_MOB );
9640 
9641         pSelect->AddSelectableRouteSegment(ptarget->Lat, ptarget->Lon, gLat, gLon, pWP_src, pWP_MOB, pAISMOBRoute );
9642 
9643         pAISMOBRoute->m_RouteNameString = _("Temporary AISMOB Route");
9644         pAISMOBRoute->m_RouteStartString = _("Present own ship");
9645         pAISMOBRoute->m_RouteEndString = mob_label;
9646 
9647         pAISMOBRoute->m_bDeleteOnArrival = false;
9648 
9649         pAISMOBRoute->SetRouteArrivalRadius( -1.0 );                    // never arrives
9650 
9651         if( g_pRouteMan->GetpActiveRoute() )
9652             g_pRouteMan->DeactivateRoute();
9653         //       g_pRouteMan->ActivateRoute( pAISMOBRoute, pWP_MOB );
9654 
9655         wxJSONValue v;
9656         v[_T("GUID")] = pAISMOBRoute->m_GUID;
9657         wxString msg_id( _T("OCPN_MAN_OVERBOARD") );
9658         g_pi_manager->SendJSONMessageToAllPlugins( msg_id, v );
9659     //}
9660 
9661     if(RouteManagerDialog::getInstanceFlag()){
9662     if( pRouteManagerDialog && pRouteManagerDialog->IsShown() ) {
9663         pRouteManagerDialog->UpdateRouteListCtrl();
9664         pRouteManagerDialog->UpdateWptListCtrl();
9665     }
9666     }
9667 
9668     RefreshAllCanvas( false );
9669 
9670     wxString mob_message( _( "AIS MAN OVERBOARD" ) );
9671     mob_message += _(" Time: ");
9672     mob_message += mob_time.Format();
9673     mob_message += _("  Ownship Position: ");
9674     mob_message += toSDMM( 1, gLat );
9675     mob_message += _T("   ");
9676     mob_message += toSDMM( 2, gLon );
9677     mob_message += _("  MOB Position: ");
9678     mob_message += toSDMM( 1, ptarget->Lat );
9679     mob_message += _T("   ");
9680     mob_message += toSDMM( 2, ptarget->Lon );
9681     wxLogMessage( mob_message );
9682 
9683 }
9684 
9685 void MyFrame::UpdateAISMOBRoute( AIS_Target_Data *ptarget )
9686 {
9687     if(pAISMOBRoute && ptarget)
9688     {
9689         //   Update Current Ownship point
9690         RoutePoint *OwnPoint = pAISMOBRoute->GetPoint( 1 );
9691         OwnPoint->m_lat = gLat;
9692         OwnPoint->m_lon = gLon;
9693 
9694         pSelect->DeleteSelectableRoutePoint( OwnPoint );
9695         pSelect->AddSelectableRoutePoint( gLat, gLon, OwnPoint );
9696 
9697         //   Update Current MOB point
9698         RoutePoint *MOB_Point = pAISMOBRoute->GetPoint( 2 );
9699         MOB_Point->m_lat = ptarget->Lat;
9700         MOB_Point->m_lon = ptarget->Lon;
9701 
9702         pSelect->DeleteSelectableRoutePoint( MOB_Point );
9703         pSelect->AddSelectableRoutePoint( ptarget->Lat, ptarget->Lon, MOB_Point );
9704 
9705         pSelect->UpdateSelectableRouteSegments( OwnPoint );
9706         pSelect->UpdateSelectableRouteSegments( MOB_Point );
9707     }
9708 
9709     RefreshAllCanvas( false );
9710 
9711     if( ptarget ){
9712         wxDateTime mob_time = wxDateTime::Now();
9713 
9714         wxString mob_message( _( "AIS MAN OVERBOARD UPDATE" ) );
9715         mob_message += _(" Time: ");
9716         mob_message += mob_time.Format();
9717         mob_message += _("  Ownship Position: ");
9718         mob_message += toSDMM( 1, gLat );
9719         mob_message += _T("   ");
9720         mob_message += toSDMM( 2, gLon );
9721         mob_message += _("  MOB Position: ");
9722         mob_message += toSDMM( 1, ptarget->Lat );
9723         mob_message += _T("   ");
9724         mob_message += toSDMM( 2, ptarget->Lon );
9725 
9726         wxLogMessage( mob_message );
9727     }
9728 
9729 }
9730 
9731 void MyFrame::applySettingsString( wxString settings)
9732 {
9733     //  Save some present values
9734     int last_UIScaleFactor = g_GUIScaleFactor;
9735     bool previous_expert = g_bUIexpert;
9736     g_last_ChartScaleFactor = g_ChartScaleFactor;
9737     ArrayOfCDI *pNewDirArray = new ArrayOfCDI;
9738 
9739     int rr = g_Platform->platformApplyPrivateSettingsString( settings, pNewDirArray);
9740 
9741     // And apply the changes
9742     pConfig->UpdateSettings();
9743 
9744     //  Might need to rebuild symbols
9745     if(g_last_ChartScaleFactor != g_ChartScaleFactor)
9746         rr |= S52_CHANGED;
9747 
9748     if(rr & S52_CHANGED){
9749         if(ps52plib){
9750             ps52plib->FlushSymbolCaches();
9751             ps52plib->ClearCNSYLUPArray();      // some CNSY depends on renderer (e.g. CARC)
9752             ps52plib->GenerateStateHash();
9753         }
9754     }
9755 
9756     ProcessOptionsDialog( rr,  pNewDirArray );
9757 
9758     // Try to detect if the toolbar is changing, to avoid a rebuild if not necessary.
9759 
9760     bool b_newToolbar = false;
9761 
9762     if(g_GUIScaleFactor != last_UIScaleFactor)
9763         b_newToolbar = true;
9764 
9765     if(previous_expert != g_bUIexpert)
9766         b_newToolbar = true;
9767 
9768     if(rr & TOOLBAR_CHANGED)
9769         b_newToolbar = true;
9770 
9771 
9772     if(b_newToolbar){
9773         // .. for each canvas...
9774         for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
9775             ChartCanvas *cc = g_canvasArray.Item(i);
9776             if(cc)
9777                 cc->DestroyToolbar();
9778         }
9779     }
9780 
9781 
9782     //  We do this is one case only to remove an orphan recovery window
9783 #ifdef __OCPN__ANDROID__
9784      if(previous_expert && !g_bUIexpert){
9785          androidForceFullRepaint();
9786      }
9787 #endif
9788 
9789     if(previous_expert != g_bUIexpert)
9790         g_Platform->applyExpertMode(g_bUIexpert);
9791 
9792     //  We set the compass size first, since that establishes the available space for the toolbar.
9793     SetGPSCompassScale();
9794     // ..For each canvas...
9795     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
9796         ChartCanvas *cc = g_canvasArray.Item(i);
9797         if(cc)
9798             cc->GetCompass()->SetScaleFactor(g_compass_scalefactor);
9799     }
9800     UpdateGPSCompassStatusBoxes( true );
9801 
9802     if(b_newToolbar){
9803         g_Platform->ShowBusySpinner();
9804 
9805         SetAllToolbarScale();
9806         RequestNewToolbars(true);    // Force rebuild, to pick up bGUIexpert and scale settings.
9807 
9808         g_Platform->HideBusySpinner();
9809 
9810         RequestNewMasterToolbar( true );
9811     }
9812 
9813     SurfaceAllCanvasToolbars();
9814 
9815     gFrame->Raise();
9816 
9817     InvalidateAllGL();
9818     DoChartUpdate();
9819     UpdateControlBar( GetPrimaryCanvas());
9820     Refresh();
9821 
9822 
9823 #if defined(__WXOSX__) || defined(__WXQT__)
9824     if( g_MainToolbar )
9825         g_MainToolbar->Raise();
9826 
9827     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
9828         ChartCanvas *cc = g_canvasArray.Item(i);
9829          if(cc && cc->GetMUIBar())
9830              cc->GetMUIBar()->Raise();
9831     }
9832 
9833 #endif
9834 
9835     if(console)
9836         console->Raise();
9837 
9838     Refresh( false );
9839 
9840     if (NMEALogWindow::Get().Active())
9841         NMEALogWindow::Get().GetTTYWindow()->Raise();
9842 
9843 }
9844 
9845 
9846 
9847 #ifdef wxHAS_POWER_EVENTS
9848 void MyFrame::OnSuspending(wxPowerEvent& event)
9849 {
9850  //   wxDateTime now = wxDateTime::Now();
9851  //   printf("OnSuspending...%d\n", now.GetTicks());
9852 
9853     wxLogMessage(_T("System suspend starting..."));
9854 }
9855 
9856 void MyFrame::OnSuspended(wxPowerEvent& WXUNUSED(event))
9857 {
9858 //    wxDateTime now = wxDateTime::Now();
9859 //    printf("OnSuspended...%d\n", now.GetTicks());
9860     wxLogMessage(_T("System is going to suspend."));
9861 
9862 }
9863 
9864 void MyFrame::OnSuspendCancel(wxPowerEvent& WXUNUSED(event))
9865 {
9866 //    wxDateTime now = wxDateTime::Now();
9867 //    printf("OnSuspendCancel...%d\n", now.GetTicks());
9868     wxLogMessage(_T("System suspend was cancelled."));
9869 }
9870 
9871 int g_last_resume_ticks;
9872 void MyFrame::OnResume(wxPowerEvent& WXUNUSED(event))
9873 {
9874     wxDateTime now = wxDateTime::Now();
9875 //    printf("OnResume...%d\n", now.GetTicks());
9876     wxLogMessage(_T("System resumed from suspend."));
9877 
9878     if((now.GetTicks() - g_last_resume_ticks) > 5){
9879         wxLogMessage(_T("Restarting streams."));
9880  //       printf("   Restarting streams\n");
9881         g_last_resume_ticks = now.GetTicks();
9882         if(g_pMUX){
9883             g_pMUX->ClearStreams();
9884 
9885             g_pMUX->StartAllStreams();
9886         }
9887     }
9888 
9889     //  If OpenGL is enabled, Windows Resume does not properly refresh the application GL context.
9890     //  We need to force a Resize event that actually does something.
9891     if(g_bopengl){
9892         if( IsMaximized() ){            // This is not real pretty on-screen, but works
9893             Maximize(false);
9894             wxYield();
9895             Maximize(true);
9896         }
9897         else {
9898             wxSize sz = GetSize();
9899             SetSize( wxSize(sz.x - 1, sz.y));
9900             wxYield();
9901             SetSize( sz );
9902         }
9903     }
9904 
9905 }
9906 #endif // wxHAS_POWER_EVENTS
9907 
9908 
9909 
9910 
9911 
9912 
9913 //----------------------------------------------------------------------------------------------------------
9914 //   Master Toolbar support
9915 //----------------------------------------------------------------------------------------------------------
9916 
9917 void MyFrame::RequestNewMasterToolbar(bool bforcenew)
9918 {
9919     bool btbRebuild = false;
9920 
9921     bool b_reshow = true;
9922     if( g_MainToolbar ) {
9923         b_reshow = g_MainToolbar->IsShown();
9924         float ff = fabs(g_MainToolbar->GetScaleFactor() - g_toolbar_scalefactor);
9925         if((ff > 0.01f) || bforcenew){
9926             g_MainToolbar->DestroyToolBar();
9927             delete g_MainToolbar;
9928             g_MainToolbar = NULL;
9929         }
9930 
9931         btbRebuild = true;
9932     }
9933 
9934     if( !g_MainToolbar ) {
9935         long orient = g_Platform->GetDefaultToolbarOrientation();
9936         g_MainToolbar = new ocpnFloatingToolbarDialog( this, wxPoint( -1, -1 ), orient, g_toolbar_scalefactor );
9937         g_MainToolbar->SetCornerRadius( 5 );
9938         g_MainToolbar->SetBackGroundColorString( _T("GREY3")  );
9939         g_MainToolbar->SetToolbarHideMethod( TOOLBAR_HIDE_TO_FIRST_TOOL );
9940         g_MainToolbar->SetToolConfigString(g_toolbarConfig);
9941         g_MainToolbar->EnableRolloverBitmaps( false );
9942         g_MainToolbar->SetGrabberEnable( false );
9943 
9944         g_MainToolbar->CreateConfigMenu();
9945         g_MainToolbar->MoveDialogInScreenCoords(wxPoint(g_maintoolbar_x, g_maintoolbar_y), wxPoint(0, 0));
9946         g_bmasterToolbarFull = true;
9947 
9948     }
9949 
9950     if( g_MainToolbar ) {
9951         CreateMasterToolbar();
9952         if (g_MainToolbar->isSubmergedToGrabber()) {
9953             g_MainToolbar->SubmergeToGrabber();
9954         } else {
9955             g_MainToolbar->RePosition();
9956             g_MainToolbar->SetColorScheme(global_color_scheme);
9957             g_MainToolbar->Show(b_reshow && g_bshowToolbar);
9958         }
9959     }
9960 
9961     if(btbRebuild){
9962         g_MainToolbar->SetAutoHide(g_bAutoHideToolbar);
9963         g_MainToolbar->SetAutoHideTimer(g_nAutoHideToolbar);
9964     }
9965 
9966     //  We need to move the toolbar for the primary (leftmost) ChartCanvas out of the way...
9967     ChartCanvas *cc = g_canvasArray[0];
9968     if(cc && cc->GetToolbar()){
9969         wxRect masterToolbarRect = g_MainToolbar->GetRect();
9970         cc->GetToolbar()->SetULDockPosition(wxPoint(masterToolbarRect.width + 8, -1));
9971         cc->RequestNewCanvasToolbar( false );
9972      }
9973 
9974 
9975 
9976 }
9977 
9978 bool MyFrame::CollapseGlobalToolbar()
9979 {
9980     if(g_MainToolbar){
9981         m_nMasterToolCountShown = 1;
9982         g_MainToolbar->SetToolShowCount(m_nMasterToolCountShown);
9983         g_MainToolbar->GetToolbar()->InvalidateBitmaps();
9984         g_MainToolbar->Realize();
9985         g_bmasterToolbarFull = false;
9986         return true;
9987     }
9988     else
9989         return false;
9990 }
9991 
9992 
9993 bool MyFrame::GetMasterToolItemShow( int toolid )
9994 {
9995     if(g_bmasterToolbarFull)
9996         return true;
9997     else
9998         return false;
9999 }
10000 
10001 ocpnToolBarSimple *MyFrame::CreateMasterToolbar()
10002 {
10003     ocpnToolBarSimple *tb = NULL;
10004 
10005     if( g_MainToolbar )
10006         tb = g_MainToolbar->GetToolbar();
10007 
10008     if( !tb )
10009         return 0;
10010 
10011     ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
10012 
10013     ToolbarItemContainer *tic= new ToolbarItemContainer( ID_MASTERTOGGLE,
10014                                                          style->GetToolIcon( _T("MUI_menu"), TOOLICON_NORMAL),
10015                                                          wxITEM_NORMAL, _("Hide Toolbar"), _T("MUI_menu"));
10016     tic->m_bRequired = true;
10017 
10018     g_MainToolbar->AddToolItem(tic);
10019 
10020     tic= new ToolbarItemContainer( ID_SETTINGS,
10021                                    style->GetToolIcon( _T("MUI_settings"), TOOLICON_NORMAL),
10022                                    wxITEM_NORMAL, _("Options"), _T("MUI_settings"));
10023     g_MainToolbar->AddToolItem(tic);
10024 
10025     tic= new ToolbarItemContainer( ID_MENU_ROUTE_NEW,
10026                                    style->GetToolIcon( _T("MUI_route"), TOOLICON_NORMAL),
10027                                    style->GetToolIcon( _T("MUI_route"), TOOLICON_TOGGLED),
10028                                    wxITEM_CHECK, wxString( _("Create Route") ) << _T(" (Ctrl-R)"), _T("MUI_route") );
10029 
10030     g_MainToolbar->AddToolItem(tic);
10031 
10032     tic= new ToolbarItemContainer( ID_ROUTEMANAGER,
10033                                    style->GetToolIcon( _T("MUI_RMD"), TOOLICON_NORMAL),
10034                                    wxITEM_NORMAL, _("Route & Mark Manager"), _T("MUI_RMD"));
10035     g_MainToolbar->AddToolItem(tic);
10036 
10037     tic= new ToolbarItemContainer( ID_TRACK,
10038                                    style->GetToolIcon( _T("MUI_track"), TOOLICON_NORMAL),
10039                                    style->GetToolIcon( _T("MUI_track"), TOOLICON_TOGGLED),
10040                                    wxITEM_CHECK, _("Enable Tracking"), _T("MUI_track"));
10041     g_MainToolbar->AddToolItem(tic);
10042 
10043     tic= new ToolbarItemContainer( ID_COLSCHEME,
10044                                    style->GetToolIcon( _T("MUI_colorscheme"), TOOLICON_NORMAL),
10045                                    wxITEM_NORMAL, _("Change Color Scheme"), _T("MUI_colorscheme"));
10046     g_MainToolbar->AddToolItem(tic);
10047     //if( GetMasterToolItemShow(ID_COLSCHEME) ){
10048       //  tb->AddTool( ID_COLSCHEME, _T("MUI_colorscheme"), style->GetToolIcon( _T("MUI_colorscheme"), TOOLICON_NORMAL ),
10049         //    tipString, wxITEM_NORMAL );
10050         //tb->SetToolTooltipHiViz( ID_COLSCHEME, true );  // cause the Tooltip to always be visible, whatever
10051                                                         //  the colorscheme
10052     //}
10053 
10054     tic= new ToolbarItemContainer( ID_PRINT,
10055                                    style->GetToolIcon( _T("MUI_print"), TOOLICON_NORMAL),
10056                                    wxITEM_NORMAL, _("Print Chart"), _T("MUI_print"));
10057     g_MainToolbar->AddToolItem(tic);
10058 
10059     tic= new ToolbarItemContainer( ID_ABOUT,
10060                                    style->GetToolIcon( _T("MUI_help"), TOOLICON_NORMAL),
10061                                    wxITEM_NORMAL, _("About OpenCPN"), _T("MUI_help"));
10062     g_MainToolbar->AddToolItem(tic);
10063 
10064     //      Add any PlugIn toolbar tools that request default positioning
10065     AddDefaultPositionPlugInTools();
10066 
10067     //  And finally add the MOB tool
10068     tic= new ToolbarItemContainer( ID_MOB,
10069                                    style->GetToolIcon( _T("mob_btn"), TOOLICON_NORMAL),
10070                                    wxITEM_NORMAL, wxString( _("Drop MOB Marker") ) << _(" (Ctrl-Space)"), _T("mob_btn"));
10071     g_MainToolbar->AddToolItem(tic);
10072 
10073     // Build the toolbar
10074     g_MainToolbar->RebuildToolbar();
10075 
10076     // Realize() the toolbar for current geometry
10077     style->Unload();
10078     g_MainToolbar->Realize();
10079 
10080 
10081 
10082 
10083     //  Set PlugIn tool toggle states
10084     ArrayOfPlugInToolbarTools tool_array = g_pi_manager->GetPluginToolbarToolArray();
10085     for( unsigned int i = 0; i < tool_array.GetCount(); i++ ) {
10086         PlugInToolbarToolContainer *pttc = tool_array.Item( i );
10087         if( !pttc->b_viz )
10088             continue;
10089 
10090         if( pttc->kind == wxITEM_CHECK )
10091             tb->ToggleTool( pttc->id, pttc->b_toggle );
10092     }
10093 
10094 
10095     return tb;
10096 }
10097 
10098 bool MyFrame::CheckAndAddPlugInTool()
10099 {
10100     if( !g_pi_manager ) return false;
10101 
10102     bool bret = false;
10103     ocpnToolBarSimple *tb = NULL;
10104 
10105     if( g_MainToolbar )
10106         tb = g_MainToolbar->GetToolbar();
10107 
10108     if(!tb)
10109         return false;
10110 
10111     int n_tools = tb->GetToolsCount();
10112 
10113     //    Walk the PlugIn tool spec array, checking the requested position
10114     //    If a tool has been requested by a plugin at this position, add it
10115     ArrayOfPlugInToolbarTools tool_array = g_pi_manager->GetPluginToolbarToolArray();
10116 
10117     for( unsigned int i = 0; i < tool_array.GetCount(); i++ ) {
10118         PlugInToolbarToolContainer *pttc = tool_array.Item( i );
10119         if( pttc->position == n_tools ) {
10120             wxBitmap *ptool_bmp;
10121 
10122             switch( global_color_scheme ){
10123                 case GLOBAL_COLOR_SCHEME_DAY:
10124                     ptool_bmp = pttc->bitmap_day;
10125                     ;
10126                     break;
10127                 case GLOBAL_COLOR_SCHEME_DUSK:
10128                     ptool_bmp = pttc->bitmap_dusk;
10129                     break;
10130                 case GLOBAL_COLOR_SCHEME_NIGHT:
10131                     ptool_bmp = pttc->bitmap_night;
10132                     break;
10133                 default:
10134                     ptool_bmp = pttc->bitmap_day;
10135                     break;
10136             }
10137 
10138             ToolbarItemContainer *tic= new ToolbarItemContainer( pttc->id, *( ptool_bmp ), pttc->kind, pttc->shortHelp, _T(""));
10139 
10140             tic->m_NormalIconSVG = pttc->pluginNormalIconSVG;
10141             tic->m_RolloverIconSVG = pttc->pluginRolloverIconSVG;
10142             tic->m_ToggledIconSVG = pttc->pluginToggledIconSVG;
10143             tic->m_bPlugin = true;
10144 
10145             bret = true;
10146         }
10147     }
10148 
10149     //    If we added a tool, call again (recursively) to allow for adding adjacent tools
10150     if( bret ) while( CheckAndAddPlugInTool() ) { /* nothing to do */
10151     }
10152 
10153     return bret;
10154 }
10155 
10156 bool MyFrame::AddDefaultPositionPlugInTools()
10157 {
10158     if( !g_pi_manager ) return false;
10159 
10160     bool bret = false;
10161 
10162     //    Walk the PlugIn tool spec array, checking the requested position
10163     //    If a tool has been requested by a plugin at this position, add it
10164     ArrayOfPlugInToolbarTools tool_array = g_pi_manager->GetPluginToolbarToolArray();
10165 
10166     for( unsigned int i = 0; i < tool_array.GetCount(); i++ ) {
10167         PlugInToolbarToolContainer *pttc = tool_array.Item( i );
10168 
10169         //      Tool is currently tagged as invisible
10170         if( !pttc->b_viz )
10171             continue;
10172 
10173         if( pttc->position == -1 )                  // PlugIn has requested default positioning
10174                 {
10175             wxBitmap *ptool_bmp;
10176 
10177             switch( global_color_scheme ){
10178                 case GLOBAL_COLOR_SCHEME_DAY:
10179                     ptool_bmp = pttc->bitmap_day;
10180                     break;
10181                 case GLOBAL_COLOR_SCHEME_DUSK:
10182                     ptool_bmp = pttc->bitmap_dusk;
10183                     break;
10184                 case GLOBAL_COLOR_SCHEME_NIGHT:
10185                     ptool_bmp = pttc->bitmap_night;
10186                     break;
10187                 default:
10188                     ptool_bmp = pttc->bitmap_day;
10189                     break;
10190             }
10191 
10192 
10193             ToolbarItemContainer *tic= new ToolbarItemContainer( pttc->id, *( ptool_bmp ), pttc->kind, pttc->shortHelp, _T(""));
10194 
10195             tic->m_NormalIconSVG = pttc->pluginNormalIconSVG;
10196             tic->m_RolloverIconSVG = pttc->pluginRolloverIconSVG;
10197             tic->m_ToggledIconSVG = pttc->pluginToggledIconSVG;
10198             tic->m_bPlugin = true;
10199 
10200             g_MainToolbar->AddToolItem(tic);
10201 
10202             bret = true;
10203         }
10204     }
10205     return bret;
10206 }
10207 
10208 
10209 
10210 
10211 
10212 
10213 
10214 
10215 
10216 
10217 //----------------------------------------------------------------------------------------------------------
10218 //      Application-wide CPL Error handler
10219 //----------------------------------------------------------------------------------------------------------
10220 void MyCPLErrorHandler( CPLErr eErrClass, int nError, const char * pszErrorMsg )
10221 
10222 {
10223     char msg[256];
10224 
10225     if( eErrClass == CE_Debug )
10226     snprintf( msg, 255, "CPL: %s", pszErrorMsg );
10227     else
10228         if( eErrClass == CE_Warning )
10229         snprintf( msg, 255, "CPL Warning %d: %s", nError, pszErrorMsg );
10230         else
10231             snprintf( msg, 255, "CPL ERROR %d: %s", nError, pszErrorMsg );
10232 
10233     wxString str( msg, wxConvUTF8 );
10234     wxLogMessage( str );
10235 }
10236 
10237 //----------------------------------------------------------------------------------------------------------
10238 //      Printing Framework Support
10239 //----------------------------------------------------------------------------------------------------------
10240 
10241 bool MyPrintout::OnPrintPage( int page )
10242 {
10243     wxDC *dc = GetDC();
10244     if( dc ) {
10245         if( page == 1 ) DrawPageOne( dc );
10246 
10247         return true;
10248     } else
10249         return false;
10250 }
10251 
10252 bool MyPrintout::OnBeginDocument( int startPage, int endPage )
10253 {
10254     if( !wxPrintout::OnBeginDocument( startPage, endPage ) ) return false;
10255 
10256     return true;
10257 }
10258 
10259 void MyPrintout::GetPageInfo( int *minPage, int *maxPage, int *selPageFrom, int *selPageTo )
10260 {
10261     *minPage = 1;
10262     *maxPage = 1;
10263     *selPageFrom = 1;
10264     *selPageTo = 1;
10265 }
10266 
10267 bool MyPrintout::HasPage( int pageNum )
10268 {
10269     return ( pageNum == 1 );
10270 }
10271 
10272 void MyPrintout::DrawPageOne( wxDC *dc )
10273 {
10274 
10275     // Get the Size of the Chart Canvas
10276     int sx, sy;
10277     gFrame->GetFocusCanvas()->GetClientSize( &sx, &sy );                       // of the canvas
10278 
10279     float maxX = sx;
10280     float maxY = sy;
10281 
10282     // Let's have at least some device units margin
10283     float marginX = 50;
10284     float marginY = 50;
10285 
10286     // Add the margin to the graphic size
10287     maxX += ( 2 * marginX );
10288     maxY += ( 2 * marginY );
10289 
10290     // Get the size of the DC in pixels
10291     int w, h;
10292     dc->GetSize( &w, &h );
10293 
10294     // Calculate a suitable scaling factor
10295     float scaleX = (float) ( w / maxX );
10296     float scaleY = (float) ( h / maxY );
10297 
10298     // Use x or y scaling factor, whichever fits on the DC
10299     float actualScale = wxMin(scaleX,scaleY);
10300 
10301     // Calculate the position on the DC for centring the graphic
10302     float posX = (float) ( ( w - ( maxX * actualScale ) ) / 2.0 );
10303     float posY = (float) ( ( h - ( maxY * actualScale ) ) / 2.0 );
10304 
10305     posX = wxMax(posX, marginX);
10306     posY = wxMax(posY, marginY);
10307 
10308     // Set the scale and origin
10309     dc->SetUserScale( actualScale, actualScale );
10310     dc->SetDeviceOrigin( (long) posX, (long) posY );
10311 
10312 //  Get the latest bitmap as rendered by the ChartCanvas
10313 
10314     if(g_bopengl) {
10315 #ifdef ocpnUSE_GL
10316         if(m_GLbmp.IsOk()){
10317             wxMemoryDC mdc;
10318             mdc.SelectObject( m_GLbmp );
10319             dc->Blit( 0, 0, m_GLbmp.GetWidth(), m_GLbmp.GetHeight(), &mdc, 0, 0 );
10320             mdc.SelectObject( wxNullBitmap );
10321         }
10322 #endif
10323     }
10324     else {
10325 
10326 //  And Blit/scale it onto the Printer DC
10327         wxMemoryDC mdc;
10328         mdc.SelectObject( *( gFrame->GetFocusCanvas()->pscratch_bm ) );
10329 
10330         dc->Blit( 0, 0, gFrame->GetFocusCanvas()->pscratch_bm->GetWidth(), gFrame->GetFocusCanvas()->pscratch_bm->GetHeight(), &mdc, 0, 0 );
10331 
10332         mdc.SelectObject( wxNullBitmap );
10333     }
10334 
10335 }
10336 
10337 void MyPrintout::GenerateGLbmp( )
10338 {
10339     if(g_bopengl) {
10340 #ifdef ocpnUSE_GL
10341         int gsx = gFrame->GetFocusCanvas()->GetglCanvas()->GetSize().x;
10342         int gsy = gFrame->GetFocusCanvas()->GetglCanvas()->GetSize().y;
10343 
10344         unsigned char *buffer = (unsigned char *)malloc( gsx * gsy * 4 );
10345         glReadPixels(0, 0, gsx, gsy, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
10346 
10347         unsigned char *e = (unsigned char *)malloc( gsx * gsy * 3 );
10348 
10349         if(buffer && e){
10350             for( int p = 0; p < gsx*gsy; p++ ) {
10351                 e[3*p+0] = buffer[4*p+0];
10352                 e[3*p+1] = buffer[4*p+1];
10353                 e[3*p+2] = buffer[4*p+2];
10354             }
10355         }
10356         free(buffer);
10357 
10358         wxImage image( gsx,gsy );
10359         image.SetData(e);
10360         wxImage mir_imag = image.Mirror( false );
10361         m_GLbmp = wxBitmap( mir_imag );
10362 #endif
10363     }
10364 }
10365 
10366 
10367 
10368 //---------------------------------------------------------------------------------------
10369 //
10370 //        GPS Positioning Device Detection
10371 //
10372 //---------------------------------------------------------------------------------------
10373 
10374 /*
10375  *     Enumerate all the serial ports on the system
10376  *
10377  *     wxArrayString *EnumerateSerialPorts(void)
10378 
10379  *     Very system specific, unavoidably.
10380  */
10381 
10382 #if defined(__UNIX__) && !defined(__OCPN__ANDROID__) && !defined(__WXOSX__)
10383 extern "C" int wait(int *);                     // POSIX wait() for process
10384 
10385 #include <sys/param.h>
10386 #include <termios.h>
10387 #include <fcntl.h>
10388 #include <sys/ioctl.h>
10389 #ifdef __linux__
10390 #include <linux/serial.h>
10391 #else
10392 #include <termios.h>
10393 #endif
10394 
10395 #endif
10396 
10397 // ****************************************
10398 // Fulup devices selection with scandir
10399 // ****************************************
10400 
10401 // reserve 4 pattern for plugins
10402 char* devPatern[] = {
10403   NULL,NULL,NULL,NULL,
10404   NULL,NULL,NULL,NULL, (char*)-1};
10405 
10406 
10407 // This function allow external plugin to search for a special device name
10408 // ------------------------------------------------------------------------
10409 int paternAdd (const char* patern) {
10410   int ind;
10411 
10412   // snan table for a free slot inside devpatern table
10413   for (ind=0; devPatern[ind] != (char*)-1; ind++)
10414        if (devPatern[ind] == NULL) break;
10415 
10416   // table if full
10417   if  (devPatern [ind] == (char*) -1) return -1;
10418 
10419   // store a copy of the patern in case calling routine had it on its stack
10420   devPatern [ind]  = strdup (patern);
10421   return 0;
10422 }
10423 
10424 
10425 #if defined(__UNIX__) && !defined(__OCPN__ANDROID__) && !defined(__WXOSX__)
10426 // This filter verify is device is withing searched patern and verify it is openable
10427 // -----------------------------------------------------------------------------------
10428 int paternFilter (const struct dirent * dir) {
10429  char* res = NULL;
10430  char  devname [272];
10431  int   fd, ind;
10432 
10433   // search if devname fits with searched paterns
10434   for (ind=0; devPatern [ind] != (char*)-1; ind++) {
10435      if (devPatern [ind] != NULL) res=(char*)strcasestr(dir->d_name,devPatern [ind]);
10436      if (res != NULL) break;
10437   }
10438 
10439   // File does not fit researched patern
10440   if (res == NULL) return 0;
10441 
10442   // Check if we may open this file
10443   snprintf (devname, sizeof (devname), "/dev/%s", dir->d_name);
10444   fd = open(devname, O_RDWR|O_NDELAY|O_NOCTTY);
10445 
10446   // device name is pointing to a real device
10447   if(fd >= 0) {
10448     close (fd);
10449     return 1;
10450   }
10451 
10452   // file is not valid
10453   perror (devname);
10454   return 0;
10455 }
10456 
10457 int isTTYreal(const char *dev)
10458 {
10459 #ifdef __FreeBSD__
10460  	            wxLogMessage( _T("FreeBSD") );
10461     if (strncmp("/dev/tty0", dev, 9) == 0)
10462 	return 1;
10463     if (strncmp("/dev/ttyU", dev, 9) == 0)
10464 	return 1;
10465     if (strcmp("/dev/gps", dev) == 0)
10466 	return 1;
10467     return 0;
10468 #else
10469 #ifdef __FreeBSD__
10470     struct termios termAttr;
10471 #else
10472     struct serial_struct serinfo;
10473 #endif
10474     int ret = 0;
10475 
10476     int fd = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY);
10477 
10478     // device name is pointing to a real device
10479     if(fd >= 0) {
10480 #ifdef __FreeBSD__
10481         if (tcgetattr(fd, &termAttr) == 0) {
10482 #else
10483         if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
10484             // If device type is no PORT_UNKNOWN we accept the port
10485             if (serinfo.type != PORT_UNKNOWN)
10486 #endif
10487                 ret = 1;
10488         }
10489         close (fd);
10490     }
10491 
10492     return ret;
10493 #endif
10494 }
10495 
10496 
10497 #endif
10498 
10499 #ifdef __MINGW32__ // do I need this because of mingw, or because I am running mingw under wine?
10500 # ifndef GUID_CLASS_COMPORT
10501 DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
10502 # endif
10503 #endif
10504 
10505 wxArrayString *EnumerateSerialPorts( void )
10506 {
10507     wxArrayString *preturn = new wxArrayString;
10508 #ifdef OCPN_USE_NEWSERIAL
10509     std::vector<serial::PortInfo> ports = serial::list_ports();
10510     for(std::vector<serial::PortInfo>::iterator it = ports.begin(); it != ports.end(); ++it) {
10511         wxString port((*it).port);
10512         if( (*it).description.length() > 0 && (*it).description != "n/a" ) {
10513             port.Append(_T(" - "));
10514             wxString s_description = wxString::FromUTF8( ((*it).description).c_str());
10515             port.Append( s_description );
10516         }
10517         preturn->Add(port);
10518     }
10519 #ifdef __WXMSW__
10520     //    Search for Garmin device driver on Windows platforms
10521     HDEVINFO hdeviceinfo = INVALID_HANDLE_VALUE;
10522     hdeviceinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_DETECT_GUID, NULL, NULL,
10523                                       DIGCF_PRESENT | DIGCF_INTERFACEDEVICE );
10524     if( hdeviceinfo != INVALID_HANDLE_VALUE ) {
10525 
10526         if(GarminProtocolHandler::IsGarminPlugged()){
10527             wxLogMessage( _T("EnumerateSerialPorts() Found Garmin USB Device.") );
10528             preturn->Add( _T("Garmin-USB") );         // Add generic Garmin selectable device
10529         }
10530     }
10531 #endif // __WXMSW__
10532 #else
10533 #if defined(__UNIX__) && !defined(__OCPN__ANDROID__) && !defined(__WXOSX__)
10534 
10535     //Initialize the pattern table
10536     if( devPatern[0] == NULL ) {
10537 #ifdef __FreeBSD__
10538         paternAdd ( "ttyU" );
10539         paternAdd ( "ttyu" );
10540         paternAdd ( "ttyd" );
10541         paternAdd ( "gps" );
10542 #else
10543         paternAdd ( "ttyUSB" );
10544         paternAdd ( "ttyACM" );
10545         paternAdd ( "ttyGPS" );
10546         paternAdd ( "refcom" );
10547 #endif
10548     }
10549 
10550  //  Looking for user privilege openable devices in /dev
10551  //  Fulup use scandir to improve user experience and support new generation of AIS devices.
10552 
10553       wxString sdev;
10554       int ind, fcount;
10555       struct dirent **filelist = {0};
10556 
10557       // scan directory filter is applied automatically by this call
10558       fcount = scandir("/dev", &filelist, paternFilter, alphasort);
10559 
10560       for(ind = 0; ind < fcount; ind++)  {
10561        wxString sdev (filelist[ind]->d_name, wxConvUTF8);
10562        sdev.Prepend (_T("/dev/"));
10563 
10564        preturn->Add (sdev);
10565        free(filelist[ind]);
10566       }
10567 
10568       free(filelist);
10569 
10570 //        We try to add a few more, arbitrarily, for those systems that have fixed, traditional COM ports
10571 
10572 #ifdef __linux__
10573     if( isTTYreal("/dev/ttyS0") )
10574         preturn->Add( _T("/dev/ttyS0") );
10575 
10576     if( isTTYreal("/dev/ttyS1") )
10577         preturn->Add( _T("/dev/ttyS1") );
10578 #endif /* linux */
10579 
10580 
10581 #endif
10582 
10583 #ifdef PROBE_PORTS__WITH_HELPER
10584 
10585     /*
10586      *     For modern Linux/(Posix??) systems, we may use
10587      *     the system files /proc/tty/driver/serial
10588      *     and /proc/tty/driver/usbserial to identify
10589      *     available serial ports.
10590      *     A complicating factor is that most (all??) linux
10591      *     systems require root privileges to access these files.
10592      *     We will use a helper program method here, despite implied vulnerability.
10593      */
10594 
10595     char buf[256]; // enough to hold one line from serial devices list
10596     char left_digit;
10597     char right_digit;
10598     int port_num;
10599     FILE *f;
10600 
10601     pid_t pID = vfork();
10602 
10603     if (pID == 0)// child
10604     {
10605 //    Temporarily gain root privileges
10606         seteuid(file_user_id);
10607 
10608 //  Execute the helper program
10609         execlp("ocpnhelper", "ocpnhelper", "-SB", NULL);
10610 
10611 //  Return to user privileges
10612         seteuid(user_user_id);
10613 
10614         wxLogMessage(_T("Warning: ocpnhelper failed...."));
10615         _exit(0);// If exec fails then exit forked process.
10616     }
10617 
10618     wait(NULL);                  // for the child to quit
10619 
10620 //    Read and parse the files
10621 
10622     /*
10623      * see if we have any traditional ttySx ports available
10624      */
10625     f = fopen("/var/tmp/serial", "r");
10626 
10627     if (f != NULL)
10628     {
10629         wxLogMessage(_T("Parsing copy of /proc/tty/driver/serial..."));
10630 
10631         /* read in each line of the file */
10632         while(fgets(buf, sizeof(buf), f) != NULL)
10633         {
10634             wxString sm(buf, wxConvUTF8);
10635             sm.Prepend(_T("   "));
10636             sm.Replace(_T("\n"), _T(" "));
10637             wxLogMessage(sm);
10638 
10639             /* if the line doesn't start with a number get the next line */
10640             if (buf[0] < '0' || buf[0] > '9')
10641             continue;
10642 
10643             /*
10644              * convert digits to an int
10645              */
10646             left_digit = buf[0];
10647             right_digit = buf[1];
10648             if (right_digit < '0' || right_digit > '9')
10649             port_num = left_digit - '0';
10650             else
10651             port_num = (left_digit - '0') * 10 + right_digit - '0';
10652 
10653             /* skip if "unknown" in the string */
10654             if (strstr(buf, "unknown") != NULL)
10655             continue;
10656 
10657             /* upper limit of 15 */
10658             if (port_num > 15)
10659             continue;
10660 
10661             /* create string from port_num  */
10662 
10663             wxString s;
10664             s.Printf(_T("/dev/ttyS%d"), port_num);
10665 
10666             /*  add to the output array  */
10667             preturn->Add(wxString(s));
10668 
10669         }
10670 
10671         fclose(f);
10672     }
10673 
10674     /*
10675      * Same for USB ports
10676      */
10677     f = fopen("/var/tmp/usbserial", "r");
10678 
10679     if (f != NULL)
10680     {
10681         wxLogMessage(_T("Parsing copy of /proc/tty/driver/usbserial..."));
10682 
10683         /* read in each line of the file */
10684         while(fgets(buf, sizeof(buf), f) != NULL)
10685         {
10686 
10687             wxString sm(buf, wxConvUTF8);
10688             sm.Prepend(_T("   "));
10689             sm.Replace(_T("\n"), _T(" "));
10690             wxLogMessage(sm);
10691 
10692             /* if the line doesn't start with a number get the next line */
10693             if (buf[0] < '0' || buf[0] > '9')
10694             continue;
10695 
10696             /*
10697              * convert digits to an int
10698              */
10699             left_digit = buf[0];
10700             right_digit = buf[1];
10701             if (right_digit < '0' || right_digit > '9')
10702             port_num = left_digit - '0';
10703             else
10704             port_num = (left_digit - '0') * 10 + right_digit - '0';
10705 
10706             /* skip if "unknown" in the string */
10707             if (strstr(buf, "unknown") != NULL)
10708             continue;
10709 
10710             /* upper limit of 15 */
10711             if (port_num > 15)
10712             continue;
10713 
10714             /* create string from port_num  */
10715 
10716             wxString s;
10717             s.Printf(_T("/dev/ttyUSB%d"), port_num);
10718 
10719             /*  add to the output array  */
10720             preturn->Add(wxString(s));
10721 
10722         }
10723 
10724         fclose(f);
10725     }
10726 
10727     //    As a fallback, in case seteuid doesn't work....
10728     //    provide some defaults
10729     //    This is currently the case for GTK+, which
10730     //    refuses to run suid.  sigh...
10731 
10732     if(preturn->IsEmpty())
10733     {
10734         preturn->Add( _T("/dev/ttyS0"));
10735         preturn->Add( _T("/dev/ttyS1"));
10736         preturn->Add( _T("/dev/ttyUSB0"));
10737         preturn->Add( _T("/dev/ttyUSB1"));
10738         preturn->Add( _T("/dev/ttyACM0"));
10739         preturn->Add( _T("/dev/ttyACM1"));
10740     }
10741 
10742 //    Clean up the temporary files created by helper.
10743     pid_t cpID = vfork();
10744 
10745     if (cpID == 0)// child
10746     {
10747 //    Temporarily gain root privileges
10748         seteuid(file_user_id);
10749 
10750 //  Execute the helper program
10751         execlp("ocpnhelper", "ocpnhelper", "-U", NULL);
10752 
10753 //  Return to user privileges
10754         seteuid(user_user_id);
10755         _exit(0);// If exec fails then exit forked process.
10756     }
10757 
10758 #endif      // __WXGTK__
10759 #ifdef __WXOSX__
10760 #include "macutils.h"
10761     char* paPortNames[MAX_SERIAL_PORTS];
10762     int iPortNameCount;
10763 
10764     memset(paPortNames,0x00,sizeof(paPortNames));
10765     iPortNameCount = FindSerialPortNames(&paPortNames[0],MAX_SERIAL_PORTS);
10766     for (int iPortIndex=0; iPortIndex<iPortNameCount; iPortIndex++)
10767     {
10768         wxString sm(paPortNames[iPortIndex], wxConvUTF8);
10769         preturn->Add(sm);
10770         free(paPortNames[iPortIndex]);
10771     }
10772 #endif      //__WXOSX__
10773 #ifdef __WXMSW__
10774     /*************************************************************************
10775      * Windows provides no system level enumeration of available serial ports
10776      * There are several ways of doing this.
10777      *
10778      *************************************************************************/
10779 
10780 #include <windows.h>
10781 
10782     //    Method 1:  Use GetDefaultCommConfig()
10783     // Try first {g_nCOMPortCheck} possible COM ports, check for a default configuration
10784     //  This method will not find some Bluetooth SPP ports
10785     for( int i = 1; i < g_nCOMPortCheck; i++ ) {
10786         wxString s;
10787         s.Printf( _T("COM%d"), i );
10788 
10789         COMMCONFIG cc;
10790         DWORD dwSize = sizeof(COMMCONFIG);
10791         if( GetDefaultCommConfig( s.fn_str(), &cc, &dwSize ) )
10792             preturn->Add( wxString( s ) );
10793     }
10794 
10795 #if 0
10796     // Method 2:  Use FileOpen()
10797     // Try all 255 possible COM ports, check to see if it can be opened, or if
10798     // not, that an expected error is returned.
10799 
10800     BOOL bFound;
10801     for (int j=1; j<256; j++)
10802     {
10803         char s[20];
10804         sprintf(s, "\\\\.\\COM%d", j);
10805 
10806         // Open the port tentatively
10807         BOOL bSuccess = FALSE;
10808         HANDLE hComm = ::CreateFile(s, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
10809 
10810         //  Check for the error returns that indicate a port is there, but not currently useable
10811         if (hComm == INVALID_HANDLE_VALUE)
10812         {
10813             DWORD dwError = GetLastError();
10814 
10815             if (dwError == ERROR_ACCESS_DENIED ||
10816                     dwError == ERROR_GEN_FAILURE ||
10817                     dwError == ERROR_SHARING_VIOLATION ||
10818                     dwError == ERROR_SEM_TIMEOUT)
10819             bFound = TRUE;
10820         }
10821         else
10822         {
10823             bFound = TRUE;
10824             CloseHandle(hComm);
10825         }
10826 
10827         if (bFound)
10828         preturn->Add(wxString(s));
10829     }
10830 #endif
10831 
10832     // Method 3:  WDM-Setupapi
10833     //  This method may not find XPort virtual ports,
10834     //  but does find Bluetooth SPP ports
10835 
10836     GUID *guidDev = (GUID*) &GUID_CLASS_COMPORT;
10837 
10838     HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
10839 
10840     hDevInfo = SetupDiGetClassDevs( guidDev,
10841                                      NULL,
10842                                      NULL,
10843                                      DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
10844 
10845     if(hDevInfo != INVALID_HANDLE_VALUE) {
10846 
10847         BOOL bOk = TRUE;
10848         SP_DEVICE_INTERFACE_DATA ifcData;
10849 
10850         ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
10851         for (DWORD ii=0; bOk; ii++) {
10852             bOk = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guidDev, ii, &ifcData);
10853             if (bOk) {
10854             // Got a device. Get the details.
10855 
10856                 SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)};
10857                 bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo,
10858                                                       &ifcData, NULL, 0, NULL, &devdata);
10859 
10860                 //      We really only need devdata
10861                 if( !bOk ) {
10862                     if( GetLastError() == 122)  //ERROR_INSUFFICIENT_BUFFER, OK in this case
10863                         bOk = true;
10864                 }
10865 
10866                 //      We could get friendly name and/or description here
10867                 TCHAR fname[256] = {0};
10868                 TCHAR desc[256] ={0};
10869                 if (bOk) {
10870                     BOOL bSuccess = SetupDiGetDeviceRegistryProperty(
10871                         hDevInfo, &devdata, SPDRP_FRIENDLYNAME, NULL,
10872                         (PBYTE)fname, sizeof(fname), NULL);
10873 
10874                     bSuccess = bSuccess && SetupDiGetDeviceRegistryProperty(
10875                         hDevInfo, &devdata, SPDRP_DEVICEDESC, NULL,
10876                         (PBYTE)desc, sizeof(desc), NULL);
10877                 }
10878 
10879                 //  Get the "COMn string from the registry key
10880                 if(bOk) {
10881                     bool bFoundCom = false;
10882                     TCHAR dname[256];
10883                     HKEY hDeviceRegistryKey = SetupDiOpenDevRegKey(hDevInfo, &devdata,
10884                                                                    DICS_FLAG_GLOBAL, 0,
10885                                                                    DIREG_DEV, KEY_QUERY_VALUE);
10886                     if(INVALID_HANDLE_VALUE != hDeviceRegistryKey) {
10887                             DWORD RegKeyType;
10888                             wchar_t    wport[80];
10889                             LPCWSTR cstr = wport;
10890                             MultiByteToWideChar( 0, 0, "PortName", -1, wport, 80);
10891                             DWORD len = sizeof(dname);
10892 
10893                             int result = RegQueryValueEx(hDeviceRegistryKey, cstr,
10894                                                         0, &RegKeyType, (PBYTE)dname, &len );
10895                             if( result == 0 )
10896                                 bFoundCom = true;
10897                     }
10898 
10899                     if( bFoundCom ) {
10900                         wxString port( dname, wxConvUTF8 );
10901 
10902                         //      If the port has already been found, remove the prior entry
10903                         //      in favor of this entry, which will have descriptive information appended
10904                         for( unsigned int n=0 ; n < preturn->GetCount() ; n++ ) {
10905                             if((preturn->Item(n)).IsSameAs(port)){
10906                                 preturn->RemoveAt( n );
10907                                 break;
10908                             }
10909                         }
10910                         wxString desc_name( desc, wxConvUTF8 );         // append "description"
10911                         port += _T(" ");
10912                         port += desc_name;
10913 
10914                         preturn->Add( port );
10915                     }
10916                 }
10917             }
10918         }//for
10919     }// if
10920 
10921 
10922 //    Search for Garmin device driver on Windows platforms
10923 
10924     HDEVINFO hdeviceinfo = INVALID_HANDLE_VALUE;
10925 
10926     hdeviceinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_DETECT_GUID, NULL, NULL,
10927             DIGCF_PRESENT | DIGCF_INTERFACEDEVICE );
10928 
10929     if( hdeviceinfo != INVALID_HANDLE_VALUE ) {
10930 
10931         if(GarminProtocolHandler::IsGarminPlugged()){
10932             wxLogMessage( _T("EnumerateSerialPorts() Found Garmin USB Device.") );
10933             preturn->Add( _T("Garmin-USB") );         // Add generic Garmin selectable device
10934         }
10935     }
10936 
10937 #if 0
10938     SP_DEVICE_INTERFACE_DATA deviceinterface;
10939     deviceinterface.cbSize = sizeof(deviceinterface);
10940 
10941     if (SetupDiEnumDeviceInterfaces(hdeviceinfo,
10942                     NULL,
10943                     (GUID *) &GARMIN_DETECT_GUID,
10944                     0,
10945                     &deviceinterface))
10946     {
10947         wxLogMessage(_T("Found Garmin Device."));
10948 
10949         preturn->Add(_T("GARMIN"));         // Add generic Garmin selectable device
10950     }
10951 #endif
10952 
10953 #endif      //__WXMSW__
10954 
10955 #ifdef __OCPN__ANDROID__
10956     preturn = androidGetSerialPortsArray();
10957 #endif  // __OCPN__ANDROID__
10958 
10959 #endif //OCPN_USE_NEWSERIAL
10960     return preturn;
10961 }
10962 
10963 
10964 bool CheckSerialAccess( void )
10965 {
10966     bool bret = true;
10967 #if defined(__UNIX__) && !defined(__OCPN__ANDROID__)
10968 
10969 #if 0
10970     termios ttyset_old;
10971     termios ttyset;
10972     termios ttyset_check;
10973 
10974     // Get a list of the ports
10975     wxArrayString *ports = EnumerateSerialPorts();
10976     if( ports->GetCount() == 0 )
10977         bret = false;
10978 
10979     for(unsigned int i=0 ; i < ports->GetCount() ; i++){
10980         wxCharBuffer buf = ports->Item(i).ToUTF8();
10981 
10982         //      For the first real port found, try to open it, write some config, and
10983         //      be sure it reads back correctly.
10984         if( isTTYreal( buf.data() ) ){
10985             int fd = open(buf.data(), O_RDWR | O_NONBLOCK | O_NOCTTY);
10986 
10987             // device name is pointing to a real device
10988             if(fd > 0) {
10989 
10990                 if (isatty(fd) != 0)
10991                 {
10992                     /* Save original terminal parameters */
10993                     tcgetattr(fd,&ttyset_old);
10994                     // Write some data
10995                     memcpy(&ttyset, &ttyset_old, sizeof(termios));
10996 
10997                     ttyset.c_cflag &=~ CSIZE;
10998                     ttyset.c_cflag |= CSIZE & CS7;
10999 
11000                     tcsetattr(fd, TCSANOW, &ttyset);
11001 
11002                     // Read it back
11003                     tcgetattr(fd, &ttyset_check);
11004                     if(( ttyset_check.c_cflag & CSIZE) != CS7 ){
11005                         bret = false;
11006                     }
11007                     else {
11008                             // and again
11009                         ttyset.c_cflag &=~ CSIZE;
11010                         ttyset.c_cflag |= CSIZE & CS8;
11011 
11012                         tcsetattr(fd, TCSANOW, &ttyset);
11013 
11014                             // Read it back
11015                         tcgetattr(fd, &ttyset_check);
11016                         if(( ttyset_check.c_cflag & CSIZE) != CS8 ){
11017                             bret = false;
11018                         }
11019                     }
11020 
11021                     tcsetattr(fd, TCSANOW, &ttyset_old);
11022                 }
11023 
11024                 close (fd);
11025             }   // if open
11026         }
11027     }
11028 
11029 #endif  // 0
11030 
11031     //  Who owns /dev/ttyS0?
11032     bret = false;
11033 
11034     wxArrayString result1;
11035     wxExecute(_T("stat -c %G /dev/ttyS0"), result1);
11036     if(!result1.size())
11037         wxExecute(_T("stat -c %G /dev/ttyUSB0"), result1);
11038 
11039     if(!result1.size())
11040         wxExecute(_T("stat -c %G /dev/ttyACM0"), result1);
11041 
11042     if(!result1.size())
11043         wxExecute(_T("stat -f %g /dev/ttyu0"), result1);
11044 
11045     if(!result1.size())
11046         wxExecute(_T("stat -f %g /dev/ttyU0"), result1);
11047 
11048     wxString msg1 = _("OpenCPN requires access to serial ports to use serial NMEA data.\n");
11049     if(!result1.size()) {
11050         wxString msg = msg1 + _("No Serial Ports can be found on this system.\n\
11051 You must install a serial port (modprobe correct kernel module) or plug in a usb serial device.\n");
11052 
11053         OCPNMessageBox ( NULL, msg, wxString( _("OpenCPN Info") ), wxICON_INFORMATION | wxOK, 30 );
11054         return false;
11055     }
11056 
11057     //  Is the current user in this group?
11058     wxString user = wxGetUserId(), group = result1[0];
11059 
11060     wxArrayString result2;
11061     wxExecute(_T("id -G ") + user, result2);
11062 
11063     if(result2.size()) {
11064         wxString user_groups = result2[0];
11065 
11066         if(user_groups.Find(group) != wxNOT_FOUND)
11067             bret = true;
11068     }
11069 
11070 #ifdef FLATPAK
11071     return bret;
11072 #endif
11073 
11074     if(!bret){
11075 
11076         wxString msg = msg1 + _("\
11077 You do currently not have permission to access the serial ports on this system.\n\n\
11078 It is suggested that you exit OpenCPN now,\n\
11079 and add yourself to the correct group to enable serial port access.\n\n\
11080 You may do so by executing the following command from the linux command line:\n\n\
11081                 sudo usermod -a -G ");
11082 
11083         msg += group;
11084         msg += _T(" ");
11085         msg += user;
11086         msg += _T("\n");
11087 
11088         OCPNMessageBox ( NULL, msg, wxString( _("OpenCPN Info") ), wxICON_INFORMATION | wxOK, 30 );
11089     }
11090 
11091 #endif  // (__UNIX__) && !defined(__OCPN__ANDROID__)
11092 
11093     return bret;
11094 }
11095 
11096 void appendOSDirSlash( wxString* pString )
11097 {
11098     wxChar sep = wxFileName::GetPathSeparator();
11099     if( pString->Last() != sep ) pString->Append( sep );
11100 }
11101 
11102 /*************************************************************************
11103  * Global color management routines
11104  *
11105  *************************************************************************/
11106 
11107 wxColour GetGlobalColor(wxString colorName)
11108 {
11109     wxColour ret_color;
11110 
11111     //    Use the S52 Presentation library if present
11112     if( ps52plib )
11113         ret_color = ps52plib->getwxColour( colorName );
11114     if( !ret_color.Ok() && pcurrent_user_color_hash )
11115         ret_color = ( *pcurrent_user_color_hash )[colorName];
11116 
11117     //    Default
11118     if( !ret_color.Ok() ) {
11119         ret_color.Set( 128, 128, 128 );  // Simple Grey
11120         wxLogMessage(_T("Warning: Color not found ") + colorName);
11121         // Avoid duplicate warnings:
11122         if (pcurrent_user_color_hash)
11123             ( *pcurrent_user_color_hash )[colorName] = ret_color;
11124     }
11125 
11126     return ret_color;
11127 }
11128 
11129 static const char *usercolors[] = { "Table:DAY", "GREEN1;120;255;120;", "GREEN2; 45;150; 45;",
11130         "GREEN3;200;220;200;", "GREEN4;  0;255;  0;", "BLUE1; 170;170;255;", "BLUE2;  45; 45;170;",
11131         "BLUE3;   0;  0;255;", "GREY1; 200;200;200;", "GREY2; 230;230;230;", "RED1;  220;200;200;",
11132         "UBLCK;   0;  0;  0;", "UWHIT; 255;255;255;", "URED;  255;  0;  0;", "UGREN;   0;255;  0;",
11133         "YELO1; 243;229; 47;", "YELO2; 128; 80;  0;", "TEAL1;   0;128;128;", "GREEN5;170;254;  0;",
11134         "COMPT; 245;247;244",
11135 #ifdef __WXOSX__
11136         "DILG0; 255;255;255;",              // Dialog Background white
11137 #else
11138         "DILG0; 238;239;242;",              // Dialog Background white
11139 #endif
11140         "DILG1; 212;208;200;",              // Dialog Background
11141         "DILG2; 255;255;255;",              // Control Background
11142         "DILG3;   0;  0;  0;",              // Text
11143         "UITX1;   0;  0;  0;",              // Menu Text, derived from UINFF
11144 
11145         "CHGRF; 163; 180; 183;",
11146         "UINFM; 197;  69; 195;",
11147         "UINFG; 104; 228;  86;",
11148         "UINFF; 125; 137; 140;",
11149         "UINFR; 241;  84; 105;",
11150         "SHIPS;   7;   7;   7;",
11151         "CHYLW; 244; 218;  72;",
11152         "CHWHT; 212; 234; 238;",
11153 
11154         "UDKRD; 124; 16;  0;",
11155         "UARTE; 200;  0;  0;",              // Active Route, Grey on Dusk/Night
11156 
11157         "NODTA; 163; 180; 183;",
11158         "CHBLK;   7;   7;   7;",
11159         "SNDG1; 125; 137; 140;",
11160         "SNDG2;   7;   7;   7;",
11161         "SCLBR; 235; 125;  54;",
11162         "UIBDR; 125; 137; 140;",
11163         "UINFB;  58; 120; 240;",
11164         "UINFD;   7;   7;   7;",
11165         "UINFO; 235; 125;  54;",
11166         "PLRTE; 220;  64;  37;",
11167         "CHMGD; 197; 69; 195;",
11168         "UIBCK; 212; 234; 238;",
11169 
11170         "DASHB; 255;255;255;",              // Dashboard Instr background
11171         "DASHL; 190;190;190;",              // Dashboard Instr Label
11172         "DASHF;  50; 50; 50;",              // Dashboard Foreground
11173         "DASHR; 200;  0;  0;",              // Dashboard Red
11174         "DASHG;   0;200;  0;",              // Dashboard Green
11175         "DASHN; 200;120;  0;",              // Dashboard Needle
11176         "DASH1; 204;204;255;",              // Dashboard Illustrations
11177         "DASH2; 122;131;172;",              // Dashboard Illustrations
11178         "COMP1; 211;211;211;",              // Compass Window Background
11179 
11180         "GREY3;  40; 40; 40;",              // MUIBar/TB background
11181         "BLUE4; 100;100;200;",              // Canvas Focus Bar
11182         "VIO01; 171; 33;141;",
11183         "VIO02; 209;115;213;",
11184 
11185 
11186 
11187         "Table:DUSK", "GREEN1; 60;128; 60;", "GREEN2; 22; 75; 22;", "GREEN3; 80;100; 80;",
11188         "GREEN4;  0;128;  0;", "BLUE1;  80; 80;160;", "BLUE2;  30; 30;120;", "BLUE3;   0;  0;128;",
11189         "GREY1; 100;100;100;", "GREY2; 128;128;128;", "RED1;  150;100;100;", "UBLCK;   0;  0;  0;",
11190         "UWHIT; 255;255;255;", "URED;  120; 54; 11;", "UGREN;  35;110; 20;", "YELO1; 120;115; 24;",
11191         "YELO2;  64; 40;  0;", "TEAL1;   0; 64; 64;", "GREEN5; 85;128; 0;",
11192         "COMPT; 124;126;121",
11193 
11194         "CHGRF;  41; 46; 46;",
11195         "UINFM;  58; 20; 57;",
11196         "UINFG;  35; 76; 29;",
11197         "UINFF;  41; 46; 46;",
11198         "UINFR;  80; 28; 35;",
11199         "SHIPS;  71; 78; 79;",
11200         "CHYLW;  81; 73; 24;",
11201         "CHWHT;  71; 78; 79;",
11202 
11203         "DILG0; 110;110;110;",              // Dialog Background
11204         "DILG1; 110;110;110;",              // Dialog Background
11205         "DILG2;   0;  0;  0;",              // Control Background
11206         "DILG3; 130;130;130;",              // Text
11207         "UITX1;  41; 46; 46;",              // Menu Text, derived from UINFF
11208         "UDKRD;  80;  0;  0;",
11209         "UARTE;  64; 64; 64;",              // Active Route, Grey on Dusk/Night
11210 
11211         "NODTA;  41;  46;  46;",
11212         "CHBLK;  54;  60;  61;",
11213         "SNDG1;  41;  46;  46;",
11214         "SNDG2;  71;  78;  79;",
11215         "SCLBR;  75;  38;  19;",
11216         "UIBDR;  54;  60;  61;",
11217         "UINFB;  19;  40;  80;",
11218         "UINFD;  71;  78;  79;",
11219         "UINFO;  75;  38;  19;",
11220         "PLRTE;  73;  21;  12;",
11221         "CHMGD; 74; 58; 81;",
11222         "UIBCK; 7; 7; 7;",
11223 
11224         "DASHB;  77; 77; 77;",              // Dashboard Instr background
11225         "DASHL;  54; 54; 54;",              // Dashboard Instr Label
11226         "DASHF;   0;  0;  0;",              // Dashboard Foreground
11227         "DASHR;  58; 21; 21;",              // Dashboard Red
11228         "DASHG;  21; 58; 21;",              // Dashboard Green
11229         "DASHN; 100; 50;  0;",              // Dashboard Needle
11230         "DASH1;  76; 76;113;",              // Dashboard Illustrations
11231         "DASH2;  48; 52; 72;",              // Dashboard Illustrations
11232         "COMP1; 107;107;107;",              // Compass Window Background
11233 
11234         "GREY3;  20; 20; 20;",              // MUIBar/TB background
11235         "BLUE4;  80; 80;160;",              // Canvas Focus Bar
11236         "VIO01; 128; 25;108;",
11237         "VIO02; 171; 33;141;",
11238 
11239         "Table:NIGHT", "GREEN1; 30; 80; 30;", "GREEN2; 15; 60; 15;", "GREEN3; 12; 23;  9;",
11240         "GREEN4;  0; 64;  0;", "BLUE1;  60; 60;100;", "BLUE2;  22; 22; 85;", "BLUE3;   0;  0; 40;",
11241         "GREY1;  48; 48; 48;", "GREY2;  32; 32; 32;", "RED1;  100; 50; 50;", "UWHIT; 255;255;255;",
11242         "UBLCK;   0;  0;  0;", "URED;   60; 27;  5;", "UGREN;  17; 55; 10;", "YELO1;  60; 65; 12;",
11243         "YELO2;  32; 20;  0;", "TEAL1;   0; 32; 32;", "GREEN5; 44; 64; 0;",
11244         "COMPT;  48; 49; 51",
11245         "DILG0;  80; 80; 80;",              // Dialog Background
11246         "DILG1;  80; 80; 80;",              // Dialog Background
11247         "DILG2;   0;  0;  0;",              // Control Background
11248         "DILG3;  65; 65; 65;",              // Text
11249         "UITX1;  31; 34; 35;",              // Menu Text, derived from UINFF
11250         "UDKRD;  50;  0;  0;",
11251         "UARTE;  64; 64; 64;",              // Active Route, Grey on Dusk/Night
11252 
11253         "CHGRF;  16; 18; 18;",
11254         "UINFM;  52; 18; 52;",
11255         "UINFG;  22; 24;  7;",
11256         "UINFF;  31; 34; 35;",
11257         "UINFR;  59; 17; 10;",
11258         "SHIPS;  37; 41; 41;",
11259         "CHYLW;  31; 33; 10;",
11260         "CHWHT;  37; 41; 41;",
11261 
11262         "NODTA;   7;   7;   7;",
11263         "CHBLK;  31;  34;  35;",
11264         "SNDG1;  31;  34;  35;",
11265         "SNDG2;  43;  48;  48;",
11266         "SCLBR;  52;  28;  12;",
11267         "UIBDR;  31;  34;  35;",
11268         "UINFB;  21;  29;  69;",
11269         "UINFD;  43;  48;  58;",
11270         "UINFO;  52;  28;  12;",
11271         "PLRTE;  66;  19;  11;",
11272         "CHMGD; 52; 18; 52;",
11273         "UIBCK; 7; 7; 7;",
11274 
11275         "DASHB;   0;  0;  0;",              // Dashboard Instr background
11276         "DASHL;  20; 20; 20;",              // Dashboard Instr Label
11277         "DASHF;  64; 64; 64;",              // Dashboard Foreground
11278         "DASHR;  70; 15; 15;",              // Dashboard Red
11279         "DASHG;  15; 70; 15;",              // Dashboard Green
11280         "DASHN;  17; 80; 56;",              // Dashboard Needle
11281         "DASH1;  48; 52; 72;",              // Dashboard Illustrations
11282         "DASH2;  36; 36; 53;",              // Dashboard Illustrations
11283         "COMP1;  24; 24; 24;",              // Compass Window Background
11284 
11285         "GREY3;  10; 10; 10;",              // MUIBar/TB background
11286         "BLUE4;  70; 70;140;",              // Canvas Focus Bar
11287         "VIO01;  85; 16; 72;",
11288         "VIO02; 128; 25;108;",
11289 
11290         "*****" };
11291 
11292 int get_static_line( char *d, const char **p, int index, int n )
11293 {
11294     if( !strcmp( p[index], "*****" ) ) return 0;
11295 
11296     strncpy( d, p[index], n );
11297     return strlen( d );
11298 }
11299 
11300 static void InitializeUserColors( void )
11301 {
11302     const char **p = usercolors;
11303     char buf[81];
11304     int index = 0;
11305     char TableName[20];
11306     colTable *ctp;
11307     colTable *ct;
11308     int R, G, B;
11309 
11310     UserColorTableArray = new wxArrayPtrVoid;
11311     UserColourHashTableArray = new wxArrayPtrVoid;
11312 
11313     //    Create 3 color table entries
11314     ct = new colTable;
11315     ct->tableName = new wxString( _T("DAY") );
11316     ct->color = new wxArrayPtrVoid;
11317     UserColorTableArray->Add( (void *) ct );
11318 
11319     ct = new colTable;
11320     ct->tableName = new wxString( _T("DUSK") );
11321     ct->color = new wxArrayPtrVoid;
11322     UserColorTableArray->Add( (void *) ct );
11323 
11324     ct = new colTable;
11325     ct->tableName = new wxString( _T("NIGHT") );
11326     ct->color = new wxArrayPtrVoid;
11327     UserColorTableArray->Add( (void *) ct );
11328 
11329     while( ( get_static_line( buf, p, index, sizeof(buf) - 1 ) ) ) {
11330         if( !strncmp( buf, "Table", 5 ) ) {
11331             sscanf( buf, "Table:%s", TableName );
11332 
11333             for( unsigned int it = 0; it < UserColorTableArray->GetCount(); it++ ) {
11334                 ctp = (colTable *) ( UserColorTableArray->Item( it ) );
11335                 if( !strcmp( TableName, ctp->tableName->mb_str() ) ) {
11336                     ct = ctp;
11337                     break;
11338                 }
11339             }
11340 
11341         } else {
11342             char name[21];
11343             int j = 0;
11344             while( buf[j] != ';' && j < 20 ) {
11345                 name[j] = buf[j];
11346                 j++;
11347             }
11348             name[j] = 0;
11349 
11350             S52color *c = new S52color;
11351             strcpy( c->colName, name );
11352 
11353             sscanf( &buf[j], ";%i;%i;%i", &R, &G, &B );
11354             c->R = (char) R;
11355             c->G = (char) G;
11356             c->B = (char) B;
11357 
11358             ct->color->Add( c );
11359 
11360         }
11361 
11362         index++;
11363     }
11364 
11365     //    Now create the Hash tables
11366 
11367     for( unsigned int its = 0; its < UserColorTableArray->GetCount(); its++ ) {
11368         wxColorHashMap *phash = new wxColorHashMap;
11369         UserColourHashTableArray->Add( (void *) phash );
11370 
11371         colTable *ctp = (colTable *) ( UserColorTableArray->Item( its ) );
11372 
11373         for( unsigned int ic = 0; ic < ctp->color->GetCount(); ic++ ) {
11374             S52color *c2 = (S52color *) ( ctp->color->Item( ic ) );
11375 
11376             wxColour c( c2->R, c2->G, c2->B );
11377             wxString key( c2->colName, wxConvUTF8 );
11378             ( *phash )[key] = c;
11379 
11380         }
11381     }
11382 
11383     //    Establish a default hash table pointer
11384     //    in case a color is needed before ColorScheme is set
11385     pcurrent_user_color_hash = (wxColorHashMap *) UserColourHashTableArray->Item( 0 );
11386 }
11387 
11388 static void DeInitializeUserColors( void )
11389 {
11390     unsigned int i;
11391     for( i = 0; i < UserColorTableArray->GetCount(); i++ ) {
11392         colTable *ct = (colTable *) UserColorTableArray->Item( i );
11393 
11394         for( unsigned int j = 0; j < ct->color->GetCount(); j++ ) {
11395             S52color *c = (S52color *) ct->color->Item( j );
11396             delete c;                     //color
11397         }
11398 
11399         delete ct->tableName;               // wxString
11400         delete ct->color;                   // wxArrayPtrVoid
11401 
11402         delete ct;                          // colTable
11403     }
11404 
11405     delete UserColorTableArray;
11406 
11407     for( i = 0; i < UserColourHashTableArray->GetCount(); i++ ) {
11408         wxColorHashMap *phash = (wxColorHashMap *) UserColourHashTableArray->Item( i );
11409         delete phash;
11410     }
11411 
11412     delete UserColourHashTableArray;
11413 
11414 }
11415 
11416 #ifdef __WXMSW__
11417 
11418 #define NCOLORS 40
11419 
11420 typedef struct _MSW_COLOR_SPEC {
11421     int COLOR_NAME;
11422     wxString S52_RGB_COLOR;
11423     int SysRGB_COLOR;
11424 } MSW_COLOR_SPEC;
11425 
11426 MSW_COLOR_SPEC color_spec[] = { { COLOR_MENU, _T("UIBCK"), 0 }, { COLOR_MENUTEXT, _T("UITX1"), 0 },
11427         { COLOR_BTNSHADOW, _T("UIBCK"), 0 },                        // Menu Frame
11428         { -1, _T(""), 0 } };
11429 
11430 void SaveSystemColors()
11431 {
11432     /*
11433      color_3dface = pGetSysColor(COLOR_3DFACE);
11434      color_3dhilite = pGetSysColor(COLOR_3DHILIGHT);
11435      color_3dshadow = pGetSysColor(COLOR_3DSHADOW);
11436      color_3ddkshadow = pGetSysColor(COLOR_3DDKSHADOW);
11437      color_3dlight = pGetSysColor(COLOR_3DLIGHT);
11438      color_activecaption = pGetSysColor(COLOR_ACTIVECAPTION);
11439      color_gradientactivecaption = pGetSysColor(27); //COLOR_3DLIGHT);
11440      color_captiontext = pGetSysColor(COLOR_CAPTIONTEXT);
11441      color_windowframe = pGetSysColor(COLOR_WINDOWFRAME);
11442      color_inactiveborder = pGetSysColor(COLOR_INACTIVEBORDER);
11443      */
11444     //    Record the default system color in my substitution structure
11445     MSW_COLOR_SPEC *pcspec = &color_spec[0];
11446     while( pcspec->COLOR_NAME != -1 ) {
11447         pcspec->SysRGB_COLOR = pGetSysColor( pcspec->COLOR_NAME );
11448         pcspec++;
11449     }
11450 }
11451 
11452 void RestoreSystemColors()
11453 {
11454     int element[NCOLORS];
11455     int rgbcolor[NCOLORS];
11456     int i = 0;
11457 
11458     MSW_COLOR_SPEC *pcspec = &color_spec[0];
11459     while( pcspec->COLOR_NAME != -1 ) {
11460         element[i] = pcspec->COLOR_NAME;
11461         rgbcolor[i] = pcspec->SysRGB_COLOR;
11462 
11463         pcspec++;
11464         i++;
11465     }
11466 
11467     pSetSysColors( i, (unsigned long *) &element[0], (unsigned long *) &rgbcolor[0] );
11468 
11469 }
11470 
11471 #endif
11472 
11473 void SetSystemColors( ColorScheme cs )
11474 {//---------------
11475 #ifdef __WXMSW__
11476     int element[NCOLORS];
11477     int rgbcolor[NCOLORS];
11478     int i = 0;
11479     if( ( GLOBAL_COLOR_SCHEME_DUSK == cs ) || ( GLOBAL_COLOR_SCHEME_NIGHT == cs ) ) {
11480         MSW_COLOR_SPEC *pcspec = &color_spec[0];
11481         while( pcspec->COLOR_NAME != -1 ) {
11482             wxColour color = GetGlobalColor( pcspec->S52_RGB_COLOR );
11483             rgbcolor[i] = ( color.Red() << 16 ) + ( color.Green() << 8 ) + color.Blue();
11484             element[i] = pcspec->COLOR_NAME;
11485 
11486             i++;
11487             pcspec++;
11488         }
11489 
11490         pSetSysColors( i, (unsigned long *) &element[0], (unsigned long *) &rgbcolor[0] );
11491 
11492     } else {         // for daylight colors, use default windows colors as saved....
11493 
11494         RestoreSystemColors();
11495     }
11496 #endif
11497 }
11498 
11499 wxColor GetDimColor(wxColor c)
11500 {
11501     if( (global_color_scheme == GLOBAL_COLOR_SCHEME_DAY) || (global_color_scheme == GLOBAL_COLOR_SCHEME_RGB))
11502         return c;
11503 
11504     float factor = 1.0;
11505     if(global_color_scheme == GLOBAL_COLOR_SCHEME_DUSK)
11506         factor = 0.5;
11507     if(global_color_scheme == GLOBAL_COLOR_SCHEME_NIGHT)
11508         factor = 0.25;
11509 
11510     wxImage::RGBValue rgb( c.Red(), c.Green(), c.Blue() );
11511     wxImage::HSVValue hsv = wxImage::RGBtoHSV( rgb );
11512     hsv.value = hsv.value * factor;
11513     wxImage::RGBValue nrgb = wxImage::HSVtoRGB( hsv );
11514 
11515     return wxColor( nrgb.red, nrgb.green, nrgb.blue );
11516 }
11517 
11518 BEGIN_EVENT_TABLE(OCPNMessageDialog, wxDialog)
11519 EVT_BUTTON(wxID_YES, OCPNMessageDialog::OnYes)
11520 EVT_BUTTON(wxID_NO, OCPNMessageDialog::OnNo)
11521 EVT_BUTTON(wxID_CANCEL, OCPNMessageDialog::OnCancel)
11522 EVT_CLOSE(OCPNMessageDialog::OnClose)
11523 END_EVENT_TABLE()
11524 
11525 
11526 OCPNMessageDialog::OCPNMessageDialog( wxWindow *parent,
11527                                                 const wxString& message,
11528                                                 const wxString& caption,
11529                                                 long style,
11530                                                 const wxPoint& pos)
11531 : wxDialog( parent, wxID_ANY, caption, pos, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP )
11532 {
11533     m_style = style;
11534     wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
11535     SetFont( *qFont );
11536 
11537     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
11538 
11539     wxBoxSizer *icon_text = new wxBoxSizer( wxHORIZONTAL );
11540 
11541     #if wxUSE_STATBMP
11542     // 1) icon
11543     if (style & wxICON_MASK)
11544     {
11545         wxBitmap bitmap;
11546         switch ( style & wxICON_MASK )
11547         {
11548             default:
11549                 wxFAIL_MSG(_T("incorrect log style"));
11550                 // fall through
11551 
11552             case wxICON_ERROR:
11553                 bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX);
11554                 break;
11555 
11556             case wxICON_INFORMATION:
11557                 bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX);
11558                 break;
11559 
11560             case wxICON_WARNING:
11561                 bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX);
11562                 break;
11563 
11564             case wxICON_QUESTION:
11565                 bitmap = wxArtProvider::GetIcon(wxART_QUESTION, wxART_MESSAGE_BOX);
11566                 break;
11567         }
11568         wxStaticBitmap *icon = new wxStaticBitmap(this, wxID_ANY, bitmap);
11569         icon_text->Add( icon, 0, wxCENTER );
11570     }
11571     #endif // wxUSE_STATBMP
11572 
11573     #if wxUSE_STATTEXT
11574     // 2) text
11575     icon_text->Add( CreateTextSizer( message ), 0, wxALIGN_CENTER | wxLEFT, 10 );
11576 
11577     topsizer->Add( icon_text, 1, wxCENTER | wxLEFT|wxRIGHT|wxTOP, 10 );
11578     #endif // wxUSE_STATTEXT
11579 
11580     // 3) buttons
11581     int AllButtonSizerFlags = wxOK|wxCANCEL|wxYES|wxNO|wxHELP|wxNO_DEFAULT;
11582     int center_flag = wxEXPAND;
11583     if (style & wxYES_NO)
11584         center_flag = wxALIGN_CENTRE;
11585     wxSizer *sizerBtn = CreateSeparatedButtonSizer(style & AllButtonSizerFlags);
11586     if ( sizerBtn )
11587         topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10 );
11588 
11589     SetAutoLayout( true );
11590     SetSizer( topsizer );
11591 
11592     topsizer->SetSizeHints( this );
11593     topsizer->Fit( this );
11594     wxSize size( GetSize() );
11595     if (size.x < size.y*3/2)
11596     {
11597         size.x = size.y*3/2;
11598         SetSize( size );
11599     }
11600 
11601     Centre( wxBOTH | wxCENTER_FRAME);
11602 }
11603 
11604 void OCPNMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event))
11605 {
11606     SetReturnCode(wxID_YES);
11607     EndModal( wxID_YES );
11608 }
11609 
11610 void OCPNMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event))
11611 {
11612     SetReturnCode(wxID_NO);
11613     EndModal( wxID_NO );
11614 }
11615 
11616 void OCPNMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
11617 {
11618     // Allow cancellation via ESC/Close button except if
11619     // only YES and NO are specified.
11620     if ( (m_style & wxYES_NO) != wxYES_NO || (m_style & wxCANCEL) )
11621     {
11622         SetReturnCode(wxID_CANCEL);
11623         EndModal( wxID_CANCEL );
11624     }
11625 }
11626 
11627 void OCPNMessageDialog::OnClose( wxCloseEvent& event )
11628 {
11629     SetReturnCode(wxID_CANCEL);
11630     EndModal( wxID_CANCEL );
11631 }
11632 
11633 
11634 
11635 
11636 class TimedMessageBox:wxEvtHandler
11637 {
11638 public:
11639     TimedMessageBox(wxWindow* parent, const wxString& message,
11640                     const wxString& caption = _T("Message box"), long style = wxOK | wxCANCEL,
11641                     int timeout_sec = -1, const wxPoint& pos = wxDefaultPosition );
11642     ~TimedMessageBox();
11643     int GetRetVal(void){ return ret_val; }
11644     void OnTimer(wxTimerEvent &evt);
11645 
11646     wxTimer     m_timer;
11647     OCPNMessageDialog *dlg;
11648     int         ret_val;
11649 
11650     DECLARE_EVENT_TABLE()
11651 };
11652 
11653 BEGIN_EVENT_TABLE(TimedMessageBox, wxEvtHandler)
11654 EVT_TIMER(-1, TimedMessageBox::OnTimer)
11655 END_EVENT_TABLE()
11656 
11657 TimedMessageBox::TimedMessageBox(wxWindow* parent, const wxString& message,
11658                                  const wxString& caption, long style, int timeout_sec, const wxPoint& pos )
11659 {
11660     ret_val = 0;
11661     m_timer.SetOwner( this, -1 );
11662 
11663     if(timeout_sec > 0)
11664         m_timer.Start( timeout_sec * 1000, wxTIMER_ONE_SHOT );
11665 
11666     dlg = new OCPNMessageDialog( parent, message, caption, style, pos );
11667     dlg->ShowModal();
11668 
11669     int ret= dlg->GetReturnCode();
11670 
11671     //  Not sure why we need this, maybe on wx3?
11672     if( ((style & wxYES_NO) == wxYES_NO) && (ret == wxID_OK))
11673         ret = wxID_YES;
11674 
11675     delete dlg;
11676     dlg = NULL;
11677 
11678     ret_val = ret;
11679 }
11680 
11681 
11682 TimedMessageBox::~TimedMessageBox()
11683 {
11684 }
11685 
11686 void TimedMessageBox::OnTimer(wxTimerEvent &evt)
11687 {
11688     if( dlg )
11689         dlg->EndModal( wxID_CANCEL );
11690 }
11691 
11692 
11693 
11694 
11695 
11696 
11697 int OCPNMessageBox( wxWindow *parent, const wxString& message, const wxString& caption, int style,
11698                     int timeout_sec, int x, int y  )
11699 {
11700 #ifdef __OCPN__ANDROID__
11701     androidDisableRotation();
11702     int style_mod = style;
11703 
11704     auto dlg = new wxMessageDialog(parent, message, caption,  style_mod);
11705     int ret = dlg->ShowModal();
11706     qDebug() << "OCPNMB-1 ret" << ret;
11707 
11708     //int ret= dlg->GetReturnCode();
11709 
11710     //  Not sure why we need this, maybe on wx3?
11711     if( ((style & wxYES_NO) == wxYES_NO) && (ret == wxID_OK))
11712         ret = wxID_YES;
11713 
11714     dlg->Destroy();
11715 
11716     androidEnableRotation();
11717     qDebug() << "OCPNMB-2 ret" << ret;
11718     return ret;
11719 
11720 #else
11721     int ret =  wxID_OK;
11722 
11723     TimedMessageBox tbox(parent, message, caption, style, timeout_sec, wxPoint( x, y )  );
11724     ret = tbox.GetRetVal() ;
11725 #endif
11726 
11727     return ret;
11728 }
11729 
11730 //               A helper function to check for proper parameters of anchor watch
11731 //
11732 double AnchorDistFix( double const d, double const AnchorPointMinDist,
11733         double const AnchorPointMaxDist )   //  pjotrc 2010.02.22
11734 {
11735     if( d >= 0.0 ) if( d < AnchorPointMinDist ) return AnchorPointMinDist;
11736     else
11737         if( d > AnchorPointMaxDist ) return AnchorPointMaxDist;
11738         else
11739             return d;
11740 
11741     else
11742         //if ( d < 0.0 )
11743         if( d > -AnchorPointMinDist ) return -AnchorPointMinDist;
11744         else
11745             if( d < -AnchorPointMaxDist ) return -AnchorPointMaxDist;
11746             else
11747                 return d;
11748 }
11749 
11750 //      Auto timed popup Window implementation
11751 
11752 BEGIN_EVENT_TABLE(TimedPopupWin, wxWindow) EVT_PAINT(TimedPopupWin::OnPaint)
11753 EVT_TIMER(POPUP_TIMER, TimedPopupWin::OnTimer)
11754 
11755 END_EVENT_TABLE()
11756 
11757 // Define a constructor
11758 TimedPopupWin::TimedPopupWin( wxWindow *parent, int timeout ) :
11759 wxWindow( parent, wxID_ANY, wxPoint( 0, 0 ), wxSize( 1, 1 ), wxNO_BORDER )
11760 {
11761     m_pbm = NULL;
11762 
11763     m_timer_timeout.SetOwner( this, POPUP_TIMER );
11764     m_timeout_sec = timeout;
11765     isActive = false;
11766     Hide();
11767 }
11768 
11769 TimedPopupWin::~TimedPopupWin()
11770 {
11771     delete m_pbm;
11772 }
11773 void TimedPopupWin::OnTimer( wxTimerEvent& event )
11774 {
11775     if( IsShown() )
11776         Hide();
11777 }
11778 
11779 
11780 void TimedPopupWin::SetBitmap( wxBitmap &bmp )
11781 {
11782     delete m_pbm;
11783     m_pbm = new wxBitmap( bmp );
11784 
11785     // Retrigger the auto timeout
11786     if( m_timeout_sec > 0 )
11787         m_timer_timeout.Start( m_timeout_sec * 1000, wxTIMER_ONE_SHOT );
11788 }
11789 
11790 void TimedPopupWin::OnPaint( wxPaintEvent& event )
11791 {
11792     int width, height;
11793     GetClientSize( &width, &height );
11794     wxPaintDC dc( this );
11795 
11796     wxMemoryDC mdc;
11797     mdc.SelectObject( *m_pbm );
11798     dc.Blit( 0, 0, width, height, &mdc, 0, 0 );
11799 
11800 }
11801 
11802 
11803 //      Console supporting printf functionality for Windows GUI app
11804 
11805 #ifdef __WXMSW__
11806 static const WORD MAX_CONSOLE_LINES = 500;  // maximum mumber of lines the output console should have
11807 
11808 //#ifdef _DEBUG
11809 
11810 void RedirectIOToConsole()
11811 
11812 {
11813 
11814     int hConHandle;
11815 
11816     wxIntPtr lStdHandle;
11817 
11818     CONSOLE_SCREEN_BUFFER_INFO coninfo;
11819 
11820     FILE *fp;
11821 
11822     // allocate a console for this app
11823 
11824     AllocConsole();
11825 
11826     // set the screen buffer to be big enough to let us scroll text
11827 
11828     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
11829     coninfo.dwSize.Y = MAX_CONSOLE_LINES;
11830     SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coninfo.dwSize);
11831 
11832     // redirect unbuffered STDOUT to the console
11833 
11834     lStdHandle = (wxIntPtr)GetStdHandle(STD_OUTPUT_HANDLE);
11835     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
11836     fp = _fdopen( hConHandle, "w" );
11837     *stdout = *fp;
11838     setvbuf( stdout, NULL, _IONBF, 0 );
11839 
11840 
11841     // redirect unbuffered STDIN to the console
11842 
11843     lStdHandle = (wxIntPtr)GetStdHandle(STD_INPUT_HANDLE);
11844     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
11845     fp = _fdopen( hConHandle, "r" );
11846     *stdin = *fp;
11847     setvbuf( stdin, NULL, _IONBF, 0 );
11848 
11849     // redirect unbuffered STDERR to the console
11850 
11851     lStdHandle = (wxIntPtr)GetStdHandle(STD_ERROR_HANDLE);
11852     hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
11853     fp = _fdopen( hConHandle, "w" );
11854     *stderr = *fp;
11855     setvbuf( stderr, NULL, _IONBF, 0 );
11856 
11857     // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
11858 
11859     //ios::sync_with_stdio();
11860 
11861 }
11862 
11863 //#endif
11864 #endif
11865 
11866 
11867 #ifdef __WXMSW__
11868 bool TestGLCanvas(wxString prog_dir)
11869 {
11870 #ifdef __MSVC__
11871     wxString test_app = prog_dir;
11872     test_app += _T("ocpn_gltest1.exe");
11873 
11874     if(::wxFileExists(test_app)){
11875         long proc_return = ::wxExecute(test_app, wxEXEC_SYNC);
11876         printf("OpenGL Test Process returned %0X\n", proc_return);
11877         if(proc_return == 0)
11878             printf("GLCanvas OK\n");
11879         else
11880             printf("GLCanvas failed to start, disabling OpenGL.\n");
11881 
11882         return (proc_return == 0);
11883     }
11884     else
11885         return true;
11886 #else
11887     /* until we can get the source to ocpn_gltest1 assume true for mingw */
11888     return true;
11889 #endif
11890 }
11891 #endif
11892 
11893 
11894 
11895 wxFont *GetOCPNScaledFont( wxString item, int default_size )
11896 {
11897     wxFont *dFont = FontMgr::Get().GetFont( item, default_size );
11898     int req_size = dFont->GetPointSize();
11899 
11900     if( g_bresponsive ){
11901         //      Adjust font size to be no smaller than xx mm actual size
11902         double scaled_font_size = dFont->GetPointSize();
11903 
11904         {
11905 
11906             double points_per_mm  = g_Platform->getFontPointsperPixel() * g_Platform->GetDisplayDPmm();
11907             double min_scaled_font_size = 3 * points_per_mm;    // smaller than 3 mm is unreadable
11908             int nscaled_font_size = wxMax( wxRound(scaled_font_size), min_scaled_font_size );
11909 
11910             if(req_size >= nscaled_font_size)
11911                 return dFont;
11912             else{
11913                 wxFont *qFont = FontMgr::Get().FindOrCreateFont( nscaled_font_size,
11914                                                              dFont->GetFamily(),
11915                                                              dFont->GetStyle(),
11916                                                              dFont->GetWeight());
11917                 return qFont;
11918             }
11919         }
11920     }
11921     return dFont;
11922 }
11923 
11924 wxFont GetOCPNGUIScaledFont( wxString item )
11925 {
11926     wxFont *dFont = FontMgr::Get().GetFont( item, 0 );
11927     int req_size = dFont->GetPointSize();
11928     wxFont qFont = *dFont;
11929 
11930     if( g_bresponsive ){
11931        double postmult =  exp( g_GUIScaleFactor * (0.693 / 5.0) );       //  exp(2)
11932        double scaled_font_size = dFont->GetPointSize() * postmult;
11933 
11934        double points_per_mm  = g_Platform->getFontPointsperPixel() * g_Platform->GetDisplayDPmm();
11935        double min_scaled_font_size = 3 * points_per_mm;    // smaller than 3 mm is unreadable
11936        int nscaled_font_size = wxMax( wxRound(scaled_font_size), min_scaled_font_size );
11937 
11938 //        wxFont *qFont = wxTheFontList->FindOrCreateFont( nscaled_font_size,
11939 //                                                                  dFont->GetFamily(),
11940 //                                                                  dFont->GetStyle(),
11941 //                                                                  dFont->GetWeight());
11942        qFont.SetPointSize(nscaled_font_size);
11943     }
11944 
11945     return qFont;
11946 }
11947 
11948 OCPN_ThreadMessageEvent::OCPN_ThreadMessageEvent(wxEventType commandType, int id)
11949 :wxEvent(id, commandType)
11950 {
11951 }
11952 
11953 OCPN_ThreadMessageEvent::~OCPN_ThreadMessageEvent()
11954 {
11955 }
11956 
11957 wxEvent* OCPN_ThreadMessageEvent::Clone() const
11958 {
11959     OCPN_ThreadMessageEvent *newevent=new OCPN_ThreadMessageEvent(*this);
11960     newevent->m_string=this->m_string;
11961     return newevent;
11962 }
11963 
11964 
11965 
11966 
11967 #if 0
11968 /*************************************************************************
11969  * Serial port enumeration routines
11970  *
11971  * The EnumSerialPort function will populate an array of SSerInfo structs,
11972  * each of which contains information about one serial port present in
11973  * the system. Note that this code must be linked with setupapi.lib,
11974  * which is included with the Win32 SDK.
11975  *
11976  * by Zach Gorman <gormanjz@hotmail.com>
11977  *
11978  * Copyright (c) 2002 Archetype Auction Software, Inc. All rights reserved.
11979  *
11980  * Redistribution and use in source and binary forms, with or without
11981  * modification, are permitted provided that the following condition is
11982  * met: Redistributions of source code must retain the above copyright
11983  * notice, this condition and the following disclaimer.
11984  *
11985  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
11986  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
11987  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11988  * DISCLAIMED. IN NO EVENT SHALL ARCHETYPE AUCTION SOFTWARE OR ITS
11989  * AFFILIATES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
11990  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
11991  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
11992  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
11993  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
11994  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
11995  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11996  ************************************************************************/
11997 
11998 // For MFC
11999 #include <stdafx.h>
12000 
12001 // The next 3 includes are needed for serial port enumeration
12002 #include <objbase.h>
12003 #include <initguid.h>
12004 #include <Setupapi.h>
12005 
12006 #include "EnumSerial.h"
12007 
12008 // The following define is from ntddser.h in the DDK. It is also
12009 // needed for serial port enumeration.
12010 #ifndef GUID_CLASS_COMPORT
12011 DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, \
12012 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
12013 #endif
12014 
12015 
12016 struct SSerInfo {
12017     SSerInfo() : bUsbDevice(FALSE) {}
12018     CString strDevPath;          // Device path for use with CreateFile()
12019     CString strPortName;         // Simple name (i.e. COM1)
12020     CString strFriendlyName;     // Full name to be displayed to a user
12021     BOOL bUsbDevice;             // Provided through a USB connection?
12022     CString strPortDesc;         // friendly name without the COMx
12023 };
12024 
12025 //---------------------------------------------------------------
12026 // Helpers for enumerating the available serial ports.
12027 // These throw a CString on failure, describing the nature of
12028 // the error that occurred.
12029 
12030 void EnumPortsWdm(CArray<SSerInfo,SSerInfo&> &asi);
12031 void EnumPortsWNt4(CArray<SSerInfo,SSerInfo&> &asi);
12032 void EnumPortsW9x(CArray<SSerInfo,SSerInfo&> &asi);
12033 void SearchPnpKeyW9x(HKEY hkPnp, BOOL bUsbDevice,
12034                      CArray<SSerInfo,SSerInfo&> &asi);
12035 
12036 
12037 //---------------------------------------------------------------
12038 // Routine for enumerating the available serial ports.
12039 // Throws a CString on failure, describing the error that
12040 // occurred. If bIgnoreBusyPorts is TRUE, ports that can't
12041 // be opened for read/write access are not included.
12042 
12043 void EnumSerialPorts(CArray<SSerInfo,SSerInfo&> &asi, BOOL bIgnoreBusyPorts)
12044 {
12045     // Clear the output array
12046     asi.RemoveAll();
12047 
12048     // Use different techniques to enumerate the available serial
12049     // ports, depending on the OS we're using
12050     OSVERSIONINFO vi;
12051     vi.dwOSVersionInfoSize = sizeof(vi);
12052     if (!::GetVersionEx(&vi)) {
12053         CString str;
12054         str.Format("Could not get OS version. (err=%lx)",
12055                    GetLastError());
12056         throw str;
12057     }
12058     // Handle windows 9x and NT4 specially
12059     if (vi.dwMajorVersion < 5) {
12060         if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT)
12061             EnumPortsWNt4(asi);
12062         else
12063             EnumPortsW9x(asi);
12064     }
12065     else {
12066         // Win2k and later support a standard API for
12067         // enumerating hardware devices.
12068         EnumPortsWdm(asi);
12069     }
12070 
12071     for (int ii=0; ii<asi.GetSize(); ii++)
12072     {
12073         SSerInfo& rsi = asi[ii];
12074         if (bIgnoreBusyPorts) {
12075             // Only display ports that can be opened for read/write
12076             HANDLE hCom = CreateFile(rsi.strDevPath,
12077                                      GENERIC_READ | GENERIC_WRITE,
12078                                      0,    /* comm devices must be opened w/exclusive-access */
12079                                      NULL, /* no security attrs */
12080                                      OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */
12081                                      0,    /* not overlapped I/O */
12082                                      NULL  /* hTemplate must be NULL for comm devices */
12083             );
12084             if (hCom == INVALID_HANDLE_VALUE) {
12085                 // It can't be opened; remove it.
12086                 asi.RemoveAt(ii);
12087                 ii--;
12088                 continue;
12089             }
12090             else {
12091                 // It can be opened! Close it and add it to the list
12092                 ::CloseHandle(hCom);
12093             }
12094         }
12095 
12096         // Come up with a name for the device.
12097         // If there is no friendly name, use the port name.
12098         if (rsi.strFriendlyName.IsEmpty())
12099             rsi.strFriendlyName = rsi.strPortName;
12100 
12101         // If there is no description, try to make one up from
12102             // the friendly name.
12103             if (rsi.strPortDesc.IsEmpty()) {
12104                 // If the port name is of the form "ACME Port (COM3)"
12105                 // then strip off the " (COM3)"
12106                 rsi.strPortDesc = rsi.strFriendlyName;
12107                 int startdex = rsi.strPortDesc.Find(" (");
12108                 int enddex = rsi.strPortDesc.Find(")");
12109                 if (startdex > 0 && enddex ==
12110                     (rsi.strPortDesc.GetLength()-1))
12111                     rsi.strPortDesc = rsi.strPortDesc.Left(startdex);
12112             }
12113     }
12114 }
12115 
12116 // Helpers for EnumSerialPorts
12117 
12118 void EnumPortsWdm(CArray<SSerInfo,SSerInfo&> &asi)
12119 {
12120     CString strErr;
12121     // Create a device information set that will be the container for
12122     // the device interfaces.
12123     GUID *guidDev = (GUID*) &GUID_CLASS_COMPORT;
12124 
12125     HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
12126     SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL;
12127 
12128     try {
12129         hDevInfo = SetupDiGetClassDevs( guidDev,
12130                                         NULL,
12131                                         NULL,
12132                                         DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
12133         );
12134 
12135         if(hDevInfo == INVALID_HANDLE_VALUE)
12136         {
12137             strErr.Format("SetupDiGetClassDevs failed. (err=%lx)",
12138                           GetLastError());
12139             throw strErr;
12140         }
12141 
12142         // Enumerate the serial ports
12143         BOOL bOk = TRUE;
12144         SP_DEVICE_INTERFACE_DATA ifcData;
12145         DWORD dwDetDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + 256;
12146         pDetData = (SP_DEVICE_INTERFACE_DETAIL_DATA*) new char[dwDetDataSize];
12147         // This is required, according to the documentation. Yes,
12148         // it's weird.
12149         ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
12150         pDetData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
12151         for (DWORD ii=0; bOk; ii++) {
12152             bOk = SetupDiEnumDeviceInterfaces(hDevInfo,
12153                                               NULL, guidDev, ii, &ifcData);
12154             if (bOk) {
12155                 // Got a device. Get the details.
12156                 SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)};
12157                 bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo,
12158                                                       &ifcData, pDetData, dwDetDataSize, NULL, &devdata);
12159                 if (bOk) {
12160                     CString strDevPath(pDetData->DevicePath);
12161                     // Got a path to the device. Try to get some more info.
12162                     TCHAR fname[256];
12163                     TCHAR desc[256];
12164                     BOOL bSuccess = SetupDiGetDeviceRegistryProperty(
12165                         hDevInfo, &devdata, SPDRP_FRIENDLYNAME, NULL,
12166                         (PBYTE)fname, sizeof(fname), NULL);
12167                     bSuccess = bSuccess && SetupDiGetDeviceRegistryProperty(
12168                         hDevInfo, &devdata, SPDRP_DEVICEDESC, NULL,
12169                         (PBYTE)desc, sizeof(desc), NULL);
12170                     BOOL bUsbDevice = FALSE;
12171                     TCHAR locinfo[256];
12172                     if (SetupDiGetDeviceRegistryProperty(
12173                         hDevInfo, &devdata, SPDRP_LOCATION_INFORMATION, NULL,
12174                         (PBYTE)locinfo, sizeof(locinfo), NULL))
12175                     {
12176                         // Just check the first three characters to determine
12177                         // if the port is connected to the USB bus. This isn't
12178                         // an infallible method; it would be better to use the
12179                         // BUS GUID. Currently, Windows doesn't let you query
12180                         // that though (SPDRP_BUSTYPEGUID seems to exist in
12181                         // documentation only).
12182                         bUsbDevice = (strncmp(locinfo, "USB", 3)==0);
12183                     }
12184                     if (bSuccess) {
12185                         // Add an entry to the array
12186                         SSerInfo si;
12187                         si.strDevPath = strDevPath;
12188                         si.strFriendlyName = fname;
12189                         si.strPortDesc = desc;
12190                         si.bUsbDevice = bUsbDevice;
12191                         asi.Add(si);
12192                     }
12193 
12194                 }
12195                 else {
12196                     strErr.Format("SetupDiGetDeviceInterfaceDetail failed. (err=%lx)",
12197                                   GetLastError());
12198                     throw strErr;
12199                 }
12200             }
12201             else {
12202                 DWORD err = GetLastError();
12203                 if (err != ERROR_NO_MORE_ITEMS) {
12204                     strErr.Format("SetupDiEnumDeviceInterfaces failed. (err=%lx)", err);
12205                     throw strErr;
12206                 }
12207             }
12208         }
12209     }
12210     catch (CString strCatchErr) {
12211         strErr = strCatchErr;
12212     }
12213 
12214     if (pDetData != NULL)
12215         delete [] (char*)pDetData;
12216     if (hDevInfo != INVALID_HANDLE_VALUE)
12217         SetupDiDestroyDeviceInfoList(hDevInfo);
12218 
12219     if (!strErr.IsEmpty())
12220         throw strErr;
12221 }
12222 
12223 void EnumPortsWNt4(CArray<SSerInfo,SSerInfo&> &asi)
12224 {
12225     // NT4's driver model is totally different, and not that
12226     // many people use NT4 anymore. Just try all the COM ports
12227     // between 1 and 16
12228     SSerInfo si;
12229     for (int ii=1; ii<=16; ii++) {
12230         CString strPort;
12231         strPort.Format("COM%d",ii);
12232         si.strDevPath = CString("\\\\.\\") + strPort;
12233         si.strPortName = strPort;
12234         asi.Add(si);
12235     }
12236 }
12237 
12238 void EnumPortsW9x(CArray<SSerInfo,SSerInfo&> &asi)
12239 {
12240     // Look at all keys in HKLM\Enum, searching for subkeys named
12241     // *PNP0500 and *PNP0501. Within these subkeys, search for
12242     // sub-subkeys containing value entries with the name "PORTNAME"
12243     // Search all subkeys of HKLM\Enum\USBPORTS for PORTNAME entries.
12244 
12245     // First, open HKLM\Enum
12246     HKEY hkEnum = NULL;
12247     HKEY hkSubEnum = NULL;
12248     HKEY hkSubSubEnum = NULL;
12249 
12250     try {
12251         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Enum", 0, KEY_READ,
12252             &hkEnum) != ERROR_SUCCESS)
12253             throw CString("Could not read from HKLM\\Enum");
12254 
12255         // Enumerate the subkeys of HKLM\Enum
12256             char acSubEnum[128];
12257             DWORD dwSubEnumIndex = 0;
12258             DWORD dwSize = sizeof(acSubEnum);
12259             while (RegEnumKeyEx(hkEnum, dwSubEnumIndex++, acSubEnum, &dwSize,
12260                 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
12261             {
12262                 HKEY hkSubEnum = NULL;
12263                 if (RegOpenKeyEx(hkEnum, acSubEnum, 0, KEY_READ,
12264                     &hkSubEnum) != ERROR_SUCCESS)
12265                     throw CString("Could not read from HKLM\\Enum\\")+acSubEnum;
12266 
12267                 // Enumerate the subkeys of HKLM\Enum\*\, looking for keys
12268                     // named *PNP0500 and *PNP0501 (or anything in USBPORTS)
12269                     BOOL bUsbDevice = (strcmp(acSubEnum,"USBPORTS")==0);
12270                     char acSubSubEnum[128];
12271                     dwSize = sizeof(acSubSubEnum);  // set the buffer size
12272                     DWORD dwSubSubEnumIndex = 0;
12273                     while (RegEnumKeyEx(hkSubEnum, dwSubSubEnumIndex++, acSubSubEnum,
12274                         &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
12275                     {
12276                         BOOL bMatch = (strcmp(acSubSubEnum,"*PNP0500")==0 ||
12277                         strcmp(acSubSubEnum,"*PNP0501")==0 ||
12278                         bUsbDevice);
12279                         if (bMatch) {
12280                             HKEY hkSubSubEnum = NULL;
12281                             if (RegOpenKeyEx(hkSubEnum, acSubSubEnum, 0, KEY_READ,
12282                                 &hkSubSubEnum) != ERROR_SUCCESS)
12283                                 throw CString("Could not read from HKLM\\Enum\\") +
12284                                 acSubEnum + "\\" + acSubSubEnum;
12285                             SearchPnpKeyW9x(hkSubSubEnum, bUsbDevice, asi);
12286                             RegCloseKey(hkSubSubEnum);
12287                             hkSubSubEnum = NULL;
12288                         }
12289 
12290                         dwSize = sizeof(acSubSubEnum);  // restore the buffer size
12291                     }
12292 
12293                     RegCloseKey(hkSubEnum);
12294                     hkSubEnum = NULL;
12295                     dwSize = sizeof(acSubEnum); // restore the buffer size
12296             }
12297     }
12298     catch (CString strError) {
12299         if (hkEnum != NULL)
12300             RegCloseKey(hkEnum);
12301         if (hkSubEnum != NULL)
12302             RegCloseKey(hkSubEnum);
12303         if (hkSubSubEnum != NULL)
12304             RegCloseKey(hkSubSubEnum);
12305         throw strError;
12306     }
12307 
12308     RegCloseKey(hkEnum);
12309 }
12310 
12311 void SearchPnpKeyW9x(HKEY hkPnp, BOOL bUsbDevice,
12312                      CArray<SSerInfo,SSerInfo&> &asi)
12313 {
12314     // Enumerate the subkeys of the given PNP key, looking for values with
12315     // the name "PORTNAME"
12316     // First, open HKLM\Enum
12317     HKEY hkSubPnp = NULL;
12318 
12319     try {
12320         // Enumerate the subkeys of HKLM\Enum\*\PNP050[01]
12321         char acSubPnp[128];
12322         DWORD dwSubPnpIndex = 0;
12323         DWORD dwSize = sizeof(acSubPnp);
12324         while (RegEnumKeyEx(hkPnp, dwSubPnpIndex++, acSubPnp, &dwSize,
12325             NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
12326         {
12327             HKEY hkSubPnp = NULL;
12328             if (RegOpenKeyEx(hkPnp, acSubPnp, 0, KEY_READ,
12329                 &hkSubPnp) != ERROR_SUCCESS)
12330                 throw CString("Could not read from HKLM\\Enum\\...\\")
12331                 + acSubPnp;
12332 
12333             // Look for the PORTNAME value
12334                 char acValue[128];
12335                 dwSize = sizeof(acValue);
12336                 if (RegQueryValueEx(hkSubPnp, "PORTNAME", NULL, NULL, (BYTE*)acValue,
12337                     &dwSize) == ERROR_SUCCESS)
12338                 {
12339                     CString strPortName(acValue);
12340 
12341                     // Got the portname value. Look for a friendly name.
12342                     CString strFriendlyName;
12343                     dwSize = sizeof(acValue);
12344                     if (RegQueryValueEx(hkSubPnp, "FRIENDLYNAME", NULL, NULL, (BYTE*)acValue,
12345                         &dwSize) == ERROR_SUCCESS)
12346                         strFriendlyName = acValue;
12347 
12348                     // Prepare an entry for the output array.
12349                         SSerInfo si;
12350                         si.strDevPath = CString("\\\\.\\") + strPortName;
12351                         si.strPortName = strPortName;
12352                         si.strFriendlyName = strFriendlyName;
12353                         si.bUsbDevice = bUsbDevice;
12354 
12355                         // Overwrite duplicates.
12356                         BOOL bDup = FALSE;
12357                         for (int ii=0; ii<asi.GetSize() && !bDup; ii++)
12358                         {
12359                             if (asi[ii].strPortName == strPortName) {
12360                                 bDup = TRUE;
12361                                 asi[ii] = si;
12362                             }
12363                         }
12364                         if (!bDup) {
12365                             // Add an entry to the array
12366                             asi.Add(si);
12367                         }
12368                 }
12369 
12370                 RegCloseKey(hkSubPnp);
12371                 hkSubPnp = NULL;
12372                 dwSize = sizeof(acSubPnp);  // restore the buffer size
12373         }
12374     }
12375     catch (CString strError) {
12376         if (hkSubPnp != NULL)
12377             RegCloseKey(hkSubPnp);
12378         throw strError;
12379     }
12380 }
12381 
12382 #endif
12383 
12384 
12385 bool ReloadLocale()
12386 {
12387     bool ret = false;
12388 
12389 #if wxUSE_XLOCALE
12390     ret = (!g_Platform->ChangeLocale( g_locale, plocale_def_lang, &plocale_def_lang ).IsEmpty());
12391 #endif
12392     return ret;
12393 }
12394 
12395 
12396 void ApplyLocale()
12397 {
12398     FontMgr::Get().SetLocale( g_locale );
12399     FontMgr::Get().ScrubList();
12400 
12401     //  Close and re-init various objects to allow new locale to show.
12402     delete g_options;
12403     g_options = NULL;
12404     g_pOptions = NULL;
12405 
12406 
12407     if( pRoutePropDialog ) {
12408         pRoutePropDialog->Hide();
12409         pRoutePropDialog->Destroy();
12410         pRoutePropDialog = NULL;
12411     }
12412 
12413     if( pRouteManagerDialog ) {
12414         pRouteManagerDialog->Hide();
12415         pRouteManagerDialog->Destroy();
12416         pRouteManagerDialog = NULL;
12417     }
12418 
12419     if(console)
12420         console->SetColorScheme( global_color_scheme );
12421 
12422     if( g_pais_query_dialog_active ){
12423         g_pais_query_dialog_active->Destroy();
12424         g_pais_query_dialog_active = NULL;
12425     }
12426 
12427     if( g_pais_alert_dialog_active ){
12428         g_pais_alert_dialog_active->Destroy();
12429         g_pais_alert_dialog_active = NULL;
12430     }
12431 
12432 
12433     if( g_pAISTargetList ) {
12434         if(g_pauimgr) g_pauimgr->DetachPane(g_pAISTargetList);
12435         g_pAISTargetList->Disconnect_decoder();
12436         g_pAISTargetList->Destroy();
12437         g_pAISTargetList = NULL;
12438     }
12439 
12440     //  Process the menubar, if present.
12441     if ( gFrame->m_pMenuBar ) {     // remove the menu bar if it is presently enabled
12442             gFrame->SetMenuBar( NULL );
12443             gFrame->m_pMenuBar->Destroy();
12444             gFrame->m_pMenuBar = NULL;
12445     }
12446     gFrame->BuildMenuBar();
12447 
12448     //  Give all canvas a chance to update, if needed
12449     for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
12450         ChartCanvas *cc = g_canvasArray.Item(i);
12451         if(cc)
12452             cc->CanvasApplyLocale();
12453     }
12454 
12455     // Capture a copy of the current perspective
12456     //  So that we may restore PlugIn window sizes, position, visibility, etc.
12457     wxString perspective;
12458     pConfig->SetPath( _T ( "/AUI" ) );
12459     pConfig->Read( _T ( "AUIPerspective" ), &perspective );
12460 
12461     //  Compliant Plugins will reload their locale message catalog during the Init() method.
12462     //  So it is sufficient to simply deactivate, and then re-activate, all "active" plugins.
12463     g_pi_manager->DeactivateAllPlugIns();
12464     g_pi_manager->UpdatePlugIns();
12465 
12466 
12467     //         // Make sure the perspective saved in the config file is "reasonable"
12468     //         // In particular, the perspective should have an entry for every
12469     //         // windows added to the AUI manager so far.
12470     //         // If any are not found, then use the default layout
12471     //
12472     bool bno_load = false;
12473     wxAuiPaneInfoArray pane_array_val = g_pauimgr->GetAllPanes();
12474 
12475     for( unsigned int i = 0; i < pane_array_val.GetCount(); i++ ) {
12476         wxAuiPaneInfo pane = pane_array_val[i];
12477         if( perspective.Find( pane.name ) == wxNOT_FOUND ) {
12478             bno_load = true;
12479             break;
12480         }
12481     }
12482 
12483      if( !bno_load )
12484          g_pauimgr->LoadPerspective( perspective, false );
12485 
12486     g_pauimgr->Update();
12487 
12488     if(gFrame){
12489         gFrame->RequestNewToolbars( true );
12490         gFrame->RequestNewMasterToolbar( true );
12491     }
12492 }
12493 
12494 
12495 BEGIN_EVENT_TABLE(OCPN_TimedHTMLMessageDialog, wxDialog)
12496 EVT_BUTTON(wxID_YES, OCPN_TimedHTMLMessageDialog::OnYes)
12497 EVT_BUTTON(wxID_NO, OCPN_TimedHTMLMessageDialog::OnNo)
12498 EVT_BUTTON(wxID_CANCEL, OCPN_TimedHTMLMessageDialog::OnCancel)
12499 EVT_CLOSE(OCPN_TimedHTMLMessageDialog::OnClose)
12500 EVT_TIMER(-1, OCPN_TimedHTMLMessageDialog::OnTimer)
12501 
12502 END_EVENT_TABLE()
12503 
12504 
12505 OCPN_TimedHTMLMessageDialog::OCPN_TimedHTMLMessageDialog( wxWindow *parent,
12506                                                     const wxString& message,
12507                                                     const wxString& caption,
12508                                                     int tSeconds,
12509                                                     long style,
12510                                                     bool bFixedFont,
12511                                                     const wxPoint& pos)
12512 : wxDialog( parent, wxID_ANY, caption, pos, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP )
12513 {
12514     m_style = style;
12515     if(bFixedFont){
12516         wxFont *dFont = GetOCPNScaledFont_PlugIn(_("Dialog"));
12517         double font_size = dFont->GetPointSize();
12518         wxFont *qFont = wxTheFontList->FindOrCreateFont( font_size,wxFONTFAMILY_TELETYPE, dFont->GetStyle(), dFont->GetWeight());
12519         SetFont( *qFont );
12520     }
12521 
12522     wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
12523 
12524     msgWindow = new wxHtmlWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
12525                                                 wxHW_SCROLLBAR_AUTO | wxHW_NO_SELECTION );
12526     msgWindow->SetBorders( 30 );
12527 
12528     topsizer->Add( msgWindow, 1, wxEXPAND, 5 );
12529 
12530     wxString html;
12531     html << message;
12532 
12533     wxCharBuffer buf = html.ToUTF8();
12534     if( buf.data() )                            // string OK?
12535        msgWindow->SetPage( html );
12536 
12537     // 3) buttons
12538        int AllButtonSizerFlags = wxOK|wxCANCEL|wxYES|wxNO|wxHELP|wxNO_DEFAULT;
12539        int center_flag = wxEXPAND;
12540        if (style & wxYES_NO)
12541            center_flag = wxALIGN_CENTRE;
12542        wxSizer *sizerBtn = CreateSeparatedButtonSizer(style & AllButtonSizerFlags);
12543        if ( sizerBtn )
12544            topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10 );
12545 
12546        SetSizer( topsizer );
12547 
12548        topsizer->Fit( this );
12549 
12550        RecalculateSize();
12551 //       wxSize szyv = msgWindow->GetVirtualSize();
12552 
12553 //       SetClientSize(szyv.x + 20, szyv.y + 20);
12554 
12555        CentreOnScreen();
12556 
12557        //msgWindow->SetBackgroundColour(wxColour(191, 183, 180));
12558        msgWindow->SetBackgroundColour(GetBackgroundColour());
12559 
12560        m_timer.SetOwner( this, -1 );
12561 
12562        if(tSeconds > 0)
12563            m_timer.Start( tSeconds * 1000, wxTIMER_ONE_SHOT );
12564 
12565 }
12566 
12567 void OCPN_TimedHTMLMessageDialog::RecalculateSize( void )
12568 {
12569     wxSize esize;
12570     esize.x = GetCharWidth() * 60;
12571     int sx, sy;
12572     ::wxDisplaySize(&sx, &sy);
12573     esize.x = wxMin(esize.x, sx * 6 / 10);
12574     esize.y = -1;
12575     SetClientSize(esize);     // This will force a recalc of internal representation
12576 
12577     int height1 = msgWindow->GetInternalRepresentation()->GetHeight();
12578 
12579     int client_size_y = wxMin(::wxGetDisplaySize().y - 100, height1 + 70);    // Must fit on screen
12580 
12581     SetClientSize(wxSize(esize.x, client_size_y ));   // constant is 2xBorders + a little slop.
12582 
12583 }
12584 
12585 void OCPN_TimedHTMLMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event))
12586 {
12587     SetReturnCode(wxID_YES);
12588     if(IsModal())
12589         EndModal( wxID_YES );
12590     else
12591         Hide();
12592 }
12593 
12594 void OCPN_TimedHTMLMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event))
12595 {
12596     SetReturnCode(wxID_NO);
12597     if(IsModal())
12598         EndModal( wxID_NO );
12599     else
12600         Hide();
12601 }
12602 
12603 void OCPN_TimedHTMLMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
12604 {
12605     // Allow cancellation via ESC/Close button except if
12606     // only YES and NO are specified.
12607     if ( (m_style & wxYES_NO) != wxYES_NO || (m_style & wxCANCEL) )
12608     {
12609         SetReturnCode(wxID_CANCEL);
12610         EndModal( wxID_CANCEL );
12611     }
12612 }
12613 
12614 void OCPN_TimedHTMLMessageDialog::OnClose( wxCloseEvent& event )
12615 {
12616     SetReturnCode(wxID_CANCEL);
12617     if(IsModal())
12618         EndModal( wxID_CANCEL );
12619     else
12620         Hide();
12621 }
12622 
12623 void OCPN_TimedHTMLMessageDialog::OnTimer(wxTimerEvent &evt)
12624 {
12625     if(IsModal())
12626         EndModal( m_style & wxNO_DEFAULT ? wxID_NO :  wxID_YES );
12627     else
12628         Hide();
12629 }
12630 
12631