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 fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1065 int to = m_pExtendRoute->GetnPoints();
1067 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1068 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1069 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1070 SetRouteAndUpdate(m_pRoute);
1074 m_btnExtend->Enable(
true);
1077bool RoutePropDlgImpl::IsThisRouteExtendable() {
1078 m_pExtendRoute = NULL;
1079 m_pExtendPoint = NULL;
1083 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1084 wxArrayPtrVoid* pEditRouteArray;
1089 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1090 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1091 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1092 pEditRouteArray->RemoveAt(i - 1);
1094 if (pEditRouteArray->GetCount() == 1) {
1095 m_pExtendPoint = pLastPoint;
1097 if (pEditRouteArray->GetCount() == 0) {
1098 int nearby_radius_meters =
1099 (int)(8. / top_frame::Get()->GetCanvasTrueScale());
1100 double rlat = pLastPoint->m_lat;
1101 double rlon = pLastPoint->m_lon;
1103 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1104 rlat, rlon, nearby_radius_meters, pLastPoint->
m_GUID);
1105 if (m_pExtendPoint) {
1106 wxArrayPtrVoid* pCloseWPRouteArray =
1108 if (pCloseWPRouteArray) {
1109 pEditRouteArray = pCloseWPRouteArray;
1112 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1113 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1114 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1115 pEditRouteArray->RemoveAt(i - 1);
1121 if (pEditRouteArray->GetCount() == 1) {
1123 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1124 int to = p->GetnPoints();
1127 delete pEditRouteArray;
1131 delete pEditRouteArray;
1136wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1137 double lon, wxDateTime utcTime) {
1138 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1140 if (stationName.IsEmpty()) {
1143 if (!utcTime.IsValid()) {
1144 return _(
"Invalid date/time!");
1146 int stationID =
ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1147 if (stationID == 0) {
1148 return _(
"Unknown station!");
1150 time_t dtmtt = utcTime.FromUTC().GetTicks();
1151 int ev =
ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1154 dtm.Set(dtmtt).MakeUTC();
1156 wxString tide_form =
"";
1159 tide_form.Append(
"LW: ");
1160 }
else if (ev == 2) {
1161 tide_form.Append(
"HW: ");
1162 }
else if (ev == 0) {
1163 tide_form.Append(_(
"Unavailable: "));
1170 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1172 wxString tideDateTime = ocpn::toUsrDateTimeFormat(dtm.FromUTC(), opts);
1173 tide_form.Append(tideDateTime);
1174 dtm.Add(wxTimeSpan(0, offset, 0));
1177 tide_form.Append(wxString::Format(
" (" + _(
"Local") +
": %s%+03d:%02d) @ %s",
1178 dtm.Format(
"%a %x %H:%M:%S"), (offset / 60),
1179 abs(offset) % 60, stationName.c_str()));
1183void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1184 wxString findurl = m_pEditedLink->GetURL();
1185 wxString findlabel = m_pEditedLink->GetLabel();
1188 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1189 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1190 DimeControl(LinkPropDlg);
1191 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1192 findlabel](
int retcode) {
1193 if (retcode == wxID_OK) {
1194 for (
Hyperlink* link : *m_pRoute->m_HyperlinkList) {
1195 wxString Link = link->Link;
1196 wxString Descr = link->DescrText;
1197 if (Link == findurl &&
1198 (Descr == findlabel || (Link == findlabel && Descr ==
""))) {
1199 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1200 link->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1201 wxHyperlinkCtrl* h =
1202 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1205 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1206 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1211 m_scrolledWindowLinks->InvalidateBestSize();
1212 m_scrolledWindowLinks->Layout();
1213 bSizerLinks->Layout();
1219void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1220 AddLinkOnButtonClick(event);
1224 wxString findurl = m_pEditedLink->GetURL();
1225 wxString findlabel = m_pEditedLink->GetLabel();
1227 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1228 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
1229 wxWindowListNode* node = kids.Item(i);
1230 wxWindow* win = node->GetData();
1232 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
1234 link_win->Disconnect(
1235 wxEVT_COMMAND_HYPERLINK,
1236 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1237 link_win->Disconnect(
1239 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1248 auto nodeToDelete = hyperlinklist->end();
1249 if (NbrOfLinks > 0) {
1250 auto it = hyperlinklist->begin();
1251 while (it != hyperlinklist->end()) {
1253 wxString Link = link->Link;
1254 wxString Descr = link->DescrText;
1255 if (Link == findurl &&
1256 (Descr == findlabel || (Link == findlabel && Descr ==
"")))
1259 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1260 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1261 wxDefaultSize, wxHL_DEFAULT_STYLE);
1263 wxEVT_COMMAND_HYPERLINK,
1264 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1268 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1271 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1276 if (nodeToDelete != hyperlinklist->end()) {
1277 hyperlinklist->erase(nodeToDelete);
1279 m_scrolledWindowLinks->InvalidateBestSize();
1280 m_scrolledWindowLinks->Layout();
1281 bSizerLinks->Layout();
1285void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1287 LinkPropDlg->m_textCtrlLinkDescription->SetValue(
"");
1288 LinkPropDlg->m_textCtrlLinkUrl->SetValue(
"");
1289 DimeControl(LinkPropDlg);
1290 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1291 if (retcode == wxID_OK) {
1292 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1293 if (desc ==
"") desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1294 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1295 m_scrolledWindowLinks, wxID_ANY, desc,
1296 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1297 wxDefaultSize, wxHL_DEFAULT_STYLE);
1298 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1299 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1301 ctrl->Connect(wxEVT_RIGHT_DOWN,
1302 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1305 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1306 m_scrolledWindowLinks->InvalidateBestSize();
1307 m_scrolledWindowLinks->Layout();
1308 bSizerLinks->Layout();
1311 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1312 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1319void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1320 if (m_toggleBtnEdit->GetValue()) {
1321 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1323 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1328void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1329 if (m_toggleBtnEdit->GetValue()) {
1330 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1331 ItemEditOnMenuSelection(event);
1344 wxString cc =
event.GetURL();
1345 if (cc.Find(
"#") != wxNOT_FOUND) {
1346 wxRegKey RegKey(wxString(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command"));
1347 if (RegKey.Exists()) {
1348 wxString command_line;
1349 RegKey.QueryValue(wxString(
""), command_line);
1352 command_line.Replace(wxString(
"\""), wxString(
""));
1355 int l = command_line.Find(
".exe");
1356 if (wxNOT_FOUND == l) l = command_line.Find(
".EXE");
1358 if (wxNOT_FOUND != l) {
1359 wxString cl = command_line.Mid(0, l + 4);
1370 wxString url =
event.GetURL();
1371 url.Replace(
" ",
"%20");
1372 ::wxLaunchDefaultBrowser(url);
1376void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1377 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1378 m_scrolledWindowLinks->PopupMenu(
1379 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1380 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.