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"
48#define GLOBAL_SETTINGS_INPUT 3
50#define ID_RCLK_MENU_COPY_TEXT 7013
51#define ID_RCLK_MENU_EDIT_WP 7014
52#define ID_RCLK_MENU_DELETE 7015
53#define ID_RCLK_MENU_MOVEUP_WP 7026
54#define ID_RCLK_MENU_MOVEDOWN_WP 7027
56#define COLUMN_PLANNED_SPEED 9
59extern wxString GetLayerName(
int id);
63extern ColorScheme global_color_scheme;
64extern RouteList* pRouteList;
69int g_route_prop_x, g_route_prop_y, g_route_prop_sx, g_route_prop_sy;
78#define PI (4. * atan(1.0))
81#define DEGS (180. / PI)
82#define RADS (PI / 180.)
92static wxString GetDaylightString(
int index) {
97 return _(
"MoTwilight");
105 return _(
"EvTwilight");
107 return _(
"Nighttime");
114static double sign(
double x) {
121static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
123static double FNday(
int y,
int m,
int d,
int h) {
124 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
125 return ((
double)fd - 730531.5 + h / 24.);
128static double FNrange(
double x) {
130 double a = TPI * (b - FNipart(b));
131 if (a < 0.) a = TPI + a;
135static double getDaylightEvent(
double glat,
double glong,
int riset,
136 double altitude,
int y,
int m,
int d) {
137 double day = FNday(y, m, d, 0);
138 double days, correction;
142 sin(altitude * RADS);
143 double sinphi = sin(glat * RADS);
144 double cosphi = cos(glat * RADS);
145 double g = glong * RADS;
146 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
148 while ((fabs(utold - utnew) > .001)) {
149 if (limit-- <= 0)
return (-1.);
150 days = day + utnew / TPI;
153 L = FNrange(4.8949504201433 + 628.331969753199 * t);
154 G = FNrange(6.2400408 + 628.3019501 * t);
155 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
157 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
158 obl = .409093 - .0002269 * t;
159 delta = asin(sin(obl) * sin(lambda));
160 GHA = utold - PI + E;
161 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
167 correction = acos(cosc);
169 utnew = FNrange(utold - (GHA + g + riset * correction));
172 return (utnew * DEGS / 15.);
175static double getLMT(
double ut,
double lon) {
176 double t = ut + lon / 15.;
189static wxString getDatetimeTimezoneSelector(
int selection) {
197 case GLOBAL_SETTINGS_INPUT:
199 return wxEmptyString;
203static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
204 if (fabs(lat) > 60.)
return (0);
205 int y = utcDateTime.GetYear();
206 int m = utcDateTime.GetMonth() + 1;
207 int d = utcDateTime.GetDay();
208 int h = utcDateTime.GetHour();
209 int n = utcDateTime.GetMinute();
210 int s = utcDateTime.GetSecond();
211 if (y < 2000 || y > 2100)
return (0);
213 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
214 double lt = getLMT(ut, lon);
215 double rsalt = -0.833;
219 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
223 sunrise = getLMT(sunrise, lon);
225 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
226 if (lt > sunrise)
return (DAY);
227 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
231 twilight = getLMT(twilight, lon);
237 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
241 sunset = getLMT(sunset, lon);
242 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
243 if (lt < sunset)
return (DAY);
244 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
248 twilight = getLMT(twilight, lon);
256RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
257 const wxString& title,
const wxPoint& pos,
258 const wxSize& size,
long style)
262 SetColorScheme(global_color_scheme);
264 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
265 g_route_prop_sx < wxGetDisplaySize().x &&
266 g_route_prop_sy < wxGetDisplaySize().y) {
267 SetSize(g_route_prop_sx, g_route_prop_sy);
270 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
271 g_route_prop_x < wxGetDisplaySize().x &&
272 g_route_prop_y < wxGetDisplaySize().y) {
273 SetPosition(wxPoint(10, 10));
277 Connect(wxEVT_COMMAND_MENU_SELECTED,
278 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
282 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
287RoutePropDlgImpl::~RoutePropDlgImpl() {
288 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
289 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
291 instanceFlag =
false;
294bool RoutePropDlgImpl::instanceFlag =
false;
295bool RoutePropDlgImpl::getInstanceFlag() {
296 return RoutePropDlgImpl::instanceFlag;
308void RoutePropDlgImpl::OnActivate(wxActivateEvent& event) {
309 auto pWin =
dynamic_cast<wxFrame*
>(
event.GetEventObject());
310 long int style = pWin->GetWindowStyle();
311 if (event.GetActive())
312 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
314 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
317void RoutePropDlgImpl::RecalculateSize(
void) {
319 esize.x = GetCharWidth() * 110;
320 esize.y = GetCharHeight() * 40;
322 wxSize dsize = GetParent()->GetSize();
323 esize.y = wxMin(esize.y, dsize.y - 0 );
324 esize.x = wxMin(esize.x, dsize.x - 0 );
327 wxSize fsize = GetSize();
328 wxSize canvas_size = GetParent()->GetSize();
329 wxPoint screen_pos = GetParent()->GetScreenPosition();
330 int xp = (canvas_size.x - fsize.x) / 2;
331 int yp = (canvas_size.y - fsize.y) / 2;
332 Move(screen_pos.x + xp, screen_pos.y + yp);
335void RoutePropDlgImpl::UpdatePoints() {
336 if (!m_pRoute)
return;
337 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
338 int selected_row = m_dvlcWaypoints->GetSelectedRow();
339 m_dvlcWaypoints->DeleteAllItems();
341 wxVector<wxVariant> data;
343 m_pRoute->UpdateSegmentDistances(
345 m_tcDistance->SetValue(
346 wxString::Format(wxT(
"%5.1f ") + getUsrDistanceUnit(),
348 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->
m_route_time)));
352 wxString slen, eta, ete;
353 double bearing, distance, speed;
354 double totalDistance = 0;
355 wxDateTime eta_dt = wxInvalidDateTime;
357 speed = pnode->GetData()->GetPlannedSpeed();
362 DistanceBearingMercator(pnode->GetData()->GetLatitude(),
363 pnode->GetData()->GetLongitude(), gLat, gLon,
364 &bearing, &distance);
368 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
370 eta = wxString::Format(
371 "Start: %s", ocpn::toUsrDateTimeFormat(
373 eta.Append(wxString::Format(
375 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
376 pnode->GetData()->m_lon,
384 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
389 distance = pnode->GetData()->GetDistance();
390 bearing = pnode->GetData()->GetCourse();
391 if (pnode->GetData()->GetETA().IsValid()) {
394 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
396 eta = ocpn::toUsrDateTimeFormat(pnode->GetData()->GetETA().FromUTC(),
398 eta.Append(wxString::Format(
400 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
401 pnode->GetData()->m_lon,
402 pnode->GetData()->GetETA()))
404 eta_dt = pnode->GetData()->GetETA();
408 ete = pnode->GetData()->GetETE();
409 totalDistance += distance;
411 wxString name = pnode->GetData()->GetName();
412 double lat = pnode->GetData()->GetLatitude();
413 double lon = pnode->GetData()->GetLongitude();
414 wxString tide_station = pnode->GetData()->m_TideStation;
415 wxString desc = pnode->GetData()->GetDescription();
417 if (pnode->GetData()->GetManualETD().IsValid()) {
422 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
424 etd = ocpn::toUsrDateTimeFormat(rt->
GetManualETD().FromUTC(), opts);
433 pnode = pnode->GetNext();
436 crs = formatAngle(pnode->GetData()->GetCourse());
442 data.push_back(wxVariant(
"---"));
444 std::ostringstream stm;
446 data.push_back(wxVariant(stm.str()));
449 wxString schar = wxEmptyString;
451 schar = wxString(
" ");
453 data.push_back(wxVariant(name + schar));
454 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(), toUsrDistance(distance));
455 data.push_back(wxVariant(schar + slen + schar));
456 data.push_back(wxVariant(schar + formatAngle(bearing)));
457 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(),
458 toUsrDistance(totalDistance));
459 data.push_back(wxVariant(schar + slen + schar));
460 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
461 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
462 data.push_back(wxVariant(schar + ete + schar));
463 data.push_back(schar + eta + schar);
465 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
466 data.push_back(wxVariant(
467 MakeTideInfo(tide_station, lat, lon, eta_dt)));
468 data.push_back(wxVariant(desc));
469 data.push_back(wxVariant(crs));
470 data.push_back(wxVariant(etd));
471 data.push_back(wxVariant(
474 m_dvlcWaypoints->AppendItem(data);
478 if (selected_row > 0) {
479 m_dvlcWaypoints->SelectRow(selected_row);
480 m_dvlcWaypoints->EnsureVisible(selection);
484void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
485 if (NULL == pR)
return;
495 pR->GetName() == wxEmptyString ? _(
"Route Properties") : pR->GetName();
499 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title, _(
"Layer"),
510 m_tz_selection = GLOBAL_SETTINGS_INPUT;
511 if (pR != m_pRoute) {
513 m_tz_selection = UTCINPUT;
515 m_tz_selection = LMTINPUT;
516 m_pEnroutePoint = NULL;
522 m_tcPlanSpeed->SetValue(
525 if (m_scrolledWindowLinks) {
526 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
527 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
528 wxWindowListNode* node = kids.Item(i);
529 wxWindow* win = node->GetData();
530 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
532 link_win->Disconnect(
533 wxEVT_COMMAND_HYPERLINK,
534 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
535 link_win->Disconnect(
537 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
543 if (NbrOfLinks > 0) {
544 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
547 wxString Link = link->Link;
548 wxString Descr = link->DescrText;
550 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
551 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
552 wxDefaultSize, wxHL_DEFAULT_STYLE);
554 wxEVT_COMMAND_HYPERLINK,
555 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
560 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
563 bSizerLinks->Add(ctrl, 0, wxALL, 5);
565 linknode = linknode->GetNext();
568 m_scrolledWindowLinks->InvalidateBestSize();
569 m_scrolledWindowLinks->Layout();
570 bSizerLinks->Layout();
573 m_choiceTimezone->SetSelection(m_tz_selection);
581 m_tcName->SetFocus();
584 wxDateTime t = toUsrDateTime(
590 wxDateTime t = toUsrDateTime(
591 wxDateTime::Now().ToUTC(), m_tz_selection,
598 m_btnSplit->Enable(
false);
599 if (!m_pRoute)
return;
601 if (m_pRoute->
m_Colour == wxEmptyString) {
602 m_choiceColor->Select(0);
604 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
606 if (m_pRoute->
m_Colour == ::GpxxColorNames[i]) {
607 m_choiceColor->Select(i + 1);
613 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(
int); i++) {
614 if (m_pRoute->
m_style == ::StyleValues[i]) {
615 m_choiceStyle->Select(i);
620 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(
int); i++) {
621 if (m_pRoute->
m_width == ::WidthValues[i]) {
622 m_choiceWidth->Select(i);
629 m_btnExtend->Enable(IsThisRouteExtendable());
632void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
633 if (!m_pRoute)
return;
639void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
640 if (!m_pRoute)
return;
646void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
647 if (!m_pRoute)
return;
648 m_tz_selection = m_choiceTimezone->GetSelection();
658void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
659 if (!m_pRoute)
return;
661 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
667 m_tcPlanSpeed->SetValue(
672void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
673 if (!m_pRoute)
return;
675 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
681 m_tcPlanSpeed->SetValue(
688void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
689 wxDataViewEvent& event) {
693 ev_col =
event.GetColumn();
696void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
697 wxDataViewEvent& event) {
698#if wxCHECK_VERSION(3, 1, 2)
700 if (!m_pRoute)
return;
701 wxDataViewModel*
const model =
event.GetModel();
703 model->GetValue(value, event.GetItem(), ev_col);
705 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
706 if (ev_col == COLUMN_PLANNED_SPEED) {
708 if (!value.GetString().ToDouble(&spd)) {
711 p->SetPlannedSpeed(fromUsrSpeed(spd));
712 }
else if (ev_col == COLUMN_ETD) {
713 wxString::const_iterator end;
716 wxString ts = value.GetString();
717 if (ts.StartsWith(
"!")) {
718 ts.Replace(
"!", wxEmptyString,
true);
724 if (!etd.ParseDateTime(ts, &end)) {
725 p->
SetETD(wxInvalidDateTime);
728 fromUsrDateTime(etd, m_tz_selection, p->m_lon).FormatISOCombined());
731 p->
SetETD(wxInvalidDateTime);
738void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
739 wxDataViewEvent& event) {
740 long selected_row = m_dvlcWaypoints->GetSelectedRow();
741 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
742 m_btnSplit->Enable(
true);
744 m_btnSplit->Enable(
false);
746 if (IsThisRouteExtendable()) {
747 m_btnExtend->Enable(
true);
749 m_btnExtend->Enable(
false);
751 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
752 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
754 if (gFrame->GetFocusCanvas()) {
755 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), prp->m_lat, prp->m_lon,
756 gFrame->GetFocusCanvas()->GetVPScale());
759 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
770 return fromUsrDateTime(
776void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
777 wxString tab(
"\t", wxConvUTF8);
778 wxString eol(
"\n", wxConvUTF8);
781 csvString << this->GetTitle() << eol << _(
"Name") << tab
785 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
786 << m_tcPlanSpeed->GetValue() << eol
787 << _(
"Departure Time") + _T(
" (") + _T(ETA_FORMAT_STR) + _T(
")")
789 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
794 noCols = m_dvlcWaypoints->GetColumnCount();
795 noRows = m_dvlcWaypoints->GetItemCount();
797 item.SetMask(wxLIST_MASK_TEXT);
799 for (
int i = 0; i < noCols; i++) {
800 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
801 csvString << col->GetTitle() << tab;
806 for (
int j = 0; j < noRows; j++) {
807 for (
int i = 0; i < noCols; i++) {
808 m_dvlcWaypoints->GetValue(value, j, i);
809 csvString << value.MakeString() << tab;
814 if (wxTheClipboard->Open()) {
815 wxTextDataObject* data =
new wxTextDataObject;
816 data->SetText(csvString);
817 wxTheClipboard->SetData(data);
818 wxTheClipboard->Close();
822void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
824 switch (event.GetId()) {
825 case ID_RCLK_MENU_COPY_TEXT: {
826 OnRoutepropCopyTxtClick(event);
829 case ID_RCLK_MENU_MOVEUP_WP: {
832 case ID_RCLK_MENU_MOVEDOWN_WP: {
834 moveup ? _(
"Are you sure you want to move Up this waypoint?")
835 : _(
"Are you sure you want to move Down this waypoint?");
837 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
838 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
840 if (dlg_return == wxID_YES) {
841 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
843 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
846 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
847 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
852 pSelect->AddAllSelectableRouteSegments(m_pRoute);
853 pSelect->AddAllSelectableRoutePoints(m_pRoute);
855 pConfig->UpdateRoute(m_pRoute);
857 m_pRoute->FinalizeForRendering();
858 m_pRoute->UpdateSegmentDistances();
861 gFrame->InvalidateAllGL();
863 m_dvlcWaypoints->SelectRow(nRP);
865 SetRouteAndUpdate(m_pRoute,
true);
869 case ID_RCLK_MENU_DELETE: {
870 int dlg_return = OCPNMessageBox(
871 this, _(
"Are you sure you want to remove this waypoint?"),
872 _(
"OpenCPN Remove Waypoint"),
873 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
875 if (dlg_return == wxID_YES) {
876 int sel = m_dvlcWaypoints->GetSelectedRow();
877 m_dvlcWaypoints->SelectRow(sel);
879 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
881 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
883 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
884 gFrame->InvalidateAllGL();
889 case ID_RCLK_MENU_EDIT_WP: {
890 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
892 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
894 RouteManagerDialog::WptShowPropertiesDialog(pRP,
this);
900void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
901 wxDataViewEvent& event) {
904 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
905 _(
"Waypoint Properties") + _T(
"..."));
906 wxMenuItem* moveUpItem =
907 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
908 wxMenuItem* moveDownItem =
909 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
910 wxMenuItem* delItem =
911 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
914 editItem->SetFont(*pf);
915 moveUpItem->SetFont(*pf);
916 moveDownItem->SetFont(*pf);
917 delItem->SetFont(*pf);
919#if defined(__WXMSW__)
921 editItem->SetFont(*pf);
922 moveUpItem->SetFont(*pf);
923 moveDownItem->SetFont(*pf);
924 delItem->SetFont(*pf);
927 menu.Append(editItem);
928 if (g_btouch) menu.AppendSeparator();
929 menu.Append(moveUpItem);
930 if (g_btouch) menu.AppendSeparator();
931 menu.Append(moveDownItem);
932 if (g_btouch) menu.AppendSeparator();
933 menu.Append(delItem);
935 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
936 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
937 m_dvlcWaypoints->GetItemCount() > 2);
938 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
939 m_dvlcWaypoints->GetSelectedRow() <
940 m_dvlcWaypoints->GetItemCount() - 1 &&
941 m_dvlcWaypoints->GetItemCount() > 2);
942 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
943 m_dvlcWaypoints->GetItemCount() > 2);
946 wxMenuItem* copyItem =
947 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
949#if defined(__WXMSW__)
951 copyItem->SetFont(*qFont);
954 if (g_btouch) menu.AppendSeparator();
955 menu.Append(copyItem);
961void RoutePropDlgImpl::ResetChanges() {
962 if (!m_pRoute)
return;
968void RoutePropDlgImpl::SaveChanges() {
975 if (m_choiceColor->GetSelection() == 0) {
978 m_pRoute->
m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
981 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
982 m_pRoute->
m_width = ::WidthValues[m_choiceWidth->GetSelection()];
983 switch (m_tz_selection) {
990 case GLOBAL_SETTINGS_INPUT:
998 pConfig->UpdateRoute(m_pRoute);
999 pConfig->UpdateSettings();
1004void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
1006void RoutePropDlgImpl::SaveGeometry() {
1007 GetSize(&g_route_prop_sx, &g_route_prop_sy);
1008 GetPosition(&g_route_prop_x, &g_route_prop_y);
1011void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1013 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1014 pRouteManagerDialog->UpdateRouteListCtrl();
1020void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1021 m_btnSplit->Enable(
false);
1025 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1026 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1027 m_pHead =
new Route();
1028 m_pTail =
new Route();
1029 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1030 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1032 pRouteList->Append(m_pHead);
1033 pConfig->AddNewRoute(m_pHead);
1035 pRouteList->Append(m_pTail);
1036 pConfig->AddNewRoute(m_pTail);
1038 pConfig->DeleteConfigRoute(m_pRoute);
1040 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1041 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1042 g_pRouteMan->
DeleteRoute(m_pRoute, NavObjectChanges::getInstance());
1043 pSelect->AddAllSelectableRouteSegments(m_pTail);
1044 pSelect->AddAllSelectableRoutePoints(m_pTail);
1045 pSelect->AddAllSelectableRouteSegments(m_pHead);
1046 pSelect->AddAllSelectableRoutePoints(m_pHead);
1048 SetRouteAndUpdate(m_pTail);
1051 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1052 pRouteManagerDialog->UpdateRouteListCtrl();
1056void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1057 static std::set<int> s_options;
1059 int result = dlg.ShowModal();
1061 if (result == wxID_OK) {
1062 dlg.GetSelected(s_options);
1065 printer.Initialize(wxPORTRAIT);
1066 printer.EnablePageNumbers(
true);
1067 printer.Print(
this, &printout);
1073void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1074 m_btnExtend->Enable(
false);
1076 if (IsThisRouteExtendable()) {
1077 int fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1078 int to = m_pExtendRoute->GetnPoints();
1080 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1081 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1082 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1083 SetRouteAndUpdate(m_pRoute);
1087 m_btnExtend->Enable(
true);
1090bool RoutePropDlgImpl::IsThisRouteExtendable() {
1091 m_pExtendRoute = NULL;
1092 m_pExtendPoint = NULL;
1096 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1097 wxArrayPtrVoid* pEditRouteArray;
1102 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1103 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1104 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1105 pEditRouteArray->RemoveAt(i - 1);
1107 if (pEditRouteArray->GetCount() == 1) {
1108 m_pExtendPoint = pLastPoint;
1110 if (pEditRouteArray->GetCount() == 0) {
1111 int nearby_radius_meters =
1112 (int)(8. / gFrame->GetPrimaryCanvas()->GetCanvasTrueScale());
1113 double rlat = pLastPoint->m_lat;
1114 double rlon = pLastPoint->m_lon;
1116 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1117 rlat, rlon, nearby_radius_meters, pLastPoint->
m_GUID);
1118 if (m_pExtendPoint) {
1119 wxArrayPtrVoid* pCloseWPRouteArray =
1121 if (pCloseWPRouteArray) {
1122 pEditRouteArray = pCloseWPRouteArray;
1125 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1126 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1127 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1128 pEditRouteArray->RemoveAt(i - 1);
1134 if (pEditRouteArray->GetCount() == 1) {
1136 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1137 int to = p->GetnPoints();
1140 delete pEditRouteArray;
1144 delete pEditRouteArray;
1149wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1150 double lon, wxDateTime utcTime) {
1151 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1153 if (stationName.IsEmpty()) {
1154 return wxEmptyString;
1156 if (!utcTime.IsValid()) {
1157 return _(
"Invalid date/time!");
1159 int stationID = ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1160 if (stationID == 0) {
1161 return _(
"Unknown station!");
1163 time_t dtmtt = utcTime.FromUTC().GetTicks();
1164 int ev = ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1167 dtm.Set(dtmtt).MakeUTC();
1169 wxString tide_form = wxEmptyString;
1172 tide_form.Append(_T(
"LW: "));
1173 }
else if (ev == 2) {
1174 tide_form.Append(_T(
"HW: "));
1175 }
else if (ev == 0) {
1176 tide_form.Append(_(
"Unavailable: "));
1180 ptcmgr->GetStationTimeOffset((
IDX_entry*)ptcmgr->GetIDX_entry(stationID));
1183 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1185 wxString tideDateTime = ocpn::toUsrDateTimeFormat(dtm.FromUTC(), opts);
1186 tide_form.Append(tideDateTime);
1187 dtm.Add(wxTimeSpan(0, offset, 0));
1190 tide_form.Append(wxString::Format(
" (" + _(
"Local") +
": %s%+03d:%02d) @ %s",
1191 dtm.Format(
"%a %x %H:%M:%S"), (offset / 60),
1192 abs(offset) % 60, stationName.c_str()));
1196void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1197 wxString findurl = m_pEditedLink->GetURL();
1198 wxString findlabel = m_pEditedLink->GetLabel();
1201 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1202 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1203 DimeControl(LinkPropDlg);
1204 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1205 findlabel](
int retcode) {
1206 if (retcode == wxID_OK) {
1210 if (NbrOfLinks > 0) {
1211 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1214 wxString Link = link->Link;
1215 wxString Descr = link->DescrText;
1216 if (Link == findurl &&
1217 (Descr == findlabel ||
1218 (Link == findlabel && Descr == wxEmptyString))) {
1219 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1221 LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1222 wxHyperlinkCtrl* h =
1223 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1226 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1227 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1230 linknode = linknode->GetNext();
1234 m_scrolledWindowLinks->InvalidateBestSize();
1235 m_scrolledWindowLinks->Layout();
1236 bSizerLinks->Layout();
1242void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1243 AddLinkOnButtonClick(event);
1247 wxHyperlinkListNode* nodeToDelete = NULL;
1248 wxString findurl = m_pEditedLink->GetURL();
1249 wxString findlabel = m_pEditedLink->GetLabel();
1251 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1252 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
1253 wxWindowListNode* node = kids.Item(i);
1254 wxWindow* win = node->GetData();
1256 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
1258 link_win->Disconnect(
1259 wxEVT_COMMAND_HYPERLINK,
1260 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1261 link_win->Disconnect(
1263 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1272 if (NbrOfLinks > 0) {
1273 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1276 wxString Link = link->Link;
1277 wxString Descr = link->DescrText;
1278 if (Link == findurl &&
1279 (Descr == findlabel || (Link == findlabel && Descr == wxEmptyString)))
1280 nodeToDelete = linknode;
1282 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1283 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1284 wxDefaultSize, wxHL_DEFAULT_STYLE);
1286 wxEVT_COMMAND_HYPERLINK,
1287 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1291 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1294 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1296 linknode = linknode->GetNext();
1300 hyperlinklist->DeleteNode(nodeToDelete);
1302 m_scrolledWindowLinks->InvalidateBestSize();
1303 m_scrolledWindowLinks->Layout();
1304 bSizerLinks->Layout();
1308void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1310 LinkPropDlg->m_textCtrlLinkDescription->SetValue(wxEmptyString);
1311 LinkPropDlg->m_textCtrlLinkUrl->SetValue(wxEmptyString);
1312 DimeControl(LinkPropDlg);
1313 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1314 if (retcode == wxID_OK) {
1315 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1316 if (desc == wxEmptyString)
1317 desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1318 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1319 m_scrolledWindowLinks, wxID_ANY, desc,
1320 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1321 wxDefaultSize, wxHL_DEFAULT_STYLE);
1322 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1323 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1325 ctrl->Connect(wxEVT_RIGHT_DOWN,
1326 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1329 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1330 m_scrolledWindowLinks->InvalidateBestSize();
1331 m_scrolledWindowLinks->Layout();
1332 bSizerLinks->Layout();
1335 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1336 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1337 h->LType = wxEmptyString;
1343void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1344 if (m_toggleBtnEdit->GetValue()) {
1345 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1347 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1352void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1353 if (m_toggleBtnEdit->GetValue()) {
1354 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1355 ItemEditOnMenuSelection(event);
1368 wxString cc =
event.GetURL();
1369 if (cc.Find(_T(
"#")) != wxNOT_FOUND) {
1371 wxString(_T(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command")));
1372 if (RegKey.Exists()) {
1373 wxString command_line;
1374 RegKey.QueryValue(wxString(_T(
"")), command_line);
1377 command_line.Replace(wxString(_T(
"\"")), wxString(_T(
"")));
1380 int l = command_line.Find(_T(
".exe"));
1381 if (wxNOT_FOUND == l) l = command_line.Find(_T(
".EXE"));
1383 if (wxNOT_FOUND != l) {
1384 wxString cl = command_line.Mid(0, l + 4);
1386 cc.Prepend(_T(
"\""));
1387 cc.Append(_T(
"\""));
1395 wxString url =
event.GetURL();
1396 url.Replace(_T(
" "), _T(
"%20"));
1397 ::wxLaunchDefaultBrowser(url);
1401void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1402 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1403 m_scrolledWindowLinks->PopupMenu(
1404 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1405 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, NavObjectChanges *nav_obj_changes)
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.