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 "routemanagerdialog.h"
38#include "routeprintout.h"
39#include "RoutePropDlgImpl.h"
47#define GLOBAL_SETTINGS_INPUT 3
49#define ID_RCLK_MENU_COPY_TEXT 7013
50#define ID_RCLK_MENU_EDIT_WP 7014
51#define ID_RCLK_MENU_DELETE 7015
52#define ID_RCLK_MENU_MOVEUP_WP 7026
53#define ID_RCLK_MENU_MOVEDOWN_WP 7027
55#define COLUMN_PLANNED_SPEED 9
58extern wxString GetLayerName(
int id);
62extern ColorScheme global_color_scheme;
63extern RouteList* pRouteList;
68int g_route_prop_x, g_route_prop_y, g_route_prop_sx, g_route_prop_sy;
77#define PI (4. * atan(1.0))
80#define DEGS (180. / PI)
81#define RADS (PI / 180.)
91static wxString GetDaylightString(
int index) {
96 return _(
"MoTwilight");
104 return _(
"EvTwilight");
106 return _(
"Nighttime");
113static double sign(
double x) {
120static double FNipart(
double x) {
return (sign(x) * (
int)(fabs(x))); }
122static double FNday(
int y,
int m,
int d,
int h) {
123 long fd = (367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d);
124 return ((
double)fd - 730531.5 + h / 24.);
127static double FNrange(
double x) {
129 double a = TPI * (b - FNipart(b));
130 if (a < 0.) a = TPI + a;
134static double getDaylightEvent(
double glat,
double glong,
int riset,
135 double altitude,
int y,
int m,
int d) {
136 double day = FNday(y, m, d, 0);
137 double days, correction;
141 sin(altitude * RADS);
142 double sinphi = sin(glat * RADS);
143 double cosphi = cos(glat * RADS);
144 double g = glong * RADS;
145 double t, L, G, ec, lambda, E, obl, delta, GHA, cosc;
147 while ((fabs(utold - utnew) > .001)) {
148 if (limit-- <= 0)
return (-1.);
149 days = day + utnew / TPI;
152 L = FNrange(4.8949504201433 + 628.331969753199 * t);
153 G = FNrange(6.2400408 + 628.3019501 * t);
154 ec = .033423 * sin(G) + .00034907 * sin(2 * G);
156 E = -1. * ec + .0430398 * sin(2 * lambda) - .00092502 * sin(4. * lambda);
157 obl = .409093 - .0002269 * t;
158 delta = asin(sin(obl) * sin(lambda));
159 GHA = utold - PI + E;
160 cosc = (sinalt - sinphi * sin(delta)) / (cosphi * cos(delta));
166 correction = acos(cosc);
168 utnew = FNrange(utold - (GHA + g + riset * correction));
171 return (utnew * DEGS / 15.);
174static double getLMT(
double ut,
double lon) {
175 double t = ut + lon / 15.;
188static wxString getDatetimeTimezoneSelector(
int selection) {
196 case GLOBAL_SETTINGS_INPUT:
198 return wxEmptyString;
202static int getDaylightStatus(
double lat,
double lon, wxDateTime utcDateTime) {
203 if (fabs(lat) > 60.)
return (0);
204 int y = utcDateTime.GetYear();
205 int m = utcDateTime.GetMonth() + 1;
206 int d = utcDateTime.GetDay();
207 int h = utcDateTime.GetHour();
208 int n = utcDateTime.GetMinute();
209 int s = utcDateTime.GetSecond();
210 if (y < 2000 || y > 2100)
return (0);
212 double ut = (double)h + (
double)n / 60. + (double)s / 3600.;
213 double lt = getLMT(ut, lon);
214 double rsalt = -0.833;
218 double sunrise = getDaylightEvent(lat, lon, +1, rsalt, y, m, d);
222 sunrise = getLMT(sunrise, lon);
224 if (fabs(lt - sunrise) < 0.15)
return (SUNRISE);
225 if (lt > sunrise)
return (DAY);
226 double twilight = getDaylightEvent(lat, lon, +1, twalt, y, m, d);
230 twilight = getLMT(twilight, lon);
236 double sunset = getDaylightEvent(lat, lon, -1, rsalt, y, m, d);
240 sunset = getLMT(sunset, lon);
241 if (fabs(lt - sunset) < 0.15)
return (SUNSET);
242 if (lt < sunset)
return (DAY);
243 double twilight = getDaylightEvent(lat, lon, -1, twalt, y, m, d);
247 twilight = getLMT(twilight, lon);
255RoutePropDlgImpl::RoutePropDlgImpl(wxWindow* parent, wxWindowID
id,
256 const wxString& title,
const wxPoint& pos,
257 const wxSize& size,
long style)
261 SetColorScheme(global_color_scheme);
263 if (g_route_prop_sx > 0 && g_route_prop_sy > 0 &&
264 g_route_prop_sx < wxGetDisplaySize().x &&
265 g_route_prop_sy < wxGetDisplaySize().y) {
266 SetSize(g_route_prop_sx, g_route_prop_sy);
269 if (g_route_prop_x > 0 && g_route_prop_y > 0 &&
270 g_route_prop_x < wxGetDisplaySize().x &&
271 g_route_prop_y < wxGetDisplaySize().y) {
272 SetPosition(wxPoint(10, 10));
276 Connect(wxEVT_COMMAND_MENU_SELECTED,
277 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
281 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(RoutePropDlgImpl::OnActivate),
286RoutePropDlgImpl::~RoutePropDlgImpl() {
287 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
288 wxCommandEventHandler(RoutePropDlgImpl::OnRoutePropMenuSelected),
290 instanceFlag =
false;
293bool RoutePropDlgImpl::instanceFlag =
false;
294bool RoutePropDlgImpl::getInstanceFlag() {
295 return RoutePropDlgImpl::instanceFlag;
307void RoutePropDlgImpl::OnActivate(wxActivateEvent& event) {
308 auto pWin =
dynamic_cast<wxFrame*
>(
event.GetEventObject());
309 long int style = pWin->GetWindowStyle();
310 if (event.GetActive())
311 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
313 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
316void RoutePropDlgImpl::RecalculateSize(
void) {
318 esize.x = GetCharWidth() * 110;
319 esize.y = GetCharHeight() * 40;
321 wxSize dsize = GetParent()->GetSize();
322 esize.y = wxMin(esize.y, dsize.y - 0 );
323 esize.x = wxMin(esize.x, dsize.x - 0 );
326 wxSize fsize = GetSize();
327 wxSize canvas_size = GetParent()->GetSize();
328 wxPoint screen_pos = GetParent()->GetScreenPosition();
329 int xp = (canvas_size.x - fsize.x) / 2;
330 int yp = (canvas_size.y - fsize.y) / 2;
331 Move(screen_pos.x + xp, screen_pos.y + yp);
334void RoutePropDlgImpl::UpdatePoints() {
335 if (!m_pRoute)
return;
336 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
337 int selected_row = m_dvlcWaypoints->GetSelectedRow();
338 m_dvlcWaypoints->DeleteAllItems();
340 wxVector<wxVariant> data;
342 m_pRoute->UpdateSegmentDistances(
343 m_pRoute->m_PlannedSpeed);
344 m_tcDistance->SetValue(
345 wxString::Format(wxT(
"%5.1f ") + getUsrDistanceUnit(),
346 toUsrDistance(m_pRoute->m_route_length)));
347 m_tcEnroute->SetValue(formatTimeDelta(wxLongLong(m_pRoute->m_route_time)));
349 wxRoutePointListNode* pnode = m_pRoute->pRoutePointList->GetFirst();
351 wxString slen, eta, ete;
352 double bearing, distance, speed;
353 double totalDistance = 0;
354 wxDateTime eta_dt = wxInvalidDateTime;
356 speed = pnode->GetData()->GetPlannedSpeed();
358 speed = m_pRoute->m_PlannedSpeed;
361 DistanceBearingMercator(pnode->GetData()->GetLatitude(),
362 pnode->GetData()->GetLongitude(), gLat, gLon,
363 &bearing, &distance);
364 if (m_pRoute->m_PlannedDeparture.IsValid()) {
367 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
369 eta = wxString::Format(
371 ocpn::toUsrDateTimeFormat(m_pRoute->m_PlannedDeparture, opts));
372 eta.Append(wxString::Format(
374 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
375 pnode->GetData()->m_lon,
376 m_pRoute->m_PlannedDeparture))
378 eta_dt = m_pRoute->m_PlannedDeparture;
383 ete = formatTimeDelta(wxLongLong(3600. * distance / speed));
388 distance = pnode->GetData()->GetDistance();
389 bearing = pnode->GetData()->GetCourse();
390 if (pnode->GetData()->GetETA().IsValid()) {
393 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
395 eta = ocpn::toUsrDateTimeFormat(pnode->GetData()->GetETA(), opts);
396 eta.Append(wxString::Format(
398 GetDaylightString(getDaylightStatus(pnode->GetData()->m_lat,
399 pnode->GetData()->m_lon,
400 pnode->GetData()->GetETA()))
402 eta_dt = pnode->GetData()->GetETA();
406 ete = pnode->GetData()->GetETE();
407 totalDistance += distance;
409 wxString name = pnode->GetData()->GetName();
410 double lat = pnode->GetData()->GetLatitude();
411 double lon = pnode->GetData()->GetLongitude();
412 wxString tide_station = pnode->GetData()->m_TideStation;
413 wxString desc = pnode->GetData()->GetDescription();
415 if (pnode->GetData()->GetManualETD().IsValid()) {
419 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
421 etd = ocpn::toUsrDateTimeFormat(pnode->GetData()->GetManualETD(), opts);
422 if (pnode->GetData()->GetManualETD().IsValid() &&
423 pnode->GetData()->GetETA().IsValid() &&
424 pnode->GetData()->GetManualETD() < pnode->GetData()->GetETA()) {
431 pnode = pnode->GetNext();
434 crs = formatAngle(pnode->GetData()->GetCourse());
440 data.push_back(wxVariant(
"---"));
442 std::ostringstream stm;
444 data.push_back(wxVariant(stm.str()));
447 wxString schar = wxEmptyString;
449 schar = wxString(
" ");
451 data.push_back(wxVariant(name + schar));
452 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(), toUsrDistance(distance));
453 data.push_back(wxVariant(schar + slen + schar));
454 data.push_back(wxVariant(schar + formatAngle(bearing)));
455 slen.Printf(wxT(
"%5.1f ") + getUsrDistanceUnit(),
456 toUsrDistance(totalDistance));
457 data.push_back(wxVariant(schar + slen + schar));
458 data.push_back(wxVariant(schar + ::toSDMM(1, lat, FALSE) + schar));
459 data.push_back(wxVariant(schar + ::toSDMM(2, lon, FALSE) + schar));
460 data.push_back(wxVariant(schar + ete + schar));
461 data.push_back(schar + eta + schar);
463 wxVariant(wxString::FromDouble(toUsrSpeed(speed))));
464 data.push_back(wxVariant(
465 MakeTideInfo(tide_station, lat, lon, eta_dt)));
466 data.push_back(wxVariant(desc));
467 data.push_back(wxVariant(crs));
468 data.push_back(wxVariant(etd));
469 data.push_back(wxVariant(
472 m_dvlcWaypoints->AppendItem(data);
476 if (selected_row > 0) {
477 m_dvlcWaypoints->SelectRow(selected_row);
478 m_dvlcWaypoints->EnsureVisible(selection);
482void RoutePropDlgImpl::SetRouteAndUpdate(
Route* pR,
bool only_points) {
483 if (NULL == pR)
return;
489 m_OrigRoute.m_PlannedDeparture = pR->m_PlannedDeparture;
490 m_OrigRoute.m_PlannedSpeed = pR->m_PlannedSpeed;
493 pR->GetName() == wxEmptyString ? _(
"Route Properties") : pR->GetName();
494 if (!pR->m_bIsInLayer)
497 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title, _(
"Layer"),
498 GetLayerName(pR->m_LayerID)));
504 if (!pR->m_PlannedDeparture.IsValid())
505 pR->m_PlannedDeparture = wxDateTime::Now().ToUTC();
507 m_tz_selection = GLOBAL_SETTINGS_INPUT;
508 if (pR != m_pRoute) {
509 if (pR->m_TimeDisplayFormat == RTE_TIME_DISP_UTC)
510 m_tz_selection = UTCINPUT;
511 else if (pR->m_TimeDisplayFormat == RTE_TIME_DISP_LOCAL)
512 m_tz_selection = LMTINPUT;
513 m_pEnroutePoint = NULL;
519 m_tcPlanSpeed->SetValue(
520 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
522 if (m_scrolledWindowLinks) {
523 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
524 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
525 wxWindowListNode* node = kids.Item(i);
526 wxWindow* win = node->GetData();
527 auto link_win =
dynamic_cast<wxHyperlinkCtrl*
>(win);
529 link_win->Disconnect(
530 wxEVT_COMMAND_HYPERLINK,
531 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick));
532 link_win->Disconnect(
534 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu));
538 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
539 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
540 if (NbrOfLinks > 0) {
541 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
544 wxString Link = link->Link;
545 wxString Descr = link->DescrText;
547 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
548 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
549 wxDefaultSize, wxHL_DEFAULT_STYLE);
551 wxEVT_COMMAND_HYPERLINK,
552 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
554 if (!m_pRoute->m_bIsInLayer) {
557 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
560 bSizerLinks->Add(ctrl, 0, wxALL, 5);
562 linknode = linknode->GetNext();
565 m_scrolledWindowLinks->InvalidateBestSize();
566 m_scrolledWindowLinks->Layout();
567 bSizerLinks->Layout();
570 m_choiceTimezone->SetSelection(m_tz_selection);
573 m_tcName->SetValue(m_pRoute->m_RouteNameString);
574 m_tcFrom->SetValue(m_pRoute->m_RouteStartString);
575 m_tcTo->SetValue(m_pRoute->m_RouteEndString);
576 m_tcDescription->SetValue(m_pRoute->m_RouteDescription);
578 m_tcName->SetFocus();
579 if (m_pRoute->m_PlannedDeparture.IsValid() &&
580 m_pRoute->m_PlannedDeparture.GetValue() > 0) {
581 m_dpDepartureDate->SetValue(
582 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
583 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
585 m_tpDepartureTime->SetValue(toUsrDateTime(
586 m_pRoute->m_PlannedDeparture, m_tz_selection,
587 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
589 m_dpDepartureDate->SetValue(
590 toUsrDateTime(wxDateTime::Now(), m_tz_selection,
591 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
593 m_tpDepartureTime->SetValue(toUsrDateTime(
594 wxDateTime::Now(), m_tz_selection,
595 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
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;
635 m_pRoute->SetDepartureDate(GetDepartureTS());
640void RoutePropDlgImpl::DepartureTimeOnTimeChanged(wxDateEvent& event) {
641 if (!m_pRoute)
return;
642 m_pRoute->SetDepartureDate(GetDepartureTS());
647void RoutePropDlgImpl::TimezoneOnChoice(wxCommandEvent& event) {
648 m_tz_selection = m_choiceTimezone->GetSelection();
649 m_dpDepartureDate->SetValue(
650 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
651 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon)
653 m_tpDepartureTime->SetValue(
654 toUsrDateTime(m_pRoute->m_PlannedDeparture, m_tz_selection,
655 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon));
660void RoutePropDlgImpl::PlanSpeedOnTextEnter(wxCommandEvent& event) {
661 if (!m_pRoute)
return;
663 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
664 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
665 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
669 m_tcPlanSpeed->SetValue(
670 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
674void RoutePropDlgImpl::PlanSpeedOnKillFocus(wxFocusEvent& event) {
675 if (!m_pRoute)
return;
677 if (m_tcPlanSpeed->GetValue().ToDouble(&spd)) {
678 if (m_pRoute->m_PlannedSpeed != fromUsrSpeed(spd)) {
679 m_pRoute->m_PlannedSpeed = fromUsrSpeed(spd);
683 m_tcPlanSpeed->SetValue(
684 wxString::FromDouble(toUsrSpeed(m_pRoute->m_PlannedSpeed)));
690void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemEditingDone(
691 wxDataViewEvent& event) {
695 ev_col =
event.GetColumn();
698void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemValueChanged(
699 wxDataViewEvent& event) {
700#if wxCHECK_VERSION(3, 1, 2)
702 if (!m_pRoute)
return;
703 wxDataViewModel*
const model =
event.GetModel();
705 model->GetValue(value, event.GetItem(), ev_col);
707 static_cast<int>(
reinterpret_cast<long long>(event.GetItem().GetID())));
708 if (ev_col == COLUMN_PLANNED_SPEED) {
710 if (!value.GetString().ToDouble(&spd)) {
713 p->SetPlannedSpeed(fromUsrSpeed(spd));
714 }
else if (ev_col == COLUMN_ETD) {
715 wxString::const_iterator end;
718 wxString ts = value.GetString();
719 if (ts.StartsWith(
"!")) {
720 ts.Replace(
"!", wxEmptyString,
true);
726 if (!etd.ParseDateTime(ts, &end)) {
727 p->SetETD(wxInvalidDateTime);
730 fromUsrDateTime(etd, m_tz_selection, p->m_lon).FormatISOCombined());
733 p->SetETD(wxInvalidDateTime);
740void RoutePropDlgImpl::WaypointsOnDataViewListCtrlSelectionChanged(
741 wxDataViewEvent& event) {
742 long selected_row = m_dvlcWaypoints->GetSelectedRow();
743 if (selected_row > 0 && selected_row < m_dvlcWaypoints->GetItemCount() - 1) {
744 m_btnSplit->Enable(
true);
746 m_btnSplit->Enable(
false);
748 if (IsThisRouteExtendable()) {
749 m_btnExtend->Enable(
true);
751 m_btnExtend->Enable(
false);
753 if (selected_row >= 0 && selected_row < m_dvlcWaypoints->GetItemCount()) {
754 RoutePoint* prp = m_pRoute->GetPoint(selected_row + 1);
756 if (gFrame->GetFocusCanvas()) {
757 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), prp->m_lat, prp->m_lon,
758 gFrame->GetFocusCanvas()->GetVPScale());
761 if (m_dvlcWaypoints) m_dvlcWaypoints->SetFocus();
767wxDateTime RoutePropDlgImpl::GetDepartureTS() {
768 wxDateTime dt = m_dpDepartureDate->GetValue();
769 dt.SetHour(m_tpDepartureTime->GetValue().GetHour());
770 dt.SetMinute(m_tpDepartureTime->GetValue().GetMinute());
771 dt.SetSecond(m_tpDepartureTime->GetValue().GetSecond());
772 return fromUsrDateTime(
774 m_pRoute->pRoutePointList->GetFirst()->GetData()->m_lon);
778void RoutePropDlgImpl::OnRoutepropCopyTxtClick(wxCommandEvent& event) {
779 wxString tab(
"\t", wxConvUTF8);
780 wxString eol(
"\n", wxConvUTF8);
783 csvString << this->GetTitle() << eol << _(
"Name") << tab
784 << m_pRoute->m_RouteNameString << eol << _(
"Depart From") << tab
785 << m_pRoute->m_RouteStartString << eol << _(
"Destination") << tab
786 << m_pRoute->m_RouteEndString << eol << _(
"Total distance") << tab
787 << m_tcDistance->GetValue() << eol << _(
"Speed (Kts)") << tab
788 << m_tcPlanSpeed->GetValue() << eol
789 << _(
"Departure Time") + _T(
" (") + _T(ETA_FORMAT_STR) + _T(
")")
790 << tab << GetDepartureTS().Format(ETA_FORMAT_STR) << eol
791 << _(
"Time enroute") << tab << m_tcEnroute->GetValue() << eol
796 noCols = m_dvlcWaypoints->GetColumnCount();
797 noRows = m_dvlcWaypoints->GetItemCount();
799 item.SetMask(wxLIST_MASK_TEXT);
801 for (
int i = 0; i < noCols; i++) {
802 wxDataViewColumn* col = m_dvlcWaypoints->GetColumn(i);
803 csvString << col->GetTitle() << tab;
808 for (
int j = 0; j < noRows; j++) {
809 for (
int i = 0; i < noCols; i++) {
810 m_dvlcWaypoints->GetValue(value, j, i);
811 csvString << value.MakeString() << tab;
816 if (wxTheClipboard->Open()) {
817 wxTextDataObject* data =
new wxTextDataObject;
818 data->SetText(csvString);
819 wxTheClipboard->SetData(data);
820 wxTheClipboard->Close();
824void RoutePropDlgImpl::OnRoutePropMenuSelected(wxCommandEvent& event) {
826 switch (event.GetId()) {
827 case ID_RCLK_MENU_COPY_TEXT: {
828 OnRoutepropCopyTxtClick(event);
831 case ID_RCLK_MENU_MOVEUP_WP: {
834 case ID_RCLK_MENU_MOVEDOWN_WP: {
836 moveup ? _(
"Are you sure you want to move Up this waypoint?")
837 : _(
"Are you sure you want to move Down this waypoint?");
839 OCPNMessageBox(
this, mess, _(
"OpenCPN Move Waypoint"),
840 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
842 if (dlg_return == wxID_YES) {
843 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
845 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
846 int nRP = m_pRoute->pRoutePointList->IndexOf(pRP) + (moveup ? -1 : 1);
848 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
849 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
851 m_pRoute->pRoutePointList->DeleteObject(pRP);
852 m_pRoute->pRoutePointList->Insert(nRP, pRP);
854 pSelect->AddAllSelectableRouteSegments(m_pRoute);
855 pSelect->AddAllSelectableRoutePoints(m_pRoute);
857 pConfig->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);
886 gFrame->InvalidateAllGL();
891 case ID_RCLK_MENU_EDIT_WP: {
892 wxDataViewItem selection = m_dvlcWaypoints->GetSelection();
894 static_cast<int>(
reinterpret_cast<long long>(selection.GetID())));
896 RouteManagerDialog::WptShowPropertiesDialog(pRP,
this);
902void RoutePropDlgImpl::WaypointsOnDataViewListCtrlItemContextMenu(
903 wxDataViewEvent& event) {
905 if (!m_pRoute->m_bIsInLayer) {
906 wxMenuItem* editItem =
new wxMenuItem(&menu, ID_RCLK_MENU_EDIT_WP,
907 _(
"Waypoint Properties") + _T(
"..."));
908 wxMenuItem* moveUpItem =
909 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEUP_WP, _(
"Move Up"));
910 wxMenuItem* moveDownItem =
911 new wxMenuItem(&menu, ID_RCLK_MENU_MOVEDOWN_WP, _(
"Move Down"));
912 wxMenuItem* delItem =
913 new wxMenuItem(&menu, ID_RCLK_MENU_DELETE, _(
"Remove Selected"));
916 editItem->SetFont(*pf);
917 moveUpItem->SetFont(*pf);
918 moveDownItem->SetFont(*pf);
919 delItem->SetFont(*pf);
921#if defined(__WXMSW__)
923 editItem->SetFont(*pf);
924 moveUpItem->SetFont(*pf);
925 moveDownItem->SetFont(*pf);
926 delItem->SetFont(*pf);
929 menu.Append(editItem);
930 if (g_btouch) menu.AppendSeparator();
931 menu.Append(moveUpItem);
932 if (g_btouch) menu.AppendSeparator();
933 menu.Append(moveDownItem);
934 if (g_btouch) menu.AppendSeparator();
935 menu.Append(delItem);
937 editItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0);
938 moveUpItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 1 &&
939 m_dvlcWaypoints->GetItemCount() > 2);
940 moveDownItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
941 m_dvlcWaypoints->GetSelectedRow() <
942 m_dvlcWaypoints->GetItemCount() - 1 &&
943 m_dvlcWaypoints->GetItemCount() > 2);
944 delItem->Enable(m_dvlcWaypoints->GetSelectedRow() >= 0 &&
945 m_dvlcWaypoints->GetItemCount() > 2);
948 wxMenuItem* copyItem =
949 new wxMenuItem(&menu, ID_RCLK_MENU_COPY_TEXT, _(
"&Copy all as text"));
951#if defined(__WXMSW__)
953 copyItem->SetFont(*qFont);
956 if (g_btouch) menu.AppendSeparator();
957 menu.Append(copyItem);
963void RoutePropDlgImpl::ResetChanges() {
964 if (!m_pRoute)
return;
965 m_pRoute->m_PlannedSpeed = m_OrigRoute.m_PlannedSpeed;
966 m_pRoute->m_PlannedDeparture = m_OrigRoute.m_PlannedDeparture;
970void RoutePropDlgImpl::SaveChanges() {
971 if (m_pRoute && !m_pRoute->m_bIsInLayer) {
973 m_pRoute->m_RouteNameString = m_tcName->GetValue();
974 m_pRoute->m_RouteStartString = m_tcFrom->GetValue();
975 m_pRoute->m_RouteEndString = m_tcTo->GetValue();
976 m_pRoute->m_RouteDescription = m_tcDescription->GetValue();
977 if (m_choiceColor->GetSelection() == 0) {
978 m_pRoute->m_Colour = wxEmptyString;
980 m_pRoute->m_Colour = ::GpxxColorNames[m_choiceColor->GetSelection() - 1];
983 (wxPenStyle)::StyleValues[m_choiceStyle->GetSelection()];
984 m_pRoute->m_width = ::WidthValues[m_choiceWidth->GetSelection()];
985 switch (m_tz_selection) {
987 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_PC;
990 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_LOCAL;
992 case GLOBAL_SETTINGS_INPUT:
993 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_GLOBAL;
997 m_pRoute->m_TimeDisplayFormat = RTE_TIME_DISP_UTC;
1000 pConfig->UpdateRoute(m_pRoute);
1001 pConfig->UpdateSettings();
1006void RoutePropDlgImpl::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
1008void RoutePropDlgImpl::SaveGeometry() {
1009 GetSize(&g_route_prop_sx, &g_route_prop_sy);
1010 GetPosition(&g_route_prop_x, &g_route_prop_y);
1013void RoutePropDlgImpl::BtnsOnOKButtonClick(wxCommandEvent& event) {
1015 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1016 pRouteManagerDialog->UpdateRouteListCtrl();
1022void RoutePropDlgImpl::SplitOnButtonClick(wxCommandEvent& event) {
1023 m_btnSplit->Enable(
false);
1025 if (m_pRoute->m_bIsInLayer)
return;
1027 int nSelected = m_dvlcWaypoints->GetSelectedRow() + 1;
1028 if ((nSelected > 1) && (nSelected < m_pRoute->GetnPoints())) {
1029 m_pHead =
new Route();
1030 m_pTail =
new Route();
1031 m_pHead->CloneRoute(m_pRoute, 1, nSelected, _(
"_A"));
1032 m_pTail->CloneRoute(m_pRoute, nSelected, m_pRoute->GetnPoints(), _(
"_B"),
1034 pRouteList->Append(m_pHead);
1035 pConfig->AddNewRoute(m_pHead);
1037 pRouteList->Append(m_pTail);
1038 pConfig->AddNewRoute(m_pTail);
1040 pConfig->DeleteConfigRoute(m_pRoute);
1042 pSelect->DeleteAllSelectableRoutePoints(m_pRoute);
1043 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1044 g_pRouteMan->
DeleteRoute(m_pRoute, NavObjectChanges::getInstance());
1045 pSelect->AddAllSelectableRouteSegments(m_pTail);
1046 pSelect->AddAllSelectableRoutePoints(m_pTail);
1047 pSelect->AddAllSelectableRouteSegments(m_pHead);
1048 pSelect->AddAllSelectableRoutePoints(m_pHead);
1050 SetRouteAndUpdate(m_pTail);
1053 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1054 pRouteManagerDialog->UpdateRouteListCtrl();
1058void RoutePropDlgImpl::PrintOnButtonClick(wxCommandEvent& event) {
1061 dlg->ShowWindowModalThenDo([
this, dlg](
int retcode) {
1062 if (retcode == wxID_OK) {
1067void RoutePropDlgImpl::ExtendOnButtonClick(wxCommandEvent& event) {
1068 m_btnExtend->Enable(
false);
1070 if (IsThisRouteExtendable()) {
1071 int fm = m_pExtendRoute->GetIndexOf(m_pExtendPoint) + 1;
1072 int to = m_pExtendRoute->GetnPoints();
1074 pSelect->DeleteAllSelectableRouteSegments(m_pRoute);
1075 m_pRoute->CloneRoute(m_pExtendRoute, fm, to, _(
"_plus"));
1076 pSelect->AddAllSelectableRouteSegments(m_pRoute);
1077 SetRouteAndUpdate(m_pRoute);
1081 m_btnExtend->Enable(
true);
1084bool RoutePropDlgImpl::IsThisRouteExtendable() {
1085 m_pExtendRoute = NULL;
1086 m_pExtendPoint = NULL;
1087 if (m_pRoute->m_bRtIsActive || m_pRoute->m_bIsInLayer)
return false;
1089 RoutePoint* pLastPoint = m_pRoute->GetLastPoint();
1090 wxArrayPtrVoid* pEditRouteArray;
1092 pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(pLastPoint);
1095 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1096 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1097 if (!p->IsVisible() || (p->m_GUID == m_pRoute->m_GUID))
1098 pEditRouteArray->RemoveAt(i - 1);
1100 if (pEditRouteArray->GetCount() == 1) {
1101 m_pExtendPoint = pLastPoint;
1103 if (pEditRouteArray->GetCount() == 0) {
1104 int nearby_radius_meters =
1105 (int)(8. / gFrame->GetPrimaryCanvas()->GetCanvasTrueScale());
1106 double rlat = pLastPoint->m_lat;
1107 double rlon = pLastPoint->m_lon;
1109 m_pExtendPoint = pWayPointMan->GetOtherNearbyWaypoint(
1110 rlat, rlon, nearby_radius_meters, pLastPoint->m_GUID);
1111 if (m_pExtendPoint) {
1112 wxArrayPtrVoid* pCloseWPRouteArray =
1113 g_pRouteMan->GetRouteArrayContaining(m_pExtendPoint);
1114 if (pCloseWPRouteArray) {
1115 pEditRouteArray = pCloseWPRouteArray;
1118 for (i = pEditRouteArray->GetCount(); i > 0; i--) {
1119 Route* p = (
Route*)pEditRouteArray->Item(i - 1);
1120 if (!p->IsVisible() || (p->m_GUID == m_pRoute->m_GUID))
1121 pEditRouteArray->RemoveAt(i - 1);
1127 if (pEditRouteArray->GetCount() == 1) {
1129 int fm = p->GetIndexOf(m_pExtendPoint) + 1;
1130 int to = p->GetnPoints();
1133 delete pEditRouteArray;
1137 delete pEditRouteArray;
1142wxString RoutePropDlgImpl::MakeTideInfo(wxString stationName,
double lat,
1143 double lon, wxDateTime utcTime) {
1144 if (stationName.Find(
"lind") != wxNOT_FOUND)
int yyp = 4;
1146 if (stationName.IsEmpty()) {
1147 return wxEmptyString;
1149 if (!utcTime.IsValid()) {
1150 return _(
"Invalid date/time!");
1152 int stationID = ptcmgr->GetStationIDXbyName(stationName, lat, lon);
1153 if (stationID == 0) {
1154 return _(
"Unknown station!");
1156 time_t dtmtt = utcTime.FromUTC().GetTicks();
1157 int ev = ptcmgr->GetNextBigEvent(&dtmtt, stationID);
1160 dtm.Set(dtmtt).MakeUTC();
1162 wxString tide_form = wxEmptyString;
1165 tide_form.Append(_T(
"LW: "));
1166 }
else if (ev == 2) {
1167 tide_form.Append(_T(
"HW: "));
1168 }
else if (ev == 0) {
1169 tide_form.Append(_(
"Unavailable: "));
1173 ptcmgr->GetStationTimeOffset((
IDX_entry*)ptcmgr->GetIDX_entry(stationID));
1176 .
SetTimezone(getDatetimeTimezoneSelector(m_tz_selection))
1178 tide_form.Append(ocpn::toUsrDateTimeFormat(dtm, opts));
1179 dtm.Add(wxTimeSpan(0, offset, 0));
1180 tide_form.Append(wxString::Format(_T(
" (") + _(
"Local") + _T(
": %s) @ %s"),
1181 ocpn::toUsrDateTimeFormat(dtm, opts),
1182 stationName.c_str()));
1187void RoutePropDlgImpl::ItemEditOnMenuSelection(wxCommandEvent& event) {
1188 wxString findurl = m_pEditedLink->GetURL();
1189 wxString findlabel = m_pEditedLink->GetLabel();
1192 LinkPropDlg->m_textCtrlLinkDescription->SetValue(findlabel);
1193 LinkPropDlg->m_textCtrlLinkUrl->SetValue(findurl);
1194 DimeControl(LinkPropDlg);
1195 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg, findurl,
1196 findlabel](
int retcode) {
1197 if (retcode == wxID_OK) {
1198 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
1199 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1201 if (NbrOfLinks > 0) {
1202 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1205 wxString Link = link->Link;
1206 wxString Descr = link->DescrText;
1207 if (Link == findurl &&
1208 (Descr == findlabel ||
1209 (Link == findlabel && Descr == wxEmptyString))) {
1210 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1212 LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1213 wxHyperlinkCtrl* h =
1214 (wxHyperlinkCtrl*)m_scrolledWindowLinks->FindWindowByLabel(
1217 h->SetLabel(LinkPropDlg->m_textCtrlLinkDescription->GetValue());
1218 h->SetURL(LinkPropDlg->m_textCtrlLinkUrl->GetValue());
1221 linknode = linknode->GetNext();
1225 m_scrolledWindowLinks->InvalidateBestSize();
1226 m_scrolledWindowLinks->Layout();
1227 bSizerLinks->Layout();
1233void RoutePropDlgImpl::ItemAddOnMenuSelection(wxCommandEvent& event) {
1234 AddLinkOnButtonClick(event);
1238 wxHyperlinkListNode* nodeToDelete = NULL;
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));
1260 int NbrOfLinks = m_pRoute->m_HyperlinkList->GetCount();
1261 HyperlinkList* hyperlinklist = m_pRoute->m_HyperlinkList;
1263 if (NbrOfLinks > 0) {
1264 wxHyperlinkListNode* linknode = hyperlinklist->GetFirst();
1267 wxString Link = link->Link;
1268 wxString Descr = link->DescrText;
1269 if (Link == findurl &&
1270 (Descr == findlabel || (Link == findlabel && Descr == wxEmptyString)))
1271 nodeToDelete = linknode;
1273 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1274 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
1275 wxDefaultSize, wxHL_DEFAULT_STYLE);
1277 wxEVT_COMMAND_HYPERLINK,
1278 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick), NULL,
1282 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu), NULL,
1285 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1287 linknode = linknode->GetNext();
1291 hyperlinklist->DeleteNode(nodeToDelete);
1293 m_scrolledWindowLinks->InvalidateBestSize();
1294 m_scrolledWindowLinks->Layout();
1295 bSizerLinks->Layout();
1299void RoutePropDlgImpl::AddLinkOnButtonClick(wxCommandEvent& event) {
1301 LinkPropDlg->m_textCtrlLinkDescription->SetValue(wxEmptyString);
1302 LinkPropDlg->m_textCtrlLinkUrl->SetValue(wxEmptyString);
1303 DimeControl(LinkPropDlg);
1304 LinkPropDlg->ShowWindowModalThenDo([
this, LinkPropDlg](
int retcode) {
1305 if (retcode == wxID_OK) {
1306 wxString desc = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1307 if (desc == wxEmptyString)
1308 desc = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1309 wxHyperlinkCtrl* ctrl =
new wxHyperlinkCtrl(
1310 m_scrolledWindowLinks, wxID_ANY, desc,
1311 LinkPropDlg->m_textCtrlLinkUrl->GetValue(), wxDefaultPosition,
1312 wxDefaultSize, wxHL_DEFAULT_STYLE);
1313 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
1314 wxHyperlinkEventHandler(RoutePropDlgImpl::OnHyperlinkClick),
1316 ctrl->Connect(wxEVT_RIGHT_DOWN,
1317 wxMouseEventHandler(RoutePropDlgImpl::HyperlinkContextMenu),
1320 bSizerLinks->Add(ctrl, 0, wxALL, 5);
1321 m_scrolledWindowLinks->InvalidateBestSize();
1322 m_scrolledWindowLinks->Layout();
1323 bSizerLinks->Layout();
1326 h->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1327 h->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1328 h->LType = wxEmptyString;
1329 m_pRoute->m_HyperlinkList->Append(h);
1334void RoutePropDlgImpl::BtnEditOnToggleButton(wxCommandEvent& event) {
1335 if (m_toggleBtnEdit->GetValue()) {
1336 m_stEditEnabled->SetLabel(_(
"Links are opened for editing."));
1338 m_stEditEnabled->SetLabel(_(
"Links are opened in the default browser."));
1343void RoutePropDlgImpl::OnHyperlinkClick(wxHyperlinkEvent& event) {
1344 if (m_toggleBtnEdit->GetValue()) {
1345 m_pEditedLink = (wxHyperlinkCtrl*)event.GetEventObject();
1346 ItemEditOnMenuSelection(event);
1359 wxString cc =
event.GetURL();
1360 if (cc.Find(_T(
"#")) != wxNOT_FOUND) {
1362 wxString(_T(
"HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command")));
1363 if (RegKey.Exists()) {
1364 wxString command_line;
1365 RegKey.QueryValue(wxString(_T(
"")), command_line);
1368 command_line.Replace(wxString(_T(
"\"")), wxString(_T(
"")));
1371 int l = command_line.Find(_T(
".exe"));
1372 if (wxNOT_FOUND == l) l = command_line.Find(_T(
".EXE"));
1374 if (wxNOT_FOUND != l) {
1375 wxString cl = command_line.Mid(0, l + 4);
1377 cc.Prepend(_T(
"\""));
1378 cc.Append(_T(
"\""));
1386 wxString url =
event.GetURL();
1387 url.Replace(_T(
" "), _T(
"%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);
Represents an index entry for tidal and current data.
Represents a waypoint or mark within the navigation system.
void ItemDeleteOnMenuSelection(wxCommandEvent &event)
Represents a navigational route in the navigation system.
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.