24#include <wx/clipbrd.h>
26#include "model/georef.h"
27#include "model/own_ship.h"
28#include "model/routeman.h"
29#include "model/select.h"
34#include "model/navutil_base.h"
37#include "print_dialog.h"
38#include "routemanagerdialog.h"
39#include "route_printout.h"
40#include "RoutePropDlgImpl.h"
49#define GLOBAL_SETTINGS_INPUT 3
51#define ID_RCLK_MENU_COPY_TEXT 7013
52#define ID_RCLK_MENU_EDIT_WP 7014
53#define ID_RCLK_MENU_DELETE 7015
54#define ID_RCLK_MENU_MOVEUP_WP 7026
55#define ID_RCLK_MENU_MOVEDOWN_WP 7027
57#define COLUMN_PLANNED_SPEED 9
60extern wxString GetLayerName(
int id);
64extern ColorScheme global_color_scheme;
65extern RouteList* pRouteList;
70int g_route_prop_x, g_route_prop_y, g_route_prop_sx, g_route_prop_sy;
79#define PI (4. * atan(1.0))
82#define DEGS (180. / PI)
83#define RADS (PI / 180.)
93static wxString GetDaylightString(
int index) {
98 return _(
"MoTwilight");
106 return _(
"EvTwilight");
108 return _(
"Nighttime");
115static double sign(
double x) {
122static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
124static double FNday(
int y,
int m,
int d,
int h) {
125 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
126 return ((
double)fd - 730531.5 + h / 24.);
129static double FNrange(
double x) {
131 double a = TPI * (b - FNipart(b));
132 if (a < 0.) a = TPI + a;
136static double getDaylightEvent(
double glat,
double glong,
int riset,
137 double altitude,
int y,
int m,
int d) {
138 double day = FNday(y, m, d, 0);
139 double days, correction;
143 sin(altitude * RADS);
144 double sinphi = sin(glat * RADS);
145 double cosphi = cos(glat * RADS);
146 double g = glong * RADS;
147 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
149 while ((fabs(utold - utnew) > .001)) {
150 if (limit-- <= 0)
return (-1.);
151 days = day + utnew / TPI;
154 L = FNrange(4.8949504201433 + 628.331969753199 * t);
155 G = FNrange(6.2400408 + 628.3019501 * t);
156 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
158 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
159 obl = .409093 - .0002269 * t;
160 delta = asin(sin(obl) * sin(lambda));
161 GHA = utold - PI + E;
162 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
168 correction = acos(cosc);
170 utnew = FNrange(utold - (GHA + g + riset * correction));
173 return (utnew * DEGS / 15.);
176static double getLMT(
double ut,
double lon) {
177 double t = ut + lon / 15.;
190static wxString getDatetimeTimezoneSelector(
int selection) {
198 case GLOBAL_SETTINGS_INPUT:
200 return wxEmptyString;
204static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
205 if (fabs(lat) > 60.)
return (0);
206 int y = utcDateTime.GetYear();
207 int m = utcDateTime.GetMonth() + 1;
208 int d = utcDateTime.GetDay();
209 int h = utcDateTime.GetHour();
210 int n = utcDateTime.GetMinute();
211 int s = utcDateTime.GetSecond();
212 if (y < 2000 || y > 2100)
return (0);
214 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
215 double lt = getLMT(ut, lon);
216 double rsalt = -0.833;
220 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
224 sunrise = getLMT(sunrise, lon);
226 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
227 if (lt > sunrise)
return (DAY);
228 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
232 twilight = getLMT(twilight, lon);
238 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
242 sunset = getLMT(sunset, lon);
243 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
244 if (lt < sunset)
return (DAY);
245 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
249 twilight = getLMT(twilight, lon);
257RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
258 const wxString& title,
const wxPoint& pos,
259 const wxSize& size,
long style)
263 SetColorScheme(global_color_scheme);
265 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
266 g_route_prop_sx < wxGetDisplaySize().x &&
267 g_route_prop_sy < wxGetDisplaySize().y) {
268 SetSize(g_route_prop_sx, g_route_prop_sy);
271 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
272 g_route_prop_x < wxGetDisplaySize().x &&
273 g_route_prop_y < wxGetDisplaySize().y) {
274 SetPosition(wxPoint(10, 10));
278 Connect(wxEVT_COMMAND_MENU_SELECTED,
279 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
283 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
288RoutePropDlgImpl::~RoutePropDlgImpl() {
289 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
290 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
292 instanceFlag =
false;
295bool RoutePropDlgImpl::instanceFlag =
false;
296bool RoutePropDlgImpl::getInstanceFlag() {
297 return RoutePropDlgImpl::instanceFlag;
309void RoutePropDlgImpl::OnActivate(wxActivateEvent& event) {
310 auto pWin =
dynamic_cast<wxFrame*
>(
event.GetEventObject());
311 long int style = pWin->GetWindowStyle();
312 if (event.GetActive())
313 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
315 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
318void RoutePropDlgImpl::RecalculateSize(
void) {
320 esize.x = GetCharWidth() * 110;
321 esize.y = GetCharHeight() * 40;
323 wxSize dsize = GetParent()->GetSize();
324 esize.y = wxMin(esize.y, dsize.y - 0 );
325 esize.x = wxMin(esize.x, dsize.x - 0 );
328 wxSize fsize = GetSize();
329 wxSize canvas_size = GetParent()->GetSize();
330 wxPoint screen_pos = GetParent()->GetScreenPosition();
331 int xp = (canvas_size.x - fsize.x) / 2;
332 int yp = (canvas_size.y - fsize.y) / 2;
333 Move(screen_pos.x + xp, screen_pos.y + yp);
336void RoutePropDlgImpl::UpdatePoints() {
337 if (!m_pRoute)
return;
338 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
339 int selected_row = m_dvlcWaypoints->GetSelectedRow();
340 m_dvlcWaypoints->DeleteAllItems();
342 wxVector<wxVariant> data;
344 m_pRoute->UpdateSegmentDistances(
346 m_tcDistance->SetValue(
347 wxString::Format(wxT(
"%5.1f ") + getUsrDistanceUnit(),
349 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->
m_route_time)));
353 wxString slen, eta, ete;
354 double bearing, distance, speed;
355 double totalDistance = 0;
356 wxDateTime eta_dt = wxInvalidDateTime;
358 speed = pnode->GetData()->GetPlannedSpeed();
363 DistanceBearingMercator(pnode->GetData()->GetLatitude(),
364 pnode->GetData()->GetLongitude(), gLat, gLon,
365 &bearing, &distance);
369 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
371 eta = wxString::Format(
372 "Start: %s", ocpn::toUsrDateTimeFormat(
374 eta.Append(wxString::Format(
376 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
377 pnode->GetData()->m_lon,
385 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
390 distance = pnode->GetData()->GetDistance();
391 bearing = pnode->GetData()->GetCourse();
392 if (pnode->GetData()->GetETA().IsValid()) {
395 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
397 eta = ocpn::toUsrDateTimeFormat(pnode->GetData()->GetETA().FromUTC(),
399 eta.Append(wxString::Format(
401 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
402 pnode->GetData()->m_lon,
403 pnode->GetData()->GetETA()))
405 eta_dt = pnode->GetData()->GetETA();
409 ete = pnode->GetData()->GetETE();
410 totalDistance += distance;
412 wxString name = pnode->GetData()->GetName();
413 double lat = pnode->GetData()->GetLatitude();
414 double lon = pnode->GetData()->GetLongitude();
415 wxString tide_station = pnode->GetData()->m_TideStation;
416 wxString desc = pnode->GetData()->GetDescription();
418 if (pnode->GetData()->GetManualETD().IsValid()) {
423 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
425 etd = ocpn::toUsrDateTimeFormat(rt->
GetManualETD().FromUTC(), opts);
434 pnode = pnode->GetNext();
437 crs = formatAngle(pnode->GetData()->GetCourse());
443 data.push_back(wxVariant(
"---"));
445 std::ostringstream stm;
447 data.push_back(wxVariant(stm.str()));
450 wxString schar = wxEmptyString;
452 schar = wxString(
" ");
454 data.push_back(wxVariant(name + schar));
455 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(), toUsrDistance(distance));
456 data.push_back(wxVariant(schar + slen + schar));
457 data.push_back(wxVariant(schar + formatAngle(bearing)));
458 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(),
459 toUsrDistance(totalDistance));
460 data.push_back(wxVariant(schar + slen + schar));
461 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
462 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
463 data.push_back(wxVariant(schar + ete + schar));
464 data.push_back(schar + eta + schar);
466 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
467 data.push_back(wxVariant(
468 MakeTideInfo(tide_station, lat, lon, eta_dt)));
469 data.push_back(wxVariant(desc));
470 data.push_back(wxVariant(crs));
471 data.push_back(wxVariant(etd));
472 data.push_back(wxVariant(
475 m_dvlcWaypoints->AppendItem(data);
479 if (selected_row > 0) {
480 m_dvlcWaypoints->SelectRow(selected_row);
481 m_dvlcWaypoints->EnsureVisible(selection);
485void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
486 if (NULL == pR)
return;
496 pR->GetName() == wxEmptyString ? _(
"Route Properties") : pR->GetName();
500 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title, _(
"Layer"),
511 m_tz_selection = GLOBAL_SETTINGS_INPUT;
512 if (pR != m_pRoute) {
514 m_tz_selection = UTCINPUT;
516 m_tz_selection = LMTINPUT;
517 m_pEnroutePoint = NULL;
523 m_tcPlanSpeed->SetValue(
526 if (m_scrolledWindowLinks) {
527 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
528 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
529 wxWindowListNode* node = kids.Item(i);
530 wxWindow* win = node->GetData();
531 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
533 link_win->Disconnect(
534 wxEVT_COMMAND_HYPERLINK,
535 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
536 link_win->Disconnect(
538 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
544 if (NbrOfLinks > 0) {
545 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
548 wxString Link = link->Link;
549 wxString Descr = link->DescrText;
551 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
552 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
553 wxDefaultSize, wxHL_DEFAULT_STYLE);
555 wxEVT_COMMAND_HYPERLINK,
556 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
561 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
564 bSizerLinks->Add(ctrl, 0, wxALL, 5);
566 linknode = linknode->GetNext();
569 m_scrolledWindowLinks->InvalidateBestSize();
570 m_scrolledWindowLinks->Layout();
571 bSizerLinks->Layout();
574 m_choiceTimezone->SetSelection(m_tz_selection);
582 m_tcName->SetFocus();
585 wxDateTime t = toUsrDateTime(
591 wxDateTime t = toUsrDateTime(
592 wxDateTime::Now().ToUTC(), m_tz_selection,
599 m_btnSplit->Enable(
false);
600 if (!m_pRoute)
return;
602 if (m_pRoute->
m_Colour == wxEmptyString) {
603 m_choiceColor->Select(0);
605 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
607 if (m_pRoute->
m_Colour == ::GpxxColorNames[i]) {
608 m_choiceColor->Select(i + 1);
614 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(
int); i++) {
615 if (m_pRoute->
m_style == ::StyleValues[i]) {
616 m_choiceStyle->Select(i);
621 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(
int); i++) {
622 if (m_pRoute->
m_width == ::WidthValues[i]) {
623 m_choiceWidth->Select(i);
630 m_btnExtend->Enable(IsThisRouteExtendable());
633void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
634 if (!m_pRoute)
return;
640void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
641 if (!m_pRoute)
return;
647void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
648 if (!m_pRoute)
return;
649 m_tz_selection = m_choiceTimezone->GetSelection();
659void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
660 if (!m_pRoute)
return;
662 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
668 m_tcPlanSpeed->SetValue(
673void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
674 if (!m_pRoute)
return;
676 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
682 m_tcPlanSpeed->SetValue(
689void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
690 wxDataViewEvent& event) {
694 ev_col =
event.GetColumn();
697void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
698 wxDataViewEvent& event) {
699#if wxCHECK_VERSION(3, 1, 2)
701 if (!m_pRoute)
return;
702 wxDataViewModel*
const model =
event.GetModel();
704 model->GetValue(value, event.GetItem(), ev_col);
706 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
707 if (ev_col == COLUMN_PLANNED_SPEED) {
709 if (!value.GetString().ToDouble(&spd)) {
712 p->SetPlannedSpeed(fromUsrSpeed(spd));
713 }
else if (ev_col == COLUMN_ETD) {
714 wxString::const_iterator end;
717 wxString ts = value.GetString();
718 if (ts.StartsWith(
"!")) {
719 ts.Replace(
"!", wxEmptyString,
true);
725 if (!etd.ParseDateTime(ts, &end)) {
726 p->
SetETD(wxInvalidDateTime);
729 fromUsrDateTime(etd, m_tz_selection, p->m_lon).FormatISOCombined());
732 p->
SetETD(wxInvalidDateTime);
739void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
740 wxDataViewEvent& event) {
741 long selected_row = m_dvlcWaypoints->GetSelectedRow();
742 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
743 m_btnSplit->Enable(
true);
745 m_btnSplit->Enable(
false);
747 if (IsThisRouteExtendable()) {
748 m_btnExtend->Enable(
true);
750 m_btnExtend->Enable(
false);
752 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
753 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
755 if (gFrame->GetFocusCanvas()) {
756 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), prp->m_lat, prp->m_lon,
757 gFrame->GetFocusCanvas()->GetVPScale());
760 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
771 return fromUsrDateTime(
777void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
778 wxString tab(
"\t", wxConvUTF8);
779 wxString eol(
"\n", wxConvUTF8);
782 csvString << this->GetTitle() << eol << _(
"Name") << tab
786 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
787 << m_tcPlanSpeed->GetValue() << eol
788 << _(
"Departure Time") + _T(
" (") + _T(ETA_FORMAT_STR) + _T(
")")
790 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
795 noCols = m_dvlcWaypoints->GetColumnCount();
796 noRows = m_dvlcWaypoints->GetItemCount();
798 item.SetMask(wxLIST_MASK_TEXT);
800 for (
int i = 0; i < noCols; i++) {
801 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
802 csvString << col->GetTitle() << tab;
807 for (
int j = 0; j < noRows; j++) {
808 for (
int i = 0; i < noCols; i++) {
809 m_dvlcWaypoints->GetValue(value, j, i);
810 csvString << value.MakeString() << tab;
815 if (wxTheClipboard->Open()) {
816 wxTextDataObject* data =
new wxTextDataObject;
817 data->SetText(csvString);
818 wxTheClipboard->SetData(data);
819 wxTheClipboard->Close();
823void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
825 switch (event.GetId()) {
826 case ID_RCLK_MENU_COPY_TEXT: {
827 OnRoutepropCopyTxtClick(event);
830 case ID_RCLK_MENU_MOVEUP_WP: {
833 case ID_RCLK_MENU_MOVEDOWN_WP: {
835 moveup ? _(
"Are you sure you want to move Up this waypoint?")
836 : _(
"Are you sure you want to move Down this waypoint?");
838 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
839 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
841 if (dlg_return == wxID_YES) {
842 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
844 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
847 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
848 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
853 pSelect->AddAllSelectableRouteSegments(m_pRoute);
854 pSelect->AddAllSelectableRoutePoints(m_pRoute);
857 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
859 m_pRoute->FinalizeForRendering();
860 m_pRoute->UpdateSegmentDistances();
863 gFrame->InvalidateAllGL();
865 m_dvlcWaypoints->SelectRow(nRP);
867 SetRouteAndUpdate(m_pRoute,
true);
871 case ID_RCLK_MENU_DELETE: {
872 int dlg_return = OCPNMessageBox(
873 this, _(
"Are you sure you want to remove this waypoint?"),
874 _(
"OpenCPN Remove Waypoint"),
875 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
877 if (dlg_return == wxID_YES) {
878 int sel = m_dvlcWaypoints->GetSelectedRow();
879 m_dvlcWaypoints->SelectRow(sel);
881 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
883 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
885 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
887 gFrame->InvalidateAllGL();
892 case ID_RCLK_MENU_EDIT_WP: {
893 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
895 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
897 RouteManagerDialog::WptShowPropertiesDialog(pRP,
this);
903void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
904 wxDataViewEvent& event) {
907 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
908 _(
"Waypoint Properties") + _T(
"..."));
909 wxMenuItem* moveUpItem =
910 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
911 wxMenuItem* moveDownItem =
912 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
913 wxMenuItem* delItem =
914 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
917 editItem->SetFont(*pf);
918 moveUpItem->SetFont(*pf);
919 moveDownItem->SetFont(*pf);
920 delItem->SetFont(*pf);
922#if defined(__WXMSW__)
924 editItem->SetFont(*pf);
925 moveUpItem->SetFont(*pf);
926 moveDownItem->SetFont(*pf);
927 delItem->SetFont(*pf);
930 menu.Append(editItem);
931 if (g_btouch) menu.AppendSeparator();
932 menu.Append(moveUpItem);
933 if (g_btouch) menu.AppendSeparator();
934 menu.Append(moveDownItem);
935 if (g_btouch) menu.AppendSeparator();
936 menu.Append(delItem);
938 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
939 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
940 m_dvlcWaypoints->GetItemCount() > 2);
941 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
942 m_dvlcWaypoints->GetSelectedRow() <
943 m_dvlcWaypoints->GetItemCount() - 1 &&
944 m_dvlcWaypoints->GetItemCount() > 2);
945 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
946 m_dvlcWaypoints->GetItemCount() > 2);
949 wxMenuItem* copyItem =
950 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
952#if defined(__WXMSW__)
954 copyItem->SetFont(*qFont);
957 if (g_btouch) menu.AppendSeparator();
958 menu.Append(copyItem);
964void RoutePropDlgImpl::ResetChanges() {
965 if (!m_pRoute)
return;
971void RoutePropDlgImpl::SaveChanges() {
978 if (m_choiceColor->GetSelection() == 0) {
981 m_pRoute->
m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
984 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
985 m_pRoute->
m_width = ::WidthValues[m_choiceWidth->GetSelection()];
986 switch (m_tz_selection) {
993 case GLOBAL_SETTINGS_INPUT:
1002 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
1003 pConfig->UpdateSettings();
1008void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
1010void RoutePropDlgImpl::SaveGeometry() {
1011 GetSize(&g_route_prop_sx, &g_route_prop_sy);
1012 GetPosition(&g_route_prop_x, &g_route_prop_y);
1015void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1017 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1018 pRouteManagerDialog->UpdateRouteListCtrl();
1024void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1025 m_btnSplit->Enable(
false);
1029 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1030 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1031 m_pHead =
new Route();
1032 m_pTail =
new Route();
1033 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1034 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1036 pRouteList->Append(m_pHead);
1038 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1040 pRouteList->Append(m_pTail);
1042 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1045 NavObj_dB::GetInstance().DeleteRoute(m_pRoute);
1047 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1048 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1050 pSelect->AddAllSelectableRouteSegments(m_pTail);
1051 pSelect->AddAllSelectableRoutePoints(m_pTail);
1052 pSelect->AddAllSelectableRouteSegments(m_pHead);
1053 pSelect->AddAllSelectableRoutePoints(m_pHead);
1055 SetRouteAndUpdate(m_pTail);
1058 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1059 pRouteManagerDialog->UpdateRouteListCtrl();
1063void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1064 static std::set<int> s_options;
1066 int result = dlg.ShowModal();
1068 if (result == wxID_OK) {
1069 dlg.GetSelected(s_options);
1070 RoutePrintout printout(m_pRoute, s_options, m_tz_selection);
1072 printer.Initialize(wxPORTRAIT);
1073 printer.EnablePageNumbers(
true);
1074 printer.Print(
this, &printout);
1080void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1081 m_btnExtend->Enable(
false);
1083 if (IsThisRouteExtendable()) {
1084 int fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1085 int to = m_pExtendRoute->GetnPoints();
1087 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1088 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1089 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1090 SetRouteAndUpdate(m_pRoute);
1094 m_btnExtend->Enable(
true);
1097bool RoutePropDlgImpl::IsThisRouteExtendable() {
1098 m_pExtendRoute = NULL;
1099 m_pExtendPoint = NULL;
1103 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1104 wxArrayPtrVoid* pEditRouteArray;
1109 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1110 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1111 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1112 pEditRouteArray->RemoveAt(i - 1);
1114 if (pEditRouteArray->GetCount() == 1) {
1115 m_pExtendPoint = pLastPoint;
1117 if (pEditRouteArray->GetCount() == 0) {
1118 int nearby_radius_meters =
1119 (int)(8. / gFrame->GetPrimaryCanvas()->GetCanvasTrueScale());
1120 double rlat = pLastPoint->m_lat;
1121 double rlon = pLastPoint->m_lon;
1123 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1124 rlat, rlon, nearby_radius_meters, pLastPoint->
m_GUID);
1125 if (m_pExtendPoint) {
1126 wxArrayPtrVoid* pCloseWPRouteArray =
1128 if (pCloseWPRouteArray) {
1129 pEditRouteArray = pCloseWPRouteArray;
1132 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1133 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1134 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1135 pEditRouteArray->RemoveAt(i - 1);
1141 if (pEditRouteArray->GetCount() == 1) {
1143 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1144 int to = p->GetnPoints();
1147 delete pEditRouteArray;
1151 delete pEditRouteArray;
1156wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1157 double lon, wxDateTime utcTime) {
1158 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1160 if (stationName.IsEmpty()) {
1161 return wxEmptyString;
1163 if (!utcTime.IsValid()) {
1164 return _(
"Invalid date/time!");
1166 int stationID = ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1167 if (stationID == 0) {
1168 return _(
"Unknown station!");
1170 time_t dtmtt = utcTime.FromUTC().GetTicks();
1171 int ev = ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1174 dtm.Set(dtmtt).MakeUTC();
1176 wxString tide_form = wxEmptyString;
1179 tide_form.Append(_T(
"LW: "));
1180 }
else if (ev == 2) {
1181 tide_form.Append(_T(
"HW: "));
1182 }
else if (ev == 0) {
1183 tide_form.Append(_(
"Unavailable: "));
1187 ptcmgr->GetStationTimeOffset((
IDX_entry*)ptcmgr->GetIDX_entry(stationID));
1190 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1192 wxString tideDateTime = ocpn::toUsrDateTimeFormat(dtm.FromUTC(), opts);
1193 tide_form.Append(tideDateTime);
1194 dtm.Add(wxTimeSpan(0, offset, 0));
1197 tide_form.Append(wxString::Format(
" (" + _(
"Local") +
": %s%+03d:%02d) @ %s",
1198 dtm.Format(
"%a %x %H:%M:%S"), (offset / 60),
1199 abs(offset) % 60, stationName.c_str()));
1203void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1204 wxString findurl = m_pEditedLink->GetURL();
1205 wxString findlabel = m_pEditedLink->GetLabel();
1208 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1209 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1210 DimeControl(LinkPropDlg);
1211 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1212 findlabel](
int retcode) {
1213 if (retcode == wxID_OK) {
1217 if (NbrOfLinks > 0) {
1218 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1221 wxString Link = link->Link;
1222 wxString Descr = link->DescrText;
1223 if (Link == findurl &&
1224 (Descr == findlabel ||
1225 (Link == findlabel && Descr == wxEmptyString))) {
1226 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1228 LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1229 wxHyperlinkCtrl* h =
1230 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1233 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1234 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1237 linknode = linknode->GetNext();
1241 m_scrolledWindowLinks->InvalidateBestSize();
1242 m_scrolledWindowLinks->Layout();
1243 bSizerLinks->Layout();
1249void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1250 AddLinkOnButtonClick(event);
1254 wxHyperlinkListNode* nodeToDelete = NULL;
1255 wxString findurl = m_pEditedLink->GetURL();
1256 wxString findlabel = m_pEditedLink->GetLabel();
1258 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1259 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
1260 wxWindowListNode* node = kids.Item(i);
1261 wxWindow* win = node->GetData();
1263 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
1265 link_win->Disconnect(
1266 wxEVT_COMMAND_HYPERLINK,
1267 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1268 link_win->Disconnect(
1270 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1279 if (NbrOfLinks > 0) {
1280 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1283 wxString Link = link->Link;
1284 wxString Descr = link->DescrText;
1285 if (Link == findurl &&
1286 (Descr == findlabel || (Link == findlabel && Descr == wxEmptyString)))
1287 nodeToDelete = linknode;
1289 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1290 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1291 wxDefaultSize, wxHL_DEFAULT_STYLE);
1293 wxEVT_COMMAND_HYPERLINK,
1294 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1298 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1301 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1303 linknode = linknode->GetNext();
1307 hyperlinklist->DeleteNode(nodeToDelete);
1309 m_scrolledWindowLinks->InvalidateBestSize();
1310 m_scrolledWindowLinks->Layout();
1311 bSizerLinks->Layout();
1315void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1317 LinkPropDlg->m_textCtrlLinkDescription->SetValue(wxEmptyString);
1318 LinkPropDlg->m_textCtrlLinkUrl->SetValue(wxEmptyString);
1319 DimeControl(LinkPropDlg);
1320 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1321 if (retcode == wxID_OK) {
1322 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1323 if (desc == wxEmptyString)
1324 desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1325 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1326 m_scrolledWindowLinks, wxID_ANY, desc,
1327 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1328 wxDefaultSize, wxHL_DEFAULT_STYLE);
1329 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1330 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1332 ctrl->Connect(wxEVT_RIGHT_DOWN,
1333 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1336 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1337 m_scrolledWindowLinks->InvalidateBestSize();
1338 m_scrolledWindowLinks->Layout();
1339 bSizerLinks->Layout();
1342 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1343 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1344 h->LType = wxEmptyString;
1350void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1351 if (m_toggleBtnEdit->GetValue()) {
1352 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1354 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1359void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1360 if (m_toggleBtnEdit->GetValue()) {
1361 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1362 ItemEditOnMenuSelection(event);
1375 wxString cc =
event.GetURL();
1376 if (cc.Find(_T(
"#")) != wxNOT_FOUND) {
1378 wxString(_T(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command")));
1379 if (RegKey.Exists()) {
1380 wxString command_line;
1381 RegKey.QueryValue(wxString(_T(
"")), command_line);
1384 command_line.Replace(wxString(_T(
"\"")), wxString(_T(
"")));
1387 int l = command_line.Find(_T(
".exe"));
1388 if (wxNOT_FOUND == l) l = command_line.Find(_T(
".EXE"));
1390 if (wxNOT_FOUND != l) {
1391 wxString cl = command_line.Mid(0, l + 4);
1393 cc.Prepend(_T(
"\""));
1394 cc.Append(_T(
"\""));
1402 wxString url =
event.GetURL();
1403 url.Replace(_T(
" "), _T(
"%20"));
1404 ::wxLaunchDefaultBrowser(url);
1408void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1409 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1410 m_scrolledWindowLinks->PopupMenu(
1411 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1412 m_pEditedLink->GetPosition().y +
event.GetPosition().y);
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.
PlugIn Object Definition/API.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.