OpenCPN Partial API docs
Loading...
Searching...
No Matches
canvasMenu.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: CanvasMenuHandler
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2015 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26// For compilers that support precompilation, includes "wx.h".
27#include <wx/wxprec.h>
28
29#include <wx/aui/aui.h>
30#include <wx/clipbrd.h>
31#include <wx/dynarray.h>
32#include <wx/event.h>
33#include <wx/font.h>
34#include <wx/gdicmn.h>
35#include <wx/graphics.h>
36#include <wx/image.h>
37#include <wx/listbook.h>
38#include <wx/listimpl.cpp>
39#include <wx/menu.h>
40
41#include "model/ais_decoder.h"
43#include "model/ais_target_data.h"
44#include "model/config_vars.h"
45#include "model/cutil.h"
46#include "model/georef.h"
47#include "model/gui.h"
48#include "model/mdns_cache.h"
49#include "model/mdns_query.h"
50#include "model/nav_object_database.h"
51#include "model/own_ship.h"
52#include "model/own_ship.h"
53#include "model/plugin_comm.h"
54#include "model/route.h"
55#include "model/routeman.h"
56#include "model/select.h"
57#include "model/track.h"
58
59#include "ais.h"
60#include "canvasMenu.h"
61#include "chartdb.h"
62#include "chcanv.h"
63#include "cm93.h" // for chart outline draw
64#include "config.h"
65#include "FontMgr.h"
66#include "kml.h"
67#include "MarkInfo.h"
68#include "navutil.h"
69#include "ocpn_frame.h"
70#include "OCPNPlatform.h"
71#include "peer_client_dlg.h"
72#include "pluginmanager.h"
73#include "Quilt.h"
74#include "route_gui.h"
75#include "routemanagerdialog.h"
76#include "routeman_gui.h"
77#include "route_point_gui.h"
78#include "RoutePropDlgImpl.h"
79#include "s52plib.h"
80#include "s52s57.h"
81#include "s57chart.h" // for ArrayOfS57Obj
82#include "SendToGpsDlg.h"
83#include "SendToPeerDlg.h"
84#include "styles.h"
85#include "tcmgr.h"
86#include "TCWin.h"
87#include "tide_time.h"
88#include "track_gui.h"
89#include "TrackPropDlg.h"
90#include "undo.h"
91#include "model/navobj_db.h"
92
93#ifdef __ANDROID__
94#include "androidUTIL.h"
95#endif
96
97// ----------------------------------------------------------------------------
98// Useful Prototypes
99// ----------------------------------------------------------------------------
100extern void pupHandler_PasteRoute();
101extern void pupHandler_PasteTrack();
102extern void pupHandler_PasteWaypoint();
103
104extern Routeman *g_pRouteMan;
105extern bool g_bskew_comp;
106extern double vLat, vLon;
107extern MyFrame *gFrame;
108extern ChartGroupArray *g_pGroupArray;
109extern PlugInManager *g_pi_manager;
110extern int g_nAWMax;
111extern int g_nAWDefault;
112extern wxString g_AW1GUID;
113extern wxString g_AW2GUID;
114extern int g_click_stop;
115extern RouteManagerDialog *pRouteManagerDialog;
116extern MarkInfoDlg *g_pMarkInfoDialog;
117extern RoutePropDlgImpl *pRoutePropDialog;
118extern ActiveTrack *g_pActiveTrack;
119extern bool g_bConfirmObjectDelete;
120extern MyConfig *pConfig;
121extern OCPNPlatform *g_Platform;
122
123extern CM93OffsetDialog *g_pCM93OffsetDialog;
124
125extern GoToPositionDialog *pGoToPositionDialog;
126extern RouteList *pRouteList;
127extern wxString g_default_wp_icon;
128extern bool g_bBasicMenus;
129extern TrackPropDlg *pTrackPropDialog;
130extern bool g_FlushNavobjChanges;
131extern ColorScheme global_color_scheme;
132
133// Constants for right click menus
134enum {
135 ID_DEF_MENU_MAX_DETAIL = 1,
136 ID_DEF_MENU_SCALE_IN,
137 ID_DEF_MENU_SCALE_OUT,
138 ID_DEF_MENU_DROP_WP,
139 ID_DEF_MENU_NEW_RT,
140 ID_DEF_MENU_QUERY,
141 ID_DEF_MENU_MOVE_BOAT_HERE,
142 ID_DEF_MENU_GOTO_HERE,
143 ID_DEF_MENU_GOTOPOSITION,
144
145 ID_WP_MENU_GOTO,
146 ID_WP_MENU_DELPOINT,
147 ID_WP_MENU_PROPERTIES,
148 ID_RT_MENU_ACTIVATE,
149 ID_RT_MENU_DEACTIVATE,
150 ID_RT_MENU_INSERT,
151 ID_RT_MENU_APPEND,
152 ID_RT_MENU_COPY,
153 ID_RT_MENU_SPLIT_LEG,
154 ID_RT_MENU_SPLIT_WPT,
155 ID_TK_MENU_COPY,
156 ID_WPT_MENU_COPY,
157 ID_WPT_MENU_SENDTOGPS,
158 ID_WPT_MENU_SENDTONEWGPS,
159 ID_WPT_MENU_SENDTOPEER,
160 ID_PASTE_WAYPOINT,
161 ID_PASTE_ROUTE,
162 ID_PASTE_TRACK,
163 ID_RT_MENU_DELETE,
164 ID_RT_MENU_REVERSE,
165 ID_RT_MENU_DELPOINT,
166 ID_RT_MENU_ACTPOINT,
167 ID_RT_MENU_DEACTPOINT,
168 ID_RT_MENU_ACTNXTPOINT,
169 ID_RT_MENU_REMPOINT,
170 ID_RT_MENU_PROPERTIES,
171 ID_RT_MENU_SENDTOGPS,
172 ID_RT_MENU_SENDTONEWGPS,
173 ID_RT_MENU_SHOWNAMES,
174 ID_RT_MENU_RESEQUENCE,
175 ID_RT_MENU_SENDTOPEER,
176 ID_WP_MENU_SET_ANCHORWATCH,
177 ID_WP_MENU_CLEAR_ANCHORWATCH,
178 ID_DEF_MENU_AISTARGETLIST,
179 ID_DEF_MENU_AIS_CPAWARNING,
180
181 ID_RC_MENU_SCALE_IN,
182 ID_RC_MENU_SCALE_OUT,
183 ID_RC_MENU_ZOOM_IN,
184 ID_RC_MENU_ZOOM_OUT,
185 ID_RC_MENU_FINISH,
186 ID_DEF_MENU_AIS_QUERY,
187 ID_DEF_MENU_AIS_CPA,
188 ID_DEF_MENU_AISSHOWTRACK,
189 ID_DEF_MENU_ACTIVATE_MEASURE,
190 ID_DEF_MENU_DEACTIVATE_MEASURE,
191 ID_DEF_MENU_COPY_MMSI,
192
193 ID_UNDO,
194 ID_REDO,
195
196 ID_DEF_MENU_CM93OFFSET_DIALOG,
197
198 ID_TK_MENU_PROPERTIES,
199 ID_TK_MENU_DELETE,
200 ID_TK_MENU_SENDTOPEER,
201 ID_WP_MENU_ADDITIONAL_INFO,
202
203 ID_DEF_MENU_QUILTREMOVE,
204 ID_DEF_MENU_COGUP,
205 ID_DEF_MENU_NORTHUP,
206 ID_DEF_MENU_HEADUP,
207 ID_DEF_MENU_TOGGLE_FULL,
208 ID_DEF_MENU_TIDEINFO,
209 ID_DEF_MENU_CURRENTINFO,
210 ID_DEF_ZERO_XTE,
211
212 ID_DEF_MENU_DEBUG,
213 ID_DGB_MENU_NMEA_WINDOW,
214
215 ID_DEF_MENU_GROUPBASE, // Must be last entry, as chart group identifiers are
216 // created dynamically
217
218 ID_DEF_MENU_LAST
219};
220
221//------------------------------------------------------------------------------
222// CanvasMenuHandler Implementation
223//------------------------------------------------------------------------------
224int CanvasMenuHandler::GetNextContextMenuId() {
225 return ID_DEF_MENU_LAST +
226 100; // Allowing for 100 dynamic menu item identifiers
227}
228
229wxFont CanvasMenuHandler::m_scaledFont;
230
231// Define a constructor for my canvas
232CanvasMenuHandler::CanvasMenuHandler(ChartCanvas *parentCanvas,
233 Route *selectedRoute, Track *selectedTrack,
234 RoutePoint *selectedPoint,
235 int selectedAIS_MMSI,
236 void *selectedTCIndex, wxWindow *nmea_log)
237 : m_nmea_log(nmea_log) {
238 parent = parentCanvas;
239 m_pSelectedRoute = selectedRoute;
240 m_pSelectedTrack = selectedTrack;
241 m_pFoundRoutePoint = selectedPoint;
242 m_FoundAIS_MMSI = selectedAIS_MMSI;
243 m_pIDXCandidate = selectedTCIndex;
244 if (!m_scaledFont.IsOk()) {
245 wxFont *qFont = GetOCPNScaledFont(_("Menu"));
246 m_scaledFont = *qFont;
247 }
248
249 m_DIPFactor = g_Platform->GetDisplayDIPMult(gFrame);
250}
251
252CanvasMenuHandler::~CanvasMenuHandler() {}
253
254//-------------------------------------------------------------------------------
255// Popup Menu Handling
256//-------------------------------------------------------------------------------
257
258void CanvasMenuHandler::PrepareMenuItem(wxMenuItem *item) {
259#if defined(__WXMSW__)
260 wxColour ctrl_back_color = GetGlobalColor(_T("DILG1")); // Control Background
261 item->SetBackgroundColour(ctrl_back_color);
262 wxColour menu_text_color = GetGlobalColor(_T ( "UITX1" ));
263 item->SetTextColour(menu_text_color);
264#endif
265}
266
267void CanvasMenuHandler::MenuPrepend1(wxMenu *menu, int id, wxString label) {
268 wxMenuItem *item = new wxMenuItem(menu, id, label);
269#if defined(__WXMSW__)
270 item->SetFont(m_scaledFont);
271#endif
272
273#ifdef __ANDROID__
274 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
275 item->SetFont(sFont);
276#endif
277
278 PrepareMenuItem(item);
279
280 if (g_btouch) menu->InsertSeparator(0);
281 menu->Prepend(item);
282}
283
284void CanvasMenuHandler::MenuAppend1(wxMenu *menu, int id, wxString label) {
285 wxMenuItem *item = new wxMenuItem(menu, id, label);
286#if defined(__WXMSW__)
287 item->SetFont(m_scaledFont);
288#endif
289
290#ifdef __ANDROID__
291 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
292 item->SetFont(sFont);
293#endif
294
295 PrepareMenuItem(item);
296
297 menu->Append(item);
298 if (g_btouch) menu->AppendSeparator();
299}
300
301void CanvasMenuHandler::SetMenuItemFont1(wxMenuItem *item) {
302#if defined(__WXMSW__)
303 item->SetFont(m_scaledFont);
304#endif
305
306#if defined(__ANDROID__)
307 wxFont *qFont = GetOCPNScaledFont(_("Menu"));
308 item->SetFont(*qFont);
309#endif
310
311 PrepareMenuItem(item);
312}
313
314void CanvasMenuHandler::CanvasPopupMenu(int x, int y, int seltype) {
315 wxMenu *contextMenu = new wxMenu;
316 wxMenu *menuWaypoint = NULL;
317 wxMenu *menuRoute = NULL;
318 wxMenu *menuTrack = NULL;
319 wxMenu *menuAIS = NULL;
320
321 wxMenu *subMenuChart = new wxMenu;
322 wxMenu *subMenuUndo = new wxMenu("Undo...Ctrl-Z");
323
324#ifdef __WXOSX__
325 wxMenu *subMenuRedo = new wxMenu("Redo...Shift-Ctrl-Z");
326#else
327 wxMenu *subMenuRedo = new wxMenu("Redo...Ctrl-Y");
328#endif
329 wxMenu *subMenuDebug = new wxMenu("");
330 MenuAppend1(subMenuDebug, ID_DGB_MENU_NMEA_WINDOW, _("Show Data Monitor"));
331
332 wxMenu *menuFocus = contextMenu; // This is the one that will be shown
333
334 popx = x;
335 popy = y;
336
337 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
338 bool bsubMenus = false;
339
340 if (bsubMenus) {
341 if (parent->undo->AnythingToUndo()) {
342 // Undo SubMenu
343 wxMenuItem *subMenuItemundo =
344 contextMenu->AppendSubMenu(subMenuUndo, _("Undo"));
345
346 wxString undoItem;
347 undoItem << _("Undo") << _T(" ")
348 << parent->undo->GetNextUndoableAction()->Description();
349 MenuAppend1(subMenuUndo, ID_UNDO, undoItem);
350 }
351 if (parent->undo->AnythingToRedo()) {
352 // Redo SubMenu
353 wxMenuItem *subMenuItemRedo =
354 contextMenu->AppendSubMenu(subMenuRedo, _("Redo"));
355
356 wxString redoItem;
357 redoItem << _("Redo") << _T(" ")
358 << parent->undo->GetNextRedoableAction()->Description();
359 MenuAppend1(subMenuRedo, ID_REDO, redoItem);
360 }
361 } else {
362 if (parent->undo->AnythingToUndo()) {
363 wxString undoItem;
364 undoItem << _("Undo") << _T(" ")
365 << parent->undo->GetNextUndoableAction()->Description();
366 MenuAppend1(contextMenu, ID_UNDO, _menuText(undoItem, _T("Ctrl-Z")));
367 }
368
369 if (parent->undo->AnythingToRedo()) {
370 wxString redoItem;
371 redoItem << _("Redo") << _T(" ")
372 << parent->undo->GetNextRedoableAction()->Description();
373#ifdef __WXOSX__
374 MenuAppend1(contextMenu, ID_REDO,
375 _menuText(redoItem, _T("Shift-Ctrl-Z")));
376#else
377 MenuAppend1(contextMenu, ID_REDO, _menuText(redoItem, _T("Ctrl-Y")));
378#endif
379 }
380 }
381 }
382
383 if (seltype == SELTYPE_ROUTECREATE) {
384 MenuAppend1(contextMenu, ID_RC_MENU_FINISH,
385 _menuText(_("End Route"), _T("Esc")));
386 }
387
388 if (!parent->m_pMouseRoute) {
389 if (parent->m_bMeasure_Active)
390 MenuAppend1(contextMenu, ID_DEF_MENU_DEACTIVATE_MEASURE,
391 _menuText(_("Measure Off"), _T("Esc")));
392 else
393 MenuAppend1(contextMenu, ID_DEF_MENU_ACTIVATE_MEASURE,
394 _menuText(_("Measure"), _T("M")));
395 }
396
397 bool ais_areanotice = false;
398 if (g_pAIS && parent->GetShowAIS() && g_bShowAreaNotices) {
399 float vp_scale = parent->GetVPScale();
400
401 for (const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
402 auto target_data = target.second;
403 if (!target_data->area_notices.empty()) {
404 for (auto &ani : target_data->area_notices) {
405 Ais8_001_22 &area_notice = ani.second;
406 BoundingBox bbox;
407
408 for (Ais8_001_22_SubAreaList::iterator sa =
409 area_notice.sub_areas.begin();
410 sa != area_notice.sub_areas.end(); ++sa) {
411 switch (sa->shape) {
412 case AIS8_001_22_SHAPE_CIRCLE: {
413 wxPoint target_point;
414 parent->GetCanvasPointPix(sa->latitude, sa->longitude,
415 &target_point);
416 bbox.Expand(target_point);
417 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
418 break;
419 }
420 case AIS8_001_22_SHAPE_RECT:
421 case AIS8_001_22_SHAPE_POLYGON:
422 case AIS8_001_22_SHAPE_POLYLINE: {
423 double lat = sa->latitude;
424 double lon = sa->longitude;
425 for (int i = 0; i < 4; ++i) {
426 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
427 &lat, &lon);
428 wxPoint target_point;
429 parent->GetCanvasPointPix(lat, lon, &target_point);
430 bbox.Expand(target_point);
431 }
432 break;
433 }
434 case AIS8_001_22_SHAPE_SECTOR: {
435 double lat1 = sa->latitude;
436 double lon1 = sa->longitude;
437 double lat, lon;
438 wxPoint target_point;
439 parent->GetCanvasPointPix(lat1, lon1, &target_point);
440 bbox.Expand(target_point);
441 for (int i = 0; i < 18; ++i) {
442 ll_gc_ll(
443 lat1, lon1,
444 sa->left_bound_deg +
445 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
446 sa->radius_m / 1852.0, &lat, &lon);
447 parent->GetCanvasPointPix(lat, lon, &target_point);
448 bbox.Expand(target_point);
449 }
450 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
451 &lat, &lon);
452 parent->GetCanvasPointPix(lat, lon, &target_point);
453 bbox.Expand(target_point);
454 break;
455 }
456 }
457 }
458
459 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
460 ais_areanotice = true;
461 break;
462 }
463 }
464 }
465 }
466 }
467
468 int nChartStack = 0;
469 if (parent->GetpCurrentStack())
470 nChartStack = parent->GetpCurrentStack()->nEntry;
471
472 if (!parent->GetVP().b_quilt) {
473 if (nChartStack > 1) {
474 MenuAppend1(contextMenu, ID_DEF_MENU_MAX_DETAIL, _("Max Detail Here"));
475 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_IN,
476 _menuText(_("Scale In"), _T("Ctrl-Left")));
477 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_OUT,
478 _menuText(_("Scale Out"), _T("Ctrl-Right")));
479 }
480
481 if ((parent->m_singleChart &&
482 (parent->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)) ||
483 ais_areanotice) {
484 MenuAppend1(contextMenu, ID_DEF_MENU_QUERY,
485 _("Object Query") + _T( "..." ));
486 }
487
488 } else {
489 ChartBase *pChartTest =
490 parent->m_pQuilt->GetChartAtPix(parent->GetVP(), wxPoint(x, y));
491 if ((pChartTest && (pChartTest->GetChartFamily() == CHART_FAMILY_VECTOR)) ||
492 ais_areanotice) {
493 MenuAppend1(contextMenu, ID_DEF_MENU_QUERY,
494 _("Object Query") + _T( "..." ));
495 } else {
496#ifndef __ANDROID__
497 if (!g_bBasicMenus && (nChartStack > 1)) {
498 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_IN,
499 _menuText(_("Scale In"), _T("Ctrl-Left")));
500 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_OUT,
501 _menuText(_("Scale Out"), _T("Ctrl-Right")));
502 }
503#endif
504 }
505 }
506
507 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
508 bool b_dm_add = true;
509 if (g_btouch && parent->IsMeasureActive()) b_dm_add = false;
510
511 if (b_dm_add) {
512 MenuAppend1(contextMenu, ID_DEF_MENU_DROP_WP,
513 _menuText(_("Drop Mark"), _T("Ctrl-M")));
514 MenuAppend1(contextMenu, ID_DEF_MENU_NEW_RT,
515 _menuText(_("New Route..."), _T("Ctrl-R")));
516 }
517
518 if (!bGPSValid)
519 MenuAppend1(contextMenu, ID_DEF_MENU_MOVE_BOAT_HERE, _("Move Boat Here"));
520 }
521
522 if (!g_bBasicMenus && !g_pRouteMan->GetpActiveRoute() &&
523 (!(seltype & SELTYPE_MARKPOINT) ||
524 (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer)))
525 MenuAppend1(contextMenu, ID_DEF_MENU_GOTO_HERE, _("Navigate To Here"));
526
527 if (!g_bBasicMenus)
528 MenuAppend1(contextMenu, ID_DEF_MENU_GOTOPOSITION,
529 _("Center view") + _T("..."));
530
531 if (!g_bBasicMenus) {
532 if (parent->GetVP().b_quilt) {
533 if (parent->GetUpMode() == NORTH_UP_MODE) {
534 MenuAppend1(contextMenu, ID_DEF_MENU_COGUP, _("Course Up Mode"));
535 if (!std::isnan(gHdt))
536 MenuAppend1(contextMenu, ID_DEF_MENU_HEADUP, _("Heading Up Mode"));
537 } else {
538 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("North Up Mode"));
539 }
540 } else {
541 if (parent->m_singleChart &&
542 (fabs(parent->m_singleChart->GetChartSkew()) > .01) && !g_bskew_comp)
543 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("Chart Up Mode"));
544 else
545 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("North Up Mode"));
546 }
547 }
548
549 if (!g_bBasicMenus) {
550 bool full_toggle_added = false;
551#ifndef __ANDROID__
552 if (g_btouch) {
553 MenuAppend1(contextMenu, ID_DEF_MENU_TOGGLE_FULL,
554 _("Toggle Full Screen"));
555 full_toggle_added = true;
556 }
557
558 if (!full_toggle_added) {
559 // if(gFrame->IsFullScreen())
560 MenuAppend1(contextMenu, ID_DEF_MENU_TOGGLE_FULL,
561 _("Toggle Full Screen"));
562 }
563#endif
564
565 if (g_pRouteMan->IsAnyRouteActive() &&
566 g_pRouteMan->GetCurrentXTEToActivePoint() > 0.)
567 MenuAppend1(contextMenu, ID_DEF_ZERO_XTE, _("Zero XTE"));
568
569 Kml *kml = new Kml;
570 int pasteBuffer = kml->ParsePasteBuffer();
571 if (pasteBuffer != KML_PASTE_INVALID) {
572 switch (pasteBuffer) {
573 case KML_PASTE_WAYPOINT: {
574 MenuAppend1(contextMenu, ID_PASTE_WAYPOINT, _("Paste Waypoint"));
575 break;
576 }
577 case KML_PASTE_ROUTE: {
578 MenuAppend1(contextMenu, ID_PASTE_ROUTE, _("Paste Route"));
579 break;
580 }
581 case KML_PASTE_TRACK: {
582 MenuAppend1(contextMenu, ID_PASTE_TRACK, _("Paste Track"));
583 break;
584 }
585 case KML_PASTE_ROUTE_TRACK: {
586 MenuAppend1(contextMenu, ID_PASTE_ROUTE, _("Paste Route"));
587 MenuAppend1(contextMenu, ID_PASTE_TRACK, _("Paste Track"));
588 break;
589 }
590 }
591 }
592 delete kml;
593
594 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
595 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
596 MenuAppend1(contextMenu, ID_DEF_MENU_CM93OFFSET_DIALOG,
597 _("CM93 Offset Dialog..."));
598 }
599
600 } // if( !g_bBasicMenus){
601
602#ifndef __ANDROID__
603// TODO stack
604// if( ( parent->GetVP().b_quilt ) && ( pCurrentStack &&
605// pCurrentStack->b_valid ) ) {
606// int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
607// parent->GetVP(), wxPoint( popx, popy ) ); if( dbIndex != -1 )
608// MenuAppend1( contextMenu, ID_DEF_MENU_QUILTREMOVE, _( "Hide This
609// Chart" ) );
610// }
611#endif
612
613#ifdef __WXMSW__
614 // If we dismiss the context menu without action, we need to discard some
615 // mouse events.... Eat the next 2 button events, which happen as down-up on
616 // MSW XP
617 g_click_stop = 2;
618#endif
619
620 // ChartGroup SubMenu
621 wxMenuItem *subItemChart =
622 contextMenu->AppendSubMenu(subMenuChart, _("Chart Groups"));
623 if (g_btouch) contextMenu->AppendSeparator();
624
625 SetMenuItemFont1(subItemChart);
626
627 if (g_pGroupArray->GetCount()) {
628#ifdef __WXMSW__
629 MenuAppend1(subMenuChart, wxID_CANCEL, _("temporary"));
630#endif
631 wxMenuItem *subItem0 = subMenuChart->AppendRadioItem(
632 ID_DEF_MENU_GROUPBASE, _("All Active Charts"));
633
634 SetMenuItemFont1(subItem0);
635
636 for (unsigned int i = 0; i < g_pGroupArray->GetCount(); i++) {
637 subItem0 = subMenuChart->AppendRadioItem(
638 ID_DEF_MENU_GROUPBASE + i + 1, g_pGroupArray->Item(i)->m_group_name);
639 SetMenuItemFont1(subItem0);
640 }
641
642#ifdef __WXMSW__
643 subMenuChart->Remove(wxID_CANCEL);
644#endif
645 subMenuChart->Check(ID_DEF_MENU_GROUPBASE + parent->m_groupIndex, true);
646 }
647
648 // This is the default context menu
649 menuFocus = contextMenu;
650
651 wxString name;
652 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
653 if (g_pAIS) {
654 if (parent->GetShowAIS() && (seltype & SELTYPE_AISTARGET)) {
655 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
656 if (!g_bBasicMenus && myptarget) {
657 name = myptarget->GetFullName();
658 if (name.IsEmpty()) name.Printf(_T("%d"), m_FoundAIS_MMSI);
659 name.Prepend(_T(" ( ")).Append(_T(" )"));
660 } else
661 name = wxEmptyString;
662 menuAIS = new wxMenu(_("AIS") + name);
663 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_QUERY, _("Target Query..."));
664 if (myptarget && myptarget->bCPA_Valid &&
665 (myptarget->n_alert_state != AIS_ALERT_SET)) {
666 if (myptarget->b_show_AIS_CPA)
667 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_CPA, _("Hide Target CPA"));
668 else
669 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_CPA, _("Show Target CPA"));
670 }
671 MenuAppend1(menuAIS, ID_DEF_MENU_AISTARGETLIST, _("Target List..."));
672 if (myptarget->Class != AIS_METEO /*g_bAISShowTracks*/) {
673 if (myptarget && !myptarget->b_PersistTrack) {
674 if (myptarget->b_show_track)
675 MenuAppend1(menuAIS, ID_DEF_MENU_AISSHOWTRACK,
676 _("Hide Target Track"));
677 else
678 MenuAppend1(menuAIS, ID_DEF_MENU_AISSHOWTRACK,
679 _("Show Target Track"));
680 }
681 }
682
683 MenuAppend1(menuAIS, ID_DEF_MENU_COPY_MMSI, _("Copy Target MMSI"));
684 menuAIS->AppendSeparator();
685
686 if (!parent->GetVP().b_quilt) {
687 if ((parent->m_singleChart &&
688 (parent->m_singleChart->GetChartFamily() ==
689 CHART_FAMILY_VECTOR))) {
690 MenuAppend1(menuAIS, ID_DEF_MENU_QUERY, _("Object Query..."));
691 }
692
693 } else {
694 ChartBase *pChartTest =
695 parent->m_pQuilt->GetChartAtPix(parent->GetVP(), wxPoint(x, y));
696 if ((pChartTest &&
697 (pChartTest->GetChartFamily() == CHART_FAMILY_VECTOR))) {
698 MenuAppend1(menuAIS, ID_DEF_MENU_QUERY, _("Object Query..."));
699 }
700 }
701
702 menuFocus = menuAIS;
703 } else {
704 MenuAppend1(contextMenu, ID_DEF_MENU_AISTARGETLIST,
705 _("AIS target list") + _T("..."));
706
707 wxString nextCPAstatus = g_bCPAWarn ? _("Hide") : _("Show");
708 MenuAppend1(contextMenu, ID_DEF_MENU_AIS_CPAWARNING,
709 _menuText(nextCPAstatus + " " + _("CPA alarm "), "W"));
710 }
711 }
712 }
713 if (g_enable_root_menu_debug) {
714 wxMenuItem *subItemDebug =
715 contextMenu->AppendSubMenu(subMenuDebug, _("Debug"));
716 if (g_btouch) contextMenu->AppendSeparator();
717 SetMenuItemFont1(subItemDebug);
718 }
719
720 if (seltype & SELTYPE_ROUTESEGMENT) {
721 if (!g_bBasicMenus && m_pSelectedRoute) {
722 name = m_pSelectedRoute->m_RouteNameString;
723 if (name.IsEmpty()) name = _("Unnamed Route");
724 name.Prepend(_T(" ( ")).Append(_T(" )"));
725 } else
726 name = wxEmptyString;
727 bool blay = false;
728 if (m_pSelectedRoute && m_pSelectedRoute->m_bIsInLayer) blay = true;
729
730 if (blay) {
731 menuRoute = new wxMenu(_("Layer Route") + name);
732 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES,
733 _("Properties") + _T( "..." ));
734 if (m_pSelectedRoute) {
735 if (m_pSelectedRoute->IsActive()) {
736 int indexActive = m_pSelectedRoute->GetIndexOf(
737 m_pSelectedRoute->m_pRouteActivePoint);
738 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
739 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
740 _("Activate Next Waypoint"));
741 }
742 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
743 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
744 } else {
745 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
746 }
747 }
748 } else {
749 menuRoute = new wxMenu(_("Route") + name);
750 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES,
751 _("Properties") + _T( "..." ));
752 if (m_pSelectedRoute) {
753 if (m_pSelectedRoute->IsActive()) {
754 int indexActive = m_pSelectedRoute->GetIndexOf(
755 m_pSelectedRoute->m_pRouteActivePoint);
756 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
757 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
758 _("Activate Next Waypoint"));
759 }
760 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
761 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
762 } else {
763 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
764 }
765 }
766 MenuAppend1(menuRoute, ID_RT_MENU_INSERT, _("Insert Waypoint"));
767 MenuAppend1(menuRoute, ID_RT_MENU_APPEND, _("Append Waypoint"));
768 if (!(seltype & SELTYPE_ROUTEPOINT) && m_pSelectedRoute) {
769 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
770 if (m_SelectedIdx > 1 &&
771 m_SelectedIdx < m_pSelectedRoute->GetnPoints() - 1)
772 MenuAppend1(menuRoute, ID_RT_MENU_SPLIT_LEG, _("Split around Leg"));
773 }
774 MenuAppend1(menuRoute, ID_RT_MENU_COPY, _("Copy as KML") + _T( "..." ));
775 MenuAppend1(menuRoute, ID_RT_MENU_DELETE, _("Delete") + _T( "..." ));
776 MenuAppend1(menuRoute, ID_RT_MENU_REVERSE, _("Reverse..."));
777 if (m_pSelectedRoute) {
778 if (m_pSelectedRoute->AreWaypointNamesVisible())
779 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
780 _("Hide Waypoint Names"));
781 else
782 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
783 _("Show Waypoint Names"));
784 }
785 MenuAppend1(menuRoute, ID_RT_MENU_RESEQUENCE,
786 _("Resequence Waypoints..."));
787
788 // #ifndef __ANDROID__
789 wxString port = parent->FindValidUploadPort();
790 parent->m_active_upload_port = port;
791 wxString item = _("Send to GPS");
792 if (!port.IsEmpty()) {
793 item.Append(_T(" ( "));
794 item.Append(port);
795 item.Append(_T(" )"));
796 }
797 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOGPS, item);
798
799 if (!port.IsEmpty()) {
800 wxString item = _("Send to new GPS");
801 MenuAppend1(menuRoute, ID_RT_MENU_SENDTONEWGPS, item);
802 }
803 // #endif
804 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
805 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOPEER, itemstp);
806 }
807 // Eventually set this menu as the "focused context menu"
808 if (menuFocus != menuAIS) menuFocus = menuRoute;
809 }
810
811 if (seltype & SELTYPE_TRACKSEGMENT) {
812 name = wxEmptyString;
813 if (!g_bBasicMenus && m_pSelectedTrack)
814 name = _T(" ( ") + m_pSelectedTrack->GetName(true) + _T(" )");
815 else
816 name = wxEmptyString;
817 bool blay = false;
818 if (m_pSelectedTrack && m_pSelectedTrack->m_bIsInLayer) blay = true;
819
820 if (blay) {
821 menuTrack = new wxMenu(_("Layer Track") + name);
822 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES,
823 _("Properties") + _T( "..." ));
824 } else {
825 menuTrack = new wxMenu(_("Track") + name);
826 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES,
827 _("Properties") + _T( "..." ));
828 MenuAppend1(menuTrack, ID_TK_MENU_COPY, _("Copy as KML"));
829 MenuAppend1(menuTrack, ID_TK_MENU_DELETE, _("Delete") + _T( "..." ));
830 }
831
832 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
833 MenuAppend1(menuTrack, ID_TK_MENU_SENDTOPEER, itemstp);
834
835 // Eventually set this menu as the "focused context menu"
836 if (menuFocus != menuAIS) menuFocus = menuTrack;
837 }
838
839 if (seltype & SELTYPE_ROUTEPOINT) {
840 if (!g_bBasicMenus && m_pFoundRoutePoint) {
841 name = m_pFoundRoutePoint->GetName();
842 if (name.IsEmpty()) name = _("Unnamed Waypoint");
843 name.Prepend(_T(" ( ")).Append(_T(" )"));
844 } else
845 name = wxEmptyString;
846 bool blay = false;
847 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
848
849 if (blay) {
850 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
851 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
852 _("Properties") + _T( "..." ));
853
854 if (m_pSelectedRoute && m_pSelectedRoute->IsActive())
855 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
856 } else {
857 menuWaypoint = new wxMenu(_("Waypoint") + name);
858 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
859 _("Properties") + _T( "..." ));
860 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
861 if (m_pSelectedRoute->m_pRouteActivePoint != m_pFoundRoutePoint)
862 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
863 }
864
865 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
866 if (m_pSelectedRoute->m_pRouteActivePoint == m_pFoundRoutePoint) {
867 int indexActive = m_pSelectedRoute->GetIndexOf(
868 m_pSelectedRoute->m_pRouteActivePoint);
869 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints())
870 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTNXTPOINT,
871 _("Activate Next Waypoint"));
872 }
873 }
874 if (m_pSelectedRoute && m_pSelectedRoute->GetnPoints() > 2) {
875 MenuAppend1(menuWaypoint, ID_RT_MENU_REMPOINT, _("Remove from Route"));
876
877 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
878 if (m_SelectedIdx > 1 && m_SelectedIdx < m_pSelectedRoute->GetnPoints())
879 MenuAppend1(menuWaypoint, ID_RT_MENU_SPLIT_WPT,
880 _("Split Route at Waypoint"));
881 }
882
883 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
884
885 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != _T("mob"))
886 MenuAppend1(menuWaypoint, ID_RT_MENU_DELPOINT, _("Delete"));
887
888 // #ifndef __ANDROID__
889 wxString port = parent->FindValidUploadPort();
890 parent->m_active_upload_port = port;
891 wxString item = _("Send to GPS");
892 if (!port.IsEmpty()) {
893 item.Append(_T(" ( "));
894 item.Append(port);
895 item.Append(_T(" )"));
896 }
897 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
898
899 if (!port.IsEmpty()) {
900 wxString item = _("Send to new GPS");
901 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTONEWGPS, item);
902 }
903
904 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
905 SYMBOL_STP_TITLE); // Send to Peer
906 }
907
908 // Eventually set this menu as the "focused context menu"
909 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
910 }
911
912 if (seltype & SELTYPE_MARKPOINT) {
913 if (!g_bBasicMenus && m_pFoundRoutePoint) {
914 name = m_pFoundRoutePoint->GetName();
915 if (name.IsEmpty()) name = _("Unnamed Mark");
916 name.Prepend(_T(" ( ")).Append(_T(" )"));
917 } else
918 name = wxEmptyString;
919 bool blay = false;
920 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
921
922 if (blay) {
923 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
924 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
925 _("Properties") + _T( "..." ));
926 } else {
927 menuWaypoint = new wxMenu(_("Mark") + name);
928 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
929 _("Properties") + _T( "..." ));
930
931 if (!g_pRouteMan->GetpActiveRoute())
932 MenuAppend1(menuWaypoint, ID_WP_MENU_GOTO, _("Navigate To This"));
933
934 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
935
936 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != _T("mob"))
937 MenuAppend1(menuWaypoint, ID_WP_MENU_DELPOINT, _("Delete"));
938
939 // #ifndef __ANDROID__
940 wxString port = parent->FindValidUploadPort();
941 parent->m_active_upload_port = port;
942 wxString item = _("Send to GPS");
943 if (!port.IsEmpty()) {
944 item.Append(_T(" ( "));
945 item.Append(port);
946 item.Append(_T(" )"));
947 }
948 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
949
950 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
951 SYMBOL_STP_TITLE); // Send to Peer
952 // #endif
953
954 if ((m_pFoundRoutePoint == pAnchorWatchPoint1) ||
955 (m_pFoundRoutePoint == pAnchorWatchPoint2))
956 MenuAppend1(menuWaypoint, ID_WP_MENU_CLEAR_ANCHORWATCH,
957 _("Clear Anchor Watch"));
958 else {
959 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
960 ((NULL == pAnchorWatchPoint1) || (NULL == pAnchorWatchPoint2))) {
961 double dist;
962 double brg;
963 DistanceBearingMercator(m_pFoundRoutePoint->m_lat,
964 m_pFoundRoutePoint->m_lon, gLat, gLon, &brg,
965 &dist);
966 if (dist * 1852. <= g_nAWMax)
967 MenuAppend1(menuWaypoint, ID_WP_MENU_SET_ANCHORWATCH,
968 _("Set Anchor Watch"));
969 }
970 }
971 }
972 // Eventually set this menu as the "focused context menu"
973 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
974 }
975
976 // Add plugin context items to the correct menu
977 AddPluginContextMenuItems(contextMenu, menuRoute, menuTrack, menuWaypoint,
978 menuAIS);
979
980 /*add the relevant submenus*/
981 enum { WPMENU = 1, TKMENU = 2, RTMENU = 4, MMMENU = 8 };
982 int sub_menu = 0;
983 if (!g_bBasicMenus && menuFocus != contextMenu) {
984 if (global_color_scheme != GLOBAL_COLOR_SCHEME_DUSK &&
985 global_color_scheme != GLOBAL_COLOR_SCHEME_NIGHT) {
986 menuFocus->AppendSeparator();
987 }
988
989 wxMenuItem *subMenu1;
990 if (menuWaypoint && menuFocus != menuWaypoint) {
991 subMenu1 =
992 menuFocus->AppendSubMenu(menuWaypoint, menuWaypoint->GetTitle());
993 SetMenuItemFont1(subMenu1);
994 sub_menu |= WPMENU;
995#ifdef __WXMSW__
996 menuWaypoint->SetTitle(wxEmptyString);
997#endif
998 }
999 if (menuTrack && menuFocus != menuTrack) {
1000 subMenu1 = menuFocus->AppendSubMenu(menuTrack, menuTrack->GetTitle());
1001 SetMenuItemFont1(subMenu1);
1002 sub_menu |= TKMENU;
1003#ifdef __WXMSW__
1004 menuTrack->SetTitle(wxEmptyString);
1005#endif
1006 }
1007 if (menuRoute && menuFocus != menuRoute) {
1008 subMenu1 = menuFocus->AppendSubMenu(menuRoute, menuRoute->GetTitle());
1009 SetMenuItemFont1(subMenu1);
1010 sub_menu |= RTMENU;
1011#ifdef __WXMSW__
1012 menuRoute->SetTitle(wxEmptyString);
1013#endif
1014 }
1015 subMenu1 = menuFocus->AppendSubMenu(contextMenu, _("Main Menu"));
1016 SetMenuItemFont1(subMenu1);
1017 sub_menu |= MMMENU;
1018 }
1019
1020 if (!subMenuChart->GetMenuItemCount()) contextMenu->Destroy(subItemChart);
1021
1022 // Add the Tide/Current selections if the item was not activated by shortcut
1023 // in right-click handlers
1024 bool bsep = false;
1025 if (seltype & SELTYPE_TIDEPOINT) {
1026 menuFocus->AppendSeparator();
1027 bsep = true;
1028 MenuAppend1(menuFocus, ID_DEF_MENU_TIDEINFO, _("Show Tide Information"));
1029 }
1030
1031 if (seltype & SELTYPE_CURRENTPOINT) {
1032 if (!bsep) menuFocus->AppendSeparator();
1033 MenuAppend1(menuFocus, ID_DEF_MENU_CURRENTINFO,
1034 _("Show Current Information"));
1035 }
1036
1037 // Invoke the correct focused drop-down menu
1038
1039#ifdef __ANDROID__
1040 androidEnableBackButton(false);
1041 androidEnableOptionsMenu(false);
1042
1043 setMenuStyleSheet(menuRoute, GetOCPNGUIScaledFont(_("Menu")));
1044 setMenuStyleSheet(menuWaypoint, GetOCPNGUIScaledFont(_("Menu")));
1045 setMenuStyleSheet(menuTrack, GetOCPNGUIScaledFont(_("Menu")));
1046 setMenuStyleSheet(menuAIS, GetOCPNGUIScaledFont(_("Menu")));
1047#endif
1048
1049 parent->PopupMenu(menuFocus, x, y);
1050
1051#ifdef __ANDROID__
1052 androidEnableBackButton(true);
1053 androidEnableOptionsMenu(true);
1054#endif
1055
1056 /* Cleanup if necessary.
1057 Do not delete menus witch are submenu as they will be deleted by their parent
1058 menu. This could create a crash*/
1059 delete menuAIS;
1060 if (!(sub_menu & MMMENU)) delete contextMenu;
1061 if (!(sub_menu & RTMENU)) delete menuRoute;
1062 if (!(sub_menu & TKMENU)) delete menuTrack;
1063 if (!(sub_menu & WPMENU)) delete menuWaypoint;
1064}
1065
1066void CanvasMenuHandler::AddPluginContextMenuItems(wxMenu *contextMenu,
1067 wxMenu *menuRoute,
1068 wxMenu *menuTrack,
1069 wxMenu *menuWaypoint,
1070 wxMenu *menuAIS) {
1071 // Give the plugins a chance to update their menu items
1072 g_pi_manager->PrepareAllPluginContextMenus();
1073
1074 // Add PlugIn Context Menu items
1075 ArrayOfPlugInMenuItems item_array =
1076 g_pi_manager->GetPluginContextMenuItemArray();
1077
1078 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1079 PlugInMenuItemContainer *pimis = item_array[i];
1080 if (!pimis->b_viz) continue;
1081
1082 wxMenu *submenu = NULL;
1083 if (pimis->pmenu_item->GetSubMenu()) {
1084 // Create a clone of the submenu referenced in the PlugInMenuItemContainer
1085 auto submenu_proto = pimis->pmenu_item->GetSubMenu();
1086 submenu = new wxMenu();
1087 const wxMenuItemList &items =
1088 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1089 for (wxMenuItemList::const_iterator it = items.begin(); it != items.end();
1090 ++it) {
1091 int id = (*it)->GetId();
1092 wxMenuItem *psmi =
1093 new wxMenuItem(submenu, id, (*it)->GetItemLabelText(),
1094 (*it)->GetHelp(), (*it)->GetKind());
1095
1096#ifdef __WXMSW__
1097 psmi->SetFont(m_scaledFont);
1098#endif
1099
1100#ifdef __ANDROID__
1101 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1102 psmi->SetFont(sFont);
1103#endif
1104
1105 PrepareMenuItem(psmi);
1106 submenu->Append(psmi);
1107 psmi->Check((*it)->IsChecked());
1108 }
1109 }
1110
1111 wxMenuItem *pmi = new wxMenuItem(
1112 contextMenu, pimis->id, pimis->pmenu_item->GetItemLabelText(),
1113 pimis->pmenu_item->GetHelp(), pimis->pmenu_item->GetKind(), submenu);
1114#ifdef __WXMSW__
1115 pmi->SetFont(m_scaledFont);
1116#endif
1117
1118#ifdef __ANDROID__
1119 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1120 pmi->SetFont(sFont);
1121#endif
1122
1123 PrepareMenuItem(pmi);
1124
1125 wxMenu *dst = contextMenu;
1126 if (pimis->m_in_menu == "Waypoint")
1127 dst = menuWaypoint;
1128 else if (pimis->m_in_menu == "Route")
1129 dst = menuRoute;
1130 else if (pimis->m_in_menu == "Track")
1131 dst = menuTrack;
1132 else if (pimis->m_in_menu == "AIS")
1133 dst = menuAIS;
1134
1135 if (dst != NULL) {
1136 dst->Append(pmi);
1137 dst->Enable(pimis->id, !pimis->b_grey);
1138 }
1139 }
1140}
1141
1142void CanvasMenuHandler::PopupMenuHandler(wxCommandEvent &event) {
1143 RoutePoint *pLast;
1144
1145 wxPoint r;
1146 double zlat, zlon;
1147
1148 int splitMode = 0; // variables for split
1149 bool dupFirstWpt = true, showRPD;
1150
1151 parent->GetCanvasPixPoint(popx * parent->GetDisplayScale(),
1152 popy * parent->GetDisplayScale(), zlat, zlon);
1153
1154 switch (event.GetId()) {
1155 case ID_DEF_MENU_MAX_DETAIL:
1156 vLat = zlat;
1157 vLon = zlon;
1158 parent->ClearbFollow();
1159
1160 parent->parent_frame->DoChartUpdate();
1161
1162 parent->SelectChartFromStack(0, false, CHART_TYPE_DONTCARE,
1163 CHART_FAMILY_RASTER);
1164 break;
1165
1166 case ID_DEF_MENU_SCALE_IN:
1167 parent->DoCanvasStackDelta(-1);
1168 break;
1169
1170 case ID_DEF_MENU_SCALE_OUT:
1171 parent->DoCanvasStackDelta(1);
1172 break;
1173
1174 case ID_UNDO:
1175 parent->undo->UndoLastAction();
1176 parent->InvalidateGL();
1177 parent->Refresh(false);
1178 break;
1179
1180 case ID_REDO:
1181 parent->undo->RedoNextAction();
1182 parent->InvalidateGL();
1183 parent->Refresh(false);
1184 break;
1185
1186 case ID_DEF_MENU_MOVE_BOAT_HERE:
1187 gLat = zlat;
1188 gLon = zlon;
1189 gFrame->UpdateStatusBar();
1190 break;
1191
1192 case ID_DEF_MENU_GOTO_HERE: {
1193 RoutePoint *pWP_dest = new RoutePoint(zlat, zlon, g_default_wp_icon,
1194 wxEmptyString, wxEmptyString);
1195 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP_dest);
1196
1197 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1198 wxEmptyString, wxEmptyString);
1199 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1200
1201 Route *temp_route = new Route();
1202 pRouteList->Append(temp_route);
1203
1204 temp_route->AddPoint(pWP_src);
1205 temp_route->AddPoint(pWP_dest);
1206
1207 pSelect->AddSelectableRouteSegment(gLat, gLon, zlat, zlon, pWP_src,
1208 pWP_dest, temp_route);
1209
1210 temp_route->m_RouteNameString = _("Temporary GOTO Route");
1211 temp_route->m_RouteStartString = _("Here");
1212 ;
1213 temp_route->m_RouteEndString = _("There");
1214
1215 temp_route->m_bDeleteOnArrival = true;
1216
1217 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1218
1219 g_pRouteMan->ActivateRoute(temp_route, pWP_dest);
1220
1221 break;
1222 }
1223
1224 case ID_DEF_MENU_DROP_WP: {
1225 RoutePoint *pWP = new RoutePoint(zlat, zlon, g_default_wp_icon,
1226 wxEmptyString, wxEmptyString);
1227 pWP->m_bIsolatedMark = true; // This is an isolated mark
1228 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP);
1229 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1230
1231 if (!RoutePointGui(*pWP).IsVisibleSelectable(this->parent))
1232 RoutePointGui(*pWP).ShowScaleWarningMessage(parent);
1233
1234 if (RouteManagerDialog::getInstanceFlag()) {
1235 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1236 pRouteManagerDialog->UpdateWptListCtrl();
1237 }
1238 }
1239
1240 parent->undo->BeforeUndoableAction(Undo_CreateWaypoint, pWP,
1241 Undo_HasParent, NULL);
1242 parent->undo->AfterUndoableAction(NULL);
1243 gFrame->RefreshAllCanvas(false);
1244 gFrame->InvalidateAllGL();
1245 g_FlushNavobjChanges = true;
1246 break;
1247 }
1248
1249 case ID_DEF_MENU_NEW_RT: {
1250 parent->StartRoute();
1251 break;
1252 }
1253
1254 case ID_DEF_MENU_AISTARGETLIST:
1255 parent->ShowAISTargetList();
1256 break;
1257
1258 case ID_DEF_MENU_AIS_CPAWARNING:
1259 parent->ToggleCPAWarn();
1260 break;
1261
1262 case ID_WP_MENU_GOTO: {
1263 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1264 wxEmptyString, wxEmptyString);
1265 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1266
1267 Route *temp_route = new Route();
1268 pRouteList->Append(temp_route);
1269
1270 temp_route->AddPoint(pWP_src);
1271 temp_route->AddPoint(m_pFoundRoutePoint);
1272 m_pFoundRoutePoint->SetShared(true);
1273
1274 pSelect->AddSelectableRouteSegment(gLat, gLon, m_pFoundRoutePoint->m_lat,
1275 m_pFoundRoutePoint->m_lon, pWP_src,
1276 m_pFoundRoutePoint, temp_route);
1277
1278 wxString name = m_pFoundRoutePoint->GetName();
1279 if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
1280 wxString rteName = _("Go to ");
1281 rteName.Append(name);
1282 temp_route->m_RouteNameString = rteName;
1283 temp_route->m_RouteStartString = _("Here");
1284 ;
1285 temp_route->m_RouteEndString = name;
1286 temp_route->m_bDeleteOnArrival = true;
1287
1288 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1289
1290 g_pRouteMan->ActivateRoute(temp_route, m_pFoundRoutePoint);
1291
1292 break;
1293 }
1294
1295 case ID_DEF_MENU_COGUP:
1296 parent->SetUpMode(COURSE_UP_MODE);
1297 break;
1298
1299 case ID_DEF_MENU_HEADUP:
1300 parent->SetUpMode(HEAD_UP_MODE);
1301 break;
1302
1303 case ID_DEF_MENU_NORTHUP:
1304 parent->SetUpMode(NORTH_UP_MODE);
1305 break;
1306
1307 case ID_DEF_MENU_TOGGLE_FULL:
1308 gFrame->ToggleFullScreen();
1309 break;
1310
1311 case ID_DEF_MENU_GOTOPOSITION:
1312 if (NULL == pGoToPositionDialog) // There is one global instance of the
1313 // Go To Position Dialog
1314 pGoToPositionDialog = new GoToPositionDialog(parent);
1315 pGoToPositionDialog->SetCanvas(parent);
1316 pGoToPositionDialog->CheckPasteBufferForPosition();
1317 pGoToPositionDialog->Show();
1318 break;
1319
1320 case ID_WP_MENU_DELPOINT: {
1321 if (m_pFoundRoutePoint == pAnchorWatchPoint1) {
1322 pAnchorWatchPoint1 = NULL;
1323 g_AW1GUID.Clear();
1324 } else if (m_pFoundRoutePoint == pAnchorWatchPoint2) {
1325 pAnchorWatchPoint2 = NULL;
1326 g_AW2GUID.Clear();
1327 }
1328
1329 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
1330 (m_pFoundRoutePoint->GetIconName() != _T("mob"))) {
1331 // If the WP belongs to an invisible route, we come here instead of to
1332 // ID_RT_MENU_DELPOINT
1333 // Check it, and if so then remove the point from its routes
1334 wxArrayPtrVoid *proute_array =
1335 g_pRouteMan->GetRouteArrayContaining(m_pFoundRoutePoint);
1336 if (proute_array) {
1337 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1338 delete proute_array;
1339 } else {
1340 parent->undo->BeforeUndoableAction(
1341 Undo_DeleteWaypoint, m_pFoundRoutePoint, Undo_IsOrphanded,
1342 NULL /*m_pFoundPoint*/);
1343 NavObj_dB::GetInstance().DeleteRoutePoint(m_pFoundRoutePoint);
1344 pSelect->DeleteSelectablePoint(m_pFoundRoutePoint,
1345 SELTYPE_ROUTEPOINT);
1346 if (NULL != pWayPointMan)
1347 pWayPointMan->RemoveRoutePoint(m_pFoundRoutePoint);
1348 parent->undo->AfterUndoableAction(NULL);
1349 }
1350
1351 if (g_pMarkInfoDialog) {
1352 g_pMarkInfoDialog->ClearData();
1353 }
1354
1355 if (RouteManagerDialog::getInstanceFlag()) {
1356 if (pRouteManagerDialog) {
1357 if (pRouteManagerDialog->IsShown())
1358 pRouteManagerDialog->UpdateWptListCtrl();
1359 }
1360 }
1361
1362 gFrame->RefreshAllCanvas(false);
1363 gFrame->InvalidateAllGL();
1364 }
1365 break;
1366 }
1367 case ID_WP_MENU_PROPERTIES:
1368 parent->ShowMarkPropertiesDialog(m_pFoundRoutePoint);
1369 break;
1370
1371 case ID_WP_MENU_CLEAR_ANCHORWATCH: {
1372 wxString guid = wxEmptyString;
1373 if (pAnchorWatchPoint1 == m_pFoundRoutePoint) {
1374 pAnchorWatchPoint1 = NULL;
1375 guid = g_AW1GUID;
1376 g_AW1GUID.Clear();
1377 } else if (pAnchorWatchPoint2 == m_pFoundRoutePoint) {
1378 pAnchorWatchPoint2 = NULL;
1379 guid = g_AW2GUID;
1380 g_AW2GUID.Clear();
1381 }
1382 if (!guid.IsEmpty()) {
1383 wxJSONValue v;
1384 v[_T("GUID")] = guid;
1385 wxString msg_id(_T("OCPN_ANCHOR_WATCH_CLEARED"));
1386 SendJSONMessageToAllPlugins(msg_id, v);
1387 }
1388 break;
1389 }
1390
1391 case ID_WP_MENU_SET_ANCHORWATCH: {
1392 wxString guid = wxEmptyString;
1393 if (pAnchorWatchPoint1 == NULL) {
1394 pAnchorWatchPoint1 = m_pFoundRoutePoint;
1395 g_AW1GUID = pAnchorWatchPoint1->m_GUID;
1396 guid = g_AW1GUID;
1397 wxString nn;
1398 nn = m_pFoundRoutePoint->GetName();
1399 if (nn.IsNull()) {
1400 nn.Printf(_T("%d m"), g_nAWDefault);
1401 m_pFoundRoutePoint->SetName(nn);
1402 }
1403 } else if (pAnchorWatchPoint2 == NULL) {
1404 pAnchorWatchPoint2 = m_pFoundRoutePoint;
1405 g_AW2GUID = pAnchorWatchPoint2->m_GUID;
1406 guid = g_AW2GUID;
1407 wxString nn;
1408 nn = m_pFoundRoutePoint->GetName();
1409 if (nn.IsNull()) {
1410 nn.Printf(_T("%d m"), g_nAWDefault);
1411 m_pFoundRoutePoint->SetName(nn);
1412 }
1413 }
1414 if (!guid.IsEmpty()) {
1415 wxJSONValue v;
1416 v[_T("GUID")] = guid;
1417 wxString msg_id(_T("OCPN_ANCHOR_WATCH_SET"));
1418 SendJSONMessageToAllPlugins(msg_id, v);
1419 }
1420 break;
1421 }
1422
1423 case ID_DEF_MENU_ACTIVATE_MEASURE:
1424 parent->StartMeasureRoute();
1425 break;
1426
1427 case ID_DEF_MENU_DEACTIVATE_MEASURE:
1428 parent->CancelMeasureRoute();
1429 // gFrame->SurfaceAllCanvasToolbars();
1430 parent->InvalidateGL();
1431 parent->Refresh(false);
1432 break;
1433
1434 case ID_DEF_MENU_CM93OFFSET_DIALOG: {
1435 if (NULL == g_pCM93OffsetDialog) {
1436 g_pCM93OffsetDialog = new CM93OffsetDialog(parent->parent_frame);
1437 }
1438
1439 cm93compchart *pch = NULL;
1440 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
1441 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
1442 pch = (cm93compchart *)parent->m_singleChart;
1443 }
1444
1445 if (g_pCM93OffsetDialog) {
1446 g_pCM93OffsetDialog->SetCM93Chart(pch);
1447 g_pCM93OffsetDialog->Show();
1448 g_pCM93OffsetDialog->UpdateMCOVRList(parent->GetVP());
1449 }
1450
1451 break;
1452 }
1453 case ID_DEF_MENU_QUERY: {
1454 parent->ShowObjectQueryWindow(popx, popy, zlat, zlon);
1455 break;
1456 }
1457 case ID_DEF_MENU_AIS_QUERY: {
1458 ShowAISTargetQueryDialog(parent, m_FoundAIS_MMSI);
1459 break;
1460 }
1461
1462 case ID_DEF_MENU_AIS_CPA: {
1463 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1464 if (myptarget) myptarget->Toggle_AIS_CPA();
1465 break;
1466 }
1467
1468 case ID_DEF_MENU_AISSHOWTRACK: {
1469 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1470 if (myptarget) myptarget->ToggleShowTrack();
1471 break;
1472 }
1473
1474 case ID_DEF_MENU_COPY_MMSI: {
1475 // Write MMSI # as text to the clipboard
1476 if (wxTheClipboard->Open()) {
1477 wxTheClipboard->SetData(new wxTextDataObject(
1478 wxString::Format(wxT("%09d"), m_FoundAIS_MMSI)));
1479 wxTheClipboard->Close();
1480 }
1481 break;
1482 }
1483
1484 case ID_DEF_MENU_QUILTREMOVE: {
1485 if (parent->GetVP().b_quilt) {
1486 int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
1487 parent->GetVP(), wxPoint(popx, popy));
1488 parent->RemoveChartFromQuilt(dbIndex);
1489
1490 parent->ReloadVP();
1491 }
1492
1493 break;
1494 }
1495
1496 case ID_DEF_MENU_CURRENTINFO: {
1497 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1498 parent->Refresh(false);
1499
1500 break;
1501 }
1502
1503 case ID_DEF_MENU_TIDEINFO: {
1504 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1505 parent->Refresh(false);
1506
1507 break;
1508 }
1509
1510 case ID_DGB_MENU_NMEA_WINDOW:
1511 m_nmea_log->Show();
1512 m_nmea_log->Raise();
1513 break;
1514
1515 case ID_RT_MENU_REVERSE: {
1516 if (m_pSelectedRoute->m_bIsInLayer) break;
1517
1518 int ask_return =
1519 OCPNMessageBox(parent, g_pRouteMan->GetRouteReverseMessage(),
1520 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1521
1522 if (ask_return != wxID_CANCEL) {
1523 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1524 m_pSelectedRoute->Reverse(ask_return == wxID_YES);
1525 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1526
1527 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1528
1529 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1530 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute);
1531 // pNew->UpdateProperties();
1532 }
1533 gFrame->InvalidateAllGL();
1534 gFrame->RefreshAllCanvas();
1535 }
1536 break;
1537 }
1538
1539 case ID_RT_MENU_SHOWNAMES: {
1540 if (m_pSelectedRoute) {
1541 m_pSelectedRoute->ShowWaypointNames(
1542 !m_pSelectedRoute->AreWaypointNamesVisible());
1543 }
1544
1545 break;
1546 }
1547
1548 case ID_RT_MENU_RESEQUENCE: {
1549 if (m_pSelectedRoute) {
1550 if (m_pSelectedRoute->m_bIsInLayer) break;
1551
1552 int ask_return =
1553 OCPNMessageBox(parent, g_pRouteMan->GetRouteResequenceMessage(),
1554 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1555
1556 if (ask_return != wxID_CANCEL) {
1557 m_pSelectedRoute->RenameRoutePoints();
1558 }
1559
1560 gFrame->InvalidateAllGL();
1561 gFrame->RefreshAllCanvas();
1562 }
1563
1564 break;
1565 }
1566
1567 case ID_RT_MENU_DELETE: {
1568 bool confirmed = RouteGui::OnDelete(parent);
1569
1570 if (confirmed) {
1571 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1572 g_pRouteMan->DeactivateRoute();
1573
1574 if (m_pSelectedRoute->m_bIsInLayer) break;
1575
1576 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1577 if (!g_pRouteMan->DeleteRoute(m_pSelectedRoute)) break;
1578
1579 if (RouteManagerDialog::getInstanceFlag()) {
1580 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1581 pRouteManagerDialog->UpdateRouteListCtrl();
1582 }
1583
1584 if (g_pMarkInfoDialog && g_pMarkInfoDialog->IsShown()) {
1585 g_pMarkInfoDialog->ValidateMark();
1586 g_pMarkInfoDialog->UpdateProperties();
1587 }
1588
1589 parent->undo->InvalidateUndo();
1590
1591 gFrame->InvalidateAllGL();
1592 gFrame->RefreshAllCanvas();
1593 }
1594 break;
1595 }
1596
1597 case ID_RT_MENU_ACTIVATE: {
1598 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1599
1600 // If this is an auto-created MOB route, always select the second point
1601 // (the MOB)
1602 // as the destination.
1603 RoutePoint *best_point;
1604 if (m_pSelectedRoute) {
1605 if (wxNOT_FOUND ==
1606 m_pSelectedRoute->m_RouteNameString.Find(_T("MOB"))) {
1607 best_point = g_pRouteMan->FindBestActivatePoint(
1608 m_pSelectedRoute, gLat, gLon, gCog, gSog);
1609 } else
1610 best_point = m_pSelectedRoute->GetPoint(2);
1611
1612 g_pRouteMan->ActivateRoute(m_pSelectedRoute, best_point);
1613 m_pSelectedRoute->m_bRtIsSelected = false;
1614 }
1615
1616 break;
1617 }
1618
1619 case ID_RT_MENU_DEACTIVATE:
1620 g_pRouteMan->DeactivateRoute();
1621 m_pSelectedRoute->m_bRtIsSelected = false;
1622
1623 break;
1624
1625 case ID_RT_MENU_INSERT: {
1626 if (m_pSelectedRoute->m_bIsInLayer) break;
1627 bool rename = false;
1628 m_pSelectedRoute->InsertPointAfter(m_pFoundRoutePoint, zlat, zlon,
1629 rename);
1630
1631 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1632 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1633
1634 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1635 pSelect->AddAllSelectableRoutePoints(m_pSelectedRoute);
1636
1637 // As a special case (which comes up often)...
1638 // If the inserted waypoint is on the active leg of an active route
1639 /* if(m_pSelectedRoute->m_bRtIsActive)
1640 {
1641 if(m_pSelectedRoute->m_nRouteActivePoint == np + 1)
1642 {
1643 pNew_Point = m_pSelectedRoute->GetPoint(np + 2);
1644 pRouteMan->ActivateRoutePoint(m_pSelectedRoute, pNew_Point);
1645 }
1646 }
1647 */
1648 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1649
1650 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1651 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1652 }
1653
1654 break;
1655 }
1656
1657 case ID_RT_MENU_APPEND:
1658
1659 if (m_pSelectedRoute->m_bIsInLayer) break;
1660
1661 parent->m_pMouseRoute = m_pSelectedRoute;
1662 parent->m_routeState = m_pSelectedRoute->GetnPoints() + 1;
1663 parent->m_pMouseRoute->m_lastMousePointIndex =
1664 m_pSelectedRoute->GetnPoints();
1665 parent->m_pMouseRoute->SetHiLite(50);
1666
1667 pLast = m_pSelectedRoute->GetLastPoint();
1668
1669 parent->m_prev_rlat = pLast->m_lat;
1670 parent->m_prev_rlon = pLast->m_lon;
1671 parent->m_prev_pMousePoint = pLast;
1672
1673 parent->m_bAppendingRoute = true;
1674
1675 parent->SetCursor(*parent->pCursorPencil);
1676#ifdef __ANDROID__
1677 androidSetRouteAnnunciator(true);
1678#endif
1679
1680 parent->HideGlobalToolbar();
1681
1682 break;
1683
1684 case ID_RT_MENU_SPLIT_LEG: // split route around a leg
1685 splitMode++;
1686 dupFirstWpt = false;
1687 case ID_RT_MENU_SPLIT_WPT: // split route at a wpt
1688
1689 showRPD = (pRoutePropDialog && pRoutePropDialog->IsShown());
1690
1691 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1692 g_pRouteMan->DeactivateRoute();
1693
1694 m_pHead = new Route();
1695 m_pTail = new Route();
1696 m_pHead->CloneRoute(m_pSelectedRoute, 1, m_SelectedIdx, _("_A"));
1697 m_pTail->CloneRoute(m_pSelectedRoute, m_SelectedIdx + splitMode,
1698 m_pSelectedRoute->GetnPoints(), _("_B"), dupFirstWpt);
1699 pRouteList->Append(m_pHead);
1700 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1701
1702 pRouteList->Append(m_pTail);
1703 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1704
1705 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1706
1707 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1708 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1709 g_pRouteMan->DeleteRoute(m_pSelectedRoute);
1710 pSelect->AddAllSelectableRouteSegments(m_pTail);
1711 pSelect->AddAllSelectableRoutePoints(m_pTail);
1712 pSelect->AddAllSelectableRouteSegments(m_pHead);
1713 pSelect->AddAllSelectableRoutePoints(m_pHead);
1714
1715 if (showRPD) {
1716 pRoutePropDialog->SetRouteAndUpdate(m_pHead);
1717 pRoutePropDialog->Show();
1718 }
1719 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog &&
1720 (pRouteManagerDialog->IsShown()))
1721 pRouteManagerDialog->UpdateRouteListCtrl();
1722 break;
1723
1724 case ID_RT_MENU_COPY:
1725 if (m_pSelectedRoute) Kml::CopyRouteToClipboard(m_pSelectedRoute);
1726 break;
1727
1728 case ID_TK_MENU_COPY:
1729 if (m_pSelectedTrack) Kml::CopyTrackToClipboard(m_pSelectedTrack);
1730 break;
1731
1732 case ID_WPT_MENU_COPY:
1733 if (m_pFoundRoutePoint) Kml::CopyWaypointToClipboard(m_pFoundRoutePoint);
1734 break;
1735
1736 case ID_WPT_MENU_SENDTOGPS:
1737 if (m_pFoundRoutePoint) {
1738 if (parent->m_active_upload_port.Length())
1739 RoutePointGui(*m_pFoundRoutePoint)
1740 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), NULL);
1741 else {
1742 SendToGpsDlg dlg;
1743 dlg.SetWaypoint(m_pFoundRoutePoint);
1744 wxFont fo = GetOCPNGUIScaledFont(_("Dialog"));
1745 dlg.SetFont(fo);
1746
1747 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1748 dlg.ShowModal();
1749 }
1750 }
1751 break;
1752
1753 case ID_WPT_MENU_SENDTONEWGPS:
1754 if (m_pFoundRoutePoint) {
1755 SendToGpsDlg dlg;
1756 dlg.SetWaypoint(m_pFoundRoutePoint);
1757
1758 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1759 dlg.ShowModal();
1760 }
1761 break;
1762
1763 case ID_WPT_MENU_SENDTOPEER:
1764 if (m_pFoundRoutePoint) {
1765 SendToPeerDlg dlg;
1766 dlg.SetWaypoint(m_pFoundRoutePoint);
1767
1768 // Perform initial scan, if necessary
1769
1770 // Check for stale cache...
1771 MdnsCache::GetInstance().Validate();
1772 if (MdnsCache::GetInstance().GetCache().empty())
1773 dlg.SetScanOnCreate(true);
1774
1775 dlg.SetScanTime(5); // seconds
1776 dlg.Create(NULL, -1, _("Send Waypoint to OpenCPN Peer") + _T( "..." ),
1777 _T(""));
1778 dlg.ShowModal();
1779 }
1780 break;
1781
1782 case ID_RT_MENU_SENDTOGPS:
1783 if (m_pSelectedRoute) {
1784 if (parent->m_active_upload_port.Length())
1785 RouteGui(*m_pSelectedRoute)
1786 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), true,
1787 NULL);
1788 else {
1789 SendToGpsDlg dlg;
1790 dlg.SetRoute(m_pSelectedRoute);
1791
1792 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1793 dlg.ShowModal();
1794 }
1795 }
1796 break;
1797
1798 case ID_RT_MENU_SENDTONEWGPS:
1799 if (m_pSelectedRoute) {
1800 SendToGpsDlg dlg;
1801 dlg.SetRoute(m_pSelectedRoute);
1802
1803 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1804 dlg.ShowModal();
1805 }
1806 break;
1807
1808 case ID_RT_MENU_SENDTOPEER:
1809 if (m_pSelectedRoute) {
1810 SendToPeerDlg dlg;
1811 dlg.SetRoute(m_pSelectedRoute);
1812
1813 // Perform initial scan, if necessary
1814
1815 // Check for stale cache...
1816 MdnsCache::GetInstance().Validate();
1817 if (MdnsCache::GetInstance().GetCache().empty())
1818 dlg.SetScanOnCreate(true);
1819
1820 dlg.SetScanTime(5); // seconds
1821 dlg.Create(NULL, -1, _("Send Route to OpenCPN Peer") + _T( "..." ),
1822 _T(""));
1823 dlg.ShowModal();
1824 }
1825 break;
1826
1827 case ID_PASTE_WAYPOINT:
1828 pupHandler_PasteWaypoint();
1829 break;
1830
1831 case ID_PASTE_ROUTE:
1832 pupHandler_PasteRoute();
1833 break;
1834
1835 case ID_PASTE_TRACK:
1836 pupHandler_PasteTrack();
1837 break;
1838
1839 case ID_RT_MENU_DELPOINT:
1840 if (m_pSelectedRoute) {
1841 if (m_pSelectedRoute->m_bIsInLayer) break;
1842
1843 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1844
1845 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1846 // Selected route may have been deleted as one-point route, so
1847 // check it
1848 if (g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
1849 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1850 } else
1851 pRoutePropDialog->Hide();
1852 }
1853
1854 if (RouteManagerDialog::getInstanceFlag()) {
1855 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1856 pRouteManagerDialog->UpdateWptListCtrl();
1857 pRouteManagerDialog->UpdateRouteListCtrl();
1858 }
1859 }
1860
1861 gFrame->InvalidateAllGL();
1862 gFrame->RefreshAllCanvas(true);
1863 }
1864
1865 break;
1866
1867 case ID_RT_MENU_REMPOINT:
1868 if (m_pSelectedRoute) {
1869 if (m_pSelectedRoute->m_bIsInLayer) break;
1870 g_pRouteMan->RemovePointFromRoute(m_pFoundRoutePoint, m_pSelectedRoute,
1871 parent->m_routeState);
1872 gFrame->InvalidateAllGL();
1873 gFrame->RefreshAllCanvas();
1874 }
1875 break;
1876
1877 case ID_RT_MENU_ACTPOINT:
1878 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1879 g_pRouteMan->ActivateRoutePoint(m_pSelectedRoute, m_pFoundRoutePoint);
1880 m_pSelectedRoute->m_bRtIsSelected = false;
1881 }
1882
1883 break;
1884
1885 case ID_RT_MENU_DEACTPOINT:
1886 break;
1887
1888 case ID_RT_MENU_ACTNXTPOINT:
1889 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1890 g_pRouteMan->ActivateNextPoint(m_pSelectedRoute, true);
1891 m_pSelectedRoute->m_bRtIsSelected = false;
1892 }
1893
1894 break;
1895
1896 case ID_RT_MENU_PROPERTIES: {
1897 parent->ShowRoutePropertiesDialog(_("Route Properties"),
1898 m_pSelectedRoute);
1899 break;
1900 }
1901
1902 case ID_TK_MENU_PROPERTIES: {
1903 parent->ShowTrackPropertiesDialog(m_pSelectedTrack);
1904 break;
1905 }
1906
1907 case ID_TK_MENU_DELETE: {
1908 int dlg_return = wxID_YES;
1909 if (g_bConfirmObjectDelete) {
1910 dlg_return = OCPNMessageBox(
1911 parent, _("Are you sure you want to delete this track?"),
1912 _("OpenCPN Track Delete"),
1913 (long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
1914 }
1915
1916 if (dlg_return == wxID_YES) {
1917 if (m_pSelectedTrack == g_pActiveTrack)
1918 m_pSelectedTrack = parent->parent_frame->TrackOff();
1919 g_pAIS->DeletePersistentTrack(m_pSelectedTrack);
1920 // pConfig->DeleteConfigTrack(m_pSelectedTrack);
1921 NavObj_dB::GetInstance().DeleteTrack(m_pSelectedTrack);
1922 RoutemanGui(*g_pRouteMan).DeleteTrack(m_pSelectedTrack);
1923
1924 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
1925 (pTrackPropDialog->IsShown()) &&
1926 (m_pSelectedTrack == pTrackPropDialog->GetTrack())) {
1927 pTrackPropDialog->Hide();
1928 }
1929
1930 if (RoutePropDlgImpl::getInstanceFlag() && pRouteManagerDialog &&
1931 pRouteManagerDialog->IsShown()) {
1932 pRouteManagerDialog->UpdateTrkListCtrl();
1933 pRouteManagerDialog->UpdateRouteListCtrl();
1934 }
1935 gFrame->InvalidateAllGL();
1936 gFrame->RefreshAllCanvas();
1937 }
1938 break;
1939 }
1940
1941 case ID_TK_MENU_SENDTOPEER:
1942 if (m_pSelectedTrack) {
1943 SendToPeerDlg dlg;
1944 dlg.SetTrack(m_pSelectedTrack);
1945
1946 // Perform initial scan, if necessary
1947
1948 // Check for stale cache...
1949 MdnsCache::GetInstance().Validate();
1950 if (MdnsCache::GetInstance().GetCache().empty())
1951 dlg.SetScanOnCreate(true);
1952
1953 dlg.SetScanTime(5); // seconds
1954 dlg.Create(NULL, -1, _("Send Track to OpenCPN Peer") + _T( "..." ),
1955 _T(""));
1956 dlg.ShowModal();
1957 }
1958 break;
1959
1960 case ID_RC_MENU_SCALE_IN:
1961 parent->parent_frame->DoStackDown(parent);
1962 parent->GetCanvasPointPix(zlat, zlon, &r);
1963 parent->WarpPointer(r.x, r.y);
1964 break;
1965
1966 case ID_RC_MENU_SCALE_OUT:
1967 parent->parent_frame->DoStackUp(parent);
1968 parent->GetCanvasPointPix(zlat, zlon, &r);
1969 parent->WarpPointer(r.x, r.y);
1970 break;
1971
1972 case ID_RC_MENU_ZOOM_IN:
1973 parent->SetVPScale(parent->GetVPScale() * 2);
1974 parent->GetCanvasPointPix(zlat, zlon, &r);
1975 parent->WarpPointer(r.x, r.y);
1976 break;
1977
1978 case ID_RC_MENU_ZOOM_OUT:
1979 parent->SetVPScale(parent->GetVPScale() / 2);
1980 parent->GetCanvasPointPix(zlat, zlon, &r);
1981 parent->WarpPointer(r.x, r.y);
1982 break;
1983
1984 case ID_RC_MENU_FINISH:
1985 parent->FinishRoute();
1986 // gFrame->SurfaceAllCanvasToolbars();
1987 parent->Refresh(false);
1988 g_FlushNavobjChanges = true;
1989 break;
1990
1991 case ID_DEF_ZERO_XTE:
1992 g_pRouteMan->ZeroCurrentXTEToActivePoint();
1993 break;
1994
1995 default: {
1996 // Look for PlugIn Context Menu selections
1997 // If found, make the callback
1998 ArrayOfPlugInMenuItems item_array =
1999 g_pi_manager->GetPluginContextMenuItemArray();
2000
2001 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
2002 PlugInMenuItemContainer *pimis = item_array[i];
2003 int target_id = pimis->id;
2004
2005 // Check submenus, if present.
2006 if (pimis->pmenu_item->GetSubMenu()) {
2007 const wxMenuItemList &items =
2008 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
2009 for (wxMenuItemList::const_iterator it = items.begin();
2010 it != items.end(); ++it) {
2011 if ((*it)->GetId() == event.GetId()) {
2012 target_id = (*it)->GetId();
2013 break;
2014 }
2015 }
2016 }
2017
2018 if (pimis->m_pplugin && (target_id == event.GetId())) {
2019 if (pimis->extended) {
2020 std::string object_type;
2021 std::string object_ident;
2022
2023 if ((pimis->m_in_menu.IsSameAs("Waypoint")) && m_pFoundRoutePoint) {
2024 object_type = "Waypoint";
2025 object_ident = m_pFoundRoutePoint->m_GUID.ToStdString();
2026 } else if ((pimis->m_in_menu.IsSameAs("Route")) &&
2027 m_pSelectedRoute) {
2028 object_type = "Route";
2029 object_ident = m_pSelectedRoute->m_GUID.ToStdString();
2030 } else if ((pimis->m_in_menu.IsSameAs("Track")) &&
2031 m_pSelectedTrack) {
2032 object_type = "Track";
2033 object_ident = m_pSelectedTrack->m_GUID.ToStdString();
2034 } else if ((pimis->m_in_menu.IsSameAs("AIS")) && m_FoundAIS_MMSI) {
2035 object_type = "AIS";
2036 wxString sAIS = wxString::Format("%d", m_FoundAIS_MMSI);
2037 object_ident = sAIS.ToStdString();
2038 }
2039
2040 opencpn_plugin_120 *ppi =
2041 dynamic_cast<opencpn_plugin_120 *>(pimis->m_pplugin);
2042 if (ppi)
2043 ppi->OnContextMenuItemCallbackExt(target_id, object_ident,
2044 object_type, zlat, zlon);
2045 } else {
2046 pimis->m_pplugin->OnContextMenuItemCallback(pimis->id);
2047 }
2048 }
2049 }
2050 break;
2051 }
2052 } // switch
2053
2054 // Chart Groups....
2055 if ((event.GetId() >= ID_DEF_MENU_GROUPBASE) &&
2056 (event.GetId() <=
2057 ID_DEF_MENU_GROUPBASE + (int)g_pGroupArray->GetCount())) {
2058 parent->SetGroupIndex(event.GetId() - ID_DEF_MENU_GROUPBASE);
2059 }
2060
2061 parent->InvalidateGL();
2062
2063 g_click_stop = 0; // Context menu was processed, all is well
2064}
Global state for AIS decoder.
double GetDisplayDIPMult(wxWindow *win)
Get the display scaling factor for DPI-aware rendering.
Represents an active track that is currently being recorded.
Definition track.h:221
Dialog for managing CM93 chart offsets.
Definition cm93.h:547
Base class for all chart types.
Definition chartbase.h:119
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:151
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4567
double GetDisplayScale()
Get the ratio of physical to logical pixel for the display.
Definition chcanv.h:824
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:464
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
Definition chcanv.cpp:5349
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4592
Definition kml.h:54
Dialog for displaying and editing waypoint properties.
Definition MarkInfo.h:212
void Validate()
Check that all entries are accessible, remove stale ones.
Main application frame.
Definition ocpn_frame.h:136
Provides platform-specific support utilities for OpenCPN.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:70
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
Definition route.h:98
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:202
wxString m_RouteStartString
Name or description of the route's starting point.
Definition route.h:251
bool m_bDeleteOnArrival
Flag indicating whether the route should be deleted once navigation reaches the end.
Definition route.h:267
wxString m_RouteEndString
Name or description of the route's ending point.
Definition route.h:256
RoutePoint * m_pRouteActivePoint
Pointer to the currently active waypoint within this route.
Definition route.h:213
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:246
wxString m_GUID
Globally unique identifier for this route.
Definition route.h:272
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
Definition route.h:277
int m_lastMousePointIndex
Index of the most recently interacted with route point.
Definition route.h:297
bool ActivateRoutePoint(Route *pA, RoutePoint *pRP)
Activates a specific waypoint within a route for navigation.
Definition routeman.cpp:344
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
Definition routeman.cpp:194
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
Definition routeman.cpp:419
bool DeleteRoute(Route *pRoute)
Definition routeman.cpp:862
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:279
Dialog for sending routes/waypoints to a GPS device.
Dialog for sending navigation objects to peer devices.
Class TrackPropDlg.
Represents a track, which is a series of connected track points.
Definition track.h:111
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Represents a composite CM93 chart covering multiple scales.
Definition cm93.h:424
virtual void OnContextMenuItemCallback(int id)
Handles context menu item selection.
The JSON value class implementation.
Definition jsonval.h:84
Hooks into gui available in model.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:54
wxFont GetOCPNGUIScaledFont(wxString item)
Retrieves a font optimized for touch and high-resolution interfaces.
Definition gui_lib.cpp:83
MdnsCache mDNS host lookups cache.
mDNS lookup wrappers.
Class NavObj_dB.
Tools to send data to plugins.