31#include <wx/dcbuffer.h>
32#include <wx/listctrl.h>
56#include "user_colors.h"
58extern ColorScheme global_color_scheme;
64 SetMinSize(wxSize(400, 200));
65 Bind(wxEVT_PAINT, &TideChartPanel::OnPaint,
this);
66 Bind(wxEVT_MOTION, &TideChartPanel::OnMouseMove,
this);
67 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
74 dc.GetTextExtent(
"W", NULL, &text_height);
75 m_refTCWTextHeight = text_height;
79 void OnPaint(wxPaintEvent &event) {
83 dc.SetBackground(wxBrush(GetBackgroundColour()));
87 wxSize panelSize = GetClientSize();
88 if (panelSize.GetWidth() <= 0 || panelSize.GetHeight() <= 0) {
94 int other_margins = 5;
95 int chart_width = panelSize.GetWidth() - left_margin - other_margins;
96 int chart_height = panelSize.GetHeight() - (2 * other_margins);
99 int bottom_text_space = 6 * m_refTCWTextHeight;
100 chart_height -= bottom_text_space;
101 chart_width = wxMax(chart_width, 300);
102 chart_height = wxMax(chart_height, 150);
103 wxRect chartRect(left_margin, other_margins, chart_width, chart_height);
106 m_tcWin->PaintChart(dc, chartRect);
109 void OnMouseMove(wxMouseEvent &event) {
110 wxPoint panelPos =
event.GetPosition();
111 wxPoint mainWindowPos = panelPos + GetPosition();
112 m_tcWin->HandleChartMouseMove(mainWindowPos.x, mainWindowPos.y, panelPos);
117 int m_refTCWTextHeight;
120enum { ID_TCWIN_NX, ID_TCWIN_PR };
122enum { TIDE_PLOT, CURRENT_PLOT };
124BEGIN_EVENT_TABLE(
TCWin, wxWindow)
125EVT_PAINT(TCWin::OnPaint)
126EVT_SIZE(TCWin::OnSize)
127EVT_MOTION(TCWin::MouseEvent)
128EVT_BUTTON(wxID_OK, TCWin::OKEvent)
129EVT_BUTTON(ID_TCWIN_NX, TCWin::NXEvent)
130EVT_BUTTON(ID_TCWIN_PR, TCWin::PREvent)
131EVT_CLOSE(TCWin::OnCloseWindow)
132EVT_TIMER(TCWININF_TIMER, TCWin::OnTCWinPopupTimerEvent)
133EVT_TIMER(TCWIN_TIME_INDICATOR_TIMER, TCWin::OnTimeIndicatorTimer)
142 m_pTCRolloverWin = NULL;
144 long wstyle = wxCLIP_CHILDREN | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER |
145 wxFRAME_FLOAT_ON_PARENT;
155 pConfig->SetPath(
"/Settings/Others");
156 pConfig->Read(
"TCWindowTimeZone", &m_tzoneDisplay, 0);
159 wxFrame::Create(parent, wxID_ANY, wxString(
""), m_position, m_tc_size,
169 if (strchr(
"Tt", pIDX->IDX_type)) {
170 m_plot_type = TIDE_PLOT;
171 SetTitle(wxString(_(
"Tide")));
174 m_plot_type = CURRENT_PLOT;
175 SetTitle(wxString(_(
"Current")));
179 GetClientSize(&sx, &sy);
189 dc.GetTextExtent(
"W", NULL, &text_height);
190 m_refTextHeight = text_height;
194 m_graph_rect = wxRect(0, 0, 400, 200);
197 wxButton *test_button =
198 new wxButton(
this, wxID_OK, _(
"OK"), wxPoint(-1, -1), wxDefaultSize);
199 test_button->GetSize(&m_tsx, &m_tsy);
202 m_TCWinPopupTimer.SetOwner(
this, TCWININF_TIMER);
205 m_TimeIndicatorTimer.SetOwner(
this, TCWIN_TIME_INDICATOR_TIMER);
206 m_TimeIndicatorTimer.Start(60000,
false);
208 m_button_height = m_tsy;
212 wxFont *dlg_font = FontMgr::Get().
GetFont(_(
"Dialog"));
213 int dlg_font_size = dlg_font->GetPointSize();
214#if defined(__WXOSX__) || defined(__WXGTK3__)
216 dlg_font_size /= GetContentScaleFactor();
220 dlg_font_size - 2, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
221 wxFONTWEIGHT_NORMAL, FALSE, wxString(
"Arial"));
223 dlg_font_size - 1, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
224 wxFONTWEIGHT_NORMAL, FALSE, wxString(
"Arial"));
226 dlg_font_size, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD,
227 FALSE, wxString(
"Arial"));
229 dlg_font_size + 1, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
230 wxFONTWEIGHT_BOLD, FALSE, wxString(
"Arial"));
233 pblack_1 = wxThePenList->FindOrCreatePen(
234 this->GetForegroundColour(), wxMax(1, (
int)(m_tcwin_scaler + 0.5)),
237 pblack_2 = wxThePenList->FindOrCreatePen(
238 this->GetForegroundColour(), wxMax(2, (
int)(2 * m_tcwin_scaler + 0.5)),
241 pblack_3 = wxThePenList->FindOrCreatePen(
242 wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW),
243 wxMax(1, (
int)(m_tcwin_scaler + 0.5)), wxPENSTYLE_SOLID);
246 pred_2 = wxThePenList->FindOrCreatePen(
247 wxColor(230, 54, 54), wxMax(4, (
int)(4 * m_tcwin_scaler + 0.5)),
251 pred_time = wxThePenList->FindOrCreatePen(
252 wxColour(0, 100, 255), wxMax(4, (
int)(4 * m_tcwin_scaler + 0.5)),
255 pltgray = wxTheBrushList->FindOrCreateBrush(this->GetBackgroundColour(),
258 pltgray2 = wxTheBrushList->FindOrCreateBrush(this->GetBackgroundColour(),
260 pgraph = wxThePenList->FindOrCreatePen(
261 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),
262 wxMax(1, (
int)(m_tcwin_scaler + 0.5)), wxPENSTYLE_SOLID);
267 InitializeStationText();
274 m_TimeIndicatorTimer.Stop();
275 pParent->Refresh(
false);
278void TCWin::CreateLayout() {
280 wxBoxSizer *mainSizer =
new wxBoxSizer(wxVERTICAL);
283 m_topPanel =
new wxPanel(
this, wxID_ANY);
284 wxBoxSizer *topSizer =
new wxBoxSizer(wxHORIZONTAL);
288 new wxTextCtrl(m_topPanel, -1,
"", wxDefaultPosition, wxDefaultSize,
289 wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
290 m_ptextctrl->SetMinSize(wxSize(
291 25 * m_refTextHeight, 7 * m_refTextHeight));
294 m_tList =
new wxListCtrl(m_topPanel, -1, wxDefaultPosition, wxDefaultSize,
295 wxLC_REPORT | wxLC_NO_HEADER);
297 wxSize(18 * m_refTextHeight,
298 4 * m_refTextHeight));
304 col0.SetAlign(wxLIST_FORMAT_LEFT);
305 col0.SetWidth(20 * m_refTextHeight);
306 m_tList->InsertColumn(0, col0);
309 topSizer->Add(m_ptextctrl, 2, wxEXPAND | wxALL,
311 topSizer->Add(m_tList, 1, wxEXPAND | wxALL, 5);
313 m_topPanel->SetSizer(topSizer);
316 m_chartPanel =
new TideChartPanel(
this);
319 m_buttonPanel =
new wxPanel(
this, wxID_ANY);
320 wxBoxSizer *buttonSizer =
new wxBoxSizer(wxHORIZONTAL);
323 PR_button =
new wxButton(m_buttonPanel, ID_TCWIN_PR, _(
"Prev"));
324 NX_button =
new wxButton(m_buttonPanel, ID_TCWIN_NX, _(
"Next"));
325 OK_button =
new wxButton(m_buttonPanel, wxID_OK, _(
"OK"));
328 wxString choiceOptions[] = {_(
"LMT@Station"), _(
"UTC")};
329 int numChoices =
sizeof(choiceOptions) /
sizeof(wxString);
330 m_choiceTimezone =
new wxChoice(m_buttonPanel, wxID_ANY, wxDefaultPosition,
331 wxDefaultSize, numChoices, choiceOptions);
332 m_choiceTimezone->SetSelection(m_tzoneDisplay);
333 m_choiceTimezone->SetToolTip(
334 _(
"Select whether tide times are shown in UTC or Local Mean Time (LMT) "
338 buttonSizer->Add(PR_button, 0, wxALL, 5);
339 buttonSizer->Add(NX_button, 0, wxALL, 5);
340 buttonSizer->AddStretchSpacer(1);
341 buttonSizer->Add(m_choiceTimezone, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
342 buttonSizer->AddSpacer(10);
343 buttonSizer->Add(OK_button, 0, wxALL, 5);
345 m_buttonPanel->SetSizer(buttonSizer);
348 mainSizer->Add(m_topPanel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP,
350 mainSizer->Add(m_chartPanel, 1, wxEXPAND | wxLEFT | wxRIGHT,
352 mainSizer->Add(m_buttonPanel, 0, wxEXPAND | wxALL,
359 m_choiceTimezone->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
360 wxCommandEventHandler(TCWin::TimezoneOnChoice),
364void TCWin::InitializeStationText() {
366 m_ptextctrl->Clear();
369 wxString locna, locnb;
370 if (locn.Contains(wxString(
","))) {
371 locna = locn.BeforeFirst(
',');
372 locnb = locn.AfterFirst(
',');
380 style.SetFont(*pLFont);
381 m_ptextctrl->SetDefaultStyle(style);
383 m_ptextctrl->AppendText(locna);
384 m_ptextctrl->AppendText(
"\n");
386 style.SetFont(*pSMFont);
387 m_ptextctrl->SetDefaultStyle(style);
389 if (!locnb.IsEmpty()) m_ptextctrl->AppendText(locnb);
390 m_ptextctrl->AppendText(
"\n");
397 m_ptextctrl->AppendText(_(
"Reference Station :"));
398 m_ptextctrl->AppendText(
"\n");
400 m_ptextctrl->AppendText(mref);
401 m_ptextctrl->AppendText(
"\n");
404 m_ptextctrl->AppendText(
"\n");
409 dsource.Prepend(
" ");
411 m_ptextctrl->AppendText(_(
"Data Source :"));
412 m_ptextctrl->AppendText(
"\n");
414 m_ptextctrl->AppendText(dsource);
416 m_ptextctrl->SetInsertionPoint(0);
417 m_ptextctrl->ShowPosition(0);
420void TCWin::PaintChart(wxDC &dc,
const wxRect &chartRect) {
426 wxRect originalGraphRect = m_graph_rect;
427 m_graph_rect = chartRect;
434 if (m_graph_rect.x == 0) {
435 m_graph_rect = originalGraphRect;
441 GetClientSize(&x, &y);
444 pblack_1->SetColour(this->GetForegroundColour());
445 pblack_2->SetColour(this->GetForegroundColour());
446 pltgray->SetColour(this->GetBackgroundColour());
447 pltgray2->SetColour(this->GetBackgroundColour());
449 GetGlobalColor(
"URED"));
450 pred_time->SetColour(
451 GetGlobalColor(
"UINFB"));
454 dc.SetPen(*pblack_1);
455 dc.SetBrush(*pltgray);
456 dc.DrawRectangle(m_graph_rect.x, m_graph_rect.y, m_graph_rect.width,
457 m_graph_rect.height);
462 const int hour_delta = 4;
464 const int hour_delta = 1;
471 for (i = 0; i < 25; i++) {
472 int xd = m_graph_rect.x + ((i)*m_graph_rect.width / 25);
473 if (hour_delta != 1) {
474 if (i % hour_delta == 0) {
475 dc.SetPen(*pblack_2);
476 dc.DrawLine(xd, m_graph_rect.y, xd,
477 m_graph_rect.y + m_graph_rect.height + 5);
479 int hour_show = hour_start + i;
480 if (hour_show >= 24) hour_show -= 24;
481 sprintf(sbuf,
"%02d", hour_show);
483 dc.DrawText(wxString(sbuf, wxConvUTF8),
484 xd + x_shim + (m_graph_rect.width / 25) / 2,
485 m_graph_rect.y + m_graph_rect.height + 8);
487 dc.SetPen(*pblack_1);
488 dc.DrawLine(xd, m_graph_rect.y, xd,
489 m_graph_rect.y + m_graph_rect.height + 5);
492 dc.SetPen(*pblack_1);
493 dc.DrawLine(xd, m_graph_rect.y, xd,
494 m_graph_rect.y + m_graph_rect.height + 5);
496 sst.Printf(
"%02d", i);
497 dc.DrawRotatedText(sst, xd + (m_graph_rect.width / 25) / 2,
498 m_graph_rect.y + m_graph_rect.height + 8, 270.);
503 wxDateTime system_now = wxDateTime::Now();
504 wxDateTime this_now = gTimeSource;
505 bool cur_time = !gTimeSource.IsValid();
506 if (cur_time) this_now = wxDateTime::Now();
509 time_t t_system_now = system_now.GetTicks();
510 t_system_now -= m_diff_mins * 60;
511 if (m_tzoneDisplay == 0)
512 t_system_now += m_stationOffset_mins * 60;
514 float t_system_ratio =
515 m_graph_rect.width * (t_system_now - m_t_graphday_GMT) / (25 * 3600.0f);
516 int x_system = (t_system_ratio < 0 || t_system_ratio > m_graph_rect.width)
518 : m_graph_rect.x + (int)t_system_ratio;
522 dc.DrawLine(x_system, m_graph_rect.y, x_system,
523 m_graph_rect.y + m_graph_rect.height);
528 if (gTimeSource.IsValid()) {
529 time_t t_selected_time = gTimeSource.GetTicks();
530 if (abs(t_selected_time - t_system_now) > 300) {
531 t_selected_time -= m_diff_mins * 60;
532 if (m_tzoneDisplay == 0)
533 t_selected_time += m_stationOffset_mins * 60;
535 float t_selected_time_ratio = m_graph_rect.width *
536 (t_selected_time - m_t_graphday_GMT) /
538 int x_selected_time = (t_selected_time_ratio < 0 ||
539 t_selected_time_ratio > m_graph_rect.width)
541 : m_graph_rect.x + (int)t_selected_time_ratio;
543 if (x_selected_time >= 0) {
544 dc.SetPen(*pred_time);
545 dc.DrawLine(x_selected_time, m_graph_rect.y, x_selected_time,
546 m_graph_rect.y + m_graph_rect.height);
550 dc.SetPen(*pblack_1);
558 m_tList->DeleteAllItems();
566 int tt_localtz = m_t_graphday_GMT + (m_diff_mins * 60);
568 if (m_tzoneDisplay == 0)
569 tt_localtz -= m_stationOffset_mins * 60;
572 ptcmgr->GetTideFlowSens(tt_localtz, BACKWARD_TEN_MINUTES_STEP,
575 for (i = 0; i < 26; i++) {
576 int tt = tt_localtz + (i * FORWARD_ONE_HOUR_STEP);
579 float tcvalue_i = tcv[i];
585 int unit_c = TCDataFactory::findunit(pmsd->unit);
587 tcv[i] = tcv[i] * TCDataFactory::known_units[unit_c].conv_factor;
590 if (CURRENT_PLOT == m_plot_type)
591 tcv[i] = toUsrSpeed(tcv[i]);
596 if (tcv[i] > tcmax) tcmax = tcv[i];
597 if (tcv[i] < tcmin) tcmin = tcv[i];
599 if (TIDE_PLOT == m_plot_type) {
600 if (!((tcv[i] > val) == wt) && (i > 0)) {
603 ptcmgr->GetHightOrLowTide(tt, BACKWARD_TEN_MINUTES_STEP,
604 BACKWARD_ONE_MINUTES_STEP, tcvalue_i, wt,
606 if (tctime > tt_localtz) {
610 tcd.Set(tctime - (m_diff_mins * 60));
611 if (m_tzoneDisplay == 0)
612 tcd.Set(tctime + (m_stationOffset_mins - m_diff_mins) * 60);
614 s.Printf(tcd.Format(
"%H:%M "));
618 double tcvalue_converted = tcvalue;
622 int unit_c = TCDataFactory::findunit(pmsd->unit);
626 TCDataFactory::known_units[unit_c].conv_factor;
629 if (CURRENT_PLOT == m_plot_type)
630 tcvalue_converted = toUsrSpeed(tcvalue_converted);
632 tcvalue_converted =
toUsrHeight(tcvalue_converted);
635 s1.Printf(
"%05.2f ", tcvalue_converted);
639 (wt) ? s.Append(_(
"HW")) : s.Append(_(
"LW"));
642 li.SetId(list_index);
643 li.SetAlign(wxLIST_FORMAT_LEFT);
646 m_tList->InsertItem(li);
653 if (CURRENT_PLOT == m_plot_type) {
656 thx.Set((time_t)tt - (m_diff_mins * 60));
657 if (m_tzoneDisplay == 0)
658 thx.Set((time_t)tt + (m_stationOffset_mins - m_diff_mins) * 60);
660 s.Printf(thx.Format(
"%H:%M "));
664 s.Append(getUsrSpeedUnit());
665 s1.Printf(
" %03.0f", dir);
669 li.SetId(list_index);
670 li.SetAlign(wxLIST_FORMAT_LEFT);
673 m_tList->InsertItem(li);
681 if (CURRENT_PLOT == m_plot_type) {
682 it = std::max(abs((
int)tcmin - 1), abs((
int)tcmax + 1));
685 m_plot_y_offset = m_graph_rect.height / 2;
689 if (tcmin < 0) ib -= 1;
692 m_plot_y_offset = (m_graph_rect.height * (it - ib)) / im;
699 dc.GetTextExtent(
"1", NULL, &height_stext);
700 float available_lines = (float)m_graph_rect.height / height_stext;
701 i_skip = (int)ceil(im / available_lines);
703 if (CURRENT_PLOT == m_plot_type && i_skip != 1) {
711 for (
auto it = m_sList.begin(); it != m_sList.end(); it++)
delete (*it);
714 for (i = 0; i < 26; i++) {
715 wxPoint *pp =
new wxPoint;
716 pp->x = m_graph_rect.x + ((i)*m_graph_rect.width / 25);
717 pp->y = m_graph_rect.y + (m_plot_y_offset) -
718 (
int)((tcv[i] - val_off) * m_graph_rect.height / im);
719 m_sList.push_back(pp);
726 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
731 int yd = m_graph_rect.y + (m_plot_y_offset) -
732 ((i - val_off) * m_graph_rect.height / im);
733 if ((m_plot_y_offset + m_graph_rect.y) == yd)
734 dc.SetPen(*pblack_2);
736 dc.SetPen(*pblack_1);
738 dc.DrawLine(m_graph_rect.x, yd, m_graph_rect.x + m_graph_rect.width, yd);
739 if ((yd < m_graph_rect.height * 48 / 100) ||
740 (yd > m_graph_rect.height * 52 / 100)) {
741 snprintf(sbuf, 99,
"%d", i);
742 dc.DrawText(wxString(sbuf, wxConvUTF8), m_graph_rect.x - 20, yd - 5);
749 for (
auto &p : m_sList) list.Append(p);
753 dc.DrawSpline(&list);
759 if (m_tzoneDisplay == 0) {
760 int station_offset =
ptcmgr->GetStationTimeOffset(pIDX);
761 int h = station_offset / 60;
762 int m = station_offset - (h * 60);
763 if (m_graphday.IsDST()) h += 1;
764 m_stz.Printf(
"UTC %+03d:%02d", h, m);
768 double lat =
ptcmgr->GetStationLat(pIDX);
771 switch (
ptcmgr->GetStationTimeOffset(pIDX)) {
783 if (m_graphday.IsDST()) mtz[1] =
'D';
793 dc.GetTextExtent(m_stz, &w, &h);
795 dc.DrawText(m_stz, m_graph_rect.x + (m_graph_rect.width / 2) - (w / 2),
796 m_graph_rect.y + m_graph_rect.height + (2 * h));
799 if (g_locale ==
"en_US")
800 sdate = m_graphday.Format(
"%A %b %d, %Y");
802 sdate = m_graphday.Format(
"%A %d %b %Y");
805 dc.GetTextExtent(sdate, &w, &h);
807 dc.DrawText(sdate, m_graph_rect.x + (m_graph_rect.width / 2) - (w / 2),
808 m_graph_rect.y + m_graph_rect.height + (5 * h / 2));
812 if (CURRENT_PLOT == m_plot_type) {
814 wxString speed_unit = getUsrSpeedUnit();
815 dc.GetTextExtent(speed_unit, &w, &h);
816 dc.DrawRotatedText(speed_unit, 0,
817 m_graph_rect.y + m_graph_rect.height / 2 + w / 2, 90.);
821 dc.GetTextExtent(height_unit, &w, &h);
822 dc.DrawRotatedText(height_unit, 0,
823 m_graph_rect.y + m_graph_rect.height / 2 + w / 2, 90.);
832 dc.DrawText(fdir, m_graph_rect.x + m_graph_rect.width + 4,
833 m_graph_rect.y + m_graph_rect.height * 1 / 4);
837 dc.DrawText(edir, m_graph_rect.x + m_graph_rect.width + 4,
838 m_graph_rect.y + m_graph_rect.height * 3 / 4);
842 if ((m_button_height * 15) < x && cur_time) {
844 int day = m_graphday.GetDayOfYear();
845 if (m_graphday.GetYear() == this_now.GetYear()) {
846 if (day == this_now.GetDayOfYear())
847 sday.Append(_(
"Today"));
848 else if (day == this_now.GetDayOfYear() + 1)
849 sday.Append(_(
"Tomorrow"));
851 sday.Append(m_graphday.GetWeekDayName(m_graphday.GetWeekDay()));
852 }
else if (m_graphday.GetYear() == this_now.GetYear() + 1 &&
853 day == this_now.Add(wxTimeSpan::Day()).GetDayOfYear())
854 sday.Append(_(
"Tomorrow"));
857 dc.GetTextExtent(sday, &w, &h);
859 dc.DrawText(sday, m_graph_rect.x,
860 m_graph_rect.y + m_graph_rect.height + (2 * h));
864 double spotDim = 4 * g_Platform->GetDisplayDPmm();
865 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(GetGlobalColor(
"YELO1"),
866 wxBRUSHSTYLE_SOLID));
867 dc.SetPen(wxPen(GetGlobalColor(
"URED"),
868 wxMax(2, 0.5 * g_Platform->GetDisplayDPmm())));
869 dc.DrawRoundedRectangle(xSpot - spotDim / 2, ySpot - spotDim / 2, spotDim,
870 spotDim, spotDim / 2);
872 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(GetGlobalColor(
"UBLCK"),
873 wxBRUSHSTYLE_SOLID));
874 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
875 double ispotDim = spotDim / 5.;
876 dc.DrawRoundedRectangle(xSpot - ispotDim / 2, ySpot - ispotDim / 2, ispotDim,
877 ispotDim, ispotDim / 2);
880 m_graph_rect = originalGraphRect;
883void TCWin::SetTimeFactors() {
885 wxDateTime this_now = gTimeSource;
886 bool cur_time = !gTimeSource.IsValid();
889 this_now = wxDateTime::Now();
891 wxDateTime this_gmt = this_now.ToGMT();
893#if wxCHECK_VERSION(2, 6, 2)
894 wxTimeSpan diff = this_now.Subtract(this_gmt);
896 wxTimeSpan diff = this_gmt.Subtract(this_now);
899 m_diff_mins = diff.GetMinutes();
904#if wxCHECK_VERSION(3, 0, 2)
905 if (m_diff_mins == 0 && this_now.IsDST()) m_diff_mins += 60;
908 int station_offset =
ptcmgr->GetStationTimeOffset(pIDX);
910 m_stationOffset_mins = station_offset;
911 if (this_now.IsDST()) {
912 m_stationOffset_mins += 60;
918#if wxCHECK_VERSION(3, 0, 2)
925 m_graphday = this_gmt;
927 int day_gmt = this_gmt.GetDayOfYear();
929 time_t ttNow = this_now.GetTicks();
930 time_t tt_at_station =
931 ttNow - (m_diff_mins * 60) + (m_stationOffset_mins * 60);
932 wxDateTime atStation(tt_at_station);
933 int day_at_station = atStation.GetDayOfYear();
935 if (day_gmt > day_at_station) {
936 wxTimeSpan dt(24, 0, 0, 0);
937 m_graphday.Subtract(dt);
938 }
else if (day_gmt < day_at_station) {
939 wxTimeSpan dt(24, 0, 0, 0);
943 wxDateTime graphday_00 = m_graphday;
944 graphday_00.ResetTime();
945 time_t t_graphday_00 = graphday_00.GetTicks();
951 m_t_graphday_GMT = t_graphday_00;
956void TCWin::TimezoneOnChoice(wxCommandEvent &event) {
957 m_tzoneDisplay = m_choiceTimezone->GetSelection();
959 m_chartPanel->Refresh();
963void TCWin::RecalculateSize() {
964 wxSize parent_size(2000, 2000);
965 if (pParent) parent_size = pParent->GetClientSize();
967 int unscaledheight = 600;
968 int unscaledwidth = 650;
974 g_tcwin_scale = wxMax(g_tcwin_scale, 10);
975 m_tcwin_scaler = g_Platform->GetDisplayDPmm() * 0.254 * g_tcwin_scale / 100.0;
977 m_tc_size.x = (int)(unscaledwidth * m_tcwin_scaler + 0.5);
978 m_tc_size.y = (int)(unscaledheight * m_tcwin_scaler + 0.5);
980 m_tc_size.x = wxMin(m_tc_size.x, parent_size.x);
981 m_tc_size.y = wxMin(m_tc_size.y, parent_size.y);
988 if ((m_x + 8 + m_tc_size.x) > parent_size.x) xc = xc - m_tc_size.x - 16;
989 if ((m_y + m_tc_size.y) > parent_size.y) yc = yc - m_tc_size.y;
995 if (pParent) pParent->ClientToScreen(&xc, &yc);
996 m_position = wxPoint(xc, yc);
1004void TCWin::OKEvent(wxCommandEvent &event) {
1008 if (pParent && pParent->pCwin ==
this) {
1009 pParent->pCwin = NULL;
1014 delete m_pTCRolloverWin;
1015 m_pTCRolloverWin = NULL;
1020 pParent->Refresh(
false);
1025 pConfig->SetPath(
"/Settings/Others");
1026 pConfig->Write(
"TCWindowTimeZone", m_tzoneDisplay);
1032void TCWin::OnCloseWindow(wxCloseEvent &event) {
1036 if (pParent && pParent->pCwin ==
this) {
1037 pParent->pCwin = NULL;
1042 delete m_pTCRolloverWin;
1043 m_pTCRolloverWin = NULL;
1049 pConfig->SetPath(
"/Settings/Others");
1050 pConfig->Write(
"TCWindowTimeZone", m_tzoneDisplay);
1056void TCWin::NXEvent(wxCommandEvent &event) {
1057 wxTimeSpan dt(24, 0, 0, 0);
1059 wxDateTime dm = m_graphday;
1061 wxDateTime graphday_00 = dm.ResetTime();
1062 time_t t_graphday_00 = graphday_00.GetTicks();
1064 if (!graphday_00.IsDST() && m_graphday.IsDST()) t_graphday_00 -= 3600;
1065 if (graphday_00.IsDST() && !m_graphday.IsDST()) t_graphday_00 += 3600;
1067 m_t_graphday_GMT = t_graphday_00;
1070 m_chartPanel->Refresh();
1074void TCWin::PREvent(wxCommandEvent &event) {
1075 wxTimeSpan dt(-24, 0, 0, 0);
1077 wxDateTime dm = m_graphday;
1079 wxDateTime graphday_00 = dm.ResetTime();
1080 time_t t_graphday_00 = graphday_00.GetTicks();
1082 if (!graphday_00.IsDST() && m_graphday.IsDST()) t_graphday_00 -= 3600;
1083 if (graphday_00.IsDST() && !m_graphday.IsDST()) t_graphday_00 += 3600;
1085 m_t_graphday_GMT = t_graphday_00;
1088 m_chartPanel->Refresh();
1092void TCWin::RePosition() {
1099 pParent->ClientToScreen(&r.x, &r.y);
1103void TCWin::OnPaint(wxPaintEvent &event) {
1115 dc.SetBrush(wxBrush(GetBackgroundColour()));
1116 dc.SetPen(wxPen(GetBackgroundColour()));
1117 wxSize size = GetClientSize();
1118 dc.DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());
1124void TCWin::OnSize(wxSizeEvent &event) {
1125 if (!m_created)
return;
1132 m_chartPanel->Refresh();
1142void TCWin::MouseEvent(wxMouseEvent &event) {
1145 event.GetPosition(&curs_x, &curs_y);
1147 if (!m_TCWinPopupTimer.IsRunning())
1148 m_TCWinPopupTimer.Start(20, wxTIMER_ONE_SHOT);
1151void TCWin::HandleChartMouseMove(
int mainWindowX,
int mainWindowY,
1152 const wxPoint &chartPanelPos) {
1155 curs_x = mainWindowX;
1156 curs_y = mainWindowY;
1161 wxSize panelSize = m_chartPanel->GetClientSize();
1162 int left_margin = 50;
1163 int other_margins = 5;
1164 int chart_width = panelSize.GetWidth() - left_margin - other_margins;
1165 int chart_height = panelSize.GetHeight() - (2 * other_margins);
1166 int bottom_text_space = 50;
1167 chart_height -= bottom_text_space;
1168 chart_width = wxMax(chart_width, 300);
1169 chart_height = wxMax(chart_height, 150);
1172 wxPoint chartPanelPos = m_chartPanel->GetPosition();
1174 wxRect(chartPanelPos.x + left_margin, chartPanelPos.y + other_margins,
1175 chart_width, chart_height);
1178 if (!m_TCWinPopupTimer.IsRunning())
1179 m_TCWinPopupTimer.Start(20, wxTIMER_ONE_SHOT);
1182void TCWin::OnTCWinPopupTimerEvent(wxTimerEvent &event) {
1186 GetClientSize(&x, &y);
1187 wxRegion cursorarea(m_graph_rect);
1188 if (cursorarea.Contains(curs_x, curs_y)) {
1189 ShowRollover =
true;
1190 SetCursor(*pParent->pCursorCross);
1191 if (NULL == m_pTCRolloverWin) {
1192 m_pTCRolloverWin =
new RolloverWin(
this, -1,
false);
1196 m_pTCRolloverWin->SetMousePropogation(1);
1197 m_pTCRolloverWin->Hide();
1205 (float)(curs_x - m_graph_rect.x) / (float)m_graph_rect.width;
1206 t = relativeX * 25.0f;
1209 t = wxMax(0.0f, wxMin(25.0f, t));
1211 int tt = m_t_graphday_GMT + (int)(t * 3600);
1216 p.Printf(thd.Format(
"%Hh %Mmn"));
1221 int tt_localtz = m_t_graphday_GMT + (m_diff_mins * 60);
1223 int ttv = tt_localtz + (int)(t * 3600);
1224 if (m_tzoneDisplay == 0) {
1225 ttv -= m_stationOffset_mins * 60;
1234 double t_converted = (t < 0 && CURRENT_PLOT == m_plot_type) ? -t : t;
1238 int unit_c = TCDataFactory::findunit(pmsd->unit);
1241 t_converted * TCDataFactory::known_units[unit_c].conv_factor;
1244 if (CURRENT_PLOT == m_plot_type)
1245 t_converted = toUsrSpeed(t_converted);
1250 s.Printf(
"%3.2f ", t_converted);
1254 if (CURRENT_PLOT == m_plot_type)
1255 p.Append(getUsrSpeedUnit());
1260 if (CURRENT_PLOT == m_plot_type) {
1261 s.Printf(
"%3.0f%c", d, 0x00B0);
1268 win_size.Set(x * 90 / 100, y * 80 / 100);
1270 m_pTCRolloverWin->SetString(p);
1271 m_pTCRolloverWin->SetBestPosition(curs_x, curs_y, 1, 1, TC_ROLLOVER,
1273 m_pTCRolloverWin->SetBitmap(TC_ROLLOVER);
1274 m_pTCRolloverWin->Refresh();
1275 m_pTCRolloverWin->Show();
1283 for (
int i = 0; i < 26; i++) {
1284 float ppx = m_graph_rect.x + ((i)*m_graph_rect.width / 25.f);
1291 if (m_sList.size() > 0 && idx > 0 && idx < (int)m_sList.size()) {
1293 auto it_a = m_sList.begin();
1294 std::advance(it_a, idx - 1);
1295 auto it_b = m_sList.begin();
1296 std::advance(it_b, idx);
1301 float pct = (curs_x - a->x) / (
float)((b->x - a->x));
1302 float dy = pct * (b->y - a->y);
1309 ySpot = m_graph_rect.y + m_graph_rect.height / 2;
1315 SetCursor(*pParent->pCursorArrow);
1316 ShowRollover =
false;
1319 if (m_pTCRolloverWin && m_pTCRolloverWin->IsShown() && !ShowRollover) {
1320 m_pTCRolloverWin->Hide();
1324void TCWin::OnTimeIndicatorTimer(wxTimerEvent &event) {
Minimal ChartCanvas interfaces.
Generic Chart canvas base.
Minimal ChartCAnvas interface with very little dependencies.
ChartCanvas - Main chart display and interaction component.
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
char IDX_reference_name[MAXNAMELEN]
Name of the reference station.
int IDX_flood_dir
Flood current direction (in degrees)
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
char source_ident[MAXNAMELEN]
Identifier of the source (typically file name)
int IDX_ebb_dir
Ebb current direction (in degrees)
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Global variables stored in configuration file.
Extern C linked utilities.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
General purpose GUI support.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
MyConfig * pConfig
Global instance.
wxString getUsrHeightUnit(int unit)
Get the abbreviation for the preferred height unit.
double toUsrHeight(double m_height, int unit)
Convert height from meters to preferred height units.
Tide and current data container.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
Timer identification constants.