OpenCPN Partial API docs
Loading...
Searching...
No Matches
OCPNPlatform.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: OpenCPN Platform specific support utilities
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2015 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
26#include <wx/wxprec.h>
27
28#ifdef __MINGW32__
29#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
30#include <windows.h>
31#endif
32
33#ifndef WX_PRECOMP
34#include <wx/wx.h>
35#endif // precompiled headers
36
37#include <wx/app.h>
38#include <wx/apptrait.h>
39#include <wx/stdpaths.h>
40#include <wx/filename.h>
41#include <wx/tokenzr.h>
42#include <wx/textfile.h>
43
44#include "config.h"
45
46#include "base_platform.h"
47//#include "dychart.h"
48#include "OCPNPlatform.h"
49#include "gui_lib.h"
50#include "cutil.h"
51#include "config_vars.h"
52#include "logger.h"
53#include "styles.h"
54#include "navutil.h"
55#include "ocpn_utils.h"
56#include "conn_params.h"
57#include "FontMgr.h"
58#include "s52s57.h"
59#include "options.h"
60#include "select.h"
61#include "AboutFrameImpl.h"
62#include "about.h"
63#include "plugin_paths.h"
64#include "ocpn_frame.h"
65#include <string>
66#include <vector>
67
68#ifdef __OCPN__ANDROID__
69#include "androidUTIL.h"
70#endif
71
72#ifdef ocpnUSE_GL
73#include "glChartCanvas.h"
74#endif
75
76// Include CrashRpt Header
77#ifdef OCPN_USE_CRASHREPORT
78#include "CrashRpt.h"
79#endif
80#ifdef __MSVC__
81#include <new.h>
82#endif
83
84#ifdef LINUX_CRASHRPT
85#include "crashprint.h"
86#endif
87
88#ifndef __WXMSW__
89#include <signal.h>
90#include <setjmp.h>
91#endif
92
93#ifdef __WXMSW__
94#include <windows.h>
95#include <winioctl.h>
96#include <initguid.h>
97#include "setupapi.h" // presently stored in opencpn/src
98#endif
99
100#ifdef __WXOSX__
101#include "macutils.h"
102#endif
103
104#ifdef __WXGTK__
105//#include <gdk/gdk.h>
106#endif
107
108#include <cstdlib>
109
110class MyApp;
111DECLARE_APP(MyApp)
112
113void appendOSDirSlash(wxString *pString);
114
115#ifndef __WXMSW__
116struct sigaction sa_all;
117struct sigaction sa_all_old;
118extern sigjmp_buf env; // the context saved by sigsetjmp();
119#endif
120
121extern OCPNPlatform *g_Platform;
122extern wxString g_winPluginDir;
123extern bool g_bFirstRun;
124extern bool g_bUpgradeInProcess;
125
126extern int quitflag;
127extern MyFrame *gFrame;
128extern bool g_bportable;
129
130extern MyConfig *pConfig;
131
132extern ocpnStyle::StyleManager *g_StyleManager;
133
134extern bool g_bshowToolbar;
135extern bool g_bexpert;
136extern bool g_bBasicMenus;
137extern bool g_bUIexpert;
138
139extern bool g_bshowToolbar;
140extern bool g_bBasicMenus;
141
142extern bool g_bShowOutlines;
143extern int g_nAWDefault;
144extern int g_nAWMax;
145extern bool g_bPermanentMOBIcon;
146extern float g_toolbar_scalefactor;
147
148extern options *g_options;
149extern bool g_boptionsactive;
150
151// AIS Global configuration
152extern double g_CPAMax_NM;
153extern double g_CPAWarn_NM;
154extern double g_TCPA_Max;
155extern bool g_bMarkLost;
156extern double g_MarkLost_Mins;
157extern bool g_bRemoveLost;
158extern double g_RemoveLost_Mins;
159extern bool g_bShowCOG;
160extern bool g_bSyncCogPredictors;
161extern double g_ShowCOG_Mins;
162extern bool g_bHideMoored;
163extern double g_ShowMoored_Kts;
164extern bool g_bShowAreaNotices;
165extern bool g_bDrawAISSize;
166extern bool g_bDrawAISRealtime;
167extern double g_AIS_RealtPred_Kts;
168extern bool g_bShowAISName;
169extern bool g_bAIS_GCPA_Alert_Audio;
170extern bool g_bAIS_SART_Alert_Audio;
171extern bool g_bAIS_DSC_Alert_Audio;
172extern bool g_bAIS_CPA_Alert_Audio;
173extern bool g_bCPAWarn;
174extern bool g_bAIS_CPA_Alert;
175
176extern wxString *pInit_Chart_Dir;
177
178extern double g_config_display_size_mm;
179extern bool g_config_display_size_manual;
180
181extern float g_selection_radius_mm;
182extern float g_selection_radius_touch_mm;
183
184extern bool g_bTrackDaily;
185extern double g_PlanSpeed;
186extern bool g_bFullScreenQuilt;
187extern bool g_bQuiltEnable;
188extern bool g_bskew_comp;
189
190extern bool g_bopengl;
191extern bool g_btouch;
192extern bool g_bresponsive;
193extern bool g_bShowStatusBar;
194extern int g_cm93_zoom_factor;
195extern int g_GUIScaleFactor;
196extern bool g_fog_overzoom;
197extern bool g_oz_vector_scale;
198extern int g_nTrackPrecision;
199extern wxString g_toolbarConfig;
200extern bool g_bPreserveScaleOnX;
201extern bool g_running;
202
203extern Select *pSelect;
204extern Select *pSelectTC;
205extern Select *pSelectAIS;
206
207extern Select *pSelect;
208extern Select *pSelectTC;
209extern Select *pSelectAIS;
210
211extern Select *pSelect;
212extern Select *pSelectTC;
213extern Select *pSelectAIS;
214
215#ifdef ocpnUSE_GL
216extern ocpnGLOptions g_GLOptions;
217#endif
218extern int g_default_font_size;
219extern wxString g_default_font_facename;
220
221wxLog *g_logger;
222bool g_bEmailCrashReport;
223extern int g_ais_alert_dialog_x, g_ais_alert_dialog_y;
224extern int g_ais_alert_dialog_sx, g_ais_alert_dialog_sy;
225
226extern double g_ChartNotRenderScaleFactor;
227extern bool g_bRollover;
228
229#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
230extern wxLocale *plocale_def_lang;
231
232extern wxString g_locale;
233extern wxString g_localeOverride;
234extern wxArrayString g_locale_catalog_array;
235
236#endif
237extern int options_lastPage;
238extern AboutFrameImpl *g_pAboutDlg;
239extern about *g_pAboutDlgLegacy;
240extern wxColour g_colourTrackLineColour;
241extern int g_n_ownship_min_mm;
242
243extern int g_AndroidVersionCode;
244extern bool g_bShowMuiZoomButtons;
245extern int g_FlushNavobjChangesTimeout;
246extern wxString g_CmdSoundString;
247extern int g_maintoolbar_x;
248extern int g_maintoolbar_y;
249extern wxArrayString TideCurrentDataSet;
250extern int g_Android_SDK_Version;
251extern wxString g_androidDownloadDirectory;
252extern wxString g_gpx_path;
253extern BasePlatform *g_BasePlatform;
254
255#ifdef __ANDROID__
256extern PlatSpec android_plat_spc;
257#endif
258
259OCPN_GLCaps *GL_Caps;
260
261static const char *const DEFAULT_XDG_DATA_DIRS =
262 "~/.local/share:/usr/local/share:/usr/share";
263
264#ifdef __WXMSW__
265static const char PATH_SEP = ';';
266#else
267static const char PATH_SEP = ':';
268#endif
269
270static bool checkIfFlatpacked() {
271 wxString id;
272 if (!wxGetEnv("FLATPAK_ID", &id)) {
273 return false;
274 }
275 return id == "org.opencpn.OpenCPN";
276}
277
278
279OCPNPlatform::OCPNPlatform() {
280 m_pt_per_pixel = 0; // cached value
281 m_bdisableWindowsDisplayEnum = false;
282 m_displaySize = wxSize(0, 0);
283 m_displaySizeMM = wxSize(0, 0);
284 m_monitorWidth = m_monitorHeight = 0;
285 m_displaySizeMMOverride = 0;
286 m_pluginDataPath = "";
287}
288
289OCPNPlatform::~OCPNPlatform() {}
290
291//--------------------------------------------------------------------------
292// Per-Platform Initialization support
293//--------------------------------------------------------------------------
294#ifdef __WXMSW__
295int MyNewHandler(size_t size) {
296 // Pass to wxWidgets Main Loop handler
297 throw std::bad_alloc();
298
299 return 0;
300}
301#endif
302
303//-----------------------------------------------------------------------
304// Signal Handlers
305//-----------------------------------------------------------------------
306#ifndef __WXMSW__
307
308// These are the signals possibly expected
309// SIGUSR1
310// Raised externally to cause orderly termination of application
311// Intended to act just like pushing the "EXIT" button
312
313// SIGSEGV
314// Some undefined segfault......
315
316int s_inhup;
317
318void catch_signals(int signo) {
319 switch (signo) {
320 case SIGUSR1:
321 quitflag++; // signal to the timer loop
322 break;
323
324 case SIGSEGV:
325 siglongjmp(env, 1); // jump back to the setjmp() point
326 break;
327
328 case SIGHUP:
329 if (!s_inhup) {
330 s_inhup++; // incase SIGHUP is closely followed by SIGTERM
331 gFrame->FastClose();
332 }
333 break;
334
335 case SIGTERM:
336 if (!s_inhup) {
337 s_inhup++; // incase SIGHUP is closely followed by SIGTERM
338 gFrame->FastClose();
339 }
340
341 break;
342
343 default:
344 break;
345 }
346}
347#endif
348
349#ifdef OCPN_USE_CRASHREPORT
350// Define the crash callback
351int CALLBACK CrashCallback(CR_CRASH_CALLBACK_INFO *pInfo) {
352 // Flush log file
353 if (g_logger) g_logger->Flush();
354
355 return CR_CB_DODEFAULT;
356}
357#endif
358
359// Called from MyApp() immediately upon entry to MyApp::OnInit()
360void OCPNPlatform::Initialize_1(void) {
361#ifdef OCPN_USE_CRASHREPORT
362#ifndef _DEBUG
363 // Install Windows crash reporting
364
365 CR_INSTALL_INFO info;
366 memset(&info, 0, sizeof(CR_INSTALL_INFO));
367 info.cb = sizeof(CR_INSTALL_INFO);
368 info.pszAppName = _T("OpenCPN");
369
370 info.pszAppVersion = wxString(VERSION_FULL).c_str();
371
372 int type = MiniDumpNormal;
373
374 // This results in the inclusion of global variables
375 type |= MiniDumpWithDataSegs;
376
377 // If this flag is specified, the contents of every readable and writeable
378 // private memory page will be included into the minidump. type |=
379 // MiniDumpWithPrivateReadWriteMemory;
380
381 // If this flag is specified, MiniDumpWriteDump function will scan the stack
382 // memory of every thread looking for pointers that point to other readable
383 // memory pages in the process' address space. type |=
384 // MiniDumpWithIndirectlyReferencedMemory;
385
386 info.uMiniDumpType = (MINIDUMP_TYPE)type;
387
388 // Install all available exception handlers....
389 info.dwFlags = CR_INST_ALL_POSSIBLE_HANDLERS;
390
391 // Except memory allocation failures
392 info.dwFlags &= ~CR_INST_NEW_OPERATOR_ERROR_HANDLER;
393
394 // Allow user to attach files
395 info.dwFlags |= CR_INST_ALLOW_ATTACH_MORE_FILES;
396
397 // Allow user to add more info
398 info.dwFlags |= CR_INST_SHOW_ADDITIONAL_INFO_FIELDS;
399
400 // URL for sending error reports over HTTP.
401
402 if (g_bEmailCrashReport) {
403 info.pszUrl = _T("https://bigdumboat.com/crashrpt/ocpn_crashrpt.php");
404 info.uPriorities[CR_HTTP] = 3; // First try send report over HTTP
405 } else {
406 info.dwFlags |= CR_INST_DONT_SEND_REPORT;
407 info.uPriorities[CR_HTTP] = CR_NEGATIVE_PRIORITY; // don't send at all
408 }
409
410 info.uPriorities[CR_SMTP] =
411 CR_NEGATIVE_PRIORITY; // Second try send report over SMTP
412 info.uPriorities[CR_SMAPI] =
413 CR_NEGATIVE_PRIORITY; // Third try send report over Simple MAPI
414
415 wxStandardPaths &crash_std_path = g_Platform->GetStdPaths();
416
417 wxString crash_rpt_save_locn = crash_std_path.GetConfigDir();
418 if (g_bportable) {
419 wxFileName exec_path_crash(crash_std_path.GetExecutablePath());
420 crash_rpt_save_locn =
421 exec_path_crash.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
422 }
423
424 wxString locn = crash_rpt_save_locn + _T("\\CrashReports");
425
426 if (!wxDirExists(locn)) wxMkdir(locn);
427
428 if (wxDirExists(locn)) {
429 wxCharBuffer buf = locn.ToUTF8();
430 wchar_t wlocn[256];
431 if (buf && (locn.Length() < sizeof(wlocn))) {
432 MultiByteToWideChar(0, 0, buf.data(), -1, wlocn, sizeof(wlocn) - 1);
433 info.pszErrorReportSaveDir = (LPCWSTR)wlocn;
434 }
435 }
436
437 // Provide privacy policy URL
438 wxFileName exec_path_crash(crash_std_path.GetExecutablePath());
439 wxString policy_file =
440 exec_path_crash.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
441 policy_file += _T("PrivacyPolicy.txt");
442 policy_file.Prepend(_T("file:"));
443
444 info.pszPrivacyPolicyURL = policy_file.c_str();
445 ;
446
447 int nResult = crInstall(&info);
448 if (nResult != 0) {
449 TCHAR buff[256];
450 crGetLastErrorMsg(buff, 256);
451 // MessageBox(NULL, buff, _T("crInstall error, Crash Reporting disabled."),
452 // MB_OK);
453 }
454
455 if (nResult == 0) { // Complete the installation
456 // Establish the crash callback function
457 crSetCrashCallback(CrashCallback, NULL);
458
459 // Take screenshot of the app window at the moment of crash
460 crAddScreenshot2(CR_AS_PROCESS_WINDOWS | CR_AS_USE_JPEG_FORMAT, 95);
461
462 // Mark some files to add to the crash report
463 wxString home_data_crash = crash_std_path.GetConfigDir();
464 if (g_bportable) {
465 wxFileName f(crash_std_path.GetExecutablePath());
466 home_data_crash = f.GetPath();
467 }
468 appendOSDirSlash(&home_data_crash);
469
470 wxString config_crash = _T("opencpn.ini");
471 config_crash.Prepend(home_data_crash);
472 crAddFile2(config_crash.c_str(), NULL, NULL,
473 CR_AF_MISSING_FILE_OK | CR_AF_ALLOW_DELETE);
474
475 wxString log_crash = _T("opencpn.log");
476 log_crash.Prepend(home_data_crash);
477 crAddFile2(log_crash.c_str(), NULL, NULL,
478 CR_AF_MISSING_FILE_OK | CR_AF_ALLOW_DELETE);
479 }
480#endif
481#endif
482
483#ifdef LINUX_CRASHRPT
484#if wxUSE_ON_FATAL_EXCEPTION
485 // fatal exceptions handling
486 wxHandleFatalExceptions(true);
487#endif
488#endif
489
490#ifdef __MSVC__
491 // Invoke my own handler for failures of malloc/new
492 _set_new_handler(MyNewHandler);
493 // configure malloc to call the New failure handler on failure
494 _set_new_mode(1);
495#endif
496
497#if 0
498#ifdef __WXMSW__
499 // On MSW, force the entire process to run on one CPU core only
500 // This resolves some difficulty with wxThread syncronization
501 //Gets the current process handle
502 HANDLE hProc = GetCurrentProcess();
503 DWORD procMask;
504 DWORD sysMask;
505 HANDLE hDup;
506 DuplicateHandle( hProc, hProc, hProc, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS );
507
508 //Gets the current process affinity mask
509 GetProcessAffinityMask( hDup, &procMask, &sysMask );
510
511 // Take a simple approach, and assume up to 4 processors
512 DWORD newMask;
513 if( ( procMask & 1 ) == 1 ) newMask = 1;
514 else
515 if( ( procMask & 2 ) == 2 ) newMask = 2;
516 else
517 if( ( procMask & 4 ) == 4 ) newMask = 4;
518 else
519 if( ( procMask & 8 ) == 8 ) newMask = 8;
520
521 //Set te affinity mask for the process
522 BOOL res = SetProcessAffinityMask( hDup, (DWORD_PTR) newMask );
523
524 if( res == 0 ) {
525 //Error setting affinity mask!!
526 }
527#endif
528#endif
529
530#ifdef __MSVC__
531
532 // Handle any Floating Point Exceptions which may leak thru from other
533 // processes. The exception filter is in cutil.c
534 // Seems to only happen for W98
535
536 wxPlatformInfo Platform;
537 if (Platform.GetOperatingSystemId() == wxOS_WINDOWS_9X)
538 SetUnhandledExceptionFilter(&MyUnhandledExceptionFilter);
539#endif
540
541#ifdef __WXMSW__
542 // _CrtSetBreakAlloc(25503);
543#endif
544
545#ifndef __WXMSW__
546 // Setup Linux SIGNAL handling, for external program control
547
548 // Build the sigaction structure
549 sa_all.sa_handler = catch_signals; // point to my handler
550 sigemptyset(&sa_all.sa_mask); // make the blocking set
551 // empty, so that all
552 // other signals will be
553 // unblocked during my handler
554 sa_all.sa_flags = 0;
555
556 sigaction(SIGUSR1, NULL,
557 &sa_all_old); // save existing action for this signal
558
559 // Register my request for some signals
560 sigaction(SIGUSR1, &sa_all, NULL);
561 sigaction(SIGUSR1, NULL,
562 &sa_all_old); // inspect existing action for this signal
563
564 sigaction(SIGTERM, &sa_all, NULL);
565 sigaction(SIGTERM, NULL, &sa_all_old);
566
567 sigaction(SIGHUP, &sa_all, NULL);
568 sigaction(SIGHUP, NULL, &sa_all_old);
569
570#endif
571
572#ifdef __OCPN__ANDROID__
573 qDebug() << "Initialize_1()";
574#ifdef NOASSERT
575 wxDisableAsserts( ); // No asserts at all in Release mode
576#endif
577 androidUtilInit();
578#endif
579
580}
581
582// Called from MyApp() immediately before creation of MyFrame()
583// Config is known to be loaded and stable
584// Log is available
585void OCPNPlatform::Initialize_2(void) {
586#ifdef __OCPN__ANDROID__
587 wxLogMessage(androidGetDeviceInfo());
588
589 // Create some directories in App private directory
590 // Mainly required for Android 11+, but useable on all versions.
591 wxChar sep = wxFileName::GetPathSeparator();
592
593 wxString ChartDir = GetPrivateDataDir();
594 if (ChartDir.Last() != sep) ChartDir.Append(sep);
595 ChartDir.Append( "Charts");
596 if (!::wxDirExists(ChartDir)) {
597 ::wxMkdir(ChartDir);
598 }
599
600 wxString GRIBDir = GetPrivateDataDir();
601 if (GRIBDir.Last() != sep) GRIBDir.Append(sep);
602 GRIBDir.Append( "GRIBS");
603 if (!::wxDirExists(GRIBDir)) {
604 ::wxMkdir(GRIBDir);
605 }
606
607 // Set the default Import/Export directory for A11+
608 if (g_Android_SDK_Version >= 30){
609 if (!g_gpx_path.StartsWith(androidGetDownloadDirectory())){
610 g_gpx_path = androidGetDownloadDirectory();
611 }
612 }
613
614#endif
615
616 // Set a global toolbar scale factor
617 g_toolbar_scalefactor = GetToolbarScaleFactor(g_GUIScaleFactor);
618 auto configdir = wxFileName(GetPrivateDataDir());
619 if (!configdir.DirExists()) {
620 if (!configdir.Mkdir()) {
621 auto msg = std::string("Cannot create config directory: ");
622 wxLogWarning(msg + configdir.GetFullPath());
623 }
624 }
625}
626
627// Called from MyApp()::OnInit() just after gFrame is created, so gFrame is
628// available
629void OCPNPlatform::Initialize_3(void) {
630 bool bcapable = IsGLCapable();
631
632#ifdef ocpnARM // Boot arm* platforms (meaning rPI) without OpenGL on first run
633 //bcapable = false;
634#endif
635
636 bool bAndroid = false;
637#ifdef __OCPN__ANDROID__
638 bAndroid = true;
639#endif
640
641 if(!bcapable)
642 g_bopengl = false;
643
644 // Try to automatically switch to guaranteed usable GL mode on an OCPN upgrade
645 // or fresh install
646
647 if ((g_bFirstRun || g_bUpgradeInProcess || bAndroid) && bcapable) {
648 g_bopengl = true;
649
650 // Set up visually nice options
651 g_GLOptions.m_bUseAcceleratedPanning = true;
652 g_GLOptions.m_bTextureCompression = true;
653 g_GLOptions.m_bTextureCompressionCaching = true;
654
655 g_GLOptions.m_iTextureDimension = 512;
656 g_GLOptions.m_iTextureMemorySize = 64;
657
658 g_GLOptions.m_GLPolygonSmoothing = true;
659 g_GLOptions.m_GLLineSmoothing = true;
660 }
661
662 gFrame->SetGPSCompassScale();
663
664 // Force a few items for Android, to ensure that UI is useable if config got
665 // scrambled
666 if (bAndroid) {
667 g_btouch = true;
668 }
669
670 if (g_bFirstRun || g_bUpgradeInProcess) {
671 if (!g_bRollover) // Not explicit set before
672 g_bRollover = g_btouch ? false : true;
673 }
674
675 g_FlushNavobjChangesTimeout = 300; // Seconds, so 5 minutes
676}
677
678// Called from MyApp() just before end of MyApp::OnInit()
679void OCPNPlatform::Initialize_4(void) {
680#ifdef __OCPN__ANDROID__
681 if (pSelect) pSelect->SetSelectPixelRadius(wxMax(25, 6.0 * getAndroidDPmm()));
682 if (pSelectTC)
683 pSelectTC->SetSelectPixelRadius(wxMax(25, 6.0 * getAndroidDPmm()));
684 if (pSelectAIS)
685 pSelectAIS->SetSelectPixelRadius(wxMax(25, 6.0 * getAndroidDPmm()));
686#endif
687
688#ifdef __WXMAC__
689 // A bit of a hack for Mojave MacOS 10.14.
690 // Force the user to actively select "Display" tab to ensure initial rendering
691 // of canvas layout select button.
692 options_lastPage = 1;
693#endif
694}
695
696void OCPNPlatform::OnExit_1(void) {}
697
698void OCPNPlatform::OnExit_2(void) {
699#ifdef OCPN_USE_CRASHREPORT
700#ifndef _DEBUG
701 // Uninstall Windows crash reporting
702// crUninstall();
703#endif
704#endif
705}
706
707
708bool OCPNPlatform::BuildGLCaps(void *pbuf) {
709 // Investigate OpenGL capabilities
710 gFrame->Show();
711 glTestCanvas *tcanvas = new glTestCanvas(gFrame);
712 tcanvas->Show();
713 wxYield();
714 wxGLContext *pctx = new wxGLContext(tcanvas);
715 tcanvas->SetCurrent(*pctx);
716
717 OCPN_GLCaps *pcaps = (OCPN_GLCaps *)pbuf;
718
719 char *str = (char *)glGetString(GL_RENDERER);
720 if (str == NULL) { //No GL at all...
721 delete tcanvas;
722 delete pctx;
723 return false;
724 }
725
726 pcaps->Renderer = std::string(str);
727 pcaps->Version = std::string((char *)glGetString(GL_VERSION));
728 pcaps->GLSL_Version = std::string((char *)glGetString(GL_SHADING_LANGUAGE_VERSION));
729 pcaps->dGLSL_Version = ::atof(pcaps->GLSL_Version.c_str());
730
731 if (pcaps->dGLSL_Version < 1.2){
732 wxString msg;
733 msg.Printf(_T("GLCaps Probe: OpenGL-> GLSL Version reported: "));
734 msg += wxString(pcaps->GLSL_Version.c_str());
735 msg += "\n OpenGL disabled due to insufficient OpenGL capabilities";
736 wxLogMessage(msg);
737 pcaps->bCanDoGLSL = false;
738 return false;
739 }
740
741 pcaps->bCanDoGLSL = true;
742
743 if (QueryExtension("GL_ARB_texture_non_power_of_two"))
744 pcaps->TextureRectangleFormat = GL_TEXTURE_2D;
745 else if (QueryExtension("GL_OES_texture_npot"))
746 pcaps->TextureRectangleFormat = GL_TEXTURE_2D;
747 else if (QueryExtension("GL_ARB_texture_rectangle"))
748 pcaps->TextureRectangleFormat = GL_TEXTURE_RECTANGLE_ARB;
749
750 pcaps->bOldIntel = false;
751
752 // Can we use VBO?
753 pcaps->bCanDoVBO = true;
754
755#if defined(__WXMSW__) || defined(__WXOSX__)
756 if (pcaps->bOldIntel) pcaps->bCanDoVBO = false;
757#endif
758
759#ifdef __OCPN__ANDROID__
760 pcaps->bCanDoVBO = false;
761#endif
762
763 // Can we use FBO?
764 pcaps->bCanDoFBO = true;
765
766#ifndef __OCPN__ANDROID__
767 // We need NPOT to support FBO rendering
768 if (!pcaps->TextureRectangleFormat) pcaps->bCanDoFBO = false;
769
770 // We require certain extensions to support FBO rendering
771 if (!QueryExtension("GL_EXT_framebuffer_object")) pcaps->bCanDoFBO = false;
772#endif
773
774 delete tcanvas;
775 delete pctx;
776
777 return true;
778}
779
780
781bool OCPNPlatform::IsGLCapable() {
782#ifdef __OCPN__ANDROID__
783 return true;
784#elif defined(CLI)
785 return false;
786#else
787 GL_Caps = new OCPN_GLCaps;
788
789 BuildGLCaps(GL_Caps);
790
791 // and so we decide....
792
793 // Require a modern GLSL implementation
794 if (!GL_Caps->bCanDoGLSL) return false;
795
796
797 // We insist on FBO support, since otherwise DC mode is always faster on
798 // canvas panning..
799 if (!GL_Caps->bCanDoFBO) return false;
800
801 return true;
802#endif
803}
804
805void OCPNPlatform::SetLocaleSearchPrefixes(void) {
806#if wxUSE_XLOCALE
807// Add a new prefixes for search order.
808#if defined(__WINDOWS__)
809
810 // Legacy and system plugin location
811 wxString locale_location = GetSharedDataDir();
812 locale_location += _T("share\\locale");
813 wxLocale::AddCatalogLookupPathPrefix(locale_location);
814 wxString imsg = _T("Adding catalog lookup path: ");
815 imsg += locale_location;
816 wxLogMessage(imsg);
817
818
819 // Managed plugin location
820 wxFileName usrShare(GetWinPluginBaseDir() + wxFileName::GetPathSeparator());
821 usrShare.RemoveLastDir();
822 locale_location = usrShare.GetFullPath() + ("share\\locale");
823 wxLocale::AddCatalogLookupPathPrefix(locale_location);
824 imsg = _T("Adding catalog lookup path: ");
825 imsg += locale_location;
826 wxLogMessage(imsg);
827
828#elif defined(__OCPN__ANDROID__)
829
830 wxString locale_location = GetSharedDataDir() + _T("locale");
831 wxLocale::AddCatalogLookupPathPrefix(locale_location);
832
833#elif defined(__UNIX__) && !defined(__WINE__)
834
835 // On Unix, wxWidgets defaults to installation prefix of its own, usually
836 // "/usr". On the other hand, canonical installation prefix for OpenCPN is
837 // "/usr/local".
838 wxString locale_location;
839 if (!wxGetEnv(_T("OPENCPN_PREFIX"), &locale_location)) {
840 locale_location = _T("/usr/local");
841 }
842 wxFileName location;
843 location.AssignDir(locale_location);
844 location.AppendDir(_T("share"));
845 location.SetName(_T("locale"));
846 locale_location = location.GetFullPath();
847 wxLocale::AddCatalogLookupPathPrefix(locale_location);
848
849 // And then for managed plugins
850 std::string dir = PluginPaths::getInstance()->UserDatadir();
851 wxString managed_locale_location(dir + "/locale");
852 wxLocale::AddCatalogLookupPathPrefix(managed_locale_location);
853#endif
854
855#ifdef __WXOSX__
856 std::string macDir =
858 "/Library/Application Support/OpenCPN/Contents/Resources";
859 wxString Mac_managed_locale_location(macDir);
860 wxLocale::AddCatalogLookupPathPrefix(Mac_managed_locale_location);
861#endif
862
863#endif
864}
865
866wxString OCPNPlatform::GetDefaultSystemLocale() {
867 wxLogMessage(_T("Getting DefaultSystemLocale..."));
868
869 wxString retval = _T("en_US");
870
871#if wxUSE_XLOCALE
872
873 const wxLanguageInfo *languageInfo =
874 wxLocale::GetLanguageInfo(wxLANGUAGE_DEFAULT);
875 if (languageInfo) retval = languageInfo->CanonicalName;
876
877#if defined(__WXMSW__)
878 LANGID lang_id = GetUserDefaultUILanguage();
879
880 wchar_t lngcp[101];
881 const wxLanguageInfo *languageInfoW = 0;
882 if (0 != GetLocaleInfo(MAKELCID(lang_id, SORT_DEFAULT), LOCALE_SENGLANGUAGE,
883 lngcp, 100)) {
884 wxString lstring = wxString(lngcp);
885
886 languageInfoW = wxLocale::FindLanguageInfo(lngcp);
887 if (languageInfoW)
888 wxLogMessage(_T("Found LanguageInfo for: ") + lstring);
889 else
890 wxLogMessage(_T("Could not find LanguageInfo for: ") + lstring);
891 } else {
892 wxLogMessage(_T("Could not get LocaleInfo, using wxLANGUAGE_DEFAULT"));
893 languageInfoW = wxLocale::GetLanguageInfo(wxLANGUAGE_DEFAULT);
894 }
895
896 if (languageInfoW) retval = languageInfoW->CanonicalName;
897#endif
898
899#if defined(__OCPN__ANDROID__)
900 retval = androidGetAndroidSystemLocale();
901#endif
902
903#endif
904
905 return retval;
906}
907
908#if wxUSE_XLOCALE || !wxCHECK_VERSION(3, 0, 0)
909wxString OCPNPlatform::GetAdjustedAppLocale() {
910 wxString adjLocale = g_locale;
911
912// For windows, installer may have left information in the registry defining
913// the user's selected install language. If so, override the config file value
914// and use this selection for opencpn...
915#if defined(__WXMSW__)
916 if (g_bFirstRun || wxIsEmpty(adjLocale)) {
917 wxRegKey RegKey(wxString(_T("HKEY_LOCAL_MACHINE\\SOFTWARE\\OpenCPN")));
918 if (RegKey.Exists()) {
919 wxLogMessage(
920 _T("Retrieving initial language selection from Windows Registry"));
921 RegKey.QueryValue(wxString(_T("InstallerLanguage")), adjLocale);
922 }
923 }
924 if (wxIsEmpty(adjLocale)) {
925 if (g_localeOverride.Length())
926 adjLocale = g_localeOverride;
927 else
928 adjLocale = GetDefaultSystemLocale();
929 }
930#endif
931#if defined(__OCPN__ANDROID__)
932 if (g_localeOverride.Length())
933 adjLocale = g_localeOverride;
934 else
935 adjLocale = GetDefaultSystemLocale();
936#endif
937
938 return adjLocale;
939}
940
941wxString OCPNPlatform::ChangeLocale(wxString &newLocaleID,
942 wxLocale *presentLocale,
943 wxLocale **newLocale) {
944 wxString return_val;
945
946 wxString imsg = _T("ChangeLocale: Language load for: ");
947 imsg += newLocaleID;
948 wxLogMessage(imsg);
949
950 // Old locale is done.
951 delete (wxLocale *)presentLocale;
952
953 wxLocale *locale = new wxLocale;
954 if (isFlatpacked()) {
955 std::string path(getenv("HOME"));
956 path += "/.var/app/org.opencpn.OpenCPN/data/locale";
957 locale->AddCatalogLookupPathPrefix(path);
958 wxLogMessage("Using flatpak locales at %s", path.c_str());
959 }
960 wxString loc_lang_canonical;
961
962 const wxLanguageInfo *pli = wxLocale::FindLanguageInfo(newLocaleID);
963 bool b_initok = false;
964
965 if (pli) {
966 locale->Init(pli->Language, 1);
967 // If the locale was not initialized OK, it may be that the wxstd.mo
968 // translations of the wxWidgets strings is not present. So try again,
969 // without attempting to load defaults wxstd.mo.
970 if (!locale->IsOk()) {
971 wxString imsg = _T("ChangeLocale: could not initialize: ");
972 imsg += newLocaleID;
973 wxLogMessage(imsg);
974
975 delete locale;
976 locale = new wxLocale;
977 locale->Init(pli->Language, 0);
978 }
979 loc_lang_canonical = pli->CanonicalName;
980
981 b_initok = locale->IsOk();
982#ifdef __OCPN__ANDROID__
983 b_initok = true;
984#endif
985 }
986
987 if (!b_initok) {
988 wxString imsg = _T("ChangeLocale: Fall back to en_US");
989 wxLogMessage(imsg);
990
991 delete locale;
992 locale = new wxLocale;
993 locale->Init(wxLANGUAGE_ENGLISH_US, 0);
994 loc_lang_canonical =
995 wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US)->CanonicalName;
996 }
997
998 if (b_initok) {
999 wxString imsg = _T("ChangeLocale: Locale Init OK for: ");
1000 imsg += loc_lang_canonical;
1001 wxLogMessage(imsg);
1002
1003 // wxWidgets assigneds precedence to message catalogs in reverse order of
1004 // loading. That is, the last catalog containing a certain translatable
1005 // item takes precedence.
1006
1007 // So, Load the catalogs saved in a global string array which is populated
1008 // as PlugIns request a catalog load. We want to load the PlugIn catalogs
1009 // first, so that core opencpn translations loaded later will become
1010 // precedent.
1011
1012 for (unsigned int i = 0; i < g_locale_catalog_array.GetCount(); i++) {
1013 if(!locale->AddCatalog(g_locale_catalog_array[i])){
1014 wxString emsg = _T("ERROR Loading translation catalog for: ");
1015 emsg += g_locale_catalog_array[i];
1016 wxLogMessage(emsg);
1017 }
1018 else {
1019 wxString imsg = _T("Loaded translation catalog for: ");
1020 imsg += g_locale_catalog_array[i];
1021 wxLogMessage(imsg);
1022 }
1023 }
1024
1025 // Get core opencpn catalog translation (.mo) file
1026 wxLogMessage(_T("Loading catalog for opencpn core."));
1027 locale->AddCatalog(_T("opencpn"));
1028
1029 return_val = locale->GetCanonicalName();
1030
1031 // We may want to override the default system locale, so set a flag.
1032 if (return_val != GetDefaultSystemLocale())
1033 g_localeOverride = return_val;
1034 else
1035 g_localeOverride = _T("");
1036 }
1037
1038 *newLocale = locale; // return the new locale
1039
1040 // Always use dot as decimal
1041 setlocale(LC_NUMERIC, "C");
1042
1043 return return_val;
1044}
1045#endif
1046
1047// Setup default global options when config file is unavailable,
1048// as on initial startup after new install
1049// The global config object (pConfig) is available, so direct updates are
1050// also allowed
1051
1052void OCPNPlatform::SetDefaultOptions(void) {
1053 // General options, applied to all platforms
1054 g_bShowOutlines = true;
1055
1056 g_CPAMax_NM = 20.;
1057 g_CPAWarn_NM = 2.;
1058 g_TCPA_Max = 30.;
1059 g_bMarkLost = true;
1060 g_MarkLost_Mins = 8;
1061 g_bRemoveLost = true;
1062 g_RemoveLost_Mins = 10;
1063 g_bShowCOG = true;
1064 g_ShowCOG_Mins = 6;
1065 g_bSyncCogPredictors = false;
1066 g_bHideMoored = false;
1067 g_ShowMoored_Kts = 0.2;
1068 g_bTrackDaily = false;
1069 g_PlanSpeed = 6.;
1070 g_bFullScreenQuilt = true;
1071 g_bQuiltEnable = true;
1072 g_bskew_comp = false;
1073 g_bShowAreaNotices = false;
1074 g_bDrawAISSize = false;
1075 g_bDrawAISRealtime = false;
1076 g_AIS_RealtPred_Kts = 0.7;
1077 g_bShowAISName = false;
1078 g_nTrackPrecision = 2;
1079 g_bPreserveScaleOnX = true;
1080 g_nAWDefault = 50;
1081 g_nAWMax = 1852;
1082 gps_watchdog_timeout_ticks = GPS_TIMEOUT_SECONDS;
1083 g_n_ownship_min_mm = 8;
1084 g_bShowMuiZoomButtons = true;
1085 g_bresponsive = false;
1086
1087 // Initial S52/S57 options
1088 if (pConfig) {
1089 pConfig->SetPath(_T ( "/Settings/GlobalState" ));
1090 pConfig->Write(_T ( "bShowS57Text" ), true);
1091 pConfig->Write(_T ( "bShowS57ImportantTextOnly" ), false);
1092 pConfig->Write(_T ( "nDisplayCategory" ), (int)(_DisCat)STANDARD);
1093 pConfig->Write(_T ( "nSymbolStyle" ), (int)(_LUPname)PAPER_CHART);
1094 pConfig->Write(_T ( "nBoundaryStyle" ), (int)(_LUPname)PLAIN_BOUNDARIES);
1095
1096 pConfig->Write(_T ( "bShowSoundg" ), true);
1097 pConfig->Write(_T ( "bShowMeta" ), false);
1098 pConfig->Write(_T ( "bUseSCAMIN" ), true);
1099 pConfig->Write(_T ( "bShowAtonText" ), false);
1100 pConfig->Write(_T ( "bShowLightDescription" ), false);
1101 pConfig->Write(_T ( "bExtendLightSectors" ), true);
1102 pConfig->Write(_T ( "bDeClutterText" ), true);
1103 pConfig->Write(_T ( "bShowNationalText" ), true);
1104
1105 pConfig->Write(_T ( "S52_MAR_SAFETY_CONTOUR" ), 3);
1106 pConfig->Write(_T ( "S52_MAR_SHALLOW_CONTOUR" ), 2);
1107 pConfig->Write(_T ( "S52_MAR_DEEP_CONTOUR" ), 6);
1108 pConfig->Write(_T ( "S52_MAR_TWO_SHADES" ), 0);
1109 pConfig->Write(_T ( "S52_DEPTH_UNIT_SHOW" ), 1);
1110
1111 pConfig->Write(_T ( "ZoomDetailFactorVector" ), 3);
1112
1113 pConfig->Write(_T ( "nColorScheme" ), 1); // higher contrast on NOAA RNCs
1114 }
1115
1116#ifdef __WXMSW__
1117 // Enable some default PlugIns, and their default options
1118 if (pConfig) {
1119 pConfig->SetPath(_T ( "/PlugIns/chartdldr_pi.dll" ));
1120 pConfig->Write(_T ( "bEnabled" ), true);
1121
1122 pConfig->SetPath(_T ( "/PlugIns/wmm_pi.dll" ));
1123 pConfig->Write(_T ( "bEnabled" ), true);
1124
1125 pConfig->SetPath(_T ( "/Settings/WMM" ));
1126 pConfig->Write(_T ( "ShowIcon" ), true);
1127 pConfig->Write(_T ( "ShowLiveIcon" ), true);
1128 }
1129#endif
1130
1131#ifdef __WXOSX__
1132 // Enable some default PlugIns, and their default options
1133 if (pConfig) {
1134 pConfig->SetPath(_T ( "/PlugIns/libchartdldr_pi.dylib" ));
1135 pConfig->Write(_T ( "bEnabled" ), true);
1136
1137 pConfig->SetPath(_T ( "/PlugIns/libwmm_pi.dylib" ));
1138 pConfig->Write(_T ( "bEnabled" ), true);
1139
1140 pConfig->SetPath(_T ( "/Settings/WMM" ));
1141 pConfig->Write(_T ( "ShowIcon" ), true);
1142 pConfig->Write(_T ( "ShowLiveIcon" ), true);
1143 }
1144#endif
1145
1146#ifdef __linux__
1147 // Enable some default PlugIns, and their default options
1148 if (pConfig) {
1149 pConfig->SetPath(_T ( "/PlugIns/libchartdldr_pi.so" ));
1150 pConfig->Write(_T ( "bEnabled" ), true);
1151
1152 pConfig->SetPath(_T ( "/PlugIns/libwmm_pi.so" ));
1153 pConfig->Write(_T ( "bEnabled" ), true);
1154
1155 pConfig->SetPath(_T ( "/Settings/WMM" ));
1156 pConfig->Write(_T ( "ShowIcon" ), true);
1157 pConfig->Write(_T ( "ShowLiveIcon" ), true);
1158 }
1159#endif
1160
1161#ifdef __OCPN__ANDROID__
1162
1163#ifdef ocpnUSE_GL
1164 g_bopengl = true;
1165 g_GLOptions.m_bTextureCompression = 1;
1166 g_GLOptions.m_bTextureCompressionCaching = 1;
1167#endif
1168
1169 qDebug() << "SetDefaultOptions";
1170
1171 g_btouch = true;
1172 g_bresponsive = true;
1173 g_default_font_size = 18; // This is pretty close to TextAppearance.Medium
1174 g_bUIexpert = true;
1175
1176 g_bShowStatusBar = true;
1177 g_cm93_zoom_factor = 0;
1178 g_oz_vector_scale = false;
1179 g_fog_overzoom = false;
1180
1181 g_bRollover = true;
1182 g_bShowMuiZoomButtons = true;
1183
1184 g_GUIScaleFactor = 0; // nominal
1185 g_ChartNotRenderScaleFactor = 2.0;
1186
1187 // Suppress most tools, especially those that appear in the Basic menus.
1188 // Of course, they may be re-enabled by experts...
1189 g_toolbarConfig = _T("X.....XX.......XX.XXXXXXXXXXX");
1190 g_bPermanentMOBIcon = false;
1191
1192 wxString sGPS = _T("2;3;;0;0;;0;1;0;0;;0;;1;0;0;0;0"); // 17 parms
1193 ConnectionParams *new_params = new ConnectionParams(sGPS);
1194
1195 new_params->bEnabled = true;
1196 TheConnectionParams()->Add(new_params);
1197
1198 g_default_font_facename = _T("Roboto");
1199
1200 // Enable some default PlugIns, and their default options
1201
1202 if (pConfig) {
1203 pConfig->SetPath(_T ( "/PlugIns/libchartdldr_pi.so" ));
1204 pConfig->Write(_T ( "bEnabled" ), true);
1205
1206 pConfig->SetPath(_T ( "/PlugIns/libwmm_pi.so" ));
1207 pConfig->Write(_T ( "bEnabled" ), true);
1208
1209 pConfig->SetPath(_T ( "/Settings/WMM" ));
1210 pConfig->Write(_T ( "ShowIcon" ), true);
1211 pConfig->Write(_T ( "ShowLiveIcon" ), true);
1212
1213 pConfig->SetPath(_T ( "/PlugIns/libgrib_pi.so" ));
1214 pConfig->Write(_T ( "bEnabled" ), true);
1215
1216 pConfig->SetPath(_T ( "/PlugIns/libdashboard_pi.so" ));
1217 pConfig->Write(_T ( "bEnabled" ), true);
1218
1219 pConfig->SetPath(_T ( "/PlugIns/GRIB" ));
1220 pConfig->Write(_T ( "GRIBCtrlBarPosX" ), 100);
1221 pConfig->Write(_T ( "GRIBCtrlBarPosY" ), 0);
1222
1223 pConfig->SetPath(_T ( "/Settings/GRIB" ));
1224 pConfig->Write(_T ( "CursorDataShown" ), 0);
1225
1226 // This is ugly hack
1227 // TODO
1228 pConfig->SetPath(_T ( "/PlugIns/liboesenc_pi.so" ));
1229 pConfig->Write(_T ( "bEnabled" ), true);
1230
1231 pConfig->SetPath(_T ( "/Settings/QTFonts" ));
1232
1233 // Status Bar
1234 wxString str = _T("en_US-b25a3899");
1235 wxString pval = _T("StatusBar:Roboto,26,-1,5,75,0,0,0,0,0:rgb(0, 0, 0)");
1236 pConfig->Write(str, pval);
1237 FontMgr::Get().LoadFontNative(&str, &pval);
1238
1239 // Dialog
1240 str = _T("en_US-9c3b3a0d");
1241 pval = _T("DialogStatusBar:Roboto,18,-1,5,50,0,0,0,0,0:rgb(0, 0, 0)");
1242 pConfig->Write(str, pval);
1243 FontMgr::Get().LoadFontNative(&str, &pval);
1244
1245 // Set track default color to magenta
1246 pConfig->SetPath(_T ( "/Settings/Others" ));
1247 pConfig->Write(_T("TrackLineColour"), _T("#C545C3"));
1248 g_colourTrackLineColour.Set(197, 69, 195);
1249
1250 qDebug() << "SetDefaultOptions.Config";
1251 }
1252
1253#endif
1254}
1255
1256// Setup global options on upgrade detected
1257// The global config object (pConfig) has already been loaded, so updates
1258// here override values set by config Direct updates to config for next
1259// boot are also allowed
1260
1261void OCPNPlatform::SetUpgradeOptions(wxString vNew, wxString vOld) {
1262#ifdef __OCPN__ANDROID__
1263
1264 qDebug() << "Upgrade check"
1265 << "from: " << vOld.mb_str() << " to: " << vNew.mb_str();
1266
1267 if (androidGetVersionCode() > g_AndroidVersionCode) { // upgrade
1268 qDebug() << "Upgrade detected"
1269 << "from VC: " << g_AndroidVersionCode
1270 << " to VC: " << androidGetVersionCode();
1271
1272 // Set some S52/S57 options
1273 if (pConfig) {
1274 pConfig->SetPath(_T ( "/Settings/GlobalState" ));
1275 pConfig->Write(_T ( "bShowS57Text" ), true);
1276 }
1277
1278 g_ChartNotRenderScaleFactor = 2.0;
1279 g_n_ownship_min_mm = 8;
1280 g_toolbarConfig = _T("X.....XX.......XX.XXXXXXXXXXX");
1281
1282 // Experience indicates a slightly larger default font size is better
1283 pConfig->DeleteGroup(_T ( "/Settings/QTFonts" ));
1284 g_default_font_size = 20;
1285 g_default_font_facename = _T("Roboto");
1286
1287 FontMgr::Get().Shutdown(); // Restart the font manager
1288
1289 // Reshow the zoom buttons
1290 g_bShowMuiZoomButtons = true;
1291
1292 // Clear the default chart storage location
1293 // Will get set to e.g. "/storage/emulated/0" later
1294 pInit_Chart_Dir->Clear();
1295
1296 pConfig->SetPath(_T ( "/Settings/WMM" ));
1297 pConfig->Write(_T ( "ShowIcon" ), true);
1298 pConfig->Write(_T ( "ShowLiveIcon" ), true);
1299 }
1300
1301 // Set track default color to magenta
1302 g_colourTrackLineColour.Set(197, 69, 195);
1303
1304 // This is ugly hack
1305 // TODO
1306 // pConfig->SetPath( _T ( "/PlugIns/liboesenc_pi.so" ) );
1307 // pConfig->Write( _T ( "bEnabled" ), true );
1308
1309#endif
1310
1311 // Check for upgrade....
1312 if (!vOld.IsSameAs(vNew)) { // upgrade
1313
1314 // Verify some default directories, create if necessary
1315
1316 // UserIcons
1317 wxString UserIconPath = GetPrivateDataDir();
1318 wxChar sep = wxFileName::GetPathSeparator();
1319 if (UserIconPath.Last() != sep) UserIconPath.Append(sep);
1320 UserIconPath.Append(_T("UserIcons"));
1321
1322 if (!::wxDirExists(UserIconPath)) {
1323 ::wxMkdir(UserIconPath);
1324 }
1325
1326 // layers
1327 wxString LayersPath = GetPrivateDataDir();
1328 if (LayersPath.Last() != sep) LayersPath.Append(sep);
1329 LayersPath.Append(_T("layers"));
1330
1331 if (!::wxDirExists(LayersPath)) {
1332 ::wxMkdir(LayersPath);
1333 }
1334
1335 // Force a generally useable sound command, overriding any previous user's
1336 // selection
1337 // that may not be available on new build.
1338 g_CmdSoundString = wxString(OCPN_SOUND_CMD);
1339 pConfig->SetPath(_T ( "/Settings" ));
1340 pConfig->Write(_T( "CmdSoundString" ), g_CmdSoundString);
1341
1342 // Force AIS specific sound effects ON, leaving the master control
1343 // (g_bAIS_CPA_Alert_Audio) as configured
1344 g_bAIS_GCPA_Alert_Audio = true;
1345 g_bAIS_SART_Alert_Audio = true;
1346 g_bAIS_DSC_Alert_Audio = true;
1347
1348 // Force a recalculation of default main toolbar location
1349 g_maintoolbar_x = -1;
1350
1351 // Force a reload of updated default tide/current datasets
1352 TideCurrentDataSet.Clear();
1353 }
1354}
1355
1356int OCPNPlatform::platformApplyPrivateSettingsString(wxString settings,
1357 ArrayOfCDI *pDirArray) {
1358 int ret_val = 0;
1359#ifdef __OCPN__ANDROID__
1360 ret_val = androidApplySettingsString(settings, pDirArray);
1361#endif
1362
1363 return ret_val;
1364}
1365
1366void OCPNPlatform::applyExpertMode(bool mode) {
1367#ifdef __OCPN__ANDROID__
1368 g_bexpert = mode; // toolbar only shows plugin icons if expert mode is false
1369 g_bBasicMenus = !mode; // simplified context menus in basic mode
1370#endif
1371}
1372
1373wxString OCPNPlatform::GetSupplementalLicenseString() {
1374 wxString lic;
1375#ifdef __OCPN__ANDROID__
1376 lic = androidGetSupplementalLicense();
1377#endif
1378 return lic;
1379}
1380
1381//--------------------------------------------------------------------------
1382// Per-Platform file/directory support
1383//--------------------------------------------------------------------------
1384
1385
1386static wxString ExpandPaths(wxString paths, OCPNPlatform *platform);
1387
1388
1389int OCPNPlatform::DoFileSelectorDialog(wxWindow *parent, wxString *file_spec,
1390 wxString Title, wxString initDir,
1391 wxString suggestedName,
1392 wxString wildcard) {
1393 wxString file;
1394 int result = wxID_CANCEL;
1395
1396#ifdef __OCPN__ANDROID__
1397 // Verify that initDir is traversable, fix it if not...
1398 wxString idir = initDir;
1399 if (initDir.StartsWith(
1400 _T("/data/data"))) // not good, provokes a crash usually...
1401 idir = GetWritableDocumentsDir();
1402
1403 result = androidFileChooser(&file, idir, Title, suggestedName, wildcard);
1404 if (file_spec) *file_spec = file;
1405#else
1406 long flag = wxFD_DEFAULT_STYLE;
1407 if (suggestedName.Length()) { // new file
1408 flag = wxFD_SAVE;
1409 }
1410
1411 wxString mask = wildcard;
1412 if (wxNOT_FOUND != mask.Find(_T("gpx")))
1413 mask.Prepend(_T("GPX files (*.gpx)|"));
1414
1415 wxFileDialog *psaveDialog =
1416 new wxFileDialog(parent, Title, initDir, suggestedName, mask, flag);
1417
1418 // Try to reduce the dialog size, and scale fonts down, if necessary.
1419 // if(g_bresponsive && parent)
1420 // psaveDialog = g_Platform->AdjustFileDialogFont(parent,
1421 // psaveDialog);
1422
1423#ifdef __WXOSX__
1424 if (parent) parent->HideWithEffect(wxSHOW_EFFECT_BLEND);
1425#endif
1426
1427 result = psaveDialog->ShowModal();
1428
1429#ifdef __WXOSX__
1430 if (parent) parent->ShowWithEffect(wxSHOW_EFFECT_BLEND);
1431#endif
1432
1433 if (file_spec) *file_spec = psaveDialog->GetPath();
1434 delete psaveDialog;
1435
1436#endif
1437
1438 return result;
1439}
1440
1441int OCPNPlatform::DoDirSelectorDialog(wxWindow *parent, wxString *file_spec,
1442 wxString Title, wxString initDir,
1443 bool b_addFiles) {
1444 wxString dir;
1445 int result = wxID_CANCEL;
1446
1447#ifdef __OCPN__ANDROID__
1448 // Verify that initDir is traversable, fix it if not...
1449 wxString idir = initDir;
1450 if (initDir.StartsWith(
1451 _T("/data/data"))) // not good, provokes a crash usually...
1452 idir = GetWritableDocumentsDir();
1453
1454 result = androidFileChooser(&dir, idir, Title, _T(""), _T(""), true,
1455 b_addFiles); // Directories only, maybe add dirs
1456 if (file_spec) *file_spec = dir;
1457#else
1458 wxDirDialog *dirSelector = new wxDirDialog(
1459 parent, Title, initDir, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
1460
1461 wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
1462 dirSelector->SetFont(*qFont);
1463
1464 // Try to reduce the dialog size, and scale fonts down, if necessary.
1465 // if(g_bresponsive && parent)
1466 // dirSelector = AdjustDirDialogFont(parent, dirSelector);
1467
1468#ifdef __WXOSX__
1469 if (parent) parent->HideWithEffect(wxSHOW_EFFECT_BLEND);
1470#endif
1471
1472 result = dirSelector->ShowModal();
1473
1474#ifdef __WXOSX__
1475 if (parent) parent->ShowWithEffect(wxSHOW_EFFECT_BLEND);
1476#endif
1477
1478 if (result == wxID_CANCEL) {
1479 } else {
1480 if (file_spec) {
1481 *file_spec = dirSelector->GetPath();
1482 }
1483 }
1484
1485 delete dirSelector;
1486#endif
1487
1488 return result;
1489}
1490
1491MyConfig *OCPNPlatform::GetConfigObject() {
1492 MyConfig *result = NULL;
1493
1494 result = new MyConfig(GetConfigFileName());
1495
1496 return result;
1497}
1498
1499//--------------------------------------------------------------------------
1500// Internal GPS Support
1501//--------------------------------------------------------------------------
1502
1503bool OCPNPlatform::hasInternalGPS(wxString profile) {
1504#ifdef __OCPN__ANDROID__
1505 bool t = androidDeviceHasGPS();
1506 // qDebug() << "androidDeviceHasGPS" << t;
1507 return t;
1508#else
1509
1510 return false;
1511
1512#endif
1513}
1514
1515//--------------------------------------------------------------------------
1516// Platform Display Support
1517//--------------------------------------------------------------------------
1518
1519void OCPNPlatform::ShowBusySpinner(void) {
1520#ifdef __OCPN__ANDROID__
1521 androidShowBusyIcon();
1522#else
1523#if wxCHECK_VERSION(2, 9, 0)
1524 // if( !::wxIsBusy() )
1525 { ::wxBeginBusyCursor(); }
1526#endif
1527#endif
1528}
1529
1530void OCPNPlatform::HideBusySpinner(void) {
1531#ifdef __OCPN__ANDROID__
1532 androidHideBusyIcon();
1533#else
1534#if wxCHECK_VERSION(2, 9, 0)
1535 // if( ::wxIsBusy() )
1536 { ::wxEndBusyCursor(); }
1537#endif
1538#endif
1539}
1540
1541double OCPNPlatform::GetDisplayDensityFactor() {
1542#ifdef __OCPN__ANDROID__
1543 return getAndroidDisplayDensity();
1544#else
1545 return 1.0;
1546#endif
1547}
1548
1549long OCPNPlatform::GetDefaultToolbarOrientation() {
1550#ifndef __OCPN__ANDROID__
1551 return wxTB_VERTICAL;
1552#else
1553 return wxTB_VERTICAL;
1554#endif
1555}
1556
1557int OCPNPlatform::GetStatusBarFieldCount() {
1558#ifdef __OCPN__ANDROID__
1559 int count = 1;
1560
1561 // Make a horizontal measurement...
1562 wxScreenDC dc;
1563 wxFont *templateFont = FontMgr::Get().GetFont(_("StatusBar"), 0);
1564 dc.SetFont(*templateFont);
1565
1566 int width;
1567 dc.GetTextExtent(_T("WWWWWW"), &width, NULL, NULL, NULL, templateFont);
1568 double font_size_pix = (double)width / 6.0;
1569
1570 wxSize dispSize = getDisplaySize();
1571
1572 double nChars = dispSize.x / font_size_pix;
1573
1574 if (nChars < 40)
1575 count = 1;
1576 else
1577 count = 2;
1578
1579 return count;
1580
1581#else
1582 return STAT_FIELD_COUNT; // default
1583#endif
1584}
1585
1586double OCPNPlatform::getFontPointsperPixel(void) {
1587 double pt_per_pixel = 1.0;
1588
1589 //#ifdef __OCPN__ANDROID__
1590 // On Android, this calculation depends on the density bucket in use.
1591 // Also uses some magic numbers...
1592 // For reference, see http://pixplicity.com/dp-px-converter/
1593 // pt_per_pixel = 14.0 / (31.11 * getAndroidDisplayDensity()) ;
1594
1595 //#else
1596
1597 if (m_pt_per_pixel == 0) {
1598 // Make a measurement...
1599 wxScreenDC dc;
1600
1601 wxFont *f = FontMgr::Get().FindOrCreateFont(
1602 12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, FALSE,
1603 wxString(_T ( "" )), wxFONTENCODING_SYSTEM);
1604 dc.SetFont(*f);
1605
1606 int width, height;
1607 dc.GetTextExtent(_T("H"), &width, &height, NULL, NULL, f);
1608
1609 if (height > 0) m_pt_per_pixel = 12.0 / (double)height;
1610 }
1611 if (m_pt_per_pixel > 0) pt_per_pixel = m_pt_per_pixel;
1612 //#endif
1613
1614 return pt_per_pixel;
1615}
1616
1617wxSize OCPNPlatform::getDisplaySize() {
1618#ifdef __OCPN__ANDROID__
1619 return getAndroidDisplayDimensions();
1620#else
1621 if (m_displaySize.x < 10)
1622 m_displaySize = ::wxGetDisplaySize(); // default, for most platforms
1623 return m_displaySize;
1624#endif
1625}
1626
1627double OCPNPlatform::GetDisplaySizeMM() {
1628 if (m_displaySizeMMOverride > 0) return m_displaySizeMMOverride;
1629
1630 if (m_displaySizeMM.x < 1) m_displaySizeMM = wxGetDisplaySizeMM();
1631
1632 double ret = m_displaySizeMM.GetWidth();
1633
1634#if 0
1635#ifdef __WXGTK__
1636 GdkScreen *screen = gdk_screen_get_default();
1637 wxSize resolution = getDisplaySize();
1638 double gdk_monitor_mm;
1639 double ratio = (double)resolution.GetWidth() / (double)resolution.GetHeight();
1640 if( std::abs(ratio - 32.0/10.0) < std::abs(ratio - 16.0/10.0) ) {
1641 // We suspect that when the resolution aspect ratio is closer to 32:10 than 16:10, there are likely 2 monitors side by side. This works nicely when they are landscape, but what if both are rotated 90 degrees...
1642 gdk_monitor_mm = gdk_screen_get_width_mm(screen);
1643 } else {
1644 gdk_monitor_mm = gdk_screen_get_monitor_width_mm(screen, 0);
1645 }
1646 if(gdk_monitor_mm > 0) // if gdk detects a valid screen width (returns -1 on raspberry pi)
1647 ret = gdk_monitor_mm;
1648#endif
1649#endif
1650
1651#ifdef __WXMSW__
1652 int w, h;
1653
1654 if (!m_bdisableWindowsDisplayEnum) {
1655 if (GetWindowsMonitorSize(&w, &h) && (w > 100)) { // sanity check
1656 m_displaySizeMM == wxSize(w, h);
1657 ret = w;
1658 } else
1659 m_bdisableWindowsDisplayEnum = true; // disable permanently
1660 }
1661
1662#endif
1663
1664#ifdef __WXOSX__
1665 ret = GetMacMonitorSize();
1666#endif
1667
1668#ifdef __OCPN__ANDROID__
1669 ret = GetAndroidDisplaySize();
1670#endif
1671
1672 wxString msg;
1673 msg.Printf(_T("Detected display size (horizontal): %d mm"), (int)ret);
1674 // wxLogMessage(msg);
1675
1676 return ret;
1677}
1678
1679double OCPNPlatform::GetDisplayAreaCM2() {
1680 double size1 = GetDisplaySizeMM();
1681 wxSize sz = getDisplaySize();
1682 double ratio = 1.;
1683 if (sz.x < sz.y)
1684 ratio = (double)sz.x / (double)sz.y; // <1
1685 else
1686 ratio = (double)sz.y / (double)sz.x; // <1
1687
1688 double area = size1 * (size1 * ratio) / 100.;
1689 // qDebug() << "cm2" << size1 << ratio << sz.x << sz.y;
1690 return area;
1691}
1692
1693void OCPNPlatform::SetDisplaySizeMM(double sizeMM) {
1694 m_displaySizeMMOverride = sizeMM;
1695}
1696
1697double OCPNPlatform::GetDisplayDPmm() {
1698#ifdef __OCPN__ANDROID__
1699 return getAndroidDPmm();
1700#else
1701 double r = getDisplaySize().x; // dots
1702 return r / GetDisplaySizeMM();
1703#endif
1704}
1705
1706unsigned int OCPNPlatform::GetSelectRadiusPix() {
1707 return GetDisplayDPmm() *
1708 (g_btouch ? g_selection_radius_touch_mm : g_selection_radius_mm);
1709}
1710
1711bool OCPNPlatform::GetFullscreen() {
1712 bool bret = false;
1713#ifdef __OCPN__ANDROID__
1714 bret = androidGetFullscreen();
1715#else
1716
1717#endif
1718
1719 return bret;
1720}
1721
1722bool OCPNPlatform::SetFullscreen(bool bFull) {
1723 bool bret = false;
1724#ifdef __OCPN__ANDROID__
1725 bret = androidSetFullscreen(bFull);
1726#else
1727#endif
1728
1729 return bret;
1730}
1731
1732void OCPNPlatform::PositionAISAlert(wxWindow *alert_window) {
1733#ifndef __OCPN__ANDROID__
1734 if (alert_window) {
1735 alert_window->SetSize(g_ais_alert_dialog_x, g_ais_alert_dialog_y,
1736 g_ais_alert_dialog_sx, g_ais_alert_dialog_sy);
1737 }
1738#else
1739 if (alert_window) {
1740 alert_window->SetSize(g_ais_alert_dialog_x, g_ais_alert_dialog_y,
1741 g_ais_alert_dialog_sx, g_ais_alert_dialog_sy);
1742 alert_window->Centre();
1743 }
1744
1745#endif
1746}
1747
1748wxDirDialog *OCPNPlatform::AdjustDirDialogFont(wxWindow *container,
1749 wxDirDialog *dlg) {
1750 wxDirDialog *ret_dlg = dlg;
1751#ifndef __WXGTK__
1752
1753 dlg->Show();
1754 dlg->SetSize(container->GetSize());
1755 dlg->Centre();
1756
1757 wxSize sds = dlg->GetSize();
1758 wxSize ss = container->GetSize();
1759
1760 if (sds.x > ss.x) {
1761 dlg->Hide();
1762
1763 wxString msg = dlg->GetMessage();
1764 wxString default_dir = dlg->GetPath();
1765
1766 delete dlg;
1767
1768 ret_dlg = new wxDirDialog(NULL, msg, default_dir,
1769 wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
1770
1771 wxFont *dialogFont = GetOCPNScaledFont(_("Dialog"));
1772 wxFont *smallFont = new wxFont(*dialogFont);
1773 smallFont->SetPointSize((smallFont->GetPointSize() / 2) +
1774 0.5); // + 0.5 to round instead of truncate
1775 ret_dlg->SetFont(*smallFont);
1776
1777 ret_dlg->SetSize(container->GetSize());
1778 ret_dlg->Centre();
1779 }
1780 ret_dlg->Hide();
1781#endif
1782 return ret_dlg;
1783}
1784
1785wxFileDialog *OCPNPlatform::AdjustFileDialogFont(wxWindow *container,
1786 wxFileDialog *dlg) {
1787 wxFileDialog *ret_dlg = dlg;
1788#ifndef __WXGTK__
1789
1790 dlg->Show();
1791 dlg->SetSize(container->GetSize());
1792 dlg->Centre();
1793
1794 wxSize sds = dlg->GetSize();
1795 wxSize ss = container->GetSize();
1796
1797 if (sds.x > ss.x) {
1798 dlg->Hide();
1799
1800 wxString msg = dlg->GetMessage();
1801 wxString default_dir = dlg->GetDirectory();
1802 wxString default_file = dlg->GetFilename();
1803 wxString wildcard = dlg->GetWildcard();
1804
1805 delete dlg;
1806
1807 ret_dlg = new wxFileDialog(NULL, msg, default_dir, default_file, wildcard,
1808 wxFD_OPEN);
1809
1810 wxFont *dialogFont = GetOCPNScaledFont(_("Dialog"));
1811 wxFont *smallFont = new wxFont(*dialogFont);
1812 smallFont->SetPointSize((smallFont->GetPointSize() / 2) +
1813 0.5); // + 0.5 to round instead of truncate
1814 ret_dlg->SetFont(*smallFont);
1815
1816 ret_dlg->SetSize(container->GetSize());
1817 ret_dlg->Centre();
1818 }
1819 ret_dlg->Hide();
1820#endif
1821 return ret_dlg;
1822}
1823
1824double OCPNPlatform::GetToolbarScaleFactor(int GUIScaleFactor) {
1825 double rv = 1.0;
1826#ifdef __OCPN__ANDROID__
1827
1828 // We try to arrange matters so that at GUIScaleFactor=0, the tool icons are
1829 // approximately 9 mm in size and that the value may range from 0.5 -> 2.0
1830
1831 // Get the basic size of a tool icon
1832 wxSize style_tool_size(32, 32);
1833
1834 if (g_StyleManager) {
1835 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
1836 if (style) style_tool_size = style->GetToolSize();
1837 }
1838 double tool_size = style_tool_size.x;
1839
1840 // unless overridden by user, we declare the "best" tool size
1841 // to be roughly the same as the ActionBar height.
1842 // This may be approximated in a device orientation-independent way as:
1843 // 45pixels * DENSITY
1844 double premult = 1.0;
1845 if (g_config_display_size_manual && (g_config_display_size_mm > 0)) {
1846 double target_size = 9.0; // mm
1847
1848 double basic_tool_size_mm = tool_size / GetDisplayDPmm();
1849 premult = target_size / basic_tool_size_mm;
1850
1851 } else {
1852 premult = wxMax(45 * getAndroidDisplayDensity(), 45) /
1853 tool_size; // make sure not too small
1854 }
1855
1856 // Adjust the scale factor using the global GUI scale parameter, ranging from
1857 // 0.5 -> 2.0
1858 double postmult = exp(GUIScaleFactor * (log(2.0) / 5.0));
1859
1860 // qDebug() << "parmsF" << GUIScaleFactor << premult << postmult;
1861
1862 rv = premult * postmult;
1863 rv = wxMin(rv, getAndroidDisplayDensity() *
1864 3); // Clamp at density * arbitrary limit factor
1865
1866#else
1867 double premult = 1.0;
1868
1869 if (g_bresponsive) {
1870 // Get the basic size of a tool icon
1871 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
1872 wxSize style_tool_size = style->GetToolSize();
1873 double tool_size = style_tool_size.x;
1874
1875 // unless overridden by user, we declare the "best" tool size
1876 // to be roughly 9 mm square.
1877 double target_size = 9.0; // mm
1878
1879 double basic_tool_size_mm = tool_size / GetDisplayDPmm();
1880 premult = target_size / basic_tool_size_mm;
1881 }
1882
1883 // Adjust the scale factor using the global GUI scale parameter
1884 double postmult = exp(GUIScaleFactor * (0.693 / 5.0)); // exp(2)
1885
1886 rv = premult * postmult;
1887 rv = wxMin(rv, 3.0); // Clamp at 3.0
1888 rv = wxMax(rv, 0.5); // and at 0.5
1889
1890 rv /= g_BasePlatform->GetDisplayDIPMult(gFrame);
1891
1892#endif
1893
1894 return rv;
1895}
1896
1897double OCPNPlatform::GetCompassScaleFactor(int GUIScaleFactor) {
1898 double rv = 1.0;
1899#ifdef __OCPN__ANDROID__
1900
1901 // We try to arrange matters so that at GUIScaleFactor=0, the compass icon is
1902 // approximately 9 mm in size and that the value may range from 0.5 -> 2.0
1903
1904 if (g_bresponsive) {
1905 // Get the basic size of a tool icon
1906 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
1907 wxSize style_tool_size = style->GetToolSize();
1908 double compass_size = style_tool_size.x;
1909
1910 // We declare the "nominal best" icon size to be a bit smaller than the
1911 // ActionBar height.
1912 // This may be approximated in a device orientation-independent way as:
1913 // 28pixels * DENSITY
1914 double premult = wxMax(28 * getAndroidDisplayDensity(), 50) / compass_size;
1915
1916 // Adjust the scale factor using the global GUI scale parameter
1917 double postmult = exp(GUIScaleFactor * (log(2.0) / 5.0));
1918 // rv = wxMin(rv, 1.5); // Clamp at 1.5
1919
1920 rv = premult * postmult;
1921 rv = wxMin(rv, getAndroidDisplayDensity() *
1922 3); // Clamp at density * arbitrary limit factor
1923 }
1924
1925#else
1926 double premult = 1.0;
1927
1928 if (g_bresponsive) {
1929 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
1930 wxSize style_tool_size = style->GetToolSize();
1931 double compass_size = style_tool_size.x;
1932
1933 // We declare the "best" tool size to be roughly 6 mm.
1934 double target_size = 6.0; // mm
1935
1936 double basic_tool_size_mm = compass_size / GetDisplayDPmm();
1937 premult = target_size / basic_tool_size_mm;
1938 }
1939
1940 double postmult = exp(GUIScaleFactor * (0.693 / 5.0)); // exp(2)
1941
1942 rv = premult * postmult;
1943
1944 rv = wxMin(rv, 3.0); // Clamp at 3.0
1945 rv = wxMax(rv, 0.5);
1946
1947#if defined(__WXOSX__) || defined(__WXGTK3__)
1948 // Support scaled HDPI displays.
1949 if (gFrame)
1950 rv *= gFrame->GetContentScaleFactor();
1951#endif
1952
1953 rv /= g_BasePlatform->GetDisplayDIPMult(gFrame);
1954
1955#endif
1956
1957 return rv;
1958}
1959
1960float OCPNPlatform::GetChartScaleFactorExp(float scale_linear) {
1961 double factor = 1.0;
1962#ifndef __OCPN__ANDROID__
1963 factor = exp(scale_linear * (log(3.0) / 5.0));
1964
1965#else
1966 // the idea here is to amplify the scale factor for higher density displays,
1967 // in a measured way....
1968 factor = exp(scale_linear * (0.693 / 5.0));
1969// factor *= getAndroidDisplayDensity();
1970#endif
1971
1972 factor = wxMax(factor, .5);
1973 factor = wxMin(factor, 6.);
1974
1975 return factor;
1976}
1977
1978float OCPNPlatform::GetMarkScaleFactorExp(float scale_linear) {
1979 if(scale_linear <= 0)
1980 return GetChartScaleFactorExp(scale_linear);
1981 else
1982 return GetChartScaleFactorExp(scale_linear-1);
1983}
1984
1985// float OCPNPlatform::GetDIPScaleFactor() {
1986// float rv = 1.0;
1987// #ifdef __WXMSW__
1988// if (gFrame)
1989// rv = (double)(gFrame->FromDIP(100))/100.;
1990// #endif
1991//
1992// return rv;
1993// }
1994
1995//--------------------------------------------------------------------------
1996// Internal Bluetooth Support
1997//--------------------------------------------------------------------------
1998
1999bool OCPNPlatform::hasInternalBT(wxString profile) {
2000#ifdef __OCPN__ANDROID__
2001 bool t = androidDeviceHasBlueTooth();
2002 // qDebug() << "androidDeviceHasBluetooth" << t;
2003 return t;
2004#else
2005
2006 return false;
2007#endif
2008}
2009
2010bool OCPNPlatform::startBluetoothScan() {
2011#ifdef __OCPN__ANDROID__
2012 return androidStartBluetoothScan();
2013#else
2014
2015 return false;
2016#endif
2017}
2018
2019bool OCPNPlatform::stopBluetoothScan() {
2020#ifdef __OCPN__ANDROID__
2021 return androidStopBluetoothScan();
2022#else
2023
2024 return false;
2025#endif
2026}
2027
2028wxArrayString OCPNPlatform::getBluetoothScanResults() {
2029 wxArrayString ret_val;
2030#ifdef __OCPN__ANDROID__
2031 return androidGetBluetoothScanResults();
2032#else
2033
2034 ret_val.Add(_T("line 1"));
2035 ret_val.Add(_T("line 2"));
2036 ret_val.Add(_T("line 3"));
2037 return ret_val;
2038
2039#endif
2040}
2041
2042//--------------------------------------------------------------------------
2043// Per-Platform Utility support
2044//--------------------------------------------------------------------------
2045
2046bool OCPNPlatform::AllowAlertDialog(const wxString &class_name) {
2047#ifdef __OCPN__ANDROID__
2048 // allow if TopLevelWindow count is <=4, implying normal runtime screen
2049 // layout
2050 int nTLW = 0;
2051 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
2052 while (node) {
2053 wxWindow *win = node->GetData();
2054 if (win->IsShown()) nTLW++;
2055
2056 node = node->GetNext();
2057 }
2058
2059 // qDebug() << "AllowAlertDialog" << g_boptionsactive << g_running << nTLW;
2060 return (g_running && !g_boptionsactive && (nTLW <= 4));
2061
2062#else
2063 return true;
2064#endif
2065}
2066
2067void OCPNPlatform::setChartTypeMaskSel(int mask, wxString &indicator) {
2068#ifdef __OCPN__ANDROID__
2069 return androidSetChartTypeMaskSel(mask, indicator);
2070#endif
2071}
2072
2073#ifdef __OCPN__ANDROID__
2074QString g_qtStyleSheet;
2075
2076bool LoadQtStyleSheet(wxString &sheet_file) {
2077 if (wxFileExists(sheet_file)) {
2078 // QApplication qApp = getqApp();
2079 if (qApp) {
2080 QString file(sheet_file.c_str());
2081 QFile File(file);
2082 File.open(QFile::ReadOnly);
2083 g_qtStyleSheet = QLatin1String(File.readAll());
2084
2085 // qApp->setStyleSheet(g_qtStyleSheet);
2086 return true;
2087 } else
2088 return false;
2089 } else
2090 return false;
2091}
2092
2093QString getQtStyleSheet(void) { return g_qtStyleSheet; }
2094
2095#endif
2096
2097
2098bool OCPNPlatform::isPlatformCapable(int flag) {
2099#ifndef __OCPN__ANDROID__
2100 return true;
2101#else
2102 if (flag == PLATFORM_CAP_PLUGINS) {
2103 long platver;
2104 wxString tsdk(android_plat_spc.msdk);
2105 if (tsdk.ToLong(&platver)) {
2106 if (platver >= 11) return true;
2107 }
2108 } else if (flag == PLATFORM_CAP_FASTPAN) {
2109 long platver;
2110 wxString tsdk(android_plat_spc.msdk);
2111 if (tsdk.ToLong(&platver)) {
2112 if (platver >= 14) return true;
2113 }
2114 }
2115
2116 return false;
2117#endif
2118}
2119
2120void OCPNPlatform::DoHelpDialog(void) {
2121#ifndef __OCPN__ANDROID__
2122 if (!g_pAboutDlg) {
2123 g_pAboutDlg = new AboutFrameImpl(gFrame);
2124 } else {
2125 g_pAboutDlg->SetFocus();
2126 }
2127 g_pAboutDlg->Show();
2128
2129#else
2130 if (!g_pAboutDlgLegacy)
2131 g_pAboutDlgLegacy = new about(gFrame, GetSharedDataDir());
2132 else
2133 g_pAboutDlgLegacy->SetFocus();
2134 g_pAboutDlgLegacy->Show();
2135
2136#endif
2137}
2138
2139void OCPNPlatform::LaunchLocalHelp(void) {
2140#ifdef __OCPN__ANDROID__
2141 androidLaunchHelpView();
2142#else
2143 wxString def_lang_canonical = _T("en_US");
2144
2145#if wxUSE_XLOCALE
2146 if (plocale_def_lang)
2147 def_lang_canonical = plocale_def_lang->GetCanonicalName();
2148#endif
2149
2150 wxString help_locn = g_Platform->GetSharedDataDir() + _T("doc/help_");
2151
2152 wxString help_try = help_locn + def_lang_canonical + _T(".html");
2153
2154 if (!::wxFileExists(help_try)) {
2155 help_try = help_locn + _T("en_US") + _T(".html");
2156
2157 if (!::wxFileExists(help_try)) {
2158 help_try = help_locn + _T("web") + _T(".html");
2159 }
2160
2161 if (!::wxFileExists(help_try)) return;
2162 }
2163
2164 wxLaunchDefaultBrowser(wxString(_T("file:///")) + help_try);
2165#endif
2166}
2167
2168void OCPNPlatform::platformLaunchDefaultBrowser(wxString URL) {
2169#ifdef __OCPN__ANDROID__
2170 androidLaunchBrowser(URL);
2171#else
2172 ::wxLaunchDefaultBrowser(URL);
2173#endif
2174}
2175
2176// ============================================================================
2177// OCPNColourPickerCtrl implementation
2178// ============================================================================
2179
2180BEGIN_EVENT_TABLE(OCPNColourPickerCtrl, wxButton)
2181#ifdef __WXMSW__
2182EVT_PAINT(OCPNColourPickerCtrl::OnPaint)
2183#endif
2184END_EVENT_TABLE()
2185
2186// ----------------------------------------------------------------------------
2187// OCPNColourPickerCtrl
2188// ----------------------------------------------------------------------------
2189
2190OCPNColourPickerCtrl::OCPNColourPickerCtrl(wxWindow *parent, wxWindowID id,
2191 const wxColour &initial,
2192 const wxPoint &pos,
2193 const wxSize &size, long style,
2194 const wxValidator &validator,
2195 const wxString &name) {
2196 Create(parent, id, initial, pos, size, style, validator, name);
2197}
2198
2199bool OCPNColourPickerCtrl::Create(wxWindow *parent, wxWindowID id,
2200 const wxColour &col, const wxPoint &pos,
2201 const wxSize &size, long style,
2202 const wxValidator &validator,
2203 const wxString &name) {
2204 m_bitmap = wxBitmap(60, 13);
2205
2206 // create this button
2207 if (!wxBitmapButton::Create(parent, id, m_bitmap, pos, size,
2208 style | wxBU_AUTODRAW, validator, name)) {
2209 wxFAIL_MSG(wxT("OCPNColourPickerCtrl creation failed"));
2210 return false;
2211 }
2212
2213 // and handle user clicks on it
2214 Connect(GetId(), wxEVT_BUTTON,
2215 wxCommandEventHandler(OCPNColourPickerCtrl::OnButtonClick), NULL,
2216 this);
2217
2218 m_colour = col;
2219 UpdateColour();
2220 InitColourData();
2221
2222 return true;
2223}
2224
2225void OCPNColourPickerCtrl::InitColourData() {
2226#if 0
2227 ms_data.SetChooseFull(true);
2228 unsigned char grey = 0;
2229 for (int i = 0; i < 16; i++, grey += 16)
2230 {
2231 // fill with grey tones the custom colors palette
2232 wxColour colour(grey, grey, grey);
2233 ms_data.SetCustomColour(i, colour);
2234 }
2235#endif
2236}
2237
2238void OCPNColourPickerCtrl::OnButtonClick(wxCommandEvent &WXUNUSED(ev)) {
2239#ifdef __OCPN__ANDROID__
2240 unsigned int cco = 0;
2241 cco |= 0xff;
2242 cco = cco << 8;
2243 cco |= m_colour.Red();
2244 cco = cco << 8;
2245 cco |= m_colour.Green();
2246 cco = cco << 8;
2247 cco |= m_colour.Blue();
2248 unsigned int cc = androidColorPicker(cco);
2249
2250 wxColour cnew;
2251 unsigned char blue = (unsigned char)cc % 256;
2252 unsigned char green = (unsigned char)(cc >> 8) % 256;
2253 ;
2254 unsigned char red = (unsigned char)(cc >> 16) % 256;
2255 cnew.Set(red, green, blue);
2256
2257 SetColour(cnew);
2258
2259#else
2260 // update the wxColouData to be shown in the dialog
2261 ms_data.SetColour(m_colour);
2262
2263 // create the colour dialog and display it
2264 wxColourDialog dlg(this, &ms_data);
2265 if (dlg.ShowModal() == wxID_OK) {
2266 ms_data = dlg.GetColourData();
2267 SetColour(ms_data.GetColour());
2268 }
2269#endif
2270}
2271
2272void OCPNColourPickerCtrl::UpdateColour() {
2273#ifndef __OCPN__ANDROID__
2274 SetBitmapLabel(wxBitmap());
2275#endif
2276
2277 wxMemoryDC dc(m_bitmap);
2278 dc.SetPen(*wxTRANSPARENT_PEN);
2279 dc.SetBrush(wxBrush(m_colour));
2280 dc.DrawRectangle(0, 0, m_bitmap.GetWidth(), m_bitmap.GetHeight());
2281
2282 dc.SelectObject(wxNullBitmap);
2283 SetBitmapLabel(m_bitmap);
2284}
2285
2286void OCPNColourPickerCtrl::SetColour(wxColour &c) {
2287 m_colour = c;
2288 m_bitmap = wxBitmap(GetSize().x - 20, GetSize().y - 20);
2289 UpdateColour();
2290}
2291
2292wxColour OCPNColourPickerCtrl::GetColour(void) { return m_colour; }
2293
2294wxSize OCPNColourPickerCtrl::DoGetBestSize() const {
2295 wxSize sz(wxBitmapButton::DoGetBestSize());
2296#ifdef __WXMAC__
2297 sz.y += 6;
2298#else
2299 sz.y += 2;
2300#endif
2301 sz.x += 30;
2302 if (HasFlag(wxCLRP_SHOW_LABEL)) return sz;
2303
2304 // if we have no label, then make this button a square
2305 // (like e.g. native GTK version of this control) ???
2306 // sz.SetWidth(sz.GetHeight());
2307 return sz;
2308}
2309
2310void OCPNColourPickerCtrl::OnPaint(wxPaintEvent &event) {
2311 wxPaintDC dc(this);
2312
2313 int offset_x = (GetSize().x - m_bitmap.GetWidth()) / 2;
2314 int offset_y = (GetSize().y - m_bitmap.GetHeight()) / 2;
2315
2316 dc.SetPen(*wxTRANSPARENT_PEN);
2317 dc.SetBrush(wxBrush(m_colour));
2318 dc.DrawRectangle(offset_x, offset_y, m_bitmap.GetWidth(),
2319 m_bitmap.GetHeight());
2320
2321 event.Skip();
2322}
wxString GetWinPluginBaseDir()
Base directory for user writable windows plugins, reflects winPluginDir option, defaults to LOCALAPPD...
Definition: ocpn_app.h:44
std::string Homedir() const
home directory, convenience stuff.
Definition: plugin_paths.h:38
std::string UserDatadir()
The single, user-writable common parent for plugin data directories, typically ending in 'plugins'.
Definition: plugin_paths.h:23
static PluginPaths * getInstance()
Return the singleton instance.
Definition: select.h:51
Definition: about.h:48