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;
299 single =
new RoutePropDlgImpl(parent);
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 int selected_row = m_dvlcWaypoints->GetSelectedRow();
335 m_dvlcWaypoints->DeleteAllItems();
337 wxVector<wxVariant> data;
339 m_pRoute->UpdateSegmentDistances(
340 m_pRoute->m_PlannedSpeed);
341 m_tcDistance->SetValue(
342 wxString::Format(
"%5.1f " + getUsrDistanceUnit(),
344 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->m_route_time)));
347 wxString slen, eta, ete;
348 double bearing, distance, speed;
349 double totalDistance = 0;
350 wxDateTime eta_dt = wxInvalidDateTime;
351 auto pnode = m_pRoute->pRoutePointList->begin();
352 while (pnode != m_pRoute->pRoutePointList->end()) {
353 speed = (*pnode)->GetPlannedSpeed();
355 speed = m_pRoute->m_PlannedSpeed;
358 DistanceBearingMercator((*pnode)->GetLatitude(), (*pnode)->GetLongitude(),
360 if (m_pRoute->m_PlannedDeparture.IsValid()) {
361 DateTimeFormatOptions opts =
362 DateTimeFormatOptions()
363 .SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
364 .SetLongitude((*pnode)->m_lon);
365 eta = wxString::Format(
366 "Start: %s", ocpn::toUsrDateTimeFormat(
367 m_pRoute->m_PlannedDeparture.FromUTC(), opts));
368 eta.Append(wxString::Format(
369 " (%s)", GetDaylightString(
370 getDaylightStatus((*pnode)->m_lat, (*pnode)->m_lon,
371 m_pRoute->m_PlannedDeparture))
373 eta_dt = m_pRoute->m_PlannedDeparture;
378 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
383 distance = (*pnode)->GetDistance();
384 bearing = (*pnode)->GetCourse();
385 if ((*pnode)->GetETA().IsValid()) {
386 DateTimeFormatOptions opts =
387 DateTimeFormatOptions()
388 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
390 eta = ocpn::toUsrDateTimeFormat((*pnode)->GetETA().FromUTC(), opts);
391 eta.Append(wxString::Format(
392 " (%s)", GetDaylightString(getDaylightStatus((*pnode)->m_lat,
396 eta_dt = (*pnode)->GetETA();
400 ete = (*pnode)->GetETE();
401 totalDistance += distance;
403 wxString name = (*pnode)->GetName();
404 double lat = (*pnode)->GetLatitude();
405 double lon = (*pnode)->GetLongitude();
406 wxString tide_station = (*pnode)->m_TideStation;
407 wxString desc = (*pnode)->GetDescription();
409 if ((*pnode)->GetManualETD().IsValid()) {
411 RoutePoint* rt = (*pnode);
412 DateTimeFormatOptions opts =
413 DateTimeFormatOptions()
414 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
416 etd = ocpn::toUsrDateTimeFormat(rt->
GetManualETD().FromUTC(), opts);
426 if (pnode != m_pRoute->pRoutePointList->end()) {
427 crs = formatAngle((*pnode)->GetCourse());
433 data.push_back(wxVariant(
"---"));
435 std::ostringstream stm;
437 data.push_back(wxVariant(stm.str()));
442 schar = wxString(
" ");
444 data.push_back(wxVariant(name + schar));
445 slen.Printf(
"%5.1f " + getUsrDistanceUnit(),
toUsrDistance(distance));
446 data.push_back(wxVariant(schar + slen + schar));
447 data.push_back(wxVariant(schar + formatAngle(bearing)));
448 slen.Printf(
"%5.1f " + getUsrDistanceUnit(),
toUsrDistance(totalDistance));
449 data.push_back(wxVariant(schar + slen + schar));
450 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
451 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
452 data.push_back(wxVariant(schar + ete + schar));
453 data.push_back(schar + eta + schar);
455 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
456 data.push_back(wxVariant(
457 MakeTideInfo(tide_station, lat, lon, eta_dt)));
458 data.push_back(wxVariant(desc));
459 data.push_back(wxVariant(crs));
460 data.push_back(wxVariant(etd));
464 m_dvlcWaypoints->AppendItem(data);
471 int count = m_dvlcWaypoints->GetItemCount();
472 if (selected_row >= 0 && count > 0) {
473 m_dvlcWaypoints->SelectRow(selected_row < count ? selected_row : count - 1);
474 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
475 if (selection.IsOk()) m_dvlcWaypoints->EnsureVisible(selection);
479void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
480 if (NULL == pR)
return;
489 wxString title = pR->GetName() ==
"" ? _(
"Route Properties") : pR->GetName();
493 wxString caption(wxString::Format(
"%s, %s: %s", title, _(
"Layer"),
504 if (pR != m_pRoute) {
513 m_pEnroutePoint = NULL;
519 m_tcPlanSpeed->SetValue(
520 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
522 if (m_scrolledWindowLinks) {
523 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
524 for (
auto const& win : m_scrolledWindowLinks->GetChildren()) {
525 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
527 link_win->Disconnect(
528 wxEVT_COMMAND_HYPERLINK,
529 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
530 link_win->Disconnect(
532 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
536 int NbrOfLinks = m_pRoute->m_HyperlinkList->size();
537 HyperlinkList* list = m_pRoute->m_HyperlinkList;
538 for (Hyperlink* link : *m_pRoute->m_HyperlinkList) {
539 wxString Link = link->Link;
540 wxString Descr = link->DescrText;
542 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
543 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
544 wxDefaultSize, wxHL_DEFAULT_STYLE);
546 wxEVT_COMMAND_HYPERLINK,
547 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
549 if (!m_pRoute->m_bIsInLayer) {
552 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
555 bSizerLinks->Add(ctrl, 0, wxALL, 5);
557 m_scrolledWindowLinks->InvalidateBestSize();
558 m_scrolledWindowLinks->Layout();
559 bSizerLinks->Layout();
562 m_choiceTimezone->SetSelection(m_tz_selection);
565 m_tcName->SetValue(m_pRoute->m_RouteNameString);
566 m_tcFrom->SetValue(m_pRoute->m_RouteStartString);
567 m_tcTo->SetValue(m_pRoute->m_RouteEndString);
568 m_tcDescription->SetValue(m_pRoute->m_RouteDescription);
570 m_tcName->SetFocus();
571 if (m_pRoute->m_PlannedDeparture.IsValid() &&
572 m_pRoute->m_PlannedDeparture.GetValue() > 0) {
575 (*m_pRoute->pRoutePointList->begin())->m_lon);
581 (*m_pRoute->pRoutePointList->begin())->m_lon);
587 m_btnSplit->Enable(
false);
588 if (!m_pRoute)
return;
590 if (m_pRoute->m_Colour ==
"") {
591 m_choiceColor->Select(0);
593 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
595 if (m_pRoute->m_Colour == ::GpxxColorNames[i]) {
596 m_choiceColor->Select(i + 1);
602 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(int); i++) {
603 if (m_pRoute->m_style == ::StyleValues[i]) {
604 m_choiceStyle->Select(i);
609 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(int); i++) {
610 if (m_pRoute->m_width == ::WidthValues[i]) {
611 m_choiceWidth->Select(i);
618 m_btnExtend->Enable(IsThisRouteExtendable());
621void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
622 if (!m_pRoute)
return;
628void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
629 if (!m_pRoute)
return;
635void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
636 if (!m_pRoute)
return;
637 m_tz_selection = m_choiceTimezone->GetSelection();
638 wxDateTime t =
toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
639 (*m_pRoute->pRoutePointList->begin())->m_lon);
646void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
647 if (!m_pRoute)
return;
649 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
650 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
651 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
655 m_tcPlanSpeed->SetValue(
656 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
660void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
661 if (!m_pRoute)
return;
663 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
664 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
665 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
669 m_tcPlanSpeed->SetValue(
670 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
676void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
677 wxDataViewEvent& event) {
681 ev_col =
event.GetColumn();
684void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
685 wxDataViewEvent& event) {
686#if wxCHECK_VERSION(3, 1, 2)
688 if (!m_pRoute)
return;
689 wxDataViewModel*
const model =
event.GetModel();
691 model->GetValue(value, event.GetItem(), ev_col);
692 RoutePoint* p = m_pRoute->GetPoint(
693 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
694 if (ev_col == COLUMN_PLANNED_SPEED) {
696 if (!value.GetString().ToDouble(&spd)) {
699 p->SetPlannedSpeed(fromUsrSpeed(spd));
700 }
else if (ev_col == COLUMN_ETD) {
701 wxString::const_iterator end;
704 wxString ts = value.GetString();
705 if (ts.StartsWith(
"!")) {
706 ts.Replace(
"!",
"",
true);
712 if (!etd.ParseDateTime(ts, &end)) {
713 p->
SetETD(wxInvalidDateTime);
719 p->
SetETD(wxInvalidDateTime);
726void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
727 wxDataViewEvent& event) {
728 long selected_row = m_dvlcWaypoints->GetSelectedRow();
729 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
730 m_btnSplit->Enable(
true);
732 m_btnSplit->Enable(
false);
734 if (IsThisRouteExtendable()) {
735 m_btnExtend->Enable(
true);
737 m_btnExtend->Enable(
false);
739 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
740 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
742 top_frame::Get()->JumpToPosition(prp->m_lat, prp->m_lon);
744 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
756 (*m_pRoute->pRoutePointList->begin())->m_lon);
760void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
761 wxString tab(
"\t", wxConvUTF8);
762 wxString eol(
"\n", wxConvUTF8);
765 csvString << this->GetTitle() << eol << _(
"Name") << tab
769 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
770 << m_tcPlanSpeed->GetValue() << eol
771 << _(
"Departure Time") +
" (" + ETA_FORMAT_STR +
")" << tab
773 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
778 noCols = m_dvlcWaypoints->GetColumnCount();
779 noRows = m_dvlcWaypoints->GetItemCount();
781 item.SetMask(wxLIST_MASK_TEXT);
783 for (
int i = 0; i < noCols; i++) {
784 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
785 csvString << col->GetTitle() << tab;
790 for (
int j = 0; j < noRows; j++) {
791 for (
int i = 0; i < noCols; i++) {
792 m_dvlcWaypoints->GetValue(value, j, i);
793 csvString << value.MakeString() << tab;
798 if (wxTheClipboard->Open()) {
799 wxTextDataObject* data =
new wxTextDataObject;
800 data->SetText(csvString);
801 wxTheClipboard->SetData(data);
802 wxTheClipboard->Close();
806void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
808 switch (event.GetId()) {
809 case ID_RCLK_MENU_COPY_TEXT: {
810 OnRoutepropCopyTxtClick(event);
813 case ID_RCLK_MENU_MOVEUP_WP: {
816 case ID_RCLK_MENU_MOVEDOWN_WP: {
818 moveup ? _(
"Are you sure you want to move Up this waypoint?")
819 : _(
"Are you sure you want to move Down this waypoint?");
821 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
822 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
824 if (dlg_return == wxID_YES) {
825 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
826 RoutePoint* pRP = m_pRoute->GetPoint(
827 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
828 auto& list = m_pRoute->pRoutePointList;
829 auto pos = std::find(list->begin(), list->end(), pRP);
831 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
832 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
834 m_pRoute->pRoutePointList->erase(pos);
835 pos += moveup ? -1 : 1;
836 m_pRoute->pRoutePointList->insert(pos, pRP);
838 pSelect->AddAllSelectableRouteSegments(m_pRoute);
839 pSelect->AddAllSelectableRoutePoints(m_pRoute);
842 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
844 m_pRoute->FinalizeForRendering();
845 m_pRoute->UpdateSegmentDistances();
848 top_frame::Get()->InvalidateAllGL();
850 m_dvlcWaypoints->SelectRow(pos - list->begin());
852 SetRouteAndUpdate(m_pRoute,
true);
856 case ID_RCLK_MENU_DELETE: {
857 int dlg_return = OCPNMessageBox(
858 this, _(
"Are you sure you want to remove this waypoint?"),
859 _(
"OpenCPN Remove Waypoint"),
860 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
862 if (dlg_return == wxID_YES) {
863 int sel = m_dvlcWaypoints->GetSelectedRow();
864 m_dvlcWaypoints->SelectRow(sel);
866 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
867 RoutePoint* pRP = m_pRoute->GetPoint(
868 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
870 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
872 top_frame::Get()->InvalidateAllGL();
877 case ID_RCLK_MENU_EDIT_WP: {
878 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
879 RoutePoint* pRP = m_pRoute->GetPoint(
880 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
882 RouteManagerDialog::WptShowPropertiesDialog(pRP,
this);
888void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
889 wxDataViewEvent& event) {
891 if (!m_pRoute->m_bIsInLayer) {
892 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
893 _(
"Waypoint Properties") +
"...");
894 wxMenuItem* moveUpItem =
895 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
896 wxMenuItem* moveDownItem =
897 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
898 wxMenuItem* delItem =
899 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
902 editItem->SetFont(*pf);
903 moveUpItem->SetFont(*pf);
904 moveDownItem->SetFont(*pf);
905 delItem->SetFont(*pf);
907#if defined(__WXMSW__)
909 editItem->SetFont(*pf);
910 moveUpItem->SetFont(*pf);
911 moveDownItem->SetFont(*pf);
912 delItem->SetFont(*pf);
915 menu.Append(editItem);
916 if (g_btouch) menu.AppendSeparator();
917 menu.Append(moveUpItem);
918 if (g_btouch) menu.AppendSeparator();
919 menu.Append(moveDownItem);
920 if (g_btouch) menu.AppendSeparator();
921 menu.Append(delItem);
923 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
924 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
925 m_dvlcWaypoints->GetItemCount() > 2);
926 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
927 m_dvlcWaypoints->GetSelectedRow() <
928 m_dvlcWaypoints->GetItemCount() - 1 &&
929 m_dvlcWaypoints->GetItemCount() > 2);
930 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
931 m_dvlcWaypoints->GetItemCount() > 2);
934 wxMenuItem* copyItem =
935 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
937#if defined(__WXMSW__)
939 copyItem->SetFont(*qFont);
942 if (g_btouch) menu.AppendSeparator();
943 menu.Append(copyItem);
949void RoutePropDlgImpl::ResetChanges() {
950 if (!m_pRoute)
return;
951 m_pRoute->m_PlannedSpeed = m_OrigRoute.m_PlannedSpeed;
952 m_pRoute->m_PlannedDeparture = m_OrigRoute.m_PlannedDeparture;
956void RoutePropDlgImpl::SaveChanges() {
957 if (m_pRoute && !m_pRoute->m_bIsInLayer) {
959 m_pRoute->m_RouteNameString = m_tcName->GetValue();
960 m_pRoute->m_RouteStartString = m_tcFrom->GetValue();
961 m_pRoute->m_RouteEndString = m_tcTo->GetValue();
962 m_pRoute->m_RouteDescription = m_tcDescription->GetValue();
963 if (m_choiceColor->GetSelection() == 0) {
964 m_pRoute->m_Colour =
"";
966 m_pRoute->m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
969 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
970 m_pRoute->m_width = ::WidthValues[m_choiceWidth->GetSelection()];
971 switch (m_tz_selection) {
973 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_PC;
976 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_LOCAL;
979 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_GLOBAL;
983 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_UTC;
987 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
993void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
995void RoutePropDlgImpl::SaveGeometry() {
996 GetSize(&g_route_prop_sx, &g_route_prop_sy);
997 GetPosition(&g_route_prop_x, &g_route_prop_y);
1000void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1009void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1010 m_btnSplit->Enable(
false);
1012 if (m_pRoute->m_bIsInLayer)
return;
1014 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1015 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1016 m_pHead =
new Route();
1017 m_pTail =
new Route();
1018 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1019 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1023 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1027 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1030 NavObj_dB::GetInstance().DeleteRoute(m_pRoute);
1032 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1033 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1035 pSelect->AddAllSelectableRouteSegments(m_pTail);
1036 pSelect->AddAllSelectableRoutePoints(m_pTail);
1037 pSelect->AddAllSelectableRouteSegments(m_pHead);
1038 pSelect->AddAllSelectableRoutePoints(m_pHead);
1040 SetRouteAndUpdate(m_pTail);
1048void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1049 RoutePrintDlg dlg(
this);
1050 int result = dlg.ShowModal();
1052 if (result == wxID_OK) {
1053 RoutePrintout printout(m_pRoute, dlg, m_tz_selection);
1055 printer.Initialize(wxPORTRAIT);
1056 printer.EnablePageNumbers(
true);
1057 printer.Print(
this, &printout);
1063void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1064 m_btnExtend->Enable(
false);
1066 if (IsThisRouteExtendable()) {
1067 int extend_idx = m_pExtendRoute->GetIndexOf(m_pExtendPoint);
1068 if (extend_idx < 0) {
1069 m_btnExtend->Enable(
true);
1072 int fm = extend_idx + 1;
1073 int to = m_pExtendRoute->GetnPoints();
1075 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1076 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1077 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1078 SetRouteAndUpdate(m_pRoute);
1082 m_btnExtend->Enable(
true);
1085bool RoutePropDlgImpl::IsThisRouteExtendable() {
1086 m_pExtendRoute = NULL;
1087 m_pExtendPoint = NULL;
1088 if (!m_pRoute || m_pRoute->m_bRtIsActive || m_pRoute->m_bIsInLayer)
1091 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1092 wxArrayPtrVoid* pEditRouteArray;
1097 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1098 Route* p = (Route*)pEditRouteArray->Item(i - 1);
1099 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->m_GUID))
1100 pEditRouteArray->RemoveAt(i - 1);
1102 if (pEditRouteArray->GetCount() == 1) {
1103 m_pExtendPoint = pLastPoint;
1105 if (pEditRouteArray->GetCount() == 0) {
1106 int nearby_radius_meters =
1107 (int)(8. / top_frame::Get()->GetCanvasTrueScale());
1108 double rlat = pLastPoint->m_lat;
1109 double rlon = pLastPoint->m_lon;
1111 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1112 rlat, rlon, nearby_radius_meters, pLastPoint->
m_GUID);
1113 if (m_pExtendPoint) {
1114 wxArrayPtrVoid* pCloseWPRouteArray =
1116 if (pCloseWPRouteArray) {
1117 pEditRouteArray = pCloseWPRouteArray;
1120 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1121 Route* p = (Route*)pEditRouteArray->Item(i - 1);
1122 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->m_GUID))
1123 pEditRouteArray->RemoveAt(i - 1);
1129 if (pEditRouteArray->GetCount() == 1) {
1130 Route* p = (Route*)pEditRouteArray->Item(0);
1131 int extend_idx = p->GetIndexOf(m_pExtendPoint);
1132 if (extend_idx < 0) {
1133 delete pEditRouteArray;
1136 int fm = extend_idx + 1;
1137 int to = p->GetnPoints();
1140 delete pEditRouteArray;
1144 delete pEditRouteArray;
1149wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1150 double lon, wxDateTime utcTime) {
1151 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1153 if (stationName.IsEmpty()) {
1156 if (!utcTime.IsValid()) {
1157 return _(
"Invalid date/time!");
1159 int stationID =
ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1160 if (stationID == 0) {
1161 return _(
"Unknown station!");
1163 time_t dtmtt = utcTime.FromUTC().GetTicks();
1164 int ev =
ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1167 dtm.Set(dtmtt).MakeUTC();
1169 wxString tide_form =
"";
1172 tide_form.Append(
"LW: ");
1173 }
else if (ev == 2) {
1174 tide_form.Append(
"HW: ");
1175 }
else if (ev == 0) {
1176 tide_form.Append(_(
"Unavailable: "));
1180 ptcmgr->GetStationTimeOffset((IDX_entry*)
ptcmgr->GetIDX_entry(stationID));
1181 DateTimeFormatOptions opts =
1182 DateTimeFormatOptions()
1183 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1185 wxString tideDateTime = ocpn::toUsrDateTimeFormat(dtm.FromUTC(), opts);
1186 tide_form.Append(tideDateTime);
1187 dtm.Add(wxTimeSpan(0, offset, 0));
1190 tide_form.Append(wxString::Format(
" (" + _(
"Local") +
": %s%+03d:%02d) @ %s",
1191 dtm.Format(
"%a %x %H:%M:%S"), (offset / 60),
1192 abs(offset) % 60, stationName.c_str()));
1196void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1197 wxString findurl = m_pEditedLink->GetURL();
1198 wxString findlabel = m_pEditedLink->GetLabel();
1200 LinkPropImpl* LinkPropDlg =
new LinkPropImpl(
this);
1201 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1202 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1203 DimeControl(LinkPropDlg);
1204 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1205 findlabel](
int retcode) {
1206 if (retcode == wxID_OK) {
1207 for (Hyperlink* link : *m_pRoute->m_HyperlinkList) {
1208 wxString Link = link->Link;
1209 wxString Descr = link->DescrText;
1210 if (Link == findurl &&
1211 (Descr == findlabel || (Link == findlabel && Descr ==
""))) {
1212 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1213 link->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1214 wxHyperlinkCtrl* h =
1215 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1218 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1219 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1224 m_scrolledWindowLinks->InvalidateBestSize();
1225 m_scrolledWindowLinks->Layout();
1226 bSizerLinks->Layout();
1232void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1233 AddLinkOnButtonClick(event);
1237 wxString findurl = m_pEditedLink->GetURL();
1238 wxString findlabel = m_pEditedLink->GetLabel();
1240 for (
const auto& win : m_scrolledWindowLinks->GetChildren()) {
1241 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
1243 link_win->Disconnect(
1244 wxEVT_COMMAND_HYPERLINK,
1245 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1246 link_win->Disconnect(
1248 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1254 int NbrOfLinks = m_pRoute->m_HyperlinkList->size();
1255 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1257 auto nodeToDelete = hyperlinklist->end();
1258 if (NbrOfLinks > 0) {
1259 auto it = hyperlinklist->begin();
1260 while (it != hyperlinklist->end()) {
1262 wxString Link = link->Link;
1263 wxString Descr = link->DescrText;
1264 if (Link == findurl &&
1265 (Descr == findlabel || (Link == findlabel && Descr ==
"")))
1268 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1269 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1270 wxDefaultSize, wxHL_DEFAULT_STYLE);
1272 wxEVT_COMMAND_HYPERLINK,
1273 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1277 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1280 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1285 if (nodeToDelete != hyperlinklist->end()) {
1286 hyperlinklist->erase(nodeToDelete);
1288 m_scrolledWindowLinks->InvalidateBestSize();
1289 m_scrolledWindowLinks->Layout();
1290 bSizerLinks->Layout();
1294void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1296 LinkPropDlg->m_textCtrlLinkDescription->SetValue(
"");
1297 LinkPropDlg->m_textCtrlLinkUrl->SetValue(
"");
1298 DimeControl(LinkPropDlg);
1299 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1300 if (retcode == wxID_OK) {
1301 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1302 if (desc ==
"") desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1303 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1304 m_scrolledWindowLinks, wxID_ANY, desc,
1305 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1306 wxDefaultSize, wxHL_DEFAULT_STYLE);
1307 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1308 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1310 ctrl->Connect(wxEVT_RIGHT_DOWN,
1311 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1314 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1315 m_scrolledWindowLinks->InvalidateBestSize();
1316 m_scrolledWindowLinks->Layout();
1317 bSizerLinks->Layout();
1320 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1321 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1328void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1329 if (m_toggleBtnEdit->GetValue()) {
1330 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1332 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1337void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1338 if (m_toggleBtnEdit->GetValue()) {
1339 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1340 ItemEditOnMenuSelection(event);
1353 wxString cc =
event.GetURL();
1354 if (cc.Find(
"#") != wxNOT_FOUND) {
1355 wxRegKey RegKey(wxString(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command"));
1356 if (RegKey.Exists()) {
1357 wxString command_line;
1358 RegKey.QueryValue(wxString(
""), command_line);
1361 command_line.Replace(wxString(
"\""), wxString(
""));
1364 int l = command_line.Find(
".exe");
1365 if (wxNOT_FOUND == l) l = command_line.Find(
".EXE");
1367 if (wxNOT_FOUND != l) {
1368 wxString cl = command_line.Mid(0, l + 4);
1379 wxString url =
event.GetURL();
1380 url.Replace(
" ",
"%20");
1381 ::wxLaunchDefaultBrowser(url);
1385void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1386 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1387 m_scrolledWindowLinks->PopupMenu(
1388 m_menuLink, m_pEditedLink->GetPosition().x + event.GetPosition().x,
1389 m_pEditedLink->GetPosition().y + event.GetPosition().y);
Generic Chart canvas base.
static PrintDialog & GetInstance()
Get instance to handle the print process,.
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.
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_RouteEndString
Name or description of the route's ending point.
wxString m_TimeDisplayFormat
Format for displaying times in the UI.
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.
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.
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.