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