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 for (
Hyperlink* link : *m_pRoute->m_HyperlinkList) {
545 wxString Link = link->Link;
546 wxString Descr = link->DescrText;
548 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
549 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
550 wxDefaultSize, wxHL_DEFAULT_STYLE);
552 wxEVT_COMMAND_HYPERLINK,
553 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
558 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
561 bSizerLinks->Add(ctrl, 0, wxALL, 5);
563 m_scrolledWindowLinks->InvalidateBestSize();
564 m_scrolledWindowLinks->Layout();
565 bSizerLinks->Layout();
568 m_choiceTimezone->SetSelection(m_tz_selection);
576 m_tcName->SetFocus();
579 wxDateTime t = toUsrDateTime(
585 wxDateTime t = toUsrDateTime(
586 wxDateTime::Now().ToUTC(), m_tz_selection,
593 m_btnSplit->Enable(
false);
594 if (!m_pRoute)
return;
596 if (m_pRoute->
m_Colour == wxEmptyString) {
597 m_choiceColor->Select(0);
599 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
601 if (m_pRoute->
m_Colour == ::GpxxColorNames[i]) {
602 m_choiceColor->Select(i + 1);
608 for (
unsigned int i = 0; i <
sizeof(::StyleValues) /
sizeof(
int); i++) {
609 if (m_pRoute->
m_style == ::StyleValues[i]) {
610 m_choiceStyle->Select(i);
615 for (
unsigned int i = 0; i <
sizeof(::WidthValues) /
sizeof(
int); i++) {
616 if (m_pRoute->
m_width == ::WidthValues[i]) {
617 m_choiceWidth->Select(i);
624 m_btnExtend->Enable(IsThisRouteExtendable());
627void RoutePropDlgImpl::DepartureDateOnDateChanged(wxDateEvent& event) {
628 if (!m_pRoute)
return;
634void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
635 if (!m_pRoute)
return;
641void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
642 if (!m_pRoute)
return;
643 m_tz_selection = m_choiceTimezone->GetSelection();
653void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
654 if (!m_pRoute)
return;
656 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
662 m_tcPlanSpeed->SetValue(
667void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
668 if (!m_pRoute)
return;
670 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
676 m_tcPlanSpeed->SetValue(
683void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
684 wxDataViewEvent& event) {
688 ev_col =
event.GetColumn();
691void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
692 wxDataViewEvent& event) {
693#if wxCHECK_VERSION(3, 1, 2)
695 if (!m_pRoute)
return;
696 wxDataViewModel*
const model =
event.GetModel();
698 model->GetValue(value, event.GetItem(), ev_col);
700 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
701 if (ev_col == COLUMN_PLANNED_SPEED) {
703 if (!value.GetString().ToDouble(&spd)) {
706 p->SetPlannedSpeed(fromUsrSpeed(spd));
707 }
else if (ev_col == COLUMN_ETD) {
708 wxString::const_iterator end;
711 wxString ts = value.GetString();
712 if (ts.StartsWith(
"!")) {
713 ts.Replace(
"!", wxEmptyString,
true);
719 if (!etd.ParseDateTime(ts, &end)) {
720 p->
SetETD(wxInvalidDateTime);
723 fromUsrDateTime(etd, m_tz_selection, p->m_lon).FormatISOCombined());
726 p->
SetETD(wxInvalidDateTime);
733void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
734 wxDataViewEvent& event) {
735 long selected_row = m_dvlcWaypoints->GetSelectedRow();
736 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
737 m_btnSplit->Enable(
true);
739 m_btnSplit->Enable(
false);
741 if (IsThisRouteExtendable()) {
742 m_btnExtend->Enable(
true);
744 m_btnExtend->Enable(
false);
746 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
747 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
749 if (gFrame->GetFocusCanvas()) {
750 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), prp->m_lat, prp->m_lon,
751 gFrame->GetFocusCanvas()->GetVPScale());
754 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
765 return fromUsrDateTime(
771void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
772 wxString tab(
"\t", wxConvUTF8);
773 wxString eol(
"\n", wxConvUTF8);
776 csvString << this->GetTitle() << eol << _(
"Name") << tab
780 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
781 << m_tcPlanSpeed->GetValue() << eol
782 << _(
"Departure Time") +
" (" + _T(ETA_FORMAT_STR) +
")" << tab
784 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
789 noCols = m_dvlcWaypoints->GetColumnCount();
790 noRows = m_dvlcWaypoints->GetItemCount();
792 item.SetMask(wxLIST_MASK_TEXT);
794 for (
int i = 0; i < noCols; i++) {
795 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
796 csvString << col->GetTitle() << tab;
801 for (
int j = 0; j < noRows; j++) {
802 for (
int i = 0; i < noCols; i++) {
803 m_dvlcWaypoints->GetValue(value, j, i);
804 csvString << value.MakeString() << tab;
809 if (wxTheClipboard->Open()) {
810 wxTextDataObject* data =
new wxTextDataObject;
811 data->SetText(csvString);
812 wxTheClipboard->SetData(data);
813 wxTheClipboard->Close();
817void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
819 switch (event.GetId()) {
820 case ID_RCLK_MENU_COPY_TEXT: {
821 OnRoutepropCopyTxtClick(event);
824 case ID_RCLK_MENU_MOVEUP_WP: {
827 case ID_RCLK_MENU_MOVEDOWN_WP: {
829 moveup ? _(
"Are you sure you want to move Up this waypoint?")
830 : _(
"Are you sure you want to move Down this waypoint?");
832 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
833 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
835 if (dlg_return == wxID_YES) {
836 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
838 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
841 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
842 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
847 pSelect->AddAllSelectableRouteSegments(m_pRoute);
848 pSelect->AddAllSelectableRoutePoints(m_pRoute);
851 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
853 m_pRoute->FinalizeForRendering();
854 m_pRoute->UpdateSegmentDistances();
857 gFrame->InvalidateAllGL();
859 m_dvlcWaypoints->SelectRow(nRP);
861 SetRouteAndUpdate(m_pRoute,
true);
865 case ID_RCLK_MENU_DELETE: {
866 int dlg_return = OCPNMessageBox(
867 this, _(
"Are you sure you want to remove this waypoint?"),
868 _(
"OpenCPN Remove Waypoint"),
869 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
871 if (dlg_return == wxID_YES) {
872 int sel = m_dvlcWaypoints->GetSelectedRow();
873 m_dvlcWaypoints->SelectRow(sel);
875 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
877 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
879 g_pRouteMan->RemovePointFromRoute(pRP, m_pRoute, 0);
881 gFrame->InvalidateAllGL();
886 case ID_RCLK_MENU_EDIT_WP: {
887 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
889 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
891 RouteManagerDialog::WptShowPropertiesDialog(pRP,
this);
897void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
898 wxDataViewEvent& event) {
901 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
902 _(
"Waypoint Properties") +
"...");
903 wxMenuItem* moveUpItem =
904 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
905 wxMenuItem* moveDownItem =
906 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
907 wxMenuItem* delItem =
908 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
911 editItem->SetFont(*pf);
912 moveUpItem->SetFont(*pf);
913 moveDownItem->SetFont(*pf);
914 delItem->SetFont(*pf);
916#if defined(__WXMSW__)
918 editItem->SetFont(*pf);
919 moveUpItem->SetFont(*pf);
920 moveDownItem->SetFont(*pf);
921 delItem->SetFont(*pf);
924 menu.Append(editItem);
925 if (g_btouch) menu.AppendSeparator();
926 menu.Append(moveUpItem);
927 if (g_btouch) menu.AppendSeparator();
928 menu.Append(moveDownItem);
929 if (g_btouch) menu.AppendSeparator();
930 menu.Append(delItem);
932 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
933 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
934 m_dvlcWaypoints->GetItemCount() > 2);
935 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
936 m_dvlcWaypoints->GetSelectedRow() <
937 m_dvlcWaypoints->GetItemCount() - 1 &&
938 m_dvlcWaypoints->GetItemCount() > 2);
939 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
940 m_dvlcWaypoints->GetItemCount() > 2);
943 wxMenuItem* copyItem =
944 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
946#if defined(__WXMSW__)
948 copyItem->SetFont(*qFont);
951 if (g_btouch) menu.AppendSeparator();
952 menu.Append(copyItem);
958void RoutePropDlgImpl::ResetChanges() {
959 if (!m_pRoute)
return;
965void RoutePropDlgImpl::SaveChanges() {
972 if (m_choiceColor->GetSelection() == 0) {
975 m_pRoute->
m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
978 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
979 m_pRoute->
m_width = ::WidthValues[m_choiceWidth->GetSelection()];
980 switch (m_tz_selection) {
987 case GLOBAL_SETTINGS_INPUT:
996 NavObj_dB::GetInstance().UpdateRoute(m_pRoute);
997 pConfig->UpdateSettings();
1002void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
1004void RoutePropDlgImpl::SaveGeometry() {
1005 GetSize(&g_route_prop_sx, &g_route_prop_sy);
1006 GetPosition(&g_route_prop_x, &g_route_prop_y);
1009void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1011 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1012 pRouteManagerDialog->UpdateRouteListCtrl();
1018void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1019 m_btnSplit->Enable(
false);
1023 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1024 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1025 m_pHead =
new Route();
1026 m_pTail =
new Route();
1027 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1028 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1030 pRouteList->Append(m_pHead);
1032 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1034 pRouteList->Append(m_pTail);
1036 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1039 NavObj_dB::GetInstance().DeleteRoute(m_pRoute);
1041 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1042 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1044 pSelect->AddAllSelectableRouteSegments(m_pTail);
1045 pSelect->AddAllSelectableRoutePoints(m_pTail);
1046 pSelect->AddAllSelectableRouteSegments(m_pHead);
1047 pSelect->AddAllSelectableRoutePoints(m_pHead);
1049 SetRouteAndUpdate(m_pTail);
1052 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1053 pRouteManagerDialog->UpdateRouteListCtrl();
1057void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1058 static std::set<int> s_options;
1060 int result = dlg.ShowModal();
1062 if (result == wxID_OK) {
1063 dlg.GetSelected(s_options);
1064 RoutePrintout printout(m_pRoute, s_options, m_tz_selection);
1066 printer.Initialize(wxPORTRAIT);
1067 printer.EnablePageNumbers(
true);
1068 printer.Print(
this, &printout);
1074void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1075 m_btnExtend->Enable(
false);
1077 if (IsThisRouteExtendable()) {
1078 int fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1079 int to = m_pExtendRoute->GetnPoints();
1081 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1082 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1083 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1084 SetRouteAndUpdate(m_pRoute);
1088 m_btnExtend->Enable(
true);
1091bool RoutePropDlgImpl::IsThisRouteExtendable() {
1092 m_pExtendRoute = NULL;
1093 m_pExtendPoint = NULL;
1097 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1098 wxArrayPtrVoid* pEditRouteArray;
1103 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1104 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1105 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1106 pEditRouteArray->RemoveAt(i - 1);
1108 if (pEditRouteArray->GetCount() == 1) {
1109 m_pExtendPoint = pLastPoint;
1111 if (pEditRouteArray->GetCount() == 0) {
1112 int nearby_radius_meters =
1113 (int)(8. / gFrame->GetPrimaryCanvas()->GetCanvasTrueScale());
1114 double rlat = pLastPoint->m_lat;
1115 double rlon = pLastPoint->m_lon;
1117 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1118 rlat, rlon, nearby_radius_meters, pLastPoint->
m_GUID);
1119 if (m_pExtendPoint) {
1120 wxArrayPtrVoid* pCloseWPRouteArray =
1122 if (pCloseWPRouteArray) {
1123 pEditRouteArray = pCloseWPRouteArray;
1126 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1127 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1128 if (!p->IsVisible() || (p->
m_GUID == m_pRoute->
m_GUID))
1129 pEditRouteArray->RemoveAt(i - 1);
1135 if (pEditRouteArray->GetCount() == 1) {
1137 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1138 int to = p->GetnPoints();
1141 delete pEditRouteArray;
1145 delete pEditRouteArray;
1150wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1151 double lon, wxDateTime utcTime) {
1152 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1154 if (stationName.IsEmpty()) {
1155 return wxEmptyString;
1157 if (!utcTime.IsValid()) {
1158 return _(
"Invalid date/time!");
1160 int stationID = ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1161 if (stationID == 0) {
1162 return _(
"Unknown station!");
1164 time_t dtmtt = utcTime.FromUTC().GetTicks();
1165 int ev = ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1168 dtm.Set(dtmtt).MakeUTC();
1170 wxString tide_form = wxEmptyString;
1173 tide_form.Append(
"LW: ");
1174 }
else if (ev == 2) {
1175 tide_form.Append(
"HW: ");
1176 }
else if (ev == 0) {
1177 tide_form.Append(_(
"Unavailable: "));
1181 ptcmgr->GetStationTimeOffset((
IDX_entry*)ptcmgr->GetIDX_entry(stationID));
1184 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1186 wxString tideDateTime = ocpn::toUsrDateTimeFormat(dtm.FromUTC(), opts);
1187 tide_form.Append(tideDateTime);
1188 dtm.Add(wxTimeSpan(0, offset, 0));
1191 tide_form.Append(wxString::Format(
" (" + _(
"Local") +
": %s%+03d:%02d) @ %s",
1192 dtm.Format(
"%a %x %H:%M:%S"), (offset / 60),
1193 abs(offset) % 60, stationName.c_str()));
1197void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1198 wxString findurl = m_pEditedLink->GetURL();
1199 wxString findlabel = m_pEditedLink->GetLabel();
1202 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1203 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1204 DimeControl(LinkPropDlg);
1205 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1206 findlabel](
int retcode) {
1207 if (retcode == wxID_OK) {
1208 for (
Hyperlink* link : *m_pRoute->m_HyperlinkList) {
1209 wxString Link = link->Link;
1210 wxString Descr = link->DescrText;
1211 if (Link == findurl &&
1212 (Descr == findlabel ||
1213 (Link == findlabel && Descr == wxEmptyString))) {
1214 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1215 link->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1216 wxHyperlinkCtrl* h =
1217 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1220 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1221 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1226 m_scrolledWindowLinks->InvalidateBestSize();
1227 m_scrolledWindowLinks->Layout();
1228 bSizerLinks->Layout();
1234void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1235 AddLinkOnButtonClick(event);
1239 wxString findurl = m_pEditedLink->GetURL();
1240 wxString findlabel = m_pEditedLink->GetLabel();
1242 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
1243 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
1244 wxWindowListNode* node = kids.Item(i);
1245 wxWindow* win = node->GetData();
1247 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
1249 link_win->Disconnect(
1250 wxEVT_COMMAND_HYPERLINK,
1251 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
1252 link_win->Disconnect(
1254 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
1263 auto nodeToDelete = hyperlinklist->end();
1264 if (NbrOfLinks > 0) {
1265 auto it = hyperlinklist->begin();
1266 while (it != hyperlinklist->end()) {
1268 wxString Link = link->Link;
1269 wxString Descr = link->DescrText;
1270 if (Link == findurl &&
1271 (Descr == findlabel || (Link == findlabel && Descr == wxEmptyString)))
1274 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1275 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1276 wxDefaultSize, wxHL_DEFAULT_STYLE);
1278 wxEVT_COMMAND_HYPERLINK,
1279 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1283 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1286 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1291 if (nodeToDelete != hyperlinklist->end()) {
1292 hyperlinklist->erase(nodeToDelete);
1294 m_scrolledWindowLinks->InvalidateBestSize();
1295 m_scrolledWindowLinks->Layout();
1296 bSizerLinks->Layout();
1300void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1302 LinkPropDlg->m_textCtrlLinkDescription->SetValue(wxEmptyString);
1303 LinkPropDlg->m_textCtrlLinkUrl->SetValue(wxEmptyString);
1304 DimeControl(LinkPropDlg);
1305 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1306 if (retcode == wxID_OK) {
1307 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1308 if (desc == wxEmptyString)
1309 desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1310 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1311 m_scrolledWindowLinks, wxID_ANY, desc,
1312 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1313 wxDefaultSize, wxHL_DEFAULT_STYLE);
1314 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1315 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1317 ctrl->Connect(wxEVT_RIGHT_DOWN,
1318 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1321 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1322 m_scrolledWindowLinks->InvalidateBestSize();
1323 m_scrolledWindowLinks->Layout();
1324 bSizerLinks->Layout();
1327 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1328 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1329 h->LType = wxEmptyString;
1335void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1336 if (m_toggleBtnEdit->GetValue()) {
1337 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1339 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1344void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1345 if (m_toggleBtnEdit->GetValue()) {
1346 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1347 ItemEditOnMenuSelection(event);
1360 wxString cc =
event.GetURL();
1361 if (cc.Find(
"#") != wxNOT_FOUND) {
1362 wxRegKey RegKey(wxString(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command"));
1363 if (RegKey.Exists()) {
1364 wxString command_line;
1365 RegKey.QueryValue(wxString(
""), command_line);
1368 command_line.Replace(wxString(
"\""), wxString(
""));
1371 int l = command_line.Find(
".exe");
1372 if (wxNOT_FOUND == l) l = command_line.Find(
".EXE");
1374 if (wxNOT_FOUND != l) {
1375 wxString cl = command_line.Mid(0, l + 4);
1386 wxString url =
event.GetURL();
1387 url.Replace(
" ",
"%20");
1388 ::wxLaunchDefaultBrowser(url);
1392void RoutePropDlgImpl::HyperlinkContextMenu(wxMouseEvent& event) {
1393 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1394 m_scrolledWindowLinks->PopupMenu(
1395 m_menuLink, m_pEditedLink->GetPosition().x +
event.GetPosition().x,
1396 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.