1 /******************************************************************************
2  *
3  * Project:  OpenCPN
4  * Purpose:  GRIB Object
5  * Author:   David Register
6  *
7  ***************************************************************************
8  *   Copyright (C) 2010 by David S. Register   *
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program; if not, write to the                         *
22  *   Free Software Foundation, Inc.,                                       *
23  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
24  ***************************************************************************
25  *
26  */
27 #include "grib_pi.h"
28 
29 #include "folder.xpm"
30 
31 extern int m_Altitude;
32 extern double m_cursor_lat, m_cursor_lon;
33 extern int m_DialogStyle;
34 
35 enum SettingsDisplay {B_ARROWS, ISO_LINE, ISO_ABBR, D_ARROWS, OVERLAY, NUMBERS, PARTICLES};
36 
37 //---------------------------------------------------------------------------------------
38 //               GRIB Cursor Data  implementation
39 //---------------------------------------------------------------------------------------
CursorData(wxWindow * window,GRIBUICtrlBar & parent)40 CursorData::CursorData( wxWindow *window, GRIBUICtrlBar &parent )
41 		: CursorDataBase(window),m_gparent(parent)
42 {
43 
44 	//transform checkboxes ID to have a formal link to data type and set the initial value
45     wxWindowListNode *node =  this->GetChildren().GetFirst();
46     while( node ) {
47         wxWindow *win = node->GetData();
48         if( win->IsKindOf(CLASSINFO(wxCheckBox)) ) {
49 			int winId = ((wxCheckBox*) win )->GetId() - ID_CB_WIND;
50 			if (m_gparent.InDataPlot(winId)) {
51 			    ((wxCheckBox*) win )->SetId( winId );
52 			    ((wxCheckBox*) win )->SetValue( m_gparent.m_bDataPlot[winId] );
53             }
54 		}
55 		node = node->GetNext();
56 	}
57 
58     m_bLeftDown = false;
59 
60     m_tCursorTrackTimer.Connect(wxEVT_TIMER, wxTimerEventHandler( CursorData::OnCursorTrackTimer ), NULL, this);
61 
62 	DimeWindow( this );
63 }
64 
OnCBAny(wxCommandEvent & event)65 void CursorData::OnCBAny( wxCommandEvent& event )
66 {
67 	int id = event.GetId();
68 	wxWindow *win = this->FindWindow( id );
69 	if (m_gparent.InDataPlot(id))
70 	    m_gparent.m_bDataPlot[id] = ((wxCheckBox*) win )->IsChecked();
71     ResolveDisplayConflicts( id );
72 }
73 
ResolveDisplayConflicts(int Id)74 void CursorData::ResolveDisplayConflicts( int Id )
75 {
76     //allow multi selection only if there is no display type superposition
77 	for( int i = 0; i < GribOverlaySettings::GEO_ALTITUDE; i++ ) {
78 		if( i != Id && m_gparent.m_bDataPlot[i] ) {
79 			if( (m_gparent.m_OverlaySettings.Settings[Id].m_bBarbedArrows &&
80 					m_gparent.m_OverlaySettings.Settings[i].m_bBarbedArrows)
81 					|| (m_gparent.m_OverlaySettings.Settings[Id].m_bDirectionArrows &&
82 					m_gparent.m_OverlaySettings.Settings[i].m_bDirectionArrows)
83 					|| (m_gparent.m_OverlaySettings.Settings[Id].m_bIsoBars &&
84 					m_gparent.m_OverlaySettings.Settings[i].m_bIsoBars)
85 					|| (m_gparent.m_OverlaySettings.Settings[Id].m_bNumbers &&
86 					m_gparent.m_OverlaySettings.Settings[i].m_bNumbers)
87 					|| (m_gparent.m_OverlaySettings.Settings[Id].m_bOverlayMap &&
88 					m_gparent.m_OverlaySettings.Settings[i].m_bOverlayMap)
89 					|| (m_gparent.m_OverlaySettings.Settings[Id].m_bParticles &&
90 					m_gparent.m_OverlaySettings.Settings[i].m_bParticles) ) {
91 				m_gparent.m_bDataPlot[i] = false;
92 				wxWindow *win = FindWindow(i);
93 				((wxCheckBox*) win )->SetValue( false );
94 			}
95 		}
96 	}
97     m_gparent.SetFactoryOptions();                     // Reload the visibility options
98 }
99 
AddTrackingControl(wxControl * ctrl1,wxControl * ctrl2,wxControl * ctrl3,wxControl * ctrl4,bool show,bool vertical,int wctrl2,int wctrl3_4)100 void CursorData::AddTrackingControl( wxControl *ctrl1,  wxControl *ctrl2,  wxControl *ctrl3, wxControl *ctrl4, bool show,
101         bool vertical, int wctrl2, int wctrl3_4)
102 {
103     if(show) {
104         m_fgTrackingControls->Add(ctrl1, 0, wxALL, 1);
105         ctrl1->Show();
106         if(ctrl2) {
107             m_fgTrackingControls->Add(ctrl2, 0, wxALL, 0);
108             ctrl2->SetMinSize(wxSize(wctrl2, -1));
109             ctrl2->Show();
110         } else
111               m_fgTrackingControls->Add(0, 0, 1, wxALL, 1); /* spacer */
112 
113         if(ctrl3) {
114             long flag1 = wxALIGN_CENTER;
115             long flag  = vertical? flag1: wxALL;
116             m_fgTrackingControls->Add(ctrl3, 0, flag, 0);
117             ctrl3->SetMinSize(wxSize(wctrl3_4, -1));
118             ctrl3->Show();
119         } else
120             if( !vertical ) m_fgTrackingControls->Add(0, 0, 1, wxALL, 1); /* spacer */
121 
122         if(ctrl4) {
123             m_fgTrackingControls->Add(ctrl4, 0, wxALL, 0);
124             ctrl4->SetMinSize(wxSize(vertical? wctrl2: wctrl3_4, -1));
125             ctrl4->Show();
126         } else
127             if( !vertical ) m_fgTrackingControls->Add(0, 0, 1, wxALL, 1 ); /* spacer */
128 
129     } else {
130         if(ctrl1) ctrl1->Hide();
131         if(ctrl2) ctrl2->Hide();
132         if(ctrl3) ctrl3->Hide();
133         if(ctrl4) ctrl4->Hide();
134     }
135 }
136 
PopulateTrackingControls(bool vertical)137 void CursorData::PopulateTrackingControls( bool vertical )
138 {
139     m_fgTrackingControls->Clear();
140     if(!vertical){
141         wxFlexGridSizer *ps = (wxFlexGridSizer*)(m_gparent.GetSizer());
142         if(ps && (ps->GetCols() == 1))
143             m_fgTrackingControls->SetCols( 4 );         // compact mode
144         else
145             m_fgTrackingControls->SetCols( 12 );
146     }
147     else
148         m_fgTrackingControls->SetCols( 2 );
149 
150     this->Fit();
151     //Get text controls sizing data
152     wxFont *font = OCPNGetFont(_("Dialog"), 10);
153     int wn, wd, ws,wl;
154     GetTextExtent( _T("abcdefghihjk"), &wn, NULL, 0, 0, font); // normal width text control size
155     GetTextExtent( _T("abcdef"), &ws, NULL, 0, 0, font); // short width text control size for direction only
156     GetTextExtent( _T("abcdefghijklmopq"), &wd, NULL, 0, 0, font); // long width text control size for double unit wind display
157     GetTextExtent( _T("abcdefghijklm"), &wl, NULL, 0, 0, font); // long width text control size for double unit wave display
158     //
159     //create a dummy textCtrl to be used as a "space" in vertical display
160     wxTextCtrl *dummy = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY|wxNO_BORDER );
161     //
162     bool bf = m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::WIND].m_Units == GribOverlaySettings::BFS;
163     wd = vertical ? wn: bf? wn: wd;
164     wl = vertical? wn : wl;
165 
166     AddTrackingControl(m_cbWind, m_tcWindSpeed, m_tcWindSpeedBf, m_tcWindDirection, false, vertical, 0, 0 ); //hide all wind's parameters
167     AddTrackingControl(m_cbWind, m_tcWindSpeed, vertical? (bf? dummy : m_tcWindSpeedBf): m_tcWindDirection, vertical? m_tcWindDirection: 0,
168         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VX) != wxNOT_FOUND
169         && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VY) != wxNOT_FOUND, vertical, wd, ws);
170     AddTrackingControl(m_cbWindGust, m_tcWindGust, 0, 0, m_gparent.m_pTimelineSet
171         && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_GUST) != wxNOT_FOUND
172 		&& m_Altitude == 0, vertical, wn);
173     AddTrackingControl(m_cbPressure, m_tcPressure, 0, 0, m_gparent.m_pTimelineSet
174         && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_PRESSURE) != wxNOT_FOUND
175 		&& m_Altitude == 0, vertical, wn);
176 
177     /* tracking for wave is funky */
178     AddTrackingControl(m_cbWave, m_tcWaveHeight, m_tcWavePeriode, m_tcWaveDirection, false, vertical, 0, 0); //hide all waves's parameters
179     if(m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_HTSIGW) != wxNOT_FOUND) {
180         if(m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WVDIR) != wxNOT_FOUND)
181             AddTrackingControl(m_cbWave, m_tcWaveHeight, vertical? m_tcWavePeriode: m_tcWaveDirection,
182                     vertical? m_tcWaveDirection: 0 , m_Altitude == 0, vertical, wl, ws);
183         else
184             AddTrackingControl(m_cbWave, m_tcWaveHeight, 0, 0, m_Altitude == 0, vertical, wn );
185     } else {
186         if(m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WVDIR) != wxNOT_FOUND)
187             AddTrackingControl(m_cbWave, m_tcWaveDirection, 0, 0, m_Altitude == 0, vertical, wn );
188     }
189 
190     AddTrackingControl(m_cbCurrent, m_tcCurrentVelocity, m_tcCurrentDirection, 0, false, vertical, 0, 0); //hide all current's parameters
191     AddTrackingControl(m_cbCurrent, m_tcCurrentVelocity, vertical? dummy: m_tcCurrentDirection, vertical? m_tcCurrentDirection: 0,
192         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_SEACURRENT_VX) != wxNOT_FOUND
193         && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_SEACURRENT_VY) != wxNOT_FOUND
194 		&& m_Altitude == 0, vertical, wn, ws);
195     AddTrackingControl(m_cbPrecipitation, m_tcPrecipitation, 0, 0,
196         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_PRECIP_TOT) != wxNOT_FOUND
197 		&& m_Altitude == 0, vertical, wn);
198     AddTrackingControl(m_cbCloud, m_tcCloud, 0, 0,
199         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_CLOUD_TOT) != wxNOT_FOUND
200 		&& m_Altitude == 0, vertical, wn);
201     AddTrackingControl(m_cbAirTemperature, m_tcAirTemperature, 0, 0,
202         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_AIR_TEMP) != wxNOT_FOUND
203 		&& m_Altitude == 0, vertical, wn);
204     AddTrackingControl(m_cbSeaTemperature, m_tcSeaTemperature, 0, 0,
205         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_SEA_TEMP) != wxNOT_FOUND
206 		&& m_Altitude == 0, vertical, wn);
207     AddTrackingControl(m_cbCAPE, m_tcCAPE, 0, 0,
208         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_CAPE) != wxNOT_FOUND
209 		&& m_Altitude == 0, vertical, wn);
210     AddTrackingControl(m_cbReflC, m_tcReflC, 0, 0,
211         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_COMP_REFL) != wxNOT_FOUND
212 		&& m_Altitude == 0, vertical, wn);
213     //
214     //init and show extra parameters for altitude tracking if necessary
215 	AddTrackingControl(m_cbAltitude, m_tcAltitude, 0, 0,
216         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_GEOP_HGT + m_Altitude) != wxNOT_FOUND
217 		&& m_Altitude != 0, vertical, wn);
218 	AddTrackingControl(m_cbTemp, m_tcTemp, 0, 0,
219         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_AIR_TEMP + m_Altitude) != wxNOT_FOUND
220 		&& m_Altitude != 0, vertical, wn);
221 	AddTrackingControl(m_cbRelHumid, m_tcRelHumid, 0, 0,
222         m_gparent.m_pTimelineSet && m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_HUMID_RE + m_Altitude) != wxNOT_FOUND
223 		&& m_Altitude != 0, vertical, wn);
224 	//
225     m_stTrackingText->SetLabel( _("Data at cursor position") );
226     //add tooltips
227     wxString t; double lev;
228 
229     lev = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::GEO_ALTITUDE, 10 );     //convert 10m in current altitude unit
230     t.Printf(
231         m_Altitude ? m_gparent.m_OverlaySettings.GetAltitudeFromIndex(
232                 m_Altitude, m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::PRESSURE].m_Units)
233                 .Append( _T(" ") ).Append( m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::PRESSURE) )
234            : wxString::Format( _T("%1.*f "), lev == (int) lev ? 0 : 1, lev )
235                 .Append( m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::GEO_ALTITUDE) )
236                 );
237     wxString pre = _T(" ");
238     if( m_Altitude ) {
239         pre.Append(_("at Geopotential Height"));
240         pre.Append(_T(" "));
241         m_tcAltitude->SetToolTip( _("Altitude" ) + t );
242         m_tcTemp->SetToolTip( _("Temperature") + t );
243         m_tcRelHumid->SetToolTip( _("Relative Humidity") + t );
244     } else{
245         pre.Append(_("at"));
246         pre.Append(_T(" "));
247     }
248     t.Prepend(pre);
249 
250     m_tcWindSpeed->SetToolTip( _("Wind Speed") + t );
251     m_tcWindSpeedBf->SetToolTip( _("Wind Speed in Bf") + t );
252     m_tcWindDirection->SetToolTip( _("Wind Direction") + t );
253 
254     t.Printf( _T(" %1.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::GEO_ALTITUDE), lev == (int) lev ? 0 : 1, lev );
255     m_tcWindGust->SetToolTip( _("Wind Gust at") + t );
256 
257     if( m_gparent.m_pTimelineSet ) {
258         wxString s[] = { _T(" "), _("Air Temperature at"), _("surface level"), _("Sea Surface Temperature") };
259 
260         lev = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::GEO_ALTITUDE, 2 );      //convert 2m in current altitude unit
261         t.Printf( m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(1000 + NORWAY_METNO) != wxNOT_FOUND ? s[0] + s[2]
262             : _T(" %1.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::GEO_ALTITUDE), lev == (int) lev ? 0 : 1, lev );
263         m_tcAirTemperature->SetToolTip(s[1] + t );
264 
265         m_tcSeaTemperature->SetToolTip( m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index( 1000 + NOAA_GFS) != wxNOT_FOUND ? s[1] + s[0] + s[2] : s[3] );
266     }
267     dummy->Show( false );
268 }
269 
UpdateTrackingControls(void)270 void CursorData::UpdateTrackingControls( void )
271 {
272     if( !m_gparent.m_pTimelineSet )
273         return;
274 
275     GribRecord **RecordArray = m_gparent.m_pTimelineSet->m_GribRecordPtrArray;
276     //    Update the wind control
277     double vkn, ang;
278     if(GribRecord::getInterpolatedValues(vkn, ang,
279                                          RecordArray[Idx_WIND_VX + m_Altitude],
280                                          RecordArray[Idx_WIND_VY + m_Altitude],
281                                          m_cursor_lon, m_cursor_lat)) {
282         double vk = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::WIND, vkn);
283 
284         m_tcWindSpeed->SetValue( wxString::Format( _T("%3d ") + m_gparent.m_OverlaySettings.GetUnitSymbol
285                                                    (GribOverlaySettings::WIND) , (int)round( vk )) );
286 
287         //wind is a special case: if current unit is not bf ==> double speed display (current unit + bf)
288         if(m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::WIND].m_Units != GribOverlaySettings::BFS) {
289             vk = m_gparent.m_OverlaySettings.GetmstobfFactor(vkn)* vkn;
290             if( m_DialogStyle == SEPARATED_VERTICAL )
291                 m_tcWindSpeedBf->SetValue( wxString::Format( _T("%2d bf"), (int)round( vk )));
292             else
293                 m_tcWindSpeed->SetValue(m_tcWindSpeed->GetValue().Append(_T(" - "))
294                         .Append(wxString::Format(_T("%2d bf"), (int)round( vk))) );
295         }
296 
297         m_tcWindDirection->SetValue( wxString::Format( _T("%03d\u00B0"), (int) ( ang ) ));
298     } else {
299         m_tcWindSpeed->SetValue( _("N/A") );
300         m_tcWindSpeedBf->SetValue( _("N/A") );
301         m_tcWindDirection->SetValue(  _("N/A") );
302     }
303 
304     //    Update the Wind gusts control
305     if( RecordArray[Idx_WIND_GUST] ) {
306         double vkn = RecordArray[Idx_WIND_GUST]->
307             getInterpolatedValue(m_cursor_lon, m_cursor_lat, true );
308 
309         if( vkn != GRIB_NOTDEF ) {
310             vkn = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::WIND_GUST, vkn);
311             m_tcWindGust->SetValue( wxString::Format(_T("%2d ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::WIND_GUST), (int)round( vkn )) );
312         } else
313             m_tcWindGust->SetValue( _("N/A") );
314     }
315 
316     //    Update the Pressure control
317     if( RecordArray[Idx_PRESSURE] ) {
318         double press = RecordArray[Idx_PRESSURE]->
319             getInterpolatedValue(m_cursor_lon, m_cursor_lat, true );
320 
321         if( press != GRIB_NOTDEF ) {
322             press = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::PRESSURE, press);
323             int p = (m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::PRESSURE].m_Units == 2) ? 2 : 1;  // if PRESSURE & inHG = two decimals
324             m_tcPressure->SetValue( wxString::Format(_T("%2.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::PRESSURE), p, ( press )) );
325         } else
326             m_tcPressure->SetValue( _("N/A") );
327     }
328 
329     //    Update the Sig Wave Height
330     if( RecordArray[Idx_HTSIGW] ) {
331         double height = RecordArray[Idx_HTSIGW]->
332             getInterpolatedValue(m_cursor_lon, m_cursor_lat, true );
333 
334         if( height != GRIB_NOTDEF ) {
335             height = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::WAVE, height);
336             wxString w( wxString::Format( _T("%4.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::WAVE), height ));
337             if( RecordArray[Idx_WVPER] ) {
338                 double period = RecordArray[Idx_WVPER]->
339                     getInterpolatedValue(m_cursor_lon, m_cursor_lat, true );
340                 if( period != GRIB_NOTDEF ) {
341                     if( m_DialogStyle == SEPARATED_VERTICAL )
342                         m_tcWavePeriode->SetValue( wxString::Format(_T("%01ds") , (int) round(period)) );
343                     else
344                         w.Append( wxString::Format( _T(" - %01ds") , (int) round(period) ));
345                 } else
346                     m_tcWavePeriode->SetValue( _("N/A") );
347             } else
348                 m_tcWavePeriode->SetValue( _("N/A") );
349 
350             m_tcWaveHeight->SetValue(w);
351         } else
352             m_tcWaveHeight->SetValue( _("N/A") );
353     }
354 
355     // Update the Wave direction
356     if( RecordArray[Idx_WVDIR] ) {
357         double direction = RecordArray[Idx_WVDIR]->
358             getInterpolatedValue(m_cursor_lon, m_cursor_lat, true, true );
359         if( direction != GRIB_NOTDEF )
360             m_tcWaveDirection->SetValue( wxString::Format( _T("%03d\u00B0"), (int)direction ));
361         else
362             m_tcWaveDirection->SetValue( _("N/A") );
363     }
364 
365     //    Update the Current control
366     if(GribRecord::getInterpolatedValues(vkn, ang,
367                                          RecordArray[Idx_SEACURRENT_VX],
368                                          RecordArray[Idx_SEACURRENT_VY],
369                                          m_cursor_lon, m_cursor_lat)) {
370 
371         // Current direction is generally reported as the "flow" direction,
372         // which is opposite from wind convention.
373         // So, adjust.
374         ang += 180;
375         if(ang >= 360) ang -= 360;
376         if( ang < 0 ) ang += 360;
377 
378         vkn = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::CURRENT, vkn);
379 
380         m_tcCurrentVelocity->SetValue( wxString::Format( _T("%4.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::CURRENT), vkn ) );
381 
382         m_tcCurrentDirection->SetValue( wxString::Format( _T("%03d\u00B0"), (int) ( ang ) ) );
383     } else {
384         m_tcCurrentVelocity->SetValue( _("N/A") );
385         m_tcCurrentDirection->SetValue( _("N/A") );
386     }
387 
388     //    Update total rainfall control
389     if( RecordArray[Idx_PRECIP_TOT] ) {
390         double precip = RecordArray[Idx_PRECIP_TOT]->
391             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
392 
393         if( precip != GRIB_NOTDEF ) {
394             precip = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::PRECIPITATION, precip);
395             int p = precip < 10. ? 2 : precip < 100. ? 1 : 0;
396             p += m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::PRECIPITATION].m_Units == 1 ? 1 : 0 ;  // if PRESSURE & in = one decimal more
397             m_tcPrecipitation->SetValue( wxString::Format( _T("%4.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::PRECIPITATION), p, precip ) );
398         } else
399             m_tcPrecipitation->SetValue( _("N/A") );
400     }
401 
402     //    Update total cloud control
403     if( RecordArray[Idx_CLOUD_TOT] ) {
404         double cloud = RecordArray[Idx_CLOUD_TOT]->
405             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
406 
407         if( cloud != GRIB_NOTDEF ) {
408             cloud = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::CLOUD, cloud);
409             wxString val( wxString::Format( _T("%5.0f "), cloud ) );
410             m_tcCloud->SetValue( val + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::CLOUD) );
411         } else
412             m_tcCloud->SetValue( _("N/A") );
413     }
414 
415     //    Update the Air Temperature
416     if( RecordArray[Idx_AIR_TEMP] ) {
417         double temp = RecordArray[Idx_AIR_TEMP]->
418             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
419 
420         if( temp != GRIB_NOTDEF ) {
421             temp = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::AIR_TEMPERATURE, temp);
422             m_tcAirTemperature->SetValue( wxString::Format( _T("%5.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::AIR_TEMPERATURE), temp ) );
423         } else
424             m_tcAirTemperature->SetValue( _("N/A") );
425     }
426 
427     //    Update the Sea Surface Temperature
428     if( RecordArray[Idx_SEA_TEMP] ) {
429         double temp = RecordArray[Idx_SEA_TEMP]->
430             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
431 
432         if( temp != GRIB_NOTDEF ) {
433             temp = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::SEA_TEMPERATURE, temp);
434             m_tcSeaTemperature->SetValue( wxString::Format( _T("%5.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::SEA_TEMPERATURE), temp ) );
435         } else
436             m_tcSeaTemperature->SetValue( _("N/A") );
437     }
438 
439     //    Update the Convective Available Potential Energy (CAPE)
440     if( RecordArray[Idx_CAPE] ) {
441         double cape = RecordArray[Idx_CAPE]->getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
442 
443         if( cape != GRIB_NOTDEF ) {
444             cape = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::CAPE, cape);
445             m_tcCAPE->SetValue( wxString::Format( _T("%5.0f ")
446                 +m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::CAPE), cape ) );
447         } else
448             m_tcCAPE->SetValue( _("N/A") );
449     }
450     if( RecordArray[Idx_COMP_REFL] ) {
451         double c_refl = RecordArray[Idx_COMP_REFL]->getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
452 
453         if( c_refl != GRIB_NOTDEF ) {
454             c_refl = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::COMP_REFL, c_refl);
455             m_tcReflC->SetValue( wxString::Format( _T("%5.0f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::COMP_REFL), c_refl ) );
456         } else
457             m_tcReflC->SetValue( _("N/A") );
458     }
459     // Update extra data for altitude
460     // geopotential altitude
461     if( RecordArray[Idx_GEOP_HGT + m_Altitude] ) {
462         double geop = RecordArray[Idx_GEOP_HGT + m_Altitude]->
463             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
464 
465         if( geop != GRIB_NOTDEF ) {
466             geop = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::GEO_ALTITUDE, geop);
467             m_tcAltitude->SetValue( wxString::Format( _T("%5.0f "), geop ) + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::GEO_ALTITUDE) );
468         } else
469             m_tcAltitude->SetValue( _("N/A") );
470     }
471 
472     // temperature
473     if( RecordArray[Idx_AIR_TEMP + m_Altitude] ) {
474         double temp = RecordArray[Idx_AIR_TEMP + m_Altitude]->
475             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
476 
477         if( temp != GRIB_NOTDEF ) {
478             temp = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::AIR_TEMPERATURE, temp);
479             m_tcTemp->SetValue( wxString::Format( _T("%5.1f "), temp ) + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::AIR_TEMPERATURE) );
480         } else
481             m_tcTemp->SetValue(  _("N/A") );
482     }
483     // relative humidity
484     if( RecordArray[Idx_HUMID_RE + m_Altitude] ) {
485         double humi = RecordArray[Idx_HUMID_RE + m_Altitude]->
486             getInterpolatedValue( m_cursor_lon, m_cursor_lat, true );
487 
488         if( humi != GRIB_NOTDEF ) {
489             humi = m_gparent.m_OverlaySettings.CalibrateValue(GribOverlaySettings::REL_HUMIDITY, humi);
490             m_tcRelHumid->SetValue( wxString::Format( _T("%5.0f "), humi ) + m_gparent.m_OverlaySettings.GetUnitSymbol(GribOverlaySettings::REL_HUMIDITY) );
491         } else
492             m_tcRelHumid->SetValue(  _("N/A") );
493     }
494 }
495 
OnMenuCallBack(wxMouseEvent & event)496 void CursorData::OnMenuCallBack( wxMouseEvent& event )
497 {
498     //populate menu
499     wxMenu* menu = new wxMenu();
500     int id = event.GetId();
501     switch( id ) {
502         case GribOverlaySettings::WIND:
503             MenuAppend( menu, B_ARROWS, _("Barbed Arrows"), id );
504             MenuAppend( menu, ISO_LINE, _("Display Isotachs"), id );
505             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
506             MenuAppend( menu, NUMBERS, _("Numbers"), id );
507             MenuAppend( menu, PARTICLES, _("Particle Map"), id );
508             break;
509         case GribOverlaySettings::WIND_GUST:
510             MenuAppend( menu, ISO_LINE, _("Display Isotachs"), id );
511             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
512             MenuAppend( menu, NUMBERS, _("Numbers"), id );
513             break;
514         case GribOverlaySettings::PRESSURE:
515             MenuAppend( menu, ISO_LINE, _("Display Isobars"), id );
516             MenuAppend( menu, ISO_ABBR, _("Abbreviated Isobars Numbers"), id );
517             MenuAppend( menu, NUMBERS, _("Numbers"), id );
518             break;
519         case GribOverlaySettings::AIR_TEMPERATURE:
520         case GribOverlaySettings::SEA_TEMPERATURE:
521             MenuAppend( menu, ISO_LINE, _("Display Isotherms"), id );
522             // fall through
523         case GribOverlaySettings::CLOUD:
524         case GribOverlaySettings::PRECIPITATION:
525             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
526             MenuAppend( menu, NUMBERS, _("Numbers"), id );
527             break;
528         case GribOverlaySettings::CAPE:
529             MenuAppend( menu, ISO_LINE, _("Display Iso CAPE"), id );
530             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
531             MenuAppend( menu, NUMBERS, _("Numbers"), id );
532             break;
533         case GribOverlaySettings::COMP_REFL:
534             MenuAppend( menu, ISO_LINE, _("Display Iso Reflectivity"), id );
535             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
536             MenuAppend( menu, NUMBERS, _("Numbers"), id );
537             break;
538         case GribOverlaySettings::WAVE:
539             MenuAppend( menu, D_ARROWS, _("Direction Arrows"), id );
540             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
541             MenuAppend( menu, NUMBERS, _("Numbers"), id );
542             break;
543         case GribOverlaySettings::CURRENT:
544             MenuAppend( menu, D_ARROWS, _("Direction Arrows"), id );
545             MenuAppend( menu, OVERLAY, _("OverlayMap"), id );
546             MenuAppend( menu, NUMBERS, _("Numbers"), id );
547             MenuAppend( menu, PARTICLES, _("Particle Map"), id );
548     }
549 
550     PopupMenu( menu );
551 
552     //apply new config
553     wxwxMenuItemListNode *node = menu->GetMenuItems().GetFirst();
554     while( node ) {
555         wxMenuItem *it = node->GetData();
556         switch( it->GetId() ) {
557             case B_ARROWS:
558                 m_gparent.m_OverlaySettings.Settings[id].m_bBarbedArrows = it->IsChecked();
559                 break;
560             case ISO_LINE:
561                 m_gparent.m_OverlaySettings.Settings[id].m_bIsoBars = it->IsChecked();
562                 break;
563             case ISO_ABBR:
564                 m_gparent.m_OverlaySettings.Settings[id].m_bAbbrIsoBarsNumbers = it->IsChecked();
565                 break;
566             case D_ARROWS:
567                 m_gparent.m_OverlaySettings.Settings[id].m_bDirectionArrows = it->IsChecked();
568                 break;
569             case OVERLAY:
570                 m_gparent.m_OverlaySettings.Settings[id].m_bOverlayMap = it->IsChecked();
571                 break;
572             case NUMBERS:
573                 m_gparent.m_OverlaySettings.Settings[id].m_bNumbers = it->IsChecked();
574                 break;
575             case PARTICLES:
576                 m_gparent.m_OverlaySettings.Settings[id].m_bParticles = it->IsChecked();
577         }
578         node = node->GetNext();
579     }
580 
581     //if the current parameter type is selected then resolve display conflicts
582 	if( m_gparent.InDataPlot(id) && m_gparent.m_bDataPlot[id] )
583 		ResolveDisplayConflicts( id );
584 
585     //save new config
586     m_gparent.m_OverlaySettings.Write();
587 
588     delete menu;
589 }
590 
MenuAppend(wxMenu * menu,int id,wxString label,int setting)591 void CursorData::MenuAppend( wxMenu *menu, int id, wxString label, int setting)
592 {
593     wxMenuItem *item = new wxMenuItem(menu, id, label, _T(""), wxITEM_CHECK);
594 
595 #ifdef __WXMSW__
596     wxFont *qFont = OCPNGetFont( _("Menu"), 10 );
597     item->SetFont(*qFont);
598 #endif
599 
600     menu->Append(item);
601 
602     bool check;
603     if( id == B_ARROWS )
604         check = m_gparent.m_OverlaySettings.Settings[setting].m_bBarbedArrows;
605     else if( id == ISO_LINE )
606         check = m_gparent.m_OverlaySettings.Settings[setting].m_bIsoBars;
607     else if( id == ISO_ABBR )
608         check = m_gparent.m_OverlaySettings.Settings[setting].m_bAbbrIsoBarsNumbers;
609     else if( id == D_ARROWS )
610         check = m_gparent.m_OverlaySettings.Settings[setting].m_bDirectionArrows;
611     else if( id == OVERLAY )
612         check = m_gparent.m_OverlaySettings.Settings[setting].m_bOverlayMap;
613     else if( id == NUMBERS )
614         check = m_gparent.m_OverlaySettings.Settings[setting].m_bNumbers;
615     else if( id == PARTICLES )
616         check = m_gparent.m_OverlaySettings.Settings[setting].m_bParticles;
617     else
618         check = false;
619     item->Check( check );
620 }
621 
OnMouseEvent(wxMouseEvent & event)622 void CursorData::OnMouseEvent( wxMouseEvent &event )
623 {
624     if( event.RightDown() ) {
625         if( m_DialogStyle >> 1 == ATTACHED ) {
626             wxMouseEvent evt(event);
627             m_gparent.OnMouseEvent( evt );
628         }
629         return;
630     }
631 
632     static wxPoint s_gspt;
633     int x, y;
634 
635     event.GetPosition( &x, &y );
636     wxPoint spt = wxPoint( x, y );
637     if( event.GetId() != 1000 )
638         spt = ClientToScreen( spt );
639     else
640         spt = GetParent()->ClientToScreen( spt );
641 
642 #ifdef __WXOSX__
643     if (!m_bLeftDown && event.LeftIsDown())
644     {
645         m_bLeftDown = true;
646         s_gspt = spt;
647         if (!HasCapture()) CaptureMouse();
648     }
649     else if (m_bLeftDown && !event.LeftIsDown())
650     {
651        // GetParent()->Move( GetParent()->GetPosition() );
652         m_bLeftDown = false;
653         if (HasCapture()) ReleaseMouse();
654     }
655 #else
656 
657     if( event.LeftDown() ) {
658         s_gspt = spt;
659         if (!HasCapture()) CaptureMouse();
660     }
661 
662     if( event.LeftUp() ) {
663         //GetParent()->Move( GetParent()->GetPosition() );
664         if( HasCapture() ) ReleaseMouse();
665     }
666 #endif
667 
668     if( event.Dragging() ) {
669 
670         wxPoint par_pos_old = GetParent()->GetPosition();
671 
672         wxPoint par_pos = par_pos_old;
673         par_pos.x += spt.x - s_gspt.x;
674         par_pos.y += spt.y - s_gspt.y;
675 
676         wxPoint pos_in_parent = GetOCPNCanvasWindow()->ScreenToClient( par_pos );
677         wxPoint pos_in_parent_old = GetOCPNCanvasWindow()->ScreenToClient( par_pos_old );
678 
679 		// X
680 		if( pos_in_parent.x < pos_in_parent_old.x ) {           // moving left
681 			if( pos_in_parent.x < 10 ) {
682 				pos_in_parent.x = 0;
683 			}
684 		} else
685         if( pos_in_parent.x > pos_in_parent_old.x ) {           // moving right
686             int max_right = GetOCPNCanvasWindow()->GetClientSize().x - GetParent()->GetSize().x;
687             if( pos_in_parent.x > ( max_right - 10 ) ) {
688                 pos_in_parent.x = max_right;
689             }
690         }
691 
692 		// Y
693 		if( pos_in_parent.y < pos_in_parent_old.y ) {            // moving up
694 			if( pos_in_parent.y < 10 ) {
695 				pos_in_parent.y = 0;
696 			}
697 		} else
698         if( pos_in_parent.y > pos_in_parent_old.y ) {            // moving dow
699             int max_down = GetOCPNCanvasWindow()->GetClientSize().y - GetParent()->GetSize().y;
700             if( pos_in_parent.y > ( max_down - 10 ) ) {
701                 pos_in_parent.y = max_down;
702             }
703         }
704 
705 		wxPoint final_pos = GetOCPNCanvasWindow()->ClientToScreen( pos_in_parent );
706 
707 		GetParent()->Move( final_pos );
708 
709         s_gspt = spt;
710 
711     }
712 }
713