24#include <wx/clipbrd.h>
53#define GLOBAL_SETTINGS_INPUT 3
55#define ID_RCLK_MENU_COPY_TEXT 7013
56#define ID_RCLK_MENU_EDIT_WP 7014
57#define ID_RCLK_MENU_DELETE 7015
58#define ID_RCLK_MENU_MOVEUP_WP 7026
59#define ID_RCLK_MENU_MOVEDOWN_WP 7027
61#define COLUMN_PLANNED_SPEED 9
65#define PI (4. * atan(1.0))
68#define DEGS (180. / PI)
69#define RADS (PI / 180.)
81extern wxString GetLayerName(
int id);
89static wxString GetDaylightString(
int index) {
94 return _(
"MoTwilight");
102 return _(
"EvTwilight");
104 return _(
"Nighttime");
111static double sign(
double x) {
118static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
120static double FNday(
int y,
int m,
int d,
int h) {
121 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
122 return ((
double)fd - 730531.5 + h / 24.);
125static double FNrange(
double x) {
127 double a = TPI * (b - FNipart(b));
128 if (a < 0.) a = TPI + a;
132static double getDaylightEvent(
double glat,
double glong,
int riset,
133 double altitude,
int y,
int m,
int d) {
134 double day = FNday(y, m, d, 0);
135 double days, correction;
139 sin(altitude * RADS);
140 double sinphi = sin(glat * RADS);
141 double cosphi = cos(glat * RADS);
142 double g = glong * RADS;
143 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
145 while ((fabs(utold - utnew) > .001)) {
146 if (limit-- <= 0)
return (-1.);
147 days = day + utnew / TPI;
150 L = FNrange(4.8949504201433 + 628.331969753199 * t);
151 G = FNrange(6.2400408 + 628.3019501 * t);
152 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
154 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
155 obl = .409093 - .0002269 * t;
156 delta = asin(sin(obl) * sin(lambda));
157 GHA = utold - PI + E;
158 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
164 correction = acos(cosc);
166 utnew = FNrange(utold - (GHA + g + riset * correction));
169 return (utnew * DEGS / 15.);
172static double getLMT(
double ut,
double lon) {
173 double t = ut + lon / 15.;
186static wxString getDatetimeTimezoneSelector(
int selection) {
200static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
201 if (fabs(lat) > 60.)
return (0);
202 int y = utcDateTime.GetYear();
203 int m = utcDateTime.GetMonth() + 1;
204 int d = utcDateTime.GetDay();
205 int h = utcDateTime.GetHour();
206 int n = utcDateTime.GetMinute();
207 int s = utcDateTime.GetSecond();
208 if (y < 2000 || y > 2100)
return (0);
210 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
211 double lt = getLMT(ut, lon);
212 double rsalt = -0.833;
216 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
220 sunrise = getLMT(sunrise, lon);
222 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
223 if (lt > sunrise)
return (DAY);
224 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
228 twilight = getLMT(twilight, lon);
234 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
238 sunset = getLMT(sunset, lon);
239 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
240 if (lt < sunset)
return (DAY);
241 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
245 twilight = getLMT(twilight, lon);
253RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
254 const wxString& title,
const wxPoint& pos,
255 const wxSize& size,
long style)
259 SetColorScheme(global_color_scheme);
261 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
262 g_route_prop_sx < wxGetDisplaySize().x &&
263 g_route_prop_sy < wxGetDisplaySize().y) {
264 SetSize(g_route_prop_sx, g_route_prop_sy);
267 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
268 g_route_prop_x < wxGetDisplaySize().x &&
269 g_route_prop_y < wxGetDisplaySize().y) {
270 SetPosition(wxPoint(10, 10));
274 Connect(wxEVT_COMMAND_MENU_SELECTED,
275 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
279 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
284RoutePropDlgImpl::~RoutePropDlgImpl() {
285 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
286 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
288 instanceFlag =
false;
291bool RoutePropDlgImpl::instanceFlag =
false;
292bool RoutePropDlgImpl::getInstanceFlag() {
293 return RoutePropDlgImpl::instanceFlag;
305void RoutePropDlgImpl::OnActivate(wxActivateEvent& event) {
306 auto pWin =
dynamic_cast<wxFrame*
>(
event.GetEventObject());
307 long int style = pWin->GetWindowStyle();
308 if (event.GetActive())
309 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
311 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
314void RoutePropDlgImpl::RecalculateSize() {
316 esize.x = GetCharWidth() * 110;
317 esize.y = GetCharHeight() * 40;
319 wxSize dsize = GetParent()->GetSize();
320 esize.y = wxMin(esize.y, dsize.y - 0 );
321 esize.x = wxMin(esize.x, dsize.x - 0 );
324 wxSize fsize = GetSize();
325 wxSize canvas_size = GetParent()->GetSize();
326 wxPoint screen_pos = GetParent()->GetScreenPosition();
327 int xp = (canvas_size.x - fsize.x) / 2;
328 int yp = (canvas_size.y - fsize.y) / 2;
329 Move(screen_pos.x + xp, screen_pos.y + yp);
332void RoutePropDlgImpl::UpdatePoints() {
333 if (!m_pRoute)
return;
334 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
335 int selected_row = m_dvlcWaypoints->GetSelectedRow();
336 m_dvlcWaypoints->DeleteAllItems();
338 wxVector<wxVariant> data;
340 m_pRoute->UpdateSegmentDistances(
342 m_tcDistance->SetValue(
343 wxString::Format(
"%5.1f " + getUsrDistanceUnit(),
345 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->
m_route_time)));
348 wxString slen, eta, ete;
349 double bearing, distance, speed;
350 double totalDistance = 0;
351 wxDateTime eta_dt = wxInvalidDateTime;
354 speed = (*pnode)->GetPlannedSpeed();
359 DistanceBearingMercator((*pnode)->GetLatitude(), (*pnode)->GetLongitude(),
364 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
366 eta = wxString::Format(
367 "Start: %s", ocpn::toUsrDateTimeFormat(
369 eta.Append(wxString::Format(
370 " (%s)", GetDaylightString(
371 getDaylightStatus((*pnode)->m_lat, (*pnode)->m_lon,
379 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
384 distance = (*pnode)->GetDistance();
385 bearing = (*pnode)->GetCourse();
386 if ((*pnode)->GetETA().IsValid()) {
389 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
391 eta = ocpn::toUsrDateTimeFormat((*pnode)->GetETA().FromUTC(), opts);
392 eta.Append(wxString::Format(
393 " (%s)", GetDaylightString(getDaylightStatus((*pnode)->m_lat,
397 eta_dt = (*pnode)->GetETA();
401 ete = (*pnode)->GetETE();
402 totalDistance += distance;
404 wxString name = (*pnode)->GetName();
405 double lat = (*pnode)->GetLatitude();
406 double lon = (*pnode)->GetLongitude();
407 wxString tide_station = (*pnode)->m_TideStation;
408 wxString desc = (*pnode)->GetDescription();
410 if ((*pnode)->GetManualETD().IsValid()) {
415 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
417 etd = ocpn::toUsrDateTimeFormat(rt->
GetManualETD().FromUTC(), opts);
428 crs = formatAngle((*pnode)->GetCourse());
434 data.push_back(wxVariant(
"---"));
436 std::ostringstream stm;
438 data.push_back(wxVariant(stm.str()));
443 schar = wxString(
" ");
445 data.push_back(wxVariant(name + schar));
446 slen.Printf(
"%5.1f " + getUsrDistanceUnit(),
toUsrDistance(distance));
447 data.push_back(wxVariant(schar + slen + schar));
448 data.push_back(wxVariant(schar + formatAngle(bearing)));
449 slen.Printf(
"%5.1f " + getUsrDistanceUnit(),
toUsrDistance(totalDistance));
450 data.push_back(wxVariant(schar + slen + schar));
451 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
452 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
453 data.push_back(wxVariant(schar + ete + schar));
454 data.push_back(schar + eta + schar);
456 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
457 data.push_back(wxVariant(
458 MakeTideInfo(tide_station, lat, lon, eta_dt)));
459 data.push_back(wxVariant(desc));
460 data.push_back(wxVariant(crs));
461 data.push_back(wxVariant(etd));
465 m_dvlcWaypoints->AppendItem(data);
469 if (selected_row > 0) {
470 m_dvlcWaypoints->SelectRow(selected_row);
471 m_dvlcWaypoints->EnsureVisible(selection);
475void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
476 if (NULL == pR)
return;
485 wxString title = pR->GetName() ==
"" ? _(
"Route Properties") : pR->GetName();
489 wxString caption(wxString::Format(
"%s, %s: %s", title, _(
"Layer"),
501 if (pR != m_pRoute) {
506 m_pEnroutePoint = NULL;
512 m_tcPlanSpeed->SetValue(
515 if (m_scrolledWindowLinks) {
516 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
517 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
518 wxWindowListNode* node = kids.Item(i);
519 wxWindow* win = node->GetData();
520 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
522 link_win->Disconnect(
523 wxEVT_COMMAND_HYPERLINK,
524 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
525 link_win->Disconnect(
527 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
533 for (
Hyperlink* link : *m_pRoute->m_HyperlinkList) {
534 wxString Link = link->Link;
535 wxString Descr = link->DescrText;
537 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
538 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
539 wxDefaultSize, wxHL_DEFAULT_STYLE);
541 wxEVT_COMMAND_HYPERLINK,
542 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
547 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
550 bSizerLinks->Add(ctrl, 0, wxALL, 5);
552 m_scrolledWindowLinks->InvalidateBestSize();
553 m_scrolledWindowLinks->Layout();
554 bSizerLinks->Layout();
557 m_choiceTimezone->SetSelection(m_tz_selection);
565 m_tcName->SetFocus();
582 m_btnSplit->Enable(
false);
583 if (!m_pRoute)
return;
586 m_choiceColor->Select(0);
588 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
590 if (m_pRoute->
m_Colour == ::GpxxColorNames[i]) {
591 m_choiceColor->Select(i + 1);
597 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(
int); i++) {
598 if (m_pRoute->
m_style == ::StyleValues[i]) {
599 m_choiceStyle->Select(i);
604 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(
int); i++) {
605 if (m_pRoute->
m_width == ::WidthValues[i]) {
606 m_choiceWidth->Select(i);
613 m_btnExtend->Enable(IsThisRouteExtendable());
616void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
617 if (!m_pRoute)
return;
623void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
624 if (!m_pRoute)
return;
630void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
631 if (!m_pRoute)
return;
632 m_tz_selection = m_choiceTimezone->GetSelection();
641void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
642 if (!m_pRoute)
return;
644 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
650 m_tcPlanSpeed->SetValue(
655void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
656 if (!m_pRoute)
return;
658 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
664 m_tcPlanSpeed->SetValue(
671void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
672 wxDataViewEvent& event) {
676 ev_col =
event.GetColumn();
679void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
680 wxDataViewEvent& event) {
681#if wxCHECK_VERSION(3, 1, 2)
683 if (!m_pRoute)
return;
684 wxDataViewModel*
const model =
event.GetModel();
686 model->GetValue(value, event.GetItem(), ev_col);
688 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
689 if (ev_col == COLUMN_PLANNED_SPEED) {
691 if (!value.GetString().ToDouble(&spd)) {
694 p->SetPlannedSpeed(fromUsrSpeed(spd));
695 }
else if (ev_col == COLUMN_ETD) {
696 wxString::const_iterator end;
699 wxString ts = value.GetString();
700 if (ts.StartsWith(
"!")) {
701 ts.Replace(
"!",
"",
true);
707 if (!etd.ParseDateTime(ts, &end)) {
708 p->
SetETD(wxInvalidDateTime);
714 p->
SetETD(wxInvalidDateTime);
721void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
722 wxDataViewEvent& event) {
723 long selected_row = m_dvlcWaypoints->GetSelectedRow();
724 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
725 m_btnSplit->Enable(
true);
727 m_btnSplit->Enable(
false);
729 if (IsThisRouteExtendable()) {
730 m_btnExtend->Enable(
true);
732 m_btnExtend->Enable(
false);
734 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
735 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
737 top_frame::Get()->JumpToPosition(prp->m_lat, prp->m_lon);
739 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
755void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
756 wxString tab(
"\t", wxConvUTF8);
757 wxString eol(
"\n", wxConvUTF8);
760 csvString << this->GetTitle() << eol << _(
"Name") << tab
764 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
765 << m_tcPlanSpeed->GetValue() << eol
766 << _(
"Departure Time") +
" (" + ETA_FORMAT_STR +
")" << tab
768 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
773 noCols = m_dvlcWaypoints->GetColumnCount();
774 noRows = m_dvlcWaypoints->GetItemCount();
776 item.SetMask(wxLIST_MASK_TEXT);
778 for (
int i = 0; i < noCols; i++) {
779 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
780 csvString << col->GetTitle() << tab;
785 for (
int j = 0; j < noRows; j++) {
786 for (
int i = 0; i < noCols; i++) {
787 m_dvlcWaypoints->GetValue(value, j, i);
788 csvString << value.MakeString() << tab;
793 if (wxTheClipboard->Open()) {
794 wxTextDataObject* data =
new wxTextDataObject;
795 data->SetText(csvString);
796 wxTheClipboard->SetData(data);
797 wxTheClipboard->Close();
801void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
803 switch (event.GetId()) {
804 case ID_RCLK_MENU_COPY_TEXT: {
805 OnRoutepropCopyTxtClick(event);
808 case ID_RCLK_MENU_MOVEUP_WP: {
811 case ID_RCLK_MENU_MOVEDOWN_WP: {
813 moveup ? _(
"Are you sure you want to move Up this waypoint?")
814 : _(
"Are you sure you want to move Down this waypoint?");
816 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
817 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
819 if (dlg_return == wxID_YES) {
820 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
822 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
824 auto pos = std::find(list->begin(), list->end(), pRP);
826 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
827 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
830 pos += moveup ? -1 : 1;
833 pSelect->AddAllSelectableRouteSegments(m_pRoute);
834 pSelect->AddAllSelectableRoutePoints(m_pRoute);
837 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
839 m_pRoute->FinalizeForRendering();
840 m_pRoute->UpdateSegmentDistances();
843 top_frame::Get()->InvalidateAllGL();
845 m_dvlcWaypoints->SelectRow(pos - list->begin());
847 SetRouteAndUpdate(m_pRoute,
true);
851 case ID_RCLK_MENU_DELETE: {
852 int dlg_return = OCPNMessageBox(
853 this, _(
"Are you sure you want to remove this waypoint?"),
854 _(
"OpenCPN Remove Waypoint"),
855 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
857 if (dlg_return == wxID_YES) {
858 int sel = m_dvlcWaypoints->GetSelectedRow();
859 m_dvlcWaypoints->SelectRow(sel);
861 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
863 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
865 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
867 top_frame::Get()->InvalidateAllGL();
872 case ID_RCLK_MENU_EDIT_WP: {
873 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
875 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
877 RouteManagerDialog::WptShowPropertiesDialog(pRP,
this);
883void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
884 wxDataViewEvent& event) {
887 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
888 _(
"Waypoint Properties") +
"...");
889 wxMenuItem* moveUpItem =
890 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
891 wxMenuItem* moveDownItem =
892 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
893 wxMenuItem* delItem =
894 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
897 editItem->SetFont(*pf);
898 moveUpItem->SetFont(*pf);
899 moveDownItem->SetFont(*pf);
900 delItem->SetFont(*pf);
902#if defined(__WXMSW__)
904 editItem->SetFont(*pf);
905 moveUpItem->SetFont(*pf);
906 moveDownItem->SetFont(*pf);
907 delItem->SetFont(*pf);
910 menu.Append(editItem);
911 if (g_btouch) menu.AppendSeparator();
912 menu.Append(moveUpItem);
913 if (g_btouch) menu.AppendSeparator();
914 menu.Append(moveDownItem);
915 if (g_btouch) menu.AppendSeparator();
916 menu.Append(delItem);
918 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
919 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
920 m_dvlcWaypoints->GetItemCount() > 2);
921 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
922 m_dvlcWaypoints->GetSelectedRow() <
923 m_dvlcWaypoints->GetItemCount() - 1 &&
924 m_dvlcWaypoints->GetItemCount() > 2);
925 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
926 m_dvlcWaypoints->GetItemCount() > 2);
929 wxMenuItem* copyItem =
930 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
932#if defined(__WXMSW__)
934 copyItem->SetFont(*qFont);
937 if (g_btouch) menu.AppendSeparator();
938 menu.Append(copyItem);
944void RoutePropDlgImpl::ResetChanges() {
945 if (!m_pRoute)
return;
951void RoutePropDlgImpl::SaveChanges() {
958 if (m_choiceColor->GetSelection() == 0) {
961 m_pRoute->
m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
964 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
965 m_pRoute->
m_width = ::WidthValues[m_choiceWidth->GetSelection()];
966 switch (m_tz_selection) {
982 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
988void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
990void RoutePropDlgImpl::SaveGeometry() {
991 GetSize(&g_route_prop_sx, &g_route_prop_sy);
992 GetPosition(&g_route_prop_x, &g_route_prop_y);
995void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1004void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1005 m_btnSplit->Enable(
false);
1009 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1010 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1011 m_pHead =
new Route();
1012 m_pTail =
new Route();
1013 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1014 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1018 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1022 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1025 NavObj_dB::GetInstance().DeleteRoute(m_pRoute);
1027 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1028 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1030 pSelect->AddAllSelectableRouteSegments(m_pTail);
1031 pSelect->AddAllSelectableRoutePoints(m_pTail);
1032 pSelect->AddAllSelectableRouteSegments(m_pHead);
1033 pSelect->AddAllSelectableRoutePoints(m_pHead);
1035 SetRouteAndUpdate(m_pTail);
1043void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1044 static std::set<int> s_options;
1046 int result = dlg.ShowModal();
1048 if (result == wxID_OK) {
1049 dlg.GetSelected(s_options);
1050 RoutePrintout printout(m_pRoute, s_options, m_tz_selection);
1052 printer.Initialize(wxPORTRAIT);
1053 printer.EnablePageNumbers(
true);
1054 printer.Print(
this, &printout);
1060void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1061 m_btnExtend->Enable(
false);
1063 if (IsThisRouteExtendable()) {
1064 int extend_idx = m_pExtendRoute->GetIndexOf(m_pExtendPoint);
1065 if (extend_idx < 0) {
1066 m_btnExtend->Enable(
true);
1069 int fm = extend_idx + 1;
1070 int to = m_pExtendRoute->GetnPoints();
1072 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1073 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1074 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1075 SetRouteAndUpdate(m_pRoute);
1079 m_btnExtend->Enable(
true);
1082bool RoutePropDlgImpl::IsThisRouteExtendable() {
1083 m_pExtendRoute = NULL;
1084 m_pExtendPoint = NULL;
1088 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1089 wxArrayPtrVoid* pEditRouteArray;
1094 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1095 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1096 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1097 pEditRouteArray->RemoveAt(i - 1);
1099 if (pEditRouteArray->GetCount() == 1) {
1100 m_pExtendPoint = pLastPoint;
1102 if (pEditRouteArray->GetCount() == 0) {
1103 int nearby_radius_meters =
1104 (int)(8. / top_frame::Get()->GetCanvasTrueScale());
1105 double rlat = pLastPoint->m_lat;
1106 double rlon = pLastPoint->m_lon;
1108 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1109 rlat, rlon, nearby_radius_meters, pLastPoint->
m_GUID);
1110 if (m_pExtendPoint) {
1111 wxArrayPtrVoid* pCloseWPRouteArray =
1113 if (pCloseWPRouteArray) {
1114 pEditRouteArray = pCloseWPRouteArray;
1117 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1118 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1119 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1120 pEditRouteArray->RemoveAt(i - 1);
1126 if (pEditRouteArray->GetCount() == 1) {
1128 int extend_idx = p->GetIndexOf(m_pExtendPoint);
1129 if (extend_idx < 0) {
1130 delete pEditRouteArray;
1133 int fm = extend_idx + 1;
1134 int to = p->GetnPoints();
1137 delete pEditRouteArray;
1141 delete pEditRouteArray;
1146wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1147 double lon, wxDateTime utcTime) {
1148 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1150 if (stationName.IsEmpty()) {
1153 if (!utcTime.IsValid()) {
1154 return _(
"Invalid date/time!");
1156 int stationID =
ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1157 if (stationID == 0) {
1158 return _(
"Unknown station!");
1160 time_t dtmtt = utcTime.FromUTC().GetTicks();
1161 int ev =
ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1164 dtm.Set(dtmtt).MakeUTC();
1166 wxString tide_form =
"";
1169 tide_form.Append(
"LW: ");
1170 }
else if (ev == 2) {
1171 tide_form.Append(
"HW: ");
1172 }
else if (ev == 0) {
1173 tide_form.Append(_(
"Unavailable: "));
1180 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1182 wxString tideDateTime = ocpn::toUsrDateTimeFormat(dtm.FromUTC(), opts);
1183 tide_form.Append(tideDateTime);
1184 dtm.Add(wxTimeSpan(0, offset, 0));
1187 tide_form.Append(wxString::Format(
" (" + _(
"Local") +
": %s%+03d:%02d) @ %s",
1188 dtm.Format(
"%a %x %H:%M:%S"), (offset / 60),
1189 abs(offset) % 60, stationName.c_str()));
1193void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1194 wxString findurl = m_pEditedLink->GetURL();
1195 wxString findlabel = m_pEditedLink->GetLabel();
1198 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1199 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1200 DimeControl(LinkPropDlg);
1201 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1202 findlabel](
int retcode) {
1203 if (retcode == wxID_OK) {
1204 for (
Hyperlink* link : *m_pRoute->m_HyperlinkList) {
1205 wxString Link = link->Link;
1206 wxString Descr = link->DescrText;
1207 if (Link == findurl &&
1208 (Descr == findlabel || (Link == findlabel && Descr ==
""))) {
1209 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1210 link->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1211 wxHyperlinkCtrl* h =
1212 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1215 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1216 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1221 m_scrolledWindowLinks->InvalidateBestSize();
1222 m_scrolledWindowLinks->Layout();
1223 bSizerLinks->Layout();
1229void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1230 AddLinkOnButtonClick(event);
1234 wxString findurl = m_pEditedLink->GetURL();
1235 wxString findlabel = m_pEditedLink->GetLabel();
1237 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1238 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
1239 wxWindowListNode* node = kids.Item(i);
1240 wxWindow* win = node->GetData();
1242 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
1244 link_win->Disconnect(
1245 wxEVT_COMMAND_HYPERLINK,
1246 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1247 link_win->Disconnect(
1249 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1258 auto nodeToDelete = hyperlinklist->end();
1259 if (NbrOfLinks > 0) {
1260 auto it = hyperlinklist->begin();
1261 while (it != hyperlinklist->end()) {
1263 wxString Link = link->Link;
1264 wxString Descr = link->DescrText;
1265 if (Link == findurl &&
1266 (Descr == findlabel || (Link == findlabel && Descr ==
"")))
1269 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1270 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1271 wxDefaultSize, wxHL_DEFAULT_STYLE);
1273 wxEVT_COMMAND_HYPERLINK,
1274 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1278 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1281 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1286 if (nodeToDelete != hyperlinklist->end()) {
1287 hyperlinklist->erase(nodeToDelete);
1289 m_scrolledWindowLinks->InvalidateBestSize();
1290 m_scrolledWindowLinks->Layout();
1291 bSizerLinks->Layout();
1295void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1297 LinkPropDlg->m_textCtrlLinkDescription->SetValue(
"");
1298 LinkPropDlg->m_textCtrlLinkUrl->SetValue(
"");
1299 DimeControl(LinkPropDlg);
1300 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1301 if (retcode == wxID_OK) {
1302 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1303 if (desc ==
"") desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1304 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1305 m_scrolledWindowLinks, wxID_ANY, desc,
1306 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1307 wxDefaultSize, wxHL_DEFAULT_STYLE);
1308 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1309 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1311 ctrl->Connect(wxEVT_RIGHT_DOWN,
1312 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1315 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1316 m_scrolledWindowLinks->InvalidateBestSize();
1317 m_scrolledWindowLinks->Layout();
1318 bSizerLinks->Layout();
1321 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1322 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1329void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1330 if (m_toggleBtnEdit->GetValue()) {
1331 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1333 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1338void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1339 if (m_toggleBtnEdit->GetValue()) {
1340 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1341 ItemEditOnMenuSelection(event);
1354 wxString cc =
event.GetURL();
1355 if (cc.Find(
"#") != wxNOT_FOUND) {
1356 wxRegKey RegKey(wxString(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command"));
1357 if (RegKey.Exists()) {
1358 wxString command_line;
1359 RegKey.QueryValue(wxString(
""), command_line);
1362 command_line.Replace(wxString(
"\""), wxString(
""));
1365 int l = command_line.Find(
".exe");
1366 if (wxNOT_FOUND == l) l = command_line.Find(
".EXE");
1368 if (wxNOT_FOUND != l) {
1369 wxString cl = command_line.Mid(0, l + 4);
1380 wxString url =
event.GetURL();
1381 url.Replace(
" ",
"%20");
1382 ::wxLaunchDefaultBrowser(url);
1386void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1387 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1388 m_scrolledWindowLinks->PopupMenu(
1389 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1390 m_pEditedLink->GetPosition().y +
event.GetPosition().y);
Generic Chart canvas base.
Represents an index entry for tidal and current data.
static PrintDialog & GetInstance()
Get instance to handle the print process,.
Represents a waypoint or mark within the navigation system.
wxString m_GUID
Globally Unique Identifier for the waypoint.
wxDateTime GetManualETD()
Retrieves the manually set Estimated Time of Departure for this waypoint, in UTC.
void SetETD(const wxDateTime &etd)
Sets the Estimated Time of Departure for this waypoint, in UTC.
wxDateTime GetETA()
Retrieves the Estimated Time of Arrival for this waypoint, in UTC.
Input dialog with route print selection.
Printout route information and a table with selected route point information.
void ItemDeleteOnMenuSelection(wxCommandEvent &event)
wxDateTime GetDepartureTS()
Returns the departure time of the route, in UTC.
wxTimePickerCtrl * m_tpDepartureTime
The time picker for the departure time of the route.
wxDatePickerCtrl * m_dpDepartureDate
The date picker for the departure date of the route.
Represents a navigational route in the navigation system.
double m_PlannedSpeed
Default planned speed for the route in knots.
wxString m_RouteStartString
Name or description of the route's starting point.
wxString m_RouteDescription
Additional descriptive information about the route.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
wxString m_Colour
Color name for rendering the route on the chart.
wxString m_RouteEndString
Name or description of the route's ending point.
wxPenStyle m_style
Style of the route line when rendered on the chart.
wxString m_TimeDisplayFormat
Format for displaying times in the UI.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
wxDateTime m_PlannedDeparture
Planned departure time for the route, in UTC.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
double m_route_time
Total estimated time to complete the route in seconds.
void SetDepartureDate(const wxDateTime &dt)
Set the departure time of the route.
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this route.
int m_LayerID
Identifier of the layer containing this route.
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool DeleteRoute(Route *pRoute)
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
General purpose GUI support.
Waypoint properties maintenance dialog.
MySQL based storage for routes, tracks, etc.
MyConfig * pConfig
Global instance.
wxDateTime toUsrDateTime(const wxDateTime ts, const int format, const double lon)
Converts a timestamp from UTC to the user's preferred time format.
wxDateTime fromUsrDateTime(const wxDateTime ts, const int format, const double lon)
Converts a timestamp from a user's preferred time format to UTC.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
Navigation Utility Functions without GUI dependencies.
PlugIn Object Definition/API.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
double gLat
Vessel's current latitude in decimal degrees.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Generic, styled prit dialog.
#define LMTINPUT
Format date/time using the remote location LMT time.
#define GLOBAL_SETTINGS_INPUT
Format date/time according to global OpenCPN settings.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
#define UTCINPUT
Format date/time in UTC.
#define LTINPUT
Format date/time using timezone configured in the operating system./*#end#*/.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RouteManagerDialog * pRouteManagerDialog
Global instance.
Select * pSelect
Global instance.
Selected route, segment, waypoint, etc.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
Abstract gFrame/MyFrame interface.