OpenCPN Partial API docs
Loading...
Searching...
No Matches
grib_pi.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
24#include "wx/wxprec.h"
25
26#ifndef WX_PRECOMP
27#include "wx/wx.h"
28#endif
29
30#include "pi_gl.h"
31
32#ifdef ocpnUSE_GL
33#include <wx/glcanvas.h>
34#endif
35
36#include <wx/fileconf.h>
37#include <wx/stdpaths.h>
38
39#include "grib_pi.h"
40
41#include "jsonwriter.h"
42
43#ifdef __WXQT__
44#include "qdebug.h"
45#endif
46
47double g_ContentScaleFactor;
48
49// the class factories, used to create and destroy instances of the PlugIn
50
51extern "C" DECL_EXP opencpn_plugin *create_pi(void *ppimgr) {
52 return new GribPi(ppimgr);
53}
54
55extern "C" DECL_EXP void destroy_pi(opencpn_plugin *p) { delete p; }
56
57extern int m_DialogStyle;
58
59GribPi *g_pi;
60bool g_bpause;
61
62//---------------------------------------------------------------------------------------------------------
63//
64// Grib PlugIn Implementation
65//
66//---------------------------------------------------------------------------------------------------------
67
68#include "icons.h"
69
70//---------------------------------------------------------------------------------------------------------
71//
72// PlugIn initialization and de-init
73//
74//---------------------------------------------------------------------------------------------------------
75
76GribPi::GribPi(void *ppimgr) : opencpn_plugin_116(ppimgr) {
77 // Create the PlugIn icons
78 initialize_images();
79
80 wxString shareLocn = *GetpSharedDataLocation() + "plugins" +
81 wxFileName::GetPathSeparator() + "grib_pi" +
82 wxFileName::GetPathSeparator() + "data" +
83 wxFileName::GetPathSeparator();
84 wxImage panelIcon(shareLocn + "grib_panel_icon.png");
85 if (panelIcon.IsOk())
86 m_panelBitmap = wxBitmap(panelIcon);
87 else
88 wxLogMessage(" GRIB panel icon NOT loaded");
89
90 m_pLastTimelineSet = nullptr;
91 m_bShowGrib = false;
92 m_GUIScaleFactor = -1.;
93 g_pi = this;
94}
95
96GribPi::~GribPi() {
97 delete _img_grib_pi;
98 delete _img_grib;
99 delete m_pLastTimelineSet;
100}
101
103 AddLocaleCatalog("opencpn-grib_pi");
104
105 // Set some default private member parameters
106 m_CtrlBarxy = wxPoint(0, 0);
107 m_CursorDataxy = wxPoint(0, 0);
108
109 m_pGribCtrlBar = nullptr;
110 m_pGRIBOverlayFactory = nullptr;
111
112 ::wxDisplaySize(&m_display_width, &m_display_height);
113
114 m_DialogStyleChanged = false;
115
116 // Get a pointer to the opencpn configuration object
117 m_pconfig = GetOCPNConfigObject();
118
119 // And load the configuration items
120 LoadConfig();
121
122 // Get a pointer to the opencpn display canvas, to use as a parent for the
123 // GRIB dialog
124 m_parent_window = GetOCPNCanvasWindow();
125
126 g_ContentScaleFactor = m_parent_window->GetContentScaleFactor();
127
128 // int m_height = GetChartbarHeight();
129 // This PlugIn needs a CtrlBar icon, so request its insertion if enabled
130 // locally
131 wxString shareLocn = *GetpSharedDataLocation() + "plugins" +
132 wxFileName::GetPathSeparator() + "grib_pi" +
133 wxFileName::GetPathSeparator() + "data" +
134 wxFileName::GetPathSeparator();
135 // Initialize catalog file
136 wxString local_grib_catalog = "sources.json";
137 wxString data_path = *GetpPrivateApplicationDataLocation() +
138 wxFileName::GetPathSeparator() + "grib_pi";
139 if (!wxDirExists(data_path)) {
140 wxMkdir(data_path);
141 }
142 m_local_sources_catalog =
143 data_path + wxFileName::GetPathSeparator() + local_grib_catalog;
144 if (!wxFileExists(m_local_sources_catalog)) {
145 wxCopyFile(shareLocn + local_grib_catalog, m_local_sources_catalog);
146 }
147 if (m_bGRIBShowIcon) {
148 wxString normalIcon = shareLocn + "grib.svg";
149 wxString toggledIcon = shareLocn + "grib_toggled.svg";
150 wxString rolloverIcon = shareLocn + "grib_rollover.svg";
151
152 // For journeyman styles, we prefer the built-in raster icons which match
153 // the rest of the toolbar.
154 if (GetActiveStyleName().Lower() != "traditional") {
155 normalIcon = "";
156 toggledIcon = "";
157 rolloverIcon = "";
158 }
159
160 wxLogMessage(normalIcon);
161 m_leftclick_tool_id = InsertPlugInToolSVG(
162 "", normalIcon, rolloverIcon, toggledIcon, wxITEM_CHECK, _("Grib"), "",
163 nullptr, GRIB_TOOL_POSITION, 0, this);
164 }
165
166 if (!QualifyCtrlBarPosition(m_CtrlBarxy, m_CtrlBar_Sizexy)) {
167 m_CtrlBarxy = wxPoint(20, 60); // reset to the default position
168 m_CursorDataxy = wxPoint(20, 170);
169 }
170
171 return (WANTS_OVERLAY_CALLBACK | WANTS_OPENGL_OVERLAY_CALLBACK |
175}
176
178 // Reset timeline to system time before shutting down
179 SendTimelineMessage(wxInvalidDateTime);
180
181 if (m_pGribCtrlBar) {
182 m_pGribCtrlBar->Close();
183 delete m_pGribCtrlBar;
184 m_pGribCtrlBar = nullptr;
185 }
186
187 delete m_pGRIBOverlayFactory;
188 m_pGRIBOverlayFactory = nullptr;
189
190 return true;
191}
192
193int GribPi::GetAPIVersionMajor() { return MY_API_VERSION_MAJOR; }
194
195int GribPi::GetAPIVersionMinor() { return MY_API_VERSION_MINOR; }
196
197int GribPi::GetPlugInVersionMajor() { return PLUGIN_VERSION_MAJOR; }
198
199int GribPi::GetPlugInVersionMinor() { return PLUGIN_VERSION_MINOR; }
200
201wxBitmap *GribPi::GetPlugInBitmap() { return &m_panelBitmap; }
202
203wxString GribPi::GetCommonName() { return "GRIB"; }
204
205wxString GribPi::GetShortDescription() { return _("GRIB PlugIn for OpenCPN"); }
206
208 return _(
209 "GRIB PlugIn for OpenCPN\n\
210Provides basic GRIB file overlay capabilities for several GRIB file types\n\
211and a request function to get GRIB files by eMail.\n\n\
212Supported GRIB data include:\n\
213- wind direction and speed (at 10 m)\n\
214- wind gust\n\
215- surface pressure\n\
216- rainfall\n\
217- cloud cover\n\
218- significant wave height and direction\n\
219- air surface temperature (at 2 m)\n\
220- sea surface temperature\n\
221- surface current direction and speed\n\
222- Convective Available Potential Energy (CAPE)\n\
223- wind, altitude, temperature and relative humidity at 300, 500, 700, 850 hPa.");
224}
225
227
228int GribPi::GetToolBarToolCount() { return 1; }
229
230bool GribPi::MouseEventHook(wxMouseEvent &event) {
231 if ((m_pGribCtrlBar && m_pGribCtrlBar->pReq_Dialog))
232 return m_pGribCtrlBar->pReq_Dialog->MouseEventHook(event);
233 return false;
234}
235
236void GribPi::ShowPreferencesDialog(wxWindow *parent) {
237 auto *Pref = new GribPreferencesDialog(parent);
238
239 DimeWindow(Pref); // aplly global colours scheme
240 SetDialogFont(Pref); // Apply global font
241
242 Pref->m_cbUseHiDef->SetValue(m_bGRIBUseHiDef);
243 Pref->m_cbUseGradualColors->SetValue(m_bGRIBUseGradualColors);
244 Pref->m_cbDrawBarbedArrowHead->SetValue(m_bDrawBarbedArrowHead);
245 Pref->m_cZoomToCenterAtInit->SetValue(m_bZoomToCenterAtInit);
246 Pref->m_cbCopyFirstCumulativeRecord->SetValue(m_bCopyFirstCumRec);
247 Pref->m_cbCopyMissingWaveRecord->SetValue(m_bCopyMissWaveRec);
248 Pref->m_rbLoadOptions->SetSelection(m_bLoadLastOpenFile);
249 Pref->m_rbStartOptions->SetSelection(m_bStartOptions);
250
251 if (Pref->m_textDirectory) { // not present on Android
252 wxFileConfig *pConf = GetOCPNConfigObject();
253 if (pConf) {
254 wxString l_grib_dir;
255 pConf->SetPath("/Directories");
256 pConf->Read("GRIBDirectory", &l_grib_dir);
257 Pref->m_grib_dir_sel = l_grib_dir;
258 Pref->m_textDirectory->ChangeValue(l_grib_dir);
259 }
260 }
261
262#ifdef __WXMSW__
263 int val = (m_GribIconsScaleFactor * 10.) - 10;
264 Pref->m_sIconSizeFactor->SetValue(val);
265#endif
266
267#ifdef __ANDROID__
268 if (m_parent_window) {
269 int xmax = m_parent_window->GetSize().GetWidth();
270 int ymax = m_parent_window->GetParent()
271 ->GetSize()
272 .GetHeight(); // This would be the Options dialog itself
273 Pref->SetSize(xmax, ymax);
274 Pref->Layout();
275 Pref->Move(0, 0);
276 }
277 Pref->Show();
278#else
279 // Constrain size on small displays
280
281 int display_width, display_height;
282 wxDisplaySize(&display_width, &display_height);
283 int char_width = GetOCPNCanvasWindow()->GetCharWidth();
284 int char_height = GetOCPNCanvasWindow()->GetCharHeight();
285 if (display_height < 600) {
286 wxSize canvas_size = GetOCPNCanvasWindow()->GetSize();
287 Pref->SetMaxSize(GetOCPNCanvasWindow()->GetSize());
288 Pref->SetSize(wxSize(60 * char_width, canvas_size.x * 8 / 10));
289 Pref->CentreOnScreen();
290 } else {
291 Pref->SetMaxSize(GetOCPNCanvasWindow()->GetSize());
292 Pref->SetSize(wxSize(60 * char_width, 32 * char_height));
293 }
294
295 Pref->ShowModal();
296#endif
297}
298
299void GribPi::UpdatePrefs(GribPreferencesDialog *Pref) {
300 m_bGRIBUseHiDef = Pref->m_cbUseHiDef->GetValue();
301 m_bGRIBUseGradualColors = Pref->m_cbUseGradualColors->GetValue();
302 m_bLoadLastOpenFile = Pref->m_rbLoadOptions->GetSelection();
303 m_bDrawBarbedArrowHead = Pref->m_cbDrawBarbedArrowHead->GetValue();
304 m_bZoomToCenterAtInit = Pref->m_cZoomToCenterAtInit->GetValue();
305#ifdef __WXMSW__
306 double val = Pref->m_sIconSizeFactor->GetValue();
307 m_GribIconsScaleFactor = 1. + (val / 10);
308#endif
309
310 if (m_pGRIBOverlayFactory)
311 m_pGRIBOverlayFactory->SetSettings(m_bGRIBUseHiDef, m_bGRIBUseGradualColors,
312 m_bDrawBarbedArrowHead);
313
314 int updatelevel = 0;
315
316 if (m_bStartOptions != Pref->m_rbStartOptions->GetSelection()) {
317 m_bStartOptions = Pref->m_rbStartOptions->GetSelection();
318 updatelevel = 1;
319 }
320
321 bool copyrec = Pref->m_cbCopyFirstCumulativeRecord->GetValue();
322 bool copywave = Pref->m_cbCopyMissingWaveRecord->GetValue();
323 if (m_bCopyFirstCumRec != copyrec || m_bCopyMissWaveRec != copywave) {
324 m_bCopyFirstCumRec = copyrec;
325 m_bCopyMissWaveRec = copywave;
326 updatelevel = 3;
327 }
328
329 if (m_pGribCtrlBar) {
330 switch (updatelevel) {
331 case 0:
332 break;
333 case 3:
334 // rebuild current activefile with new parameters and rebuil data list
335 // with current index
336 m_pGribCtrlBar->CreateActiveFileFromNames(
337 m_pGribCtrlBar->m_bGRIBActiveFile->GetFileNames());
338 m_pGribCtrlBar->PopulateComboDataList();
339 m_pGribCtrlBar->TimelineChanged();
340 break;
341 case 2:
342 // only rebuild data list with current index and new timezone
343 // This no longer applicable because the timezone is set in the
344 // OpenCPN core global settings (Options -> Display -> General)
345 m_pGribCtrlBar->PopulateComboDataList();
346 m_pGribCtrlBar->TimelineChanged();
347 break;
348 case 1:
349 // only re-compute the best forecast
350 m_pGribCtrlBar->ComputeBestForecastForNow();
351 break;
352 }
353 if (Pref->m_grib_dir_sel.Length()) {
354 m_pGribCtrlBar->m_grib_dir = Pref->m_grib_dir_sel;
355 m_pGribCtrlBar->m_file_names.Clear();
356 }
357 }
358
359 if (Pref->m_grib_dir_sel.Length()) {
360 wxFileConfig *pConf = GetOCPNConfigObject();
361 if (pConf) {
362 pConf->SetPath("/Directories");
363 pConf->Write("GRIBDirectory", Pref->m_grib_dir_sel);
364 pConf->DeleteGroup("/Settings/GRIB/FileNames");
365 pConf->Flush();
366 }
367 }
368 SaveConfig();
369}
370
371bool GribPi::QualifyCtrlBarPosition(
372 wxPoint position,
373 wxSize size) { // Make sure drag bar (title bar) or grabber always screen
374 bool b_reset_pos = false;
375#ifdef __WXMSW__
376 // Support MultiMonitor setups which an allow negative window positions.
377 // If the requested window does not intersect any installed monitor,
378 // then default to simple primary monitor positioning.
379 RECT frame_title_rect;
380 frame_title_rect.left = position.x;
381 frame_title_rect.top = position.y;
382 frame_title_rect.right = position.x + size.x;
383 frame_title_rect.bottom = m_DialogStyle == ATTACHED_HAS_CAPTION
384 ? position.y + 30
385 : position.y + size.y;
386
387 if (nullptr == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
388 b_reset_pos = true;
389#else
390 wxRect window_title_rect; // conservative estimate
391 window_title_rect.x = position.x;
392 window_title_rect.y = position.y;
393 window_title_rect.width = size.x;
394 window_title_rect.height =
395 m_DialogStyle == ATTACHED_HAS_CAPTION ? 30 : size.y;
396
397 wxRect ClientRect = wxGetClientDisplayRect();
398 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos = true;
399
400#endif
401 return !b_reset_pos;
402}
403
404void GribPi::MoveDialog(wxDialog *dialog, wxPoint position) {
405 // Use the application frame to bound the control bar position.
406 wxApp *app = wxTheApp;
407
408 wxWindow *frame =
409 app->GetTopWindow(); // or GetOCPNCanvasWindow()->GetParent();
410 if (!frame) return;
411
412 wxPoint p = frame->ScreenToClient(position);
413 // Check and ensure there is always a "grabb" zone always visible wathever the
414 // dialoue size is.
415 if (p.x + dialog->GetSize().GetX() > frame->GetClientSize().GetX())
416 p.x = frame->GetClientSize().GetX() - dialog->GetSize().GetX();
417 if (p.y + dialog->GetSize().GetY() > frame->GetClientSize().GetY())
418 p.y = frame->GetClientSize().GetY() - dialog->GetSize().GetY();
419
420#ifdef __WXGTK__
421 dialog->Move(0, 0);
422#endif
423 dialog->Move(frame->ClientToScreen(p));
424}
425
427 // if( !::wxIsBusy() ) ::wxBeginBusyCursor();
428
429 bool starting = false;
430
431 double scale_factor =
433#ifdef __WXMSW__
434 scale_factor *= m_GribIconsScaleFactor;
435#endif
436 if (scale_factor != m_GUIScaleFactor) starting = true;
437
438 if (!m_pGribCtrlBar) {
439 starting = true;
440 long style = m_DialogStyle == ATTACHED_HAS_CAPTION
441 ? wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU
442 : wxBORDER_NONE | wxSYSTEM_MENU;
443#ifdef __WXOSX__
444 style |= wxSTAY_ON_TOP;
445#endif
446 m_pGribCtrlBar = new GRIBUICtrlBar(m_parent_window, wxID_ANY, wxEmptyString,
447 wxDefaultPosition, wxDefaultSize, style,
448 this, scale_factor);
449 m_pGribCtrlBar->SetScaledBitmap(scale_factor);
450
451 auto *dummy = new wxMenu("Plugin");
452 auto *table = new wxMenuItem(dummy, wxID_ANY, wxString(_("Weather table")),
453 wxEmptyString, wxITEM_NORMAL);
454 /* Menu font do not work properly for MSW (wxWidgets 3.2.1)
455 #ifdef __WXMSW__
456 wxFont *qFont = OCPNGetFont(_("Menu"));
457 table->SetFont(*qFont);
458 #endif
459 */
460 m_MenuItem = AddCanvasContextMenuItem(table, this);
461 SetCanvasContextMenuItemViz(m_MenuItem, false);
462
463 // Create the drawing factory
464 m_pGRIBOverlayFactory = new GRIBOverlayFactory(*m_pGribCtrlBar);
465 m_pGRIBOverlayFactory->SetMessageFont();
466 m_pGRIBOverlayFactory->SetParentSize(m_display_width, m_display_height);
467 m_pGRIBOverlayFactory->SetSettings(m_bGRIBUseHiDef, m_bGRIBUseGradualColors,
468 m_bDrawBarbedArrowHead);
469
470 m_pGribCtrlBar->OpenFile(m_bLoadLastOpenFile == 0);
471 }
472
473 // Toggle GRIB overlay display
474 if (id >= 0) m_bShowGrib = !m_bShowGrib;
475
476 // Toggle dialog?
477 if (m_bShowGrib || id < 0) {
478 // A new file could have been added since grib plugin opened
479 if (!starting && m_bLoadLastOpenFile == 0) {
480 m_pGribCtrlBar->OpenFile(true);
481 starting = true;
482 }
483 // the dialog font could have been changed since grib plugin opened
484 if (m_pGribCtrlBar->GetFont() != *OCPNGetFont(_("Dialog"))) starting = true;
485 if (starting) {
486 m_pGRIBOverlayFactory->SetMessageFont();
487 SetDialogFont(m_pGribCtrlBar);
488 m_GUIScaleFactor = scale_factor;
489 m_pGribCtrlBar->SetScaledBitmap(m_GUIScaleFactor);
490 m_pGribCtrlBar->SetDialogsStyleSizePosition(true);
491 m_pGribCtrlBar->Refresh();
492 } else {
493 MoveDialog(m_pGribCtrlBar, GetCtrlBarXY());
494 if (m_DialogStyle >> 1 == SEPARATED) {
495 MoveDialog(m_pGribCtrlBar->GetCDataDialog(), GetCursorDataXY());
496 m_pGribCtrlBar->GetCDataDialog()->Show(m_pGribCtrlBar->m_CDataIsShown);
497 }
498#ifdef __ANDROID__
499 m_pGribCtrlBar->SetDialogsStyleSizePosition(true);
500 m_pGribCtrlBar->Refresh();
501#endif
502 }
503 if (id >= 0) m_pGribCtrlBar->Show();
504 if (m_pGribCtrlBar->m_bGRIBActiveFile) {
505 if (m_pGribCtrlBar->m_bGRIBActiveFile->IsOK()) {
506 ArrayOfGribRecordSets *rsa =
507 m_pGribCtrlBar->m_bGRIBActiveFile->GetRecordSetArrayPtr();
508 if (rsa->GetCount() > 1) {
509 SetCanvasContextMenuItemViz(m_MenuItem, true);
510 }
511 if (rsa->GetCount() >= 1) { // XXX Should be only on Show
512 SendTimelineMessage(m_pGribCtrlBar->TimelineTime());
513 }
514 }
515 }
516 // Toggle is handled by the CtrlBar but we must keep plugin manager b_toggle
517 // updated to actual status to ensure correct status upon CtrlBar rebuild
518 SetToolbarItemState(m_leftclick_tool_id, m_bShowGrib);
519
520 // Do an automatic "zoom-to-center" on the overlay canvas if set in
521 // Preferences
522 if (m_pGribCtrlBar && m_bZoomToCenterAtInit) {
523 m_pGribCtrlBar->DoZoomToCenter();
524 }
525
526 RequestRefresh(m_parent_window); // refresh main window
527 } else
528 m_pGribCtrlBar->Close();
529}
530
531void GribPi::OnGribCtrlBarClose() {
532 m_bShowGrib = false;
533 SetToolbarItemState(m_leftclick_tool_id, m_bShowGrib);
534
535 m_pGribCtrlBar->Hide();
536
537 SaveConfig();
538
539 SetCanvasContextMenuItemViz(m_MenuItem, false);
540
541 RequestRefresh(m_parent_window); // refresh main window
542
543 if (::wxIsBusy()) ::wxEndBusyCursor();
544
545#ifdef __ANDROID__
546 m_DialogStyleChanged = true; // Force a delete of the control bar dialog
547#endif
548
549 if (m_DialogStyleChanged) {
550 m_pGribCtrlBar->Destroy();
551 m_pGribCtrlBar = nullptr;
552 m_DialogStyleChanged = false;
553 }
554}
555
556bool GribPi::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp) { return false; }
557
558bool GribPi::DoRenderOverlay(wxDC &dc, PlugIn_ViewPort *vp, int canvasIndex) {
559 if (!m_pGribCtrlBar || !m_pGribCtrlBar->IsShown() || !m_pGRIBOverlayFactory)
560 return false;
561
562 m_pGRIBOverlayFactory->RenderGribOverlay(dc, vp);
563 if (PluginGetFocusCanvas() == GetCanvasByIndex(canvasIndex)) {
564 m_pGribCtrlBar->SetViewPortWithFocus(vp);
565 }
566
567 if (GetCanvasByIndex(canvasIndex) == GetCanvasUnderMouse()) {
568 m_pGribCtrlBar->SetViewPortUnderMouse(vp);
569 if (m_pGribCtrlBar->pReq_Dialog &&
571 m_pGribCtrlBar->pReq_Dialog->GetBoundingBoxCanvasIndex()) {
572 m_pGribCtrlBar->pReq_Dialog->RenderZoneOverlay(dc);
573 }
574 }
575 if (::wxIsBusy()) ::wxEndBusyCursor();
576 return true;
577}
578
579bool GribPi::RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp) {
580 return false;
581}
582
583bool GribPi::DoRenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp,
584 int canvasIndex) {
585 if (!m_pGribCtrlBar || !m_pGribCtrlBar->IsShown() || !m_pGRIBOverlayFactory)
586 return false;
587
588 m_pGRIBOverlayFactory->RenderGLGribOverlay(pcontext, vp);
589 if (PluginGetFocusCanvas() == GetCanvasByIndex(canvasIndex)) {
590 m_pGribCtrlBar->SetViewPortWithFocus(vp);
591 }
592
593 if (GetCanvasByIndex(canvasIndex) == GetCanvasUnderMouse()) {
594 m_pGribCtrlBar->SetViewPortUnderMouse(vp);
595 if (m_pGribCtrlBar->pReq_Dialog &&
597 m_pGribCtrlBar->pReq_Dialog->GetBoundingBoxCanvasIndex()) {
598 m_pGribCtrlBar->pReq_Dialog->RenderGlZoneOverlay();
599 }
600 }
601
602 if (::wxIsBusy()) ::wxEndBusyCursor();
603
604#ifdef __ANDROID__
605 m_pGribCtrlBar->Raise(); // Control bar should always be visible
606#endif
607
608 return true;
609}
610
611bool GribPi::RenderGLOverlayMultiCanvas(wxGLContext *pcontext,
612 PlugIn_ViewPort *vp, int canvasIndex) {
613 return DoRenderGLOverlay(pcontext, vp, canvasIndex);
614}
615
617 int canvasIndex) {
618 return DoRenderOverlay(dc, vp, canvasIndex);
619}
620
621void GribPi::SetCursorLatLon(double lat, double lon) {
622 if (m_pGribCtrlBar && m_pGribCtrlBar->IsShown())
623 m_pGribCtrlBar->SetCursorLatLon(lat, lon);
624}
625
627 if (!m_pGribCtrlBar->m_bGRIBActiveFile) return;
628 m_pGribCtrlBar->ContextMenuItemCallback(id);
629}
630
631void GribPi::SetDialogFont(wxWindow *dialog, wxFont *font) {
632 dialog->SetFont(*font);
633 wxWindowList list = dialog->GetChildren();
634 wxWindowListNode *node = list.GetFirst();
635 for (size_t i = 0; i < list.GetCount(); i++) {
636 wxWindow *win = node->GetData();
637 win->SetFont(*font);
638 node = node->GetNext();
639 }
640 dialog->Fit();
641 dialog->Refresh();
642}
643
644void GribPi::SetPluginMessage(wxString &message_id, wxString &message_body) {
645 if (message_id == "GRIB_VALUES_REQUEST") {
646 if (!m_pGribCtrlBar) OnToolbarToolCallback(-1);
647
648 // lat, lon, time, what
649 wxJSONReader r;
650 wxJSONValue v;
651 r.Parse(message_body, &v);
652 if (!v.HasMember("Day")) {
653 // bogus or loading grib
654 SendPluginMessage(wxString("GRIB_VALUES"), "");
655 return;
656 }
657 wxDateTime time(v["Day"].AsInt(), (wxDateTime::Month)v["Month"].AsInt(),
658 v["Year"].AsInt(), v["Hour"].AsInt(), v["Minute"].AsInt(),
659 v["Second"].AsInt());
660 double lat = v["lat"].AsDouble();
661 double lon = v["lon"].AsDouble();
662
663 if (m_pGribCtrlBar) {
664 if (v.HasMember("WIND SPEED")) {
665 double vkn, ang;
666 if (m_pGribCtrlBar->getTimeInterpolatedValues(
667 vkn, ang, Idx_WIND_VX, Idx_WIND_VY, lon, lat, time) &&
668 vkn != GRIB_NOTDEF) {
669 v["Type"] = wxString("Reply");
670 v["WIND SPEED"] = vkn;
671 v["WIND DIR"] = ang;
672 } else {
673 v.Remove("WIND SPEED");
674 v.Remove("WIND DIR");
675 }
676 }
677 if (v.HasMember("CURRENT SPEED")) {
678 double vkn, ang;
679 if (m_pGribCtrlBar->getTimeInterpolatedValues(
680 vkn, ang, Idx_SEACURRENT_VX, Idx_SEACURRENT_VY, lon, lat,
681 time) &&
682 vkn != GRIB_NOTDEF) {
683 v["Type"] = wxString("Reply");
684 v["CURRENT SPEED"] = vkn;
685 v["CURRENT DIR"] = ang;
686 } else {
687 v.Remove("CURRENT SPEED");
688 v.Remove("CURRENT DIR");
689 }
690 }
691 if (v.HasMember("GUST")) {
692 double vkn = m_pGribCtrlBar->getTimeInterpolatedValue(Idx_WIND_GUST,
693 lon, lat, time);
694 if (vkn != GRIB_NOTDEF) {
695 v["Type"] = wxString("Reply");
696 v["GUST"] = vkn;
697 } else
698 v.Remove("GUST");
699 }
700 if (v.HasMember("SWELL")) {
701 double vkn = m_pGribCtrlBar->getTimeInterpolatedValue(Idx_HTSIGW, lon,
702 lat, time);
703 if (vkn != GRIB_NOTDEF) {
704 v["Type"] = wxString("Reply");
705 v["SWELL"] = vkn;
706 } else
707 v.Remove("SWELL");
708 }
709
710 wxJSONWriter w;
711 wxString out;
712 w.Write(v, out);
713 SendPluginMessage(wxString("GRIB_VALUES"), out);
714 }
715 } else if (message_id == "GRIB_VERSION_REQUEST") {
716 wxJSONValue v;
717 v["GribVersionMinor"] = GetAPIVersionMinor();
718 v["GribVersionMajor"] = GetAPIVersionMajor();
719
720 wxJSONWriter w;
721 wxString out;
722 w.Write(v, out);
723 SendPluginMessage(wxString("GRIB_VERSION"), out);
724 } else if (message_id == "GRIB_TIMELINE_REQUEST") {
725 // local time
726 SendTimelineMessage(m_pGribCtrlBar ? m_pGribCtrlBar->TimelineTime()
727 : wxDateTime::Now());
728 } else if (message_id == "GRIB_TIMELINE_RECORD_REQUEST") {
729 wxJSONReader r;
730 wxJSONValue v;
731 r.Parse(message_body, &v);
732 wxDateTime time(v["Day"].AsInt(), (wxDateTime::Month)v["Month"].AsInt(),
733 v["Year"].AsInt(), v["Hour"].AsInt(), v["Minute"].AsInt(),
734 v["Second"].AsInt());
735
736 if (!m_pGribCtrlBar) OnToolbarToolCallback(-1);
737
739 m_pGribCtrlBar ? m_pGribCtrlBar->GetTimeLineRecordSet(time) : nullptr;
740
741 char ptr[64];
742 snprintf(ptr, sizeof ptr, "%p", set);
743
744 v["GribVersionMajor"] = PLUGIN_VERSION_MAJOR;
745 v["GribVersionMinor"] = PLUGIN_VERSION_MINOR;
746 v["TimelineSetPtr"] = wxString::From8BitData(ptr);
747
748 wxJSONWriter w;
749 wxString out;
750 w.Write(v, out);
751 SendPluginMessage(wxString("GRIB_TIMELINE_RECORD"), out);
752 delete m_pLastTimelineSet;
753 m_pLastTimelineSet = set;
754 }
755
756 else if (message_id == "GRIB_APPLY_JSON_CONFIG") {
757 wxLogMessage("Got GRIB_APPLY_JSON_CONFIG");
758
759 if (m_pGribCtrlBar) {
760 m_pGribCtrlBar->OpenFileFromJSON(message_body);
761
762 m_pGribCtrlBar->m_OverlaySettings.JSONToSettings(message_body);
763 m_pGribCtrlBar->m_OverlaySettings.Write();
764 m_pGribCtrlBar->SetDialogsStyleSizePosition(true);
765 }
766 }
767}
768
769bool GribPi::LoadConfig() {
770 auto *pConf = (wxFileConfig *)m_pconfig;
771
772 if (!pConf) return false;
773
774 pConf->SetPath("/PlugIns/GRIB");
775 pConf->Read("LoadLastOpenFile", &m_bLoadLastOpenFile, 0);
776 pConf->Read("OpenFileOption", &m_bStartOptions, 1);
777 pConf->Read("GRIBUseHiDef", &m_bGRIBUseHiDef, false);
778 pConf->Read("GRIBUseGradualColors", &m_bGRIBUseGradualColors, false);
779 pConf->Read("DrawBarbedArrowHead", &m_bDrawBarbedArrowHead, true);
780 pConf->Read("ZoomToCenterAtInit", &m_bZoomToCenterAtInit, true);
781 pConf->Read("ShowGRIBIcon", &m_bGRIBShowIcon, true);
782 pConf->Read("CopyFirstCumulativeRecord", &m_bCopyFirstCumRec, true);
783 pConf->Read("CopyMissingWaveRecord", &m_bCopyMissWaveRec, true);
784#ifdef __WXMSW__
785 pConf->Read("GribIconsScaleFactor", &m_GribIconsScaleFactor, 1);
786#endif
787
788 m_CtrlBar_Sizexy.x = pConf->Read("GRIBCtrlBarSizeX", 1400L);
789 m_CtrlBar_Sizexy.y = pConf->Read("GRIBCtrlBarSizeY", 800L);
790 m_CtrlBarxy.x = pConf->Read("GRIBCtrlBarPosX", 20L);
791 m_CtrlBarxy.y = pConf->Read("GRIBCtrlBarPosY", 60L);
792 m_CursorDataxy.x = pConf->Read("GRIBCursorDataPosX", 20L);
793 m_CursorDataxy.y = pConf->Read("GRIBCursorDataPosY", 170L);
794
795 pConf->Read("GribCursorDataDisplayStyle", &m_DialogStyle, 0);
796 if (m_DialogStyle > 3)
797 m_DialogStyle = 0; // ensure validity of the .conf value
798
799 return true;
800}
801
802bool GribPi::SaveConfig(void) {
803 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
804
805 if (!pConf) return false;
806
807 pConf->SetPath("/PlugIns/GRIB");
808
809 pConf->Write("LoadLastOpenFile", m_bLoadLastOpenFile);
810 pConf->Write("OpenFileOption", m_bStartOptions);
811 pConf->Write("ShowGRIBIcon", m_bGRIBShowIcon);
812 pConf->Write("GRIBUseHiDef", m_bGRIBUseHiDef);
813 pConf->Write("GRIBUseGradualColors", m_bGRIBUseGradualColors);
814 pConf->Write("CopyFirstCumulativeRecord", m_bCopyFirstCumRec);
815 pConf->Write("CopyMissingWaveRecord", m_bCopyMissWaveRec);
816 pConf->Write("DrawBarbedArrowHead", m_bDrawBarbedArrowHead);
817 pConf->Write("ZoomToCenterAtInit", m_bZoomToCenterAtInit);
818#ifdef __WXMSW__
819 pConf->Write("GribIconsScaleFactor", m_GribIconsScaleFactor);
820#endif
821
822 pConf->Write("GRIBCtrlBarSizeX", m_CtrlBar_Sizexy.x);
823 pConf->Write("GRIBCtrlBarSizeY", m_CtrlBar_Sizexy.y);
824 pConf->Write("GRIBCtrlBarPosX", m_CtrlBarxy.x);
825 pConf->Write("GRIBCtrlBarPosY", m_CtrlBarxy.y);
826 pConf->Write("GRIBCursorDataPosX", m_CursorDataxy.x);
827 pConf->Write("GRIBCursorDataPosY", m_CursorDataxy.y);
828
829 return true;
830}
831
833 DimeWindow(m_pGribCtrlBar);
834 if (m_pGribCtrlBar) {
835 if (m_pGRIBOverlayFactory) m_pGRIBOverlayFactory->ClearCachedLabel();
836 if (m_pGribCtrlBar->pReq_Dialog) m_pGribCtrlBar->pReq_Dialog->Refresh();
837 m_pGribCtrlBar->Refresh();
838 // m_pGribDialog->SetDataBackGroundColor();
839 }
840}
841
842void GribPi::SendTimelineMessage(wxDateTime time) {
843 if (!m_pGribCtrlBar) return;
844
845 wxJSONValue v;
846 if (time.IsValid()) {
847 v["Day"] = time.GetDay();
848 v["Month"] = time.GetMonth();
849 v["Year"] = time.GetYear();
850 v["Hour"] = time.GetHour();
851 v["Minute"] = time.GetMinute();
852 v["Second"] = time.GetSecond();
853 } else {
854 v["Day"] = -1;
855 v["Month"] = -1;
856 v["Year"] = -1;
857 v["Hour"] = -1;
858 v["Minute"] = -1;
859 v["Second"] = -1;
860 }
861 wxJSONWriter w;
862 wxString out;
863 w.Write(v, out);
864 SendPluginMessage(wxString("GRIB_TIMELINE"), out);
865}
866
868 m_boat_cog = pfix.Cog;
869 m_boat_sog = pfix.Sog;
870 m_boat_lat = pfix.Lat;
871 m_boat_lon = pfix.Lon;
872 if (pfix.FixTime != 0) {
873 m_boat_time = pfix.FixTime;
874 } else {
875 m_boat_time = wxDateTime::Now().GetTicks();
876 }
877}
878
879//----------------------------------------------------------------------------------------------------------
880// Prefrence dialog Implementation
881//----------------------------------------------------------------------------------------------------------
882void GribPreferencesDialog::OnStartOptionChange(wxCommandEvent &event) {
883 if (m_rbStartOptions->GetSelection() == 2) {
885 this,
886 _("You have chosen to authorize interpolation.\nDon't forget that data "
887 "displayed at current time will not be real but Recomputed\nThis can "
888 "decrease accuracy!"),
889 _("Warning!"));
890 }
891}
892
893void GribPreferencesDialog::OnOKClick(wxCommandEvent &event) {
894 if (g_pi) g_pi->UpdatePrefs(this);
895 Close();
896}
bool IsOK() const
Checks if file loading and parsing was successful.
wxArrayString & GetFileNames()
Gets the list of source filenames being used.
ArrayOfGribRecordSets * GetRecordSetArrayPtr()
Gets pointer to array of record sets organized by timestamp.
Factory class for creating and managing GRIB data visualizations.
void SetViewPortWithFocus(PlugIn_ViewPort *vp)
Set the ViewPort that has the focus.
GribOverlaySettings m_OverlaySettings
Settings that control how GRIB data is displayed and overlaid.
void SetViewPortUnderMouse(PlugIn_ViewPort *vp)
Set the ViewPort under the mouse.
wxString m_grib_dir
Directory containing GRIB files.
GRIBFile * m_bGRIBActiveFile
Currently active GRIB file being displayed.
wxDateTime TimelineTime()
Returns the selected time in the GRIB timeline widget.
wxArrayString m_file_names
List of GRIB filenames being displayed.
GribTimelineRecordSet * GetTimeLineRecordSet(wxDateTime time)
Retrieves or creates a temporally interpolated GRIB record set for a specific timestamp.
bool RenderOverlayMultiCanvas(wxDC &dc, PlugIn_ViewPort *vp, int canvasIndex) override
Renders plugin overlay graphics in standard DC mode for multi-canvas support.
Definition grib_pi.cpp:616
void OnContextMenuItemCallback(int id) override
Handles context menu item selection.
Definition grib_pi.cpp:626
bool RenderGLOverlayMultiCanvas(wxGLContext *pcontext, PlugIn_ViewPort *vp, int canvasIndex) override
Renders plugin overlay graphics in OpenGL mode for multi-canvas support.
Definition grib_pi.cpp:611
void SetDefaults() override
Sets plugin default options.
Definition grib_pi.cpp:226
void ShowPreferencesDialog(wxWindow *parent) override
Shows the plugin preferences dialog.
Definition grib_pi.cpp:236
int GetPlugInVersionMajor() override
Returns the major version number of the plugin itself.
Definition grib_pi.cpp:197
wxString GetShortDescription() override
Get a brief description of the plugin.
Definition grib_pi.cpp:205
wxString GetLongDescription() override
Get detailed plugin information.
Definition grib_pi.cpp:207
bool MouseEventHook(wxMouseEvent &event) override
Handles mouse events from chart window.
Definition grib_pi.cpp:230
void SetPositionFixEx(PlugIn_Position_Fix_Ex &pfix) override
Updates plugin with extended position fix data at regular intervals.
Definition grib_pi.cpp:867
int GetAPIVersionMajor() override
Returns the major version number of the plugin API that this plugin supports.
Definition grib_pi.cpp:193
int GetAPIVersionMinor() override
Returns the minor version number of the plugin API that this plugin supports.
Definition grib_pi.cpp:195
bool DeInit() override
Clean up plugin resources.
Definition grib_pi.cpp:177
void SetColorScheme(PI_ColorScheme cs) override
Updates plugin color scheme.
Definition grib_pi.cpp:832
void OnToolbarToolCallback(int id) override
Handles toolbar tool clicks.
Definition grib_pi.cpp:426
wxBitmap * GetPlugInBitmap() override
Get the plugin's icon bitmap.
Definition grib_pi.cpp:201
void SetCursorLatLon(double lat, double lon) override
Receives cursor lat/lon position updates.
Definition grib_pi.cpp:621
int Init() override
Initialize the plugin and declare its capabilities.
Definition grib_pi.cpp:102
wxString GetCommonName() override
Get the plugin's common (short) name.
Definition grib_pi.cpp:203
bool RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp) override
Renders plugin overlay graphics in OpenGL mode for single canvas.
Definition grib_pi.cpp:579
int GetPlugInVersionMinor() override
Returns the minor version number of the plugin itself.
Definition grib_pi.cpp:199
bool RenderGlZoneOverlay()
Renders the GRIB area selection overlay using OpenGL.
bool RenderZoneOverlay(wxDC &dc)
Renders the GRIB area selection overlay using standard device context.
bool MouseEventHook(wxMouseEvent &event)
Intercepts mouse events to handle GRIB area selection.
A specialized GribRecordSet that represents temporally interpolated weather data with isobar renderin...
Extended position fix information.
double Cog
Course over ground in degrees [0-360).
double Lat
Latitude in decimal degrees.
time_t FixTime
UTC time of fix.
double Lon
Longitude in decimal degrees.
double Sog
Speed over ground in knots.
Contains view parameters and status information for a chart display viewport.
Base class for OpenCPN plugins.
The JSON parser.
Definition jsonreader.h:45
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
Definition jsonval.h:79
bool Remove(int index)
Remove the item at the specified index or key.
Definition jsonval.cpp:1552
bool HasMember(unsigned index) const
Return TRUE if the object contains an element at the specified index.
Definition jsonval.cpp:1299
double AsDouble() const
Return the stored value as a double.
Definition jsonval.cpp:830
The JSON document writer.
Definition jsonwriter.h:45
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
GRIB Weather Data Plugin for OpenCPN.
@ Idx_WIND_GUST
Wind gust speed at surface in m/s.
@ Idx_WIND_VX
Surface wind velocity X component in m/s.
@ Idx_HTSIGW
Significant wave height in meters.
@ Idx_SEACURRENT_VY
Sea current velocity Y component in m/s.
@ Idx_WIND_VY
Surface wind velocity Y component in m/s.
@ Idx_SEACURRENT_VX
Sea current velocity X component in m/s.
#define wxCLOSE_BOX
Definition mark_info.h:133
#define WANTS_NMEA_EVENTS
Receive decoded NMEA events with parsed data.
PI_ColorScheme
Color schemes for different lighting conditions.
#define WANTS_ONPAINT_VIEWPORT
Receive callbacks during chart viewport painting.
#define WANTS_MOUSE_EVENTS
Receive mouse events (clicks, movement, etc).
#define WANTS_PREFERENCES
Plugin will add page(s) to global preferences dialog.
#define WANTS_CONFIG
Plugin requires persistent configuration storage.
#define WANTS_PLUGIN_MESSAGING
Enable message passing between plugins.
#define INSTALLS_TOOLBAR_TOOL
Plugin will add one or more toolbar buttons.
#define WANTS_CURSOR_LATLON
Receive updates when cursor moves over chart.
Definition ocpn_plugin.h:95
#define WANTS_TOOLBAR_CALLBACK
Receive notification when user left-clicks plugin's toolbar buttons.
#define WANTS_OVERLAY_CALLBACK
Receive callbacks to render custom overlay graphics on the chart.
Definition ocpn_plugin.h:91
wxWindow * PluginGetFocusCanvas()
Gets the currently focused chart canvas.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
void SetCanvasContextMenuItemViz(int item, bool viz)
Temporarily changes context menu item visibility.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
wxFileConfig * GetOCPNConfigObject()
Gets OpenCPN's configuration object.
int InsertPlugInToolSVG(wxString label, wxString SVGfile, wxString SVGfileRollover, wxString SVGfileToggled, wxItemKind kind, wxString shortHelp, wxString longHelp, wxObject *clientData, int position, int tool_sel, opencpn_plugin *pplugin)
Adds a tool using SVG graphics.
wxString * GetpSharedDataLocation()
Gets shared application data location.
void DimeWindow(wxWindow *win)
Applies system color scheme to window.
wxWindow * GetCanvasUnderMouse()
Gets canvas window under mouse cursor.
double GetOCPNGUIToolScaleFactor_PlugIn()
Gets current global GUI scaling factor.
int AddCanvasContextMenuItem(wxMenuItem *pitem, opencpn_plugin *pplugin)
Adds item to chart canvas context menu.
wxString GetActiveStyleName()
Gets name of currently active style sheet.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
void SetToolbarItemState(int item, bool toggle)
Sets toolbar item toggle state.
wxWindow * GetCanvasByIndex(int canvasIndex)
Gets chart canvas window by index.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
void SendPluginMessage(wxString message_id, wxString message_body)
Sends message to other plugins.
void RequestRefresh(wxWindow *win)
Requests window refresh.
bool AddLocaleCatalog(wxString catalog)
Adds a locale catalog for translations.
OpenGL Platform Abstraction Layer.
wxString * GetpPrivateApplicationDataLocation()
Gets private application data directory.
int OCPNMessageBox_PlugIn(wxWindow *parent, const wxString &message, const wxString &caption, int style, int x, int y)
Shows a message box dialog.