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 m_world_models_catalog =
148 data_path + wxFileName::GetPathSeparator() + "models.json";
149 if (!wxFileExists(m_world_models_catalog)) {
150 wxCopyFile(shareLocn + "models.json", m_world_models_catalog);
151 }
152 if (m_bGRIBShowIcon) {
153 wxString normalIcon = shareLocn + "grib.svg";
154 wxString toggledIcon = shareLocn + "grib_toggled.svg";
155 wxString rolloverIcon = shareLocn + "grib_rollover.svg";
156
157 // For journeyman styles, we prefer the built-in raster icons which match
158 // the rest of the toolbar.
159 if (GetActiveStyleName().Lower() != "traditional") {
160 normalIcon = "";
161 toggledIcon = "";
162 rolloverIcon = "";
163 }
164
165 wxLogMessage(normalIcon);
166 m_leftclick_tool_id = InsertPlugInToolSVG(
167 "", normalIcon, rolloverIcon, toggledIcon, wxITEM_CHECK, _("Grib"), "",
168 nullptr, GRIB_TOOL_POSITION, 0, this);
169 }
170
171 if (!QualifyCtrlBarPosition(m_CtrlBarxy, m_CtrlBar_Sizexy)) {
172 m_CtrlBarxy = wxPoint(20, 60); // reset to the default position
173 m_CursorDataxy = wxPoint(20, 170);
174 }
175
176 return (WANTS_OVERLAY_CALLBACK | WANTS_OPENGL_OVERLAY_CALLBACK |
180}
181
183 // Reset timeline to system time before shutting down
184 SendTimelineMessage(wxInvalidDateTime);
185
186 if (m_pGribCtrlBar) {
187 m_pGribCtrlBar->Close();
188 delete m_pGribCtrlBar;
189 m_pGribCtrlBar = nullptr;
190 }
191
192 delete m_pGRIBOverlayFactory;
193 m_pGRIBOverlayFactory = nullptr;
194
195 return true;
196}
197
198int GribPi::GetAPIVersionMajor() { return MY_API_VERSION_MAJOR; }
199
200int GribPi::GetAPIVersionMinor() { return MY_API_VERSION_MINOR; }
201
202int GribPi::GetPlugInVersionMajor() { return PLUGIN_VERSION_MAJOR; }
203
204int GribPi::GetPlugInVersionMinor() { return PLUGIN_VERSION_MINOR; }
205
206wxBitmap *GribPi::GetPlugInBitmap() { return &m_panelBitmap; }
207
208wxString GribPi::GetCommonName() { return "GRIB"; }
209
210wxString GribPi::GetShortDescription() { return _("GRIB PlugIn for OpenCPN"); }
211
213 return _(
214 "GRIB PlugIn for OpenCPN\n\
215Provides basic GRIB file overlay capabilities for several GRIB file types\n\
216and a request function to get GRIB files by eMail.\n\n\
217Supported GRIB data include:\n\
218- wind direction and speed (at 10 m)\n\
219- wind gust\n\
220- surface pressure\n\
221- rainfall\n\
222- cloud cover\n\
223- significant wave height and direction\n\
224- air surface temperature (at 2 m)\n\
225- sea surface temperature\n\
226- surface current direction and speed\n\
227- Convective Available Potential Energy (CAPE)\n\
228- wind, altitude, temperature and relative humidity at 300, 500, 700, 850 hPa.");
229}
230
232
233int GribPi::GetToolBarToolCount() { return 1; }
234
235bool GribPi::MouseEventHook(wxMouseEvent &event) {
236 if ((m_pGribCtrlBar && m_pGribCtrlBar->pReq_Dialog))
237 return m_pGribCtrlBar->pReq_Dialog->MouseEventHook(event);
238 return false;
239}
240
241void GribPi::ShowPreferencesDialog(wxWindow *parent) {
242 auto *Pref = new GribPreferencesDialog(parent);
243
244 DimeWindow(Pref); // aplly global colours scheme
245 SetDialogFont(Pref); // Apply global font
246
247 Pref->m_cbUseHiDef->SetValue(m_bGRIBUseHiDef);
248 Pref->m_cbUseGradualColors->SetValue(m_bGRIBUseGradualColors);
249 Pref->m_cbDrawBarbedArrowHead->SetValue(m_bDrawBarbedArrowHead);
250 Pref->m_cZoomToCenterAtInit->SetValue(m_bZoomToCenterAtInit);
251 Pref->m_cbCopyFirstCumulativeRecord->SetValue(m_bCopyFirstCumRec);
252 Pref->m_cbCopyMissingWaveRecord->SetValue(m_bCopyMissWaveRec);
253 Pref->m_rbLoadOptions->SetSelection(m_bLoadLastOpenFile);
254 Pref->m_rbStartOptions->SetSelection(m_bStartOptions);
255
256 if (Pref->m_textDirectory) { // not present on Android
257 wxFileConfig *pConf = GetOCPNConfigObject();
258 if (pConf) {
259 wxString l_grib_dir;
260 pConf->SetPath("/Directories");
261 pConf->Read("GRIBDirectory", &l_grib_dir);
262 Pref->m_grib_dir_sel = l_grib_dir;
263 Pref->m_textDirectory->ChangeValue(l_grib_dir);
264 }
265 }
266
267#ifdef __WXMSW__
268 int val = (m_GribIconsScaleFactor * 10.) - 10;
269 Pref->m_sIconSizeFactor->SetValue(val);
270#endif
271
272#ifdef __ANDROID__
273 if (m_parent_window) {
274 int xmax = m_parent_window->GetSize().GetWidth();
275 int ymax = m_parent_window->GetParent()
276 ->GetSize()
277 .GetHeight(); // This would be the Options dialog itself
278 Pref->SetSize(xmax, ymax);
279 Pref->Layout();
280 Pref->Move(0, 0);
281 }
282 Pref->Show();
283#else
284 // Constrain size on small displays
285
286 int display_width, display_height;
287 wxDisplaySize(&display_width, &display_height);
288 int char_width = GetOCPNCanvasWindow()->GetCharWidth();
289 int char_height = GetOCPNCanvasWindow()->GetCharHeight();
290 if (display_height < 600) {
291 wxSize canvas_size = GetOCPNCanvasWindow()->GetSize();
292 Pref->SetMaxSize(GetOCPNCanvasWindow()->GetSize());
293 Pref->SetSize(wxSize(60 * char_width, canvas_size.x * 8 / 10));
294 Pref->CentreOnScreen();
295 } else {
296 Pref->SetMaxSize(GetOCPNCanvasWindow()->GetSize());
297 Pref->SetSize(wxSize(60 * char_width, 32 * char_height));
298 }
299
300 Pref->ShowModal();
301#endif
302}
303
304void GribPi::UpdatePrefs(GribPreferencesDialog *Pref) {
305 m_bGRIBUseHiDef = Pref->m_cbUseHiDef->GetValue();
306 m_bGRIBUseGradualColors = Pref->m_cbUseGradualColors->GetValue();
307 m_bLoadLastOpenFile = Pref->m_rbLoadOptions->GetSelection();
308 m_bDrawBarbedArrowHead = Pref->m_cbDrawBarbedArrowHead->GetValue();
309 m_bZoomToCenterAtInit = Pref->m_cZoomToCenterAtInit->GetValue();
310#ifdef __WXMSW__
311 double val = Pref->m_sIconSizeFactor->GetValue();
312 m_GribIconsScaleFactor = 1. + (val / 10);
313#endif
314
315 if (m_pGRIBOverlayFactory)
316 m_pGRIBOverlayFactory->SetSettings(m_bGRIBUseHiDef, m_bGRIBUseGradualColors,
317 m_bDrawBarbedArrowHead);
318
319 int updatelevel = 0;
320
321 if (m_bStartOptions != Pref->m_rbStartOptions->GetSelection()) {
322 m_bStartOptions = Pref->m_rbStartOptions->GetSelection();
323 updatelevel = 1;
324 }
325
326 bool copyrec = Pref->m_cbCopyFirstCumulativeRecord->GetValue();
327 bool copywave = Pref->m_cbCopyMissingWaveRecord->GetValue();
328 if (m_bCopyFirstCumRec != copyrec || m_bCopyMissWaveRec != copywave) {
329 m_bCopyFirstCumRec = copyrec;
330 m_bCopyMissWaveRec = copywave;
331 updatelevel = 3;
332 }
333
334 if (m_pGribCtrlBar) {
335 switch (updatelevel) {
336 case 0:
337 break;
338 case 3:
339 // rebuild current activefile with new parameters and rebuil data list
340 // with current index
341 m_pGribCtrlBar->CreateActiveFileFromNames(
342 m_pGribCtrlBar->m_bGRIBActiveFile->GetFileNames());
343 m_pGribCtrlBar->PopulateComboDataList();
344 m_pGribCtrlBar->TimelineChanged();
345 break;
346 case 2:
347 // only rebuild data list with current index and new timezone
348 // This no longer applicable because the timezone is set in the
349 // OpenCPN core global settings (Options -> Display -> General)
350 m_pGribCtrlBar->PopulateComboDataList();
351 m_pGribCtrlBar->TimelineChanged();
352 break;
353 case 1:
354 // only re-compute the best forecast
355 m_pGribCtrlBar->ComputeBestForecastForNow();
356 break;
357 }
358 if (Pref->m_grib_dir_sel.Length()) {
359 m_pGribCtrlBar->m_grib_dir = Pref->m_grib_dir_sel;
360 m_pGribCtrlBar->m_file_names.Clear();
361 }
362 }
363
364 if (Pref->m_grib_dir_sel.Length()) {
365 wxFileConfig *pConf = GetOCPNConfigObject();
366 if (pConf) {
367 pConf->SetPath("/Directories");
368 pConf->Write("GRIBDirectory", Pref->m_grib_dir_sel);
369 pConf->DeleteGroup("/Settings/GRIB/FileNames");
370 pConf->Flush();
371 }
372 }
373 SaveConfig();
374}
375
376bool GribPi::QualifyCtrlBarPosition(
377 wxPoint position,
378 wxSize size) { // Make sure drag bar (title bar) or grabber always screen
379 bool b_reset_pos = false;
380#ifdef __WXMSW__
381 // Support MultiMonitor setups which an allow negative window positions.
382 // If the requested window does not intersect any installed monitor,
383 // then default to simple primary monitor positioning.
384 RECT frame_title_rect;
385 frame_title_rect.left = position.x;
386 frame_title_rect.top = position.y;
387 frame_title_rect.right = position.x + size.x;
388 frame_title_rect.bottom = m_DialogStyle == ATTACHED_HAS_CAPTION
389 ? position.y + 30
390 : position.y + size.y;
391
392 if (nullptr == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
393 b_reset_pos = true;
394#else
395 wxRect window_title_rect; // conservative estimate
396 window_title_rect.x = position.x;
397 window_title_rect.y = position.y;
398 window_title_rect.width = size.x;
399 window_title_rect.height =
400 m_DialogStyle == ATTACHED_HAS_CAPTION ? 30 : size.y;
401
402 wxRect ClientRect = wxGetClientDisplayRect();
403 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos = true;
404
405#endif
406 return !b_reset_pos;
407}
408
409void GribPi::MoveDialog(wxDialog *dialog, wxPoint position) {
410 // Use the application frame to bound the control bar position.
411 wxApp *app = wxTheApp;
412
413 wxWindow *frame =
414 app->GetTopWindow(); // or GetOCPNCanvasWindow()->GetParent();
415 if (!frame) return;
416
417 wxPoint p = frame->ScreenToClient(position);
418 // Check and ensure there is always a "grabb" zone always visible wathever the
419 // dialoue size is.
420 if (p.x + dialog->GetSize().GetX() > frame->GetClientSize().GetX())
421 p.x = frame->GetClientSize().GetX() - dialog->GetSize().GetX();
422 if (p.y + dialog->GetSize().GetY() > frame->GetClientSize().GetY())
423 p.y = frame->GetClientSize().GetY() - dialog->GetSize().GetY();
424
425#ifdef __WXGTK__
426 dialog->Move(0, 0);
427#endif
428 dialog->Move(frame->ClientToScreen(p));
429}
430
432 // if( !::wxIsBusy() ) ::wxBeginBusyCursor();
433
434 bool starting = false;
435
436 double scale_factor =
438#ifdef __WXMSW__
439 scale_factor *= m_GribIconsScaleFactor;
440#endif
441 if (scale_factor != m_GUIScaleFactor) starting = true;
442
443 if (!m_pGribCtrlBar) {
444 starting = true;
445 long style = m_DialogStyle == ATTACHED_HAS_CAPTION
446 ? wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU
447 : wxBORDER_NONE | wxSYSTEM_MENU;
448#ifdef __WXOSX__
449 style |= wxSTAY_ON_TOP;
450#endif
451 m_pGribCtrlBar = new GRIBUICtrlBar(m_parent_window, wxID_ANY, wxEmptyString,
452 wxDefaultPosition, wxDefaultSize, style,
453 this, scale_factor);
454 m_pGribCtrlBar->SetScaledBitmap(scale_factor);
455
456 auto *dummy = new wxMenu("Plugin");
457 auto *table = new wxMenuItem(dummy, wxID_ANY, wxString(_("Weather table")),
458 wxEmptyString, wxITEM_NORMAL);
459 /* Menu font do not work properly for MSW (wxWidgets 3.2.1)
460 #ifdef __WXMSW__
461 wxFont *qFont = OCPNGetFont(_("Menu"));
462 table->SetFont(*qFont);
463 #endif
464 */
465 m_MenuItem = AddCanvasContextMenuItem(table, this);
466 SetCanvasContextMenuItemViz(m_MenuItem, false);
467
468 // Create the drawing factory
469 m_pGRIBOverlayFactory = new GRIBOverlayFactory(*m_pGribCtrlBar);
470 m_pGRIBOverlayFactory->SetMessageFont();
471 m_pGRIBOverlayFactory->SetParentSize(m_display_width, m_display_height);
472 m_pGRIBOverlayFactory->SetSettings(m_bGRIBUseHiDef, m_bGRIBUseGradualColors,
473 m_bDrawBarbedArrowHead);
474
475 m_pGribCtrlBar->OpenFile(m_bLoadLastOpenFile == 0);
476 }
477
478 // Toggle GRIB overlay display
479 if (id >= 0) m_bShowGrib = !m_bShowGrib;
480
481 // Toggle dialog?
482 if (m_bShowGrib || id < 0) {
483 // A new file could have been added since grib plugin opened
484 if (!starting && m_bLoadLastOpenFile == 0) {
485 m_pGribCtrlBar->OpenFile(true);
486 starting = true;
487 }
488 // the dialog font could have been changed since grib plugin opened
489 if (m_pGribCtrlBar->GetFont() != *OCPNGetFont(_("Dialog"))) starting = true;
490 if (starting) {
491 m_pGRIBOverlayFactory->SetMessageFont();
492 SetDialogFont(m_pGribCtrlBar);
493 m_GUIScaleFactor = scale_factor;
494 m_pGribCtrlBar->SetScaledBitmap(m_GUIScaleFactor);
495 m_pGribCtrlBar->SetDialogsStyleSizePosition(true);
496 m_pGribCtrlBar->Refresh();
497 } else {
498 MoveDialog(m_pGribCtrlBar, GetCtrlBarXY());
499 if (m_DialogStyle >> 1 == SEPARATED) {
500 MoveDialog(m_pGribCtrlBar->GetCDataDialog(), GetCursorDataXY());
501 m_pGribCtrlBar->GetCDataDialog()->Show(m_pGribCtrlBar->m_CDataIsShown);
502 }
503#ifdef __ANDROID__
504 m_pGribCtrlBar->SetDialogsStyleSizePosition(true);
505 m_pGribCtrlBar->Refresh();
506#endif
507 }
508 if (id >= 0) m_pGribCtrlBar->Show();
509 if (m_pGribCtrlBar->m_bGRIBActiveFile) {
510 if (m_pGribCtrlBar->m_bGRIBActiveFile->IsOK()) {
511 ArrayOfGribRecordSets *rsa =
512 m_pGribCtrlBar->m_bGRIBActiveFile->GetRecordSetArrayPtr();
513 if (rsa->GetCount() > 1) {
514 SetCanvasContextMenuItemViz(m_MenuItem, true);
515 }
516 if (rsa->GetCount() >= 1) { // XXX Should be only on Show
517 SendTimelineMessage(m_pGribCtrlBar->TimelineTime());
518 }
519 }
520 }
521 // Toggle is handled by the CtrlBar but we must keep plugin manager b_toggle
522 // updated to actual status to ensure correct status upon CtrlBar rebuild
523 SetToolbarItemState(m_leftclick_tool_id, m_bShowGrib);
524
525 // Do an automatic "zoom-to-center" on the overlay canvas if set in
526 // Preferences
527 if (m_pGribCtrlBar && m_bZoomToCenterAtInit) {
528 m_pGribCtrlBar->DoZoomToCenter();
529 }
530
531 RequestRefresh(m_parent_window); // refresh main window
532 } else
533 m_pGribCtrlBar->Close();
534}
535
536void GribPi::OnGribCtrlBarClose() {
537 m_bShowGrib = false;
538 SetToolbarItemState(m_leftclick_tool_id, m_bShowGrib);
539
540 m_pGribCtrlBar->Hide();
541
542 SaveConfig();
543
544 SetCanvasContextMenuItemViz(m_MenuItem, false);
545
546 RequestRefresh(m_parent_window); // refresh main window
547
548 if (::wxIsBusy()) ::wxEndBusyCursor();
549
550#ifdef __ANDROID__
551 m_DialogStyleChanged = true; // Force a delete of the control bar dialog
552#endif
553
554 if (m_DialogStyleChanged) {
555 m_pGribCtrlBar->Destroy();
556 m_pGribCtrlBar = nullptr;
557 m_DialogStyleChanged = false;
558 }
559}
560
561bool GribPi::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp) { return false; }
562
563bool GribPi::DoRenderOverlay(wxDC &dc, PlugIn_ViewPort *vp, int canvasIndex) {
564 if (!m_pGribCtrlBar || !m_pGribCtrlBar->IsShown() || !m_pGRIBOverlayFactory)
565 return false;
566
567 m_pGRIBOverlayFactory->RenderGribOverlay(dc, vp);
568 if (PluginGetFocusCanvas() == GetCanvasByIndex(canvasIndex)) {
569 m_pGribCtrlBar->SetViewPortWithFocus(vp);
570 }
571
572 if (GetCanvasByIndex(canvasIndex) == GetCanvasUnderMouse()) {
573 m_pGribCtrlBar->SetViewPortUnderMouse(vp);
574 if (m_pGribCtrlBar->pReq_Dialog &&
576 m_pGribCtrlBar->pReq_Dialog->GetBoundingBoxCanvasIndex()) {
577 m_pGribCtrlBar->pReq_Dialog->RenderZoneOverlay(dc);
578 }
579 }
580 if (::wxIsBusy()) ::wxEndBusyCursor();
581 return true;
582}
583
584bool GribPi::RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp) {
585 return false;
586}
587
588bool GribPi::DoRenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp,
589 int canvasIndex) {
590 if (!m_pGribCtrlBar || !m_pGribCtrlBar->IsShown() || !m_pGRIBOverlayFactory)
591 return false;
592
593 m_pGRIBOverlayFactory->RenderGLGribOverlay(pcontext, vp);
594 if (PluginGetFocusCanvas() == GetCanvasByIndex(canvasIndex)) {
595 m_pGribCtrlBar->SetViewPortWithFocus(vp);
596 }
597
598 if (GetCanvasByIndex(canvasIndex) == GetCanvasUnderMouse()) {
599 m_pGribCtrlBar->SetViewPortUnderMouse(vp);
600 if (m_pGribCtrlBar->pReq_Dialog &&
602 m_pGribCtrlBar->pReq_Dialog->GetBoundingBoxCanvasIndex()) {
603 m_pGribCtrlBar->pReq_Dialog->RenderGlZoneOverlay();
604 }
605 }
606
607 if (::wxIsBusy()) ::wxEndBusyCursor();
608
609#ifdef __ANDROID__
610 m_pGribCtrlBar->Raise(); // Control bar should always be visible
611#endif
612
613 return true;
614}
615
616bool GribPi::RenderGLOverlayMultiCanvas(wxGLContext *pcontext,
617 PlugIn_ViewPort *vp, int canvasIndex) {
618 return DoRenderGLOverlay(pcontext, vp, canvasIndex);
619}
620
622 int canvasIndex) {
623 return DoRenderOverlay(dc, vp, canvasIndex);
624}
625
626void GribPi::SetCursorLatLon(double lat, double lon) {
627 if (m_pGribCtrlBar && m_pGribCtrlBar->IsShown())
628 m_pGribCtrlBar->SetCursorLatLon(lat, lon);
629}
630
632 if (!m_pGribCtrlBar->m_bGRIBActiveFile) return;
633 m_pGribCtrlBar->ContextMenuItemCallback(id);
634}
635
636void GribPi::SetDialogFont(wxWindow *dialog, wxFont *font) {
637 dialog->SetFont(*font);
638 wxWindowList list = dialog->GetChildren();
639 wxWindowList::compatibility_iterator node = list.GetFirst();
640 for (size_t i = 0; i < list.GetCount(); i++) {
641 wxWindow *win = node->GetData();
642 win->SetFont(*font);
643 node = node->GetNext();
644 }
645 dialog->Fit();
646 dialog->Refresh();
647}
648
649void GribPi::SetPluginMessage(wxString &message_id, wxString &message_body) {
650 if (message_id == "GRIB_VALUES_REQUEST") {
651 if (!m_pGribCtrlBar) OnToolbarToolCallback(-1);
652
653 // lat, lon, time, what
654 wxJSONReader r;
655 wxJSONValue v;
656 r.Parse(message_body, &v);
657 if (!v.HasMember("Day")) {
658 // bogus or loading grib
659 SendPluginMessage(wxString("GRIB_VALUES"), "");
660 return;
661 }
662 wxDateTime time(v["Day"].AsInt(), (wxDateTime::Month)v["Month"].AsInt(),
663 v["Year"].AsInt(), v["Hour"].AsInt(), v["Minute"].AsInt(),
664 v["Second"].AsInt());
665 double lat = v["lat"].AsDouble();
666 double lon = v["lon"].AsDouble();
667
668 if (m_pGribCtrlBar) {
669 if (v.HasMember("WIND SPEED")) {
670 double vkn, ang;
671 if (m_pGribCtrlBar->getTimeInterpolatedValues(
672 vkn, ang, Idx_WIND_VX, Idx_WIND_VY, lon, lat, time) &&
673 vkn != GRIB_NOTDEF) {
674 v["Type"] = wxString("Reply");
675 v["WIND SPEED"] = vkn;
676 v["WIND DIR"] = ang;
677 } else {
678 v.Remove("WIND SPEED");
679 v.Remove("WIND DIR");
680 }
681 }
682 if (v.HasMember("CURRENT SPEED")) {
683 double vkn, ang;
684 if (m_pGribCtrlBar->getTimeInterpolatedValues(
685 vkn, ang, Idx_SEACURRENT_VX, Idx_SEACURRENT_VY, lon, lat,
686 time) &&
687 vkn != GRIB_NOTDEF) {
688 v["Type"] = wxString("Reply");
689 v["CURRENT SPEED"] = vkn;
690 v["CURRENT DIR"] = ang;
691 } else {
692 v.Remove("CURRENT SPEED");
693 v.Remove("CURRENT DIR");
694 }
695 }
696 if (v.HasMember("GUST")) {
697 double vkn = m_pGribCtrlBar->getTimeInterpolatedValue(Idx_WIND_GUST,
698 lon, lat, time);
699 if (vkn != GRIB_NOTDEF) {
700 v["Type"] = wxString("Reply");
701 v["GUST"] = vkn;
702 } else
703 v.Remove("GUST");
704 }
705 if (v.HasMember("SWELL")) {
706 double vkn = m_pGribCtrlBar->getTimeInterpolatedValue(Idx_HTSIGW, lon,
707 lat, time);
708 if (vkn != GRIB_NOTDEF) {
709 v["Type"] = wxString("Reply");
710 v["SWELL"] = vkn;
711 } else
712 v.Remove("SWELL");
713 }
714
715 wxJSONWriter w;
716 wxString out;
717 w.Write(v, out);
718 SendPluginMessage(wxString("GRIB_VALUES"), out);
719 }
720 } else if (message_id == "GRIB_VERSION_REQUEST") {
721 wxJSONValue v;
722 v["GribVersionMinor"] = GetAPIVersionMinor();
723 v["GribVersionMajor"] = GetAPIVersionMajor();
724
725 wxJSONWriter w;
726 wxString out;
727 w.Write(v, out);
728 SendPluginMessage(wxString("GRIB_VERSION"), out);
729 } else if (message_id == "GRIB_TIMELINE_REQUEST") {
730 // local time
731 SendTimelineMessage(m_pGribCtrlBar ? m_pGribCtrlBar->TimelineTime()
732 : wxDateTime::Now());
733 } else if (message_id == "GRIB_TIMELINE_RECORD_REQUEST") {
734 wxJSONReader r;
735 wxJSONValue v;
736 r.Parse(message_body, &v);
737 wxDateTime time(v["Day"].AsInt(), (wxDateTime::Month)v["Month"].AsInt(),
738 v["Year"].AsInt(), v["Hour"].AsInt(), v["Minute"].AsInt(),
739 v["Second"].AsInt());
740
741 if (!m_pGribCtrlBar) OnToolbarToolCallback(-1);
742
744 m_pGribCtrlBar ? m_pGribCtrlBar->GetTimeLineRecordSet(time) : nullptr;
745
746 char ptr[64];
747 snprintf(ptr, sizeof ptr, "%p", set);
748
749 v["GribVersionMajor"] = PLUGIN_VERSION_MAJOR;
750 v["GribVersionMinor"] = PLUGIN_VERSION_MINOR;
751 v["TimelineSetPtr"] = wxString::From8BitData(ptr);
752
753 wxJSONWriter w;
754 wxString out;
755 w.Write(v, out);
756 SendPluginMessage(wxString("GRIB_TIMELINE_RECORD"), out);
757 delete m_pLastTimelineSet;
758 m_pLastTimelineSet = set;
759 }
760
761 else if (message_id == "GRIB_APPLY_JSON_CONFIG") {
762 wxLogMessage("Got GRIB_APPLY_JSON_CONFIG");
763
764 if (m_pGribCtrlBar) {
765 m_pGribCtrlBar->OpenFileFromJSON(message_body);
766
767 m_pGribCtrlBar->m_OverlaySettings.JSONToSettings(message_body);
768 m_pGribCtrlBar->m_OverlaySettings.Write();
769 m_pGribCtrlBar->SetDialogsStyleSizePosition(true);
770 }
771 }
772}
773
774bool GribPi::LoadConfig() {
775 auto *pConf = (wxFileConfig *)m_pconfig;
776
777 if (!pConf) return false;
778
779 pConf->SetPath("/PlugIns/GRIB");
780 pConf->Read("LoadLastOpenFile", &m_bLoadLastOpenFile, 0);
781 pConf->Read("OpenFileOption", &m_bStartOptions, 1);
782 pConf->Read("GRIBUseHiDef", &m_bGRIBUseHiDef, false);
783 pConf->Read("GRIBUseGradualColors", &m_bGRIBUseGradualColors, false);
784 pConf->Read("DrawBarbedArrowHead", &m_bDrawBarbedArrowHead, true);
785 pConf->Read("ZoomToCenterAtInit", &m_bZoomToCenterAtInit, true);
786 pConf->Read("ShowGRIBIcon", &m_bGRIBShowIcon, true);
787 pConf->Read("CopyFirstCumulativeRecord", &m_bCopyFirstCumRec, true);
788 pConf->Read("CopyMissingWaveRecord", &m_bCopyMissWaveRec, true);
789#ifdef __WXMSW__
790 pConf->Read("GribIconsScaleFactor", &m_GribIconsScaleFactor, 1);
791#endif
792
793 m_CtrlBar_Sizexy.x = pConf->Read("GRIBCtrlBarSizeX", 1400L);
794 m_CtrlBar_Sizexy.y = pConf->Read("GRIBCtrlBarSizeY", 800L);
795 m_CtrlBarxy.x = pConf->Read("GRIBCtrlBarPosX", 20L);
796 m_CtrlBarxy.y = pConf->Read("GRIBCtrlBarPosY", 60L);
797 m_CursorDataxy.x = pConf->Read("GRIBCursorDataPosX", 20L);
798 m_CursorDataxy.y = pConf->Read("GRIBCursorDataPosY", 170L);
799
800 pConf->Read("GribCursorDataDisplayStyle", &m_DialogStyle, 0);
801 if (m_DialogStyle > 3)
802 m_DialogStyle = 0; // ensure validity of the .conf value
803
804 return true;
805}
806
807bool GribPi::SaveConfig(void) {
808 wxFileConfig *pConf = (wxFileConfig *)m_pconfig;
809
810 if (!pConf) return false;
811
812 pConf->SetPath("/PlugIns/GRIB");
813
814 pConf->Write("LoadLastOpenFile", m_bLoadLastOpenFile);
815 pConf->Write("OpenFileOption", m_bStartOptions);
816 pConf->Write("ShowGRIBIcon", m_bGRIBShowIcon);
817 pConf->Write("GRIBUseHiDef", m_bGRIBUseHiDef);
818 pConf->Write("GRIBUseGradualColors", m_bGRIBUseGradualColors);
819 pConf->Write("CopyFirstCumulativeRecord", m_bCopyFirstCumRec);
820 pConf->Write("CopyMissingWaveRecord", m_bCopyMissWaveRec);
821 pConf->Write("DrawBarbedArrowHead", m_bDrawBarbedArrowHead);
822 pConf->Write("ZoomToCenterAtInit", m_bZoomToCenterAtInit);
823#ifdef __WXMSW__
824 pConf->Write("GribIconsScaleFactor", m_GribIconsScaleFactor);
825#endif
826
827 pConf->Write("GRIBCtrlBarSizeX", m_CtrlBar_Sizexy.x);
828 pConf->Write("GRIBCtrlBarSizeY", m_CtrlBar_Sizexy.y);
829 pConf->Write("GRIBCtrlBarPosX", m_CtrlBarxy.x);
830 pConf->Write("GRIBCtrlBarPosY", m_CtrlBarxy.y);
831 pConf->Write("GRIBCursorDataPosX", m_CursorDataxy.x);
832 pConf->Write("GRIBCursorDataPosY", m_CursorDataxy.y);
833
834 return true;
835}
836
838 DimeWindow(m_pGribCtrlBar);
839 if (m_pGribCtrlBar) {
840 if (m_pGRIBOverlayFactory) m_pGRIBOverlayFactory->ClearCachedLabel();
841 if (m_pGribCtrlBar->pReq_Dialog) m_pGribCtrlBar->pReq_Dialog->Refresh();
842 m_pGribCtrlBar->Refresh();
843 // m_pGribDialog->SetDataBackGroundColor();
844 }
845}
846
847void GribPi::SendTimelineMessage(wxDateTime time) {
848 if (!m_pGribCtrlBar) return;
849
850 wxJSONValue v;
851 if (time.IsValid()) {
852 v["Day"] = time.GetDay();
853 v["Month"] = time.GetMonth();
854 v["Year"] = time.GetYear();
855 v["Hour"] = time.GetHour();
856 v["Minute"] = time.GetMinute();
857 v["Second"] = time.GetSecond();
858 } else {
859 v["Day"] = -1;
860 v["Month"] = -1;
861 v["Year"] = -1;
862 v["Hour"] = -1;
863 v["Minute"] = -1;
864 v["Second"] = -1;
865 }
866 wxJSONWriter w;
867 wxString out;
868 w.Write(v, out);
869 SendPluginMessage(wxString("GRIB_TIMELINE"), out);
870}
871
873 m_boat_cog = pfix.Cog;
874 m_boat_sog = pfix.Sog;
875 m_boat_lat = pfix.Lat;
876 m_boat_lon = pfix.Lon;
877 if (pfix.FixTime != 0) {
878 m_boat_time = pfix.FixTime;
879 } else {
880 m_boat_time = wxDateTime::Now().GetTicks();
881 }
882}
883
884//----------------------------------------------------------------------------------------------------------
885// Prefrence dialog Implementation
886//----------------------------------------------------------------------------------------------------------
887void GribPreferencesDialog::OnStartOptionChange(wxCommandEvent &event) {
888 if (m_rbStartOptions->GetSelection() == 2) {
890 this,
891 _("You have chosen to authorize interpolation.\nDon't forget that data "
892 "displayed at current time will not be real but Recomputed\nThis can "
893 "decrease accuracy!"),
894 _("Warning!"));
895 }
896}
897
898void GribPreferencesDialog::OnOKClick(wxCommandEvent &event) {
899 if (g_pi) g_pi->UpdatePrefs(this);
900 Close();
901}
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:621
void OnContextMenuItemCallback(int id) override
Handles context menu item selection.
Definition grib_pi.cpp:631
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:616
void SetDefaults() override
Sets plugin default options.
Definition grib_pi.cpp:231
void ShowPreferencesDialog(wxWindow *parent) override
Shows the plugin preferences dialog.
Definition grib_pi.cpp:241
int GetPlugInVersionMajor() override
Returns the major version number of the plugin itself.
Definition grib_pi.cpp:202
wxString GetShortDescription() override
Get a brief description of the plugin.
Definition grib_pi.cpp:210
wxString GetLongDescription() override
Get detailed plugin information.
Definition grib_pi.cpp:212
bool MouseEventHook(wxMouseEvent &event) override
Handles mouse events from chart window.
Definition grib_pi.cpp:235
void SetPositionFixEx(PlugIn_Position_Fix_Ex &pfix) override
Updates plugin with extended position fix data at regular intervals.
Definition grib_pi.cpp:872
int GetAPIVersionMajor() override
Returns the major version number of the plugin API that this plugin supports.
Definition grib_pi.cpp:198
int GetAPIVersionMinor() override
Returns the minor version number of the plugin API that this plugin supports.
Definition grib_pi.cpp:200
bool DeInit() override
Clean up plugin resources.
Definition grib_pi.cpp:182
void SetColorScheme(PI_ColorScheme cs) override
Updates plugin color scheme.
Definition grib_pi.cpp:837
void OnToolbarToolCallback(int id) override
Handles toolbar tool clicks.
Definition grib_pi.cpp:431
wxBitmap * GetPlugInBitmap() override
Get the plugin's icon bitmap.
Definition grib_pi.cpp:206
void SetCursorLatLon(double lat, double lon) override
Receives cursor lat/lon position updates.
Definition grib_pi.cpp:626
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:208
bool RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp) override
Renders plugin overlay graphics in OpenGL mode for single canvas.
Definition grib_pi.cpp:584
int GetPlugInVersionMinor() override
Returns the minor version number of the plugin itself.
Definition grib_pi.cpp:204
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:134
#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:93
#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:89
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.