24#include <wx/clipbrd.h>
50#define GLOBAL_SETTINGS_INPUT 3
52#define ID_RCLK_MENU_COPY_TEXT 7013
53#define ID_RCLK_MENU_EDIT_WP 7014
54#define ID_RCLK_MENU_DELETE 7015
55#define ID_RCLK_MENU_MOVEUP_WP 7026
56#define ID_RCLK_MENU_MOVEDOWN_WP 7027
58#define COLUMN_PLANNED_SPEED 9
62#define PI (4. * atan(1.0))
65#define DEGS (180. / PI)
66#define RADS (PI / 180.)
78extern wxString GetLayerName(
int id);
86static wxString GetDaylightString(
int index) {
91 return _(
"MoTwilight");
99 return _(
"EvTwilight");
101 return _(
"Nighttime");
108static double sign(
double x) {
115static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
117static double FNday(
int y,
int m,
int d,
int h) {
118 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
119 return ((
double)fd - 730531.5 + h / 24.);
122static double FNrange(
double x) {
124 double a = TPI * (b - FNipart(b));
125 if (a < 0.) a = TPI + a;
129static double getDaylightEvent(
double glat,
double glong,
int riset,
130 double altitude,
int y,
int m,
int d) {
131 double day = FNday(y, m, d, 0);
132 double days, correction;
136 sin(altitude * RADS);
137 double sinphi = sin(glat * RADS);
138 double cosphi = cos(glat * RADS);
139 double g = glong * RADS;
140 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
142 while ((fabs(utold - utnew) > .001)) {
143 if (limit-- <= 0)
return (-1.);
144 days = day + utnew / TPI;
147 L = FNrange(4.8949504201433 + 628.331969753199 * t);
148 G = FNrange(6.2400408 + 628.3019501 * t);
149 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
151 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
152 obl = .409093 - .0002269 * t;
153 delta = asin(sin(obl) * sin(lambda));
154 GHA = utold - PI + E;
155 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
161 correction = acos(cosc);
163 utnew = FNrange(utold - (GHA + g + riset * correction));
166 return (utnew * DEGS / 15.);
169static double getLMT(
double ut,
double lon) {
170 double t = ut + lon / 15.;
183static wxString getDatetimeTimezoneSelector(
int selection) {
197static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
198 if (fabs(lat) > 60.)
return (0);
199 int y = utcDateTime.GetYear();
200 int m = utcDateTime.GetMonth() + 1;
201 int d = utcDateTime.GetDay();
202 int h = utcDateTime.GetHour();
203 int n = utcDateTime.GetMinute();
204 int s = utcDateTime.GetSecond();
205 if (y < 2000 || y > 2100)
return (0);
207 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
208 double lt = getLMT(ut, lon);
209 double rsalt = -0.833;
213 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
217 sunrise = getLMT(sunrise, lon);
219 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
220 if (lt > sunrise)
return (DAY);
221 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
225 twilight = getLMT(twilight, lon);
231 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
235 sunset = getLMT(sunset, lon);
236 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
237 if (lt < sunset)
return (DAY);
238 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
242 twilight = getLMT(twilight, lon);
250RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
251 const wxString& title,
const wxPoint& pos,
252 const wxSize& size,
long style)
256 SetColorScheme(global_color_scheme);
258 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
259 g_route_prop_sx < wxGetDisplaySize().x &&
260 g_route_prop_sy < wxGetDisplaySize().y) {
261 SetSize(g_route_prop_sx, g_route_prop_sy);
264 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
265 g_route_prop_x < wxGetDisplaySize().x &&
266 g_route_prop_y < wxGetDisplaySize().y) {
267 SetPosition(wxPoint(10, 10));
271 Connect(wxEVT_COMMAND_MENU_SELECTED,
272 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
276 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
281RoutePropDlgImpl::~RoutePropDlgImpl() {
282 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
283 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
285 instanceFlag =
false;
288bool RoutePropDlgImpl::instanceFlag =
false;
289bool RoutePropDlgImpl::getInstanceFlag() {
290 return RoutePropDlgImpl::instanceFlag;
302void RoutePropDlgImpl::OnActivate(wxActivateEvent& event) {
303 auto pWin =
dynamic_cast<wxFrame*
>(
event.GetEventObject());
304 long int style = pWin->GetWindowStyle();
305 if (event.GetActive())
306 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
308 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
311void RoutePropDlgImpl::RecalculateSize() {
313 esize.x = GetCharWidth() * 110;
314 esize.y = GetCharHeight() * 40;
316 wxSize dsize = GetParent()->GetSize();
317 esize.y = wxMin(esize.y, dsize.y - 0 );
318 esize.x = wxMin(esize.x, dsize.x - 0 );
321 wxSize fsize = GetSize();
322 wxSize canvas_size = GetParent()->GetSize();
323 wxPoint screen_pos = GetParent()->GetScreenPosition();
324 int xp = (canvas_size.x - fsize.x) / 2;
325 int yp = (canvas_size.y - fsize.y) / 2;
326 Move(screen_pos.x + xp, screen_pos.y + yp);
329void RoutePropDlgImpl::UpdatePoints() {
330 if (!m_pRoute)
return;
331 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
332 int selected_row = m_dvlcWaypoints->GetSelectedRow();
333 m_dvlcWaypoints->DeleteAllItems();
335 wxVector<wxVariant> data;
337 m_pRoute->UpdateSegmentDistances(
339 m_tcDistance->SetValue(
340 wxString::Format(
"%5.1f " + getUsrDistanceUnit(),
342 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->
m_route_time)));
345 wxString slen, eta, ete;
346 double bearing, distance, speed;
347 double totalDistance = 0;
348 wxDateTime eta_dt = wxInvalidDateTime;
351 speed = (*pnode)->GetPlannedSpeed();
356 DistanceBearingMercator((*pnode)->GetLatitude(), (*pnode)->GetLongitude(),
361 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
363 eta = wxString::Format(
364 "Start: %s", ocpn::toUsrDateTimeFormat(
366 eta.Append(wxString::Format(
367 " (%s)", GetDaylightString(
368 getDaylightStatus((*pnode)->m_lat, (*pnode)->m_lon,
376 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
381 distance = (*pnode)->GetDistance();
382 bearing = (*pnode)->GetCourse();
383 if ((*pnode)->GetETA().IsValid()) {
386 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
388 eta = ocpn::toUsrDateTimeFormat((*pnode)->GetETA().FromUTC(), opts);
389 eta.Append(wxString::Format(
390 " (%s)", GetDaylightString(getDaylightStatus((*pnode)->m_lat,
394 eta_dt = (*pnode)->GetETA();
398 ete = (*pnode)->GetETE();
399 totalDistance += distance;
401 wxString name = (*pnode)->GetName();
402 double lat = (*pnode)->GetLatitude();
403 double lon = (*pnode)->GetLongitude();
404 wxString tide_station = (*pnode)->m_TideStation;
405 wxString desc = (*pnode)->GetDescription();
407 if ((*pnode)->GetManualETD().IsValid()) {
412 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
414 etd = ocpn::toUsrDateTimeFormat(rt->
GetManualETD().FromUTC(), opts);
425 crs = formatAngle((*pnode)->GetCourse());
431 data.push_back(wxVariant(
"---"));
433 std::ostringstream stm;
435 data.push_back(wxVariant(stm.str()));
440 schar = wxString(
" ");
442 data.push_back(wxVariant(name + schar));
443 slen.Printf(
"%5.1f " + getUsrDistanceUnit(),
toUsrDistance(distance));
444 data.push_back(wxVariant(schar + slen + schar));
445 data.push_back(wxVariant(schar + formatAngle(bearing)));
446 slen.Printf(
"%5.1f " + getUsrDistanceUnit(),
toUsrDistance(totalDistance));
447 data.push_back(wxVariant(schar + slen + schar));
448 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
449 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
450 data.push_back(wxVariant(schar + ete + schar));
451 data.push_back(schar + eta + schar);
453 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
454 data.push_back(wxVariant(
455 MakeTideInfo(tide_station, lat, lon, eta_dt)));
456 data.push_back(wxVariant(desc));
457 data.push_back(wxVariant(crs));
458 data.push_back(wxVariant(etd));
462 m_dvlcWaypoints->AppendItem(data);
466 if (selected_row > 0) {
467 m_dvlcWaypoints->SelectRow(selected_row);
468 m_dvlcWaypoints->EnsureVisible(selection);
472void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
473 if (NULL == pR)
return;
482 wxString title = pR->GetName() ==
"" ? _(
"Route Properties") : pR->GetName();
486 wxString caption(wxString::Format(
"%s, %s: %s", title, _(
"Layer"),
498 if (pR != m_pRoute) {
503 m_pEnroutePoint = NULL;
509 m_tcPlanSpeed->SetValue(
512 if (m_scrolledWindowLinks) {
513 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
514 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
515 wxWindowListNode* node = kids.Item(i);
516 wxWindow* win = node->GetData();
517 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
519 link_win->Disconnect(
520 wxEVT_COMMAND_HYPERLINK,
521 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
522 link_win->Disconnect(
524 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
530 for (
Hyperlink* link : *m_pRoute->m_HyperlinkList) {
531 wxString Link = link->Link;
532 wxString Descr = link->DescrText;
534 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
535 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
536 wxDefaultSize, wxHL_DEFAULT_STYLE);
538 wxEVT_COMMAND_HYPERLINK,
539 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
544 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
547 bSizerLinks->Add(ctrl, 0, wxALL, 5);
549 m_scrolledWindowLinks->InvalidateBestSize();
550 m_scrolledWindowLinks->Layout();
551 bSizerLinks->Layout();
554 m_choiceTimezone->SetSelection(m_tz_selection);
562 m_tcName->SetFocus();
579 m_btnSplit->Enable(
false);
580 if (!m_pRoute)
return;
583 m_choiceColor->Select(0);
585 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
587 if (m_pRoute->
m_Colour == ::GpxxColorNames[i]) {
588 m_choiceColor->Select(i + 1);
594 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(
int); i++) {
595 if (m_pRoute->
m_style == ::StyleValues[i]) {
596 m_choiceStyle->Select(i);
601 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(
int); i++) {
602 if (m_pRoute->
m_width == ::WidthValues[i]) {
603 m_choiceWidth->Select(i);
610 m_btnExtend->Enable(IsThisRouteExtendable());
613void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
614 if (!m_pRoute)
return;
620void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
621 if (!m_pRoute)
return;
627void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
628 if (!m_pRoute)
return;
629 m_tz_selection = m_choiceTimezone->GetSelection();
638void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
639 if (!m_pRoute)
return;
641 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
647 m_tcPlanSpeed->SetValue(
652void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
653 if (!m_pRoute)
return;
655 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
661 m_tcPlanSpeed->SetValue(
668void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
669 wxDataViewEvent& event) {
673 ev_col =
event.GetColumn();
676void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
677 wxDataViewEvent& event) {
678#if wxCHECK_VERSION(3, 1, 2)
680 if (!m_pRoute)
return;
681 wxDataViewModel*
const model =
event.GetModel();
683 model->GetValue(value, event.GetItem(), ev_col);
685 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
686 if (ev_col == COLUMN_PLANNED_SPEED) {
688 if (!value.GetString().ToDouble(&spd)) {
691 p->SetPlannedSpeed(fromUsrSpeed(spd));
692 }
else if (ev_col == COLUMN_ETD) {
693 wxString::const_iterator end;
696 wxString ts = value.GetString();
697 if (ts.StartsWith(
"!")) {
698 ts.Replace(
"!",
"",
true);
704 if (!etd.ParseDateTime(ts, &end)) {
705 p->
SetETD(wxInvalidDateTime);
711 p->
SetETD(wxInvalidDateTime);
718void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
719 wxDataViewEvent& event) {
720 long selected_row = m_dvlcWaypoints->GetSelectedRow();
721 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
722 m_btnSplit->Enable(
true);
724 m_btnSplit->Enable(
false);
726 if (IsThisRouteExtendable()) {
727 m_btnExtend->Enable(
true);
729 m_btnExtend->Enable(
false);
731 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
732 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
734 if (gFrame->GetFocusCanvas()) {
735 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), 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 gFrame->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 gFrame->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);
983 pConfig->UpdateSettings();
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) {
997 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
998 pRouteManagerDialog->UpdateRouteListCtrl();
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);
1038 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1039 pRouteManagerDialog->UpdateRouteListCtrl();
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. / gFrame->GetPrimaryCanvas()->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.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
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.
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.
Select * pSelect
Global instance.
Selected route, segment, waypoint, etc.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.