diff --git a/.gitignore b/.gitignore index 47e49d7cff..0b32965e5a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ buildwin/NSIS_Unicode/Include/Langstrings_*.nsh buildwin/crashrpt/CrashRpt1402.dll buildwin/crashrpt/CrashSender1402.exe buildwin/configdev.bat +build-* cache +cmake-build-* crowdin.yaml cscope.files cscope.out diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d82c43776..724f29410a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -784,6 +784,7 @@ set(GUI_HDRS ${GUI_HDR_DIR}/GoToPositionDialog.h ${GUI_HDR_DIR}/gshhs.h ${GUI_HDR_DIR}/gui_lib.h + ${GUI_HDR_DIR}/hotkeys_dlg.h ${GUI_HDR_DIR}/IDX_entry.h ${GUI_HDR_DIR}/iENCToolbar.h ${GUI_HDR_DIR}/kml.h @@ -903,6 +904,7 @@ set(GUI_SRC ${GUI_SRC_DIR}/GoToPositionDialog.cpp ${GUI_SRC_DIR}/gshhs.cpp ${GUI_SRC_DIR}/gui_lib.cpp + ${GUI_SRC_DIR}/hotkeys_dlg.cpp ${GUI_SRC_DIR}/IDX_entry.cpp ${GUI_SRC_DIR}/iENCToolbar.cpp ${GUI_SRC_DIR}/kml.cpp @@ -911,11 +913,12 @@ set(GUI_SRC ${GUI_SRC_DIR}/load_errors_dlg.cpp ${GUI_SRC_DIR}/MarkInfo.cpp ${GUI_SRC_DIR}/mbtiles/mbtiles.cpp - ${GUI_SRC_DIR}/mbtiles/WorkerThread.cpp - ${GUI_SRC_DIR}/mbtiles/WorkerThread.hpp - ${GUI_SRC_DIR}/mbtiles/TileQueue.hpp - ${GUI_SRC_DIR}/mbtiles/TileDescriptor.hpp - ${GUI_SRC_DIR}/mbtiles/TileCache.hpp + ${GUI_SRC_DIR}/mbtiles/tile_thread.cpp + ${GUI_SRC_DIR}/mbtiles/tile_thread.h + ${GUI_SRC_DIR}/mbtiles/tile_queue.h + ${GUI_SRC_DIR}/mbtiles/tile_descr.h + ${GUI_SRC_DIR}/mbtiles/tile_cache.h + ${GUI_SRC_DIR}/mbtiles/tile_cache.cpp ${GUI_SRC_DIR}/MUIBar.cpp ${GUI_SRC_DIR}/navutil.cpp ${GUI_SRC_DIR}/NMEALogWindow.cpp @@ -1467,6 +1470,9 @@ target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::tinyxml) message(STATUS " Adding local wxserverdisc") add_subdirectory(libs/wxservdisc) +add_subdirectory(libs/manual) +target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::manual) + if (MSVC) install(FILES "cache/buildwin/libssl-3.dll" DESTINATION ".") install(FILES "cache/buildwin/libcrypto-3.dll" DESTINATION ".") diff --git a/gui/include/gui/glChartCanvas.h b/gui/include/gui/glChartCanvas.h index 8390faad69..0660047ee2 100644 --- a/gui/include/gui/glChartCanvas.h +++ b/gui/include/gui/glChartCanvas.h @@ -25,6 +25,32 @@ #ifndef __GLCHARTCANVAS_H__ #define __GLCHARTCANVAS_H__ +// We need to set up our openGL environment before including +// glcanvas.h which includes GL/gl.h +#ifdef __ANDROID__ +#include +#include // this is a cut-down version of gl.h +#include + +#elif defined(ocpnUSE_GL) +#if defined(__MSVC__) +#include "glew.h" + +#elif defined(__WXOSX__) +#include +#include +typedef void (*_GLUfuncptr)(); +#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 + +#elif defined(__WXQT__) || defined(__WXGTK__) +#include +#include + +#else +# error platform not supported. +#endif // __ANDROID__ +#endif // ocpnUSE_GL + #include #include "dychart.h" diff --git a/gui/include/gui/hotkeys_dlg.h b/gui/include/gui/hotkeys_dlg.h new file mode 100644 index 0000000000..8aafddf212 --- /dev/null +++ b/gui/include/gui/hotkeys_dlg.h @@ -0,0 +1,34 @@ +/************************************************************************** + * Copyright (C) 2024 Alec Leamas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + **************************************************************************/ + +#ifndef HOTKEYS_DLG_H_ +#define HOTKEYS_DLG_H_ + +#include +#include + +/** + * Modal dialog displaying hotkeys. + */ +class HotkeysDlg : public wxDialog { +public: + HotkeysDlg(wxWindow* parent); +}; + +#endif // HOTKEYS_DLG_H diff --git a/gui/include/gui/mbtiles.h b/gui/include/gui/mbtiles.h index 8849846123..09dd9ae333 100644 --- a/gui/include/gui/mbtiles.h +++ b/gui/include/gui/mbtiles.h @@ -1,10 +1,4 @@ -/****************************************************************************** - * - * Project: OpenCPN - * Purpose: MBTiles Chart Support - * Author: David Register - * - *************************************************************************** +/*************************************************************************** * Copyright (C) 2018 by David S. Register * * * * This program is free software; you can redistribute it and/or modify * @@ -21,144 +15,183 @@ * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - *************************************************************************** - * - * - */ + ***************************************************************************/ #ifndef _CHARTMBTILES_H_ #define _CHARTMBTILES_H_ #include +#include + #include "chartbase.h" #include "model/georef.h" // for GeoRef type #include "OCPNRegion.h" +#include "ocpn_pixel.h" #include "viewport.h" -#include "TileDescriptor.hpp" -#include "WorkerThread.hpp" -#include "TileCache.hpp" - -enum class MBTilesType : std::int8_t { BASE, OVERLAY }; -enum class MBTilesScheme : std::int8_t { XYZ, TMS }; +#include "tile_descr.h" +#include "tile_thread.h" +#include "tile_cache.h" -class WXDLLEXPORT ChartMbTiles; - -//----------------------------------------------------------------------------- -// Constants, etc. -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Fwd Refs -//----------------------------------------------------------------------------- - -class ViewPort; -class PixelCache; -class ocpnBitmap; -class mbTileDescriptor; - -namespace SQLite { -class Database; -} +#ifdef ocpnUSE_GL +#include "shaders.h" +#endif -class GLShaderProgram; -class MbtTilesThread; -//----------------------------------------------------------------------------- -// Helper classes -//----------------------------------------------------------------------------- +/** The type of a MBTiles chart. */ +enum class MbTilesType : std::int8_t { + BASE, ///< Base map, providing the primary chart imagery + OVERLAY ///< Overlay map, adding additional information on top of a base map +}; -// ---------------------------------------------------------------------------- -// ChartMBTiles -// ---------------------------------------------------------------------------- +/** The tile scheme used in the MBTiles chart. */ +enum class MbTilesScheme : std::int8_t { + XYZ, ///< "Slippy Map" tilenames. Origin at top-left, Y increases + /// southward. + TMS ///< Tile Map Service scheme. Origin at bottom-left, Y increases + /// northward. +}; -class ChartMBTiles : public ChartBase { +/** + * Represents an MBTiles format chart. + * + * Provides functionality to load, render, and interact with MBTiles format + * charts. MBTiles stores tiled map data in SQLite databases for efficient + * storage and retrieval. + * + * An MBTiles chart consists of: + * + * - A set of image tiles at various zoom levels. + * - Metadata about the tileset (e.g., attribution, description). + * - An SQLite database structure for organizing and accessing tiles. + * + * Handles tile management, caching, and rendering for efficient + * display of large tiled datasets, supporting both XYZ and TMS tile schemes. + */ +class ChartMbTiles : public ChartBase { public: - // Public methods - - ChartMBTiles(); - virtual ~ChartMBTiles(); + ChartMbTiles(); + virtual ~ChartMbTiles(); // Accessors - virtual ThumbData *GetThumbData(int tnx, int tny, float lat, float lon); - virtual ThumbData *GetThumbData(); + + /** + * Get the Chart thumbnail data structure, + * creating the thumbnail bitmap as required + */ + virtual ThumbData* GetThumbData(int tnx, int tny, float lat, float lon); + virtual ThumbData* GetThumbData(); virtual bool UpdateThumbData(double lat, double lon); - virtual bool AdjustVP(ViewPort &vp_last, ViewPort &vp_proposed); + virtual bool AdjustVP(ViewPort& vp_last, ViewPort& vp_proposed); int GetNativeScale() { return m_Chart_Scale; } + + /** + * Report recommended minimum scale values for which use of this + * chart is valid + */ double GetNormalScaleMin(double canvas_scale_factor, bool b_allow_overzoom); + + /** + * Report recommended maximum scale values for which use of this + * chart is valid + */ double GetNormalScaleMax(double canvas_scale_factor, int canvas_width); - virtual InitReturn Init(const wxString &name, ChartInitFlag init_flags); + virtual InitReturn Init(const wxString& name, ChartInitFlag init_flags); - bool RenderRegionViewOnDC(wxMemoryDC &dc, const ViewPort &VPoint, - const OCPNRegion &Region); + bool RenderRegionViewOnDC(wxMemoryDC& dc, const ViewPort& VPoint, + const OCPNRegion& Region); - virtual bool RenderRegionViewOnGL(const wxGLContext &glc, - const ViewPort &VPoint, - const OCPNRegion &RectRegion, - const LLRegion &Region); + virtual bool RenderRegionViewOnGL(const wxGLContext& glc, + const ViewPort& vpoint, + const OCPNRegion& rect_region, + const LLRegion& region); virtual double GetNearestPreferredScalePPM(double target_scale_ppm); - virtual void GetValidCanvasRegion(const ViewPort &VPoint, - OCPNRegion *pValidRegion); + virtual void GetValidCanvasRegion(const ViewPort& v_point, + OCPNRegion* valid_region); virtual LLRegion GetValidRegion(); - virtual bool GetChartExtent(Extent *pext); + virtual bool GetChartExtent(Extent* pext); void SetColorScheme(ColorScheme cs, bool bApplyImmediate); double GetPPM() { return m_ppm_avg; } - double GetZoomFactor() { return m_zoomScaleFactor; } - MBTilesType GetTileType() { return m_TileType; } + double GetZoomFactor() { return m_zoom_scale_factor; } + MbTilesType GetTileType() { return m_tile_type; } protected: // Methods - bool RenderViewOnDC(wxMemoryDC &dc, const ViewPort &VPoint); - InitReturn PreInit(const wxString &name, ChartInitFlag init_flags, + bool RenderViewOnDC(wxMemoryDC& dc, const ViewPort& VPoint); + InitReturn PreInit(const wxString& name, ChartInitFlag init_flags, ColorScheme cs); InitReturn PostInit(void); void PrepareTiles(); void PrepareTilesForZoom(int zoomFactor, bool bset_geom); - bool getTileTexture(mbTileDescriptor *tile); + + /** + * Loads a tile into OpenGL's texture memory for rendering. If the tile + * is not ready to be rendered (i.e. the tile has not been loaded from + * disk or ndecompressed to memory), the function sends a request to + * the worker thread which will do this later in the background + * @param tile Pointer to the tile descriptor to be prepared + * @return true if the tile is ready to be rendered, false else. + */ + bool GetTileTexture(SharedTilePtr tile); void FlushTiles(void); - bool RenderTile(mbTileDescriptor *tile, int zoomLevel, - const ViewPort &VPoint); + bool RenderTile(SharedTilePtr tile, int zoom_level, const ViewPort& vpoint); // Protected Data - float m_LonMax, m_LonMin, m_LatMax, m_LatMin; + float m_lon_max; + float m_lon_min; + float m_lat_max; + float m_lat_min; double m_ppm_avg; // Calculated true scale factor of the 1X chart, // pixels per meter - MBTilesType m_TileType; + MbTilesType m_tile_type; int m_b_cdebug; - int m_minZoom, m_maxZoom; - TileCache *m_tileCache; - LLRegion m_minZoomRegion; - wxBitmapType m_imageType; + int m_min_zoom; + int m_max_zoom; + std::unique_ptr m_tile_cache; + LLRegion m_min_zoom_region; + wxBitmapType m_image_type; int m_last_clean_zoom; - double m_zoomScaleFactor; + double m_zoom_scale_factor; - MBTilesScheme m_Scheme; + MbTilesScheme m_scheme; - SQLite::Database *m_pDB; - int m_nTiles; + std::shared_ptr m_db; + int m_n_tiles; std::string m_format; - GLShaderProgram *m_tile_shader_program; - uint32_t m_tileCount; - MbtTilesThread *m_workerThread; + uint32_t m_tile_count; + std::unique_ptr m_worker_thread; + std::thread m_thread; + +#ifdef ocpnUSE_GL + GLShaderProgram* m_tile_shader_program; +#endif + + /** + * Create and start the worker thread. This thread is dedicated at + * loading and decompressing chart tiles into memory, in the background. If + * for any reason the thread would fail to load, the method return false + */ bool StartThread(); + + /** Stop and delete the worker thread. Called when OpenCPN is quitting. */ void StopThread(); private: - void InitFromTiles(const wxString &name); - wxPoint2DDouble GetDoublePixFromLL(ViewPort &vp, double lat, double lon); + void InitFromTiles(const wxString& name); + wxPoint2DDouble GetDoublePixFromLL(ViewPort& vp, double lat, double lon); }; #endif diff --git a/gui/src/chartdb.cpp b/gui/src/chartdb.cpp index 11db20480f..ea8d31dd7c 100644 --- a/gui/src/chartdb.cpp +++ b/gui/src/chartdb.cpp @@ -420,7 +420,7 @@ ChartBase *ChartDB::GetChart(const wxChar *theFilePath, } else if (chartExt == wxT("GEO")) { pch = new ChartGEO; } else if (chartExt == wxT("MBTILES")) { - pch = new ChartMBTiles; + pch = new ChartMbTiles; } else if (chartExt == wxT("000") || chartExt == wxT("S57")) { LoadS57(); pch = new s57chart; @@ -1175,7 +1175,7 @@ ChartBase *ChartDB::OpenChartUsingCache(int dbindex, ChartInitFlag init_flag) { Ch = new ChartGEO(); else if (chart_type == CHART_TYPE_MBTILES) - Ch = new ChartMBTiles(); + Ch = new ChartMbTiles(); else if (chart_type == CHART_TYPE_S57) { LoadS57(); diff --git a/gui/src/chartdbs.cpp b/gui/src/chartdbs.cpp index 0a814f40b2..4dd15a1fa6 100644 --- a/gui/src/chartdbs.cpp +++ b/gui/src/chartdbs.cpp @@ -1091,7 +1091,7 @@ void ChartDatabase::UpdateChartClassDescriptorArray(void) { m_ChartClassDescriptorArray.push_back(ChartClassDescriptor( _T("cm93compchart"), _T("00300000.a"), BUILTIN_DESCRIPTOR)); m_ChartClassDescriptorArray.push_back(ChartClassDescriptor( - _T("ChartMBTiles"), _T("*.mbtiles"), BUILTIN_DESCRIPTOR)); + _T("ChartMbTiles"), _T("*.mbtiles"), BUILTIN_DESCRIPTOR)); } // If the PlugIn Manager exists, get the array of dynamically loadable // chart class names diff --git a/gui/src/chcanv.cpp b/gui/src/chcanv.cpp index 90a31f1557..cc809bca60 100644 --- a/gui/src/chcanv.cpp +++ b/gui/src/chcanv.cpp @@ -70,6 +70,7 @@ #include "compass.h" #include "concanv.h" #include "displays.h" +#include "hotkeys_dlg.h" #include "FontMgr.h" #include "glTextureDescriptor.h" #include "gshhs.h" @@ -2590,7 +2591,19 @@ void ChartCanvas::OnKeyChar(wxKeyEvent &event) { // anything else int key_char = event.GetKeyCode(); - + switch (key_char) { + case '?': + HotkeysDlg(wxWindow::FindWindowByName("MainWindow")).ShowModal(); + break; + case '+': + ZoomCanvas(g_plus_minus_zoom_factor, false); + break; + case '-': + ZoomCanvas(1.0 / g_plus_minus_zoom_factor, false); + break; + default: + break; + } if (g_benable_rotate) { switch (key_char) { case ']': @@ -2855,18 +2868,6 @@ void ChartCanvas::OnKeyDown(wxKeyEvent &event) { // Handle both QWERTY and AZERTY keyboard separately for a few control // codes if (!g_b_assume_azerty) { - switch (key_char) { - case '+': - case '=': - ZoomCanvas(g_plus_minus_zoom_factor, false); - break; - - case '-': - case '_': - ZoomCanvas(1.0 / g_plus_minus_zoom_factor, false); - break; - } - #ifdef __WXMAC__ if (g_benable_rotate) { switch (key_char) { @@ -11823,7 +11824,7 @@ emboss_data *ChartCanvas::EmbossOverzoomIndicator(ocpnDC &dc) { ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType(); if (current_type == CHART_TYPE_MBTILES) { ChartBase *pChart = m_pQuilt->GetRefChart(); - ChartMBTiles *ptc = dynamic_cast(pChart); + ChartMbTiles *ptc = dynamic_cast(pChart); if (ptc) { zoom_factor = ptc->GetZoomFactor(); } diff --git a/gui/src/glChartCanvas.cpp b/gui/src/glChartCanvas.cpp index 73d59ef22d..ee0ab11d55 100644 --- a/gui/src/glChartCanvas.cpp +++ b/gui/src/glChartCanvas.cpp @@ -4564,12 +4564,12 @@ void glChartCanvas::RenderSingleMBTileOverlay(const int dbIndex, bool bOverlay, // other reason... if (chart == NULL) return; - ChartMBTiles *pcmbt = dynamic_cast(chart); + ChartMbTiles *pcmbt = dynamic_cast(chart); if (!pcmbt) return; // Is tile an OVERLAY type? // Render, or not, depending on passed flag. - if (bOverlay && pcmbt->GetTileType() != MBTilesType::OVERLAY) return; + if (bOverlay && pcmbt->GetTileType() != MbTilesType::OVERLAY) return; wxFileName tileFile(chart->GetFullPath()); // Size test for 5 GByte diff --git a/gui/src/hotkeys_dlg.cpp b/gui/src/hotkeys_dlg.cpp new file mode 100644 index 0000000000..040501b6f6 --- /dev/null +++ b/gui/src/hotkeys_dlg.cpp @@ -0,0 +1,152 @@ +/************************************************************************** + * Copyright (C) 2024 Alec Leamas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + **************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ocpn_plugin.h" + +#include "hotkeys_dlg.h" +#include "manual.h" + +static inline wxString U8(const char* s) { return wxString::FromUTF8(s); } + +/** Two buttons at bottom */ +class ButtonsSizer : public wxStdDialogButtonSizer { +public: + /** The "Browse manual" button */ + class ManualButton : public wxButton { + public: + ManualButton(wxWindow* parent) + : wxButton(parent, wxID_OK, _("Browse manual")) { + Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](wxCommandEvent) { + wxString datadir = GetPluginDataDir("manual_pi"); + Manual(this, datadir.ToStdString()).Launch("Hotkeys"); + }); + } + }; + + /** The Close button */ + class CloseButton : public wxButton { + public: + CloseButton(wxDialog* parent) : wxButton(parent, wxID_CLOSE) { + Bind(wxEVT_COMMAND_BUTTON_CLICKED, + [parent](wxCommandEvent) { parent->EndModal(wxID_OK); }); + }; + }; + + ButtonsSizer(wxDialog* parent) : wxStdDialogButtonSizer() { + AddButton(new ManualButton(parent)); + AddButton(new CloseButton(parent)); + Realize(); + }; +}; + +/** Overall help message: key functions and bindings in a string matrix */ +class GridSizer : public wxGridSizer { +public: + GridSizer(wxWindow* parent) : wxGridSizer(kMacMessages[0].size()) { + const auto osSystemId = wxPlatformInfo::Get().GetOperatingSystemId(); + const auto& kMessages = + (osSystemId & wxOS_MAC) ? kMacMessages : kWinLinuxMessages; + for (auto line = kMessages.begin(); line != kMessages.end(); line++) { + for (auto word = line->begin(); word != line->end(); word++) { + Add(new wxStaticText(parent, wxID_ANY, *word), + wxSizerFlags().DoubleBorder()); + } + } + } + +private: + // It's unclear whether _() actually works in this context or + // if wxTRANSLATE is needed instead... + const std::array, 12> kWinLinuxMessages{ + // clang-format off + {{_("Zoom in"), "+, PgUp", + _("Zoom out"), "-, PgDown"}, + {_("Fine zoom in"), "Alt +", + _("Fine zoom out"), "Alt -"}, + {_("Fine zoom"), _("Ctrl scroll-wheel"), + "", ""}, + {_("Panning"), U8("→ ← ↑ ↓") + , _("Slow panning"), U8("Alt → ← ↑ ↓")}, + {_("Larger scale chart"), U8("Ctrl ←, F7"), + _("Smaller scale chart"), U8("Ctrl →, F8")}, + {_("Toggle quilting "), "Q, F9", + _("Toggle auto-follow"), "Ctrl A, F2"}, + {_("Toggle outlines"), "O, F12", + _("Toggle range rings"), "R"}, + {_("Toggle chart bar"), "Ctrl B", + _("Change color scheme"), "Ctrl-G, F5"}, + {_("Toggle full screen"), "F11", + "", ""}, + {"", "", "", ""}, + {_("Start measure mode"), "M, F4", + _("Stop measure mode"), "Esc"}, + {_("Drop mark"), _("Ctrl O, space bar"), + "", ""}}}; + + const std::array, 12> kMacMessages{ + {{_("Zoom in"), "+, PgUp", + _("Zoom out"), "-, PgDown"}, + {_("Fine zoom in"), "Alt +", + _("Fine zoom out"), "Alt -"}, + {_("Fine zoom"), _("Ctrl scroll-wheel"), + "", ""}, + {_("Panning"), U8("→ ← ↑ ↓") + , _("Slow panning"), U8("Alt → ← ↑ ↓")}, + {_("Larger scale chart"), U8("Cmd ←, F7"), + _("Smaller scale chart"), U8("Cmd →, F8")}, + {_("Toggle quilting "), "Q, F9", + _("Toggle auto-follow"), "Cmd A"}, + {_("Toggle outlines"), "O, F12", + _("Toggle range rings"), "R"}, + {_("Toggle chart bar"), "Ctrl B", + _("Change color scheme"), "Ctrl-G, F5"}, + {_("Toggle full screen"), "Ctrl Cmd F", + "", ""}, + {"", "", "", ""}, + {_("Start measure mode"), "F4", + _("Stop measure mode"), "Esc"}, + {_("Drop mark"), _("Ctrl O, space bar"), + "", ""}}}; // clang-format on +}; + +HotkeysDlg::HotkeysDlg(wxWindow* parent) + : wxDialog(parent, wxID_ANY, _("Keyboard Shortcuts")) { + auto vbox = new wxBoxSizer(wxVERTICAL); + auto flags = wxSizerFlags().DoubleBorder(); + vbox->Add(new GridSizer(this), flags.Expand()); + vbox->Add(new wxStaticText(this, wxID_ANY, + _("More keys are available in the manual.")), + wxSizerFlags().DoubleBorder().Centre()); + vbox->Add(new ButtonsSizer(this), flags.Expand()); + SetSizer(vbox); + Fit(); + Layout(); + Bind(wxEVT_CLOSE_WINDOW, [&](wxCloseEvent&) { EndModal(wxID_OK); }); +} diff --git a/gui/src/mbtiles/TileCache.hpp b/gui/src/mbtiles/TileCache.hpp deleted file mode 100644 index 155f25eb24..0000000000 --- a/gui/src/mbtiles/TileCache.hpp +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef _TILECACHE_H_ -#define _TILECACHE_H_ - -#include "TileDescriptor.hpp" -#include - -/// @brief Class managing the tiles of a mbtiles file -class TileCache { - // Per zoomlevel descriptor of tile array for that zoomlevel - class ZoomDescriptor { - public: - int tile_x_min, tile_x_max; - int tile_y_min, tile_y_max; - }; - -private: - const double eps = 6e-6; // about 1cm on earth's surface at equator - std::unordered_map tileMap; - ZoomDescriptor *zoomTable; - int minZoom, maxZoom, nbZoom; - // Chained list parameters - -public: - TileCache(int minZoom, int maxZoom, float LonMin, float LatMin, float LonMax, - float LatMax) { - this->minZoom = minZoom; - this->maxZoom = maxZoom; - nbZoom = (maxZoom - minZoom) + 1; - zoomTable = new ZoomDescriptor[nbZoom]; - - // Compute cache coverage for every zoom level in WMTS coordinates - for (int i = 0; i < nbZoom; i++) { - int zoomFactor = minZoom + i; - zoomTable[i].tile_x_min = - mbTileDescriptor::long2tilex(LonMin + eps, zoomFactor); - zoomTable[i].tile_x_max = - mbTileDescriptor::long2tilex(LonMax - eps, zoomFactor); - zoomTable[i].tile_y_min = - mbTileDescriptor::lat2tiley(LatMin + eps, zoomFactor); - zoomTable[i].tile_y_max = - mbTileDescriptor::lat2tiley(LatMax - eps, zoomFactor); - } - } - - virtual ~TileCache() { delete[] zoomTable; } - - /// Return mutex to lock given tile. There is a fixed number of mutexes - /// available, the mutex returned might collide with another id causing - /// random serialization. - static std::mutex &GetMutex(uint64_t tile_id) { - static const int kMutexCount = 100; - static std::array mutexes; - return mutexes[tile_id % kMutexCount]; - } - - static std::mutex &GetMutex(const mbTileDescriptor *tile) { - uint64_t key = mbTileDescriptor::GetMapKey(tile->m_zoomLevel, tile->tile_x, - tile->tile_y); - return TileCache::GetMutex(key); - } - - /// @brief Flush the tile cache, including OpenGL texture memory if needed - void Flush() { - for (auto const &it : tileMap) { - mbTileDescriptor *tile = it.second; - if (tile) { - // Note that all buffers are properly freed by the destructor, including - // OpenGL textures. It means that this function must only be called from - // the main rendering thread since OpenGL is not thread safe. - delete tile; - } - } - } - - // Get the north limit of the cache area for a given zoom in WMTS coordinates - int GetNorthLimit(int zoomLevel) { - return zoomTable[zoomLevel - minZoom].tile_y_max; - } - - // Get the south limit of the cache area for a given zoom in WMTS coordinates - int GetSouthLimit(int zoomLevel) { - return zoomTable[zoomLevel - minZoom].tile_y_min; - } - - /// @brief Get the current size of the cache in number of tiles - /// @return Number of tiles in the cache - uint32_t GetCacheSize() const { return tileMap.size(); } - - /// @brief Retreive a tile from the cache. If the tile is not present in the - /// cache, an empty tile is created and added. - /// @param z Zoom level of the tile - /// @param x x coordinate of the tile - /// @param y y coordinate of the tile - /// @return Pointer to the tile - mbTileDescriptor *GetTile(int z, int x, int y) { - uint64_t index = mbTileDescriptor::GetMapKey(z, x, y); - auto ref = tileMap.find(index); - if (ref != tileMap.end()) { - // The tile is in the cache - ref->second->SetTimestamp(); - return ref->second; - } - - // The tile is not in the cache : create an empty one and add it to the tile - // map and list - mbTileDescriptor *tile = new mbTileDescriptor(z, x, y); - tileMap[index] = tile; - return tile; - } - - /// @brief Reduce the size of the cache if it exceeds the given limit. To - /// reduce the size of the cache, the tiles at the end of the tile list are - /// deleted first (i.e. the least frequently used ones). This function must - /// only be called by rendering thread since it uses OpenGL calls. - /// @param maxTiles Maximum number of tiles to be kept in the list - void CleanCache(uint32_t maxTiles) { - if (tileMap.size() <= maxTiles) return; - - /** Create a sorted list of keys, oldest first. */ - std::vector keys; - for (auto &kv : tileMap) keys.push_back(kv.first); - auto compare = [&](const uint64_t lhs, const uint64_t rhs) { - return tileMap[lhs]->last_used < tileMap[rhs]->last_used; - }; - std::sort(keys.begin(), keys.end(), compare); - - for (size_t i = 0; i < tileMap.size() - maxTiles; i += 1) { - std::lock_guard lock(TileCache::GetMutex(tileMap[keys[i]])); - auto tile = tileMap[keys[i]]; - - // Do not remove tiles that may be pending in the worker thread queue - if (tile->m_bAvailable && !tile->glTextureName && !tile->m_teximage) - continue; - - tileMap.erase(keys[i]); - delete tile; - } - } - - void DeepCleanCache() { - using namespace std::chrono; - auto time_now = - duration_cast(system_clock::now().time_since_epoch()); - - auto age_limit = std::chrono::duration(5); // 5 seconds - - std::vector keys; - for (auto &kv : tileMap) keys.push_back(kv.first); - - for (size_t i = 0; i < keys.size(); i += 1) { - std::lock_guard lock(TileCache::GetMutex(tileMap[keys[i]])); - auto tile = tileMap[keys[i]]; - const std::chrono::duration elapsed_seconds{time_now - - tile->last_used}; - - // Looking for tiles that have been fetched from sql, - // but not yet rendered. Such tiles contain a large bitmap allocation. - // After some time, it is likely they never will be needed in short term. - // So safe to delete, and reload as necessary. - if (((!tile->glTextureName) && tile->m_teximage) && - (elapsed_seconds > age_limit)) { - tileMap.erase(keys[i]); - delete tile; - } - } - } -}; -#endif diff --git a/gui/src/mbtiles/TileDescriptor.hpp b/gui/src/mbtiles/TileDescriptor.hpp deleted file mode 100644 index a9a949820c..0000000000 --- a/gui/src/mbtiles/TileDescriptor.hpp +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef _MBTILES_TILEDESCRIPTOR_H_ -#define _MBTILES_TILEDESCRIPTOR_H_ - -#include -#include -#include -#include - -#include "chartbase.h" -#include "glChartCanvas.h" - -/// @brief Per tile descriptor -class mbTileDescriptor { -public: - int tile_x, tile_y; - int m_zoomLevel; - float latmin, lonmin, latmax, lonmax; - LLBBox box; - std::chrono::milliseconds last_used; - - // Set to true if a load request from main thread is already pending for this - // tile - bool m_requested; - // Pointer to the decompressed tile image - std::atomic m_teximage; - // Identifier of the tile texture in OpenGL memory - GLuint glTextureName; - // Set to true if the tile has not been found into the SQL database. - std::atomic m_bAvailable; - // Pointer to the previous element of the tile chained list - mbTileDescriptor *prev; - // Pointer to the next element of the tile chained list - mbTileDescriptor *next; - - mbTileDescriptor(int zoomFactor, int x, int y) { - glTextureName = 0; - m_bAvailable = true; - m_teximage = nullptr; - m_requested = false; - prev = nullptr; - next = nullptr; - tile_x = x; - tile_y = y; - m_zoomLevel = zoomFactor; - // Calculate tile boundaries - lonmin = - round(mbTileDescriptor::tilex2long(tile_x, zoomFactor) / eps) * eps; - lonmax = - round(mbTileDescriptor::tilex2long(tile_x + 1, zoomFactor) / eps) * eps; - latmin = - round(mbTileDescriptor::tiley2lat(tile_y - 1, zoomFactor) / eps) * eps; - latmax = round(mbTileDescriptor::tiley2lat(tile_y, zoomFactor) / eps) * eps; - - box.Set(latmin, lonmin, latmax, lonmax); - SetTimestamp(); - } - - virtual ~mbTileDescriptor() { - // Delete intermediate texture buffer if still allocated - if (m_teximage != nullptr) { - free(m_teximage); - } - // Delete OpenGL texture buffer if allocated - if (glTextureName > 0) { - glDeleteTextures(1, &glTextureName); - } - } - - /// @brief Generates a unique 64 bit key/identifier of a tile. This key can - /// be used to uniquely reference tiles in a unordered_map or other similar - /// list, with not risk of key collision up to zoom level 20 - /// @param z Zoom level of the tile - /// @param x x coordinate of the file - /// @param y y coordinate of the tile - /// @return Unique 64 bit key of the tile - static uint64_t GetMapKey(int z, int x, int y) { - return ((uint64_t)z << 40) | ((uint64_t)y << 20) | x; - } - - /// @brief Generates a unique 64 bit key/identifier of the tile. This key can - /// be used to uniquely reference tiles in a unordered_map or other similar - /// list, with not risk of key collision up to zoom level 20 - /// @return Unique 64 bit key of the tile - uint64_t GetMapKey() { - return mbTileDescriptor::GetMapKey(m_zoomLevel, tile_x, tile_y); - } - - static int long2tilex(double lon, int z) { - if (lon < -180) lon += 360; - - return (int)(floor((lon + 180.0) / 360.0 * (1 << z))); - } - - static int lat2tiley(double lat, int z) { - int y = (int)(floor( - (1.0 - - log(tan(lat * M_PI / 180.0) + 1.0 / cos(lat * M_PI / 180.0)) / M_PI) / - 2.0 * (1 << z))); - int ymax = 1 << z; - y = ymax - y - 1; - return y; - } - - static double tilex2long(int x, int z) { - return x / (double)(1 << z) * 360.0 - 180; - } - - static double tiley2lat(int y, int z) { - // double n = pow(2.0, z); - double n = 1 << z; - int ymax = 1 << z; - y = ymax - y - 1; - double latRad = atan(sinh(M_PI * (1 - (2 * y / n)))); - return 180.0 / M_PI * latRad; - } - - /** Update last_used to current time. */ - void SetTimestamp() { - using namespace std::chrono; - last_used = - duration_cast(system_clock::now().time_since_epoch()); - } - -private: - const double eps = 6e-6; // about 1cm on earth's surface at equator -}; - -#endif /* _MBTILES_TILEDESCRIPTOR_H_ */ diff --git a/gui/src/mbtiles/TileQueue.hpp b/gui/src/mbtiles/TileQueue.hpp deleted file mode 100644 index 77c5f9fa4a..0000000000 --- a/gui/src/mbtiles/TileQueue.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _MBTILESTILEQUEUE_H_ -#define _MBTILESTILEQUEUE_H_ - -#include -#include -#include - -#include "TileDescriptor.hpp" - -/// @brief Class implementing a thread safe tile queue between two thread -class TileQueue { -public: - TileQueue() {} - - /// @brief Push a tile to the queue. This method is thread safe - /// @param tile Pointer to the tile descriptor to be pushed. - void Push(mbTileDescriptor *tile) { - wxMutexLocker lock(m_queueMutex); - m_tileList.push_back(tile); - m_tileCounter.Post(); - } - - /// @brief Retreives a tile from the queue. If there is not tile in the queue, - /// the calling thread is blocked until a tile is pushed to the queue. This - /// method is thread safe. - /// @return A pointer to a tile descriptor - mbTileDescriptor *Pop() { - m_tileCounter.Wait(); - wxMutexLocker lock(m_queueMutex); - mbTileDescriptor *tile = m_tileList.at(0); - m_tileList.erase(m_tileList.cbegin()); - return tile; - } - - /// @brief Get current size of the queue. - /// @return Queue size in tiles - uint32_t GetSize() { - uint32_t size; - wxMutexLocker lock(m_queueMutex); - - size = m_tileList.size(); - - return size; - } - -private: - std::vector m_tileList; - wxMutex m_queueMutex; - wxSemaphore m_tileCounter; -}; - -#endif \ No newline at end of file diff --git a/gui/src/mbtiles/WorkerThread.hpp b/gui/src/mbtiles/WorkerThread.hpp deleted file mode 100644 index fffa31ab4d..0000000000 --- a/gui/src/mbtiles/WorkerThread.hpp +++ /dev/null @@ -1,76 +0,0 @@ - -#ifndef _MBTILESTHREAD_H_ -#define _MBTILESTHREAD_H_ - -#include -#include -#include - -#include "mbtiles.h" -#include "chartbase.h" -#include "ocpn_frame.h" -#include "ocpn_app.h" - -#include -#include - -#include "TileQueue.hpp" - -#ifdef __WXMSW__ -class SE_Exception { -private: - unsigned int nSE; - -public: - SE_Exception() {} - SE_Exception(unsigned int n) : nSE(n) {} - ~SE_Exception() {} - unsigned int getSeNumber() { return nSE; } -}; - -#endif - -/// @brief Worker thread of the MbTiles chart decoder. It receives requests from -/// the MbTile front-end to load and uncompress tiles from an MbTiles file. Once -/// done, the tile list in memory is updated and a refresh of the map triggered. -class MbtTilesThread : public wxThread { -public: - /// @brief Create the instance of the worker thread - /// @param pDB Pointer to the SQL database handler - MbtTilesThread(SQLite::Database *pDB) - : wxThread(wxTHREAD_DETACHED), - m_exitThread(false), - m_finished(false), - m_pDB(pDB) {} - - virtual ~MbtTilesThread() {} - - /// @brief Request a tile to be loaded by the thread. This method is thread - /// safe. - /// @param tile Pointer to the tile to load - void RequestTile(mbTileDescriptor *tile); - - /// @brief Request the thread to stop/delete itself - void RequestStop(); - size_t GetQueueSize(); - -private: - // Set to true to tell the main loop to stop execution - bool m_exitThread; - // Set to true when the thread has finished - bool m_finished; - // The queue storing all the tile requests - TileQueue m_tileQueue; - // Pointer the SQL object managing the MbTiles file - SQLite::Database *m_pDB; - - /// @brief Main loop of the worker thread - /// @return Always 0 - virtual ExitCode Entry(); - - /// @brief Load bitmap data of a tile from the MbTiles file to the tile cache - /// @param tile Pointer to the tile to be loaded - void LoadTile(mbTileDescriptor *tile); -}; - -#endif /* _MBTILESTHREAD_H_ */ diff --git a/gui/src/mbtiles/mbtiles.cpp b/gui/src/mbtiles/mbtiles.cpp index af45c3dceb..2dbb98a184 100644 --- a/gui/src/mbtiles/mbtiles.cpp +++ b/gui/src/mbtiles/mbtiles.cpp @@ -1,10 +1,5 @@ -/****************************************************************************** - * - * Project: OpenCPN - * Purpose: MBTiles chart type support - * Author: David Register - * - *************************************************************************** + +/************************************************************************** * Copyright (C) 2018 by David S. Register * * * * This program is free software; you can redistribute it and/or modify * @@ -21,17 +16,11 @@ * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - *************************************************************************** - * - */ - -// ============================================================================ -// declarations -// ============================================================================ + ***************************************************************************/ -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- +#include +#include +#include // For compilers that support precompilation, includes "wx.h". #include @@ -50,9 +39,6 @@ #include #include #include -#include -#include -#include #include //We need some defines #include @@ -80,16 +66,16 @@ typedef unsigned __int64 uint64_t; #if !defined(NAN) static const long long lNaN = 0xfff8000000000000; -#define NAN (*(double *)&lNaN) +#define NAN (*(double*)&lNaN) #endif #ifdef OCPN_USE_CONFIG -class MyConfig; -extern MyConfig *pConfig; +#include "navutil.h" +extern MyConfig* pConfig; #endif -// Raster Zoom Modifier value from advanced display preference pane -// Physically located in ocpn_app.cpp +/// Raster Zoom Modifier value from advanced display preference pane +/// Physically located in ocpn_app.cpp extern int g_chart_zoom_modifier_raster; #define LON_UNDEF NAN @@ -97,17 +83,15 @@ extern int g_chart_zoom_modifier_raster; // A "nominal" scale value, by zoom factor. Estimated at equator, with monitor // pixel size of 0.3mm -static double OSM_zoomScale[22]; +static double osm_zoom_scale[22]; // Meters per pixel, by zoom factor -static double OSM_zoomMPP[22]; +static double osm_zoom_mpp[22]; -extern MyFrame *gFrame; - -static const double eps = 6e-6; // about 1cm on earth's surface at equator +extern MyFrame* gFrame; // Private tile shader source -static const GLchar *tile_vertex_shader_source = +static const GLchar* tile_vertex_shader_source = "attribute vec2 aPos;\n" "attribute vec2 aUV;\n" "uniform mat4 MVMatrix;\n" @@ -117,7 +101,7 @@ static const GLchar *tile_vertex_shader_source = " varCoord = aUV;\n" "}\n"; -static const GLchar *tile_fragment_shader_source = +static const GLchar* tile_fragment_shader_source = "precision lowp float;\n" "uniform sampler2D uTex;\n" "varying vec2 varCoord;\n" @@ -127,7 +111,9 @@ static const GLchar *tile_fragment_shader_source = " gl_FragColor = vec4(textureColor.rgb * brightness, textureColor.w);\n" "}\n"; -GLShaderProgram *g_tile_shader_program; +#ifdef ocpnUSE_GL +GLShaderProgram* g_tile_shader_program; +#endif #if defined(__UNIX__) && \ !defined(__WXOSX__) // high resolution stopwatch for profiling @@ -148,23 +134,19 @@ class OCPNStopWatch { }; #endif -// ============================================================================ -// ChartMBTiles implementation -// ============================================================================ - -ChartMBTiles::ChartMBTiles() { +ChartMbTiles::ChartMbTiles() { // Compute scale & MPP for each zoom level // Initial constants taken from // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames - OSM_zoomScale[0] = 554680041; - OSM_zoomMPP[0] = 156543.03; - for (int i = 1; i < (int)(sizeof(OSM_zoomScale) / sizeof(double)); i++) { - OSM_zoomScale[i] = OSM_zoomScale[i - 1] / 2; - OSM_zoomMPP[i] = OSM_zoomMPP[i - 1] / 2; + osm_zoom_scale[0] = 554680041; + osm_zoom_mpp[0] = 156543.03; + for (int i = 1; i < (int)(sizeof(osm_zoom_scale) / sizeof(double)); i++) { + osm_zoom_scale[i] = osm_zoom_scale[i - 1] / 2; + osm_zoom_mpp[i] = osm_zoom_mpp[i - 1] / 2; } // Init some private data - m_workerThread = nullptr; + m_worker_thread = nullptr; m_ChartFamily = CHART_FAMILY_RASTER; m_ChartType = CHART_TYPE_MBTILES; @@ -172,12 +154,12 @@ ChartMBTiles::ChartMBTiles() { m_datum_str = _T("WGS84"); // assume until proven otherwise m_projection = PROJECTION_WEB_MERCATOR; - m_imageType = wxBITMAP_TYPE_ANY; + m_image_type = wxBITMAP_TYPE_ANY; m_b_cdebug = 0; - m_minZoom = 0; - m_maxZoom = 21; + m_min_zoom = 0; + m_max_zoom = 21; m_nNoCOVREntries = 0; m_nCOVREntries = 0; @@ -185,114 +167,98 @@ ChartMBTiles::ChartMBTiles() { m_pCOVRTable = NULL; m_pNoCOVRTablePoints = NULL; m_pNoCOVRTable = NULL; - m_tileCache = NULL; + m_tile_cache = NULL; - m_LonMin = LON_UNDEF; - m_LonMax = LON_UNDEF; - m_LatMin = LAT_UNDEF; - m_LatMax = LAT_UNDEF; + m_lon_min = LON_UNDEF; + m_lon_max = LON_UNDEF; + m_lat_min = LAT_UNDEF; + m_lat_max = LAT_UNDEF; #ifdef OCPN_USE_CONFIG - wxFileConfig *pfc = (wxFileConfig *)pConfig; + wxFileConfig* pfc = (wxFileConfig*)pConfig; pfc->SetPath(_T ( "/Settings" )); pfc->Read(_T ( "DebugMBTiles" ), &m_b_cdebug, 0); #endif - m_pDB = NULL; + m_db = NULL; } -ChartMBTiles::~ChartMBTiles() { +ChartMbTiles::~ChartMbTiles() { // Stop the worker thread before destroying this instance StopThread(); FlushTiles(); - - if (m_tileCache) { - delete m_tileCache; - } - - if (m_pDB) { - delete m_pDB; - } } -//------------------------------------------------------------------------------------------------- -// Get the Chart thumbnail data structure -// Creating the thumbnail bitmap as required -//------------------------------------------------------------------------------------------------- - -ThumbData *ChartMBTiles::GetThumbData() { return NULL; } +ThumbData* ChartMbTiles::GetThumbData() { return NULL; } -ThumbData *ChartMBTiles::GetThumbData(int tnx, int tny, float lat, float lon) { +ThumbData* ChartMbTiles::GetThumbData(int tnx, int tny, float lat, float lon) { return NULL; } -bool ChartMBTiles::UpdateThumbData(double lat, double lon) { return true; } +bool ChartMbTiles::UpdateThumbData(double lat, double lon) { return true; } -bool ChartMBTiles::AdjustVP(ViewPort &vp_last, ViewPort &vp_proposed) { +bool ChartMbTiles::AdjustVP(ViewPort& vp_last, ViewPort& vp_proposed) { return true; } -// Report recommended minimum and maximum scale values for which use of this -// chart is valid - -double ChartMBTiles::GetNormalScaleMin(double canvas_scale_factor, +double ChartMbTiles::GetNormalScaleMin(double canvas_scale_factor, bool b_allow_overzoom) { return (1); // allow essentially unlimited overzoom } -double ChartMBTiles::GetNormalScaleMax(double canvas_scale_factor, +double ChartMbTiles::GetNormalScaleMax(double canvas_scale_factor, int canvas_width) { return (canvas_scale_factor / m_ppm_avg) * 40.0; // excessive underscale is slow, and unreadable } -double ChartMBTiles::GetNearestPreferredScalePPM(double target_scale_ppm) { +double ChartMbTiles::GetNearestPreferredScalePPM(double target_scale_ppm) { return target_scale_ppm; } // Checks/corrects/completes the initialization based on real data from the // tiles table -void ChartMBTiles::InitFromTiles(const wxString &name) { +void ChartMbTiles::InitFromTiles(const wxString& name) { try { // Open the MBTiles database file - const char *name_UTF8 = ""; + const char* name_utf8 = ""; wxCharBuffer utf8CB = name.ToUTF8(); // the UTF-8 buffer - if (utf8CB.data()) name_UTF8 = utf8CB.data(); + if (utf8CB.data()) name_utf8 = utf8CB.data(); - SQLite::Database db(name_UTF8); + SQLite::Database db(name_utf8); // Check if tiles with advertised min and max zoom level really exist, or // correct the defaults We can't blindly use what we find though - the DB // often contains empty cells at very low zoom levels, so if we have some // info from metadata, we will use that if more conservative... SQLite::Statement query(db, - "SELECT min(zoom_level) AS min_zoom, " - "max(zoom_level) AS max_zoom FROM tiles"); + "SELECT min(zoom_level) AS m_min_zoom, " + "max(zoom_level) AS m_max_zoom FROM tiles"); while (query.executeStep()) { - const char *colMinZoom = query.getColumn(0); - const char *colMaxZoom = query.getColumn(1); + const char* col_min_zoom = query.getColumn(0); + const char* col_max_zoom = query.getColumn(1); int min_zoom = 0, max_zoom = 0; - sscanf(colMinZoom, "%i", &min_zoom); - m_minZoom = wxMax(m_minZoom, min_zoom); - sscanf(colMaxZoom, "%i", &max_zoom); - m_maxZoom = wxMin(m_maxZoom, max_zoom); - if (m_minZoom > m_maxZoom) { + sscanf(col_min_zoom, "%i", &min_zoom); + m_min_zoom = wxMax(m_min_zoom, min_zoom); + sscanf(col_max_zoom, "%i", &max_zoom); + m_max_zoom = wxMin(m_max_zoom, max_zoom); + if (m_min_zoom > m_max_zoom) { // We are looking at total nonsense with wrong metatadata and actual // tile coverage out of it, better use what's really in the data to be // able to show at least something - m_minZoom = min_zoom; - m_maxZoom = max_zoom; + m_min_zoom = min_zoom; + m_max_zoom = max_zoom; } } - // std::cout << name.c_str() << " zoom_min: " << m_minZoom << " - // zoom_max: " << m_maxZoom << std::endl; + // std::cout << name.c_str() << " zoom_min: " << m_min_zoom << " + // zoom_max: " << m_max_zoom << std::endl; // Traversing the entire tile table can be expensive.... // Use declared bounds if present. - if (!std::isnan(m_LatMin) && !std::isnan(m_LatMax) && - !std::isnan(m_LonMin) && !std::isnan(m_LonMax)) + if (!std::isnan(m_lat_min) && !std::isnan(m_lat_max) && + !std::isnan(m_lon_min) && !std::isnan(m_lon_max)) return; // Try to guess the coverage extents from the tiles. This will be hard to @@ -310,16 +276,16 @@ void ChartMBTiles::InitFromTiles(const wxString &name) { "min(tile_column) as min_column, max(tile_column) as max_column, " "count(*) as cnt, zoom_level FROM tiles WHERE zoom_level >= %d " "AND zoom_level <= %d GROUP BY zoom_level ORDER BY zoom_level ASC", - m_minZoom, m_maxZoom) + m_min_zoom, m_max_zoom) .c_str()); - float minLat = 999., maxLat = -999.0, minLon = 999., maxLon = -999.0; + float min_lat = 999., max_lat = -999.0, min_lon = 999., max_lon = -999.0; while (query1.executeStep()) { - const char *colMinRow = query1.getColumn(0); - const char *colMaxRow = query1.getColumn(1); - const char *colMinCol = query1.getColumn(2); - const char *colMaxCol = query1.getColumn(3); - const char *colCnt = query1.getColumn(4); - const char *colZoom = query1.getColumn(5); + const char* colMinRow = query1.getColumn(0); + const char* colMaxRow = query1.getColumn(1); + const char* colMinCol = query1.getColumn(2); + const char* colMaxCol = query1.getColumn(3); + const char* colCnt = query1.getColumn(4); + const char* colZoom = query1.getColumn(5); int minRow, maxRow, minCol, maxCol, cnt, zoom; sscanf(colMinRow, "%i", &minRow); @@ -334,29 +300,29 @@ void ChartMBTiles::InitFromTiles(const wxString &name) { // Let's try to use the simplest possible algo and just look for the zoom // level with largest extent (Which probably be the one with lowest // resolution?)... - minLat = wxMin(minLat, mbTileDescriptor::tiley2lat(minRow, zoom)); - maxLat = wxMax(maxLat, mbTileDescriptor::tiley2lat(maxRow - 1, zoom)); - minLon = wxMin(minLon, mbTileDescriptor::tilex2long(minCol, zoom)); - maxLon = wxMax(maxLon, mbTileDescriptor::tilex2long(maxCol + 1, zoom)); - // std::cout << "Zoom: " << zoom << " minlat: " << tiley2lat(minRow, zoom) - // << " maxlat: " << tiley2lat(maxRow - 1, zoom) << " minlon: " << - // tilex2long(minCol, zoom) << " maxlon: " << tilex2long(maxCol + 1, zoom) + min_lat = wxMin(min_lat, MbTileDescriptor::Tiley2lat(minRow, zoom)); + max_lat = wxMax(max_lat, MbTileDescriptor::Tiley2lat(maxRow - 1, zoom)); + min_lon = wxMin(min_lon, MbTileDescriptor::Tilex2long(minCol, zoom)); + max_lon = wxMax(max_lon, MbTileDescriptor::Tilex2long(maxCol + 1, zoom)); + // std::cout << "Zoom: " << zoom << " minlat: " << Tiley2lat(minRow, zoom) + // << " maxlat: " << Tiley2lat(maxRow - 1, zoom) << " minlon: " << + // tilex2long(minCol, zoom) << " maxlon: " << Tilex2long(maxCol + 1, zoom) // << std::endl; } // ... and use what we found only in case we miss some of the values from // metadata... - if (std::isnan(m_LatMin)) m_LatMin = minLat; - if (std::isnan(m_LatMax)) m_LatMax = maxLat; - if (std::isnan(m_LonMin)) m_LonMin = minLon; - if (std::isnan(m_LonMax)) m_LonMax = maxLon; - } catch (std::exception &e) { - const char *t = e.what(); + if (std::isnan(m_lat_min)) m_lat_min = min_lat; + if (std::isnan(m_lat_max)) m_lat_max = max_lat; + if (std::isnan(m_lon_min)) m_lon_min = min_lon; + if (std::isnan(m_lon_max)) m_lon_max = max_lon; + } catch (std::exception& e) { + const char* t = e.what(); wxLogMessage("mbtiles exception: %s", e.what()); } } -InitReturn ChartMBTiles::Init(const wxString &name, ChartInitFlag init_flags) { +InitReturn ChartMbTiles::Init(const wxString& name, ChartInitFlag init_flags) { m_global_color_scheme = GLOBAL_COLOR_SCHEME_RGB; m_FullPath = name; @@ -364,60 +330,61 @@ InitReturn ChartMBTiles::Init(const wxString &name, ChartInitFlag init_flags) { try { // Open the MBTiles database file - const char *name_UTF8 = ""; + const char* name_utf8 = ""; wxCharBuffer utf8CB = name.ToUTF8(); // the UTF-8 buffer - if (utf8CB.data()) name_UTF8 = utf8CB.data(); + if (utf8CB.data()) name_utf8 = utf8CB.data(); - SQLite::Database db(name_UTF8); + SQLite::Database db(name_utf8); // Compile a SQL query, getting everything from the "metadata" table SQLite::Statement query(db, "SELECT * FROM metadata "); // Loop to execute the query step by step, to get rows of result while (query.executeStep()) { - const char *colName = query.getColumn(0); - const char *colValue = query.getColumn(1); + const char* col_name = query.getColumn(0); + const char* col_value = query.getColumn(1); // Get the geometric extent of the data - if (!strncmp(colName, "bounds", 6)) { + if (!strncmp(col_name, "bounds", 6)) { float lon1, lat1, lon2, lat2; - sscanf(colValue, "%g,%g,%g,%g", &lon1, &lat1, &lon2, &lat2); + sscanf(col_value, "%g,%g,%g,%g", &lon1, &lat1, &lon2, &lat2); // There is some confusion over the layout of this field... - m_LatMax = wxMax(lat1, lat2); - m_LatMin = wxMin(lat1, lat2); - m_LonMax = wxMax(lon1, lon2); - m_LonMin = wxMin(lon1, lon2); + m_lat_max = wxMax(lat1, lat2); + m_lat_min = wxMin(lat1, lat2); + m_lon_max = wxMax(lon1, lon2); + m_lon_min = wxMin(lon1, lon2); } - else if (!strncmp(colName, "format", 6)) { - m_format = std::string(colValue); + else if (!strncmp(col_name, "format", 6)) { + m_format = std::string(col_value); } // Get the min and max zoom values present in the db - else if (!strncmp(colName, "minzoom", 7)) { - sscanf(colValue, "%i", &m_minZoom); - } else if (!strncmp(colName, "maxzoom", 7)) { - sscanf(colValue, "%i", &m_maxZoom); + else if (!strncmp(col_name, "minzoom", 7)) { + sscanf(col_value, "%i", &m_min_zoom); + } else if (!strncmp(col_name, "maxzoom", 7)) { + sscanf(col_value, "%i", &m_max_zoom); } - else if (!strncmp(colName, "description", 11)) { - m_Description = wxString(colValue, wxConvUTF8); - } else if (!strncmp(colName, "name", 11)) { - m_Name = wxString(colValue, wxConvUTF8); - } else if (!strncmp(colName, "type", 11)) { - m_TileType = wxString(colValue, wxConvUTF8).Upper().IsSameAs("OVERLAY") - ? MBTilesType::OVERLAY - : MBTilesType::BASE; - } else if (!strncmp(colName, "scheme", 11)) { - m_Scheme = wxString(colValue, wxConvUTF8).Upper().IsSameAs("XYZ") - ? MBTilesScheme::XYZ - : MBTilesScheme::TMS; + else if (!strncmp(col_name, "description", 11)) { + m_Description = wxString(col_value, wxConvUTF8); + } else if (!strncmp(col_name, "name", 11)) { + m_Name = wxString(col_value, wxConvUTF8); + } else if (!strncmp(col_name, "type", 11)) { + m_tile_type = + wxString(col_value, wxConvUTF8).Upper().IsSameAs("OVERLAY") + ? MbTilesType::OVERLAY + : MbTilesType::BASE; + } else if (!strncmp(col_name, "scheme", 11)) { + m_scheme = wxString(col_value, wxConvUTF8).Upper().IsSameAs("XYZ") + ? MbTilesScheme::XYZ + : MbTilesScheme::TMS; } } - } catch (std::exception &e) { - const char *t = e.what(); + } catch (std::exception& e) { + const char* t = e.what(); wxLogMessage("mbtiles exception: %s", e.what()); return INIT_FAIL_REMOVE; } @@ -426,50 +393,50 @@ InitReturn ChartMBTiles::Init(const wxString &name, ChartInitFlag init_flags) { InitFromTiles(name); // set the chart scale parameters based on the max zoom factor - m_ppm_avg = 1.0 / OSM_zoomMPP[m_minZoom]; - m_Chart_Scale = OSM_zoomScale[m_maxZoom]; + m_ppm_avg = 1.0 / osm_zoom_mpp[m_min_zoom]; + m_Chart_Scale = osm_zoom_scale[m_max_zoom]; // Initialize the tile data structures - m_tileCache = new TileCache(m_minZoom, m_maxZoom, m_LonMin, m_LatMin, - m_LonMax, m_LatMax); + m_tile_cache = std::make_unique(m_min_zoom, m_max_zoom, m_lon_min, + m_lat_min, m_lon_max, m_lat_max); - LLRegion covrRegion; + LLRegion covr_region; - LLBBox extentBox; - extentBox.Set(m_LatMin, m_LonMin, m_LatMax, m_LonMax); + LLBBox extent_box; + extent_box.Set(m_lat_min, m_lon_min, m_lat_max, m_lon_max); - const char *name_UTF8 = ""; + const char* name_utf8 = ""; wxCharBuffer utf8CB = name.ToUTF8(); // the UTF-8 buffer - if (utf8CB.data()) name_UTF8 = utf8CB.data(); + if (utf8CB.data()) name_utf8 = utf8CB.data(); - SQLite::Database db(name_UTF8); + SQLite::Database db(name_utf8); - int zoomFactor = m_minZoom; - int minRegionZoom = -1; + int zoom_factor = m_min_zoom; + int min_region_zoom = -1; bool covr_populated = false; - m_nTiles = 0; - while ((zoomFactor <= m_maxZoom) && (minRegionZoom < 0)) { - LLRegion covrRegionZoom; - wxRegion regionZoom; + m_n_tiles = 0; + while ((zoom_factor <= m_max_zoom) && (min_region_zoom < 0)) { + LLRegion covr_region_zoom; + wxRegion region_zoom; char qrs[100]; // Protect against trying to create the exact coverage for the brutal large // scale layers contianing tens of thousand tiles. sprintf(qrs, "select count(*) from tiles where zoom_level = %d ", - zoomFactor); + zoom_factor); SQLite::Statement query_size(db, qrs); if (query_size.executeStep()) { - const char *colValue = query_size.getColumn(0); - int tile_at_zoom = atoi(colValue); - m_nTiles += tile_at_zoom; + const char* col_value = query_size.getColumn(0); + int tile_at_zoom = atoi(col_value); + m_n_tiles += tile_at_zoom; if (tile_at_zoom > 1000) { - zoomFactor++; + zoom_factor++; if (!covr_populated) { covr_populated = true; - covrRegion = extentBox; + covr_region = extent_box; } continue; } @@ -478,77 +445,78 @@ InitReturn ChartMBTiles::Init(const wxString &name, ChartInitFlag init_flags) { // query the database sprintf(qrs, "select tile_column, tile_row from tiles where zoom_level = %d ", - zoomFactor); + zoom_factor); // Compile a SQL query, getting the specific data SQLite::Statement query(db, qrs); covr_populated = true; while (query.executeStep()) { - const char *colValue = query.getColumn(0); - const char *c2 = query.getColumn(1); - int tile_x_found = atoi(colValue); // tile_x - int tile_y_found = atoi(c2); // tile_y + const char* col_value = query.getColumn(0); + const char* c2 = query.getColumn(1); + int tile_x_found = atoi(col_value); // m_tile_x + int tile_y_found = atoi(c2); // m_tile_y - regionZoom.Union(tile_x_found, tile_y_found - 1, 1, 1); + region_zoom.Union(tile_x_found, tile_y_found - 1, 1, 1); } // inner while - wxRegionIterator upd(regionZoom); // get the rect list - double eps_factor = eps * 100; // roughly 1 m + wxRegionIterator upd(region_zoom); // get the rect list + double eps_factor = kEps * 100; // roughly 1 m while (upd) { wxRect rect = upd.GetRect(); - double lonmin = - round(mbTileDescriptor::tilex2long(rect.x, zoomFactor) / eps_factor) * - eps_factor; + double lonmin = round(MbTileDescriptor::Tilex2long(rect.x, zoom_factor) / + eps_factor) * + eps_factor; double lonmax = - round(mbTileDescriptor::tilex2long(rect.x + rect.width, zoomFactor) / + round(MbTileDescriptor::Tilex2long(rect.x + rect.width, zoom_factor) / eps_factor) * eps_factor; double latmin = - round(mbTileDescriptor::tiley2lat(rect.y, zoomFactor) / eps_factor) * + round(MbTileDescriptor::Tiley2lat(rect.y, zoom_factor) / eps_factor) * eps_factor; double latmax = - round(mbTileDescriptor::tiley2lat(rect.y + rect.height, zoomFactor) / + round(MbTileDescriptor::Tiley2lat(rect.y + rect.height, zoom_factor) / eps_factor) * eps_factor; LLBBox box; box.Set(latmin, lonmin, latmax, lonmax); - LLRegion tileRegion(box); + LLRegion tile_region(box); // if(i <= 1) - covrRegionZoom.Union(tileRegion); + covr_region_zoom.Union(tile_region); upd++; - minRegionZoom = zoomFactor; // We take the first populated (lowest) zoom - // level region as the final chart region + min_region_zoom = + zoom_factor; // We take the first populated (lowest) zoom + // level region as the final chart region } - covrRegion.Union(covrRegionZoom); + covr_region.Union(covr_region_zoom); - zoomFactor++; + zoom_factor++; } // while // The coverage region must be reduced if necessary to include only the db // specified bounds. - covrRegion.Intersect(extentBox); + covr_region.Intersect(extent_box); - m_minZoomRegion = covrRegion; + m_min_zoom_region = covr_region; // Populate M_COVR entries for the OCPN chart database - if (covrRegion.contours.size()) { // Check for no intersection caused by ?? - m_nCOVREntries = covrRegion.contours.size(); - m_pCOVRTablePoints = (int *)malloc(m_nCOVREntries * sizeof(int)); - m_pCOVRTable = (float **)malloc(m_nCOVREntries * sizeof(float *)); - std::list::iterator it = covrRegion.contours.begin(); + if (covr_region.contours.size()) { // Check for no intersection caused by ?? + m_nCOVREntries = covr_region.contours.size(); + m_pCOVRTablePoints = (int*)malloc(m_nCOVREntries * sizeof(int)); + m_pCOVRTable = (float**)malloc(m_nCOVREntries * sizeof(float*)); + std::list::iterator it = covr_region.contours.begin(); for (int i = 0; i < m_nCOVREntries; i++) { m_pCOVRTablePoints[i] = it->size(); m_pCOVRTable[i] = - (float *)malloc(m_pCOVRTablePoints[i] * 2 * sizeof(float)); + (float*)malloc(m_pCOVRTablePoints[i] * 2 * sizeof(float)); std::list::iterator jt = it->begin(); for (int j = 0; j < m_pCOVRTablePoints[i]; j++) { m_pCOVRTable[i][2 * j + 0] = jt->y; @@ -574,88 +542,81 @@ InitReturn ChartMBTiles::Init(const wxString &name, ChartInitFlag init_flags) { return INIT_OK; } -InitReturn ChartMBTiles::PreInit(const wxString &name, ChartInitFlag init_flags, +InitReturn ChartMbTiles::PreInit(const wxString& name, ChartInitFlag init_flags, ColorScheme cs) { m_global_color_scheme = cs; return INIT_OK; } -InitReturn ChartMBTiles::PostInit(void) { +InitReturn ChartMbTiles::PostInit(void) { // Create the persistent MBTiles database file - const char *name_UTF8 = ""; + const char* name_UTF8 = ""; wxCharBuffer utf8CB = m_FullPath.ToUTF8(); // the UTF-8 buffer if (utf8CB.data()) name_UTF8 = utf8CB.data(); - m_pDB = new SQLite::Database(name_UTF8); - m_pDB->exec("PRAGMA locking_mode=EXCLUSIVE"); - m_pDB->exec("PRAGMA cache_size=-10000"); + m_db = std::make_unique(name_UTF8); + m_db->exec("PRAGMA locking_mode=EXCLUSIVE"); + m_db->exec("PRAGMA cache_size=-10000"); bReadyToRender = true; return INIT_OK; } // FIXME : useless now -void ChartMBTiles::FlushTiles() { +void ChartMbTiles::FlushTiles() { // Delete all the tiles in the tile cache // Note that this function also deletes OpenGL texture memory associated to // the tiles - if (m_tileCache) { - m_tileCache->Flush(); + if (m_tile_cache) { + m_tile_cache->Flush(); } } -bool ChartMBTiles::GetChartExtent(Extent *pext) { - pext->NLAT = m_LatMax; - pext->SLAT = m_LatMin; - pext->ELON = m_LonMax; - pext->WLON = m_LonMin; - +bool ChartMbTiles::GetChartExtent(Extent* pext) { + pext->NLAT = m_lat_max; + pext->SLAT = m_lat_min; + pext->ELON = m_lon_max; + pext->WLON = m_lon_min; return true; } -void ChartMBTiles::SetColorScheme(ColorScheme cs, bool bApplyImmediate) { +void ChartMbTiles::SetColorScheme(ColorScheme cs, bool bApplyImmediate) { m_global_color_scheme = cs; } -void ChartMBTiles::GetValidCanvasRegion(const ViewPort &VPoint, - OCPNRegion *pValidRegion) { - pValidRegion->Clear(); - pValidRegion->Union(0, 0, VPoint.pix_width, VPoint.pix_height); +void ChartMbTiles::GetValidCanvasRegion(const ViewPort& v_point, + OCPNRegion* valid_region) { + valid_region->Clear(); + valid_region->Union(0, 0, v_point.pix_width, v_point.pix_height); return; } -LLRegion ChartMBTiles::GetValidRegion() { return m_minZoomRegion; } +LLRegion ChartMbTiles::GetValidRegion() { return m_min_zoom_region; } -bool ChartMBTiles::RenderViewOnDC(wxMemoryDC &dc, const ViewPort &VPoint) { +bool ChartMbTiles::RenderViewOnDC(wxMemoryDC& dc, const ViewPort& VPoint) { return true; } -/// @brief Loads a tile into OpenGL's texture memory for rendering. If the tile -/// is not ready to be rendered (i.e. the tile has not been loaded from disk or -/// decompressed to memory), the function sends a request to the worker thread -/// which will do this later in the background. -/// @param tile Pointer to the tile descriptor to be prepared -/// @return true if the tile is ready to be rendered, false else. -bool ChartMBTiles::getTileTexture(mbTileDescriptor *tile) { - if (!m_pDB) return false; - m_tileCount++; +bool ChartMbTiles::GetTileTexture(SharedTilePtr tile) { + if (!m_db) return false; + m_tile_count++; // Is the texture ready to be rendered ? - if (tile->glTextureName > 0) { + if (tile->m_gl_texture_name > 0) { // Yes : bind the texture and return to the caller - glBindTexture(GL_TEXTURE_2D, tile->glTextureName); + glBindTexture(GL_TEXTURE_2D, tile->m_gl_texture_name); return true; - } else if (!tile->m_bAvailable) { + } else if (!tile->m_is_available) { // Tile is not in MbTiles file : no texture to render return false; } else if (tile->m_teximage == 0) { // Throttle the worker thread // Avoids unmanaged spikes in memory usage that arise from // processing very large tiles at small display scale (issue #4043) - if (m_workerThread->GetQueueSize() < 500) { + if (m_worker_thread->GetQueueSize() < 500) { if (tile->m_requested == false) { // The tile has not been loaded and decompressed yet : request it // to the worker thread - m_workerThread->RequestTile(tile); + m_worker_thread->RequestTile(tile); } } return false; @@ -665,8 +626,8 @@ bool ChartMBTiles::getTileTexture(mbTileDescriptor *tile) { #ifndef __OCPN__ANDROID__ glEnable(GL_COLOR_MATERIAL); #endif - glGenTextures(1, &tile->glTextureName); - glBindTexture(GL_TEXTURE_2D, tile->glTextureName); + glGenTextures(1, &tile->m_gl_texture_name); + glBindTexture(GL_TEXTURE_2D, tile->m_gl_texture_name); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -688,11 +649,11 @@ bool ChartMBTiles::getTileTexture(mbTileDescriptor *tile) { class wxPoint2DDouble; -wxPoint2DDouble ChartMBTiles::GetDoublePixFromLL(ViewPort &vp, double lat, +wxPoint2DDouble ChartMbTiles::GetDoublePixFromLL(ViewPort& vp, double lat, double lon) { double easting = 0; double northing = 0; - double xlon = lon - eps; + double xlon = lon - kEps; switch (vp.m_projection_type) { case PROJECTION_MERCATOR: @@ -733,12 +694,12 @@ wxPoint2DDouble ChartMBTiles::GetDoublePixFromLL(ViewPort &vp, double lat, (vp.pix_height / 2.0) - dyr); } -bool ChartMBTiles::RenderTile(mbTileDescriptor *tile, int zoomLevel, - const ViewPort &VPoint) { +bool ChartMbTiles::RenderTile(SharedTilePtr tile, int zoom_level, + const ViewPort& vpoint) { #ifdef ocpnUSE_GL - ViewPort vp = VPoint; + ViewPort vp = vpoint; - bool btexture = getTileTexture(tile); + bool btexture = GetTileTexture(tile); if (!btexture) { // Tile is not available yet, don't render it and wait for the worker thread // to load and decompress it later. @@ -761,21 +722,21 @@ bool ChartMBTiles::RenderTile(mbTileDescriptor *tile, int zoomLevel, wxPoint2DDouble p; - p = GetDoublePixFromLL(mvp, tile->latmin, tile->lonmin); + p = GetDoublePixFromLL(mvp, tile->m_latmin, tile->m_lonmin); coords[0] = p.m_x; coords[1] = p.m_y; - p = GetDoublePixFromLL(mvp, tile->latmax, tile->lonmin); + p = GetDoublePixFromLL(mvp, tile->m_latmax, tile->m_lonmin); coords[2] = p.m_x; coords[3] = p.m_y; - p = GetDoublePixFromLL(mvp, tile->latmax, tile->lonmax); + p = GetDoublePixFromLL(mvp, tile->m_latmax, tile->m_lonmax); coords[4] = p.m_x; coords[5] = p.m_y; - p = GetDoublePixFromLL(mvp, tile->latmin, tile->lonmax); + p = GetDoublePixFromLL(mvp, tile->m_latmin, tile->m_lonmax); coords[6] = p.m_x; coords[7] = p.m_y; if (!g_tile_shader_program) { - GLShaderProgram *shaderProgram = new GLShaderProgram; + GLShaderProgram* shaderProgram = new GLShaderProgram; shaderProgram->addShaderFromSource(tile_vertex_shader_source, GL_VERTEX_SHADER); shaderProgram->addShaderFromSource(tile_fragment_shader_source, @@ -784,13 +745,13 @@ bool ChartMBTiles::RenderTile(mbTileDescriptor *tile, int zoomLevel, g_tile_shader_program = shaderProgram; } - GLShaderProgram *shader = g_tile_shader_program; + GLShaderProgram* shader = g_tile_shader_program; shader->Bind(); // Set up the texture sampler to texture unit 0 shader->SetUniform1i("uTex", 0); - shader->SetUniformMatrix4fv("MVMatrix", (GLfloat *)vp.vp_matrix_transform); + shader->SetUniformMatrix4fv("MVMatrix", (GLfloat*)vp.vp_matrix_transform); float co1[8]; float tco1[8]; @@ -851,146 +812,147 @@ bool ChartMBTiles::RenderTile(mbTileDescriptor *tile, int zoomLevel, return true; } -bool ChartMBTiles::RenderRegionViewOnGL(const wxGLContext &glc, - const ViewPort &VPoint, - const OCPNRegion &RectRegion, - const LLRegion &Region) { +bool ChartMbTiles::RenderRegionViewOnGL(const wxGLContext& glc, + const ViewPort& vpoint, + const OCPNRegion& rect_region, + const LLRegion& region) { #ifdef ocpnUSE_GL // Reset the tile counter. This counter is used to know how many tile are // currently used to draw the chart and then to dimension the tile cache size // properly w.r.t the size of the screen and the level of details - m_tileCount = 0; + m_tile_count = 0; // Do not render if significantly underzoomed - if (VPoint.chart_scale > (20 * OSM_zoomScale[m_minZoom])) { - if (m_nTiles > 500) { + if (vpoint.chart_scale > (20 * osm_zoom_scale[m_min_zoom])) { + if (m_n_tiles > 500) { return true; } } - ViewPort vp = VPoint; + ViewPort vp = vpoint; OCPNRegion screen_region(wxRect(0, 0, vp.pix_width, vp.pix_height)); LLRegion screenLLRegion = vp.GetLLRegion(screen_region); LLBBox screenBox = screenLLRegion.GetBox(); - if ((m_LonMax - m_LonMin) > 180) { // big chart - LLRegion validRegion = m_minZoomRegion; - validRegion.Intersect(screenLLRegion); - glChartCanvas::SetClipRegion(vp, validRegion); + if ((m_lon_max - m_lon_min) > 180) { // big chart + LLRegion valid_region = m_min_zoom_region; + valid_region.Intersect(screenLLRegion); + glChartCanvas::SetClipRegion(vp, valid_region); } else - glChartCanvas::SetClipRegion(vp, m_minZoomRegion); + glChartCanvas::SetClipRegion(vp, m_min_zoom_region); /* setup opengl parameters */ glEnable(GL_TEXTURE_2D); - int viewZoom = m_maxZoom; + int viewZoom = m_max_zoom; // Set zoom modifier according to Raster Zoom Modifier settings from display // preference pane - double zoomMod = 2 * pow(2, -g_chart_zoom_modifier_raster / 3.0); + double zoom_mod = 2 * pow(2, -g_chart_zoom_modifier_raster / 3.0); - for (int kz = m_minZoom; kz <= 19; kz++) { - double db_mpp = OSM_zoomMPP[kz]; + for (int kz = m_min_zoom; kz <= 19; kz++) { + double db_mpp = osm_zoom_mpp[kz]; double vp_mpp = 1. / vp.view_scale_ppm; - if (db_mpp < vp_mpp * zoomMod) { + if (db_mpp < vp_mpp * zoom_mod) { viewZoom = kz; break; } } - viewZoom = wxMin(viewZoom, m_maxZoom); + viewZoom = wxMin(viewZoom, m_max_zoom); // printf("viewZoomCalc: %d %g %g\n", viewZoom, - // VPoint.view_scale_ppm, 1. / VPoint.view_scale_ppm); + // vpoint.view_scale_ppm, 1. / vpoint.view_scale_ppm); - int zoomFactor = m_minZoom; + int zoomFactor = m_min_zoom; zoomFactor = wxMax(zoomFactor, viewZoom - g_mbtilesMaxLayers); // DEBUG TODO Show single zoom - // zoomFactor = 5; //m_minZoom; + // zoomFactor = 5; //m_min_zoom; // viewZoom = zoomFactor; - int maxrenZoom = m_minZoom; + int maxren_zoom = m_min_zoom; - LLBBox box = Region.GetBox(); - LLBBox region_box = Region.GetBox(); + LLBBox box = region.GetBox(); + LLBBox region_box = region.GetBox(); bool render_pass = true; // if the full screen box spans IDL, // we need to render the entire screen in two passes. - bool btwoPass = false; + bool is_two_pass = false; if (((screenBox.GetMinLon() < -180) && (screenBox.GetMaxLon() > -180)) || ((screenBox.GetMinLon() < 180) && (screenBox.GetMaxLon() > 180))) { - btwoPass = true; + is_two_pass = true; box = screenBox; } // For tiles declared as "OVERLAY", render only the zoom level that // corresponds to the currently viewed zoom level - if (m_TileType == MBTilesType::OVERLAY) zoomFactor = viewZoom; + if (m_tile_type == MbTilesType::OVERLAY) zoomFactor = viewZoom; while (zoomFactor <= viewZoom) { // Get the tile numbers of the box corners of this render region, at this // zoom level - vp = VPoint; + vp = vpoint; // First pass, right hand side in twopass rendering - int topTile = - wxMin(m_tileCache->GetNorthLimit(zoomFactor), - mbTileDescriptor::lat2tiley(box.GetMaxLat(), zoomFactor)); - int botTile = - wxMax(m_tileCache->GetSouthLimit(zoomFactor), - mbTileDescriptor::lat2tiley(box.GetMinLat(), zoomFactor)); - int leftTile = mbTileDescriptor::long2tilex(box.GetMinLon(), zoomFactor); - int rightTile = mbTileDescriptor::long2tilex(box.GetMaxLon(), zoomFactor); - - if (btwoPass) { - vp = VPoint; + int top_tile = + wxMin(m_tile_cache->GetNorthLimit(zoomFactor), + MbTileDescriptor::Lat2tiley(box.GetMaxLat(), zoomFactor)); + int bot_tile = + wxMax(m_tile_cache->GetSouthLimit(zoomFactor), + MbTileDescriptor::Lat2tiley(box.GetMinLat(), zoomFactor)); + int left_tile = MbTileDescriptor::Long2tilex(box.GetMinLon(), zoomFactor); + int right_tile = MbTileDescriptor::Long2tilex(box.GetMaxLon(), zoomFactor); + + if (is_two_pass) { + vp = vpoint; if (vp.clon > 0) { vp.clon -= 360; - leftTile = mbTileDescriptor::long2tilex(-180 + eps, zoomFactor); - rightTile = - mbTileDescriptor::long2tilex(box.GetMaxLon() - 360., zoomFactor); + left_tile = MbTileDescriptor::Long2tilex(-180 + kEps, zoomFactor); + right_tile = + MbTileDescriptor::Long2tilex(box.GetMaxLon() - 360., zoomFactor); } else { - leftTile = mbTileDescriptor::long2tilex(-180 + eps, zoomFactor); - rightTile = mbTileDescriptor::long2tilex(box.GetMaxLon(), zoomFactor); + left_tile = MbTileDescriptor::Long2tilex(-180 + kEps, zoomFactor); + right_tile = MbTileDescriptor::Long2tilex(box.GetMaxLon(), zoomFactor); } } - for (int iy = botTile; iy <= topTile; iy++) { - for (int ix = leftTile; ix <= rightTile; ix++) { - mbTileDescriptor *tile = m_tileCache->GetTile(zoomFactor, ix, iy); + for (int iy = bot_tile; iy <= top_tile; iy++) { + for (int ix = left_tile; ix <= right_tile; ix++) { + SharedTilePtr tile = m_tile_cache->GetTile(zoomFactor, ix, iy); - if (!Region.IntersectOut(tile->box)) { - if (RenderTile(tile, zoomFactor, vp)) maxrenZoom = zoomFactor; + if (!region.IntersectOut(tile->m_box)) { + if (RenderTile(tile, zoomFactor, vp)) maxren_zoom = zoomFactor; } } } // second pass - if (btwoPass) { - vp = VPoint; + if (is_two_pass) { + vp = vpoint; if (vp.clon < 0) vp.clon += 360; // Get the tile numbers of the box corners of this render region, at // this zoom level - int topTile = - wxMin(m_tileCache->GetNorthLimit(zoomFactor), - mbTileDescriptor::lat2tiley(box.GetMaxLat(), zoomFactor)); - int botTile = - wxMax(m_tileCache->GetSouthLimit(zoomFactor), - mbTileDescriptor::lat2tiley(box.GetMinLat(), zoomFactor)); - int leftTile = mbTileDescriptor::long2tilex(box.GetMinLon(), zoomFactor); - int rightTile = mbTileDescriptor::long2tilex(-180 - eps, zoomFactor); - - if (rightTile < leftTile) rightTile = leftTile; - - for (int iy = botTile; iy <= topTile; iy++) { - for (int ix = leftTile; ix <= rightTile; ix++) { - mbTileDescriptor *tile = m_tileCache->GetTile(zoomFactor, ix, iy); - - if (!Region.IntersectOut(tile->box)) RenderTile(tile, zoomFactor, vp); + int top_tile = + wxMin(m_tile_cache->GetNorthLimit(zoomFactor), + MbTileDescriptor::Lat2tiley(box.GetMaxLat(), zoomFactor)); + int bot_tile = + wxMax(m_tile_cache->GetSouthLimit(zoomFactor), + MbTileDescriptor::Lat2tiley(box.GetMinLat(), zoomFactor)); + int left_tile = MbTileDescriptor::Long2tilex(box.GetMinLon(), zoomFactor); + int right_tile = MbTileDescriptor::Long2tilex(-180 - kEps, zoomFactor); + + if (right_tile < left_tile) right_tile = left_tile; + + for (int iy = bot_tile; iy <= top_tile; iy++) { + for (int ix = left_tile; ix <= right_tile; ix++) { + SharedTilePtr tile = m_tile_cache->GetTile(zoomFactor, ix, iy); + + if (!region.IntersectOut(tile->m_box)) + RenderTile(tile, zoomFactor, vp); } } } @@ -1000,8 +962,8 @@ bool ChartMBTiles::RenderRegionViewOnGL(const wxGLContext &glc, glDisable(GL_TEXTURE_2D); - m_zoomScaleFactor = - 2 * OSM_zoomMPP[maxrenZoom] * VPoint.view_scale_ppm / zoomMod; + m_zoom_scale_factor = + 2 * osm_zoom_mpp[maxren_zoom] * vpoint.view_scale_ppm / zoom_mod; glChartCanvas::DisableClipRegion(); @@ -1009,10 +971,10 @@ bool ChartMBTiles::RenderRegionViewOnGL(const wxGLContext &glc, // viewport. This dynamic limit allows to automatically adapt to the actual // resolution of the screen and to handle tricky configuration with multiple // screens or hdpi displays - m_tileCache->CleanCache(m_tileCount * 3); + m_tile_cache->CleanCache(m_tile_count * 3); if (m_last_clean_zoom != viewZoom) { - m_tileCache->DeepCleanCache(); + m_tile_cache->DeepCleanCache(); m_last_clean_zoom = viewZoom; } @@ -1020,37 +982,26 @@ bool ChartMBTiles::RenderRegionViewOnGL(const wxGLContext &glc, return true; } -bool ChartMBTiles::RenderRegionViewOnDC(wxMemoryDC &dc, const ViewPort &VPoint, - const OCPNRegion &Region) { +bool ChartMbTiles::RenderRegionViewOnDC(wxMemoryDC& dc, const ViewPort& VPoint, + const OCPNRegion& Region) { gFrame->GetPrimaryCanvas()->SetAlertString( _("MBTile requires OpenGL to be enabled")); return true; } -/// @brief Create and start the wortker thread. This thread is dedicated at -/// loading and decompressing chart tiles into memory, in the background. If -/// for any reason the thread would fail to load, the method return false -bool ChartMBTiles::StartThread() { +bool ChartMbTiles::StartThread() { // Create the worker thread - m_workerThread = new MbtTilesThread(m_pDB); - if (m_workerThread->Run() != wxTHREAD_NO_ERROR) { - delete m_workerThread; - m_workerThread = nullptr; - // Not beeing able to create the worker thread is really a bad situation, - // never supposed to happen. So we trigger a fatal error. - wxLogMessage("MbTiles: Can't create an MBTiles worker thread"); - return false; - } + m_worker_thread = std::make_unique(m_db); + m_thread = std::thread([&] { m_worker_thread->Run(); }); + m_thread.detach(); return true; } -/// @brief Stop and delete the worker thread. This function is called when -/// OpenCPN is quitting. -void ChartMBTiles::StopThread() { +void ChartMbTiles::StopThread() { // Stop the worker thread - if (m_workerThread != nullptr) { - m_workerThread->RequestStop(); - m_workerThread = nullptr; + if (m_worker_thread != nullptr) { + m_worker_thread->RequestStop(); + m_worker_thread = nullptr; } } diff --git a/gui/src/mbtiles/tile_cache.cpp b/gui/src/mbtiles/tile_cache.cpp new file mode 100644 index 0000000000..1e866c806b --- /dev/null +++ b/gui/src/mbtiles/tile_cache.cpp @@ -0,0 +1,102 @@ +#include "tile_cache.h" +#include + +TileCache::TileCache(int min_zoom, int max_zoom, float Lon_min, float Lat_min, + float lon_max, float lat_max) + : m_min_zoom(min_zoom), + m_max_zoom(max_zoom), + m_nb_zoom(max_zoom - min_zoom + 1), + zoom_table([&] { + using Mtd = MbTileDescriptor; + std::vector v(m_nb_zoom); + for (int i = 0; i < m_nb_zoom; i++) { + int zoom_factor = min_zoom + i; + v[i].m_tile_x_min = Mtd::Long2tilex(Lon_min + kEps, zoom_factor); + v[i].m_tile_x_max = Mtd::Long2tilex(lon_max - kEps, zoom_factor); + v[i].m_tile_y_min = Mtd::Lat2tiley(Lat_min + kEps, zoom_factor); + v[i].m_tile_y_max = Mtd::Lat2tiley(lat_max - kEps, zoom_factor); + } + return v; + }()) { + // Set up how to handle the ~MbTileDescriptor() message sent using + // on_delete.Notify(). The message contains GL resources to be deallocated. + auto action = [&](ObservedEvt& evt) { + auto teximage = static_cast(evt.GetClientData()); + if (teximage) free(teximage); + auto gl_texture_name = static_cast(evt.GetInt()); + if (gl_texture_name) glDeleteTextures(1, &gl_texture_name); + }; + delete_listener.Init(on_delete, action); +} + +std::mutex& TileCache::GetMutex(uint64_t tile_id) { + static const int kMutexCount = 100; + static std::array mutexes; + return mutexes[tile_id % kMutexCount]; +} + +std::mutex& TileCache::GetMutex(const SharedTilePtr& tile) { + uint64_t key = MbTileDescriptor::GetMapKey(tile->m_zoom_level, tile->m_tile_x, + tile->m_tile_y); + return TileCache::GetMutex(key); +} + +SharedTilePtr TileCache::GetTile(int z, int x, int y) { + uint64_t index = MbTileDescriptor::GetMapKey(z, x, y); + auto ref = m_tile_map.find(index); + if (ref != m_tile_map.end()) { + // The tile is in the cache + ref->second->SetTimestamp(); + return ref->second; + } + + // The tile is not in the cache : create an empty one and add it to the tile + // map and list + auto tile = std::make_shared(z, x, y, on_delete); + m_tile_map[index] = tile; + return tile; +} + +void TileCache::CleanCache(uint32_t max_tiles) { + if (m_tile_map.size() <= max_tiles) return; + + // Create a sorted list of keys, oldest first. + std::vector keys; + for (auto& kv : m_tile_map) keys.push_back(kv.first); + auto compare = [&](const uint64_t lhs, const uint64_t rhs) { + return m_tile_map[lhs]->m_last_used < m_tile_map[rhs]->m_last_used; + }; + std::sort(keys.begin(), keys.end(), compare); + + for (size_t i = 0; i < m_tile_map.size() - max_tiles; i += 1) { + std::lock_guard lock(TileCache::GetMutex(m_tile_map[keys[i]])); + auto tile = m_tile_map[keys[i]]; + m_tile_map.erase(keys[i]); + } +} + +void TileCache::DeepCleanCache() { + using namespace std::chrono; + auto time_now = + duration_cast(system_clock::now().time_since_epoch()); + + auto age_limit = std::chrono::duration(5); // 5 seconds + + std::vector keys; + for (auto& kv : m_tile_map) keys.push_back(kv.first); + + for (size_t i = 0; i < keys.size(); i += 1) { + std::lock_guard lock(TileCache::GetMutex(m_tile_map[keys[i]])); + auto tile = m_tile_map[keys[i]]; + const std::chrono::duration elapsed_seconds{time_now - + tile->m_last_used}; + + // Looking for tiles that have been fetched from sql, + // but not yet rendered. Such tiles contain a large bitmap allocation. + // After some time, it is likely they never will be needed in short term. + // So safe to delete, and reload as necessary. + if (elapsed_seconds > age_limit) { + m_tile_map.erase(keys[i]); + } + } +} diff --git a/gui/src/mbtiles/tile_cache.h b/gui/src/mbtiles/tile_cache.h new file mode 100644 index 0000000000..32d96bc41b --- /dev/null +++ b/gui/src/mbtiles/tile_cache.h @@ -0,0 +1,93 @@ +#ifndef _TILECACHE_H_ +#define _TILECACHE_H_ + +#include + +#include "tile_descr.h" +#include "observable_evtvar.h" + +/** Manage the tiles of a mbtiles file. */ +class TileCache { + // Per zoomlevel descriptor of tile array for that zoomlevel + class ZoomDescriptor { + public: + int m_tile_x_min; + int m_tile_x_max; + int m_tile_y_min; + int m_tile_y_max; + }; + +private: + const double kEps = 6e-6; // about 1cm on earth's surface at equator + std::unordered_map m_tile_map; + const int m_min_zoom; + const int m_max_zoom; + const int m_nb_zoom; + const std::vector zoom_table; + ObsListener delete_listener; + +public: + TileCache(int min_zoom, int max_zoom, float Lon_min, float Lat_min, + float lon_max, float lat_max); + + /** Notified with a GLUint and const char* when a tile goes out of scope. */ + EventVar on_delete; + + /** + * Return mutex to lock given tile. There is a fixed number of mutexes + * available, the mutex returned might collide with another id causing + * random serialization. + */ + static std::mutex& GetMutex(uint64_t tile_id); + + /** + * Return mutex to lock given tile. There is a fixed number of mutexes + * available, the mutex returned might collide with another id causing + * random serialization. + */ + static std::mutex& GetMutex(const SharedTilePtr& tile); + + /** Flush the tile cache, including OpenGL texture memory if needed */ + void Flush() { m_tile_map.clear(); } + + /** + * Get the north limit of the cache area for a given zoom in WMTS coordinates. + */ + int GetNorthLimit(int zoom_level) { + return zoom_table[zoom_level - m_min_zoom].m_tile_y_max; + } + + /** + * Get the south limit of the cache area for a given zoom in WMTS coordinates. + */ + int GetSouthLimit(int zoom_level) { + return zoom_table[zoom_level - m_min_zoom].m_tile_y_min; + } + + /** + * Get the current cache size. + * @return Number of tiles in cache. + */ + uint32_t GetCacheSize() const { return m_tile_map.size(); } + + /** + * Retreive a tile from cache. If the tile is not present an empty tile + * is created, added and returned. + * @param z Tile zoom level. + * @param x Tile x coordinate. + * @param y Tile y coordinate. + * @return Pointer to tile + */ + SharedTilePtr GetTile(int z, int x, int y); + + /** + * Reduce the size of the cache if it exceeds the given limit. Must + * only be called by rendering thread since it uses OpenGL calls. + * @param max_tiles Maximum number of tiles to be kept in the cache. + */ + void CleanCache(uint32_t max_tiles); + + void DeepCleanCache(); +}; + +#endif diff --git a/gui/src/mbtiles/tile_descr.h b/gui/src/mbtiles/tile_descr.h new file mode 100644 index 0000000000..08645958c8 --- /dev/null +++ b/gui/src/mbtiles/tile_descr.h @@ -0,0 +1,141 @@ +#ifndef _MBTILES_TILEDESCRIPTOR_H_ +#define _MBTILES_TILEDESCRIPTOR_H_ + +#include +#include +#include +#include +#include + +#include "chartbase.h" +#include "glChartCanvas.h" +#include "observable_evtvar.h" + +class MbTileDescriptor; // forward + +using SharedTilePtr = std::shared_ptr; + +static const double kEps = 6e-6; // about 1cm on earth's surface at equator + +class MbTileDescriptor { +public: + int m_tile_x; + int m_tile_y; + int m_zoom_level; + float m_latmin; + float m_lonmin; + float m_latmax; + float m_lonmax; + LLBBox m_box; + std::chrono::milliseconds m_last_used; + + /// Set to true if a load request from main thread is already pending for this + /// tile + bool m_requested; + + /// Pointer to the decompressed tile image + unsigned char* m_teximage; + + /// Identifier of the tile texture in OpenGL memory + GLuint m_gl_texture_name; + + /// Set to true if the tile has not been found into the SQL database. + std::atomic m_is_available; + + /** Notified on delete. */ + EventVar& m_on_delete; + + MbTileDescriptor(int zoom_level, int x, int y, EventVar& on_delete) + : m_tile_x(x), + m_tile_y(y), + m_zoom_level(zoom_level), + // Calculate tile boundaries + m_latmin(round(MbTileDescriptor::Tiley2lat(m_tile_y - 1, zoom_level) / + kEps) * + kEps), + m_lonmin( + round(MbTileDescriptor::Tilex2long(m_tile_x, zoom_level) / kEps) * + kEps), + m_latmax( + round(MbTileDescriptor::Tiley2lat(m_tile_y, zoom_level) / kEps) * + kEps), + m_lonmax(round(MbTileDescriptor::Tilex2long(m_tile_x + 1, zoom_level) / + kEps) * + kEps), + m_requested(false), + m_teximage(nullptr), + m_gl_texture_name(0), + m_is_available(true), + m_on_delete(on_delete) { + m_box.Set(m_latmin, m_lonmin, m_latmax, m_lonmax); + SetTimestamp(); + } + + virtual ~MbTileDescriptor() { + if (m_gl_texture_name || m_teximage) { + // Message to main thread: Deallocate GL buffers. + m_on_delete.Notify(static_cast(m_gl_texture_name), m_teximage); + m_gl_texture_name = 0; + m_teximage = nullptr; + } + } + /** + * Generate an unique 64 bit key/identifier for a tile. This key can + * be used to uniquely reference tiles in an unordered_map or other similar + * list, with not risk of key collision up to zoom level 20 + * @param z Tile Zoom level. + * @param x Tile x coordinate. + * @param y Tile y coordinate. + * @return Unique 64 bit key for tile + */ + static uint64_t GetMapKey(int z, int x, int y) { + return ((uint64_t)z << 40) | ((uint64_t)y << 20) | x; + } + + /** + * Generate a unique 64 bit key/identifier for tile. This key can + * be used to uniquely reference tiles in a unordered_map or other similar + * list, with not risk of key collision up to zoom level 20 + * @return Unique 64 bit key for tile + */ + uint64_t GetMapKey() { + return MbTileDescriptor::GetMapKey(m_zoom_level, m_tile_x, m_tile_y); + } + + static int Long2tilex(double lon, int z) { + if (lon < -180) lon += 360; + return (int)(floor((lon + 180.0) / 360.0 * (1 << z))); + } + + static int Lat2tiley(double lat, int z) { + int y = (int)(floor( + (1.0 - + log(tan(lat * M_PI / 180.0) + 1.0 / cos(lat * M_PI / 180.0)) / M_PI) / + 2.0 * (1 << z))); + int ymax = 1 << z; + y = ymax - y - 1; + return y; + } + + static double Tilex2long(int x, int z) { + return x / (double)(1 << z) * 360.0 - 180; + } + + static double Tiley2lat(int y, int z) { + // double n = pow(2.0, z); + double n = 1 << z; + int ymax = 1 << z; + y = ymax - y - 1; + double lat_rad = atan(sinh(M_PI * (1 - (2 * y / n)))); + return 180.0 / M_PI * lat_rad; + } + + /** Update m_last_used to current time. */ + void SetTimestamp() { + using namespace std::chrono; + m_last_used = + duration_cast(system_clock::now().time_since_epoch()); + } +}; + +#endif /* _MBTILES_TILEDESCRIPTOR_H_ */ diff --git a/gui/src/mbtiles/tile_queue.h b/gui/src/mbtiles/tile_queue.h new file mode 100644 index 0000000000..c7666f36ea --- /dev/null +++ b/gui/src/mbtiles/tile_queue.h @@ -0,0 +1,53 @@ +#ifndef _MBTILESTILEQUEUE_H_ +#define _MBTILESTILEQUEUE_H_ + +#include +#include +#include + +#include "tile_descr.h" + +/** A thread safe tile queue between two threads. */ +class TileQueue { +public: + TileQueue() {} + + /** + * Push a tile to the queue. + * @param tile Pointer to tile descriptor to be pushed. + */ + void Push(SharedTilePtr tile) { + { + std::lock_guard lock(m_mutex); + m_tile_list.push_back(tile); + } + m_cv.notify_all(); + } + + /** + * Retrieve a tile from the queue. If there is no tile in the queue, + * calling thread is blocked until a tile is available. + * + * @return Pointer to tile descriptor + */ + SharedTilePtr Pop() { + std::unique_lock lock(m_mutex); + m_cv.wait(lock, [&] { return m_tile_list.size() > 0; }); + auto tile = m_tile_list.at(0); + m_tile_list.erase(m_tile_list.cbegin()); + return tile; + } + + /** Retrieve current size of queue. */ + uint32_t GetSize() { + std::lock_guard lock(m_mutex); + return m_tile_list.size(); + } + +private: + std::vector m_tile_list; + std::mutex m_mutex; + std::condition_variable m_cv; +}; + +#endif diff --git a/gui/src/mbtiles/WorkerThread.cpp b/gui/src/mbtiles/tile_thread.cpp similarity index 69% rename from gui/src/mbtiles/WorkerThread.cpp rename to gui/src/mbtiles/tile_thread.cpp index 91efc8851d..6913beb18a 100644 --- a/gui/src/mbtiles/WorkerThread.cpp +++ b/gui/src/mbtiles/tile_thread.cpp @@ -1,42 +1,39 @@ #include + #include + #include "dychart.h" -#include "WorkerThread.hpp" +#include "tile_thread.h" +#include "tile_cache.h" #ifdef __WXMSW__ -void my_translate_mbtile(unsigned int code, _EXCEPTION_POINTERS *ep) { +void my_translate_mbtile(unsigned int code, _EXCEPTION_POINTERS* ep) { throw SE_Exception(); } #endif -/// @brief Worker thread of the MbTiles chart decoder. It receives requests from -/// the MbTile front-end to load and uncompress tiles from an MbTiles file. Once -/// done, the tile list in memory is updated and a refresh of the map triggered. - -/// @brief Request a tile to be loaded by the thread. This method is thread -/// safe. -/// @param tile Pointer to the tile to load -void MbtTilesThread::RequestTile(mbTileDescriptor *tile) { +/** + * Request a tile to be loaded by the thread. This method is thread + * safe. + * @param tile Pointer to the tile to load + */ +void MbtTilesThread::RequestTile(SharedTilePtr tile) { tile->m_requested = true; - m_tileQueue.Push(tile); + m_tile_queue.Push(tile); } -/// @brief Request the thread to stop/delete itself void MbtTilesThread::RequestStop() { - // Set the exit request boolean - m_exitThread = true; - // Force worker thread to wake-up - m_tileQueue.Push(nullptr); + m_exit_thread = true; + m_tile_queue.Push(nullptr); while (!m_finished) { + wxYield(); } } -size_t MbtTilesThread::GetQueueSize() { return m_tileQueue.GetSize(); } +size_t MbtTilesThread::GetQueueSize() { return m_tile_queue.GetSize(); } -/// @brief Main loop of the worker thread -/// @return Always 0 -wxThread::ExitCode MbtTilesThread::Entry() { +void MbtTilesThread::Run() { #ifdef __MSVC__ _set_se_translator(my_translate_mbtile); @@ -47,11 +44,10 @@ wxThread::ExitCode MbtTilesThread::Entry() { #endif - mbTileDescriptor *tile; - + SharedTilePtr tile; do { // Wait for the next job - tile = m_tileQueue.Pop(); + tile = m_tile_queue.Pop(); // Only process non null tiles. A null pointer can be sent to force the // thread to check for a deletion request if (tile != nullptr) { @@ -59,33 +55,29 @@ wxThread::ExitCode MbtTilesThread::Entry() { } // Only request a refresh of the display when there is no more tiles in // the queue. - if (m_tileQueue.GetSize() == 0) { + if (m_tile_queue.GetSize() == 0) { wxGetApp().GetTopWindow()->GetEventHandler()->CallAfter( &MyFrame::RefreshAllCanvas, true); } // Check if the thread has been requested to be destroyed - } while ((TestDestroy() == false) && (m_exitThread == false)); + } while (!m_exit_thread); // Since the worker is a detached thread, we need a special mecanism to // allow the main thread to wait for its deletion m_finished = true; - - return (wxThread::ExitCode)0; } -/// @brief Load bitmap data of a tile from the MbTiles file to the tile cache -/// @param tile Pointer to the tile to be loaded -void MbtTilesThread::LoadTile(mbTileDescriptor *tile) { +void MbtTilesThread::LoadTile(SharedTilePtr tile) { std::lock_guard lock(TileCache::GetMutex(tile)); // If the tile has not been found in the SQL database in a previous attempt, // don't search for it again - if (!tile->m_bAvailable) return; + if (!tile->m_is_available) return; // If the tile has already been uncompressed, don't uncompress it // again if (tile->m_teximage != nullptr) return; - if (tile->glTextureName > 0) return; + if (tile->m_gl_texture_name > 0) return; // Fetch the tile data from the mbtile database try { @@ -95,19 +87,19 @@ void MbtTilesThread::LoadTile(mbTileDescriptor *tile) { sprintf(qrs, "select tile_data, length(tile_data) from tiles where zoom_level " "= %d AND tile_column=%d AND tile_row=%d", - tile->m_zoomLevel, tile->tile_x, tile->tile_y); - SQLite::Statement query(*m_pDB, qrs); + tile->m_zoom_level, tile->m_tile_x, tile->m_tile_y); + SQLite::Statement query(*m_db, qrs); int queryResult = query.tryExecuteStep(); if (SQLITE_DONE == queryResult) { // The tile has not been found in databse, mark it as "not available" so // that we won't try to find it again later - tile->m_bAvailable = false; + tile->m_is_available = false; return; } else { // Get the blob SQLite::Column blobColumn = query.getColumn(0); - const void *blob = blobColumn.getBlob(); + const void* blob = blobColumn.getBlob(); // Get the length int length = query.getColumn(1); @@ -116,7 +108,7 @@ void MbtTilesThread::LoadTile(mbTileDescriptor *tile) { wxImage blobImage; blobImage = wxImage(blobStream, wxBITMAP_TYPE_ANY); int blobWidth, blobHeight; - unsigned char *imgdata; + unsigned char* imgdata; // Check that the tile is OK and rescale it to 256x256 if necessary if (blobImage.IsOk()) { @@ -129,14 +121,14 @@ void MbtTilesThread::LoadTile(mbTileDescriptor *tile) { } else { // wxWidget can't uncompress the tile : mark it as not available and // exit - tile->m_bAvailable = false; + tile->m_is_available = false; return; } if (!imgdata) { // wxWidget can't uncompress the tile : mark it as not available and // exit - tile->m_bAvailable = false; + tile->m_is_available = false; return; } @@ -144,7 +136,7 @@ void MbtTilesThread::LoadTile(mbTileDescriptor *tile) { int tex_w = 256; int tex_h = 256; // Copy and process the tile - unsigned char *teximage = (unsigned char *)malloc(stride * tex_w * tex_h); + unsigned char* teximage = (unsigned char*)malloc(stride * tex_w * tex_h); if (!teximage) return; bool transparent = blobImage.HasAlpha(); @@ -178,12 +170,12 @@ void MbtTilesThread::LoadTile(mbTileDescriptor *tile) { #ifdef __MSVC__ catch (SE_Exception e) { wxLogMessage("MbTiles: SE_Exception"); - tile->m_bAvailable = false; + tile->m_is_available = false; tile->m_teximage = 0; } #else - catch (std::exception &e) { - const char *t = e.what(); + catch (std::exception& e) { + const char* t = e.what(); wxLogMessage("mbtiles std::exception: %s", e.what()); } #endif diff --git a/gui/src/mbtiles/tile_thread.h b/gui/src/mbtiles/tile_thread.h new file mode 100644 index 0000000000..d415d04df8 --- /dev/null +++ b/gui/src/mbtiles/tile_thread.h @@ -0,0 +1,84 @@ + +#ifndef _MBTILESTHREAD_H_ +#define _MBTILESTHREAD_H_ + +#include + +#include +#include + +#include +#include + +#include "chartbase.h" +#include "ocpn_frame.h" +#include "ocpn_app.h" +#include "tile_queue.h" + +#ifdef __WXMSW__ +class SE_Exception { +private: + unsigned int nSE; + +public: + SE_Exception() {} + SE_Exception(unsigned int n) : nSE(n) {} + ~SE_Exception() {} + unsigned int getSeNumber() { return nSE; } +}; + +#endif + +/** + * MbTiles chart decoder worker thread. Receives requests from + * the MbTile front-end to load and uncompress tiles from an MbTiles file. Once + * done, the tile list in memory is updated and a refresh of the map triggered. + */ +class MbtTilesThread { +public: + /** + * Create worker thread instance. + * @param pDB Pointer to SQL database handler. + */ + MbtTilesThread(std::shared_ptr db) + : m_exit_thread(false), m_finished(false), m_db(db) {} + + virtual ~MbtTilesThread() {} + + /** + * Request a tile to be loaded by the thread. This method is thread + * safe. + * @param tile Pointer to tile to load + */ + void RequestTile(SharedTilePtr tile); + + /** Request the thread to stop/delete itself. */ + void RequestStop(); + + /** Return number of tiles in worker thread queue. */ + size_t GetQueueSize(); + + /** Worker thread main loop. */ + virtual void Run(); + +private: + /// Set to true to tell the main loop to stop execution + bool m_exit_thread; + + /// Set to true when the thread has finished + bool m_finished; + + /// The queue storing all the tile requests + TileQueue m_tile_queue; + + /// Pointer to SQL object managing the MbTiles file + std::shared_ptr m_db; + + /** + * Load bitmap data of a tile from the MbTiles file to the tile cache + * @param tile Pointer to the tile to be loaded + */ + void LoadTile(SharedTilePtr tile); +}; + +#endif /* _MBTILESTHREAD_H_ */ diff --git a/libs/manual/CMakeLists.txt b/libs/manual/CMakeLists.txt new file mode 100644 index 0000000000..3457f1ca03 --- /dev/null +++ b/libs/manual/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.5) + +if (TARGET ocpn::manual) + return () +endif () + +set( SRC + src/manual.cpp + src/manual_dlg.cpp + include/manual.h + include/manual_dlg.h +) +set(CMAKE_CXX_STANDARD 17) +add_library(_MANUAL STATIC ${SRC}) +add_library(ocpn::manual ALIAS _MANUAL) +set_property(TARGET _MANUAL PROPERTY POSITION_INDEPENDENT_CODE ON) + +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|GNU") # Apple is AppleClang + target_compile_options(_MANUAL PRIVATE -fvisibility=default) +endif () +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + target_compile_options(_MANUAL PRIVATE -x c++) +endif () + + +target_include_directories(_MANUAL PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +target_include_directories(_MANUAL PRIVATE ${wxWidgets_INCLUDE_DIRS}) +target_link_libraries(_MANUAL PRIVATE ${wxWidgets_LIBRARIES}) +target_link_libraries(_MANUAL PRIVATE ocpn::filesystem) +target_link_libraries(_MANUAL PRIVATE ocpn::wxjson) diff --git a/libs/manual/include/manual.h b/libs/manual/include/manual.h new file mode 100644 index 0000000000..c0271c793b --- /dev/null +++ b/libs/manual/include/manual.h @@ -0,0 +1,61 @@ + +/*************************************************************************** + * Copyright (C) 2024 Alec Leamas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + **************************************************************************/ + +/** \file manual.h Tools to invoke the manual provided by manual_pi. */ + +#ifndef MANUAL_H_ +#define MANUAL_H_ + +#include + +#include +#include + +class Manual { +public: + /** + * Construct a Manual object. + * + * @param path Manual plugin data directory as returned by + * GetPluginDataDir("manual") + */ + Manual(wxWindow* parent, const std::string& path); + + /** + * Launch a web browser displaying a manual entry point. If the manual + * plugin is installed use that, otherwise offer user to use the on-line + * manual. + * + * @param entrypoint Named entry in the entrypoints.json file provided + * by the manual_pi plugin. If the plugin is not installed a + * hardcoded list of entrypoints provides internet links. See + * kOnlineEntries in manual_pi.cpp for list of valid values. + * @return true if entrypoint exists in entrypoints.json, else false + * + */ + bool Launch(const std::string& entrypoint); + +private: + std::string m_datadir; + wxJSONValue m_root; + wxWindow* m_parent; +}; + +#endif // MANUAL_H_ diff --git a/libs/manual/include/manual_dlg.h b/libs/manual/include/manual_dlg.h new file mode 100644 index 0000000000..e27326be98 --- /dev/null +++ b/libs/manual/include/manual_dlg.h @@ -0,0 +1,39 @@ + +/*************************************************************************** + * Copyright (C) 2024 Alec Leamas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + **************************************************************************/ + +/** \file manual_dlg.h The "manual not found" dialog. */ + +#ifndef MANUAL_DLG_H_ +#define MANUAL_DLG_H_ + +#include + +#include + +/** Dialog handling "Manual not found" */ +class ManualDlg : public wxDialog { +public: + ManualDlg(wxWindow* parent, const std::string& url); + +private: + const std::string m_url; +}; + +#endif // MANUAL_DLG_H_ diff --git a/libs/manual/src/manual.cpp b/libs/manual/src/manual.cpp new file mode 100644 index 0000000000..798970ad81 --- /dev/null +++ b/libs/manual/src/manual.cpp @@ -0,0 +1,98 @@ + +/*************************************************************************** + * Copyright (C) 2024 Alec Leamas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + **************************************************************************/ + +/** \file manual.cpp Implement manual.h */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "manual.h" +#include "manual_dlg.h" +#include "std_filesystem.h" + +static const char* const kOnlineRoot = "https://opencpn-manuals.github.io/main"; +static const char* const kOnlinePlugroot = + "https://opencpn-manuals.github.io/main/opencpn-plugins"; +static const char* const kWikiRoot = + "https://opencpn.org/wiki/dokuwiki/doku.php"; + + +static const std::unordered_map kOnlineEntries = { + {"Toc", "@ONLINE_ROOT@/index.html"}, + {"Chartdldr", + "@ONLINE_PLUGROOT@/chart_downloader_tab/chart_downloader_tab.html"}, + {"Wmm", "@ONLINE_PLUGROOT@/wmm/wmm.html"}, + {"Dashboard", "@ONLINE_PLUGROOT@/dashboard/dashboard.html"}, + {"Grib", "@ONLINE_PLUGROOT@/grib_weather/grib_weather.html"}, + {"Hotkeys", + "@WIKI_ROOT@?id=opencpn:manual_basic:ui_user_interface:keyboard_shortcuts" } +}; + +static bool replace(std::string& str, const std::string& from, + const std::string& to) { + size_t start_pos = str.find(from); + if (start_pos == std::string::npos) return false; + str.replace(start_pos, from.length(), to); + return true; +} + +Manual::Manual(wxWindow* parent, const std::string& path) + : m_datadir(path), m_parent(parent) { + auto datadir_path(fs::path(m_datadir) / "data" / "entrypoints.json"); + if (!fs::exists(datadir_path)) { + wxLogDebug("Manual plugin is not installed"); + return; + } + std::ifstream stream(datadir_path.string()); + std::stringstream ss; + ss << stream.rdbuf(); + wxJSONReader reader; + int err_count = reader.Parse(ss.str(), &m_root); + if (err_count != 0) { + wxLogWarning("Cannot parse entrypoints.json from manual plugin"); + } +} + +bool Manual::Launch(const std::string& entrypoint) { + std::string path(m_root[entrypoint].AsString()); + replace(path, "@LOCAL_ROOT@", m_datadir); + if (fs::exists(fs::path(path))) { + wxLaunchDefaultBrowser(path); + return true; + } + auto found = kOnlineEntries.find(entrypoint); + if (found == kOnlineEntries.end()) { + wxLogWarning("Using illegal manual entry point: %s", entrypoint.c_str()); + return false; + } + path = found->second; + replace(path, "@ONLINE_PLUGROOT@", kOnlinePlugroot); + replace(path, "@ONLINE_ROOT@", kOnlineRoot); + replace(path, "@WIKI_ROOT@", kWikiRoot); + ManualDlg dlg(m_parent, path); + dlg.ShowModal(); + return true; +} diff --git a/libs/manual/src/manual_dlg.cpp b/libs/manual/src/manual_dlg.cpp new file mode 100644 index 0000000000..be22c9dc78 --- /dev/null +++ b/libs/manual/src/manual_dlg.cpp @@ -0,0 +1,81 @@ + +/*************************************************************************** + * Copyright (C) 2024 Alec Leamas * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + **************************************************************************/ + +/** \file manual_dlg.cpp Implement manual_dlg.h */ + +#include +#include +#include +#include +#include + +#include "manual_dlg.h" + +const char* const kMessage = _(R"--( +The off-line manual is not installed. To make it +available install the "manual" plugin. + +If you are connected to the Internet you might want +to try the on-line manual instead +)--"); + +/** The two "browse on-line" and "Close" buttons at bottom */ +class ButtonsSizer : public wxStdDialogButtonSizer { +public: + + /** The "Browse on-line manual" button */ + class OnLineButton : public wxButton { + public: + OnLineButton(wxWindow* parent, const std::string& url) + : wxButton(parent, wxID_OK, _("Browse on-line manual")) { + Bind(wxEVT_COMMAND_BUTTON_CLICKED, + [url](wxCommandEvent) { wxLaunchDefaultBrowser(url); }); + } + }; + + /** The Close button */ + class CloseButton : public wxButton { + public: + CloseButton(wxDialog* parent) : wxButton(parent, wxID_CLOSE) { + Bind(wxEVT_COMMAND_BUTTON_CLICKED, + [parent](wxCommandEvent) { parent->EndModal(wxID_OK); }); + }; + }; + + ButtonsSizer(wxDialog* parent, const std::string& url) + : wxStdDialogButtonSizer() { + AddButton(new OnLineButton(parent, url)); + AddButton(new CloseButton(parent)); + Realize(); + } +}; + +/** Overall "Local manual not found" window" */ +ManualDlg::ManualDlg(wxWindow* parent, const std::string& url) + : wxDialog(parent, wxID_ANY, "Manual not found"), m_url(url) { + + auto vbox = new wxBoxSizer(wxVERTICAL); + auto flags = wxSizerFlags().Expand().DoubleBorder(); + vbox->Add(new wxStaticText(this, wxID_ANY, kMessage), flags); + vbox->Add(new ButtonsSizer(this, url), flags); + SetSizer(vbox); + Fit(); + Layout(); +} diff --git a/libs/observable/include/observable_evtvar.h b/libs/observable/include/observable_evtvar.h index ce4f01274c..3fde5cac84 100644 --- a/libs/observable/include/observable_evtvar.h +++ b/libs/observable/include/observable_evtvar.h @@ -83,6 +83,10 @@ class EventVar : public Observable { /** Notify all listeners about variable change with a string and an int */ const void Notify(int n, const std::string& s) { Observable::Notify(0, s, n, 0); } + + /** Notify all listeners about variable change with an int and ClientData */ + const void Notify(int n, void* p) { Observable::Notify(0, "", n, p); } + /** * Notify all listeners about variable change with shared_ptr, * a string and an optional number. diff --git a/libs/std_filesystem/CMakeLists.txt b/libs/std_filesystem/CMakeLists.txt index 04038f850b..fa270f1ce3 100644 --- a/libs/std_filesystem/CMakeLists.txt +++ b/libs/std_filesystem/CMakeLists.txt @@ -23,6 +23,11 @@ # # Exports: ocpn::filesystem transitive link target # +# Usage: +# #include "std_filesystem.h" +# ... +# auto p = fs::path("/some/path"); +# if (TARGET ocpn::filesystem) return () @@ -35,6 +40,10 @@ if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) target_link_libraries(_FILESYS INTERFACE stdc++fs) endif () +target_include_directories( + _FILESYS INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include +) + string(TOLOWER ${CMAKE_CXX_COMPILER_ID} lc_compiler_id) if ((${lc_compiler_id} MATCHES clang AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 15.0) @@ -43,9 +52,6 @@ if ((${lc_compiler_id} MATCHES clang # MacOS 10.13 # Boost pulled in from Homebrew on the builders is not good enough as # it is not ABI compatible with older targets, use ghc instead. - target_include_directories( - _FILESYS INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include - ) if(APPLE) target_compile_definitions(_FILESYS INTERFACE OCPN_GHC_FILESYSTEM) endif() diff --git a/libs/std_filesystem/include/std_filesystem.h b/libs/std_filesystem/include/std_filesystem.h new file mode 100644 index 0000000000..d500ee41fd --- /dev/null +++ b/libs/std_filesystem/include/std_filesystem.h @@ -0,0 +1,11 @@ +// MacOS 1.13: +#if (defined(OCPN_GHC_FILESYSTEM) || \ + (defined(__clang_major__) && (__clang_major__ < 15))) +#include +namespace fs = ghc::filesystem; + +#else +#include +#include +namespace fs = std::filesystem; +#endif diff --git a/manual/modules/ROOT/pages/create-deb-package.adoc b/manual/modules/ROOT/pages/create-deb-package.adoc index af7c9c188f..69737058bf 100644 --- a/manual/modules/ROOT/pages/create-deb-package.adoc +++ b/manual/modules/ROOT/pages/create-deb-package.adoc @@ -95,14 +95,10 @@ The standard message for a new version is "New upstream Release". === Import a release tag into upstream/latest -For now, the debian directory needs to be removed. After that, create a -tarball based on HEAD. Using v5.9.3-beta3 as example: +Create an archive based on a tag. +Using the tag v5.9.3-beta3 as example: - $ git checkout git checkout v5.9.3-beta3 - $ git switch -c tmp-build - $ git rm -r debian - $ git commit -m "Remove unused debian/ dir" - $ git archive --prefix opencpn-5.9.3-beta3/ --output ../opencpn.tar.gz HEAD + $ git archive --prefix opencpn-5.9.3-beta3/ --output ../opencpn.tar.gz v5.9.3-beta3 The `--prefix` part should be modified to reflect current version, but is not critical. Note the trailing slash! @@ -140,36 +136,25 @@ above>> creating a downstream release goes like: 1. Initiate the environment as described <>. 2. Clone and checkout all branches, see <>. -3. Create a orig.tar.xz tarball in .. - - $ gbp export-orig - -This is a one time setup, the results can be used in various branches like -ubuntu/jammy and debian/bookworm. For each release do: 1. Checkout the actual branch like ubuntu/jammy. Work on ubuntu branches must be done on an ubuntu host -2. Create a provisional version entry in _debian/changelog_ using `dch -R`. -3. Merge upstream changes using `gbp import-ref -u5.9.3-beta3`. The -u argument is - the last part of an upstream tag like `upstream/5.9.3-beta3` - This command fails in some branch(es), see below. -4. Do possible changes in the new release. +2. Create a provisional version entry in _debian/changelog_ using + something like `dch -v 1:5.10.2+dfsg-1ubuntu1~bpo20.04+2`. +3. Create a orig.tar.xz tarball in .. using `gbp export-orig`. +4. Merge upstream changes using `gbp import-ref -u5.9.3-beta3`. + The -u argument is the last part of an upstream tag like + `upstream/5.9.3-beta3`. +5. Do possible changes in the new release. Note that only files in the _debian/_ directory can be modified; changes in other files are handled using patches in _debian/patches_. See Modifying Sources <> -5. Commit all changes. -6. Finalize the changelog entry using `dch -r`. -7. Commit the change in _debian/changelog_ -8. Push the actual branch, for example `git push upstream ubuntu/jammy` - -If `gbp import-ref` fails, use the tarball created by `gbp export-orig` -instead. For this to work, the corresponding tag should be deleted. -Something like - - $ git tag -d upstream/5.8.4+dfsg - $ gbp import-orig ../opencpn_5.8.4~beta4+dfsg.orig.tar.xz +6. Commit all changes. +7. Finalize the changelog entry using `dch -r`. +8. Commit the change in _debian/changelog_ +9. Push the actual branch, for example `git push upstream ubuntu/jammy` [#publish] == Publish existing downstream release to PPA diff --git a/manual/modules/ROOT/pages/linux.adoc b/manual/modules/ROOT/pages/linux.adoc index 7d57061e6e..fdf5ebb83b 100644 --- a/manual/modules/ROOT/pages/linux.adoc +++ b/manual/modules/ROOT/pages/linux.adoc @@ -4,7 +4,7 @@ image::opencpn_dev_linux_0.png[width=50] == Documented platforms The documentation here covers Debian/Ubuntu and Flatpak. Debian .deb -packages and Flatpaks are the primary deployment platforms for Linux. +packages and Flatpak are the primary deployment platforms for Linux. It is certainly possible to compile OpenCPN on other Linux distributions by adapting these instructions. @@ -27,9 +27,6 @@ is the ultimate source for how to build on Linux. $ sudo apt-get --allow-unauthenticated install -f Notes: - - * On old systems like Debian Buster and Ubuntu Bionic it is possible to build - OpenCPN linked against gtk2 or gtk3. The default alternative is to use gtk3. * The build setup is generally updated for Debian and Ubuntu LTS releases. @@ -58,13 +55,11 @@ the appropriate option to cmake: _cmake_ is only required when building source code for the first time, then running _make_ is enough even if the source code is updated. -=== 5. Install it or create a package +=== 5. Install $ sudo make install -Or, to create a .deb package: - - $ make package +Creating .deb packages is documented in the xref:/create-deb-package.adoc[Debian packaging page] == Flatpak diff --git a/plugins/chartdldr_pi/CMakeLists.txt b/plugins/chartdldr_pi/CMakeLists.txt index 18899e29a7..e45851adf8 100644 --- a/plugins/chartdldr_pi/CMakeLists.txt +++ b/plugins/chartdldr_pi/CMakeLists.txt @@ -167,6 +167,7 @@ endif () find_package(OcpnLibarchive) target_link_libraries(${PACKAGE_NAME} PUBLIC ocpn::libarchive) +target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::manual) if (APPLE AND OCPN_USE_SYSTEM_LIBARCHIVE) # If we use system libarchive, we do not bundle the dylib and need to # comment it out from the pkg project file diff --git a/plugins/chartdldr_pi/data/doc/03-Chart-Downloader-Tab-First-Time.png b/plugins/chartdldr_pi/data/doc/03-Chart-Downloader-Tab-First-Time.png deleted file mode 100644 index ebb505021d..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/03-Chart-Downloader-Tab-First-Time.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/04-AddNewChartSource-Predefined.png b/plugins/chartdldr_pi/data/doc/04-AddNewChartSource-Predefined.png deleted file mode 100644 index d9b9cc08cb..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/04-AddNewChartSource-Predefined.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/05-PleaseUpdate.png b/plugins/chartdldr_pi/data/doc/05-PleaseUpdate.png deleted file mode 100644 index f20ef3cf81..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/05-PleaseUpdate.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/08-AfterDownloading.png b/plugins/chartdldr_pi/data/doc/08-AfterDownloading.png deleted file mode 100644 index d746e20d84..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/08-AfterDownloading.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/12-Add-Edit-Custom-Chart-Source.png b/plugins/chartdldr_pi/data/doc/12-Add-Edit-Custom-Chart-Source.png deleted file mode 100644 index 94c097fb6a..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/12-Add-Edit-Custom-Chart-Source.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/15-Chart-Status-Selection.png b/plugins/chartdldr_pi/data/doc/15-Chart-Status-Selection.png deleted file mode 100644 index 5b8c785dcd..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/15-Chart-Status-Selection.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/16-Show-Local-Files.png b/plugins/chartdldr_pi/data/doc/16-Show-Local-Files.png deleted file mode 100644 index 373d83cfa7..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/16-Show-Local-Files.png and /dev/null differ diff --git a/plugins/chartdldr_pi/data/doc/MathJax.js b/plugins/chartdldr_pi/data/doc/MathJax.js deleted file mode 100644 index a5bdfc4791..0000000000 --- a/plugins/chartdldr_pi/data/doc/MathJax.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * /MathJax.js - * - * Copyright (c) 2009-2015 The MathJax Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -if(document.getElementById&&document.childNodes&&document.createElement){if(!(window.MathJax&&MathJax.Hub)){if(window.MathJax){window.MathJax={AuthorConfig:window.MathJax}}else{window.MathJax={}}MathJax.isPacked=true;MathJax.version="2.5.1";MathJax.fileversion="2.5.1";MathJax.cdnVersion="2.5.1";MathJax.cdnFileVersions={};(function(d){var b=window[d];if(!b){b=window[d]={}}var e=[];var c=function(f){var g=f.constructor;if(!g){g=function(){}}for(var h in f){if(h!=="constructor"&&f.hasOwnProperty(h)){g[h]=f[h]}}return g};var a=function(){return function(){return arguments.callee.Init.call(this,arguments)}};b.Object=c({constructor:a(),Subclass:function(f,h){var g=a();g.SUPER=this;g.Init=this.Init;g.Subclass=this.Subclass;g.Augment=this.Augment;g.protoFunction=this.protoFunction;g.can=this.can;g.has=this.has;g.isa=this.isa;g.prototype=new this(e);g.prototype.constructor=g;g.Augment(f,h);return g},Init:function(f){var g=this;if(f.length===1&&f[0]===e){return g}if(!(g instanceof f.callee)){g=new f.callee(e)}return g.Init.apply(g,f)||g},Augment:function(f,g){var h;if(f!=null){for(h in f){if(f.hasOwnProperty(h)){this.protoFunction(h,f[h])}}if(f.toString!==this.prototype.toString&&f.toString!=={}.toString){this.protoFunction("toString",f.toString)}}if(g!=null){for(h in g){if(g.hasOwnProperty(h)){this[h]=g[h]}}}return this},protoFunction:function(g,f){this.prototype[g]=f;if(typeof f==="function"){f.SUPER=this.SUPER.prototype}},prototype:{Init:function(){},SUPER:function(f){return f.callee.SUPER},can:function(f){return typeof(this[f])==="function"},has:function(f){return typeof(this[f])!=="undefined"},isa:function(f){return(f instanceof Object)&&(this instanceof f)}},can:function(f){return this.prototype.can.call(this,f)},has:function(f){return this.prototype.has.call(this,f)},isa:function(g){var f=this;while(f){if(f===g){return true}else{f=f.SUPER}}return false},SimpleSUPER:c({constructor:function(f){return this.SimpleSUPER.define(f)},define:function(f){var h={};if(f!=null){for(var g in f){if(f.hasOwnProperty(g)){h[g]=this.wrap(g,f[g])}}if(f.toString!==this.prototype.toString&&f.toString!=={}.toString){h.toString=this.wrap("toString",f.toString)}}return h},wrap:function(i,h){if(typeof(h)!=="function"||!h.toString().match(/\.\s*SUPER\s*\(/)){return h}var g=function(){this.SUPER=g.SUPER[i];try{var f=h.apply(this,arguments)}catch(j){delete this.SUPER;throw j}delete this.SUPER;return f};g.toString=function(){return h.toString.apply(h,arguments)};return g}})})})("MathJax");(function(BASENAME){var BASE=window[BASENAME];if(!BASE){BASE=window[BASENAME]={}}var CALLBACK=function(data){var cb=function(){return arguments.callee.execute.apply(arguments.callee,arguments)};for(var id in CALLBACK.prototype){if(CALLBACK.prototype.hasOwnProperty(id)){if(typeof(data[id])!=="undefined"){cb[id]=data[id]}else{cb[id]=CALLBACK.prototype[id]}}}cb.toString=CALLBACK.prototype.toString;return cb};CALLBACK.prototype={isCallback:true,hook:function(){},data:[],object:window,execute:function(){if(!this.called||this.autoReset){this.called=!this.autoReset;return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)))}},reset:function(){delete this.called},toString:function(){return this.hook.toString.apply(this.hook,arguments)}};var ISCALLBACK=function(f){return(typeof(f)==="function"&&f.isCallback)};var EVAL=function(code){return eval.call(window,code)};var TESTEVAL=function(){EVAL("var __TeSt_VaR__ = 1");if(window.__TeSt_VaR__){try{delete window.__TeSt_VaR__}catch(error){window.__TeSt_VaR__=null}}else{if(window.execScript){EVAL=function(code){BASE.__code=code;code="try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";window.execScript(code);var result=BASE.__result;delete BASE.__result;delete BASE.__code;if(result instanceof Error){throw result}return result}}else{EVAL=function(code){BASE.__code=code;code="try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";var head=(document.getElementsByTagName("head"))[0];if(!head){head=document.body}var script=document.createElement("script");script.appendChild(document.createTextNode(code));head.appendChild(script);head.removeChild(script);var result=BASE.__result;delete BASE.__result;delete BASE.__code;if(result instanceof Error){throw result}return result}}}TESTEVAL=null};var USING=function(args,i){if(arguments.length>1){if(arguments.length===2&&!(typeof arguments[0]==="function")&&arguments[0] instanceof Object&&typeof arguments[1]==="number"){args=[].slice.call(args,i)}else{args=[].slice.call(arguments,0)}}if(args instanceof Array&&args.length===1){args=args[0]}if(typeof args==="function"){if(args.execute===CALLBACK.prototype.execute){return args}return CALLBACK({hook:args})}else{if(args instanceof Array){if(typeof(args[0])==="string"&&args[1] instanceof Object&&typeof args[1][args[0]]==="function"){return CALLBACK({hook:args[1][args[0]],object:args[1],data:args.slice(2)})}else{if(typeof args[0]==="function"){return CALLBACK({hook:args[0],data:args.slice(1)})}else{if(typeof args[1]==="function"){return CALLBACK({hook:args[1],object:args[0],data:args.slice(2)})}}}}else{if(typeof(args)==="string"){if(TESTEVAL){TESTEVAL()}return CALLBACK({hook:EVAL,data:[args]})}else{if(args instanceof Object){return CALLBACK(args)}else{if(typeof(args)==="undefined"){return CALLBACK({})}}}}}throw Error("Can't make callback from given data")};var DELAY=function(time,callback){callback=USING(callback);callback.timeout=setTimeout(callback,time);return callback};var WAITFOR=function(callback,signal){callback=USING(callback);if(!callback.called){WAITSIGNAL(callback,signal);signal.pending++}};var WAITEXECUTE=function(){var signals=this.signal;delete this.signal;this.execute=this.oldExecute;delete this.oldExecute;var result=this.execute.apply(this,arguments);if(ISCALLBACK(result)&&!result.called){WAITSIGNAL(result,signals)}else{for(var i=0,m=signals.length;i0&&priority=0;i--){this.hooks.splice(i,1)}this.remove=[]}});var EXECUTEHOOKS=function(hooks,data,reset){if(!hooks){return null}if(!(hooks instanceof Array)){hooks=[hooks]}if(!(data instanceof Array)){data=(data==null?[]:[data])}var handler=HOOKS(reset);for(var i=0,m=hooks.length;ig){g=document.styleSheets.length}if(!i){i=document.head||((document.getElementsByTagName("head"))[0]);if(!i){i=document.body}}return i};var f=[];var c=function(){for(var k=0,j=f.length;k=this.timeout){i(this.STATUS.ERROR);return 1}return 0},file:function(j,i){if(i<0){a.Ajax.loadTimeout(j)}else{a.Ajax.loadComplete(j)}},execute:function(){this.hook.call(this.object,this,this.data[0],this.data[1])},checkSafari2:function(i,j,k){if(i.time(k)){return}if(document.styleSheets.length>j&&document.styleSheets[j].cssRules&&document.styleSheets[j].cssRules.length){k(i.STATUS.OK)}else{setTimeout(i,i.delay)}},checkLength:function(i,l,n){if(i.time(n)){return}var m=0;var j=(l.sheet||l.styleSheet);try{if((j.cssRules||j.rules||[]).length>0){m=1}}catch(k){if(k.message.match(/protected variable|restricted URI/)){m=1}else{if(k.message.match(/Security error/)){m=1}}}if(m){setTimeout(a.Callback([n,i.STATUS.OK]),0)}else{setTimeout(i,i.delay)}}},loadComplete:function(i){i=this.fileURL(i);var j=this.loading[i];if(j&&!j.preloaded){a.Message.Clear(j.message);clearTimeout(j.timeout);if(j.script){if(f.length===0){setTimeout(c,0)}f.push(j.script)}this.loaded[i]=j.status;delete this.loading[i];this.addHook(i,j.callback)}else{if(j){delete this.loading[i]}this.loaded[i]=this.STATUS.OK;j={status:this.STATUS.OK}}if(!this.loadHooks[i]){return null}return this.loadHooks[i].Execute(j.status)},loadTimeout:function(i){if(this.loading[i].timeout){clearTimeout(this.loading[i].timeout)}this.loading[i].status=this.STATUS.ERROR;this.loadError(i);this.loadComplete(i)},loadError:function(i){a.Message.Set(["LoadFailed","File failed to load: %1",i],null,2000);a.Hub.signal.Post(["file load error",i])},Styles:function(k,l){var i=this.StyleString(k);if(i===""){l=a.Callback(l);l()}else{var j=document.createElement("style");j.type="text/css";this.head=h(this.head);this.head.appendChild(j);if(j.styleSheet&&typeof(j.styleSheet.cssText)!=="undefined"){j.styleSheet.cssText=i}else{j.appendChild(document.createTextNode(i))}l=this.timer.create.call(this,l,j)}return l},StyleString:function(n){if(typeof(n)==="string"){return n}var k="",o,m;for(o in n){if(n.hasOwnProperty(o)){if(typeof n[o]==="string"){k+=o+" {"+n[o]+"}\n"}else{if(n[o] instanceof Array){for(var l=0;l="0"&&p<="9"){f[j]=o[f[j]-1];if(typeof f[j]==="number"){f[j]=this.number(f[j])}}else{if(p==="{"){p=f[j].substr(1);if(p>="0"&&p<="9"){f[j]=o[f[j].substr(1,f[j].length-2)-1];if(typeof f[j]==="number"){f[j]=this.number(f[j])}}else{var k=f[j].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);if(k){if(k[1]==="plural"){var d=o[k[2]-1];if(typeof d==="undefined"){f[j]="???"}else{d=this.plural(d)-1;var h=k[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/);if(d>=0&&d=3){c.push([f[0],f[1],this.processSnippet(g,f[2])])}else{c.push(e[d])}}}}else{c.push(e[d])}}return c},markdownPattern:/(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,processMarkdown:function(b,h,d){var j=[],e;var c=b.split(this.markdownPattern);var g=c[0];for(var f=1,a=c.length;f1?d[1]:""));f=null}if(e&&(!b.preJax||d)){c.nodeValue=c.nodeValue.replace(b.postJax,(e.length>1?e[1]:""))}if(f&&!f.nodeValue.match(/\S/)){f=f.previousSibling}}if(b.preRemoveClass&&f&&f.className===b.preRemoveClass){a.MathJax.preview=f}a.MathJax.checked=1},processInput:function(a){var b,i=MathJax.ElementJax.STATE;var h,e,d=a.scripts.length;try{while(a.ithis.processUpdateTime&&a.i1){d.jax[a.outputJax].push(b)}b.MathJax.state=c.OUTPUT},prepareOutput:function(c,f){while(c.jthis.processUpdateTime&&h.i=0;p--){if((b[p].src||"").match(e)){r.script=b[p].innerHTML;if(RegExp.$2){var s=RegExp.$2.substr(1).split(/\&/);for(var o=0,k=s.length;o=parseInt(x[y])}}return true},Select:function(j){var i=j[c.Browser];if(i){return i(c.Browser)}return null}};var d=h.replace(/^Mozilla\/(\d+\.)+\d+ /,"").replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"").replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,"");c.Browser=c.Insert(c.Insert(new String("Unknown"),{version:"0.0"}),a);for(var u in a){if(a.hasOwnProperty(u)){if(a[u]&&u.substr(0,2)==="is"){u=u.slice(2);if(u==="Mac"||u==="PC"){continue}c.Browser=c.Insert(new String(u),a);var q=new RegExp(".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|.*("+u+")"+(u=="MSIE"?" ":"/")+"((?:\\d+\\.)*\\d+)|(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)");var t=q.exec(d)||["","","","unknown","0.0"];c.Browser.name=(t[1]!=""?u:(t[3]||t[5]));c.Browser.version=t[2]||t[4]||t[6];break}}}c.Browser.Select({Safari:function(j){var i=parseInt((String(j.version).split("."))[0]);if(i>85){j.webkit=j.version}if(i>=538){j.version="8.0"}else{if(i>=537){j.version="7.0"}else{if(i>=536){j.version="6.0"}else{if(i>=534){j.version="5.1"}else{if(i>=533){j.version="5.0"}else{if(i>=526){j.version="4.0"}else{if(i>=525){j.version="3.1"}else{if(i>500){j.version="3.0"}else{if(i>400){j.version="2.0"}else{if(i>85){j.version="1.0"}}}}}}}}}}j.webkit=(navigator.appVersion.match(/WebKit\/(\d+)\./))[1];j.isMobile=(navigator.appVersion.match(/Mobile/i)!=null);j.noContextMenu=j.isMobile},Firefox:function(j){if((j.version==="0.0"||h.match(/Firefox/)==null)&&navigator.product==="Gecko"){var m=h.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);if(m){j.version=m[1]}else{var i=(navigator.buildID||navigator.productSub||"0").substr(0,8);if(i>="20111220"){j.version="9.0"}else{if(i>="20111120"){j.version="8.0"}else{if(i>="20110927"){j.version="7.0"}else{if(i>="20110816"){j.version="6.0"}else{if(i>="20110621"){j.version="5.0"}else{if(i>="20110320"){j.version="4.0"}else{if(i>="20100121"){j.version="3.6"}else{if(i>="20090630"){j.version="3.5"}else{if(i>="20080617"){j.version="3.0"}else{if(i>="20061024"){j.version="2.0"}}}}}}}}}}}}j.isMobile=(navigator.appVersion.match(/Android/i)!=null||h.match(/ Fennec\//)!=null||h.match(/Mobile/)!=null)},Opera:function(i){i.version=opera.version()},MSIE:function(j){j.isIE9=!!(document.documentMode&&(window.performance||window.msPerformance));MathJax.HTML.setScriptBug=!j.isIE9||document.documentMode<9;MathJax.Hub.msieHTMLCollectionBug=(document.documentMode<9);if(document.documentMode<10&&!r.params.NoMathPlayer){try{new ActiveXObject("MathPlayer.Factory.1");j.hasMathPlayer=true}catch(m){}try{if(j.hasMathPlayer){var i=document.createElement("object");i.id="mathplayer";i.classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987";f.appendChild(i);document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");j.mpNamespace=true;if(document.readyState&&(document.readyState==="loading"||document.readyState==="interactive")){document.write('');j.mpImported=true}}else{document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink")}}catch(m){}}}});c.Browser.Select(MathJax.Message.browsers);if(g.AuthorConfig&&typeof g.AuthorConfig.AuthorInit==="function"){g.AuthorConfig.AuthorInit()}c.queue=g.Callback.Queue();c.queue.Push(["Post",r.signal,"Begin"],["Config",r],["Cookie",r],["Styles",r],["Message",r],function(){var i=g.Callback.Queue(r.Jax(),r.Extensions());return i.Push({})},["Menu",r],r.onLoad(),function(){MathJax.isReady=true},["Typeset",r],["Hash",r],["MenuZoom",r],["Post",r.signal,"End"])})("MathJax")}}; diff --git a/plugins/chartdldr_pi/data/doc/advanced.html b/plugins/chartdldr_pi/data/doc/advanced.html deleted file mode 100644 index 4ec0516fc6..0000000000 --- a/plugins/chartdldr_pi/data/doc/advanced.html +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - Chart Downloader Plug-in for OpenCPN - - - - - - - - - - - -

- Advanced Usage -

-

- The chart downloader plugin is a handy tool that can automatically use the Internet to keep your free charts up to date. No longer do you have to go to a web site, download large .zip files then manually unzip them. The plugin will do all that work for you. A bonus feature is that it only downloads charts that have changed since the last time you udpated chart files which can reduce the amount of data downloaded. This tool is just a way to automatically download charts. The plugin does not change the way OpenCPN works and you don’t have to use it to manage your charts at all, it just makes managing your charts easier once you have a working Internet connection. -

-

- Existing OpenCPN users will no doubt already have charts and they may wish to have the downloader plugin keep these existing charts up to date. Below we explain how the downloader works so that you can utilize it to automatically update your existing charts. -

-

- The Chart Directory Structure -

-

- The plugin by default assumes you keep your charts in a multilevel directory tree, separating charts both by type (raster/vector) and by the coverage area. While it is not needed, we strongly suggest you adopt this scheme as it -

-
Charts top level folder
-   |-ENC
-      |-Some area
-      |-Another area
-   |-RNC
-      |-Some area
-      |-Another area
-      |-Yet another are
-
-

- By default the plugin places all your chart bellow - - <Your documents folder>\Charts - - . In case you don’t like the location, you can change it in the plugin preferences dialog. Get to it by - - Options - - > - - Plugins - - > - - ChartDownloader - - > - - Preferences - - after you enable the plugin. -

-

- Preferences -

-

- The Default Path to Charts tells the downloader the top level directory where all your charts are stored. This default path will be used along with any additional subdirectories defined for each chart catalog to define the entire path to charts. -

-

- Other settings -

-

- Most existing users will want to select the check box labeled - - All updated charts - - so that is the default. This tells the downloader that you want to download any charts that are newer than the charts you have. You can also select - - All new charts - - . This will tell the downloader that we also want to automatically download any new charts that don’t already exist. Before selecting that we recommend that you read through this documentation and then decide if you need that option or not. Most existing users don’t need to use that option. -

-

- This may seem a little confusing at first so let’s look at an example. Assume you have entered the Default Path to Charts as C:\Users\Dan\Documents\Charts. Then go to the “Predefined” charts tab by selecting - - Options - - > - - Charts - - > - - Chart Downloader - - > - - Add Catalog - - then select the “Predefined” tab. There you will find a tree of predefined chart catalogs. One of these is the - - USA - NOAA and Inland Charts - - > - - RNC - - > - - by Region - - > - - Region 02 - Block Island, RI to Canadian Border - - . If you click it you will see something like this: -

-

- Add New Chart Catalog Source -

-

- Many users will have all their existing raster charts stored in one directory called BSB_ROOT and vector charts in one directory called ENC_ROOT. In the above example there is no BSB_ROOT directory and you may be wondering why not. The large .zip files from NOAA have BSB_ROOT or ENC_ROOT as their top level so it will be easier to combine multiple .zip files into a single directory structure. If you unzipped multiple files into the same directory then all your chart files will be in one big directory called BSB_ROOT or ENC_ROOT. -

-

- If you already have some region 2 charts in a directory called BSB_ROOT and you want to keep them up to date just click on the Browse button or edit the path in - - Chart Directory - - so that it points to the BSB_ROOT or whatever the directory name where region 2 charts are stored now. Then click OK and you are ready to update your region 2 raster charts. -

-

- After clicking OK you will be back at the main plugin screen. Click the button on the right labeled - - Update - - . This will check your existing charts against the current NOAA region 2 database. Any existing charts that are out of date will be marked with a check box and the status will show - - Update available - - . Any charts that are not in your chart folder will show status as - - New - - . The rest will show status - - Up to date - - . If you want to get some new charts scroll through the list of charts. Click the check box of any new charts you would like to see. -

-

- Download all the charts with a check box by clicking the button at the bottom labeled - - Download selected charts - - . -

-

- If the status shows - - New - - for every chart you will get a message that no charts were selected for download. In that case you may not have gotten the chart directory right. You can edit the chart directory by clicking the button labeled - - Edit… - - . This brings up a dialog box similar to the Add Catalog button except you can edit the Name, URL and Chart Directory. Be careful if you change the URL because if the wrong URL is given the chart downloader will not be able to find the NOAA chart catalog. Once you have the Chart Directory correct click OK then - - Update - - followed by - - Download selected charts - - . All your existing charts for region 2 will be updated to the latest revision. -

-

- Once you have downloaded charts, the plugin sets OpenCPN to scan for new and updated charts and update it's chart database once you close the Toolbox. -

-

- Existing Users have Two Options -

-

- You can keep all your charts updated in their existing directories (typically two directories called BSB_ROOT and ENC_ROOT) or you can keep each group of charts in separate directories. This latter choice is what the downloader does by default. It puts charts from each new source into a new directory beneath the - - Default Path to Charts - - in - - Preferences - - . There is a good reason to use this scheme as it makes defining groups of charts in OpenCPN much more straightforward. -

-

- If you want to keep your charts in their existing directories then when adding each catalog simply change the - - Chart Directory - - so it points to the BSB_ROOT or ENC_ROOT or whatever directory your chart files are in now. If your existing charts are in two big directories (ENC_ROOT and BSB_ROOT) you may wish to add just the catalogs ALL RNCs and ALL ENCs. Make sure the - - Chart Directory - - for each one points to the correct root directory (e.g. BSB_ROOT or ENC_ROOT). -

-

- The plugin tries to save you all the work with setting up OpenCPN to see your charts when you configure the catalogs. If you decide to later change the directory structure for your charts, make sure to adjust the respective configuration on - - Options > Charts > Chart Files - - tab. -

-

- That’s pretty much all there is to setting up the downloader for existing charts. Next we look at how to keep your chart catalogs up to date. -

-

- Once you have everything set up the way you like there is a one-button update process available. As it might be confusing for new users, the function is disabled by default and you have to enable it in the plugin preferences by ticking the - - Allow bulk update of all configured chart sources and charts - - checkbox. A new button, labeled - - Update All - - appears on the Chart Downloader tab. This button will update each catalog starting from the first one and then download any updated charts according to the Preferences check boxes. Usually this will be - - All updated charts - - . If you want to get all new charts automatically with one-button update then select - - All new charts - - in Preferences too. -

-

- Custom Chart Sources -

-

- The plugin allows definition of completely customized chart sources. If you want to make your own set of charts available to be managed by the plugin, you will have to create your own XML chart catalog and make it available on a webserver. Refer to - - https://github.com/chartcatalogs/catalogs - - for examples of catalogs covering the non-US charts available. -
- To configure the plugin to use your chart catalog, click the “ - - Add - - ” button, go to the - - Custom - - tab and enter the URL of you catalog and the destination directory for your charts. -

-

- Add-Edit New Custom Chart Source -

- - diff --git a/plugins/chartdldr_pi/data/doc/basic.html b/plugins/chartdldr_pi/data/doc/basic.html deleted file mode 100644 index 01c3753a7b..0000000000 --- a/plugins/chartdldr_pi/data/doc/basic.html +++ /dev/null @@ -1,307 +0,0 @@ - - - - - - Chart Downloader Plug-in for OpenCPN - - - - - - - - - - - -

- Basic Usage Instructions -

-

- Chartdldr Plugin provides easy access to free charts available for download from the Internet and helps you keep them up to date. -

-

- A Few Basic Concepts -

-

- Chart Catalogs -

-

- The Chart Downloader relies on catalogs of charts. A catalog is an XML file containing the names of charts along with the most recent chart update date and time together with the Internet address of the actual chart data. Before being able to download any charts we have to configure and download one or more chart catalogs. -

-

- The catalogs are provided by the agencies publishing the charts (NOAA and the Army Corps of Engineers in the USA) and by the - - ChartCatalogs - - project created by the author of this plugin. When a catalog is loaded the Chart Downloader automatically scans the existing charts on your computer looking for updated or new charts listed in the catalog. -

-

- Chart Downloader Tab -

-

- After installing and enabling the plugin (refer to the Installation chapter) a new tab is added to the OpenCPN Options Toolbox, accessible by clicking on the wrench icon in the toolba, allowing you to manage your chart downloads. -
- This is what the plugin looks like when first opened by clicking - - Options - - > - - Charts - - > - - Chart Downloader - - : -

-

- Chart Downloader Tab -

-

- Using the Chart Downloader -

-

- The screen has two sections. -
- The top section is for Chart Catalogs. Some chart sources provide many different catalogs for the same set of charts. For example, in the USA, NOAA provides chart catalogs for each state, region and Coast Guard district as well as the huge complete set. There are also separate catalogs for raster (RNC) and vector (ENC) NOAA charts. The first step in getting new charts is to select the appropriate Chart Catalog, make sure you think first though - having everything is not always the best option to organize your charts, so especially in the US, consider using more smaller catalogs over the one with the complete set of thousands of charts. -

-

- Adding a chart source -

-

- Click the “ - - Add - - ” button to get the “ - - New chart source - - ” dialog. -

-

- Add New Chart Catalog Source -

-

- There are “ - - Predefined - - ” catalogs for all the free chart sources worldwide known at the time of the release of this plugin. The catalogs are organized in a folder structure. Open each folder to see subfolders. Open subfolders to see catalogs. Select any catalog you like by clicking the catalog description. After clicking the catalog the “ - - Chart Directory - - ” will be automatically filled in. This is the directory on your computer where the catalog and the charts for this catalog will be downloaded. If the recommended directory is acceptable click “ - - OK - - ”. Otherwise you can use the “ - - Browse - - ” button to browse to another directory where you want the catalog and charts to be kept. Once you are happy with the Chart Directory click “ - - OK - - ”. -
- In case you selected a path to save the charts not covered by the current OpenCPN configuration, the plugin configures it for you. -
- You can check the configuration on the - - Chart Files - - tab. For more details about managing your charts, you should definitely read the relevant - - OpenCPN documentation - - . -

-

- Please Update Catalog -

-

- Now you will see the Chart Catalog listed in the Catalogs section. Note that it will say (Please update first) under the “ - - Released - - ” column. Click the catalog name then click the “ - - Update - - ” button. The downloader will retrieve the catalog from the server. After the catalog is saved a list of charts will appear in the lower section. Each chart has a check box. If the box is checked then that chart is scheduled to be downloaded. Depending on the Preferences you selected earlier the boxes will be automatically checked. You can check or uncheck individual charts or use the right mouse button to check and uncheck groups of charts. -

-

- Updating the catalogs -

-

- The US agencies update their catalogs on a standard weekly schedule, related to the Notice to Mariners releases. The catalogs from the ChartCatalogs project are updated occasionally, without any fixed schedule. You should select the chart source and click the - - Update - - button every once in a while to get the latest chart updates. -

-

- Selecting charts for download -

-

- You can select the charts to be downloaded by ticking the checkboxes in the list of charts. In case you want to select multiple charts at once, - - right-click - - in Chart Window will show a context menu, allowing you to “ - - Select all - - ” charts,” - - Deselect all - - ” charts, “ - - Invert selection - - ”, “ - - Select updated - - ” charts and “ - - Select newly released - - ” charts. You can configure the plugin to automatically preselect the updated and/or new charts after an update of the chart catalog in the preferences. -
- Chart File Status Selection -

-

- Downloading charts -

-

- After selecting the charts for download, click the “ - - Download selected charts - - ” button to start downloading the charts. It can be a lengthy progress and a dialog box showing progress will pop as each chart is downloaded. If any charts do not download correctly a warning will pop up at the end. The status of the charts that have been downloaded successfully will change to “Up to Date”. Sometimes a slow or flaky Internet connection will cause a chart not to download and the status will remain the same. You can just click the “ - - Download selected charts - - ” button again give them a second chance. -

-

- - Chart Folder Tab and Chart Group Tab reminder. - -
- A reminder box will pop up to tell you that you have to notify OpenCPN where to find the charts. We’ll do that in the next step. -

-

- After the download -

-

- After the charts are downloaded, you have to tell OpenCPN to update it’s internal chart database and the plugin will remind you about it with a dialog. -

-

- After Downloading Charts -

-

- For more details you should definitely read the relevant - - OpenCPN documentation - - . -

-

- To make it short, go to - - Options - - > - - Charts - - > - - Chart Files - - tab and tick the - - Scan Charts and Update Database - - checkbox and when you close the Toolbox using the - - OK - - button, your newly downloaded charts will be scanned and made available for viewing. -

-

- Checking the downloaded charts -

-

- The button - - Show Local Files - - on the lower right will open your default file manager in a separate window, which allows you to check files and directories easily. -

-

- Show local files -

-

- The Preferences -

-

- You can customize the behavior of the plugin to certain extent. To access the preferences, select the Chart Downloader plugin on th - - Options - - > - - Plugins - - tab and click on the - - Preferences - - button -

-

- Chartdldr preferences -

-

- The - - Default Path to Charts - - option allows you to set the top directory for all your charts, used to construct the suggested locations for the chart sources you configure. -

-

- The - - All updated charts - - and - - All new charts - - checkboxes tell the plugin which charts you want to select for download automatically upon a catalog update. -

-

- The - - Allow bulk update of all configured chart sources and charts - - checkbox adds a new button to the chart downloader tab, allowing you to update and download all the charts you are managing using the plugin with a single click. The behavior of this function depends on the forementioned checkboxes - either it downloads only new or updated charts or both. -

- - diff --git a/plugins/chartdldr_pi/data/doc/github.min.css b/plugins/chartdldr_pi/data/doc/github.min.css deleted file mode 100644 index 7b3600c93b..0000000000 --- a/plugins/chartdldr_pi/data/doc/github.min.css +++ /dev/null @@ -1 +0,0 @@ -.hljs{display:block;overflow-x:auto;padding:.5em;color:#333;background:#f8f8f8}.hljs-comment,.hljs-template_comment,.diff .hljs-header,.hljs-javadoc{color:#998;font-style:italic}.hljs-keyword,.css .rule .hljs-keyword,.hljs-winutils,.javascript .hljs-title,.nginx .hljs-title,.hljs-subst,.hljs-request,.hljs-status{color:#333;font-weight:bold}.hljs-number,.hljs-hexcolor,.ruby .hljs-constant{color:#099}.hljs-string,.hljs-tag .hljs-value,.hljs-phpdoc,.tex .hljs-formula{color:#d14}.hljs-title,.hljs-id,.coffeescript .hljs-params,.scss .hljs-preprocessor{color:#900;font-weight:bold}.javascript .hljs-title,.lisp .hljs-title,.clojure .hljs-title,.hljs-subst{font-weight:normal}.hljs-class .hljs-title,.haskell .hljs-type,.vhdl .hljs-literal,.tex .hljs-command{color:#458;font-weight:bold}.hljs-tag,.hljs-tag .hljs-title,.hljs-rules .hljs-property,.django .hljs-tag .hljs-keyword{color:#000080;font-weight:normal}.hljs-attribute,.hljs-variable,.lisp .hljs-body{color:#008080}.hljs-regexp{color:#009926}.hljs-symbol,.ruby .hljs-symbol .hljs-string,.lisp .hljs-keyword,.tex .hljs-special,.hljs-prompt{color:#990073}.hljs-built_in,.lisp .hljs-title,.clojure .hljs-built_in{color:#0086b3}.hljs-preprocessor,.hljs-pragma,.hljs-pi,.hljs-doctype,.hljs-shebang,.hljs-cdata{color:#999;font-weight:bold}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.diff .hljs-change{background:#0086b3}.hljs-chunk{color:#aaa} \ No newline at end of file diff --git a/plugins/chartdldr_pi/data/doc/highlight.min.js b/plugins/chartdldr_pi/data/doc/highlight.min.js deleted file mode 100644 index 64ac72bb97..0000000000 --- a/plugins/chartdldr_pi/data/doc/highlight.min.js +++ /dev/null @@ -1 +0,0 @@ -var hljs=new function(){function j(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function h(w,x){var v=w&&w.exec(x);return v&&v.index==0}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^lang(uage)?-/,"")});return v.filter(function(x){return i(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=j(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+j(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};var E=function(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})};if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b="\\b("+D.bK.split(" ").join("|")+")\\b"}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?("+F.b+")\\.?":F.b}).concat([D.tE,D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){if(!I.k){return j(C)}var T="";var W=0;I.lR.lastIndex=0;var U=I.lR.exec(C);while(U){T+=j(C.substr(W,U.index-W));var V=E(I,U);if(V){H+=V[1];T+=w(V[0],j(U[0]))}else{T+=j(U[0])}W=I.lR.lastIndex;U=I.lR.exec(C)}return T+j(C.substr(W))}function F(){if(I.sL&&!f[I.sL]){return j(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):e(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=j(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=j(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=i(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D+=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:j(L)}}else{throw O}}}function e(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:j(y)};var w=v;x.forEach(function(z){if(!i(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function g(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
")}return v}function p(z){var y=b.useBR?z.innerHTML.replace(/\n/g,"").replace(/
|
]*>/g,"\n").replace(/<[^>]*>/g,""):z.textContent;var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):e(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=g(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function d(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function k(){return Object.keys(f)}function i(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=e;this.fixMarkup=g;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=d;this.listLanguages=k;this.getLanguage=i;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/};this.CLCM={cN:"comment",b:"//",e:"$",c:[this.PWM]};this.CBCM={cN:"comment",b:"/\\*",e:"\\*/",c:[this.PWM]};this.HCM={cN:"comment",b:"#",e:"$",c:[this.PWM]};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.CSSNM={cN:"number",b:this.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0};this.RM={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("coffeescript",function(c){var b={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf",built_in:"npm require console print module global window document"};var a="[A-Za-z$_][0-9A-Za-z$_]*";var f=c.inherit(c.TM,{b:a});var e={cN:"subst",b:/#\{/,e:/}/,k:b};var d=[c.BNM,c.inherit(c.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[c.BE]},{b:/'/,e:/'/,c:[c.BE]},{b:/"""/,e:/"""/,c:[c.BE,e]},{b:/"/,e:/"/,c:[c.BE,e]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[e,c.HCM]},{b:"//[gim]*",r:0},{b:"/\\S(\\\\.|[^\\n])*?/[gim]*(?=\\s|\\W|$)"}]},{cN:"property",b:"@"+a},{b:"`",e:"`",eB:true,eE:true,sL:"javascript"}];e.c=d;return{aliases:["coffee","cson","iced"],k:b,c:d.concat([{cN:"comment",b:"###",e:"###"},c.HCM,{cN:"function",b:"("+a+"\\s*=\\s*)?(\\(.*\\))?\\s*\\B[-=]>",e:"[-=]>",rB:true,c:[f,{cN:"params",b:"\\(",rB:true,c:[{b:/\(/,e:/\)/,k:b,c:["self"].concat(d)}]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:true,i:/[:="\[\]]/,c:[f]},f]},{cN:"attribute",b:a+":",e:":",rB:true,eE:true,r:0}])}});hljs.registerLanguage("nginx",function(c){var b={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+c.UIR}]};var a={eW:true,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[c.HCM,{cN:"string",c:[c.BE,b],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:true,eE:true},{cN:"regexp",c:[c.BE,b],v:[{b:"\\s\\^",e:"\\s|{|;",rE:true},{b:"~\\*?\\s+",e:"\\s|{|;",rE:true},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},b]};return{aliases:["nginxconf"],c:[c.HCM,{b:c.UIR+"\\s",e:";|{",rB:true,c:[{cN:"title",b:c.UIR,starts:a}],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBCM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBCM,a.RM,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:true,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("sql",function(a){var b={cN:"comment",b:"--",e:"$"};return{cI:true,i:/[<>]/,c:[{cN:"operator",bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate savepoint release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup",e:/;/,eW:true,k:{keyword:"abs absolute acos action add adddate addtime aes_decrypt aes_encrypt after aggregate all allocate alter analyze and any are as asc ascii asin assertion at atan atan2 atn2 authorization authors avg backup before begin benchmark between bin binlog bit_and bit_count bit_length bit_or bit_xor both by cache call cascade cascaded case cast catalog ceil ceiling chain change changed char_length character_length charindex charset check checksum checksum_agg choose close coalesce coercibility collate collation collationproperty column columns columns_updated commit compress concat concat_ws concurrent connect connection connection_id consistent constraint constraints continue contributors conv convert convert_tz corresponding cos cot count count_big crc32 create cross cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime data database databases datalength date_add date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts datetimeoffsetfromparts day dayname dayofmonth dayofweek dayofyear deallocate declare decode default deferrable deferred degrees delayed delete des_decrypt des_encrypt des_key_file desc describe descriptor diagnostics difference disconnect distinct distinctrow div do domain double drop dumpfile each else elt enclosed encode encrypt end end-exec engine engines eomonth errors escape escaped event eventdata events except exception exec execute exists exp explain export_set extended external extract fast fetch field fields find_in_set first first_value floor flush for force foreign format found found_rows from from_base64 from_days from_unixtime full function get get_format get_lock getdate getutcdate global go goto grant grants greatest group group_concat grouping grouping_id gtid_subset gtid_subtract handler having help hex high_priority hosts hour ident_current ident_incr ident_seed identified identity if ifnull ignore iif ilike immediate in index indicator inet6_aton inet6_ntoa inet_aton inet_ntoa infile initially inner innodb input insert install instr intersect into is is_free_lock is_ipv4 is_ipv4_compat is_ipv4_mapped is_not is_not_null is_used_lock isdate isnull isolation join key kill language last last_day last_insert_id last_value lcase lead leading least leaves left len lenght level like limit lines ln load load_file local localtime localtimestamp locate lock log log10 log2 logfile logs low_priority lower lpad ltrim make_set makedate maketime master master_pos_wait match matched max md5 medium merge microsecond mid min minute mod mode module month monthname mutex name_const names national natural nchar next no no_write_to_binlog not now nullif nvarchar oct octet_length of old_password on only open optimize option optionally or ord order outer outfile output pad parse partial partition password patindex percent_rank percentile_cont percentile_disc period_add period_diff pi plugin position pow power pragma precision prepare preserve primary prior privileges procedure procedure_analyze processlist profile profiles public publishingservername purge quarter query quick quote quotename radians rand read references regexp relative relaylog release release_lock rename repair repeat replace replicate reset restore restrict return returns reverse revoke right rlike rollback rollup round row row_count rows rpad rtrim savepoint schema scroll sec_to_time second section select serializable server session session_user set sha sha1 sha2 share show sign sin size slave sleep smalldatetimefromparts snapshot some soname soundex sounds_like space sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sql_variant_property sqlstate sqrt square start starting status std stddev stddev_pop stddev_samp stdev stdevp stop str str_to_date straight_join strcmp string stuff subdate substr substring subtime subtring_index sum switchoffset sysdate sysdatetime sysdatetimeoffset system_user sysutcdatetime table tables tablespace tan temporary terminated tertiary_weights then time time_format time_to_sec timediff timefromparts timestamp timestampadd timestampdiff timezone_hour timezone_minute to to_base64 to_days to_seconds todatetimeoffset trailing transaction translation trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse ucase uncompress uncompressed_length unhex unicode uninstall union unique unix_timestamp unknown unlock update upgrade upped upper usage use user user_resources using utc_date utc_time utc_timestamp uuid uuid_short validate_password_strength value values var var_pop var_samp variables variance varp version view warnings week weekday weekofyear weight_string when whenever where with work write xml xor year yearweek zon",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int integer interval number numeric real serial smallint varchar varying int8 serial8 text"},c:[{cN:"string",b:"'",e:"'",c:[a.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[a.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[a.BE]},a.CNM,a.CBCM,b]},a.CBCM,b]}});hljs.registerLanguage("php",function(b){var e={cN:"variable",b:"(\\$|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var a={cN:"preprocessor",b:/<\?(php)?|\?>/};var c={cN:"string",c:[b.BE,a],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},b.inherit(b.ASM,{i:null}),b.inherit(b.QSM,{i:null})]};var d={v:[b.BNM,b.CNM]};return{aliases:["php3","php4","php5","php6"],cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[b.CLCM,b.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},a]},{cN:"comment",b:"__halt_compiler.+?;",eW:true,k:"__halt_compiler",l:b.UIR},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[b.BE]},a,e,{cN:"function",bK:"function",e:/[;{]/,eE:true,i:"\\$|\\[|%",c:[b.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",e,b.CBCM,c,d]}]},{cN:"class",bK:"class interface",e:"{",eE:true,i:/[:\(\$"]/,c:[{bK:"extends implements",r:10},b.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[b.UTM]},{bK:"use",e:";",c:[b.UTM]},{b:"=>"},c,d]}});hljs.registerLanguage("makefile",function(a){var b={cN:"variable",b:/\$\(/,e:/\)/,c:[a.BE]};return{aliases:["mk","mak"],c:[a.HCM,{b:/^\w+\s*\W*=/,rB:true,r:0,starts:{cN:"constant",e:/\s*\W*=/,eE:true,starts:{e:/$/,r:0,c:[b]}}},{cN:"title",b:/^[\w]+:\s*$/},{cN:"phony",b:/^\.PHONY:/,e:/$/,k:".PHONY",l:/[\.\w]+/},{b:/^\t+/,e:/$/,c:[a.QSM,b]}]}});hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("cpp",function(a){var b={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long throw volatile static protected bool template mutable if public friend do return goto auto void enum else break new extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginary",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c","h","c++","h++"],k:b,i:""]',k:"include",i:"\\n"},a.CLCM]},{cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:b,c:["self"]},{b:a.IR+"::"}]}});hljs.registerLanguage("perl",function(c){var d="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when";var f={cN:"subst",b:"[$@]\\{",e:"\\}",k:d};var g={b:"->{",e:"}"};var a={cN:"variable",v:[{b:/\$\d/},{b:/[\$\%\@](\^\w\b|#\w+(\:\:\w+)*|{\w+}|\w+(\:\:\w*)*)/},{b:/[\$\%\@][^\s\w{]/,r:0}]};var e={cN:"comment",b:"^(__END__|__DATA__)",e:"\\n$",r:5};var h=[c.BE,f,a];var b=[a,c.HCM,e,{cN:"comment",b:"^\\=\\w",e:"\\=cut",eW:true},g,{cN:"string",c:h,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[c.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[c.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+c.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[c.HCM,e,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[c.BE],r:0}]},{cN:"sub",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",r:5},{cN:"operator",b:"-\\w\\b",r:0}];f.c=b;g.c=b;return{aliases:["pl"],k:d,c:b}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("apache",function(a){var b={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:true,c:[a.HCM,{cN:"tag",b:""},{cN:"keyword",b:/\w+/,r:0,k:{common:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",b]},b,a.QSM]}}],i:/\S/}});hljs.registerLanguage("java",function(b){var a="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws";return{aliases:["jsp"],k:a,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}],r:10},b.CLCM,b.CBCM,b.ASM,b.QSM,{bK:"protected public private",e:/[{;=]/,k:a,c:[{cN:"class",bK:"class interface",eW:true,eE:true,i:/[:"\[\]]/,c:[{bK:"extends implements",r:10},b.UTM]},{b:b.UIR+"\\s*\\(",rB:true,c:[b.UTM]}]},b.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{aliases:["md","mkdown","mkd"],c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("cs",function(b){var a="abstract as base bool break byte case catch char checked const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async await ascending descending from get group into join let orderby partial select set value var where yield";return{aliases:["csharp"],k:a,i:/::/,c:[{cN:"comment",b:"///",e:"$",rB:true,c:[{cN:"xmlDocTag",v:[{b:"///",r:0},{b:""},{b:""}]}]},b.CLCM,b.CBCM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},b.ASM,b.QSM,b.CNM,{bK:"protected public private internal",e:/[{;=]/,k:a,c:[{bK:"class namespace interface",starts:{c:[b.TM]}},{b:b.IR+"\\s*\\(",rB:true,c:[b.TM]}]}]}});hljs.registerLanguage("ruby",function(f){var j="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var i="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor";var b={cN:"yardoctag",b:"@[A-Za-z]+"};var c={cN:"value",b:"#<",e:">"};var k={cN:"comment",v:[{b:"#",e:"$",c:[b]},{b:"^\\=begin",e:"^\\=end",c:[b],r:10},{b:"^__END__",e:"\\n$"}]};var d={cN:"subst",b:"#\\{",e:"}",k:i};var e={cN:"string",c:[f.BE,d],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:"%[qw]?\\(",e:"\\)"},{b:"%[qw]?\\[",e:"\\]"},{b:"%[qw]?{",e:"}"},{b:"%[qw]?<",e:">"},{b:"%[qw]?/",e:"/"},{b:"%[qw]?%",e:"%"},{b:"%[qw]?-",e:"-"},{b:"%[qw]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]};var a={cN:"params",b:"\\(",e:"\\)",k:i};var h=[e,c,k,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[f.inherit(f.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+f.IR+"::)?"+f.IR}]},k]},{cN:"function",bK:"def",e:" |$|;",r:0,c:[f.inherit(f.TM,{b:j}),a,k]},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:[e,{b:j}],r:0},{cN:"symbol",b:f.UIR+"(\\!|\\?)?:",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+f.RSR+")\\s*",c:[c,k,{cN:"regexp",c:[f.BE,d],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];d.c=h;a.c=h;var g=[{r:1,cN:"output",b:"^\\s*=> ",e:"$",rB:true,c:[{cN:"status",b:"^\\s*=>"},{b:" ",e:"$",c:h}]},{r:1,cN:"input",b:"^[^ ][^=>]*>+ ",e:"$",rB:true,c:[{cN:"prompt",b:"^[^ ][^=>]*>+"},{b:" ",e:"$",c:h}]}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:i,c:g.concat(h)}});hljs.registerLanguage("diff",function(a){return{aliases:["patch"],c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("objectivec",function(a){var d={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"NSString NSDictionary CGRect CGPoint UIButton UILabel UITextView UIWebView MKMapView NSView NSViewController NSWindow NSWindowController NSSet NSUUID NSIndexSet UISegmentedControl NSObject UITableViewDelegate UITableViewDataSource NSThread UIActivityIndicator UITabbar UIToolBar UIBarButtonItem UIImageView NSAutoreleasePool UITableView BOOL NSInteger CGFloat NSException NSLog NSMutableString NSMutableArray NSMutableDictionary NSURL NSIndexPath CGSize UITableViewCell UIView UIViewController UINavigationBar UINavigationController UITabBarController UIPopoverController UIPopoverControllerDelegate UIImage NSNumber UISearchBar NSFetchedResultsController NSFetchedResultsChangeType UIScrollView UIScrollViewDelegate UIEdgeInsets UIColor UIFont UIApplication NSNotFound NSNotificationCenter NSNotification UILocalNotification NSBundle NSFileManager NSTimeInterval NSDate NSCalendar NSUserDefaults UIWindow NSRange NSArray NSError NSURLRequest NSURLConnection UIInterfaceOrientation MPMoviePlayerController dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"};var c=/[a-zA-Z@][a-zA-Z0-9_]*/;var b="@interface @class @protocol @implementation";return{aliases:["m","mm","objc","obj-c"],k:d,l:c,i:""}]}]},{cN:"class",b:"("+b.split(" ").join("|")+")\\b",e:"({|$)",eE:true,k:b,l:c,c:[a.UTM]},{cN:"variable",b:"\\."+a.UIR,r:0}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",rB:true,eE:true,e:"\\("};return{cI:true,i:"[=/|']",c:[a.CBCM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.CSSNM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBCM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.CSSNM,a.QSM,a.ASM,a.CBCM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("python",function(a){var f={cN:"prompt",b:/^(>>>|\.\.\.) /};var b={cN:"string",c:[a.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[f],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[f],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},a.ASM,a.QSM]};var d={cN:"number",r:0,v:[{b:a.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:a.CNR+"[lLjJ]?"}]};var e={cN:"params",b:/\(/,e:/\)/,c:["self",f,d,b]};var c={e:/:/,i:/[${=;\n]/,c:[a.UTM,e]};return{aliases:["py","gyp"],k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[f,d,b,a.HCM,a.inherit(c,{cN:"function",bK:"def",r:10}),a.inherit(c,{cN:"class",bK:"class"}),{cN:"decorator",b:/@/,e:/$/},{b:/\b(print|exec)\(/}]}}); \ No newline at end of file diff --git a/plugins/chartdldr_pi/data/doc/index.html b/plugins/chartdldr_pi/data/doc/index.html deleted file mode 100644 index 625825dad0..0000000000 --- a/plugins/chartdldr_pi/data/doc/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - Chart Downloader Plug-in for OpenCPN - - - - - - - - - - - -

- Welcome to the chartdldr_pi documentation! -

-

- Chart Downloader User documentation -

-

- Every user, especially a new one, should read about the - - Basic Concepts - - behind this plugin and it's usage. -
- Once you are comfortable with it, feel free to continue to the - - Advanced Usage - - section, which also covers the scenarios for user who already have their charts installed and would like to start managing them using the plugin. -

- -

- You should definitely read the OpenCPN documentation about installing, managing and using charts, available in the - - online manual - - and in the help file bundled with your OpenCPN. -

-

- Problems? -

-

- If you feel like there is a bug in the plugin, want to help with the development or feel like this documentation is not accurate, please visit us on - - Github - - and let us know. -

- - diff --git a/plugins/chartdldr_pi/data/doc/preferences.png b/plugins/chartdldr_pi/data/doc/preferences.png deleted file mode 100644 index 0f0a16af34..0000000000 Binary files a/plugins/chartdldr_pi/data/doc/preferences.png and /dev/null differ diff --git a/plugins/chartdldr_pi/src/androidSupport.cpp b/plugins/chartdldr_pi/src/androidSupport.cpp index b11771fabe..a3f4e565a9 100644 --- a/plugins/chartdldr_pi/src/androidSupport.cpp +++ b/plugins/chartdldr_pi/src/androidSupport.cpp @@ -369,13 +369,9 @@ void androidHideBusyIcon() { b_androidBusyShown = false; } -void androidEnableRotation(void) { - callActivityMethod_vs("EnableRotation"); -} +void androidEnableRotation(void) { callActivityMethod_vs("EnableRotation"); } -void androidDisableRotation(void) { - callActivityMethod_vs("DisableRotation"); -} +void androidDisableRotation(void) { callActivityMethod_vs("DisableRotation"); } int androidGetSDKVersion() { wxString deviceInfo = callActivityMethod_vs("getDeviceInfo"); diff --git a/plugins/chartdldr_pi/src/chartcatalog.h b/plugins/chartdldr_pi/src/chartcatalog.h index d9b4cb19f5..a2a09e940d 100644 --- a/plugins/chartdldr_pi/src/chartcatalog.h +++ b/plugins/chartdldr_pi/src/chartcatalog.h @@ -223,7 +223,7 @@ class NoticeToMariners // for and class Vertex { public: Vertex(pugi::xml_node &xmldata); - virtual ~Vertex(){}; + virtual ~Vertex() {}; // public methods // public properties diff --git a/plugins/chartdldr_pi/src/chartdldr_pi.cpp b/plugins/chartdldr_pi/src/chartdldr_pi.cpp index 0b0a5368e1..a3faf56ed1 100644 --- a/plugins/chartdldr_pi/src/chartdldr_pi.cpp +++ b/plugins/chartdldr_pi/src/chartdldr_pi.cpp @@ -71,9 +71,6 @@ #include #endif - - - #ifdef __WXMAC__ #define CATALOGS_NAME_WIDTH 300 #define CATALOGS_DATE_WIDTH 120 diff --git a/plugins/chartdldr_pi/src/chartdldrgui.cpp b/plugins/chartdldr_pi/src/chartdldrgui.cpp index e4cce9a4b6..ab50a781fb 100644 --- a/plugins/chartdldr_pi/src/chartdldrgui.cpp +++ b/plugins/chartdldr_pi/src/chartdldrgui.cpp @@ -7,6 +7,8 @@ #include "chartdldr_pi.h" #include "chartdldrgui.h" +#include "manual.h" +#include "../../../libs/manual/include/manual.h" #include #include #include @@ -362,9 +364,8 @@ void AddSourceDlg::OnNbPage(wxNotebookEvent& event) { wxTreeItemId item = m_treeCtrlPredefSrcs->GetSelection(); ChartSource* cs = nullptr; if (item.IsOk()) - cs = (ChartSource *)(m_treeCtrlPredefSrcs->GetItemData(item)); - if(!cs) - m_buttonChartDirectory->Disable(); + cs = (ChartSource*)(m_treeCtrlPredefSrcs->GetItemData(item)); + if (!cs) m_buttonChartDirectory->Disable(); } } @@ -535,12 +536,12 @@ ChartDldrPanel::ChartDldrPanel(wxWindow* parent, wxWindowID id, m_scrollWinChartList->SetMinSize(wxSize(-1, 12 * GetCharHeight())); #ifdef HAVE_WX_GESTURE_EVENTS - if (!m_scrollWinChartList->EnableTouchEvents( wxTOUCH_PRESS_GESTURES)) { + if (!m_scrollWinChartList->EnableTouchEvents(wxTOUCH_PRESS_GESTURES)) { wxLogError("Failed to enable touch events on chart downloader"); } Bind(wxEVT_LONG_PRESS, &ChartDldrPanel::OnLongPress, this); #endif - + m_boxSizerCharts = new wxBoxSizer(wxVERTICAL); m_scrollWinChartList->SetSizer(m_boxSizerCharts); @@ -590,8 +591,7 @@ ChartDldrPanel::ChartDldrPanel(wxWindow* parent, wxWindowID id, wxDefaultPosition, wxDefaultSize, 0); chartsPanelBoxSizer->Add(m_bDnldCharts, 0, wxALIGN_LEFT | wxALL, 5); - m_stCatalogInfo = new wxStaticText(chartsPanel, wxID_ANY, - "", + m_stCatalogInfo = new wxStaticText(chartsPanel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0); chartsPanelBoxSizer->Add(m_stCatalogInfo, 1, wxEXPAND | wxALL, 5); /// mainSizer->Add( m_stCatalogInfo, 0, wxEXPAND| wxALL, 5 ); @@ -655,8 +655,6 @@ ChartDldrPanel::ChartDldrPanel(wxWindow* parent, wxWindowID id, wxEVT_RIGHT_DOWN, wxMouseEventHandler(ChartDldrPanel::OnContextMenu), NULL, this); #endif /* CHART_LIST */ - // m_bHelp->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( - // ChartDldrPanel::DoHelp ), NULL, this ); m_bDnldCharts->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartDldrPanel::OnDownloadCharts), NULL, this); @@ -716,9 +714,6 @@ ChartDldrPanel::~ChartDldrPanel() { wxEVT_RIGHT_DOWN, wxMouseEventHandler(ChartDldrPanel::OnContextMenu), NULL, this); #endif /* CHART_LIST */ - - // m_bHelp->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( - // ChartDldrPanel::DoHelp ), NULL, this ); m_bDnldCharts->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartDldrPanel::OnDownloadCharts), NULL, this); @@ -728,7 +723,7 @@ ChartDldrPanel::~ChartDldrPanel() { } #ifdef HAVE_WX_GESTURE_EVENTS -void ChartDldrPanel::OnLongPress(wxLongPressEvent &event) { +void ChartDldrPanel::OnLongPress(wxLongPressEvent& event) { printf(" OnLongPress\n"); if (1) { wxPoint pos = event.GetPosition(); @@ -736,9 +731,8 @@ void ChartDldrPanel::OnLongPress(wxLongPressEvent &event) { ev.m_x = pos.x; ev.m_y = pos.y; - //MouseEvent(ev); + // MouseEvent(ev); } - } #endif @@ -835,11 +829,11 @@ ChartPanel::ChartPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, m_dldrPanel = DldrPanel; -#ifdef HAVE_WX_GESTURE_EVENTS +#ifdef HAVE_WX_GESTURE_EVENTS Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(ChartPanel::OnContextMenu), NULL, this); - if (!EnableTouchEvents( wxTOUCH_PRESS_GESTURES)) { + if (!EnableTouchEvents(wxTOUCH_PRESS_GESTURES)) { wxLogError("Failed to enable touch events on chart downloader"); } @@ -868,14 +862,14 @@ void ChartPanel::OnContextMenu(wxMouseEvent& event) { } #ifdef HAVE_WX_GESTURE_EVENTS -void ChartPanel::OnLongPress(wxLongPressEvent &event) { +void ChartPanel::OnLongPress(wxLongPressEvent& event) { /* we defer the popup menu call upon the leftup event else the menu disappears immediately, */ m_popupWanted = true; } #endif -void ChartPanel::OnLeftUp(wxMouseEvent &event) { +void ChartPanel::OnLeftUp(wxMouseEvent& event) { wxPoint pos = event.GetPosition(); if (m_popupWanted) { @@ -898,16 +892,18 @@ ChartDldrPrefsDlg::ChartDldrPrefsDlg(wxWindow* parent, wxWindowID id, this->SetSizeHints(wxDefaultSize, wxDefaultSize); - wxBoxSizer *itemBoxSizerMainPanel = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* itemBoxSizerMainPanel = new wxBoxSizer(wxVERTICAL); SetSizer(itemBoxSizerMainPanel); - wxScrolledWindow *scrollWin = new wxScrolledWindow( - this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), wxVSCROLL); + wxScrolledWindow* scrollWin = new wxScrolledWindow( + this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), wxVSCROLL); scrollWin->SetScrollRate(1, 1); itemBoxSizerMainPanel->Add(scrollWin, 1, wxEXPAND | wxALL, 0); m_sdbSizerBtns = new wxStdDialogButtonSizer(); + m_bHelp = new wxButton(this, wxID_HELP); + m_sdbSizerBtns->Add(m_bHelp); m_sdbSizerBtnsOK = new wxButton(this, wxID_OK); m_sdbSizerBtns->AddButton(m_sdbSizerBtnsOK); m_sdbSizerBtnsCancel = new wxButton(this, wxID_CANCEL, _("Cancel")); @@ -916,23 +912,25 @@ ChartDldrPrefsDlg::ChartDldrPrefsDlg(wxWindow* parent, wxWindowID id, itemBoxSizerMainPanel->Add(m_sdbSizerBtns, 0, wxALL | wxEXPAND, 5); - wxBoxSizer *bSizerPrefsMain = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* bSizerPrefsMain = new wxBoxSizer(wxVERTICAL); scrollWin->SetSizer(bSizerPrefsMain); wxStaticBoxSizer* sbSizerPaths; sbSizerPaths = new wxStaticBoxSizer( - new wxStaticBox(scrollWin, wxID_ANY, _("Default Path to Charts")), wxVERTICAL); + new wxStaticBox(scrollWin, wxID_ANY, _("Default Path to Charts")), + wxVERTICAL); // m_dpDefaultDir = new wxDirPickerCtrl( this, wxID_ANY, wxEmptyString, // _("Select a root folder for your charts"), wxDefaultPosition, // wxDefaultSize, wxDIRP_USE_TEXTCTRL ); sbSizerPaths->Add( // m_dpDefaultDir, 0, wxALL|wxEXPAND, 5 ); - m_tcDefaultDir = new wxTextCtrl(scrollWin, wxID_ANY, _T(""), wxDefaultPosition, - wxSize(-1, -1), wxHSCROLL); + m_tcDefaultDir = new wxTextCtrl(scrollWin, wxID_ANY, _T(""), + wxDefaultPosition, wxSize(-1, -1), wxHSCROLL); sbSizerPaths->Add(m_tcDefaultDir, 3, wxALL | wxEXPAND, 5); - m_buttonChartDirectory = new wxButton(scrollWin, wxID_ANY, _("Select a folder")); + m_buttonChartDirectory = + new wxButton(scrollWin, wxID_ANY, _("Select a folder")); sbSizerPaths->Add(m_buttonChartDirectory, 1, wxALIGN_RIGHT | wxALL, 5); bSizerPrefsMain->Add(sbSizerPaths, 0, wxALL | wxEXPAND, 5); @@ -949,8 +947,9 @@ ChartDldrPrefsDlg::ChartDldrPrefsDlg(wxWindow* parent, wxWindowID id, m_stPreselect->Wrap(-1); sbSizerBehavior->Add(m_stPreselect, 0, wxALL, 5); - m_cbSelectUpdated = new wxCheckBox(scrollWin, wxID_ANY, _("All updated charts"), - wxDefaultPosition, wxDefaultSize, 0); + m_cbSelectUpdated = + new wxCheckBox(scrollWin, wxID_ANY, _("All updated charts"), + wxDefaultPosition, wxDefaultSize, 0); m_cbSelectUpdated->SetValue(true); sbSizerBehavior->Add(m_cbSelectUpdated, 0, wxALL, 5); @@ -976,7 +975,6 @@ ChartDldrPrefsDlg::ChartDldrPrefsDlg(wxWindow* parent, wxWindowID id, bSizerPrefsMain->Add(sbSizerBehavior, 1, wxALL | wxEXPAND, 5); - this->Fit(); // Constrain size on small displays @@ -984,11 +982,10 @@ ChartDldrPrefsDlg::ChartDldrPrefsDlg(wxWindow* parent, wxWindowID id, wxDisplaySize(&display_width, &display_height); wxSize canvas_size = GetOCPNCanvasWindow()->GetSize(); - if(display_height < 600){ + if (display_height < 600) { SetMaxSize(GetOCPNCanvasWindow()->GetSize()); SetSize(wxSize(60 * GetCharWidth(), canvas_size.y * 8 / 10)); - } - else { + } else { SetMaxSize(GetOCPNCanvasWindow()->GetSize()); SetSize(wxSize(60 * GetCharWidth(), canvas_size.y * 8 / 10)); } @@ -1008,6 +1005,11 @@ ChartDldrPrefsDlg::ChartDldrPrefsDlg(wxWindow* parent, wxWindowID id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ChartDldrPrefsDlg::OnDownloadMasterCatalog), NULL, this); + m_bHelp->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](wxCommandEvent) { + wxString datadir = GetPluginDataDir("manual_pi"); + Manual manual(this, datadir.ToStdString()); + manual.Launch("Chartdldr"); + }); } void ChartDldrPrefsDlg::OnDownloadMasterCatalog(wxCommandEvent& event) { diff --git a/plugins/chartdldr_pi/src/chartdldrgui.h b/plugins/chartdldr_pi/src/chartdldrgui.h index 2fab1876c8..616980e382 100644 --- a/plugins/chartdldr_pi/src/chartdldrgui.h +++ b/plugins/chartdldr_pi/src/chartdldrgui.h @@ -125,7 +125,6 @@ class ChartDldrPanel : public wxPanel { wxButton* m_bUpdateChartList; wxButton* m_bUpdateAllCharts; wxStaticText* m_stCatalogInfo; - // wxButton* m_bHelp; wxButton* m_bDnldCharts; // wxButton* m_bShowLocal; #if defined(CHART_LIST) @@ -157,7 +156,7 @@ class ChartDldrPanel : public wxPanel { virtual void OnShowLocalDir(wxCommandEvent& event) { event.Skip(); } virtual void OnSize(wxSizeEvent& event); #ifdef HAVE_WX_GESTURE_EVENTS - void OnLongPress(wxLongPressEvent &event); + void OnLongPress(wxLongPressEvent& event); #endif #if defined(CHART_LIST) @@ -208,6 +207,7 @@ class ChartDldrPrefsDlg : public wxDialog { wxStaticLine* m_staticline1; wxCheckBox* m_cbBulkUpdate; wxStdDialogButtonSizer* m_sdbSizerBtns; + wxButton* m_bHelp; wxButton* m_sdbSizerBtnsOK; wxButton* m_sdbSizerBtnsCancel; wxButton* m_buttonChartDirectory; @@ -244,9 +244,9 @@ class ChartPanel : public wxPanel { wxCheckBox* GetCB() { return m_cb; } bool isNew() { return (m_stat == _("New")); } bool isUpdated() { return (m_stat == _("Out of date")); } - void OnLeftUp(wxMouseEvent &event); + void OnLeftUp(wxMouseEvent& event); #ifdef HAVE_WX_GESTURE_EVENTS - void OnLongPress(wxLongPressEvent &event); + void OnLongPress(wxLongPressEvent& event); #endif private: diff --git a/plugins/dashboard_pi/CMakeLists.txt b/plugins/dashboard_pi/CMakeLists.txt index 32286b896f..8bf8baa299 100644 --- a/plugins/dashboard_pi/CMakeLists.txt +++ b/plugins/dashboard_pi/CMakeLists.txt @@ -199,6 +199,7 @@ target_include_directories(${PACKAGE_NAME} PRIVATE ) target_link_libraries(${PACKAGE_NAME} ocpn::opencpn ) target_link_libraries(${PACKAGE_NAME} ocpn::N2KParser ) +target_link_libraries(${PACKAGE_NAME} ocpn::manual ) IF (WIN32 AND NOT MSVC) SET( CMAKE_SHARED_LINKER_FLAGS "-L../../" ) diff --git a/plugins/dashboard_pi/src/dashboard_pi.cpp b/plugins/dashboard_pi/src/dashboard_pi.cpp index 0853c180e3..983e739947 100644 --- a/plugins/dashboard_pi/src/dashboard_pi.cpp +++ b/plugins/dashboard_pi/src/dashboard_pi.cpp @@ -5,7 +5,7 @@ * Purpose: Dashboard Plugin * Author: Jean-Eudes Onfray * expanded: Bernd Cirotzki 2023 (special colour design) - * + * *************************************************************************** * Copyright (C) 2010 by David S. Register * * * @@ -45,6 +45,7 @@ #include "wx/jsonwriter.h" #include "N2KParser.h" #include "../../../gui/include/gui/ocpn_fontdlg.h" +#include "manual.h" wxFontData *g_pFontTitle; wxFontData *g_pFontData; @@ -101,7 +102,6 @@ static const long long lNaN = 0xfff8000000000000; #include "qdebug.h" #endif - // the class factories, used to create and destroy instances of the PlugIn extern "C" DECL_EXP opencpn_plugin *create_pi(void *ppimgr) { @@ -513,15 +513,15 @@ int dashboard_pi::Init(void) { mPriMDA = 99; // Air press mPriDepth = 99; mPriSTW = 99; - mPriWTP = 99; // Water temp - mPriATMP = 99; // Air temp + mPriWTP = 99; // Water temp + mPriATMP = 99; // Air temp mPriSatStatus = 99; mPriSatUsed = 99; mSatsInView = 0; mPriAlt = 99; - mPriRSA = 99; //Rudder angle - mPriPitchRoll = 99; //Pitch and roll - mPriHUM = 99; // Humidity + mPriRSA = 99; // Rudder angle + mPriPitchRoll = 99; // Pitch and roll + mPriHUM = 99; // Humidity m_config_version = -1; mHDx_Watchdog = 2; mHDT_Watchdog = 2; @@ -531,7 +531,7 @@ int dashboard_pi::Init(void) { mVar_Watchdog = 2; mMWVA_Watchdog = 2; mMWVT_Watchdog = 2; - mDPT_DBT_Watchdog = 2; // Depth + mDPT_DBT_Watchdog = 2; // Depth mSTW_Watchdog = 2; mWTP_Watchdog = 2; mRSA_Watchdog = 2; @@ -549,16 +549,20 @@ int dashboard_pi::Init(void) { mHUM_Watchdog = 2; g_pFontTitle = new wxFontData(); - g_pFontTitle->SetChosenFont(wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL)); - + g_pFontTitle->SetChosenFont( + wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL)); + g_pFontData = new wxFontData(); - g_pFontData->SetChosenFont(wxFont(14, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + g_pFontData->SetChosenFont( + wxFont(14, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); g_pFontLabel = new wxFontData(); - g_pFontLabel->SetChosenFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + g_pFontLabel->SetChosenFont( + wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); g_pFontSmall = new wxFontData(); - g_pFontSmall->SetChosenFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + g_pFontSmall->SetChosenFont( + wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); g_pUSFontTitle = &g_USFontTitle; g_pUSFontData = &g_USFontData; @@ -617,81 +621,61 @@ int dashboard_pi::Init(void) { wxDEFINE_EVENT(EVT_N2K_127245, ObservedEvt); NMEA2000Id id_127245 = NMEA2000Id(127245); listener_127245 = GetListener(id_127245, EVT_N2K_127245, this); - Bind(EVT_N2K_127245, [&](ObservedEvt ev) { - HandleN2K_127245(ev); - }); - + Bind(EVT_N2K_127245, [&](ObservedEvt ev) { HandleN2K_127245(ev); }); // Roll Pitch PGN 127257 wxDEFINE_EVENT(EVT_N2K_127257, ObservedEvt); NMEA2000Id id_127257 = NMEA2000Id(127257); listener_127257 = GetListener(id_127257, EVT_N2K_127257, this); - Bind(EVT_N2K_127257, [&](ObservedEvt ev) { - HandleN2K_127257(ev); - }); + Bind(EVT_N2K_127257, [&](ObservedEvt ev) { HandleN2K_127257(ev); }); // Speed through water PGN 128259 wxDEFINE_EVENT(EVT_N2K_128259, ObservedEvt); NMEA2000Id id_128259 = NMEA2000Id(128259); listener_128259 = GetListener(id_128259, EVT_N2K_128259, this); - Bind(EVT_N2K_128259, [&](ObservedEvt ev) { - HandleN2K_128259(ev); - }); + Bind(EVT_N2K_128259, [&](ObservedEvt ev) { HandleN2K_128259(ev); }); // Depth Data PGN 128267 wxDEFINE_EVENT(EVT_N2K_128267, ObservedEvt); NMEA2000Id id_128267 = NMEA2000Id(128267); listener_128267 = GetListener(id_128267, EVT_N2K_128267, this); - Bind(EVT_N2K_128267, [&](ObservedEvt ev) { - HandleN2K_128267(ev); - }); + Bind(EVT_N2K_128267, [&](ObservedEvt ev) { HandleN2K_128267(ev); }); // Distance log wxDEFINE_EVENT(EVT_N2K_128275, ObservedEvt); NMEA2000Id id_128275 = NMEA2000Id(128275); listener_128275 = GetListener(id_128275, EVT_N2K_128275, this); - Bind(EVT_N2K_128275, [&](ObservedEvt ev) { - HandleN2K_128275(ev); - }); + Bind(EVT_N2K_128275, [&](ObservedEvt ev) { HandleN2K_128275(ev); }); // GNSS Position Data PGN 129029 wxDEFINE_EVENT(EVT_N2K_129029, ObservedEvt); NMEA2000Id id_129029 = NMEA2000Id(129029); listener_129029 = GetListener(id_129029, EVT_N2K_129029, this); - Bind(EVT_N2K_129029, [&](ObservedEvt ev) { - HandleN2K_129029(ev); - }); + Bind(EVT_N2K_129029, [&](ObservedEvt ev) { HandleN2K_129029(ev); }); // GNSS Satellites in View PGN 129540 wxDEFINE_EVENT(EVT_N2K_129540, ObservedEvt); NMEA2000Id id_129540 = NMEA2000Id(129540); listener_129540 = GetListener(id_129540, EVT_N2K_129540, this); - Bind(EVT_N2K_129540, [&](ObservedEvt ev) { - HandleN2K_129540(ev); - }); + Bind(EVT_N2K_129540, [&](ObservedEvt ev) { HandleN2K_129540(ev); }); // Wind PGN 130306 wxDEFINE_EVENT(EVT_N2K_130306, ObservedEvt); NMEA2000Id id_130306 = NMEA2000Id(130306); listener_130306 = GetListener(id_130306, EVT_N2K_130306, this); - Bind(EVT_N2K_130306, [&](ObservedEvt ev) { - HandleN2K_130306(ev); - }); + Bind(EVT_N2K_130306, [&](ObservedEvt ev) { HandleN2K_130306(ev); }); // Envorinment PGN 130310 wxDEFINE_EVENT(EVT_N2K_130310, ObservedEvt); NMEA2000Id id_130310 = NMEA2000Id(130310); listener_130310 = GetListener(id_130310, EVT_N2K_130310, this); - Bind(EVT_N2K_130310, [&](ObservedEvt ev) { - HandleN2K_130310(ev); - }); + Bind(EVT_N2K_130310, [&](ObservedEvt ev) { HandleN2K_130310(ev); }); - // Envorinment PGN 130313 + // Envorinment PGN 130313 wxDEFINE_EVENT(EVT_N2K_130313, ObservedEvt); NMEA2000Id id_130313 = NMEA2000Id(130313); listener_130313 = GetListener(id_130313, EVT_N2K_130313, this); - Bind(EVT_N2K_130313, [&](ObservedEvt ev) { HandleN2K_130313(ev); - }); + Bind(EVT_N2K_130313, [&](ObservedEvt ev) { HandleN2K_130313(ev); }); Start(1000, wxTIMER_CONTINUOUS); @@ -721,10 +705,10 @@ bool dashboard_pi::DeInit(void) { delete pdwc; } -// delete g_pFontTitle; -// delete g_pFontData; -// delete g_pFontLabel; -// delete g_pFontSmall; + // delete g_pFontTitle; + // delete g_pFontData; + // delete g_pFontLabel; + // delete g_pFontSmall; return true; } @@ -742,8 +726,6 @@ double GetJsonDouble(wxJSONValue &value) { return nan(""); } - - void dashboard_pi::Notify() { SendUtcTimeToAllInstruments(mUTCDateTime); for (size_t i = 0; i < m_ArrayOfDashboardWindow.GetCount(); i++) { @@ -1003,7 +985,7 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { m_NMEA0183 << sentence; if (m_NMEA0183.PreParse()) { - if (m_NMEA0183.LastSentenceIDReceived == _T("DBT")) { + if (m_NMEA0183.LastSentenceIDReceived == _T("DBT")) { if (mPriDepth >= 5) { if (m_NMEA0183.Parse()) { /* @@ -1027,7 +1009,7 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { mPriDepth = 5; mDPT_DBT_Watchdog = gps_watchdog_timeout_ticks; } - } + } } } @@ -1058,9 +1040,9 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { else if (m_NMEA0183.LastSentenceIDReceived == _T("GGA")) { if (0) // debug output printf("GGA mPriPosition=%d mPriSatUsed=%d \tnSat=%d alt=%3.2f\n", - mPriPosition, mPriSatUsed, - m_NMEA0183.Gga.NumberOfSatellitesInUse, - m_NMEA0183.Gga.AntennaAltitudeMeters); + mPriPosition, mPriSatUsed, + m_NMEA0183.Gga.NumberOfSatellitesInUse, + m_NMEA0183.Gga.AntennaAltitudeMeters); if (mPriAlt >= 3 && (mPriPosition >= 1 || mPriSatUsed >= 1)) { if (m_NMEA0183.Parse()) { if (m_NMEA0183.Gga.GPSQuality > 0 && @@ -1099,7 +1081,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } if (mPriSatUsed >= 3) { mSatsInUse = m_NMEA0183.Gga.NumberOfSatellitesInUse; - SendSentenceToAllInstruments( OCPN_DBP_STC_SAT, mSatsInUse, _T ("")); + SendSentenceToAllInstruments(OCPN_DBP_STC_SAT, mSatsInUse, + _T ("")); mPriSatUsed = 3; mSatsUsed_Wdog = gps_watchdog_timeout_ticks; } @@ -1167,8 +1150,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { if (mPriSatStatus >= 3) { SendSatInfoToAllInstruments( - mSatsInView, m_NMEA0183.Gsv.MessageNumber, - m_NMEA0183.TalkerID, m_NMEA0183.Gsv.SatInfo); + mSatsInView, m_NMEA0183.Gsv.MessageNumber, m_NMEA0183.TalkerID, + m_NMEA0183.Gsv.SatInfo); mPriSatStatus = 3; mSatStatus_Wdog = gps_watchdog_timeout_ticks; } @@ -1280,7 +1263,7 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } } } else if (m_NMEA0183.LastSentenceIDReceived == _T("MDA") && - (mPriMDA >= 5 || mPriATMP >= 5 || mPriHUM >= 4)) { + (mPriMDA >= 5 || mPriATMP >= 5 || mPriHUM >= 4)) { // Barometric pressure || HUmidity || Air temp if (m_NMEA0183.Parse()) { // TODO make posibilyti to select between Bar or InchHg @@ -1290,8 +1273,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { */ if (mPriMDA >= 5 && m_NMEA0183.Mda.Pressure > .8 && m_NMEA0183.Mda.Pressure < 1.1) { - SendSentenceToAllInstruments( OCPN_DBP_STC_MDA, - m_NMEA0183.Mda.Pressure * 1000, _T("hPa")); + SendSentenceToAllInstruments( + OCPN_DBP_STC_MDA, m_NMEA0183.Mda.Pressure * 1000, _T("hPa")); mPriMDA = 5; mMDA_Watchdog = no_nav_watchdog_timeout_ticks; } @@ -1299,9 +1282,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { double airtemp = m_NMEA0183.Mda.AirTemp; if (!std::isnan(airtemp) && airtemp < 999.0) { SendSentenceToAllInstruments( - OCPN_DBP_STC_ATMP, - toUsrTemp_Plugin(airtemp, g_iDashTempUnit), - getUsrTempUnit_Plugin(g_iDashTempUnit)); + OCPN_DBP_STC_ATMP, toUsrTemp_Plugin(airtemp, g_iDashTempUnit), + getUsrTempUnit_Plugin(g_iDashTempUnit)); mATMP_Watchdog = no_nav_watchdog_timeout_ticks; mPriATMP = 5; } @@ -1358,8 +1340,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { wxString windunit; if (!std::isnan(m_NMEA0183.Mwd.WindAngleTrue)) { // if WindAngleTrue is available, use it ... - SendSentenceToAllInstruments( OCPN_DBP_STC_TWD, - m_NMEA0183.Mwd.WindAngleTrue, _T("\u00B0")); + SendSentenceToAllInstruments( + OCPN_DBP_STC_TWD, m_NMEA0183.Mwd.WindAngleTrue, _T("\u00B0")); mPriWDN = 6; // MWD can be seldom updated by the sensor. Set prolonged watchdog mWDN_Watchdog = no_nav_watchdog_timeout_ticks; @@ -1373,17 +1355,18 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } else if (twd < 0.) { twd += 360; } - SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, twd, - _T("\u00B0")); + SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, twd, _T("\u00B0")); mPriWDN = 6; mWDN_Watchdog = no_nav_watchdog_timeout_ticks; } } - SendSentenceToAllInstruments(OCPN_DBP_STC_TWS, + SendSentenceToAllInstruments( + OCPN_DBP_STC_TWS, toUsrSpeed_Plugin(m_NMEA0183.Mwd.WindSpeedKnots, g_iDashWindSpeedUnit), getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); - SendSentenceToAllInstruments(OCPN_DBP_STC_TWS2, + SendSentenceToAllInstruments( + OCPN_DBP_STC_TWS2, toUsrSpeed_Plugin(m_NMEA0183.Mwd.WindSpeedKnots, g_iDashWindSpeedUnit), getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); @@ -1591,10 +1574,9 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { if (mPriRSA >= 3) { if (m_NMEA0183.Parse()) { if (m_NMEA0183.Rsa.IsStarboardDataValid == NTrue) { - SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, - m_NMEA0183.Rsa.Starboard, _T("\u00B0")); - } - else if (m_NMEA0183.Rsa.IsPortDataValid == NTrue) { + SendSentenceToAllInstruments( + OCPN_DBP_STC_RSA, m_NMEA0183.Rsa.Starboard, _T("\u00B0")); + } else if (m_NMEA0183.Rsa.IsPortDataValid == NTrue) { SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, -m_NMEA0183.Rsa.Port, _T("\u00B0")); } @@ -1762,7 +1744,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { xdrdata = m_NMEA0183.Xdr.TransducerInfo[i].MeasurementData; // XDR Airtemp if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerType == _T("C")) { - if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName.MakeUpper() + if (m_NMEA0183.Xdr.TransducerInfo[i] + .TransducerName.MakeUpper() .Contains(_T("AIR")) || m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == _T("Te") || m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == @@ -1779,10 +1762,10 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { continue; } } // Water temp - if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName.MakeUpper() - .Contains("WATER") || - m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == - "WTHI") { + if (m_NMEA0183.Xdr.TransducerInfo[i] + .TransducerName.MakeUpper() + .Contains("WATER") || + m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == "WTHI") { if (mPriWTP >= 3) { mPriWTP = 3; SendSentenceToAllInstruments( @@ -1798,8 +1781,10 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } // XDR Pressure if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerType == "P") { - if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName.MakeUpper() - .Contains(_T("BARO")) && mPriMDA >= 4) { + if (m_NMEA0183.Xdr.TransducerInfo[i] + .TransducerName.MakeUpper() + .Contains(_T("BARO")) && + mPriMDA >= 4) { if (m_NMEA0183.Xdr.TransducerInfo[i].UnitOfMeasurement == "B") { xdrdata *= 1000; SendSentenceToAllInstruments(OCPN_DBP_STC_MDA, xdrdata, @@ -1834,8 +1819,8 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } } // XDR Heel - if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName. - Contains("ROLL")) { + if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName.Contains( + "ROLL")) { if (mPriPitchRoll >= 3) { if (m_NMEA0183.Xdr.TransducerInfo[i].MeasurementData > 0) { xdrunit = _T("\u00B0\u003E") + _("Stbd"); @@ -1854,8 +1839,9 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } } // XDR Rudder Angle - if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName.MakeUpper() - .Contains("RUDDER")) { + if (m_NMEA0183.Xdr.TransducerInfo[i] + .TransducerName.MakeUpper() + .Contains("RUDDER")) { if (mPriRSA > 4) { SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, xdrdata, _T("\u00B0")); @@ -1868,12 +1854,13 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { // Depth sounding if ((m_NMEA0183.Xdr.TransducerInfo[i].TransducerType == "D")) { bool goodvalue = false; - if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == "XDHI" - && mPriDepth >= 6) { + if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == "XDHI" && + mPriDepth >= 6) { goodvalue = true; mPriDepth = 6; - } else if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == "XDLO" - && mPriDepth >= 7) { + } else if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerName == + "XDLO" && + mPriDepth >= 7) { goodvalue = true; mPriDepth = 7; } @@ -1894,7 +1881,7 @@ void dashboard_pi::SetNMEASentence(wxString &sentence) { } } } - } // Humidity + } // Humidity if (m_NMEA0183.Xdr.TransducerInfo[i].TransducerType == "H") { if (mPriHUM >= 3) { if (m_NMEA0183.Xdr.TransducerInfo[i].UnitOfMeasurement == "P") { @@ -2012,7 +1999,7 @@ void dashboard_pi::CalculateAndUpdateTWDS(double awsKnots, double awaDegrees) { // Rudder data PGN 127245 void dashboard_pi::HandleN2K_127245(ObservedEvt ev) { NMEA2000Id id_127245(127245); - std::vectorv = GetN2000Payload(id_127245, ev); + std::vector v = GetN2000Payload(id_127245, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); @@ -2026,8 +2013,7 @@ void dashboard_pi::HandleN2K_127245(ObservedEvt ev) { if (mPriRSA == 1) { // We favor first received after last WD if (source != prio127245) return; - } - else { + } else { // First time use after WD time out. prio127245 = source; } @@ -2036,11 +2022,13 @@ void dashboard_pi::HandleN2K_127245(ObservedEvt ev) { unsigned char Instance; tN2kRudderDirectionOrder RudderDirectionOrder; - // Get rudder position - if (ParseN2kPGN127245(v, RudderPosition, Instance, RudderDirectionOrder, AngleOrder)) { + // Get rudder position + if (ParseN2kPGN127245(v, RudderPosition, Instance, RudderDirectionOrder, + AngleOrder)) { if (!N2kIsNA(RudderPosition)) { double m_rudangle = GEODESIC_RAD2DEG(RudderPosition); - SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, m_rudangle, _T("\u00B0")); + SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, m_rudangle, + _T("\u00B0")); mRSA_Watchdog = gps_watchdog_timeout_ticks; mPriRSA = 1; } @@ -2051,7 +2039,7 @@ void dashboard_pi::HandleN2K_127245(ObservedEvt ev) { // Roll Pitch data PGN 127257 void dashboard_pi::HandleN2K_127257(ObservedEvt ev) { NMEA2000Id id_127257(127257); - std::vectorv = GetN2000Payload(id_127257, ev); + std::vector v = GetN2000Payload(id_127257, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); @@ -2065,8 +2053,7 @@ void dashboard_pi::HandleN2K_127257(ObservedEvt ev) { if (mPriPitchRoll == 1) { // We favor first received after last WD if (source != prio127257) return; - } - else { + } else { // First time use after WD time out. prio127257 = source; } @@ -2104,7 +2091,7 @@ void dashboard_pi::HandleN2K_127257(ObservedEvt ev) { void dashboard_pi::HandleN2K_128267(ObservedEvt ev) { NMEA2000Id id_128267(128267); - std::vectorv = GetN2000Payload(id_128267, ev); + std::vector v = GetN2000Payload(id_128267, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); @@ -2117,8 +2104,7 @@ void dashboard_pi::HandleN2K_128267(ObservedEvt ev) { if (mPriDepth >= 1) { if (mPriDepth == 1) { if (source != prio128267) return; - } - else { + } else { prio128267 = source; } @@ -2130,12 +2116,15 @@ void dashboard_pi::HandleN2K_128267(ObservedEvt ev) { if (!N2kIsNA(DepthBelowTransducer)) { double depth = DepthBelowTransducer; // Set prio to sensor's offset - if (!std::isnan(Offset) && !N2kIsNA(Offset)) depth += Offset; - else (depth += g_dDashDBTOffset); + if (!std::isnan(Offset) && !N2kIsNA(Offset)) + depth += Offset; + else + (depth += g_dDashDBTOffset); - SendSentenceToAllInstruments(OCPN_DBP_STC_DPT, - toUsrDistance_Plugin(depth / 1852.0, g_iDashDepthUnit), - getUsrDistanceUnit_Plugin(g_iDashDepthUnit)); + SendSentenceToAllInstruments( + OCPN_DBP_STC_DPT, + toUsrDistance_Plugin(depth / 1852.0, g_iDashDepthUnit), + getUsrDistanceUnit_Plugin(g_iDashDepthUnit)); mPriDepth = 1; mDPT_DBT_Watchdog = gps_watchdog_timeout_ticks; } @@ -2143,37 +2132,35 @@ void dashboard_pi::HandleN2K_128267(ObservedEvt ev) { } } - void dashboard_pi::HandleN2K_128275(ObservedEvt ev) { NMEA2000Id id_128275(128275); - std::vectorv = GetN2000Payload(id_128275, ev); + std::vector v = GetN2000Payload(id_128275, ev); uint16_t DaysSince1970; double SecondsSinceMidnight; uint32_t Log, TripLog; // Get log & Trip log if (ParseN2kPGN128275(v, DaysSince1970, SecondsSinceMidnight, Log, TripLog)) { - if (!N2kIsNA(Log)) { double m_slog = METERS2NM((double)Log); - SendSentenceToAllInstruments( OCPN_DBP_STC_VLW2, - toUsrDistance_Plugin(m_slog, g_iDashDistanceUnit), - getUsrDistanceUnit_Plugin(g_iDashDistanceUnit)); + SendSentenceToAllInstruments( + OCPN_DBP_STC_VLW2, toUsrDistance_Plugin(m_slog, g_iDashDistanceUnit), + getUsrDistanceUnit_Plugin(g_iDashDistanceUnit)); mLOG_Watchdog = no_nav_watchdog_timeout_ticks; } } if (!N2kIsNA(TripLog)) { double m_tlog = METERS2NM((double)TripLog); SendSentenceToAllInstruments( - OCPN_DBP_STC_VLW1, toUsrDistance_Plugin(m_tlog, g_iDashDistanceUnit), - getUsrDistanceUnit_Plugin(g_iDashDistanceUnit)); + OCPN_DBP_STC_VLW1, toUsrDistance_Plugin(m_tlog, g_iDashDistanceUnit), + getUsrDistanceUnit_Plugin(g_iDashDistanceUnit)); mTrLOG_Watchdog = no_nav_watchdog_timeout_ticks; } } void dashboard_pi::HandleN2K_128259(ObservedEvt ev) { NMEA2000Id id_128259(128259); - std::vectorv = GetN2000Payload(id_128259, ev); + std::vector v = GetN2000Payload(id_128259, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); @@ -2186,8 +2173,7 @@ void dashboard_pi::HandleN2K_128259(ObservedEvt ev) { if (mPriSTW >= 1) { if (mPriSTW == 1) { if (source != prio128259) return; - } - else { + } else { prio128259 = source; } @@ -2197,12 +2183,11 @@ void dashboard_pi::HandleN2K_128259(ObservedEvt ev) { // Get speed through water if (ParseN2kPGN128259(v, SID, WaterReferenced, GroundReferenced, SWRT)) { - if (!N2kIsNA(WaterReferenced)) { double stw_knots = MS2KNOTS(WaterReferenced); SendSentenceToAllInstruments( - OCPN_DBP_STC_STW, toUsrSpeed_Plugin(stw_knots, g_iDashSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); + OCPN_DBP_STC_STW, toUsrSpeed_Plugin(stw_knots, g_iDashSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); mPriSTW = 1; mSTW_Watchdog = gps_watchdog_timeout_ticks; } @@ -2213,7 +2198,7 @@ void dashboard_pi::HandleN2K_128259(ObservedEvt ev) { wxString talker_N2k = wxEmptyString; void dashboard_pi::HandleN2K_129029(ObservedEvt ev) { NMEA2000Id id_129029(129029); - std::vectorv = GetN2000Payload(id_129029, ev); + std::vector v = GetN2000Payload(id_129029, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); char ss[4]; @@ -2221,7 +2206,7 @@ void dashboard_pi::HandleN2K_129029(ObservedEvt ev) { std::string ident = std::string(ss); std::string source = GetN2000Source(id_129029, ev); source += ":" + ident; - //Use the source prioritized by OCPN only + // Use the source prioritized by OCPN only if (source != prioN2kPGNsat) return; unsigned char SID; @@ -2238,21 +2223,35 @@ void dashboard_pi::HandleN2K_129029(ObservedEvt ev) { double AgeOfCorrection; // Get used satellite system - if (ParseN2kPGN129029(v, SID, DaysSince1970, SecondsSinceMidnight, - Latitude, Longitude, Altitude, - GNSStype, GNSSmethod, - nSatellites, HDOP, PDOP, GeoidalSeparation, - nReferenceStations, ReferenceStationType, ReferenceSationID, + if (ParseN2kPGN129029(v, SID, DaysSince1970, SecondsSinceMidnight, Latitude, + Longitude, Altitude, GNSStype, GNSSmethod, nSatellites, + HDOP, PDOP, GeoidalSeparation, nReferenceStations, + ReferenceStationType, ReferenceSationID, AgeOfCorrection)) { switch (GNSStype) { - case 0: talker_N2k = "GP"; break; //GPS - case 1: talker_N2k = "GL"; break; //GLONASS - case 2: talker_N2k = "GPSGLONAS"; break; - case 3: talker_N2k = "GP"; break; - case 4: talker_N2k = "GPSGLONAS"; break; - case 5: talker_N2k = "Chayka"; break; - case 8: talker_N2k = "GA"; break; //Galileo - default: talker_N2k = wxEmptyString; + case 0: + talker_N2k = "GP"; + break; // GPS + case 1: + talker_N2k = "GL"; + break; // GLONASS + case 2: + talker_N2k = "GPSGLONAS"; + break; + case 3: + talker_N2k = "GP"; + break; + case 4: + talker_N2k = "GPSGLONAS"; + break; + case 5: + talker_N2k = "Chayka"; + break; + case 8: + talker_N2k = "GA"; + break; // Galileo + default: + talker_N2k = wxEmptyString; } if (!N2kIsNA(Altitude)) { if (mPriAlt >= 1) { @@ -2266,7 +2265,7 @@ void dashboard_pi::HandleN2K_129029(ObservedEvt ev) { void dashboard_pi::HandleN2K_129540(ObservedEvt ev) { NMEA2000Id id_129540(129540); - std::vectorv = GetN2000Payload(id_129540, ev); + std::vector v = GetN2000Payload(id_129540, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); @@ -2275,7 +2274,7 @@ void dashboard_pi::HandleN2K_129540(ObservedEvt ev) { std::string ident = std::string(ss); std::string source = GetN2000Source(id_129540, ev); source += ":" + ident; - //Use the source prioritized by OCPN only + // Use the source prioritized by OCPN only if (source != prioN2kPGNsat) return; unsigned char SID; @@ -2284,7 +2283,6 @@ void dashboard_pi::HandleN2K_129540(ObservedEvt ev) { // Get the GNSS status data if (ParseN2kPGN129540(v, SID, Mode, NumberOfSVs)) { - if (!N2kIsNA(NumberOfSVs) && mPriSatStatus == 1) { // Step through each satellite, one-by-one // Arrange to max three messages with up to 4 sats each like N0183 GSV @@ -2299,7 +2297,7 @@ void dashboard_pi::HandleN2K_129540(ObservedEvt ev) { for (idx = 0; idx < 4; idx++) { tSatelliteInfo SatelliteInfo; index = idx + 4 * iMesNum; - if (index >= NumberOfSVs -1) break; + if (index >= NumberOfSVs - 1) break; if (ParseN2kPGN129540(v, index, SatelliteInfo)) { iPRN = (int)SatelliteInfo.PRN; dElevRad = SatelliteInfo.Elevation; @@ -2314,8 +2312,9 @@ void dashboard_pi::HandleN2K_129540(ObservedEvt ev) { } // Send to GPS.cpp if (idx > 0) { - SendSatInfoToAllInstruments(NumberOfSVs, iMesNum + 1, talker_N2k, N2K_SatInfo); - //mPriSatStatus = 1; + SendSatInfoToAllInstruments(NumberOfSVs, iMesNum + 1, talker_N2k, + N2K_SatInfo); + // mPriSatStatus = 1; mSatStatus_Wdog = gps_watchdog_timeout_ticks; } } @@ -2326,7 +2325,7 @@ void dashboard_pi::HandleN2K_129540(ObservedEvt ev) { // Wind PGN 130306 void dashboard_pi::HandleN2K_130306(ObservedEvt ev) { NMEA2000Id id_130306(130306); - std::vectorv = GetN2000Payload(id_130306, ev); + std::vector v = GetN2000Payload(id_130306, ev); // Get a uniqe ID to prioritize source(s) unsigned char source_id = v.at(7); @@ -2339,8 +2338,7 @@ void dashboard_pi::HandleN2K_130306(ObservedEvt ev) { if (mPriWDN >= 1) { if (mPriWDN == 1) { if (source != prio130306) return; - } - else { + } else { prio130306 = source; } @@ -2350,90 +2348,93 @@ void dashboard_pi::HandleN2K_130306(ObservedEvt ev) { // Get wind data if (ParseN2kPGN130306(v, SID, WindSpeed, WindAngle, WindReference)) { - if (!N2kIsNA(WindSpeed) && !N2kIsNA(WindAngle)) { double m_twaangle, m_twaspeed_kn; bool sendTrueWind = false; switch (WindReference) { - case 0: // N2kWind direction True North - if (mPriWDN >= 1) { - double m_twdT = GEODESIC_RAD2DEG(WindAngle); - SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, m_twdT, _T("\u00B0")); - mPriWDN = 1; - mWDN_Watchdog = no_nav_watchdog_timeout_ticks; - } - break; - case 1: // N2kWind direction Magnetic North - if (mPriWDN >= 1) { - double m_twdT = GEODESIC_RAD2DEG(WindAngle); - // Make it true if variation is available - if (!std::isnan(mVar)) { - m_twdT = (m_twdT)+mVar; - if (m_twdT > 360.) { - m_twdT -= 360; + case 0: // N2kWind direction True North + if (mPriWDN >= 1) { + double m_twdT = GEODESIC_RAD2DEG(WindAngle); + SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, m_twdT, + _T("\u00B0")); + mPriWDN = 1; + mWDN_Watchdog = no_nav_watchdog_timeout_ticks; + } + break; + case 1: // N2kWind direction Magnetic North + if (mPriWDN >= 1) { + double m_twdT = GEODESIC_RAD2DEG(WindAngle); + // Make it true if variation is available + if (!std::isnan(mVar)) { + m_twdT = (m_twdT) + mVar; + if (m_twdT > 360.) { + m_twdT -= 360; + } else if (m_twdT < 0.) { + m_twdT += 360; + } } - else if (m_twdT < 0.) { - m_twdT += 360; + SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, m_twdT, + _T("\u00B0")); + mPriWDN = 1; + mWDN_Watchdog = no_nav_watchdog_timeout_ticks; + } + break; + case 2: // N2kWind_Apparent_centerline + if (mPriAWA >= 1) { + double m_awaangle, m_awaspeed_kn, calc_angle; + // Angle equals 0-360 degr + m_awaangle = GEODESIC_RAD2DEG(WindAngle); + calc_angle = m_awaangle; + wxString m_awaunit = _T("\u00B0R"); + // Should be unit "L" and 0-180 to port + if (m_awaangle > 180.0) { + m_awaangle = 360.0 - m_awaangle; + m_awaunit = _T("\u00B0L"); + } + SendSentenceToAllInstruments(OCPN_DBP_STC_AWA, m_awaangle, + m_awaunit); + // Speed + m_awaspeed_kn = MS2KNOTS(WindSpeed); + SendSentenceToAllInstruments( + OCPN_DBP_STC_AWS, + toUsrSpeed_Plugin(m_awaspeed_kn, g_iDashWindSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); + mPriAWA = 1; + mMWVA_Watchdog = gps_watchdog_timeout_ticks; + + // If not N2K true wind data are recently received calculate it. + if (mPriTWA != 1) { + // Wants -+ angle instead of "L"/"R" + if (calc_angle > 180) calc_angle -= 360.0; + CalculateAndUpdateTWDS(m_awaspeed_kn, calc_angle); + mPriTWA = 2; + mPriWDN = 2; + mMWVT_Watchdog = gps_watchdog_timeout_ticks; + mWDN_Watchdog = no_nav_watchdog_timeout_ticks; } } - SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, m_twdT, _T("\u00B0")); - mPriWDN = 1; - mWDN_Watchdog = no_nav_watchdog_timeout_ticks; - } - break; - case 2: // N2kWind_Apparent_centerline - if (mPriAWA >= 1) { - double m_awaangle, m_awaspeed_kn, calc_angle; - // Angle equals 0-360 degr - m_awaangle = GEODESIC_RAD2DEG(WindAngle); - calc_angle = m_awaangle; - wxString m_awaunit = _T("\u00B0R"); - // Should be unit "L" and 0-180 to port - if (m_awaangle > 180.0) { - m_awaangle = 360.0 - m_awaangle; - m_awaunit = _T("\u00B0L"); + break; + case 3: // N2kWind_True_centerline_boat(ground) + if (mPriTWA >= 1 && g_bDBtrueWindGround) { + m_twaangle = GEODESIC_RAD2DEG(WindAngle); + m_twaspeed_kn = MS2KNOTS(WindSpeed); + sendTrueWind = true; } - SendSentenceToAllInstruments(OCPN_DBP_STC_AWA, m_awaangle, m_awaunit); - // Speed - m_awaspeed_kn = MS2KNOTS(WindSpeed); - SendSentenceToAllInstruments(OCPN_DBP_STC_AWS, - toUsrSpeed_Plugin(m_awaspeed_kn, g_iDashWindSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); - mPriAWA = 1; - mMWVA_Watchdog = gps_watchdog_timeout_ticks; - - // If not N2K true wind data are recently received calculate it. - if (mPriTWA != 1) { - // Wants -+ angle instead of "L"/"R" - if (calc_angle > 180) calc_angle -= 360.0; - CalculateAndUpdateTWDS(m_awaspeed_kn, calc_angle); - mPriTWA = 2; - mPriWDN = 2; - mMWVT_Watchdog = gps_watchdog_timeout_ticks; - mWDN_Watchdog = no_nav_watchdog_timeout_ticks; + break; + case 4: // N2kWind_True_Centerline__water + if (mPriTWA >= 1 && !g_bDBtrueWindGround) { + m_twaangle = GEODESIC_RAD2DEG(WindAngle); + m_twaspeed_kn = MS2KNOTS(WindSpeed); + sendTrueWind = true; } - } - break; - case 3: // N2kWind_True_centerline_boat(ground) - if (mPriTWA >= 1 && g_bDBtrueWindGround) { - m_twaangle = GEODESIC_RAD2DEG(WindAngle); - m_twaspeed_kn = MS2KNOTS(WindSpeed); - sendTrueWind = true; - } - break; - case 4: // N2kWind_True_Centerline__water - if (mPriTWA >= 1 && !g_bDBtrueWindGround) { - m_twaangle = GEODESIC_RAD2DEG(WindAngle); - m_twaspeed_kn = MS2KNOTS(WindSpeed); - sendTrueWind = true; - } - break; - case 6: // N2kWind_Error - break; - case 7: // N2kWind_Unavailable - break; - default: break; + break; + case 6: // N2kWind_Error + break; + case 7: // N2kWind_Unavailable + break; + default: + break; } if (sendTrueWind) { @@ -2446,14 +2447,16 @@ void dashboard_pi::HandleN2K_130306(ObservedEvt ev) { } SendSentenceToAllInstruments(OCPN_DBP_STC_TWA, m_twaangle, m_twaunit); // Wind speed - SendSentenceToAllInstruments(OCPN_DBP_STC_TWS, - toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); - SendSentenceToAllInstruments(OCPN_DBP_STC_TWS2, - toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); + SendSentenceToAllInstruments( + OCPN_DBP_STC_TWS, + toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); + SendSentenceToAllInstruments( + OCPN_DBP_STC_TWS2, + toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); mPriTWA = 1; - mPriWDN = 1; // For source prio + mPriWDN = 1; // For source prio mMWVT_Watchdog = gps_watchdog_timeout_ticks; } } @@ -2463,20 +2466,20 @@ void dashboard_pi::HandleN2K_130306(ObservedEvt ev) { void dashboard_pi::HandleN2K_130310(ObservedEvt ev) { NMEA2000Id id_130310(130310); - std::vectorv = GetN2000Payload(id_130310, ev); + std::vector v = GetN2000Payload(id_130310, ev); unsigned char SID; double WaterTemperature, OutsideAmbientAirTemperature, AtmosphericPressure; // Outside Environmental parameters - if (ParseN2kPGN130310(v, SID, WaterTemperature, - OutsideAmbientAirTemperature, AtmosphericPressure)) { + if (ParseN2kPGN130310(v, SID, WaterTemperature, OutsideAmbientAirTemperature, + AtmosphericPressure)) { if (mPriWTP >= 1) { if (!N2kIsNA(WaterTemperature)) { double m_wtemp KELVIN2C(WaterTemperature); - SendSentenceToAllInstruments( - OCPN_DBP_STC_TMP, toUsrTemp_Plugin(m_wtemp, g_iDashTempUnit), - getUsrTempUnit_Plugin(g_iDashTempUnit)); - mPriWTP =1; + SendSentenceToAllInstruments(OCPN_DBP_STC_TMP, + toUsrTemp_Plugin(m_wtemp, g_iDashTempUnit), + getUsrTempUnit_Plugin(g_iDashTempUnit)); + mPriWTP = 1; mWTP_Watchdog = no_nav_watchdog_timeout_ticks; } } @@ -2486,8 +2489,8 @@ void dashboard_pi::HandleN2K_130310(ObservedEvt ev) { double m_airtemp = KELVIN2C(OutsideAmbientAirTemperature); if (m_airtemp > -60 && m_airtemp < 100) { SendSentenceToAllInstruments( - OCPN_DBP_STC_ATMP, toUsrTemp_Plugin(m_airtemp, g_iDashTempUnit), - getUsrTempUnit_Plugin(g_iDashTempUnit)); + OCPN_DBP_STC_ATMP, toUsrTemp_Plugin(m_airtemp, g_iDashTempUnit), + getUsrTempUnit_Plugin(g_iDashTempUnit)); mPriATMP = 1; mATMP_Watchdog = no_nav_watchdog_timeout_ticks; } @@ -2522,7 +2525,6 @@ void dashboard_pi::HandleN2K_130313(ObservedEvt ev) { } } - /****** Signal K *******/ void dashboard_pi::ParseSignalK(wxString &msg) { wxJSONValue root; @@ -2542,7 +2544,6 @@ void dashboard_pi::ParseSignalK(wxString &msg) { else if (root["self"].AsString().Length()) m_self = _T("vessels.") + (root["self"].AsString()); // for Node.js server - } if (root.HasMember("context") && root["context"].IsString()) { @@ -2582,7 +2583,8 @@ void dashboard_pi::handleSKUpdate(wxJSONValue &update) { } } -void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &sfixtime) { +void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, + wxString &sfixtime) { if (item.HasMember("path") && item.HasMember("value")) { const wxString &update_path = item["path"].AsString(); wxJSONValue &value = item["value"]; @@ -2602,27 +2604,24 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mPriPosition = 2; } } - } - else if (update_path == _T("navigation.speedOverGround") && - 2 == mPriPosition) { + } else if (update_path == _T("navigation.speedOverGround") && + 2 == mPriPosition) { double sog_knot = GetJsonDouble(value); if (std::isnan(sog_knot)) return; SendSentenceToAllInstruments( - OCPN_DBP_STC_SOG, - toUsrSpeed_Plugin(mSOGFilter.filter(sog_knot), g_iDashSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); - } - else if (update_path == _T("navigation.courseOverGroundTrue") && - 2 == mPriPosition) { + OCPN_DBP_STC_SOG, + toUsrSpeed_Plugin(mSOGFilter.filter(sog_knot), g_iDashSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); + } else if (update_path == _T("navigation.courseOverGroundTrue") && + 2 == mPriPosition) { double cog_rad = GetJsonDouble(value); if (std::isnan(cog_rad)) return; double cog_deg = GEODESIC_RAD2DEG(cog_rad); SendSentenceToAllInstruments(OCPN_DBP_STC_COG, mCOGFilter.filter(cog_deg), _T("\u00B0")); - } - else if (update_path == _T("navigation.headingTrue")) { + } else if (update_path == _T("navigation.headingTrue")) { if (mPriHeadingT >= 2) { double hdt = GetJsonDouble(value); if (std::isnan(hdt)) return; @@ -2632,8 +2631,7 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mPriHeadingT = 2; mHDT_Watchdog = gps_watchdog_timeout_ticks; } - } - else if (update_path == _T("navigation.headingMagnetic")) { + } else if (update_path == _T("navigation.headingMagnetic")) { if (mPriHeadingM >= 2) { double hdm = GetJsonDouble(value); if (std::isnan(hdm)) return; @@ -2644,7 +2642,7 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mHDx_Watchdog = gps_watchdog_timeout_ticks; // If no higher priority HDT, calculate it here. - if (mPriHeadingT >= 6 && ( !std::isnan(mVar) )) { + if (mPriHeadingT >= 6 && (!std::isnan(mVar))) { double heading = hdm + mVar; if (heading < 0) heading += 360; @@ -2655,21 +2653,19 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mHDT_Watchdog = gps_watchdog_timeout_ticks; } } - } - else if (update_path == _T("navigation.speedThroughWater")) { + } else if (update_path == _T("navigation.speedThroughWater")) { if (mPriSTW >= 2) { double stw_knots = GetJsonDouble(value); if (std::isnan(stw_knots)) return; stw_knots = MS2KNOTS(stw_knots); SendSentenceToAllInstruments( - OCPN_DBP_STC_STW, toUsrSpeed_Plugin(stw_knots, g_iDashSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); + OCPN_DBP_STC_STW, toUsrSpeed_Plugin(stw_knots, g_iDashSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); mPriSTW = 2; mSTW_Watchdog = gps_watchdog_timeout_ticks; } - } - else if (update_path == _T("navigation.magneticVariation")) { + } else if (update_path == _T("navigation.magneticVariation")) { if (mPriVar >= 2) { double dvar = GetJsonDouble(value); if (std::isnan(dvar)) return; @@ -2681,8 +2677,7 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mVar_Watchdog = gps_watchdog_timeout_ticks; } } - } - else if (update_path == _T("environment.wind.angleApparent")) { + } else if (update_path == _T("environment.wind.angleApparent")) { if (mPriAWA >= 2) { double m_awaangle = GetJsonDouble(value); if (std::isnan(m_awaangle)) return; @@ -2698,19 +2693,18 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mPriAWA = 2; // Set prio only here. No need to catch speed if no angle. mMWVA_Watchdog = gps_watchdog_timeout_ticks; } - } - else if (update_path == _T("environment.wind.speedApparent")) { + } else if (update_path == _T("environment.wind.speedApparent")) { if (mPriAWA >= 2) { double m_awaspeed_kn = GetJsonDouble(value); if (std::isnan(m_awaspeed_kn)) return; m_awaspeed_kn = MS2KNOTS(m_awaspeed_kn); SendSentenceToAllInstruments( - OCPN_DBP_STC_AWS, - toUsrSpeed_Plugin(m_awaspeed_kn, g_iDashWindSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); + OCPN_DBP_STC_AWS, + toUsrSpeed_Plugin(m_awaspeed_kn, g_iDashWindSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); - // If no TWA from SK try to use AWS/AWA to calculate it + // If no TWA from SK try to use AWS/AWA to calculate it if (mPriTWA >= 6 && !std::isnan(skAWA)) { CalculateAndUpdateTWDS(m_awaspeed_kn, skAWA); mPriTWA = 6; @@ -2718,11 +2712,10 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s mWDN_Watchdog = no_nav_watchdog_timeout_ticks; } } - } - else if (( update_path == _T("environment.wind.angleTrueWater") && - !g_bDBtrueWindGround ) || - ( update_path == _T("environment.wind.angleTrueGround") && - g_bDBtrueWindGround )) { + } else if ((update_path == _T("environment.wind.angleTrueWater") && + !g_bDBtrueWindGround) || + (update_path == _T("environment.wind.angleTrueGround") && + g_bDBtrueWindGround)) { if (mPriTWA >= 3) { double m_twaangle = GetJsonDouble(value); if (std::isnan(m_twaangle)) return; @@ -2744,11 +2737,10 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s // If no TWD with higher priority is present and // true heading is available calculate it. if (g_dHDT < 361. && g_dHDT >= 0.0) { - double g_dCalWdir = (m_twaangle_raw)+g_dHDT; + double g_dCalWdir = (m_twaangle_raw) + g_dHDT; if (g_dCalWdir > 360.) { g_dCalWdir -= 360; - } - else if (g_dCalWdir < 0.) { + } else if (g_dCalWdir < 0.) { g_dCalWdir += 360; } SendSentenceToAllInstruments(OCPN_DBP_STC_TWD, g_dCalWdir, @@ -2758,27 +2750,25 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s } } } - } - else if (( update_path == _T("environment.wind.speedTrue") && - !g_bDBtrueWindGround ) || - ( update_path == _T("environment.wind.speedOverGround") && - g_bDBtrueWindGround )) { + } else if ((update_path == _T("environment.wind.speedTrue") && + !g_bDBtrueWindGround) || + (update_path == _T("environment.wind.speedOverGround") && + g_bDBtrueWindGround)) { if (mPriTWA >= 3) { double m_twaspeed_kn = GetJsonDouble(value); if (std::isnan(m_twaspeed_kn)) return; m_twaspeed_kn = MS2KNOTS(m_twaspeed_kn); SendSentenceToAllInstruments( - OCPN_DBP_STC_TWS, - toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); + OCPN_DBP_STC_TWS, + toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); SendSentenceToAllInstruments( - OCPN_DBP_STC_TWS2, - toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); + OCPN_DBP_STC_TWS2, + toUsrSpeed_Plugin(m_twaspeed_kn, g_iDashWindSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashWindSpeedUnit)); } - } - else if (update_path == _T("environment.depth.belowSurface")) { + } else if (update_path == _T("environment.depth.belowSurface")) { if (mPriDepth >= 3) { double depth = GetJsonDouble(value); if (std::isnan(depth)) return; @@ -2787,12 +2777,11 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s depth += g_dDashDBTOffset; depth /= 1852.0; SendSentenceToAllInstruments( - OCPN_DBP_STC_DPT, toUsrDistance_Plugin(depth, g_iDashDepthUnit), - getUsrDistanceUnit_Plugin(g_iDashDepthUnit)); + OCPN_DBP_STC_DPT, toUsrDistance_Plugin(depth, g_iDashDepthUnit), + getUsrDistanceUnit_Plugin(g_iDashDepthUnit)); mDPT_DBT_Watchdog = gps_watchdog_timeout_ticks; } - } - else if (update_path == _T("environment.depth.belowTransducer")) { + } else if (update_path == _T("environment.depth.belowTransducer")) { if (mPriDepth >= 3) { double depth = GetJsonDouble(value); if (std::isnan(depth)) return; @@ -2801,12 +2790,11 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s depth += g_dDashDBTOffset; depth /= 1852.0; SendSentenceToAllInstruments( - OCPN_DBP_STC_DPT, toUsrDistance_Plugin(depth, g_iDashDepthUnit), - getUsrDistanceUnit_Plugin(g_iDashDepthUnit)); + OCPN_DBP_STC_DPT, toUsrDistance_Plugin(depth, g_iDashDepthUnit), + getUsrDistanceUnit_Plugin(g_iDashDepthUnit)); mDPT_DBT_Watchdog = gps_watchdog_timeout_ticks; } - } - else if (update_path == _T("environment.water.temperature")) { + } else if (update_path == _T("environment.water.temperature")) { if (mPriWTP >= 2) { double m_wtemp = GetJsonDouble(value); if (std::isnan(m_wtemp)) return; @@ -2814,34 +2802,32 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s m_wtemp = KELVIN2C(m_wtemp); if (m_wtemp > -60 && m_wtemp < 200 && !std::isnan(m_wtemp)) { SendSentenceToAllInstruments( - OCPN_DBP_STC_TMP, toUsrTemp_Plugin(m_wtemp, g_iDashTempUnit), - getUsrTempUnit_Plugin(g_iDashTempUnit)); + OCPN_DBP_STC_TMP, toUsrTemp_Plugin(m_wtemp, g_iDashTempUnit), + getUsrTempUnit_Plugin(g_iDashTempUnit)); mPriWTP = 2; mWTP_Watchdog = no_nav_watchdog_timeout_ticks; } } - } - else if (update_path == - _T("navigation.courseRhumbline.nextPoint.velocityMadeGood")) { + } else if (update_path == + _T("navigation.courseRhumbline.nextPoint.velocityMadeGood")) { double m_vmg_kn = GetJsonDouble(value); if (std::isnan(m_vmg_kn)) return; m_vmg_kn = MS2KNOTS(m_vmg_kn); SendSentenceToAllInstruments( - OCPN_DBP_STC_VMG, toUsrSpeed_Plugin(m_vmg_kn, g_iDashSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); + OCPN_DBP_STC_VMG, toUsrSpeed_Plugin(m_vmg_kn, g_iDashSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); mVMG_Watchdog = gps_watchdog_timeout_ticks; } - else if (update_path == - _T("performance.velocityMadeGood")) { + else if (update_path == _T("performance.velocityMadeGood")) { double m_vmgw_kn = GetJsonDouble(value); if (std::isnan(m_vmgw_kn)) return; m_vmgw_kn = MS2KNOTS(m_vmgw_kn); SendSentenceToAllInstruments( - OCPN_DBP_STC_VMGW, toUsrSpeed_Plugin(m_vmgw_kn, g_iDashSpeedUnit), - getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); + OCPN_DBP_STC_VMGW, toUsrSpeed_Plugin(m_vmgw_kn, g_iDashSpeedUnit), + getUsrSpeedUnit_Plugin(g_iDashSpeedUnit)); mVMGW_Watchdog = gps_watchdog_timeout_ticks; } @@ -2851,27 +2837,27 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s if (std::isnan(m_rudangle)) return; m_rudangle = GEODESIC_RAD2DEG(m_rudangle); - SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, m_rudangle, _T("\u00B0")); + SendSentenceToAllInstruments(OCPN_DBP_STC_RSA, m_rudangle, + _T("\u00B0")); mRSA_Watchdog = gps_watchdog_timeout_ticks; mPriRSA = 2; } - } - else if (update_path == - _T("navigation.gnss.satellites")) { // GNSS satellites in use + } else if (update_path == + _T("navigation.gnss.satellites")) { // GNSS satellites in use if (mPriSatUsed >= 2) { - int usedSats = ( value ).AsInt(); - if (usedSats < 1 ) return; + int usedSats = (value).AsInt(); + if (usedSats < 1) return; SendSentenceToAllInstruments(OCPN_DBP_STC_SAT, usedSats, _T ("")); mPriSatUsed = 2; mSatsUsed_Wdog = gps_watchdog_timeout_ticks; } - } - else if (update_path == _T("navigation.gnss.type") ) { + } else if (update_path == _T("navigation.gnss.type")) { if (value.IsString() && value.AsString() != wxEmptyString) { - talkerID = (value.AsString()); //Like "Combined GPS/GLONASS" + talkerID = (value.AsString()); // Like "Combined GPS/GLONASS" talkerID.MakeUpper(); m_PriN2kTalker = gps_watchdog_timeout_ticks; - if (( talkerID.Contains(_T("GPS")) ) && ( talkerID.Contains(_T("GLONASS")) )) + if ((talkerID.Contains(_T("GPS"))) && + (talkerID.Contains(_T("GLONASS")))) talkerID = _T("GPSGLONAS"); else if (talkerID.Contains(_T("GPS"))) talkerID = _T("GP"); @@ -2882,11 +2868,10 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s else if (talkerID.Contains(_T("BEIDOU"))) talkerID = _T("GI"); } - } - else if (update_path == + } else if (update_path == _T("navigation.gnss.satellitesInView")) { // GNSS satellites in // view - if (mPriSatUsed >= 4 ) { + if (mPriSatUsed >= 4) { if (value.HasMember("count") && value["count"].IsInt()) { double m_SK_SatsInView = (value["count"].AsInt()); SendSentenceToAllInstruments(OCPN_DBP_STC_SAT, m_SK_SatsInView, @@ -2900,9 +2885,9 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s // Update satellites data. int iNumSats; if (value.HasMember("count") && value["count"].IsInt()) { - iNumSats = ( value["count"].AsInt() ); - } - else iNumSats = value[_T ("satellites")].Size(); + iNumSats = (value["count"].AsInt()); + } else + iNumSats = value[_T ("satellites")].Size(); SAT_INFO SK_SatInfo[4]; for (int idx = 0; idx < 4; idx++) { @@ -2923,14 +2908,14 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s for (int iMesNum = 0; iMesNum < 3; iMesNum++) { for (idx = 0; idx < 4; idx++) { arr = idx + 4 * iMesNum; - if (value["satellites"][arr]["id"].IsInt()) - iID = value["satellites"][arr]["id"].AsInt(); - if (value["satellites"][arr]["elevation"].IsDouble()) - dElevRad = value["satellites"][arr]["elevation"].AsDouble(); - if (value["satellites"][arr]["azimuth"].IsDouble()) - dAzimRad = value["satellites"][arr]["azimuth"].AsDouble(); - if (value["satellites"][arr]["SNR"].IsInt()) - iSNR = value["satellites"][arr]["SNR"].AsInt(); + if (value["satellites"][arr]["id"].IsInt()) + iID = value["satellites"][arr]["id"].AsInt(); + if (value["satellites"][arr]["elevation"].IsDouble()) + dElevRad = value["satellites"][arr]["elevation"].AsDouble(); + if (value["satellites"][arr]["azimuth"].IsDouble()) + dAzimRad = value["satellites"][arr]["azimuth"].AsDouble(); + if (value["satellites"][arr]["SNR"].IsInt()) + iSNR = value["satellites"][arr]["SNR"].AsInt(); if (iID < 1) break; SK_SatInfo[idx].SatNumber = iID; @@ -2940,11 +2925,13 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s } if (idx > 0) { if (m_PriN2kTalker <= 0 && talker != wxEmptyString && - (talker.StartsWith(_T("G")) || talker.StartsWith(_T("BD")))) { - talkerID = talker; //Origin NMEA0183 + (talker.StartsWith(_T("G")) || + talker.StartsWith(_T("BD")))) { + talkerID = talker; // Origin NMEA0183 } - SendSatInfoToAllInstruments(iNumSats, iMesNum + 1, talkerID, SK_SatInfo); - //mPriSatStatus = 2; + SendSatInfoToAllInstruments(iNumSats, iMesNum + 1, talkerID, + SK_SatInfo); + // mPriSatStatus = 2; mSatStatus_Wdog = gps_watchdog_timeout_ticks; } @@ -3019,8 +3006,7 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s m_twdM = (m_twdM) + mVar; if (m_twdM > 360.) { m_twdM -= 360; - } - else if (m_twdM < 0.) { + } else if (m_twdM < 0.) { m_twdM += 360; } } @@ -3086,7 +3072,6 @@ void dashboard_pi::updateSKItem(wxJSONValue &item, wxString &talker, wxString &s /*******Nav data from OCPN core *******/ void dashboard_pi::SetPositionFixEx(PlugIn_Position_Fix_Ex &pfix) { - if (mPriPosition >= 1) { mPriPosition = 1; SendSentenceToAllInstruments(OCPN_DBP_STC_LAT, pfix.Lat, _T("SDMM")); @@ -3143,8 +3128,10 @@ void dashboard_pi::SetPositionFixEx(PlugIn_Position_Fix_Ex &pfix) { double hdm = pfix.Hdm; if (std::isnan(hdm) && !std::isnan(pfix.Hdt) && !std::isnan(pfix.Var)) { hdm = pfix.Hdt - pfix.Var; - if (hdm < 0) hdm += 360; - else if (hdm >= 360.0) hdm -= 360; + if (hdm < 0) + hdm += 360; + else if (hdm >= 360.0) + hdm -= 360; } if (std::isnan(hdm)) return; SendSentenceToAllInstruments(OCPN_DBP_STC_HDM, hdm, _T("\u00B0M")); @@ -3394,7 +3381,6 @@ void dashboard_pi::OnToolbarToolCallback(int id) { SetToolbarItemState(m_toolbar_item_id, GetDashboardWindowShownCount() != 0 /*cnt==0*/); m_pauimgr->Update(); - } void dashboard_pi::UpdateAuiStatus(void) { @@ -3457,10 +3443,10 @@ bool dashboard_pi::LoadConfig(void) { double scaler = 1.0; wxFont DummyFont; - wxFont* pDF = &DummyFont; + wxFont *pDF = &DummyFont; if (OCPN_GetWinDIPScaleFactor() < 1.0) - scaler = 1.0 + OCPN_GetWinDIPScaleFactor()/4; + scaler = 1.0 + OCPN_GetWinDIPScaleFactor() / 4; scaler = wxMax(1.0, scaler); g_pFontTitle = &g_FontTitle; @@ -3472,7 +3458,7 @@ bool dashboard_pi::LoadConfig(void) { g_pUSFontTitle->SetColour(DummyColor); g_FontTitle = *g_pUSFontTitle; g_FontTitle.SetChosenFont(g_pUSFontTitle->GetChosenFont().Scaled(scaler)); - g_USFontTitle = *g_pUSFontTitle; + g_USFontTitle = *g_pUSFontTitle; g_pFontData = &g_FontData; pConf->Read(_T("FontData"), &config, DataFont); @@ -3491,13 +3477,13 @@ bool dashboard_pi::LoadConfig(void) { int alignment; pConf->Read(_T("TitleAlignment"), &alignment, (int)wxALIGN_LEFT); - g_TitleAlignment=(wxAlignment)alignment; - if ( g_TitleAlignment==wxALIGN_INVALID ) g_TitleAlignment=wxALIGN_LEFT; + g_TitleAlignment = (wxAlignment)alignment; + if (g_TitleAlignment == wxALIGN_INVALID) g_TitleAlignment = wxALIGN_LEFT; pConf->Read(_T("TitleMargin"), &g_iTitleMargin, 5); pConf->Read(_T("DataShowUnit"), &g_bShowUnit, true); pConf->Read(_T("DataAlignment"), &alignment, (int)wxALIGN_LEFT); - g_DataAlignment=(wxAlignment)alignment; - if ( g_DataAlignment==wxALIGN_INVALID ) g_DataAlignment=wxALIGN_LEFT; + g_DataAlignment = (wxAlignment)alignment; + if (g_DataAlignment == wxALIGN_INVALID) g_DataAlignment = wxALIGN_LEFT; pConf->Read(_T("DataMargin"), &g_iDataMargin, 10); pConf->Read(_T("InstrumentSpacing"), &g_iInstrumentSpacing, 0); pConf->Read(_T("TitleVerticalOffset"), &g_TitleVerticalOffset, 0.0); @@ -3606,80 +3592,101 @@ bool dashboard_pi::LoadConfig(void) { wxArrayInt ar; wxArrayOfInstrumentProperties Property; for (int i = 0; i < i_cnt; i++) { - int id; - pConf->Read(wxString::Format(_T("Instrument%d"), i + 1), &id, -1); - if (id != -1) - { - ar.Add(id); - InstrumentProperties* instp; - if (pConf->Exists(wxString::Format(_T("InstTitleFont%d"), i + 1))) - { - instp = new InstrumentProperties(id, i); - - pConf->Read(wxString::Format(_T("InstTitleFont%d"), i + 1), &config, TitleFont); - LoadFont(&pDF, config); - pConf->Read(wxString::Format(_T("InstTitleColor%d"), i + 1), &config, "#000000"); - DummyColor.Set(config); - instp->m_USTitleFont.SetChosenFont(DummyFont); - instp->m_USTitleFont.SetColour(DummyColor); - instp->m_TitleFont=instp->m_USTitleFont; - instp->m_TitleFont.SetChosenFont(instp->m_USTitleFont.GetChosenFont().Scaled(scaler)); - - pConf->Read(wxString::Format(_T("InstDataShowUnit%d"), i + 1), &instp->m_ShowUnit, -1); - pConf->Read(wxString::Format(_T("InstDataMargin%d"), i + 1), &instp->m_DataMargin, -1); - pConf->Read(wxString::Format(_T("InstDataAlignment%d"), i + 1), &alignment, (int)wxALIGN_INVALID); - instp->m_DataAlignment=(wxAlignment)alignment; - pConf->Read(wxString::Format(_T("InstInstrumentSpacing%d"), i + 1), &instp->m_InstrumentSpacing, -1); - pConf->Read(wxString::Format(_T("InstDataFormat%d"), i + 1), &instp->m_Format, ""); - pConf->Read(wxString::Format(_T("InstTitle%d"), i + 1), &instp->m_Title, ""); - - pConf->Read(wxString::Format(_T("InstDataFont%d"), i + 1), &config, DataFont); - LoadFont(&pDF, config); - pConf->Read(wxString::Format(_T("InstDataColor%d"), i + 1), &config, "#000000"); - DummyColor.Set(config); - instp->m_USDataFont.SetChosenFont(DummyFont); - instp->m_USDataFont.SetColour(DummyColor); - instp->m_DataFont=instp->m_USDataFont; - instp->m_DataFont.SetChosenFont(instp->m_USDataFont.GetChosenFont().Scaled(scaler)); - - pConf->Read(wxString::Format(_T("InstLabelFont%d"), i + 1), &config, LabelFont); - LoadFont(&pDF, config); - pConf->Read(wxString::Format(_T("InstLabelColor%d"), i + 1), &config, "#000000"); - DummyColor.Set(config); - instp->m_USLabelFont.SetChosenFont(DummyFont); - instp->m_USLabelFont.SetColour(DummyColor); - instp->m_LabelFont=instp->m_USLabelFont; - instp->m_LabelFont.SetChosenFont(instp->m_USLabelFont.GetChosenFont().Scaled(scaler)); - - pConf->Read(wxString::Format(_T("InstSmallFont%d"), i + 1), &config, SmallFont); - LoadFont(&pDF, config); - pConf->Read(wxString::Format(_T("InstSmallColor%d"), i + 1), &config, "#000000"); - DummyColor.Set(config); - instp->m_USSmallFont.SetChosenFont(DummyFont); - instp->m_USSmallFont.SetColour(DummyColor); - instp->m_SmallFont=instp->m_USSmallFont; - instp->m_SmallFont.SetChosenFont(instp->m_USSmallFont.GetChosenFont().Scaled(scaler)); - - pConf->Read(wxString::Format(_T("TitleBackColor%d"), i + 1), &config, "DASHL"); - instp->m_TitleBackgroundColour.Set(config); - - pConf->Read(wxString::Format(_T("DataBackColor%d"), i + 1), &config, "DASHB"); - instp->m_DataBackgroundColour.Set(config); - - pConf->Read(wxString::Format(_T("ArrowFirst%d"), i + 1), &config, "DASHN"); - instp->m_Arrow_First_Colour.Set(config); - - pConf->Read(wxString::Format(_T("ArrowSecond%d"), i + 1), &config, "BLUE3"); - instp->m_Arrow_Second_Colour.Set(config); - - Property.Add(instp); - } + int id; + pConf->Read(wxString::Format(_T("Instrument%d"), i + 1), &id, -1); + if (id != -1) { + ar.Add(id); + InstrumentProperties *instp; + if (pConf->Exists(wxString::Format(_T("InstTitleFont%d"), i + 1))) { + instp = new InstrumentProperties(id, i); + + pConf->Read(wxString::Format(_T("InstTitleFont%d"), i + 1), + &config, TitleFont); + LoadFont(&pDF, config); + pConf->Read(wxString::Format(_T("InstTitleColor%d"), i + 1), + &config, "#000000"); + DummyColor.Set(config); + instp->m_USTitleFont.SetChosenFont(DummyFont); + instp->m_USTitleFont.SetColour(DummyColor); + instp->m_TitleFont = instp->m_USTitleFont; + instp->m_TitleFont.SetChosenFont( + instp->m_USTitleFont.GetChosenFont().Scaled(scaler)); + + pConf->Read(wxString::Format(_T("InstDataShowUnit%d"), i + 1), + &instp->m_ShowUnit, -1); + pConf->Read(wxString::Format(_T("InstDataMargin%d"), i + 1), + &instp->m_DataMargin, -1); + pConf->Read(wxString::Format(_T("InstDataAlignment%d"), i + 1), + &alignment, (int)wxALIGN_INVALID); + instp->m_DataAlignment = (wxAlignment)alignment; + pConf->Read( + wxString::Format(_T("InstInstrumentSpacing%d"), i + 1), + &instp->m_InstrumentSpacing, -1); + pConf->Read(wxString::Format(_T("InstDataFormat%d"), i + 1), + &instp->m_Format, ""); + pConf->Read(wxString::Format(_T("InstTitle%d"), i + 1), + &instp->m_Title, ""); + + pConf->Read(wxString::Format(_T("InstDataFont%d"), i + 1), + &config, DataFont); + LoadFont(&pDF, config); + pConf->Read(wxString::Format(_T("InstDataColor%d"), i + 1), + &config, "#000000"); + DummyColor.Set(config); + instp->m_USDataFont.SetChosenFont(DummyFont); + instp->m_USDataFont.SetColour(DummyColor); + instp->m_DataFont = instp->m_USDataFont; + instp->m_DataFont.SetChosenFont( + instp->m_USDataFont.GetChosenFont().Scaled(scaler)); + + pConf->Read(wxString::Format(_T("InstLabelFont%d"), i + 1), + &config, LabelFont); + LoadFont(&pDF, config); + pConf->Read(wxString::Format(_T("InstLabelColor%d"), i + 1), + &config, "#000000"); + DummyColor.Set(config); + instp->m_USLabelFont.SetChosenFont(DummyFont); + instp->m_USLabelFont.SetColour(DummyColor); + instp->m_LabelFont = instp->m_USLabelFont; + instp->m_LabelFont.SetChosenFont( + instp->m_USLabelFont.GetChosenFont().Scaled(scaler)); + + pConf->Read(wxString::Format(_T("InstSmallFont%d"), i + 1), + &config, SmallFont); + LoadFont(&pDF, config); + pConf->Read(wxString::Format(_T("InstSmallColor%d"), i + 1), + &config, "#000000"); + DummyColor.Set(config); + instp->m_USSmallFont.SetChosenFont(DummyFont); + instp->m_USSmallFont.SetColour(DummyColor); + instp->m_SmallFont = instp->m_USSmallFont; + instp->m_SmallFont.SetChosenFont( + instp->m_USSmallFont.GetChosenFont().Scaled(scaler)); + + pConf->Read(wxString::Format(_T("TitleBackColor%d"), i + 1), + &config, "DASHL"); + instp->m_TitleBackgroundColour.Set(config); + + pConf->Read(wxString::Format(_T("DataBackColor%d"), i + 1), + &config, "DASHB"); + instp->m_DataBackgroundColour.Set(config); + + pConf->Read(wxString::Format(_T("ArrowFirst%d"), i + 1), &config, + "DASHN"); + instp->m_Arrow_First_Colour.Set(config); + + pConf->Read(wxString::Format(_T("ArrowSecond%d"), i + 1), &config, + "BLUE3"); + instp->m_Arrow_Second_Colour.Set(config); + + Property.Add(instp); } + } } // TODO: Do not add if GetCount == 0 - DashboardWindowContainer *cont = - new DashboardWindowContainer(NULL, name, caption, orient, ar, Property); + DashboardWindowContainer *cont = new DashboardWindowContainer( + NULL, name, caption, orient, ar, Property); cont->m_bPersVisible = b_persist; cont->m_conf_best_size = best_size; @@ -3717,14 +3724,22 @@ bool dashboard_pi::SaveConfig(void) { if (pConf) { pConf->SetPath(_T("/PlugIns/Dashboard")); pConf->Write(_T("Version"), _T("2")); - pConf->Write(_T("FontTitle"), g_pUSFontTitle->GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(_T("ColorTitle"), g_pUSFontTitle->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(_T("FontData"), g_pUSFontData->GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(_T("ColorData"), g_pUSFontData->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(_T("FontLabel"), g_pUSFontLabel->GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(_T("ColorLabel"), g_pUSFontLabel->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(_T("FontSmall"), g_pUSFontSmall->GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(_T("ColorSmall"), g_pUSFontSmall->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write(_T("FontTitle"), + g_pUSFontTitle->GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write(_T("ColorTitle"), + g_pUSFontTitle->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write(_T("FontData"), + g_pUSFontData->GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write(_T("ColorData"), + g_pUSFontData->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write(_T("FontLabel"), + g_pUSFontLabel->GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write(_T("ColorLabel"), + g_pUSFontLabel->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write(_T("FontSmall"), + g_pUSFontSmall->GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write(_T("ColorSmall"), + g_pUSFontSmall->GetColour().GetAsString(wxC2S_HTML_SYNTAX)); pConf->Write(_T("SpeedometerMax"), g_iDashSpeedMax); pConf->Write(_T("COGDamp"), g_iDashCOGDamp); pConf->Write(_T("SpeedUnit"), g_iDashSpeedUnit); @@ -3743,10 +3758,11 @@ bool dashboard_pi::SaveConfig(void) { (int)m_ArrayOfDashboardWindow.GetCount()); // Delete old Dashborads for (size_t i = m_ArrayOfDashboardWindow.GetCount(); i < 20; i++) { - if (pConf->Exists(wxString::Format(_T("/PlugIns/Dashboard/Dashboard%zu"), i + 1))) - { - pConf->DeleteGroup(wxString::Format(_T("/PlugIns/Dashboard/Dashboard%zu"), i + 1)); - } + if (pConf->Exists( + wxString::Format(_T("/PlugIns/Dashboard/Dashboard%zu"), i + 1))) { + pConf->DeleteGroup( + wxString::Format(_T("/PlugIns/Dashboard/Dashboard%zu"), i + 1)); + } } for (size_t i = 0; i < m_ArrayOfDashboardWindow.GetCount(); i++) { DashboardWindowContainer *cont = m_ArrayOfDashboardWindow.Item(i); @@ -3763,90 +3779,124 @@ bool dashboard_pi::SaveConfig(void) { // Delete old Instruments for (size_t i = cont->m_aInstrumentList.GetCount(); i < 40; i++) { - if (pConf->Exists(wxString::Format(_T("Instrument%zu"), i + 1))) - { - pConf->DeleteEntry(wxString::Format(_T("Instrument%zu"), i + 1)); - if (pConf->Exists(wxString::Format(_T("InstTitleFont%zu"), i + 1))) - { - pConf->DeleteEntry(wxString::Format(_T("InstTitleFont%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstTitleColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstTitle%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataShowUnit%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataMargin%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataAlignment%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataFormat%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataFont%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstLabelFont%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstLabelColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstSmallFont%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstSmallColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("TitleBackColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("DataBackColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("ArrowFirst%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("ArrowSecond%zu"), i + 1)); - } + if (pConf->Exists(wxString::Format(_T("Instrument%zu"), i + 1))) { + pConf->DeleteEntry(wxString::Format(_T("Instrument%zu"), i + 1)); + if (pConf->Exists(wxString::Format(_T("InstTitleFont%zu"), i + 1))) { + pConf->DeleteEntry(wxString::Format(_T("InstTitleFont%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstTitleColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstTitle%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataShowUnit%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataMargin%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataAlignment%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataFormat%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstDataFont%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstDataColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstLabelFont%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstLabelColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstSmallFont%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstSmallColor%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("TitleBackColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("DataBackColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("ArrowFirst%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("ArrowSecond%zu"), i + 1)); } + } } - for (size_t j = 0; j < cont->m_aInstrumentList.GetCount(); j++) - { - pConf->Write(wxString::Format(_T("Instrument%zu"), j + 1), cont->m_aInstrumentList.Item(j)); - InstrumentProperties* Inst = NULL; - // First delete - if (pConf->Exists(wxString::Format(_T("InstTitleFont%zu"), j + 1))) - { - bool Delete = true; - for (size_t i = 0; i < cont->m_aInstrumentPropertyList.GetCount(); i++) - { - Inst = cont->m_aInstrumentPropertyList.Item(i); - if (Inst->m_Listplace == (int)j) - { - Delete = false; - break; - } - } - if (Delete) - { - pConf->DeleteEntry(wxString::Format(_T("InstTitleFont%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstTitleColor%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstTitle%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataShowUnit%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataMargin%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataAlignment%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataFormat%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataFont%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstDataColor%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstLabelFont%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstLabelColor%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstSmallFont%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("InstSmallColor%zu"), j + 1)); - pConf->DeleteEntry(wxString::Format(_T("TitleBackColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("DataBackColor%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("ArrowFirst%zu"), i + 1)); - pConf->DeleteEntry(wxString::Format(_T("ArrowSecond%zu"), i + 1)); - } + for (size_t j = 0; j < cont->m_aInstrumentList.GetCount(); j++) { + pConf->Write(wxString::Format(_T("Instrument%zu"), j + 1), + cont->m_aInstrumentList.Item(j)); + InstrumentProperties *Inst = NULL; + // First delete + if (pConf->Exists(wxString::Format(_T("InstTitleFont%zu"), j + 1))) { + bool Delete = true; + for (size_t i = 0; i < cont->m_aInstrumentPropertyList.GetCount(); + i++) { + Inst = cont->m_aInstrumentPropertyList.Item(i); + if (Inst->m_Listplace == (int)j) { + Delete = false; + break; + } } - Inst = NULL; - for (size_t i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); i++) - { - Inst = cont->m_aInstrumentPropertyList.Item(i); - if (Inst->m_Listplace == (int)j) - { - pConf->Write(wxString::Format(_T("InstTitleFont%zu"), j + 1), Inst->m_USTitleFont.GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(wxString::Format(_T("InstTitleColor%zu"), j + 1), Inst->m_USTitleFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("InstDataFont%zu"), j + 1), Inst->m_USDataFont.GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(wxString::Format(_T("InstDataColor%zu"), j + 1), Inst->m_USDataFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("InstLabelFont%zu"), j + 1), Inst->m_USLabelFont.GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(wxString::Format(_T("InstLabelColor%zu"), j + 1), Inst->m_USLabelFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("InstSmallFont%zu"), j + 1), Inst->m_USSmallFont.GetChosenFont().GetNativeFontInfoDesc()); - pConf->Write(wxString::Format(_T("InstSmallColor%zu"), j + 1), Inst->m_USSmallFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("TitleBackColor%zu"), j + 1), Inst->m_TitleBackgroundColour.GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("DataBackColor%zu"), j + 1), Inst->m_DataBackgroundColour.GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("ArrowFirst%zu"), j + 1), Inst->m_Arrow_First_Colour.GetAsString(wxC2S_HTML_SYNTAX)); - pConf->Write(wxString::Format(_T("ArrowSecond%zu"), j + 1), Inst->m_Arrow_Second_Colour.GetAsString(wxC2S_HTML_SYNTAX)); - break; - } + if (Delete) { + pConf->DeleteEntry(wxString::Format(_T("InstTitleFont%zu"), j + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstTitleColor%zu"), j + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstTitle%zu"), j + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataShowUnit%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataMargin%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataAlignment%zu"), i + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstDataFormat%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstDataFont%zu"), j + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstDataColor%zu"), j + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstLabelFont%zu"), j + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstLabelColor%zu"), j + 1)); + pConf->DeleteEntry(wxString::Format(_T("InstSmallFont%zu"), j + 1)); + pConf->DeleteEntry( + wxString::Format(_T("InstSmallColor%zu"), j + 1)); + pConf->DeleteEntry( + wxString::Format(_T("TitleBackColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("DataBackColor%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("ArrowFirst%zu"), i + 1)); + pConf->DeleteEntry(wxString::Format(_T("ArrowSecond%zu"), i + 1)); } + } + Inst = NULL; + for (size_t i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); + i++) { + Inst = cont->m_aInstrumentPropertyList.Item(i); + if (Inst->m_Listplace == (int)j) { + pConf->Write( + wxString::Format(_T("InstTitleFont%zu"), j + 1), + Inst->m_USTitleFont.GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write( + wxString::Format(_T("InstTitleColor%zu"), j + 1), + Inst->m_USTitleFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("InstDataFont%zu"), j + 1), + Inst->m_USDataFont.GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write( + wxString::Format(_T("InstDataColor%zu"), j + 1), + Inst->m_USDataFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("InstLabelFont%zu"), j + 1), + Inst->m_USLabelFont.GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write( + wxString::Format(_T("InstLabelColor%zu"), j + 1), + Inst->m_USLabelFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("InstSmallFont%zu"), j + 1), + Inst->m_USSmallFont.GetChosenFont().GetNativeFontInfoDesc()); + pConf->Write( + wxString::Format(_T("InstSmallColor%zu"), j + 1), + Inst->m_USSmallFont.GetColour().GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("TitleBackColor%zu"), j + 1), + Inst->m_TitleBackgroundColour.GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("DataBackColor%zu"), j + 1), + Inst->m_DataBackgroundColour.GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("ArrowFirst%zu"), j + 1), + Inst->m_Arrow_First_Colour.GetAsString(wxC2S_HTML_SYNTAX)); + pConf->Write( + wxString::Format(_T("ArrowSecond%zu"), j + 1), + Inst->m_Arrow_Second_Colour.GetAsString(wxC2S_HTML_SYNTAX)); + break; + } + } } } return true; @@ -3873,12 +3923,12 @@ void dashboard_pi::ApplyConfig(void) { // A new dashboard is created cont->m_pDashboardWindow = new DashboardWindow( GetOCPNCanvasWindow(), wxID_ANY, m_pauimgr, this, orient, cont); - cont->m_pDashboardWindow->SetInstrumentList(cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); + cont->m_pDashboardWindow->SetInstrumentList( + cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); bool vertical = orient == wxVERTICAL; wxSize sz = cont->m_pDashboardWindow->GetMinSize(); wxSize best = cont->m_conf_best_size; - if (best.x < 100) - best = sz; + if (best.x < 100) best = sz; // Mac has a little trouble with initial Layout() sizing... #ifdef __WXOSX__ @@ -3918,7 +3968,8 @@ void dashboard_pi::ApplyConfig(void) { pane.Caption(cont->m_sCaption).Show(cont->m_bIsVisible); if (!cont->m_pDashboardWindow->isInstrumentListEqual( cont->m_aInstrumentList)) { - cont->m_pDashboardWindow->SetInstrumentList(cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); + cont->m_pDashboardWindow->SetInstrumentList( + cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); wxSize sz = cont->m_pDashboardWindow->GetMinSize(); pane.MinSize(sz).BestSize(sz).FloatingSize(sz); } @@ -3948,9 +3999,7 @@ void dashboard_pi::PopulateContextMenu(wxMenu *menu) { visItem = item; } } - if( nvis == 1 && visItem) - visItem->Enable(false); - + if (nvis == 1 && visItem) visItem->Enable(false); } void dashboard_pi::ShowDashboard(size_t id, bool visible) { @@ -4013,13 +4062,21 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( itemBoxSizerMainPanel->Add(itemBoxSizer2, 1, wxEXPAND); #endif - wxStdDialogButtonSizer *DialogButtonSizer = - CreateStdDialogButtonSizer(wxOK | wxCANCEL); - itemBoxSizerMainPanel->Add(DialogButtonSizer, 0, wxALIGN_RIGHT | wxALL, 5); + auto *DialogButtonSizer = new wxStdDialogButtonSizer(); + DialogButtonSizer->AddButton(new wxButton(this, wxID_OK)); + DialogButtonSizer->AddButton(new wxButton(this, wxID_CANCEL)); + wxButton *help_btn = new wxButton(this, wxID_HELP); + help_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](wxCommandEvent) { + wxString datadir = GetPluginDataDir("manual_pi"); + Manual(this, datadir.ToStdString()).Launch("Dashboard"); + }); + DialogButtonSizer->AddButton(help_btn); + DialogButtonSizer->Realize(); + itemBoxSizerMainPanel->Add(DialogButtonSizer, 0, wxALIGN_RIGHT | wxALL, 5); - wxNotebook *itemNotebook = new wxNotebook(dparent, wxID_ANY, wxDefaultPosition, - wxDefaultSize, wxNB_TOP); + wxNotebook *itemNotebook = new wxNotebook( + dparent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP); itemBoxSizer2->Add(itemNotebook, 0, wxALL | wxEXPAND, border_size); wxPanel *itemPanelNotebook01 = @@ -4080,19 +4137,15 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( #endif #ifdef ocpnUSE_SVG - bmPlus = GetBitmapFromSVGFile(shareLocn + _T("plus.svg"), bmSize, - bmSize); - bmMinus = GetBitmapFromSVGFile(shareLocn + _T("minus.svg"), bmSize, - bmSize); + bmPlus = GetBitmapFromSVGFile(shareLocn + _T("plus.svg"), bmSize, bmSize); + bmMinus = GetBitmapFromSVGFile(shareLocn + _T("minus.svg"), bmSize, bmSize); #else wxImage plus1 = wxBitmap(*_img_plus).ConvertToImage(); - wxImage plus1s = - plus1.Scale(bmSize, bmSize, wxIMAGE_QUALITY_HIGH); + wxImage plus1s = plus1.Scale(bmSize, bmSize, wxIMAGE_QUALITY_HIGH); bmPlus = wxBitmap(plus1s); wxImage minus1 = wxBitmap(*_img_minus).ConvertToImage(); - wxImage minus1s = - minus1.Scale(bmSize, bmSize, wxIMAGE_QUALITY_HIGH); + wxImage minus1s = minus1.Scale(bmSize, bmSize, wxIMAGE_QUALITY_HIGH); bmMinus = wxBitmap(minus1s); #endif @@ -4231,12 +4284,13 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( this); // TODO Instrument Properties ... done by Bernd Cirotzki - m_pButtonEdit = new wxButton( m_pPanelDashboard, wxID_ANY, _("Edit"), - wxDefaultPosition, wxDefaultSize ); itemBoxSizer04->Add( m_pButtonEdit, 0, - wxEXPAND | wxALL, border_size ); m_pButtonEdit->Connect( - wxEVT_COMMAND_BUTTON_CLICKED, - wxCommandEventHandler(DashboardPreferencesDialog::OnInstrumentEdit), - NULL, this ); + m_pButtonEdit = new wxButton(m_pPanelDashboard, wxID_ANY, _("Edit"), + wxDefaultPosition, wxDefaultSize); + itemBoxSizer04->Add(m_pButtonEdit, 0, wxEXPAND | wxALL, border_size); + m_pButtonEdit->Connect( + wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(DashboardPreferencesDialog::OnInstrumentEdit), NULL, + this); // m_pFontPickerTitle = // new wxFontPickerCtrl(m_pPanelDashboard, wxID_ANY, g_USFontTitle, @@ -4322,18 +4376,19 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( itemFlexGridSizer03->Add(m_pFontPickerSmall, 0, wxALIGN_RIGHT | wxALL, 0); // wxColourPickerCtrl - wxStaticText* itemStaticText80 = + wxStaticText *itemStaticText80 = new wxStaticText(itemPanelNotebook02, wxID_ANY, _("Reset:"), - wxDefaultPosition, wxDefaultSize, 0); + wxDefaultPosition, wxDefaultSize, 0); itemFlexGridSizer03->Add(itemStaticText80, 0, wxEXPAND | wxALL, border_size); - m_pButtondefaultFont = new wxButton(itemPanelNotebook02, wxID_ANY, _("Set dashboard default fonts"), - wxDefaultPosition, wxSize(-1, -1)); + m_pButtondefaultFont = new wxButton(itemPanelNotebook02, wxID_ANY, + _("Set dashboard default fonts"), + wxDefaultPosition, wxSize(-1, -1)); itemFlexGridSizer03->Add(m_pButtondefaultFont, 0, wxALIGN_RIGHT | wxALL, 0); m_pButtondefaultFont->Connect( wxEVT_COMMAND_BUTTON_CLICKED, - wxCommandEventHandler(DashboardPreferencesDialog::OnDashboarddefaultFont), NULL, - this); + wxCommandEventHandler(DashboardPreferencesDialog::OnDashboarddefaultFont), + NULL, this); wxStaticBox *itemStaticBox04 = new wxStaticBox(itemPanelNotebook02, wxID_ANY, _("Units, Ranges, Formats")); @@ -4512,13 +4567,12 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( m_pChoiceTempUnit->SetSelection(g_iDashTempUnit); itemFlexGridSizer04->Add(m_pChoiceTempUnit, 0, wxALIGN_RIGHT | wxALL, 0); - m_pUseTrueWinddata = new wxCheckBox( - itemPanelNotebook02, wxID_ANY, - _("Use N2K & SignalK true wind data over ground.\n(Instead of through water)")); + m_pUseTrueWinddata = new wxCheckBox(itemPanelNotebook02, wxID_ANY, + _("Use N2K & SignalK true wind data over " + "ground.\n(Instead of through water)")); m_pUseTrueWinddata->SetValue(g_bDBtrueWindGround); itemFlexGridSizer04->Add(m_pUseTrueWinddata, 1, wxALIGN_LEFT, border_size); - curSel = -1; for (size_t i = 0; i < m_Config.GetCount(); i++) { m_pListCtrlDashboards->InsertItem(i, 0); @@ -4534,7 +4588,7 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( UpdateDashboardButtonsState(); UpdateButtonsState(); - //SetMinSize(wxSize(400, -1)); + // SetMinSize(wxSize(400, -1)); Fit(); @@ -4542,22 +4596,20 @@ DashboardPreferencesDialog::DashboardPreferencesDialog( SetMaxSize(wxSize(display_width, display_height)); wxSize canvas_size = GetOCPNCanvasWindow()->GetSize(); - if(display_height < 600){ - if(g_dashPrefWidth > 0 && g_dashPrefHeight > 0) + if (display_height < 600) { + if (g_dashPrefWidth > 0 && g_dashPrefHeight > 0) SetSize(wxSize(g_dashPrefWidth, g_dashPrefHeight)); else - SetSize(wxSize(canvas_size.x * 8/10, canvas_size.y * 8 / 10)); - } - else { - if(g_dashPrefWidth > 0 && g_dashPrefHeight > 0) + SetSize(wxSize(canvas_size.x * 8 / 10, canvas_size.y * 8 / 10)); + } else { + if (g_dashPrefWidth > 0 && g_dashPrefHeight > 0) SetSize(wxSize(g_dashPrefWidth, g_dashPrefHeight)); else - SetSize(wxSize(canvas_size.x * 3 /4, canvas_size.y * 8 / 10)); + SetSize(wxSize(canvas_size.x * 3 / 4, canvas_size.y * 8 / 10)); } Layout(); CentreOnScreen(); - } void DashboardPreferencesDialog::RecalculateSize(void) { @@ -4672,44 +4724,47 @@ void DashboardPreferencesDialog::UpdateDashboardButtonsState() { // UpdateButtonsState(); } -void DashboardPreferencesDialog::OnDashboarddefaultFont(wxCommandEvent& event){ - - m_pFontPickerTitle->SetSelectedFont(wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL)); - m_pFontPickerTitle->SetSelectedColour(wxColour(0, 0, 0)); - m_pFontPickerData->SetSelectedFont(wxFont(14, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); - m_pFontPickerData->SetSelectedColour(wxColour(0, 0, 0)); - m_pFontPickerLabel->SetSelectedFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); - m_pFontPickerLabel->SetSelectedColour(wxColour(0, 0, 0)); - m_pFontPickerSmall->SetSelectedFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); - m_pFontPickerSmall->SetSelectedColour(wxColour(0, 0, 0)); - double scaler = 1.0; - if (OCPN_GetWinDIPScaleFactor() < 1.0) - scaler = 1.0 + OCPN_GetWinDIPScaleFactor() / 4; - scaler = wxMax(1.0, scaler); - - g_USFontTitle = *(m_pFontPickerTitle->GetFontData()); - g_FontTitle = *g_pUSFontTitle; - g_FontTitle.SetChosenFont(g_pUSFontTitle->GetChosenFont().Scaled(scaler)); - g_FontTitle.SetColour(g_pUSFontTitle->GetColour()); - g_USFontTitle = *g_pUSFontTitle; - - g_USFontData = *(m_pFontPickerData->GetFontData()); - g_FontData = *g_pUSFontData; - g_FontData.SetChosenFont(g_pUSFontData->GetChosenFont().Scaled(scaler)); - g_FontData.SetColour(g_pUSFontData->GetColour()); - g_USFontData = *g_pUSFontData; - - g_USFontLabel = *(m_pFontPickerLabel->GetFontData()); - g_FontLabel = *g_pUSFontLabel; - g_FontLabel.SetChosenFont(g_pUSFontLabel->GetChosenFont().Scaled(scaler)); - g_FontLabel.SetColour(g_pUSFontLabel->GetColour()); - g_USFontLabel = *g_pUSFontLabel; - - g_USFontSmall = *(m_pFontPickerSmall->GetFontData()); - g_FontSmall = *g_pUSFontSmall; - g_FontSmall.SetChosenFont(g_pUSFontSmall->GetChosenFont().Scaled(scaler)); - g_FontSmall.SetColour(g_pUSFontSmall->GetColour()); - g_USFontSmall = *g_pUSFontSmall; +void DashboardPreferencesDialog::OnDashboarddefaultFont(wxCommandEvent &event) { + m_pFontPickerTitle->SetSelectedFont( + wxFont(10, wxFONTFAMILY_SWISS, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL)); + m_pFontPickerTitle->SetSelectedColour(wxColour(0, 0, 0)); + m_pFontPickerData->SetSelectedFont( + wxFont(14, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + m_pFontPickerData->SetSelectedColour(wxColour(0, 0, 0)); + m_pFontPickerLabel->SetSelectedFont( + wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + m_pFontPickerLabel->SetSelectedColour(wxColour(0, 0, 0)); + m_pFontPickerSmall->SetSelectedFont( + wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + m_pFontPickerSmall->SetSelectedColour(wxColour(0, 0, 0)); + double scaler = 1.0; + if (OCPN_GetWinDIPScaleFactor() < 1.0) + scaler = 1.0 + OCPN_GetWinDIPScaleFactor() / 4; + scaler = wxMax(1.0, scaler); + + g_USFontTitle = *(m_pFontPickerTitle->GetFontData()); + g_FontTitle = *g_pUSFontTitle; + g_FontTitle.SetChosenFont(g_pUSFontTitle->GetChosenFont().Scaled(scaler)); + g_FontTitle.SetColour(g_pUSFontTitle->GetColour()); + g_USFontTitle = *g_pUSFontTitle; + + g_USFontData = *(m_pFontPickerData->GetFontData()); + g_FontData = *g_pUSFontData; + g_FontData.SetChosenFont(g_pUSFontData->GetChosenFont().Scaled(scaler)); + g_FontData.SetColour(g_pUSFontData->GetColour()); + g_USFontData = *g_pUSFontData; + + g_USFontLabel = *(m_pFontPickerLabel->GetFontData()); + g_FontLabel = *g_pUSFontLabel; + g_FontLabel.SetChosenFont(g_pUSFontLabel->GetChosenFont().Scaled(scaler)); + g_FontLabel.SetColour(g_pUSFontLabel->GetColour()); + g_USFontLabel = *g_pUSFontLabel; + + g_USFontSmall = *(m_pFontPickerSmall->GetFontData()); + g_FontSmall = *g_pUSFontSmall; + g_FontSmall.SetChosenFont(g_pUSFontSmall->GetChosenFont().Scaled(scaler)); + g_FontSmall.SetColour(g_pUSFontSmall->GetColour()); + g_USFontSmall = *g_pUSFontSmall; } void DashboardPreferencesDialog::OnDashboardAdd(wxCommandEvent &event) { @@ -4747,7 +4802,7 @@ void DashboardPreferencesDialog::UpdateButtonsState() { bool enable = (item != -1); m_pButtonDelete->Enable(enable); - m_pButtonEdit->Enable(enable); // TODO: Properties ... done Bernd Cirotzki + m_pButtonEdit->Enable(enable); // TODO: Properties ... done Bernd Cirotzki m_pButtonUp->Enable(item > 0); m_pButtonDown->Enable(item != -1 && item < m_pListCtrlInstruments->GetItemCount() - 1); @@ -4784,43 +4839,41 @@ void DashboardPreferencesDialog::OnInstrumentAdd(wxCommandEvent &event) { void DashboardPreferencesDialog::OnInstrumentDelete(wxCommandEvent &event) { long itemIDWindow = -1; - itemIDWindow = m_pListCtrlDashboards->GetNextItem(itemIDWindow, wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); + itemIDWindow = m_pListCtrlDashboards->GetNextItem( + itemIDWindow, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); long itemID = -1; itemID = m_pListCtrlInstruments->GetNextItem(itemID, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - DashboardWindowContainer* cont = m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); + DashboardWindowContainer *cont = + m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); InstrumentProperties *InstDel = NULL; - if (cont) - { - InstrumentProperties *Inst = NULL; - for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); i++) - { - Inst = cont->m_aInstrumentPropertyList.Item(i); - if (Inst->m_aInstrument == (int)m_pListCtrlInstruments->GetItemData(itemID) && - Inst->m_Listplace == itemID) - { - cont->m_aInstrumentPropertyList.Remove(Inst); - InstDel = Inst; - break; - } - else - { - if (Inst->m_Listplace > itemID) - Inst->m_Listplace--; - } + if (cont) { + InstrumentProperties *Inst = NULL; + for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); + i++) { + Inst = cont->m_aInstrumentPropertyList.Item(i); + if (Inst->m_aInstrument == + (int)m_pListCtrlInstruments->GetItemData(itemID) && + Inst->m_Listplace == itemID) { + cont->m_aInstrumentPropertyList.Remove(Inst); + InstDel = Inst; + break; + } else { + if (Inst->m_Listplace > itemID) Inst->m_Listplace--; } + } } m_pListCtrlInstruments->DeleteItem(itemID); - if (InstDel) - { - cont->m_pDashboardWindow->SetInstrumentList(cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); - delete InstDel; + if (InstDel) { + cont->m_pDashboardWindow->SetInstrumentList( + cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); + delete InstDel; } UpdateButtonsState(); } -inline void GetFontData(OCPNFontButton* FontButton, wxFontData &UnScaledFont, wxFontData &ScaledFont, double scaler) { +inline void GetFontData(OCPNFontButton *FontButton, wxFontData &UnScaledFont, + wxFontData &ScaledFont, double scaler) { UnScaledFont = *(FontButton->GetFontData()); ScaledFont = UnScaledFont; ScaledFont.SetChosenFont(UnScaledFont.GetChosenFont().Scaled(scaler)); @@ -4829,85 +4882,99 @@ inline void GetFontData(OCPNFontButton* FontButton, wxFontData &UnScaledFont, wx void DashboardPreferencesDialog::OnInstrumentEdit(wxCommandEvent &event) { // TODO: Instument options // m_Config = Arrayofdashboardwindows. - long itemIDWindow = -1; - itemIDWindow = m_pListCtrlDashboards->GetNextItem(itemIDWindow, wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - long itemID = -1; - itemID = m_pListCtrlInstruments->GetNextItem(itemID, wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - //m_Config. - // curSel = m_pListCtrlDashboards->GetItemData(itemWindow); - // DashboardWindowContainer *cont = m_Config.Item(curSel); - // if (cont) .... - DashboardWindowContainer* cont = m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); - if (!cont) return; - InstrumentProperties* Inst = NULL; - for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); i++) - { - Inst = cont->m_aInstrumentPropertyList.Item(i); // m_pListCtrlInstruments->GetItemData(itemID) - if (Inst->m_aInstrument == (int)m_pListCtrlInstruments->GetItemData(itemID)) // Is for right Instrumenttype. - { - if (Inst->m_Listplace == itemID) - break; - } - Inst = NULL; - } - if (!Inst) + long itemIDWindow = -1; + itemIDWindow = m_pListCtrlDashboards->GetNextItem( + itemIDWindow, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + long itemID = -1; + itemID = m_pListCtrlInstruments->GetNextItem(itemID, wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + // m_Config. + // curSel = m_pListCtrlDashboards->GetItemData(itemWindow); + // DashboardWindowContainer *cont = m_Config.Item(curSel); + // if (cont) .... + DashboardWindowContainer *cont = + m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); + if (!cont) return; + InstrumentProperties *Inst = NULL; + for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); + i++) { + Inst = cont->m_aInstrumentPropertyList.Item( + i); // m_pListCtrlInstruments->GetItemData(itemID) + if (Inst->m_aInstrument == (int)m_pListCtrlInstruments->GetItemData( + itemID)) // Is for right Instrumenttype. { - Inst = new InstrumentProperties(m_pListCtrlInstruments->GetItemData(itemID), itemID); - cont->m_aInstrumentPropertyList.Add(Inst); + if (Inst->m_Listplace == itemID) break; } - EditDialog *Edit = new EditDialog(this, *Inst, wxID_ANY); - Edit->Fit(); - bool DefaultFont = false; - if (Edit->ShowModal() == wxID_OK) { - DefaultFont = true; - double scaler = 1.0; - if (OCPN_GetWinDIPScaleFactor() < 1.0) - scaler = 1.0 + OCPN_GetWinDIPScaleFactor() / 4; - scaler = wxMax(1.0, scaler); - if (Edit->m_fontPicker2->GetFont().Scaled(scaler) != g_FontTitle.GetChosenFont() || Edit->m_fontPicker2->GetSelectedColour() != g_FontTitle.GetColour()) - DefaultFont = false; - if (Edit->m_fontPicker4->GetFont().Scaled(scaler) != g_FontData.GetChosenFont() || Edit->m_fontPicker4->GetSelectedColour() != g_FontData.GetColour()) - DefaultFont = false; - if (Edit->m_fontPicker5->GetFont().Scaled(scaler) != g_FontLabel.GetChosenFont() || Edit->m_fontPicker5->GetSelectedColour() != g_FontLabel.GetColour()) - DefaultFont = false; - if (Edit->m_fontPicker6->GetFont().Scaled(scaler) != g_FontSmall.GetChosenFont() || Edit->m_fontPicker6->GetSelectedColour() != g_FontSmall.GetColour()) - DefaultFont = false; - wxColour dummy; - GetGlobalColor(_T("DASHL"), &dummy); - if (Edit->m_colourPicker1->GetColour() != dummy) DefaultFont = false; - GetGlobalColor(_T("DASHB"), &dummy); - if (Edit->m_colourPicker2->GetColour() != dummy) DefaultFont = false; - GetGlobalColor(_T("DASHN"), &dummy); - if (Edit->m_colourPicker3->GetColour() != dummy) DefaultFont = false; - GetGlobalColor(_T("BLUE3"), &dummy); - if (Edit->m_colourPicker4->GetColour() != dummy) DefaultFont = false; - if (DefaultFont) - cont->m_aInstrumentPropertyList.Remove(Inst); - else - { - GetFontData(Edit->m_fontPicker2,Inst->m_USTitleFont,Inst->m_TitleFont,scaler); - GetFontData(Edit->m_fontPicker4,Inst->m_USDataFont,Inst->m_DataFont,scaler); - GetFontData(Edit->m_fontPicker5,Inst->m_USLabelFont,Inst->m_LabelFont,scaler); - GetFontData(Edit->m_fontPicker6,Inst->m_USSmallFont,Inst->m_SmallFont,scaler); - Inst->m_DataBackgroundColour = Edit->m_colourPicker2->GetColour(); - Inst->m_TitleBackgroundColour = Edit->m_colourPicker1->GetColour(); - Inst->m_Arrow_First_Colour = Edit->m_colourPicker3->GetColour(); - Inst->m_Arrow_Second_Colour = Edit->m_colourPicker4->GetColour(); - } - } - delete Edit; - if (cont->m_pDashboardWindow) { - cont->m_pDashboardWindow->SetInstrumentList(cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); + Inst = NULL; + } + if (!Inst) { + Inst = new InstrumentProperties(m_pListCtrlInstruments->GetItemData(itemID), + itemID); + cont->m_aInstrumentPropertyList.Add(Inst); + } + EditDialog *Edit = new EditDialog(this, *Inst, wxID_ANY); + Edit->Fit(); + bool DefaultFont = false; + if (Edit->ShowModal() == wxID_OK) { + DefaultFont = true; + double scaler = 1.0; + if (OCPN_GetWinDIPScaleFactor() < 1.0) + scaler = 1.0 + OCPN_GetWinDIPScaleFactor() / 4; + scaler = wxMax(1.0, scaler); + if (Edit->m_fontPicker2->GetFont().Scaled(scaler) != + g_FontTitle.GetChosenFont() || + Edit->m_fontPicker2->GetSelectedColour() != g_FontTitle.GetColour()) + DefaultFont = false; + if (Edit->m_fontPicker4->GetFont().Scaled(scaler) != + g_FontData.GetChosenFont() || + Edit->m_fontPicker4->GetSelectedColour() != g_FontData.GetColour()) + DefaultFont = false; + if (Edit->m_fontPicker5->GetFont().Scaled(scaler) != + g_FontLabel.GetChosenFont() || + Edit->m_fontPicker5->GetSelectedColour() != g_FontLabel.GetColour()) + DefaultFont = false; + if (Edit->m_fontPicker6->GetFont().Scaled(scaler) != + g_FontSmall.GetChosenFont() || + Edit->m_fontPicker6->GetSelectedColour() != g_FontSmall.GetColour()) + DefaultFont = false; + wxColour dummy; + GetGlobalColor(_T("DASHL"), &dummy); + if (Edit->m_colourPicker1->GetColour() != dummy) DefaultFont = false; + GetGlobalColor(_T("DASHB"), &dummy); + if (Edit->m_colourPicker2->GetColour() != dummy) DefaultFont = false; + GetGlobalColor(_T("DASHN"), &dummy); + if (Edit->m_colourPicker3->GetColour() != dummy) DefaultFont = false; + GetGlobalColor(_T("BLUE3"), &dummy); + if (Edit->m_colourPicker4->GetColour() != dummy) DefaultFont = false; + if (DefaultFont) + cont->m_aInstrumentPropertyList.Remove(Inst); + else { + GetFontData(Edit->m_fontPicker2, Inst->m_USTitleFont, Inst->m_TitleFont, + scaler); + GetFontData(Edit->m_fontPicker4, Inst->m_USDataFont, Inst->m_DataFont, + scaler); + GetFontData(Edit->m_fontPicker5, Inst->m_USLabelFont, Inst->m_LabelFont, + scaler); + GetFontData(Edit->m_fontPicker6, Inst->m_USSmallFont, Inst->m_SmallFont, + scaler); + Inst->m_DataBackgroundColour = Edit->m_colourPicker2->GetColour(); + Inst->m_TitleBackgroundColour = Edit->m_colourPicker1->GetColour(); + Inst->m_Arrow_First_Colour = Edit->m_colourPicker3->GetColour(); + Inst->m_Arrow_Second_Colour = Edit->m_colourPicker4->GetColour(); } - if (DefaultFont) delete Inst; + } + delete Edit; + if (cont->m_pDashboardWindow) { + cont->m_pDashboardWindow->SetInstrumentList( + cont->m_aInstrumentList, &(cont->m_aInstrumentPropertyList)); + } + if (DefaultFont) delete Inst; } void DashboardPreferencesDialog::OnInstrumentUp(wxCommandEvent &event) { long itemIDWindow = -1; - itemIDWindow = m_pListCtrlDashboards->GetNextItem(itemIDWindow, wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); + itemIDWindow = m_pListCtrlDashboards->GetNextItem( + itemIDWindow, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); long itemID = -1; itemID = m_pListCtrlInstruments->GetNextItem(itemID, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); @@ -4916,23 +4983,22 @@ void DashboardPreferencesDialog::OnInstrumentUp(wxCommandEvent &event) { item.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE | wxLIST_MASK_DATA); m_pListCtrlInstruments->GetItem(item); item.SetId(itemID - 1); - // item.SetImage(0); // image 0, by default + // item.SetImage(0); // image 0, by default // Now see if the Old itemId has an own Fontdata - DashboardWindowContainer* cont = m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); - if (cont) - { - InstrumentProperties* Inst = NULL; - for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); i++) - { - Inst = cont->m_aInstrumentPropertyList.Item(i); - if (Inst->m_Listplace == (itemID - 1)) - Inst->m_Listplace = itemID; - if (Inst->m_aInstrument == (int)m_pListCtrlInstruments->GetItemData(itemID) && - Inst->m_Listplace == itemID) - { - cont->m_aInstrumentPropertyList.Item(i)->m_Listplace = itemID - 1; - } + DashboardWindowContainer *cont = + m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); + if (cont) { + InstrumentProperties *Inst = NULL; + for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); + i++) { + Inst = cont->m_aInstrumentPropertyList.Item(i); + if (Inst->m_Listplace == (itemID - 1)) Inst->m_Listplace = itemID; + if (Inst->m_aInstrument == + (int)m_pListCtrlInstruments->GetItemData(itemID) && + Inst->m_Listplace == itemID) { + cont->m_aInstrumentPropertyList.Item(i)->m_Listplace = itemID - 1; } + } } m_pListCtrlInstruments->DeleteItem(itemID); m_pListCtrlInstruments->InsertItem(item); @@ -4947,8 +5013,8 @@ void DashboardPreferencesDialog::OnInstrumentUp(wxCommandEvent &event) { void DashboardPreferencesDialog::OnInstrumentDown(wxCommandEvent &event) { long itemIDWindow = -1; - itemIDWindow = m_pListCtrlDashboards->GetNextItem(itemIDWindow, wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); + itemIDWindow = m_pListCtrlDashboards->GetNextItem( + itemIDWindow, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); long itemID = -1; itemID = m_pListCtrlInstruments->GetNextItem(itemID, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); @@ -4958,24 +5024,26 @@ void DashboardPreferencesDialog::OnInstrumentDown(wxCommandEvent &event) { item.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE | wxLIST_MASK_DATA); m_pListCtrlInstruments->GetItem(item); item.SetId(itemID + 1); - // item.SetImage(0); // image 0, by default + // item.SetImage(0); // image 0, by default // Now see if the Old itemId has an own Fontdata - DashboardWindowContainer* cont = m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); - if (cont) - { - InstrumentProperties* Inst = NULL; - for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); i++) - { - Inst = cont->m_aInstrumentPropertyList.Item(i); - if (Inst->m_Listplace == (itemID + 1) && Inst->m_aInstrument != (int)m_pListCtrlInstruments->GetItemData(itemID)) - Inst->m_Listplace = itemID; - if (Inst->m_aInstrument == (int)m_pListCtrlInstruments->GetItemData(itemID) && - Inst->m_Listplace == itemID) - { - cont->m_aInstrumentPropertyList.Item(i)->m_Listplace = itemID + 1; - break; - } + DashboardWindowContainer *cont = + m_Config.Item(m_pListCtrlDashboards->GetItemData(itemIDWindow)); + if (cont) { + InstrumentProperties *Inst = NULL; + for (unsigned int i = 0; i < (cont->m_aInstrumentPropertyList.GetCount()); + i++) { + Inst = cont->m_aInstrumentPropertyList.Item(i); + if (Inst->m_Listplace == (itemID + 1) && + Inst->m_aInstrument != + (int)m_pListCtrlInstruments->GetItemData(itemID)) + Inst->m_Listplace = itemID; + if (Inst->m_aInstrument == + (int)m_pListCtrlInstruments->GetItemData(itemID) && + Inst->m_Listplace == itemID) { + cont->m_aInstrumentPropertyList.Item(i)->m_Listplace = itemID + 1; + break; } + } } m_pListCtrlInstruments->DeleteItem(itemID); m_pListCtrlInstruments->InsertItem(item); @@ -5090,7 +5158,7 @@ DashboardWindow::DashboardWindow(wxWindow *pparent, wxWindowID id, m_pauimgr = auimgr; m_plugin = plugin; m_Container = mycont; - + // wx2.9 itemBoxSizer = new wxWrapSizer( orient ); itemBoxSizer = new wxBoxSizer(orient); SetSizer(itemBoxSizer); @@ -5492,9 +5560,9 @@ void DashboardWindow::SetColorScheme(PI_ColorScheme cs) { DimeWindow(this); // Improve appearance, especially in DUSK or NIGHT palette - wxColour col=g_BackgroundColor; + wxColour col = g_BackgroundColor; - if ( !g_ForceBackgroundColor ) GetGlobalColor(_T("DASHL"), &col); + if (!g_ForceBackgroundColor) GetGlobalColor(_T("DASHL"), &col); SetBackgroundColour(col); Refresh(false); @@ -5561,7 +5629,8 @@ bool DashboardWindow::isInstrumentListEqual(const wxArrayInt &list) { return isArrayIntEqual(list, m_ArrayOfInstrument); } -void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProperties* InstrumentPropertyList) { +void DashboardWindow::SetInstrumentList( + wxArrayInt list, wxArrayOfInstrumentProperties *InstrumentPropertyList) { /* options ID_DBP_D_SOG: config max value, show STW optional ID_DBP_D_COG: +SOG +HDG? +BRG? @@ -5580,33 +5649,32 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp for (size_t i = 0; i < list.GetCount(); i++) { int id = list.Item(i); Properties = NULL; - for (size_t j = 0; j < InstrumentPropertyList->GetCount(); j++) - { - if (InstrumentPropertyList->Item(j)->m_aInstrument == id && InstrumentPropertyList->Item(j)->m_Listplace == (int)i) - { - Properties = InstrumentPropertyList->Item(j); - break; - } + for (size_t j = 0; j < InstrumentPropertyList->GetCount(); j++) { + if (InstrumentPropertyList->Item(j)->m_aInstrument == id && + InstrumentPropertyList->Item(j)->m_Listplace == (int)i) { + Properties = InstrumentPropertyList->Item(j); + break; + } } DashboardInstrument *instrument = NULL; switch (id) { case ID_DBP_I_POS: - instrument = new DashboardInstrument_Position(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_Position( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_I_SOG: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_SOG, - _T("%5.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_SOG, _T("%5.1f")); break; case ID_DBP_D_SOG: instrument = new DashboardInstrument_Speedometer( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_SOG, 0, - g_iDashSpeedMax); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_SOG, 0, g_iDashSpeedMax); ((DashboardInstrument_Dial *)instrument) ->SetOptionLabel(g_iDashSpeedMax / 20 + 1, DIAL_LABEL_HORIZONTAL); //(DashboardInstrument_Dial *)instrument->SetOptionMarker(0.1, - //DIAL_MARKER_SIMPLE, 5); + // DIAL_MARKER_SIMPLE, 5); ((DashboardInstrument_Dial *)instrument) ->SetOptionMarker(0.5, DIAL_MARKER_SIMPLE, 2); ((DashboardInstrument_Dial *)instrument) @@ -5629,17 +5697,18 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_COG: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_COG, - _T("%03.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_COG, _T("%03.0f")); break; case ID_DBP_M_COG: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_MCOG, - _T("%03.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_MCOG, _T("%03.0f")); break; case ID_DBP_D_COG: instrument = new DashboardInstrument_Compass( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_COG); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_COG); ((DashboardInstrument_Dial *)instrument) ->SetOptionMarker(5, DIAL_MARKER_SIMPLE, 2); ((DashboardInstrument_Dial *)instrument) @@ -5650,7 +5719,8 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_D_HDT: instrument = new DashboardInstrument_Compass( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_HDT); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_HDT); ((DashboardInstrument_Dial *)instrument) ->SetOptionMarker(5, DIAL_MARKER_SIMPLE, 2); ((DashboardInstrument_Dial *)instrument) @@ -5661,24 +5731,25 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_STW: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_STW, - _T("%.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_STW, _T("%.1f")); break; case ID_DBP_I_HDT: // true heading // TODO: Option True or Magnetic instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_HDT, - _T("%03.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_HDT, _T("%03.0f")); break; case ID_DBP_I_HDM: // magnetic heading instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_HDM, - _T("%03.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_HDM, _T("%03.0f")); break; case ID_DBP_D_AW: case ID_DBP_D_AWA: - instrument = new DashboardInstrument_Wind( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_AWA); + instrument = new DashboardInstrument_Wind(this, wxID_ANY, + getInstrumentCaption(id), + Properties, OCPN_DBP_STC_AWA); ((DashboardInstrument_Dial *)instrument) ->SetOptionMainValue(_T("%.0f"), DIAL_POSITION_BOTTOMLEFT); ((DashboardInstrument_Dial *)instrument) @@ -5687,12 +5758,13 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_AWS: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_AWS, - _T("%.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_AWS, _T("%.1f")); break; case ID_DBP_D_AWS: instrument = new DashboardInstrument_Speedometer( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_AWS, 0, 45); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_AWS, 0, 45); ((DashboardInstrument_Dial *)instrument) ->SetOptionLabel(5, DIAL_LABEL_HORIZONTAL); ((DashboardInstrument_Dial *)instrument) @@ -5705,7 +5777,8 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_D_TW: // True Wind angle +-180 degr on boat axis instrument = new DashboardInstrument_TrueWindAngle( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_TWA); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_TWA); ((DashboardInstrument_Dial *)instrument) ->SetOptionMainValue(_T("%.0f"), DIAL_POSITION_BOTTOMLEFT); ((DashboardInstrument_Dial *)instrument) @@ -5714,7 +5787,8 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_D_AWA_TWA: // App/True Wind angle +-180 degr on boat axis instrument = new DashboardInstrument_AppTrueWindAngle( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_AWA); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_AWA); ((DashboardInstrument_Dial *)instrument)->SetCapFlag(OCPN_DBP_STC_TWA); ((DashboardInstrument_Dial *)instrument) ->SetOptionMainValue(_T("%.0f"), DIAL_POSITION_NONE); @@ -5727,7 +5801,8 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_D_TWD: // True Wind direction instrument = new DashboardInstrument_WindCompass( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_TWD); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_TWD); ((DashboardInstrument_Dial *)instrument) ->SetOptionMainValue(_T("%.0f"), DIAL_POSITION_BOTTOMLEFT); ((DashboardInstrument_Dial *)instrument) @@ -5736,36 +5811,36 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_ALTI: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_ALTI, - _T("%6.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_ALTI, _T("%6.1f")); break; case ID_DBP_D_ALTI: - instrument = new DashboardInstrument_Altitude(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_Altitude( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_I_DPT: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_DPT, - _T("%5.2f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_DPT, _T("%5.2f")); break; case ID_DBP_D_DPT: - instrument = new DashboardInstrument_Depth(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_Depth( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_I_TMP: // water temperature instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_TMP, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_TMP, _T("%2.1f")); break; case ID_DBP_I_MDA: // barometric pressure instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_MDA, - _T("%5.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_MDA, _T("%5.1f")); break; case ID_DBP_D_MDA: // barometric pressure instrument = new DashboardInstrument_Speedometer( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_MDA, 938, - 1088); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_MDA, 938, 1088); ((DashboardInstrument_Dial *)instrument) ->SetOptionLabel(15, DIAL_LABEL_HORIZONTAL); ((DashboardInstrument_Dial *)instrument) @@ -5775,55 +5850,55 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_ATMP: // air temperature instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_ATMP, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_ATMP, _T("%2.1f")); break; case ID_DBP_I_VLW1: // Trip Log instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_VLW1, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_VLW1, _T("%2.1f")); break; case ID_DBP_I_VLW2: // Sum Log instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_VLW2, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_VLW2, _T("%2.1f")); break; case ID_DBP_I_TWA: // true wind angle instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_TWA, - _T("%5.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_TWA, _T("%5.0f")); break; case ID_DBP_I_TWD: // true wind direction instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_TWD, - _T("%3.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_TWD, _T("%3.0f")); break; case ID_DBP_I_TWS: // true wind speed instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_TWS, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_TWS, _T("%2.1f")); break; case ID_DBP_I_AWA: // apparent wind angle instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_AWA, - _T("%3.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_AWA, _T("%3.0f")); break; - case ID_DBP_I_VMGW: // VMG based on wind and STW + case ID_DBP_I_VMGW: // VMG based on wind and STW instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_VMGW, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_VMGW, _T("%2.1f")); break; case ID_DBP_I_VMG: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_VMG, - _T("%5.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_VMG, _T("%5.1f")); break; case ID_DBP_D_VMG: instrument = new DashboardInstrument_Speedometer( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_VMG, 0, - g_iDashSpeedMax); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_VMG, 0, g_iDashSpeedMax); ((DashboardInstrument_Dial *)instrument) ->SetOptionLabel(1, DIAL_LABEL_HORIZONTAL); ((DashboardInstrument_Dial *)instrument) @@ -5834,8 +5909,8 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_RSA: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_RSA, - _T("%5.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_RSA, _T("%5.0f")); break; case ID_DBP_D_RSA: instrument = new DashboardInstrument_RudderAngle( @@ -5843,29 +5918,29 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_SAT: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_SAT, - _T("%5.0f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_SAT, _T("%5.0f")); break; case ID_DBP_D_GPS: - instrument = new DashboardInstrument_GPS(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_GPS( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_I_PTR: instrument = new DashboardInstrument_Position( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_PLA, - OCPN_DBP_STC_PLO); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_PLA, OCPN_DBP_STC_PLO); break; case ID_DBP_I_GPSUTC: - instrument = new DashboardInstrument_Clock(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_Clock( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_I_SUN: - instrument = new DashboardInstrument_Sun(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_Sun( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_D_MON: - instrument = new DashboardInstrument_Moon(this, wxID_ANY, - getInstrumentCaption(id), Properties); + instrument = new DashboardInstrument_Moon( + this, wxID_ANY, getInstrumentCaption(id), Properties); break; case ID_DBP_D_WDH: instrument = new DashboardInstrument_WindDirHistory( @@ -5881,25 +5956,25 @@ void DashboardWindow::SetInstrumentList(wxArrayInt list, wxArrayOfInstrumentProp break; case ID_DBP_I_PITCH: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_PITCH, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_PITCH, _T("%2.1f")); break; case ID_DBP_I_HEEL: instrument = new DashboardInstrument_Single( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_HEEL, - _T("%2.1f")); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_HEEL, _T("%2.1f")); break; // any clock display with "LCL" in the format string is converted from // UTC to local TZ case ID_DBP_I_SUNLCL: - instrument = new DashboardInstrument_Sun(this, wxID_ANY, - getInstrumentCaption(id), Properties, - _T( "%02i:%02i:%02i LCL" )); + instrument = new DashboardInstrument_Sun( + this, wxID_ANY, getInstrumentCaption(id), Properties, + _T( "%02i:%02i:%02i LCL" )); break; case ID_DBP_I_GPSLCL: instrument = new DashboardInstrument_Clock( - this, wxID_ANY, getInstrumentCaption(id), Properties, OCPN_DBP_STC_CLK, - _T( "%02i:%02i:%02i LCL" )); + this, wxID_ANY, getInstrumentCaption(id), Properties, + OCPN_DBP_STC_CLK, _T( "%02i:%02i:%02i LCL" )); break; case ID_DBP_I_CPULCL: instrument = new DashboardInstrument_CPUClock( @@ -5977,9 +6052,9 @@ void DashboardWindow::SendUtcTimeToAllInstruments(wxDateTime value) { } } -//#include "wx/fontpicker.h" +// #include "wx/fontpicker.h" -//#include "wx/fontdlg.h" +// #include "wx/fontdlg.h" // ============================================================================ // implementation @@ -6012,7 +6087,8 @@ bool OCPNFontButton::Create(wxWindow *parent, wxWindowID id, wxCommandEventHandler(OCPNFontButton::OnButtonClick), NULL, this); m_data = initial; - m_selectedFont = initial.GetChosenFont().IsOk() ? initial.GetChosenFont() : *wxNORMAL_FONT; + m_selectedFont = + initial.GetChosenFont().IsOk() ? initial.GetChosenFont() : *wxNORMAL_FONT; UpdateFont(); return true; @@ -6038,22 +6114,21 @@ void OCPNFontButton::OnButtonClick(wxCommandEvent &WXUNUSED(ev)) { GetEventHandler()->ProcessEvent(event); UpdateFont(); } - } - else { + } else { // create the font dialog and display it wxFontDialog dlg(this, m_data); dlg.SetFont(*pF); if (dlg.ShowModal() == wxID_OK) { m_data = dlg.GetFontData(); m_selectedFont = m_data.GetChosenFont(); - // fire an event + // fire an event wxFontPickerEvent event(this, GetId(), m_selectedFont); GetEventHandler()->ProcessEvent(event); UpdateFont(); } } -#else // Not __GTK__ +#else // Not __GTK__ // create the font dialog and display it wxFontDialog dlg(this, m_data); dlg.SetFont(*pF); @@ -6110,7 +6185,7 @@ void OCPNFontButton::UpdateFont() { } auto minsize = GetTextExtent(label); - SetSize(minsize); + SetSize(minsize); GetParent()->Layout(); GetParent()->Fit(); @@ -6118,145 +6193,170 @@ void OCPNFontButton::UpdateFont() { // Edit Dialog -EditDialog::EditDialog(wxWindow* parent, InstrumentProperties& Properties, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) -{ - this->SetSizeHints(wxDefaultSize, wxDefaultSize); - - wxBoxSizer* bSizer5; - bSizer5 = new wxBoxSizer(wxVERTICAL); - - wxFlexGridSizer* fgSizer2; - fgSizer2 = new wxFlexGridSizer(0, 2, 0, 0); - fgSizer2->SetFlexibleDirection(wxBOTH); - fgSizer2->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); - - m_staticText1 = new wxStaticText(this, wxID_ANY, _("Title:"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText1->Wrap(-1); - fgSizer2->Add(m_staticText1, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - - m_fontPicker2 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USTitleFont, wxDefaultPosition, wxDefaultSize); - fgSizer2->Add(m_fontPicker2, 0, wxALL, 5); - - m_staticText5 = new wxStaticText(this, wxID_ANY, _("Title background color:"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText5->Wrap(-1); - fgSizer2->Add(m_staticText5, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - - m_colourPicker1 = new wxColourPickerCtrl(this, wxID_ANY, Properties.m_TitleBackgroundColour, wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE); - fgSizer2->Add(m_colourPicker1, 0, wxALL, 5); +EditDialog::EditDialog(wxWindow *parent, InstrumentProperties &Properties, + wxWindowID id, const wxString &title, const wxPoint &pos, + const wxSize &size, long style) + : wxDialog(parent, id, title, pos, size, style) { + this->SetSizeHints(wxDefaultSize, wxDefaultSize); + + wxBoxSizer *bSizer5; + bSizer5 = new wxBoxSizer(wxVERTICAL); + + wxFlexGridSizer *fgSizer2; + fgSizer2 = new wxFlexGridSizer(0, 2, 0, 0); + fgSizer2->SetFlexibleDirection(wxBOTH); + fgSizer2->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + m_staticText1 = new wxStaticText(this, wxID_ANY, _("Title:"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText1->Wrap(-1); + fgSizer2->Add(m_staticText1, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + + m_fontPicker2 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USTitleFont, + wxDefaultPosition, wxDefaultSize); + fgSizer2->Add(m_fontPicker2, 0, wxALL, 5); + + m_staticText5 = new wxStaticText(this, wxID_ANY, _("Title background color:"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText5->Wrap(-1); + fgSizer2->Add(m_staticText5, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - m_staticText2 = new wxStaticText(this, wxID_ANY, _("Data:"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText2->Wrap(-1); - fgSizer2->Add(m_staticText2, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_colourPicker1 = new wxColourPickerCtrl( + this, wxID_ANY, Properties.m_TitleBackgroundColour, wxDefaultPosition, + wxDefaultSize, wxCLRP_DEFAULT_STYLE); + fgSizer2->Add(m_colourPicker1, 0, wxALL, 5); - m_fontPicker4 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USDataFont, wxDefaultPosition, wxDefaultSize); - fgSizer2->Add(m_fontPicker4, 0, wxALL, 5); + m_staticText2 = new wxStaticText(this, wxID_ANY, _("Data:"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText2->Wrap(-1); + fgSizer2->Add(m_staticText2, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - m_staticText6 = new wxStaticText(this, wxID_ANY, _("Data background color:"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText6->Wrap(-1); - fgSizer2->Add(m_staticText6, 0, wxALL, 5); + m_fontPicker4 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USDataFont, + wxDefaultPosition, wxDefaultSize); + fgSizer2->Add(m_fontPicker4, 0, wxALL, 5); - m_colourPicker2 = new wxColourPickerCtrl(this, wxID_ANY, Properties.m_DataBackgroundColour, wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE); - fgSizer2->Add(m_colourPicker2, 0, wxALL, 5); + m_staticText6 = new wxStaticText(this, wxID_ANY, _("Data background color:"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText6->Wrap(-1); + fgSizer2->Add(m_staticText6, 0, wxALL, 5); - m_staticText3 = new wxStaticText(this, wxID_ANY, _("Label:"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText3->Wrap(-1); - fgSizer2->Add(m_staticText3, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_colourPicker2 = new wxColourPickerCtrl( + this, wxID_ANY, Properties.m_DataBackgroundColour, wxDefaultPosition, + wxDefaultSize, wxCLRP_DEFAULT_STYLE); + fgSizer2->Add(m_colourPicker2, 0, wxALL, 5); - m_fontPicker5 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USLabelFont, wxDefaultPosition, wxDefaultSize); - fgSizer2->Add(m_fontPicker5, 0, wxALL, 5); + m_staticText3 = new wxStaticText(this, wxID_ANY, _("Label:"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText3->Wrap(-1); + fgSizer2->Add(m_staticText3, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - m_staticText4 = new wxStaticText(this, wxID_ANY, _("Small:"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText4->Wrap(-1); - fgSizer2->Add(m_staticText4, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_fontPicker5 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USLabelFont, + wxDefaultPosition, wxDefaultSize); + fgSizer2->Add(m_fontPicker5, 0, wxALL, 5); - m_fontPicker6 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USSmallFont, wxDefaultPosition, wxDefaultSize); - fgSizer2->Add(m_fontPicker6, 0, wxALL, 5); + m_staticText4 = new wxStaticText(this, wxID_ANY, _("Small:"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText4->Wrap(-1); + fgSizer2->Add(m_staticText4, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - m_staticText9 = new wxStaticText(this, wxID_ANY, _("Arrow 1 Colour :"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText9->Wrap(-1); - fgSizer2->Add(m_staticText9, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_fontPicker6 = new wxFontPickerCtrl(this, wxID_ANY, Properties.m_USSmallFont, + wxDefaultPosition, wxDefaultSize); + fgSizer2->Add(m_fontPicker6, 0, wxALL, 5); - m_colourPicker3 = new wxColourPickerCtrl(this, wxID_ANY, Properties.m_Arrow_First_Colour, wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE); - fgSizer2->Add(m_colourPicker3, 0, wxALL, 5); + m_staticText9 = new wxStaticText(this, wxID_ANY, _("Arrow 1 Colour :"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText9->Wrap(-1); + fgSizer2->Add(m_staticText9, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - m_staticText10 = new wxStaticText(this, wxID_ANY, _("Arrow 2 Colour :"), wxDefaultPosition, wxDefaultSize, 0); - m_staticText10->Wrap(-1); - fgSizer2->Add(m_staticText10, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_colourPicker3 = new wxColourPickerCtrl( + this, wxID_ANY, Properties.m_Arrow_First_Colour, wxDefaultPosition, + wxDefaultSize, wxCLRP_DEFAULT_STYLE); + fgSizer2->Add(m_colourPicker3, 0, wxALL, 5); - m_colourPicker4 = new wxColourPickerCtrl(this, wxID_ANY, Properties.m_Arrow_Second_Colour, wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE); - fgSizer2->Add(m_colourPicker4, 0, wxALL, 5); + m_staticText10 = new wxStaticText(this, wxID_ANY, _("Arrow 2 Colour :"), + wxDefaultPosition, wxDefaultSize, 0); + m_staticText10->Wrap(-1); + fgSizer2->Add(m_staticText10, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - m_staticline1 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL); - fgSizer2->Add(m_staticline1, 0, wxEXPAND | wxALL, 5); + m_colourPicker4 = new wxColourPickerCtrl( + this, wxID_ANY, Properties.m_Arrow_Second_Colour, wxDefaultPosition, + wxDefaultSize, wxCLRP_DEFAULT_STYLE); + fgSizer2->Add(m_colourPicker4, 0, wxALL, 5); - m_staticline2 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL); - fgSizer2->Add(m_staticline2, 0, wxEXPAND | wxALL, 5); + m_staticline1 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, + wxDefaultSize, wxLI_HORIZONTAL); + fgSizer2->Add(m_staticline1, 0, wxEXPAND | wxALL, 5); - fgSizer2->Add(0, 5, 1, wxEXPAND, 5); + m_staticline2 = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, + wxDefaultSize, wxLI_HORIZONTAL); + fgSizer2->Add(m_staticline2, 0, wxEXPAND | wxALL, 5); - fgSizer2->Add(0, 0, 1, wxEXPAND, 5); + fgSizer2->Add(0, 5, 1, wxEXPAND, 5); - m_staticText7 = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); - m_staticText7->Wrap(-1); - fgSizer2->Add(m_staticText7, 0, wxALL, 5); + fgSizer2->Add(0, 0, 1, wxEXPAND, 5); + + m_staticText7 = new wxStaticText(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, 0); + m_staticText7->Wrap(-1); + fgSizer2->Add(m_staticText7, 0, wxALL, 5); - m_button1 = new wxButton(this, wxID_ANY, _("Set default"), wxDefaultPosition, wxDefaultSize, 0); - fgSizer2->Add(m_button1, 0, wxALL, 5); + m_button1 = new wxButton(this, wxID_ANY, _("Set default"), wxDefaultPosition, + wxDefaultSize, 0); + fgSizer2->Add(m_button1, 0, wxALL, 5); - fgSizer2->Add(0, 5, 1, wxEXPAND, 5); + fgSizer2->Add(0, 5, 1, wxEXPAND, 5); - fgSizer2->Add(5, 0, 1, wxEXPAND, 5); + fgSizer2->Add(5, 0, 1, wxEXPAND, 5); - bSizer5->Add(fgSizer2, 1, wxALL | wxEXPAND, 5); + bSizer5->Add(fgSizer2, 1, wxALL | wxEXPAND, 5); - m_sdbSizer3 = new wxStdDialogButtonSizer(); - m_sdbSizer3OK = new wxButton(this, wxID_OK); - m_sdbSizer3->AddButton(m_sdbSizer3OK); - m_sdbSizer3Cancel = new wxButton(this, wxID_CANCEL); - m_sdbSizer3->AddButton(m_sdbSizer3Cancel); - m_sdbSizer3->Realize(); + m_sdbSizer3 = new wxStdDialogButtonSizer(); + m_sdbSizer3OK = new wxButton(this, wxID_OK); + m_sdbSizer3->AddButton(m_sdbSizer3OK); + m_sdbSizer3Cancel = new wxButton(this, wxID_CANCEL); + m_sdbSizer3->AddButton(m_sdbSizer3Cancel); + m_sdbSizer3->Realize(); - bSizer5->Add(m_sdbSizer3, 0, 0, 1); + bSizer5->Add(m_sdbSizer3, 0, 0, 1); + bSizer5->Add(0, 10, 0, wxEXPAND, 5); - bSizer5->Add(0, 10, 0, wxEXPAND, 5); + this->SetSizer(bSizer5); + this->Layout(); + bSizer5->Fit(this); + this->Centre(wxBOTH); - this->SetSizer(bSizer5); - this->Layout(); - bSizer5->Fit(this); - - this->Centre(wxBOTH); - - // Connect Events - m_button1->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(EditDialog::OnSetdefault), NULL, this); + // Connect Events + m_button1->Connect(wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(EditDialog::OnSetdefault), NULL, + this); } -EditDialog::~EditDialog() -{ - // Disconnect Events - m_button1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(EditDialog::OnSetdefault), NULL, this); +EditDialog::~EditDialog() { + // Disconnect Events + m_button1->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(EditDialog::OnSetdefault), NULL, + this); } -void EditDialog::OnSetdefault(wxCommandEvent& event) -{ - m_fontPicker2->SetSelectedFont(g_USFontTitle.GetChosenFont()); - m_fontPicker2->SetSelectedColour(g_USFontTitle.GetColour()); - m_fontPicker4->SetSelectedFont(g_USFontData.GetChosenFont()); - m_fontPicker4->SetSelectedColour(g_USFontData.GetColour()); - m_fontPicker5->SetSelectedFont(g_USFontLabel.GetChosenFont()); - m_fontPicker5->SetSelectedColour(g_USFontLabel.GetColour()); - m_fontPicker6->SetSelectedFont(g_USFontSmall.GetChosenFont()); - m_fontPicker6->SetSelectedColour(g_USFontSmall.GetColour()); - wxColour dummy; - GetGlobalColor(_T("DASHL"), &dummy); - m_colourPicker1->SetColour(dummy); - GetGlobalColor(_T("DASHB"), &dummy); - m_colourPicker2->SetColour(dummy); - GetGlobalColor(_T("DASHN"), &dummy); - m_colourPicker3->SetColour(dummy); - GetGlobalColor(_T("BLUE3"), &dummy); - m_colourPicker4->SetColour(dummy); - Update(); +void EditDialog::OnSetdefault(wxCommandEvent &event) { + m_fontPicker2->SetSelectedFont(g_USFontTitle.GetChosenFont()); + m_fontPicker2->SetSelectedColour(g_USFontTitle.GetColour()); + m_fontPicker4->SetSelectedFont(g_USFontData.GetChosenFont()); + m_fontPicker4->SetSelectedColour(g_USFontData.GetColour()); + m_fontPicker5->SetSelectedFont(g_USFontLabel.GetChosenFont()); + m_fontPicker5->SetSelectedColour(g_USFontLabel.GetColour()); + m_fontPicker6->SetSelectedFont(g_USFontSmall.GetChosenFont()); + m_fontPicker6->SetSelectedColour(g_USFontSmall.GetColour()); + wxColour dummy; + GetGlobalColor(_T("DASHL"), &dummy); + m_colourPicker1->SetColour(dummy); + GetGlobalColor(_T("DASHB"), &dummy); + m_colourPicker2->SetColour(dummy); + GetGlobalColor(_T("DASHN"), &dummy); + m_colourPicker3->SetColour(dummy); + GetGlobalColor(_T("BLUE3"), &dummy); + m_colourPicker4->SetColour(dummy); + Update(); } - diff --git a/plugins/grib_pi/CMakeLists.txt b/plugins/grib_pi/CMakeLists.txt index f9a649e43e..fbe48d184c 100644 --- a/plugins/grib_pi/CMakeLists.txt +++ b/plugins/grib_pi/CMakeLists.txt @@ -262,6 +262,7 @@ else (NOT QT_ANDROID) endif (NOT QT_ANDROID) target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::wxjson) +target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::manual) target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::opencpn) if (NOT WIN32) diff --git a/plugins/grib_pi/src/GribUIDialogBase.cpp b/plugins/grib_pi/src/GribUIDialogBase.cpp index ce137fc8a2..f740a1df23 100644 --- a/plugins/grib_pi/src/GribUIDialogBase.cpp +++ b/plugins/grib_pi/src/GribUIDialogBase.cpp @@ -7,6 +7,7 @@ #include "GribUIDialogBase.h" #include "XyGribPanel.h" +#include "manual.h" /////////////////////////////////////////////////////////////////////////// @@ -2077,6 +2078,13 @@ GribPreferencesDialogBase::GribPreferencesDialogBase( m_sdbSizer2->AddButton(m_sdbSizer2OK); m_sdbSizer2Cancel = new wxButton(this, wxID_CANCEL, _("Cancel")); m_sdbSizer2->AddButton(m_sdbSizer2Cancel); + auto help_btn = new wxButton(this, wxID_HELP); + help_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](wxCommandEvent) { + wxString datadir = GetPluginDataDir("manual_pi"); + Manual(this, datadir.ToStdString()).Launch("Grib"); + }); + m_sdbSizer2->AddButton(help_btn); + m_sdbSizer2->Realize(); itemBoxSizerMainPanel->Add(m_sdbSizer2, 0, wxEXPAND, 5); @@ -3543,4 +3551,4 @@ double ProjectBoatPanel::GetSpeed() { } bool ProjectBoatPanel::ProjectionEnabled() { return m_cbProjectPosition->IsChecked(); -} \ No newline at end of file +} diff --git a/plugins/wmm_pi/CMakeLists.txt b/plugins/wmm_pi/CMakeLists.txt index 365af1c48d..e13b87759c 100644 --- a/plugins/wmm_pi/CMakeLists.txt +++ b/plugins/wmm_pi/CMakeLists.txt @@ -128,6 +128,7 @@ if (APPLE) endif (APPLE) # target_link_libraries(${PACKAGE_NAME} ocpn::opencpn ) +target_link_libraries(${PACKAGE_NAME} PRIVATE ocpn::manual) # Copy shared library to execution folder for debugging if not CI build if (NOT OCPN_CI_BUILD) diff --git a/plugins/wmm_pi/src/WmmUIDialog.cpp b/plugins/wmm_pi/src/WmmUIDialog.cpp index 30ab237471..21290f51c9 100644 --- a/plugins/wmm_pi/src/WmmUIDialog.cpp +++ b/plugins/wmm_pi/src/WmmUIDialog.cpp @@ -6,6 +6,8 @@ /////////////////////////////////////////////////////////////////////////// #include "WmmUIDialog.h" +#include "manual.h" +#include "ocpn_plugin.h" /////////////////////////////////////////////////////////////////////////// @@ -315,7 +317,7 @@ void WmmUIDialogBase::OnKey(wxKeyEvent& ke) { } } -void WmmUIDialogBase::OnClose( wxCloseEvent& event ) { +void WmmUIDialogBase::OnClose(wxCloseEvent& event) { if (event.CanVeto()) { Hide(); event.Veto(); @@ -324,7 +326,7 @@ void WmmUIDialogBase::OnClose( wxCloseEvent& event ) { } } -void WmmUIDialogBase::OnClose( wxCommandEvent& event ) { +void WmmUIDialogBase::OnClose(wxCommandEvent& event) { Hide(); event.Skip(); } @@ -378,6 +380,13 @@ WmmPrefsDialog::WmmPrefsDialog(wxWindow* parent, wxWindowID id, m_sdbSizer1->AddButton(m_sdbSizer1OK); m_sdbSizer1Cancel = new wxButton(this, wxID_CANCEL, _("Cancel")); m_sdbSizer1->AddButton(m_sdbSizer1Cancel); + auto* help_btn = new wxButton(this, wxID_HELP); + help_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](wxCommandEvent) { + wxString datadir = GetPluginDataDir("manual_pi"); + Manual(this, datadir.ToStdString()).Launch("Wmm"); + }); + m_sdbSizer1->AddButton(help_btn); + m_sdbSizer1->Realize(); bSizer2->Add(m_sdbSizer1, 0, wxBOTTOM | wxEXPAND | wxTOP, 5);