OpenCPN Partial API docs
Loading...
Searching...
No Matches
TCWin.cpp
1// For compilers that support precompilation, includes "wx.h".
2#include <wx/wxprec.h>
3
4#include <wx/listctrl.h>
5#include <wx/choice.h>
6
7#include "TCWin.h"
8#include "timers.h"
9#include "chcanv.h"
10#include "tide_time.h"
11#include "tcmgr.h"
12#include "dychart.h"
13#include "cutil.h"
14#include "FontMgr.h"
15#include "wx28compat.h"
16#include "OCPNPlatform.h"
17#include "RolloverWin.h"
18#include "navutil.h"
19#include "gui_lib.h"
20#include "ocpn_frame.h"
21
22extern ColorScheme global_color_scheme;
23extern IDX_entry *gpIDX;
24extern int gpIDXn;
25extern TCMgr *ptcmgr;
26extern wxString g_locale;
27extern OCPNPlatform *g_Platform;
28extern MyConfig *pConfig;
29
30int g_tcwin_scale;
31
32enum { ID_TCWIN_NX, ID_TCWIN_PR };
33
34enum { TIDE_PLOT, CURRENT_PLOT };
35
36#include <wx/listimpl.cpp>
37WX_DEFINE_LIST(SplineList);
38
39BEGIN_EVENT_TABLE(TCWin, wxWindow)
40EVT_PAINT(TCWin::OnPaint) EVT_SIZE(TCWin::OnSize) EVT_MOTION(TCWin::MouseEvent)
41 EVT_BUTTON(wxID_OK, TCWin::OKEvent) EVT_BUTTON(ID_TCWIN_NX, TCWin::NXEvent)
42 EVT_BUTTON(ID_TCWIN_PR, TCWin::PREvent) EVT_CLOSE(TCWin::OnCloseWindow)
43 EVT_TIMER(TCWININF_TIMER, TCWin::OnTCWinPopupTimerEvent)
44 END_EVENT_TABLE()
45
46 // Define a constructor
47 extern wxDateTime gTimeSource;
48TCWin::TCWin(ChartCanvas *parent, int x, int y, void *pvIDX) {
49 // As a display optimization....
50 // if current color scheme is other than DAY,
51 // Then create the dialog ..WITHOUT.. borders and title bar.
52 // This way, any window decorations set by external themes, etc
53 // will not detract from night-vision
54
55 m_created = false;
56 xSpot = 0;
57 ySpot = 0;
58
59 m_pTCRolloverWin = NULL;
60
61 long wstyle = wxCLIP_CHILDREN | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER |
62 wxFRAME_FLOAT_ON_PARENT;
63 if ((global_color_scheme != GLOBAL_COLOR_SCHEME_DAY) &&
64 (global_color_scheme != GLOBAL_COLOR_SCHEME_RGB))
65 wstyle |= (wxNO_BORDER);
66
67 pParent = parent;
68 m_x = x;
69 m_y = y;
70
71 RecalculateSize();
72
73 // Read the config file to get the user specified time zone.
74 if (pConfig) {
75 pConfig->SetPath(_T ( "/Settings/Others" ));
76 pConfig->Read(_T ( "TCWindowTimeZone" ), &m_tzoneDisplay, 0);
77 }
78
79 wxFrame::Create(parent, wxID_ANY, wxString(_T ( "" )), m_position, m_tc_size,
80 wstyle);
81
82 m_created = true;
83 wxFont *qFont = GetOCPNScaledFont(_("Dialog"));
84 SetFont(*qFont);
85
86 pIDX = (IDX_entry *)pvIDX;
87 gpIDXn++;
88
89 // Set up plot type
90 if (strchr("Tt", pIDX->IDX_type)) {
91 m_plot_type = TIDE_PLOT;
92 SetTitle(wxString(_("Tide")));
93 gpIDX = pIDX; // remember pointer for routeplan
94
95 } else {
96 m_plot_type = CURRENT_PLOT;
97 SetTitle(wxString(_("Current")));
98 }
99
100 int sx, sy;
101 GetClientSize(&sx, &sy);
102
103 SetTimeFactors();
104
105 btc_valid = false;
106
107 wxString *TClist = NULL;
108 m_tList = new wxListCtrl(this, -1, wxPoint(sx * 65 / 100, 11),
109 wxSize((sx * 32 / 100), (sy * 20 / 100)),
110 wxLC_REPORT | wxLC_NO_HEADER);
111
112 // Add first column
113 wxListItem col0;
114 col0.SetId(0);
115 col0.SetText(_T(""));
116 col0.SetAlign(wxLIST_FORMAT_LEFT);
117 col0.SetWidth(sx * 30 / 100);
118 m_tList->InsertColumn(0, col0);
119
120 // Measure the size of a generic button, with label
121 wxButton *test_button =
122 new wxButton(this, wxID_OK, _("OK"), wxPoint(-1, -1), wxDefaultSize);
123 test_button->GetSize(&m_tsx, &m_tsy);
124 delete test_button;
125
126 // In the interest of readability, if the width of the dialog is too narrow,
127 // simply skip showing the "Hi/Lo" list control.
128
129 if ((m_tsy * 15) > sx) m_tList->Hide();
130
131 OK_button = new wxButton(this, wxID_OK, _("OK"),
132 wxPoint(sx - (2 * m_tsy + 10), sy - (m_tsy + 10)),
133 wxDefaultSize);
134
135 PR_button = new wxButton(this, ID_TCWIN_PR, _("Prev"),
136 wxPoint(10, sy - (m_tsy + 10)), wxSize(-1, -1));
137
138 wxSize texc_size = wxSize((sx * 60 / 100), (sy * 29 / 100));
139 if (!m_tList->IsShown()) {
140 texc_size = wxSize((sx * 90 / 100), (sy * 29 / 100));
141 }
142
143 m_ptextctrl =
144 new wxTextCtrl(this, -1, _T(""), wxPoint(sx * 3 / 100, 6), texc_size,
145 wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
146 int bsx, bsy, bpx, bpy;
147 PR_button->GetSize(&bsx, &bsy);
148 PR_button->GetPosition(&bpx, &bpy);
149
150 NX_button =
151 new wxButton(this, ID_TCWIN_NX, _("Next"),
152 wxPoint(bpx + bsx + 5, sy - (m_tsy + 10)), wxSize(-1, -1));
153
154 wxString m_choiceTimezoneChoices[] = {_("LMT@Station"), _("UTC")};
155 int m_choiceTimezoneNChoices =
156 sizeof(m_choiceTimezoneChoices) / sizeof(wxString);
157 m_choiceTimezone = new wxChoice(
158 this, wxID_ANY, wxPoint((sx - (bsx * 2)) / 2, sy - (m_tsy + 10)),
159 wxSize(2 * bsx, bsy), m_choiceTimezoneNChoices, m_choiceTimezoneChoices,
160 0);
161
162 m_choiceTimezone->SetSelection(m_tzoneDisplay);
163 m_choiceTimezone->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
164 wxCommandEventHandler(TCWin::TimezoneOnChoice),
165 NULL, this);
166
167 m_TCWinPopupTimer.SetOwner(this, TCWININF_TIMER);
168
169 wxScreenDC dc;
170 int text_height;
171 dc.GetTextExtent(_T("W"), NULL, &text_height);
172 m_button_height = m_tsy; // text_height + 20;
173
174 // Build graphics tools
175
176 wxFont *dlg_font = FontMgr::Get().GetFont(_("Dialog"));
177 int dlg_font_size = dlg_font->GetPointSize();
178
179 pSFont = FontMgr::Get().FindOrCreateFont(
180 dlg_font_size - 2, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
181 wxFONTWEIGHT_NORMAL, FALSE, wxString(_T ( "Arial" )));
182 pSMFont = FontMgr::Get().FindOrCreateFont(
183 dlg_font_size - 1, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
184 wxFONTWEIGHT_NORMAL, FALSE, wxString(_T ( "Arial" )));
185 pMFont = FontMgr::Get().FindOrCreateFont(
186 dlg_font_size, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD,
187 FALSE, wxString(_T ( "Arial" )));
188 pLFont = FontMgr::Get().FindOrCreateFont(
189 dlg_font_size + 1, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
190 wxFONTWEIGHT_BOLD, FALSE, wxString(_T ( "Arial" )));
191
192 pblack_1 = wxThePenList->FindOrCreatePen(
193 GetGlobalColor(_T ( "UINFD" )), wxMax(1, (int)(m_tcwin_scaler + 0.5)),
194 wxPENSTYLE_SOLID);
195 pblack_2 = wxThePenList->FindOrCreatePen(
196 GetGlobalColor(_T ( "UINFD" )), wxMax(2, (int)(2 * m_tcwin_scaler + 0.5)),
197 wxPENSTYLE_SOLID);
198 pblack_3 = wxThePenList->FindOrCreatePen(
199 GetGlobalColor(_T ( "UWHIT" )), wxMax(1, (int)(m_tcwin_scaler + 0.5)),
200 wxPENSTYLE_SOLID);
201 pred_2 = wxThePenList->FindOrCreatePen(
202 GetGlobalColor(_T ( "UINFR" )), wxMax(4, (int)(4 * m_tcwin_scaler + 0.5)),
203 wxPENSTYLE_SOLID);
204 pltgray = wxTheBrushList->FindOrCreateBrush(GetGlobalColor(_T ( "UIBCK" )),
205 wxBRUSHSTYLE_SOLID);
206 pltgray2 = wxTheBrushList->FindOrCreateBrush(GetGlobalColor(_T ( "DILG1" )),
207 wxBRUSHSTYLE_SOLID);
208
209 DimeControl(this);
210
211 // Fill in some static text control information
212
213 // Tidi station information
214 m_ptextctrl->Clear();
215
216 wxString locn(pIDX->IDX_station_name, wxConvUTF8);
217 wxString locna, locnb;
218 if (locn.Contains(wxString(_T ( "," )))) {
219 locna = locn.BeforeFirst(',');
220 locnb = locn.AfterFirst(',');
221 } else {
222 locna = locn;
223 locnb.Empty();
224 }
225
226 // write the first line
227 wxTextAttr style;
228 style.SetFont(*pLFont);
229 m_ptextctrl->SetDefaultStyle(style);
230
231 m_ptextctrl->AppendText(locna);
232 m_ptextctrl->AppendText(_T("\n"));
233
234 style.SetFont(*pSMFont);
235 m_ptextctrl->SetDefaultStyle(style);
236
237 if (!locnb.IsEmpty()) m_ptextctrl->AppendText(locnb);
238 m_ptextctrl->AppendText(_T("\n"));
239
240 // Reference to the master station
241 if (('t' == pIDX->IDX_type) || ('c' == pIDX->IDX_type)) {
242 wxString mref(pIDX->IDX_reference_name, wxConvUTF8);
243 mref.Prepend(_T(" "));
244
245 m_ptextctrl->AppendText(_("Reference Station :"));
246 m_ptextctrl->AppendText(_T("\n"));
247
248 m_ptextctrl->AppendText(mref);
249 m_ptextctrl->AppendText(_T("\n"));
250
251 } else {
252 m_ptextctrl->AppendText(_T("\n"));
253 }
254
255 // Show the data source
256 wxString dsource(pIDX->source_ident, wxConvUTF8);
257 dsource.Prepend(_T(" "));
258
259 m_ptextctrl->AppendText(_("Data Source :"));
260 m_ptextctrl->AppendText(_T("\n"));
261
262 m_ptextctrl->AppendText(dsource);
263
264 m_ptextctrl->ShowPosition(0);
265}
266
267TCWin::~TCWin() { pParent->Refresh(false); }
268
269void TCWin::SetTimeFactors() {
270 // Figure out this computer timezone minute offset
271 wxDateTime this_now = gTimeSource;
272 bool cur_time = !gTimeSource.IsValid();
273
274 if (cur_time) {
275 this_now = wxDateTime::Now();
276 }
277 wxDateTime this_gmt = this_now.ToGMT();
278
279#if wxCHECK_VERSION(2, 6, 2)
280 wxTimeSpan diff = this_now.Subtract(this_gmt);
281#else
282 wxTimeSpan diff = this_gmt.Subtract(this_now);
283#endif
284
285 m_diff_mins = diff.GetMinutes();
286
287 // Correct a bug in wx3.0.2
288 // If the system TZ happens to be GMT, with DST active (e.g.summer in
289 // London), then wxDateTime returns incorrect results for toGMT() method
290#if wxCHECK_VERSION(3, 0, 2)
291 if (m_diff_mins == 0 && this_now.IsDST()) m_diff_mins += 60;
292#endif
293
294 int station_offset = ptcmgr->GetStationTimeOffset(pIDX);
295
296 m_stationOffset_mins = station_offset;
297 if (this_now.IsDST()) m_stationOffset_mins += 60;
298
299 // Correct a bug in wx3.0.2
300 // If the system TZ happens to be GMT, with DST active (e.g.summer in
301 // London), then wxDateTime returns incorrect results for toGMT() method
302#if wxCHECK_VERSION(3, 0, 2)
303// if( this_now.IsDST() )
304// m_corr_mins +=60;
305#endif
306
307 // Establish the inital drawing day as today, in the timezone of the
308 // station
309 m_graphday = this_gmt;
310
311 int day_gmt = this_gmt.GetDayOfYear();
312
313 time_t ttNow = this_now.GetTicks();
314 time_t tt_at_station =
315 ttNow - (m_diff_mins * 60) + (m_stationOffset_mins * 60);
316 wxDateTime atStation(tt_at_station);
317 int day_at_station = atStation.GetDayOfYear();
318
319 if (day_gmt > day_at_station) {
320 wxTimeSpan dt(24, 0, 0, 0);
321 m_graphday.Subtract(dt);
322 } else if (day_gmt < day_at_station) {
323 wxTimeSpan dt(24, 0, 0, 0);
324 m_graphday.Add(dt);
325 }
326
327 wxDateTime graphday_00 = m_graphday; // this_gmt;
328 graphday_00.ResetTime();
329 time_t t_graphday_00 = graphday_00.GetTicks();
330
331 // Correct a Bug in wxWidgets time support
332 // if( !graphday_00.IsDST() && m_graphday.IsDST() ) t_graphday_00 -= 3600;
333 // if( graphday_00.IsDST() && !m_graphday.IsDST() ) t_graphday_00 += 3600;
334
335 m_t_graphday_GMT = t_graphday_00;
336
337 btc_valid = false; // Force re-calculation
338}
339
340void TCWin::TimezoneOnChoice(wxCommandEvent &event) {
341 m_tzoneDisplay = m_choiceTimezone->GetSelection();
342 SetTimeFactors();
343
344 Refresh();
345}
346
347void TCWin::RecalculateSize() {
348 wxSize parent_size(2000, 2000);
349 if (pParent) parent_size = pParent->GetClientSize();
350
351 int unscaledheight = 600;
352 int unscaledwidth = 650;
353
354 // value of m_tcwin_scaler should be about unity on a 100 dpi display,
355 // when scale parameter g_tcwin_scale is 100
356 // parameter g_tcwin_scale is set in config file as value of
357 // TideCurrentWindowScale
358 g_tcwin_scale = wxMax(g_tcwin_scale, 10); // sanity check on g_tcwin_scale
359 m_tcwin_scaler = g_Platform->GetDisplayDPmm() * 0.254 * g_tcwin_scale / 100.0;
360
361 m_tc_size.x = (int)(unscaledwidth * m_tcwin_scaler + 0.5);
362 m_tc_size.y = (int)(unscaledheight * m_tcwin_scaler + 0.5);
363
364 m_tc_size.x = wxMin(m_tc_size.x, parent_size.x);
365 m_tc_size.y = wxMin(m_tc_size.y, parent_size.y);
366
367 int xc = m_x + 8;
368 int yc = m_y;
369
370 // Arrange for tcWindow to be always totally visible
371 // by shifting left and/or up
372 if ((m_x + 8 + m_tc_size.x) > parent_size.x) xc = xc - m_tc_size.x - 16;
373 if ((m_y + m_tc_size.y) > parent_size.y) yc = yc - m_tc_size.y;
374
375 // Don't let the window origin move out of client area
376 if (yc < 0) yc = 0;
377 if (xc < 0) xc = 0;
378
379 if (pParent) pParent->ClientToScreen(&xc, &yc);
380 m_position = wxPoint(xc, yc);
381
382 if (m_created) {
383 SetSize(m_tc_size);
384 Move(m_position);
385 }
386}
387
388void TCWin::OKEvent(wxCommandEvent &event) {
389 Hide();
390 pParent->pCwin = NULL;
391 if (--gpIDXn == 0) gpIDX = NULL;
392 delete m_pTCRolloverWin;
393 delete m_tList;
394 pParent->Refresh(false);
395
396 // Update the config file to set the user specified time zone.
397 if (pConfig) {
398 pConfig->SetPath(_T ( "/Settings/Others" ));
399 pConfig->Write(_T ( "TCWindowTimeZone" ), m_tzoneDisplay);
400 }
401
402 Destroy(); // that hurts
403}
404
405void TCWin::OnCloseWindow(wxCloseEvent &event) {
406 Hide();
407 pParent->pCwin = NULL;
408 if (--gpIDXn == 0) gpIDX = NULL;
409 delete m_pTCRolloverWin;
410 delete m_tList;
411
412 // Update the config file to set the user specified time zone.
413 if (pConfig) {
414 pConfig->SetPath(_T ( "/Settings/Others" ));
415 pConfig->Write(_T ( "TCWindowTimeZone" ), m_tzoneDisplay);
416 }
417
418 Destroy(); // that hurts
419}
420
421void TCWin::NXEvent(wxCommandEvent &event) {
422 wxTimeSpan dt(24, 0, 0, 0);
423 m_graphday.Add(dt);
424 wxDateTime dm = m_graphday;
425
426 wxDateTime graphday_00 = dm.ResetTime();
427 time_t t_graphday_00 = graphday_00.GetTicks();
428
429 if (!graphday_00.IsDST() && m_graphday.IsDST()) t_graphday_00 -= 3600;
430 if (graphday_00.IsDST() && !m_graphday.IsDST()) t_graphday_00 += 3600;
431
432 m_t_graphday_GMT = t_graphday_00;
433
434 btc_valid = false;
435 Refresh();
436}
437
438void TCWin::PREvent(wxCommandEvent &event) {
439 wxTimeSpan dt(-24, 0, 0, 0);
440 m_graphday.Add(dt);
441 wxDateTime dm = m_graphday;
442
443 wxDateTime graphday_00 = dm.ResetTime();
444 time_t t_graphday_00 = graphday_00.GetTicks();
445
446 if (!graphday_00.IsDST() && m_graphday.IsDST()) t_graphday_00 -= 3600;
447 if (graphday_00.IsDST() && !m_graphday.IsDST()) t_graphday_00 += 3600;
448
449 m_t_graphday_GMT = t_graphday_00;
450
451 btc_valid = false;
452 Refresh();
453}
454
455void TCWin::RePosition(void) {
456 // Position the window
457 double lon = pIDX->IDX_lon;
458 double lat = pIDX->IDX_lat;
459
460 wxPoint r;
461 pParent->GetCanvasPointPix(lat, lon, &r);
462 pParent->ClientToScreen(&r.x, &r.y);
463 Move(r);
464}
465
466void TCWin::OnPaint(wxPaintEvent &event) {
467 if (!IsShown()) {
468 return;
469 }
470 int x, y;
471 int i;
472 char sbuf[100];
473 int w;
474 float tcmax, tcmin;
475
476 if (m_graph_rect.x == 0) return;
477
478 GetClientSize(&x, &y);
479 // qDebug() << "OnPaint" << x << y;
480
481#if 0
482 // establish some graphic element sizes/locations
483 int x_graph = x * 1 / 10;
484 int y_graph = y * 32 / 100;
485 int x_graph_w = x * 8 / 10;
486 int y_graph_h = (y * .7) - (3 * m_button_height);
487 m_graph_rect = wxRect(x_graph, y_graph, x_graph_w, y_graph_h);
488
489 wxSize texc_size = wxSize( ( x * 60 / 100 ), ( y *29 / 100 ) );
490 if( !m_tList->IsShown()){
491 texc_size = wxSize( ( x * 90 / 100 ), ( y *29 / 100 ) );
492 }
493
494 m_ptextctrl->SetSize(texc_size);
495#endif
496
497 wxPaintDC dc(this);
498
499 wxString tlocn(pIDX->IDX_station_name, wxConvUTF8);
500
501 // if(1/*bForceRedraw*/)
502 {
503 int x_textbox = x * 5 / 100;
504 int y_textbox = 6;
505
506 int x_textbox_w = x * 51 / 100;
507 int y_textbox_h = y * 25 / 100;
508
509 // box the location text & tide-current table
510 dc.SetPen(*pblack_3);
511 dc.SetBrush(*pltgray2);
512 dc.DrawRoundedRectangle(x_textbox, y_textbox, x_textbox_w, y_textbox_h,
513 4); // location text box
514
515 if (m_tList->IsShown()) {
516 wxRect tab_rect = m_tList->GetRect();
517 dc.DrawRoundedRectangle(tab_rect.x - 4, y_textbox, tab_rect.width + 8,
518 y_textbox_h, 4); // tide-current table box
519 }
520
521 // Box the graph
522 dc.SetPen(*pblack_1);
523 dc.SetBrush(*pltgray);
524 dc.DrawRectangle(m_graph_rect.x, m_graph_rect.y, m_graph_rect.width,
525 m_graph_rect.height);
526
527 // On some platforms, we cannot draw rotated text.
528 // So, reduce the complexity of horizontal axis time labels
529#ifndef __WXMSW__
530 const int hour_delta = 4;
531#else
532 const int hour_delta = 1;
533#endif
534
535 int hour_start = 0;
536 // if(m_tzoneDisplay == 1){ // UTC
537 // hour_start = m_diff_mins / 60;
538 // }
539
540 // Horizontal axis
541 dc.SetFont(*pSFont);
542 for (i = 0; i < 25; i++) {
543 int xd = m_graph_rect.x + ((i)*m_graph_rect.width / 25);
544 if (hour_delta != 1) {
545 if (i % hour_delta == 0) {
546 dc.SetPen(*pblack_2);
547 dc.DrawLine(xd, m_graph_rect.y, xd,
548 m_graph_rect.y + m_graph_rect.height + 5);
549 char sbuf[5];
550 int hour_show = hour_start + i;
551 if (hour_show >= 24) hour_show -= 24;
552 sprintf(sbuf, "%02d", hour_show);
553 int x_shim = -20;
554 dc.DrawText(wxString(sbuf, wxConvUTF8),
555 xd + x_shim + (m_graph_rect.width / 25) / 2,
556 m_graph_rect.y + m_graph_rect.height + 8);
557 } else {
558 dc.SetPen(*pblack_1);
559 dc.DrawLine(xd, m_graph_rect.y, xd,
560 m_graph_rect.y + m_graph_rect.height + 5);
561 }
562 } else {
563 dc.SetPen(*pblack_1);
564 dc.DrawLine(xd, m_graph_rect.y, xd,
565 m_graph_rect.y + m_graph_rect.height + 5);
566 wxString sst;
567 sst.Printf(_T("%02d"), i);
568 dc.DrawRotatedText(sst, xd + (m_graph_rect.width / 25) / 2,
569 m_graph_rect.y + m_graph_rect.height + 8, 270.);
570 }
571 }
572
573 // Make a line for "right now"
574 wxDateTime this_now = gTimeSource;
575 bool cur_time = !gTimeSource.IsValid();
576 if (cur_time) this_now = wxDateTime::Now();
577
578 time_t t_now = this_now.GetTicks(); // now, in ticks
579 t_now -= m_diff_mins * 60;
580 if (m_tzoneDisplay == 0) // LMT @ Station
581 t_now += m_stationOffset_mins * 60;
582
583 float t_ratio =
584 m_graph_rect.width * (t_now - m_t_graphday_GMT) / (25 * 3600.0f);
585
586 // must eliminate line outside the graph (in that case put it outside the
587 // window)
588 int xnow = (t_ratio < 0 || t_ratio > m_graph_rect.width)
589 ? -1
590 : m_graph_rect.x + (int)t_ratio;
591 dc.SetPen(*pred_2);
592 dc.DrawLine(xnow, m_graph_rect.y, xnow,
593 m_graph_rect.y + m_graph_rect.height);
594 dc.SetPen(*pblack_1);
595
596 // Build the array of values, capturing max and min and HW/LW list
597
598 if (!btc_valid) {
599 float dir;
600 tcmax = -10;
601 tcmin = 10;
602 float val = -100;
603 m_tList->DeleteAllItems();
604 int list_index = 0;
605 bool wt = false;
606
607 wxBeginBusyCursor();
608
609 // The tide/current modules calculate values based on PC local time
610 // We want UTC, so adjust accordingly
611 int tt_localtz = m_t_graphday_GMT + (m_diff_mins * 60);
612
613 // get tide flow sens ( flood or ebb ? )
614 ptcmgr->GetTideFlowSens(tt_localtz, BACKWARD_TEN_MINUTES_STEP,
615 pIDX->IDX_rec_num, tcv[0], val, wt);
616
617 if (m_tzoneDisplay == 0)
618 tt_localtz -= m_stationOffset_mins * 60; // LMT at station
619
620 for (i = 0; i < 26; i++) {
621 int tt = tt_localtz + (i * FORWARD_ONE_HOUR_STEP);
622
623 ptcmgr->GetTideOrCurrent(tt, pIDX->IDX_rec_num, tcv[i], dir);
624 tt_tcv[i] = tt; // store the corresponding time_t value
625 if (tcv[i] > tcmax) tcmax = tcv[i];
626
627 if (tcv[i] < tcmin) tcmin = tcv[i];
628 if (TIDE_PLOT == m_plot_type) {
629 if (!((tcv[i] > val) == wt) && (i > 0)) // if tide flow sense change
630 {
631 float tcvalue; // look backward for HW or LW
632 time_t tctime;
633 ptcmgr->GetHightOrLowTide(tt, BACKWARD_TEN_MINUTES_STEP,
634 BACKWARD_ONE_MINUTES_STEP, tcv[i], wt,
635 pIDX->IDX_rec_num, tcvalue, tctime);
636 if (tctime > tt_localtz) { // Only show events visible in graphic
637 // presently shown
638 wxDateTime tcd; // write date
639 wxString s, s1;
640 tcd.Set(tctime - (m_diff_mins * 60));
641 if (m_tzoneDisplay == 0) // LMT @ Station
642 tcd.Set(tctime + (m_stationOffset_mins - m_diff_mins) * 60);
643
644 s.Printf(tcd.Format(_T("%H:%M ")));
645 s1.Printf(_T("%05.2f "), tcvalue); // write value
646 s.Append(s1);
647 Station_Data *pmsd = pIDX->pref_sta_data; // write unit
648 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
649 s.Append(_T(" "));
650 (wt) ? s.Append(_("HW")) : s.Append(_("LW")); // write HW or LT
651
652 wxListItem li;
653 li.SetId(list_index);
654 li.SetAlign(wxLIST_FORMAT_LEFT);
655 li.SetText(s);
656 li.SetColumn(0);
657 m_tList->InsertItem(li);
658 list_index++;
659 }
660 wt = !wt; // change tide flow sens
661 }
662 val = tcv[i];
663 }
664 if (CURRENT_PLOT == m_plot_type) {
665 wxDateTime thx; // write date
666 wxString s, s1;
667
668 thx.Set((time_t)tt - (m_diff_mins * 60));
669 if (m_tzoneDisplay == 0) // LMT @ Station
670 thx.Set((time_t)tt + (m_stationOffset_mins - m_diff_mins) * 60);
671
672 s.Printf(thx.Format(_T("%H:%M ")));
673 s1.Printf(_T("%05.2f "), fabs(tcv[i])); // write value
674 s.Append(s1);
675 Station_Data *pmsd = pIDX->pref_sta_data; // write unit
676 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
677 s1.Printf(_T(" %03.0f"), dir); // write direction
678 s.Append(s1);
679
680 wxListItem li;
681 li.SetId(list_index);
682 li.SetAlign(wxLIST_FORMAT_LEFT);
683 li.SetText(s);
684 li.SetColumn(0);
685 m_tList->InsertItem(li);
686 list_index++;
687 }
688 }
689
690 wxEndBusyCursor();
691
692 // Set up the vertical parameters based on Tide or Current plot
693 if (CURRENT_PLOT == m_plot_type) {
694 it = std::max(abs((int)tcmin - 1), abs((int)tcmax + 1));
695 ib = -it;
696
697 im = 2 * it;
698 m_plot_y_offset = m_graph_rect.height / 2;
699 val_off = 0;
700 } else {
701 ib = (int)tcmin;
702 if (tcmin < 0) ib -= 1;
703 it = (int)tcmax + 1;
704
705 im = it - ib; // abs ( ib ) + abs ( it );
706 m_plot_y_offset = (m_graph_rect.height * (it - ib)) / im;
707 val_off = ib;
708 }
709
710 // Arrange to skip some lines and legends if there are too many for the
711 // vertical space we have
712 int height_stext;
713 dc.GetTextExtent(_T("1"), NULL, &height_stext);
714 float available_lines = (float)m_graph_rect.height / height_stext;
715 i_skip = (int)ceil(im / available_lines);
716
717 if (CURRENT_PLOT == m_plot_type && i_skip != 1) {
718 // Adjust steps so slack current "0" line is always drawn on graph
719 ib -= it % i_skip;
720 it = -ib;
721 im = 2 * it;
722 }
723
724 // Build spline list of points
725
726 m_sList.DeleteContents(true);
727 m_sList.Clear();
728
729 for (i = 0; i < 26; i++) {
730 wxPoint *pp = new wxPoint;
731 pp->x = m_graph_rect.x + ((i)*m_graph_rect.width / 25);
732 pp->y = m_graph_rect.y + (m_plot_y_offset) -
733 (int)((tcv[i] - val_off) * m_graph_rect.height / im);
734
735 m_sList.Append(pp);
736 }
737
738 btc_valid = true;
739 }
740
741 dc.SetTextForeground(GetGlobalColor(_T ( "DILG3" )));
742
743 // Vertical Axis
744
745 i = ib;
746 while (i < it + 1) {
747 int yd = m_graph_rect.y + (m_plot_y_offset) -
748 ((i - val_off) * m_graph_rect.height / im);
749
750 if ((m_plot_y_offset + m_graph_rect.y) == yd)
751 dc.SetPen(*pblack_2);
752 else
753 dc.SetPen(*pblack_1);
754
755 dc.DrawLine(m_graph_rect.x, yd, m_graph_rect.x + m_graph_rect.width, yd);
756 snprintf(sbuf, 99, "%d", i);
757 dc.DrawText(wxString(sbuf, wxConvUTF8), m_graph_rect.x - 20, yd - 5);
758 i += i_skip;
759 }
760
761 // Draw the Value curve
762#if wxCHECK_VERSION(2, 9, 0)
763 wxPointList *list = (wxPointList *)&m_sList;
764#else
765 wxList *list = (wxList *)&m_sList;
766#endif
767
768 dc.SetPen(*pblack_2);
769#if wxUSE_SPLINES
770 dc.DrawSpline(list);
771#else
772 dc.DrawLines(list);
773#endif
774 // More Info
775
776 if (m_tzoneDisplay == 0) {
777 int station_offset = ptcmgr->GetStationTimeOffset(pIDX);
778 int h = station_offset / 60;
779 int m = station_offset - (h * 60);
780 if (m_graphday.IsDST()) h += 1;
781 m_stz.Printf(_T("UTC %+03d:%02d"), h, m);
782
783 // Make the "nice" (for the US) station time-zone string, brutally by
784 // hand
785 double lat = ptcmgr->GetStationLat(pIDX);
786
787 if (lat > 20.0) {
788 wxString mtz;
789 switch (ptcmgr->GetStationTimeOffset(pIDX)) {
790 case -240:
791 mtz = _T( "AST" );
792 break;
793 case -300:
794 mtz = _T( "EST" );
795 break;
796 case -360:
797 mtz = _T( "CST" );
798 break;
799 }
800
801 if (mtz.Len()) {
802 if (m_graphday.IsDST()) mtz[1] = 'D';
803 m_stz = mtz;
804 }
805 }
806 }
807
808 else
809 m_stz = _T("UTC");
810
811 int h;
812 dc.SetFont(*pSFont);
813 dc.GetTextExtent(m_stz, &w, &h);
814 dc.DrawText(m_stz, x / 2 - w / 2, y - 2.5 * m_button_height);
815
816 wxString sdate;
817 if (g_locale == _T("en_US"))
818 sdate = m_graphday.Format(_T ( "%A %b %d, %Y" ));
819 else
820 sdate = m_graphday.Format(_T ( "%A %d %b %Y" ));
821
822 dc.SetFont(*pMFont);
823 dc.GetTextExtent(sdate, &w, &h);
824 dc.DrawText(sdate, x / 2 - w / 2, y - 2.0 * m_button_height);
825
826 Station_Data *pmsd = pIDX->pref_sta_data;
827 if (pmsd) {
828 dc.GetTextExtent(wxString(pmsd->units_conv, wxConvUTF8), &w, &h);
829 dc.DrawRotatedText(wxString(pmsd->units_conv, wxConvUTF8), 5,
830 m_graph_rect.y + m_graph_rect.height / 2 + w / 2, 90.);
831 }
832
833 // Show flood and ebb directions
834 if ((strchr("c", pIDX->IDX_type)) || (strchr("C", pIDX->IDX_type))) {
835 dc.SetFont(*pSFont);
836
837 wxString fdir;
838 fdir.Printf(_T("%03d"), pIDX->IDX_flood_dir);
839 dc.DrawText(fdir, m_graph_rect.x + m_graph_rect.width + 4,
840 m_graph_rect.y + m_graph_rect.height * 1 / 4);
841
842 wxString edir;
843 edir.Printf(_T("%03d"), pIDX->IDX_ebb_dir);
844 dc.DrawText(edir, m_graph_rect.x + m_graph_rect.width + 4,
845 m_graph_rect.y + m_graph_rect.height * 3 / 4);
846 }
847
848 // Today or tomorrow
849 if ((m_button_height * 15) < x && cur_time) { // large enough horizontally?
850 wxString sday;
851
852 int day = m_graphday.GetDayOfYear();
853 if (m_graphday.GetYear() == this_now.GetYear()) {
854 if (day == this_now.GetDayOfYear())
855 sday.Append(_("Today"));
856 else if (day == this_now.GetDayOfYear() + 1)
857 sday.Append(_("Tomorrow"));
858 else
859 sday.Append(m_graphday.GetWeekDayName(m_graphday.GetWeekDay()));
860 } else if (m_graphday.GetYear() == this_now.GetYear() + 1 &&
861 day == this_now.Add(wxTimeSpan::Day()).GetDayOfYear())
862 sday.Append(_("Tomorrow"));
863
864 dc.SetFont(*pSFont);
865 dc.GetTextExtent(sday, &w, &h);
866 dc.DrawText(sday, 55 - w / 2, y - 2 * m_button_height);
867 }
868
869 // Render "Spot of interest"
870 double spotDim = 4 * g_Platform->GetDisplayDPmm();
871
872 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(
873 GetGlobalColor(_T ( "YELO1" )), wxBRUSHSTYLE_SOLID));
874 dc.SetPen(wxPen(GetGlobalColor(_T ( "URED" )),
875 wxMax(2, 0.5 * g_Platform->GetDisplayDPmm())));
876 dc.DrawRoundedRectangle(xSpot - spotDim / 2, ySpot - spotDim / 2, spotDim,
877 spotDim, spotDim / 2);
878
879 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(
880 GetGlobalColor(_T ( "UBLCK" )), wxBRUSHSTYLE_SOLID));
881 dc.SetPen(wxPen(GetGlobalColor(_T ( "UBLCK" )), 1));
882
883 double ispotDim = spotDim / 5.;
884 dc.DrawRoundedRectangle(xSpot - ispotDim / 2, ySpot - ispotDim / 2,
885 ispotDim, ispotDim, ispotDim / 2);
886 }
887}
888
889void TCWin::OnSize(wxSizeEvent &event) {
890 if (!m_created) return;
891
892 int x, y;
893 GetClientSize(&x, &y);
894
895 // establish some graphic element sizes/locations
896 int x_graph = x * 1 / 10;
897 int y_graph = y * 32 / 100;
898 int x_graph_w = x * 8 / 10;
899 int y_graph_h = (y * .7) - (7 * m_button_height / 2);
900 y_graph_h =
901 wxMax(y_graph_h, 2); // ensure minimum size is positive, at least.
902
903 m_graph_rect = wxRect(x_graph, y_graph, x_graph_w, y_graph_h);
904
905 // In the interest of readability, if the width of the dialog is too narrow,
906 // simply skip showing the "Hi/Lo" list control.
907
908 if ((m_tsy * 15) > x)
909 m_tList->Hide();
910 else {
911 m_tList->Move(wxPoint(x * 65 / 100, 11));
912 m_tList->Show();
913 }
914
915 wxSize texc_size = wxSize((x * 60 / 100), (y * 29 / 100));
916 if (!m_tList->IsShown()) {
917 texc_size = wxSize((x * 90 / 100), (y * 29 / 100));
918 }
919 m_ptextctrl->SetSize(texc_size);
920
921#ifdef __WXOSX__
922 OK_button->Move(wxPoint(x - (4 * m_tsy + 10), y - (m_tsy + 10)));
923#else
924 OK_button->Move(wxPoint(x - (3 * m_tsy + 10), y - (m_tsy + 10)));
925#endif
926 PR_button->Move(wxPoint(10, y - (m_tsy + 10)));
927
928 int bsx, bsy, bpx, bpy;
929 PR_button->GetSize(&bsx, &bsy);
930 PR_button->GetPosition(&bpx, &bpy);
931
932 NX_button->Move(wxPoint(bpx + bsx + 5, y - (m_tsy + 10)));
933
934 btc_valid = false;
935
936 Refresh(true);
937 Update();
938}
939
940void TCWin::MouseEvent(wxMouseEvent &event) {
941 event.GetPosition(&curs_x, &curs_y);
942
943 if (!m_TCWinPopupTimer.IsRunning())
944 m_TCWinPopupTimer.Start(20, wxTIMER_ONE_SHOT);
945}
946
947void TCWin::OnTCWinPopupTimerEvent(wxTimerEvent &event) {
948 int x, y;
949 bool ShowRollover;
950
951 GetClientSize(&x, &y);
952 wxRegion cursorarea(m_graph_rect);
953 if (cursorarea.Contains(curs_x, curs_y)) {
954 ShowRollover = true;
955 SetCursor(*pParent->pCursorCross);
956 if (NULL == m_pTCRolloverWin) {
957 m_pTCRolloverWin = new RolloverWin(this, -1, false);
958 // doesn't really work, mouse positions are relative to rollover window
959 // not this window.
960 // effect: hide rollover window if mouse on rollover
961 m_pTCRolloverWin->SetMousePropogation(1);
962 m_pTCRolloverWin->Hide();
963 }
964 float t, d;
965 wxString p, s;
966 // set time on x cursor position
967 t = (25 / ((float)x * 8 / 10)) * ((float)curs_x - ((float)x * 1 / 10));
968
969 int tt = m_t_graphday_GMT + (int)(t * 3600);
970 time_t ths = tt;
971
972 wxDateTime thd;
973 thd.Set(ths);
974 p.Printf(thd.Format(_T("%Hh %Mmn")));
975 p.Append(_T("\n"));
976
977 // The tide/current modules calculate values based on PC local time
978 // We want UTC, so adjust accordingly
979 int tt_localtz = m_t_graphday_GMT + (m_diff_mins * 60);
980
981 int ttv = tt_localtz + (int)(t * 3600);
982 if (m_tzoneDisplay == 0) {
983 ttv -= m_stationOffset_mins * 60; // LMT at station
984 }
985
986 time_t tts = ttv;
987
988 // set tide level or current speed at that time
989 ptcmgr->GetTideOrCurrent(tts, pIDX->IDX_rec_num, t, d);
990 s.Printf(_T("%3.2f "), (t < 0 && CURRENT_PLOT == m_plot_type)
991 ? -t
992 : t); // always positive if current
993 p.Append(s);
994
995 // set unit
996 Station_Data *pmsd = pIDX->pref_sta_data;
997 if (pmsd) p.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
998
999 // set current direction
1000 if (CURRENT_PLOT == m_plot_type) {
1001 s.Printf("%3.0f%c", d, 0x00B0);
1002 p.Append(_T("\n"));
1003 p.Append(s);
1004 }
1005
1006 // set rollover area size
1007 wxSize win_size;
1008 win_size.Set(x * 90 / 100, y * 80 / 100);
1009
1010 m_pTCRolloverWin->SetString(p);
1011 m_pTCRolloverWin->SetBestPosition(curs_x, curs_y, 1, 1, TC_ROLLOVER,
1012 win_size);
1013 m_pTCRolloverWin->SetBitmap(TC_ROLLOVER);
1014 m_pTCRolloverWin->Refresh();
1015 m_pTCRolloverWin->Show();
1016
1017 // Mark the actual spot on the curve
1018 // x value is clear...
1019 // Find the point in the window that is used for the curev rendering,
1020 // rounding as necessary
1021
1022 int idx = 1; // in case m_graph_rect.width is weird ie ppx never > curs_x
1023 for (int i = 0; i < 26; i++) {
1024 float ppx = m_graph_rect.x + ((i)*m_graph_rect.width / 25.f);
1025 if (ppx > curs_x) {
1026 idx = i;
1027 break;
1028 }
1029 }
1030
1031 wxPointList *list = (wxPointList *)&m_sList;
1032 wxPoint *a = list->Item(idx - 1)->GetData();
1033 wxPoint *b = list->Item(idx)->GetData();
1034
1035 float pct = (curs_x - a->x) / (float)((b->x - a->x));
1036 float dy = pct * (b->y - a->y);
1037
1038 ySpot = a->y + dy;
1039 xSpot = curs_x;
1040
1041 Refresh(true);
1042
1043 } else {
1044 SetCursor(*pParent->pCursorArrow);
1045 ShowRollover = false;
1046 }
1047
1048 if (m_pTCRolloverWin && m_pTCRolloverWin->IsShown() && !ShowRollover) {
1049 m_pTCRolloverWin->Hide();
1050 }
1051}
Definition: IDX_entry.h:41
Definition: tcmgr.h:86
Definition: TCWin.h:46