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
62extern wxString GetLayerName(
int id);
66extern ColorScheme global_color_scheme;
67extern RouteList* pRouteList;
72int g_route_prop_x, g_route_prop_y, g_route_prop_sx, g_route_prop_sy;
81#define PI (4. * atan(1.0))
84#define DEGS (180. / PI)
85#define RADS (PI / 180.)
95static wxString GetDaylightString(
int index) {
100 return _(
"MoTwilight");
108 return _(
"EvTwilight");
110 return _(
"Nighttime");
117static double sign(
double x) {
124static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
126static double FNday(
int y,
int m,
int d,
int h) {
127 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
128 return ((
double)fd - 730531.5 + h / 24.);
131static double FNrange(
double x) {
133 double a = TPI * (b - FNipart(b));
134 if (a < 0.) a = TPI + a;
138static double getDaylightEvent(
double glat,
double glong,
int riset,
139 double altitude,
int y,
int m,
int d) {
140 double day = FNday(y, m, d, 0);
141 double days, correction;
145 sin(altitude * RADS);
146 double sinphi = sin(glat * RADS);
147 double cosphi = cos(glat * RADS);
148 double g = glong * RADS;
149 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
151 while ((fabs(utold - utnew) > .001)) {
152 if (limit-- <= 0)
return (-1.);
153 days = day + utnew / TPI;
156 L = FNrange(4.8949504201433 + 628.331969753199 * t);
157 G = FNrange(6.2400408 + 628.3019501 * t);
158 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
160 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
161 obl = .409093 - .0002269 * t;
162 delta = asin(sin(obl) * sin(lambda));
163 GHA = utold - PI + E;
164 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
170 correction = acos(cosc);
172 utnew = FNrange(utold - (GHA + g + riset * correction));
175 return (utnew * DEGS / 15.);
178static double getLMT(
double ut,
double lon) {
179 double t = ut + lon / 15.;
192static wxString getDatetimeTimezoneSelector(
int selection) {
200 case GLOBAL_SETTINGS_INPUT:
202 return wxEmptyString;
206static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
207 if (fabs(lat) > 60.)
return (0);
208 int y = utcDateTime.GetYear();
209 int m = utcDateTime.GetMonth() + 1;
210 int d = utcDateTime.GetDay();
211 int h = utcDateTime.GetHour();
212 int n = utcDateTime.GetMinute();
213 int s = utcDateTime.GetSecond();
214 if (y < 2000 || y > 2100)
return (0);
216 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
217 double lt = getLMT(ut, lon);
218 double rsalt = -0.833;
222 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
226 sunrise = getLMT(sunrise, lon);
228 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
229 if (lt > sunrise)
return (DAY);
230 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
234 twilight = getLMT(twilight, lon);
240 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
244 sunset = getLMT(sunset, lon);
245 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
246 if (lt < sunset)
return (DAY);
247 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
251 twilight = getLMT(twilight, lon);
259RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
260 const wxString& title,
const wxPoint& pos,
261 const wxSize& size,
long style)
265 SetColorScheme(global_color_scheme);
267 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
268 g_route_prop_sx < wxGetDisplaySize().x &&
269 g_route_prop_sy < wxGetDisplaySize().y) {
270 SetSize(g_route_prop_sx, g_route_prop_sy);
273 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
274 g_route_prop_x < wxGetDisplaySize().x &&
275 g_route_prop_y < wxGetDisplaySize().y) {
276 SetPosition(wxPoint(10, 10));
280 Connect(wxEVT_COMMAND_MENU_SELECTED,
281 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
285 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
290RoutePropDlgImpl::~RoutePropDlgImpl() {
291 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
292 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
294 instanceFlag =
false;
297bool RoutePropDlgImpl::instanceFlag =
false;
298bool RoutePropDlgImpl::getInstanceFlag() {
299 return RoutePropDlgImpl::instanceFlag;
311void RoutePropDlgImpl::OnActivate(wxActivateEvent& event) {
312 auto pWin =
dynamic_cast<wxFrame*
>(
event.GetEventObject());
313 long int style = pWin->GetWindowStyle();
314 if (event.GetActive())
315 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
317 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
320void RoutePropDlgImpl::RecalculateSize(
void) {
322 esize.x = GetCharWidth() * 110;
323 esize.y = GetCharHeight() * 40;
325 wxSize dsize = GetParent()->GetSize();
326 esize.y = wxMin(esize.y, dsize.y - 0 );
327 esize.x = wxMin(esize.x, dsize.x - 0 );
330 wxSize fsize = GetSize();
331 wxSize canvas_size = GetParent()->GetSize();
332 wxPoint screen_pos = GetParent()->GetScreenPosition();
333 int xp = (canvas_size.x - fsize.x) / 2;
334 int yp = (canvas_size.y - fsize.y) / 2;
335 Move(screen_pos.x + xp, screen_pos.y + yp);
338void RoutePropDlgImpl::UpdatePoints() {
339 if (!m_pRoute)
return;
340 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
341 int selected_row = m_dvlcWaypoints->GetSelectedRow();
342 m_dvlcWaypoints->DeleteAllItems();
344 wxVector<wxVariant> data;
346 m_pRoute->UpdateSegmentDistances(
348 m_tcDistance->SetValue(
349 wxString::Format(
"%5.1f " + getUsrDistanceUnit(),
351 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->
m_route_time)));
355 wxString slen, eta, ete;
356 double bearing, distance, speed;
357 double totalDistance = 0;
358 wxDateTime eta_dt = wxInvalidDateTime;
360 speed = pnode->GetData()->GetPlannedSpeed();
365 DistanceBearingMercator(pnode->GetData()->GetLatitude(),
366 pnode->GetData()->GetLongitude(), gLat, gLon,
367 &bearing, &distance);
371 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
373 eta = wxString::Format(
374 "Start: %s", ocpn::toUsrDateTimeFormat(
376 eta.Append(wxString::Format(
378 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
379 pnode->GetData()->m_lon,
387 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
392 distance = pnode->GetData()->GetDistance();
393 bearing = pnode->GetData()->GetCourse();
394 if (pnode->GetData()->GetETA().IsValid()) {
397 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
399 eta = ocpn::toUsrDateTimeFormat(pnode->GetData()->GetETA().FromUTC(),
401 eta.Append(wxString::Format(
403 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
404 pnode->GetData()->m_lon,
405 pnode->GetData()->GetETA()))
407 eta_dt = pnode->GetData()->GetETA();
411 ete = pnode->GetData()->GetETE();
412 totalDistance += distance;
414 wxString name = pnode->GetData()->GetName();
415 double lat = pnode->GetData()->GetLatitude();
416 double lon = pnode->GetData()->GetLongitude();
417 wxString tide_station = pnode->GetData()->m_TideStation;
418 wxString desc = pnode->GetData()->GetDescription();
420 if (pnode->GetData()->GetManualETD().IsValid()) {
425 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
427 etd = ocpn::toUsrDateTimeFormat(rt->
GetManualETD().FromUTC(), opts);
435 pnode = pnode->GetNext();
438 crs = formatAngle(pnode->GetData()->GetCourse());
444 data.push_back(wxVariant(
"---"));
446 std::ostringstream stm;
448 data.push_back(wxVariant(stm.str()));
451 wxString schar = wxEmptyString;
453 schar = wxString(
" ");
455 data.push_back(wxVariant(name + schar));
456 slen.Printf(
"%5.1f " + getUsrDistanceUnit(), toUsrDistance(distance));
457 data.push_back(wxVariant(schar + slen + schar));
458 data.push_back(wxVariant(schar + formatAngle(bearing)));
459 slen.Printf(
"%5.1f " + getUsrDistanceUnit(), 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(
"%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(ETA_FORMAT_STR) +
")" << tab
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") +
"...");
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(
"LW: ");
1180 }
else if (ev == 2) {
1181 tide_form.Append(
"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(
"#") != wxNOT_FOUND) {
1377 wxRegKey RegKey(wxString(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command"));
1378 if (RegKey.Exists()) {
1379 wxString command_line;
1380 RegKey.QueryValue(wxString(
""), command_line);
1383 command_line.Replace(wxString(
"\""), wxString(
""));
1386 int l = command_line.Find(
".exe");
1387 if (wxNOT_FOUND == l) l = command_line.Find(
".EXE");
1389 if (wxNOT_FOUND != l) {
1390 wxString cl = command_line.Mid(0, l + 4);
1401 wxString url =
event.GetURL();
1402 url.Replace(
" ",
"%20");
1403 ::wxLaunchDefaultBrowser(url);
1407void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1408 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1409 m_scrolledWindowLinks->PopupMenu(
1410 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1411 m_pEditedLink->GetPosition().y +
event.GetPosition().y);
Generic Chart canvas base.
Represents an index entry for tidal and current data.
static PrintDialog & GetInstance()
Get instance to handle the print process,.
Represents a waypoint or mark within the navigation system.
wxString m_GUID
Globally Unique Identifier for the waypoint.
wxDateTime GetManualETD()
Retrieves the manually set Estimated Time of Departure for this waypoint, in UTC.
void SetETD(const wxDateTime &etd)
Sets the Estimated Time of Departure for this waypoint, in UTC.
wxDateTime GetETA()
Retrieves the Estimated Time of Arrival for this waypoint, in UTC.
Input dialog with route print selection.
Printout route information and a table with selected route point information.
void ItemDeleteOnMenuSelection(wxCommandEvent &event)
wxDateTime GetDepartureTS()
Returns the departure time of the route, in UTC.
wxTimePickerCtrl * m_tpDepartureTime
The time picker for the departure time of the route.
wxDatePickerCtrl * m_dpDepartureDate
The date picker for the departure date of the route.
Represents a navigational route in the navigation system.
double m_PlannedSpeed
Default planned speed for the route in knots.
wxString m_RouteStartString
Name or description of the route's starting point.
wxString m_RouteDescription
Additional descriptive information about the route.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
wxString m_Colour
Color name for rendering the route on the chart.
wxString m_RouteEndString
Name or description of the route's ending point.
wxPenStyle m_style
Style of the route line when rendered on the chart.
wxString m_TimeDisplayFormat
Format for displaying times in the UI.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
wxDateTime m_PlannedDeparture
Planned departure time for the route, in UTC.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
double m_route_time
Total estimated time to complete the route in seconds.
void SetDepartureDate(const wxDateTime &dt)
Set the departure time of the route.
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this route.
int m_LayerID
Identifier of the layer containing this route.
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool DeleteRoute(Route *pRoute)
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
General purpose GUI support.
PlugIn Object Definition/API.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.