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 contextMenu->AppendSubMenu(subMenuDebug, _("Debug"));
715
716 if (seltype & SELTYPE_ROUTESEGMENT) {
717 if (!g_bBasicMenus && m_pSelectedRoute) {
718 name = m_pSelectedRoute->m_RouteNameString;
719 if (name.IsEmpty()) name = _("Unnamed Route");
720 name.Prepend(_T(" ( ")).Append(_T(" )"));
721 } else
722 name = wxEmptyString;
723 bool blay = false;
724 if (m_pSelectedRoute && m_pSelectedRoute->m_bIsInLayer) blay = true;
725
726 if (blay) {
727 menuRoute = new wxMenu(_("Layer Route") + name);
728 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES,
729 _("Properties") + _T( "..." ));
730 if (m_pSelectedRoute) {
731 if (m_pSelectedRoute->IsActive()) {
732 int indexActive = m_pSelectedRoute->GetIndexOf(
733 m_pSelectedRoute->m_pRouteActivePoint);
734 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
735 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
736 _("Activate Next Waypoint"));
737 }
738 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
739 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
740 } else {
741 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
742 }
743 }
744 } else {
745 menuRoute = new wxMenu(_("Route") + name);
746 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES,
747 _("Properties") + _T( "..." ));
748 if (m_pSelectedRoute) {
749 if (m_pSelectedRoute->IsActive()) {
750 int indexActive = m_pSelectedRoute->GetIndexOf(
751 m_pSelectedRoute->m_pRouteActivePoint);
752 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
753 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
754 _("Activate Next Waypoint"));
755 }
756 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
757 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
758 } else {
759 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
760 }
761 }
762 MenuAppend1(menuRoute, ID_RT_MENU_INSERT, _("Insert Waypoint"));
763 MenuAppend1(menuRoute, ID_RT_MENU_APPEND, _("Append Waypoint"));
764 if (!(seltype & SELTYPE_ROUTEPOINT) && m_pSelectedRoute) {
765 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
766 if (m_SelectedIdx > 1 &&
767 m_SelectedIdx < m_pSelectedRoute->GetnPoints() - 1)
768 MenuAppend1(menuRoute, ID_RT_MENU_SPLIT_LEG, _("Split around Leg"));
769 }
770 MenuAppend1(menuRoute, ID_RT_MENU_COPY, _("Copy as KML") + _T( "..." ));
771 MenuAppend1(menuRoute, ID_RT_MENU_DELETE, _("Delete") + _T( "..." ));
772 MenuAppend1(menuRoute, ID_RT_MENU_REVERSE, _("Reverse..."));
773 if (m_pSelectedRoute) {
774 if (m_pSelectedRoute->AreWaypointNamesVisible())
775 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
776 _("Hide Waypoint Names"));
777 else
778 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
779 _("Show Waypoint Names"));
780 }
781 MenuAppend1(menuRoute, ID_RT_MENU_RESEQUENCE,
782 _("Resequence Waypoints..."));
783
784 // #ifndef __ANDROID__
785 wxString port = parent->FindValidUploadPort();
786 parent->m_active_upload_port = port;
787 wxString item = _("Send to GPS");
788 if (!port.IsEmpty()) {
789 item.Append(_T(" ( "));
790 item.Append(port);
791 item.Append(_T(" )"));
792 }
793 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOGPS, item);
794
795 if (!port.IsEmpty()) {
796 wxString item = _("Send to new GPS");
797 MenuAppend1(menuRoute, ID_RT_MENU_SENDTONEWGPS, item);
798 }
799 // #endif
800 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
801 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOPEER, itemstp);
802 }
803 // Eventually set this menu as the "focused context menu"
804 if (menuFocus != menuAIS) menuFocus = menuRoute;
805 }
806
807 if (seltype & SELTYPE_TRACKSEGMENT) {
808 name = wxEmptyString;
809 if (!g_bBasicMenus && m_pSelectedTrack)
810 name = _T(" ( ") + m_pSelectedTrack->GetName(true) + _T(" )");
811 else
812 name = wxEmptyString;
813 bool blay = false;
814 if (m_pSelectedTrack && m_pSelectedTrack->m_bIsInLayer) blay = true;
815
816 if (blay) {
817 menuTrack = new wxMenu(_("Layer Track") + name);
818 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES,
819 _("Properties") + _T( "..." ));
820 } else {
821 menuTrack = new wxMenu(_("Track") + name);
822 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES,
823 _("Properties") + _T( "..." ));
824 MenuAppend1(menuTrack, ID_TK_MENU_COPY, _("Copy as KML"));
825 MenuAppend1(menuTrack, ID_TK_MENU_DELETE, _("Delete") + _T( "..." ));
826 }
827
828 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
829 MenuAppend1(menuTrack, ID_TK_MENU_SENDTOPEER, itemstp);
830
831 // Eventually set this menu as the "focused context menu"
832 if (menuFocus != menuAIS) menuFocus = menuTrack;
833 }
834
835 if (seltype & SELTYPE_ROUTEPOINT) {
836 if (!g_bBasicMenus && m_pFoundRoutePoint) {
837 name = m_pFoundRoutePoint->GetName();
838 if (name.IsEmpty()) name = _("Unnamed Waypoint");
839 name.Prepend(_T(" ( ")).Append(_T(" )"));
840 } else
841 name = wxEmptyString;
842 bool blay = false;
843 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
844
845 if (blay) {
846 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
847 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
848 _("Properties") + _T( "..." ));
849
850 if (m_pSelectedRoute && m_pSelectedRoute->IsActive())
851 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
852 } else {
853 menuWaypoint = new wxMenu(_("Waypoint") + name);
854 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
855 _("Properties") + _T( "..." ));
856 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
857 if (m_pSelectedRoute->m_pRouteActivePoint != m_pFoundRoutePoint)
858 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
859 }
860
861 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
862 if (m_pSelectedRoute->m_pRouteActivePoint == m_pFoundRoutePoint) {
863 int indexActive = m_pSelectedRoute->GetIndexOf(
864 m_pSelectedRoute->m_pRouteActivePoint);
865 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints())
866 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTNXTPOINT,
867 _("Activate Next Waypoint"));
868 }
869 }
870 if (m_pSelectedRoute && m_pSelectedRoute->GetnPoints() > 2) {
871 MenuAppend1(menuWaypoint, ID_RT_MENU_REMPOINT, _("Remove from Route"));
872
873 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
874 if (m_SelectedIdx > 1 && m_SelectedIdx < m_pSelectedRoute->GetnPoints())
875 MenuAppend1(menuWaypoint, ID_RT_MENU_SPLIT_WPT,
876 _("Split Route at Waypoint"));
877 }
878
879 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
880
881 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != _T("mob"))
882 MenuAppend1(menuWaypoint, ID_RT_MENU_DELPOINT, _("Delete"));
883
884 // #ifndef __ANDROID__
885 wxString port = parent->FindValidUploadPort();
886 parent->m_active_upload_port = port;
887 wxString item = _("Send to GPS");
888 if (!port.IsEmpty()) {
889 item.Append(_T(" ( "));
890 item.Append(port);
891 item.Append(_T(" )"));
892 }
893 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
894
895 if (!port.IsEmpty()) {
896 wxString item = _("Send to new GPS");
897 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTONEWGPS, item);
898 }
899
900 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
901 SYMBOL_STP_TITLE); // Send to Peer
902 }
903
904 // Eventually set this menu as the "focused context menu"
905 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
906 }
907
908 if (seltype & SELTYPE_MARKPOINT) {
909 if (!g_bBasicMenus && m_pFoundRoutePoint) {
910 name = m_pFoundRoutePoint->GetName();
911 if (name.IsEmpty()) name = _("Unnamed Mark");
912 name.Prepend(_T(" ( ")).Append(_T(" )"));
913 } else
914 name = wxEmptyString;
915 bool blay = false;
916 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
917
918 if (blay) {
919 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
920 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
921 _("Properties") + _T( "..." ));
922 } else {
923 menuWaypoint = new wxMenu(_("Mark") + name);
924 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
925 _("Properties") + _T( "..." ));
926
927 if (!g_pRouteMan->GetpActiveRoute())
928 MenuAppend1(menuWaypoint, ID_WP_MENU_GOTO, _("Navigate To This"));
929
930 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
931
932 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != _T("mob"))
933 MenuAppend1(menuWaypoint, ID_WP_MENU_DELPOINT, _("Delete"));
934
935 // #ifndef __ANDROID__
936 wxString port = parent->FindValidUploadPort();
937 parent->m_active_upload_port = port;
938 wxString item = _("Send to GPS");
939 if (!port.IsEmpty()) {
940 item.Append(_T(" ( "));
941 item.Append(port);
942 item.Append(_T(" )"));
943 }
944 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
945
946 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
947 SYMBOL_STP_TITLE); // Send to Peer
948 // #endif
949
950 if ((m_pFoundRoutePoint == pAnchorWatchPoint1) ||
951 (m_pFoundRoutePoint == pAnchorWatchPoint2))
952 MenuAppend1(menuWaypoint, ID_WP_MENU_CLEAR_ANCHORWATCH,
953 _("Clear Anchor Watch"));
954 else {
955 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
956 ((NULL == pAnchorWatchPoint1) || (NULL == pAnchorWatchPoint2))) {
957 double dist;
958 double brg;
959 DistanceBearingMercator(m_pFoundRoutePoint->m_lat,
960 m_pFoundRoutePoint->m_lon, gLat, gLon, &brg,
961 &dist);
962 if (dist * 1852. <= g_nAWMax)
963 MenuAppend1(menuWaypoint, ID_WP_MENU_SET_ANCHORWATCH,
964 _("Set Anchor Watch"));
965 }
966 }
967 }
968 // Eventually set this menu as the "focused context menu"
969 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
970 }
971
972 // Add plugin context items to the correct menu
973 AddPluginContextMenuItems(contextMenu, menuRoute, menuTrack, menuWaypoint,
974 menuAIS);
975
976 /*add the relevant submenus*/
977 enum { WPMENU = 1, TKMENU = 2, RTMENU = 4, MMMENU = 8 };
978 int sub_menu = 0;
979 if (!g_bBasicMenus && menuFocus != contextMenu) {
980 if (global_color_scheme != GLOBAL_COLOR_SCHEME_DUSK &&
981 global_color_scheme != GLOBAL_COLOR_SCHEME_NIGHT) {
982 menuFocus->AppendSeparator();
983 }
984
985 wxMenuItem *subMenu1;
986 if (menuWaypoint && menuFocus != menuWaypoint) {
987 subMenu1 =
988 menuFocus->AppendSubMenu(menuWaypoint, menuWaypoint->GetTitle());
989 SetMenuItemFont1(subMenu1);
990 sub_menu |= WPMENU;
991#ifdef __WXMSW__
992 menuWaypoint->SetTitle(wxEmptyString);
993#endif
994 }
995 if (menuTrack && menuFocus != menuTrack) {
996 subMenu1 = menuFocus->AppendSubMenu(menuTrack, menuTrack->GetTitle());
997 SetMenuItemFont1(subMenu1);
998 sub_menu |= TKMENU;
999#ifdef __WXMSW__
1000 menuTrack->SetTitle(wxEmptyString);
1001#endif
1002 }
1003 if (menuRoute && menuFocus != menuRoute) {
1004 subMenu1 = menuFocus->AppendSubMenu(menuRoute, menuRoute->GetTitle());
1005 SetMenuItemFont1(subMenu1);
1006 sub_menu |= RTMENU;
1007#ifdef __WXMSW__
1008 menuRoute->SetTitle(wxEmptyString);
1009#endif
1010 }
1011 subMenu1 = menuFocus->AppendSubMenu(contextMenu, _("Main Menu"));
1012 SetMenuItemFont1(subMenu1);
1013 sub_menu |= MMMENU;
1014 }
1015
1016 if (!subMenuChart->GetMenuItemCount()) contextMenu->Destroy(subItemChart);
1017
1018 // Add the Tide/Current selections if the item was not activated by shortcut
1019 // in right-click handlers
1020 bool bsep = false;
1021 if (seltype & SELTYPE_TIDEPOINT) {
1022 menuFocus->AppendSeparator();
1023 bsep = true;
1024 MenuAppend1(menuFocus, ID_DEF_MENU_TIDEINFO, _("Show Tide Information"));
1025 }
1026
1027 if (seltype & SELTYPE_CURRENTPOINT) {
1028 if (!bsep) menuFocus->AppendSeparator();
1029 MenuAppend1(menuFocus, ID_DEF_MENU_CURRENTINFO,
1030 _("Show Current Information"));
1031 }
1032
1033 // Invoke the correct focused drop-down menu
1034
1035#ifdef __ANDROID__
1036 androidEnableBackButton(false);
1037 androidEnableOptionsMenu(false);
1038
1039 setMenuStyleSheet(menuRoute, GetOCPNGUIScaledFont(_("Menu")));
1040 setMenuStyleSheet(menuWaypoint, GetOCPNGUIScaledFont(_("Menu")));
1041 setMenuStyleSheet(menuTrack, GetOCPNGUIScaledFont(_("Menu")));
1042 setMenuStyleSheet(menuAIS, GetOCPNGUIScaledFont(_("Menu")));
1043#endif
1044
1045 parent->PopupMenu(menuFocus, x, y);
1046
1047#ifdef __ANDROID__
1048 androidEnableBackButton(true);
1049 androidEnableOptionsMenu(true);
1050#endif
1051
1052 /* Cleanup if necessary.
1053 Do not delete menus witch are submenu as they will be deleted by their parent
1054 menu. This could create a crash*/
1055 delete menuAIS;
1056 if (!(sub_menu & MMMENU)) delete contextMenu;
1057 if (!(sub_menu & RTMENU)) delete menuRoute;
1058 if (!(sub_menu & TKMENU)) delete menuTrack;
1059 if (!(sub_menu & WPMENU)) delete menuWaypoint;
1060}
1061
1062void CanvasMenuHandler::AddPluginContextMenuItems(wxMenu *contextMenu,
1063 wxMenu *menuRoute,
1064 wxMenu *menuTrack,
1065 wxMenu *menuWaypoint,
1066 wxMenu *menuAIS) {
1067 // Give the plugins a chance to update their menu items
1068 g_pi_manager->PrepareAllPluginContextMenus();
1069
1070 // Add PlugIn Context Menu items
1071 ArrayOfPlugInMenuItems item_array =
1072 g_pi_manager->GetPluginContextMenuItemArray();
1073
1074 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1075 PlugInMenuItemContainer *pimis = item_array[i];
1076 if (!pimis->b_viz) continue;
1077
1078 wxMenu *submenu = NULL;
1079 if (pimis->pmenu_item->GetSubMenu()) {
1080 // Create a clone of the submenu referenced in the PlugInMenuItemContainer
1081 auto submenu_proto = pimis->pmenu_item->GetSubMenu();
1082 submenu = new wxMenu();
1083 const wxMenuItemList &items =
1084 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1085 for (wxMenuItemList::const_iterator it = items.begin(); it != items.end();
1086 ++it) {
1087 int id = (*it)->GetId();
1088 wxMenuItem *psmi =
1089 new wxMenuItem(submenu, id, (*it)->GetItemLabelText(),
1090 (*it)->GetHelp(), (*it)->GetKind());
1091
1092#ifdef __WXMSW__
1093 psmi->SetFont(m_scaledFont);
1094#endif
1095
1096#ifdef __ANDROID__
1097 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1098 psmi->SetFont(sFont);
1099#endif
1100
1101 PrepareMenuItem(psmi);
1102 submenu->Append(psmi);
1103 psmi->Check((*it)->IsChecked());
1104 }
1105 }
1106
1107 wxMenuItem *pmi = new wxMenuItem(
1108 contextMenu, pimis->id, pimis->pmenu_item->GetItemLabelText(),
1109 pimis->pmenu_item->GetHelp(), pimis->pmenu_item->GetKind(), submenu);
1110#ifdef __WXMSW__
1111 pmi->SetFont(m_scaledFont);
1112#endif
1113
1114#ifdef __ANDROID__
1115 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1116 pmi->SetFont(sFont);
1117#endif
1118
1119 PrepareMenuItem(pmi);
1120
1121 wxMenu *dst = contextMenu;
1122 if (pimis->m_in_menu == "Waypoint")
1123 dst = menuWaypoint;
1124 else if (pimis->m_in_menu == "Route")
1125 dst = menuRoute;
1126 else if (pimis->m_in_menu == "Track")
1127 dst = menuTrack;
1128 else if (pimis->m_in_menu == "AIS")
1129 dst = menuAIS;
1130
1131 if (dst != NULL) {
1132 dst->Append(pmi);
1133 dst->Enable(pimis->id, !pimis->b_grey);
1134 }
1135 }
1136}
1137
1138void CanvasMenuHandler::PopupMenuHandler(wxCommandEvent &event) {
1139 RoutePoint *pLast;
1140
1141 wxPoint r;
1142 double zlat, zlon;
1143
1144 int splitMode = 0; // variables for split
1145 bool dupFirstWpt = true, showRPD;
1146
1147 parent->GetCanvasPixPoint(popx * parent->GetDisplayScale(),
1148 popy * parent->GetDisplayScale(), zlat, zlon);
1149
1150 switch (event.GetId()) {
1151 case ID_DEF_MENU_MAX_DETAIL:
1152 vLat = zlat;
1153 vLon = zlon;
1154 parent->ClearbFollow();
1155
1156 parent->parent_frame->DoChartUpdate();
1157
1158 parent->SelectChartFromStack(0, false, CHART_TYPE_DONTCARE,
1159 CHART_FAMILY_RASTER);
1160 break;
1161
1162 case ID_DEF_MENU_SCALE_IN:
1163 parent->DoCanvasStackDelta(-1);
1164 break;
1165
1166 case ID_DEF_MENU_SCALE_OUT:
1167 parent->DoCanvasStackDelta(1);
1168 break;
1169
1170 case ID_UNDO:
1171 parent->undo->UndoLastAction();
1172 parent->InvalidateGL();
1173 parent->Refresh(false);
1174 break;
1175
1176 case ID_REDO:
1177 parent->undo->RedoNextAction();
1178 parent->InvalidateGL();
1179 parent->Refresh(false);
1180 break;
1181
1182 case ID_DEF_MENU_MOVE_BOAT_HERE:
1183 gLat = zlat;
1184 gLon = zlon;
1185 gFrame->UpdateStatusBar();
1186 break;
1187
1188 case ID_DEF_MENU_GOTO_HERE: {
1189 RoutePoint *pWP_dest = new RoutePoint(zlat, zlon, g_default_wp_icon,
1190 wxEmptyString, wxEmptyString);
1191 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP_dest);
1192
1193 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1194 wxEmptyString, wxEmptyString);
1195 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1196
1197 Route *temp_route = new Route();
1198 pRouteList->Append(temp_route);
1199
1200 temp_route->AddPoint(pWP_src);
1201 temp_route->AddPoint(pWP_dest);
1202
1203 pSelect->AddSelectableRouteSegment(gLat, gLon, zlat, zlon, pWP_src,
1204 pWP_dest, temp_route);
1205
1206 temp_route->m_RouteNameString = _("Temporary GOTO Route");
1207 temp_route->m_RouteStartString = _("Here");
1208 ;
1209 temp_route->m_RouteEndString = _("There");
1210
1211 temp_route->m_bDeleteOnArrival = true;
1212
1213 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1214
1215 g_pRouteMan->ActivateRoute(temp_route, pWP_dest);
1216
1217 break;
1218 }
1219
1220 case ID_DEF_MENU_DROP_WP: {
1221 RoutePoint *pWP = new RoutePoint(zlat, zlon, g_default_wp_icon,
1222 wxEmptyString, wxEmptyString);
1223 pWP->m_bIsolatedMark = true; // This is an isolated mark
1224 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP);
1225 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1226
1227 if (!RoutePointGui(*pWP).IsVisibleSelectable(this->parent))
1228 RoutePointGui(*pWP).ShowScaleWarningMessage(parent);
1229
1230 if (RouteManagerDialog::getInstanceFlag()) {
1231 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1232 pRouteManagerDialog->UpdateWptListCtrl();
1233 }
1234 }
1235
1236 parent->undo->BeforeUndoableAction(Undo_CreateWaypoint, pWP,
1237 Undo_HasParent, NULL);
1238 parent->undo->AfterUndoableAction(NULL);
1239 gFrame->RefreshAllCanvas(false);
1240 gFrame->InvalidateAllGL();
1241 g_FlushNavobjChanges = true;
1242 break;
1243 }
1244
1245 case ID_DEF_MENU_NEW_RT: {
1246 parent->StartRoute();
1247 break;
1248 }
1249
1250 case ID_DEF_MENU_AISTARGETLIST:
1251 parent->ShowAISTargetList();
1252 break;
1253
1254 case ID_DEF_MENU_AIS_CPAWARNING:
1255 parent->ToggleCPAWarn();
1256 break;
1257
1258 case ID_WP_MENU_GOTO: {
1259 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1260 wxEmptyString, wxEmptyString);
1261 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1262
1263 Route *temp_route = new Route();
1264 pRouteList->Append(temp_route);
1265
1266 temp_route->AddPoint(pWP_src);
1267 temp_route->AddPoint(m_pFoundRoutePoint);
1268 m_pFoundRoutePoint->SetShared(true);
1269
1270 pSelect->AddSelectableRouteSegment(gLat, gLon, m_pFoundRoutePoint->m_lat,
1271 m_pFoundRoutePoint->m_lon, pWP_src,
1272 m_pFoundRoutePoint, temp_route);
1273
1274 wxString name = m_pFoundRoutePoint->GetName();
1275 if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
1276 wxString rteName = _("Go to ");
1277 rteName.Append(name);
1278 temp_route->m_RouteNameString = rteName;
1279 temp_route->m_RouteStartString = _("Here");
1280 ;
1281 temp_route->m_RouteEndString = name;
1282 temp_route->m_bDeleteOnArrival = true;
1283
1284 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1285
1286 g_pRouteMan->ActivateRoute(temp_route, m_pFoundRoutePoint);
1287
1288 break;
1289 }
1290
1291 case ID_DEF_MENU_COGUP:
1292 parent->SetUpMode(COURSE_UP_MODE);
1293 break;
1294
1295 case ID_DEF_MENU_HEADUP:
1296 parent->SetUpMode(HEAD_UP_MODE);
1297 break;
1298
1299 case ID_DEF_MENU_NORTHUP:
1300 parent->SetUpMode(NORTH_UP_MODE);
1301 break;
1302
1303 case ID_DEF_MENU_TOGGLE_FULL:
1304 gFrame->ToggleFullScreen();
1305 break;
1306
1307 case ID_DEF_MENU_GOTOPOSITION:
1308 if (NULL == pGoToPositionDialog) // There is one global instance of the
1309 // Go To Position Dialog
1310 pGoToPositionDialog = new GoToPositionDialog(parent);
1311 pGoToPositionDialog->SetCanvas(parent);
1312 pGoToPositionDialog->CheckPasteBufferForPosition();
1313 pGoToPositionDialog->Show();
1314 break;
1315
1316 case ID_WP_MENU_DELPOINT: {
1317 if (m_pFoundRoutePoint == pAnchorWatchPoint1) {
1318 pAnchorWatchPoint1 = NULL;
1319 g_AW1GUID.Clear();
1320 } else if (m_pFoundRoutePoint == pAnchorWatchPoint2) {
1321 pAnchorWatchPoint2 = NULL;
1322 g_AW2GUID.Clear();
1323 }
1324
1325 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
1326 (m_pFoundRoutePoint->GetIconName() != _T("mob"))) {
1327 // If the WP belongs to an invisible route, we come here instead of to
1328 // ID_RT_MENU_DELPOINT
1329 // Check it, and if so then remove the point from its routes
1330 wxArrayPtrVoid *proute_array =
1331 g_pRouteMan->GetRouteArrayContaining(m_pFoundRoutePoint);
1332 if (proute_array) {
1333 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1334 delete proute_array;
1335 } else {
1336 parent->undo->BeforeUndoableAction(
1337 Undo_DeleteWaypoint, m_pFoundRoutePoint, Undo_IsOrphanded,
1338 NULL /*m_pFoundPoint*/);
1339 NavObj_dB::GetInstance().DeleteRoutePoint(m_pFoundRoutePoint);
1340 pSelect->DeleteSelectablePoint(m_pFoundRoutePoint,
1341 SELTYPE_ROUTEPOINT);
1342 if (NULL != pWayPointMan)
1343 pWayPointMan->RemoveRoutePoint(m_pFoundRoutePoint);
1344 parent->undo->AfterUndoableAction(NULL);
1345 }
1346
1347 if (g_pMarkInfoDialog) {
1348 g_pMarkInfoDialog->ClearData();
1349 }
1350
1351 if (RouteManagerDialog::getInstanceFlag()) {
1352 if (pRouteManagerDialog) {
1353 if (pRouteManagerDialog->IsShown())
1354 pRouteManagerDialog->UpdateWptListCtrl();
1355 }
1356 }
1357
1358 gFrame->RefreshAllCanvas(false);
1359 gFrame->InvalidateAllGL();
1360 }
1361 break;
1362 }
1363 case ID_WP_MENU_PROPERTIES:
1364 parent->ShowMarkPropertiesDialog(m_pFoundRoutePoint);
1365 break;
1366
1367 case ID_WP_MENU_CLEAR_ANCHORWATCH: {
1368 wxString guid = wxEmptyString;
1369 if (pAnchorWatchPoint1 == m_pFoundRoutePoint) {
1370 pAnchorWatchPoint1 = NULL;
1371 guid = g_AW1GUID;
1372 g_AW1GUID.Clear();
1373 } else if (pAnchorWatchPoint2 == m_pFoundRoutePoint) {
1374 pAnchorWatchPoint2 = NULL;
1375 guid = g_AW2GUID;
1376 g_AW2GUID.Clear();
1377 }
1378 if (!guid.IsEmpty()) {
1379 wxJSONValue v;
1380 v[_T("GUID")] = guid;
1381 wxString msg_id(_T("OCPN_ANCHOR_WATCH_CLEARED"));
1382 SendJSONMessageToAllPlugins(msg_id, v);
1383 }
1384 break;
1385 }
1386
1387 case ID_WP_MENU_SET_ANCHORWATCH: {
1388 wxString guid = wxEmptyString;
1389 if (pAnchorWatchPoint1 == NULL) {
1390 pAnchorWatchPoint1 = m_pFoundRoutePoint;
1391 g_AW1GUID = pAnchorWatchPoint1->m_GUID;
1392 guid = g_AW1GUID;
1393 wxString nn;
1394 nn = m_pFoundRoutePoint->GetName();
1395 if (nn.IsNull()) {
1396 nn.Printf(_T("%d m"), g_nAWDefault);
1397 m_pFoundRoutePoint->SetName(nn);
1398 }
1399 } else if (pAnchorWatchPoint2 == NULL) {
1400 pAnchorWatchPoint2 = m_pFoundRoutePoint;
1401 g_AW2GUID = pAnchorWatchPoint2->m_GUID;
1402 guid = g_AW2GUID;
1403 wxString nn;
1404 nn = m_pFoundRoutePoint->GetName();
1405 if (nn.IsNull()) {
1406 nn.Printf(_T("%d m"), g_nAWDefault);
1407 m_pFoundRoutePoint->SetName(nn);
1408 }
1409 }
1410 if (!guid.IsEmpty()) {
1411 wxJSONValue v;
1412 v[_T("GUID")] = guid;
1413 wxString msg_id(_T("OCPN_ANCHOR_WATCH_SET"));
1414 SendJSONMessageToAllPlugins(msg_id, v);
1415 }
1416 break;
1417 }
1418
1419 case ID_DEF_MENU_ACTIVATE_MEASURE:
1420 parent->StartMeasureRoute();
1421 break;
1422
1423 case ID_DEF_MENU_DEACTIVATE_MEASURE:
1424 parent->CancelMeasureRoute();
1425 // gFrame->SurfaceAllCanvasToolbars();
1426 parent->InvalidateGL();
1427 parent->Refresh(false);
1428 break;
1429
1430 case ID_DEF_MENU_CM93OFFSET_DIALOG: {
1431 if (NULL == g_pCM93OffsetDialog) {
1432 g_pCM93OffsetDialog = new CM93OffsetDialog(parent->parent_frame);
1433 }
1434
1435 cm93compchart *pch = NULL;
1436 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
1437 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
1438 pch = (cm93compchart *)parent->m_singleChart;
1439 }
1440
1441 if (g_pCM93OffsetDialog) {
1442 g_pCM93OffsetDialog->SetCM93Chart(pch);
1443 g_pCM93OffsetDialog->Show();
1444 g_pCM93OffsetDialog->UpdateMCOVRList(parent->GetVP());
1445 }
1446
1447 break;
1448 }
1449 case ID_DEF_MENU_QUERY: {
1450 parent->ShowObjectQueryWindow(popx, popy, zlat, zlon);
1451 break;
1452 }
1453 case ID_DEF_MENU_AIS_QUERY: {
1454 ShowAISTargetQueryDialog(parent, m_FoundAIS_MMSI);
1455 break;
1456 }
1457
1458 case ID_DEF_MENU_AIS_CPA: {
1459 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1460 if (myptarget) myptarget->Toggle_AIS_CPA();
1461 break;
1462 }
1463
1464 case ID_DEF_MENU_AISSHOWTRACK: {
1465 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1466 if (myptarget) myptarget->ToggleShowTrack();
1467 break;
1468 }
1469
1470 case ID_DEF_MENU_COPY_MMSI: {
1471 // Write MMSI # as text to the clipboard
1472 if (wxTheClipboard->Open()) {
1473 wxTheClipboard->SetData(new wxTextDataObject(
1474 wxString::Format(wxT("%09d"), m_FoundAIS_MMSI)));
1475 wxTheClipboard->Close();
1476 }
1477 break;
1478 }
1479
1480 case ID_DEF_MENU_QUILTREMOVE: {
1481 if (parent->GetVP().b_quilt) {
1482 int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
1483 parent->GetVP(), wxPoint(popx, popy));
1484 parent->RemoveChartFromQuilt(dbIndex);
1485
1486 parent->ReloadVP();
1487 }
1488
1489 break;
1490 }
1491
1492 case ID_DEF_MENU_CURRENTINFO: {
1493 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1494 parent->Refresh(false);
1495
1496 break;
1497 }
1498
1499 case ID_DEF_MENU_TIDEINFO: {
1500 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1501 parent->Refresh(false);
1502
1503 break;
1504 }
1505
1506 case ID_DGB_MENU_NMEA_WINDOW:
1507 m_nmea_log->Show();
1508 m_nmea_log->Raise();
1509 break;
1510
1511 case ID_RT_MENU_REVERSE: {
1512 if (m_pSelectedRoute->m_bIsInLayer) break;
1513
1514 int ask_return =
1515 OCPNMessageBox(parent, g_pRouteMan->GetRouteReverseMessage(),
1516 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1517
1518 if (ask_return != wxID_CANCEL) {
1519 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1520 m_pSelectedRoute->Reverse(ask_return == wxID_YES);
1521 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1522
1523 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1524
1525 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1526 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute);
1527 // pNew->UpdateProperties();
1528 }
1529 gFrame->InvalidateAllGL();
1530 gFrame->RefreshAllCanvas();
1531 }
1532 break;
1533 }
1534
1535 case ID_RT_MENU_SHOWNAMES: {
1536 if (m_pSelectedRoute) {
1537 m_pSelectedRoute->ShowWaypointNames(
1538 !m_pSelectedRoute->AreWaypointNamesVisible());
1539 }
1540
1541 break;
1542 }
1543
1544 case ID_RT_MENU_RESEQUENCE: {
1545 if (m_pSelectedRoute) {
1546 if (m_pSelectedRoute->m_bIsInLayer) break;
1547
1548 int ask_return =
1549 OCPNMessageBox(parent, g_pRouteMan->GetRouteResequenceMessage(),
1550 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1551
1552 if (ask_return != wxID_CANCEL) {
1553 m_pSelectedRoute->RenameRoutePoints();
1554 }
1555
1556 gFrame->InvalidateAllGL();
1557 gFrame->RefreshAllCanvas();
1558 }
1559
1560 break;
1561 }
1562
1563 case ID_RT_MENU_DELETE: {
1564 bool confirmed = RouteGui::OnDelete(parent);
1565
1566 if (confirmed) {
1567 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1568 g_pRouteMan->DeactivateRoute();
1569
1570 if (m_pSelectedRoute->m_bIsInLayer) break;
1571
1572 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1573 if (!g_pRouteMan->DeleteRoute(m_pSelectedRoute)) break;
1574
1575 if (RouteManagerDialog::getInstanceFlag()) {
1576 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1577 pRouteManagerDialog->UpdateRouteListCtrl();
1578 }
1579
1580 if (g_pMarkInfoDialog && g_pMarkInfoDialog->IsShown()) {
1581 g_pMarkInfoDialog->ValidateMark();
1582 g_pMarkInfoDialog->UpdateProperties();
1583 }
1584
1585 parent->undo->InvalidateUndo();
1586
1587 gFrame->InvalidateAllGL();
1588 gFrame->RefreshAllCanvas();
1589 }
1590 break;
1591 }
1592
1593 case ID_RT_MENU_ACTIVATE: {
1594 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1595
1596 // If this is an auto-created MOB route, always select the second point
1597 // (the MOB)
1598 // as the destination.
1599 RoutePoint *best_point;
1600 if (m_pSelectedRoute) {
1601 if (wxNOT_FOUND ==
1602 m_pSelectedRoute->m_RouteNameString.Find(_T("MOB"))) {
1603 best_point = g_pRouteMan->FindBestActivatePoint(
1604 m_pSelectedRoute, gLat, gLon, gCog, gSog);
1605 } else
1606 best_point = m_pSelectedRoute->GetPoint(2);
1607
1608 g_pRouteMan->ActivateRoute(m_pSelectedRoute, best_point);
1609 m_pSelectedRoute->m_bRtIsSelected = false;
1610 }
1611
1612 break;
1613 }
1614
1615 case ID_RT_MENU_DEACTIVATE:
1616 g_pRouteMan->DeactivateRoute();
1617 m_pSelectedRoute->m_bRtIsSelected = false;
1618
1619 break;
1620
1621 case ID_RT_MENU_INSERT: {
1622 if (m_pSelectedRoute->m_bIsInLayer) break;
1623 bool rename = false;
1624 m_pSelectedRoute->InsertPointAfter(m_pFoundRoutePoint, zlat, zlon,
1625 rename);
1626
1627 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1628 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1629
1630 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1631 pSelect->AddAllSelectableRoutePoints(m_pSelectedRoute);
1632
1633 // As a special case (which comes up often)...
1634 // If the inserted waypoint is on the active leg of an active route
1635 /* if(m_pSelectedRoute->m_bRtIsActive)
1636 {
1637 if(m_pSelectedRoute->m_nRouteActivePoint == np + 1)
1638 {
1639 pNew_Point = m_pSelectedRoute->GetPoint(np + 2);
1640 pRouteMan->ActivateRoutePoint(m_pSelectedRoute, pNew_Point);
1641 }
1642 }
1643 */
1644 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1645
1646 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1647 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1648 }
1649
1650 break;
1651 }
1652
1653 case ID_RT_MENU_APPEND:
1654
1655 if (m_pSelectedRoute->m_bIsInLayer) break;
1656
1657 parent->m_pMouseRoute = m_pSelectedRoute;
1658 parent->m_routeState = m_pSelectedRoute->GetnPoints() + 1;
1659 parent->m_pMouseRoute->m_lastMousePointIndex =
1660 m_pSelectedRoute->GetnPoints();
1661 parent->m_pMouseRoute->SetHiLite(50);
1662
1663 pLast = m_pSelectedRoute->GetLastPoint();
1664
1665 parent->m_prev_rlat = pLast->m_lat;
1666 parent->m_prev_rlon = pLast->m_lon;
1667 parent->m_prev_pMousePoint = pLast;
1668
1669 parent->m_bAppendingRoute = true;
1670
1671 parent->SetCursor(*parent->pCursorPencil);
1672#ifdef __ANDROID__
1673 androidSetRouteAnnunciator(true);
1674#endif
1675
1676 parent->HideGlobalToolbar();
1677
1678 break;
1679
1680 case ID_RT_MENU_SPLIT_LEG: // split route around a leg
1681 splitMode++;
1682 dupFirstWpt = false;
1683 case ID_RT_MENU_SPLIT_WPT: // split route at a wpt
1684
1685 showRPD = (pRoutePropDialog && pRoutePropDialog->IsShown());
1686
1687 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1688 g_pRouteMan->DeactivateRoute();
1689
1690 m_pHead = new Route();
1691 m_pTail = new Route();
1692 m_pHead->CloneRoute(m_pSelectedRoute, 1, m_SelectedIdx, _("_A"));
1693 m_pTail->CloneRoute(m_pSelectedRoute, m_SelectedIdx + splitMode,
1694 m_pSelectedRoute->GetnPoints(), _("_B"), dupFirstWpt);
1695 pRouteList->Append(m_pHead);
1696 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1697
1698 pRouteList->Append(m_pTail);
1699 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1700
1701 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1702
1703 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1704 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1705 g_pRouteMan->DeleteRoute(m_pSelectedRoute);
1706 pSelect->AddAllSelectableRouteSegments(m_pTail);
1707 pSelect->AddAllSelectableRoutePoints(m_pTail);
1708 pSelect->AddAllSelectableRouteSegments(m_pHead);
1709 pSelect->AddAllSelectableRoutePoints(m_pHead);
1710
1711 if (showRPD) {
1712 pRoutePropDialog->SetRouteAndUpdate(m_pHead);
1713 pRoutePropDialog->Show();
1714 }
1715 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog &&
1716 (pRouteManagerDialog->IsShown()))
1717 pRouteManagerDialog->UpdateRouteListCtrl();
1718 break;
1719
1720 case ID_RT_MENU_COPY:
1721 if (m_pSelectedRoute) Kml::CopyRouteToClipboard(m_pSelectedRoute);
1722 break;
1723
1724 case ID_TK_MENU_COPY:
1725 if (m_pSelectedTrack) Kml::CopyTrackToClipboard(m_pSelectedTrack);
1726 break;
1727
1728 case ID_WPT_MENU_COPY:
1729 if (m_pFoundRoutePoint) Kml::CopyWaypointToClipboard(m_pFoundRoutePoint);
1730 break;
1731
1732 case ID_WPT_MENU_SENDTOGPS:
1733 if (m_pFoundRoutePoint) {
1734 if (parent->m_active_upload_port.Length())
1735 RoutePointGui(*m_pFoundRoutePoint)
1736 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), NULL);
1737 else {
1738 SendToGpsDlg dlg;
1739 dlg.SetWaypoint(m_pFoundRoutePoint);
1740 wxFont fo = GetOCPNGUIScaledFont(_("Dialog"));
1741 dlg.SetFont(fo);
1742
1743 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1744 dlg.ShowModal();
1745 }
1746 }
1747 break;
1748
1749 case ID_WPT_MENU_SENDTONEWGPS:
1750 if (m_pFoundRoutePoint) {
1751 SendToGpsDlg dlg;
1752 dlg.SetWaypoint(m_pFoundRoutePoint);
1753
1754 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1755 dlg.ShowModal();
1756 }
1757 break;
1758
1759 case ID_WPT_MENU_SENDTOPEER:
1760 if (m_pFoundRoutePoint) {
1761 SendToPeerDlg dlg;
1762 dlg.SetWaypoint(m_pFoundRoutePoint);
1763
1764 // Perform initial scan, if necessary
1765
1766 // Check for stale cache...
1767 MdnsCache::GetInstance().Validate();
1768 if (MdnsCache::GetInstance().GetCache().empty())
1769 dlg.SetScanOnCreate(true);
1770
1771 dlg.SetScanTime(5); // seconds
1772 dlg.Create(NULL, -1, _("Send Waypoint to OpenCPN Peer") + _T( "..." ),
1773 _T(""));
1774 dlg.ShowModal();
1775 }
1776 break;
1777
1778 case ID_RT_MENU_SENDTOGPS:
1779 if (m_pSelectedRoute) {
1780 if (parent->m_active_upload_port.Length())
1781 RouteGui(*m_pSelectedRoute)
1782 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), true,
1783 NULL);
1784 else {
1785 SendToGpsDlg dlg;
1786 dlg.SetRoute(m_pSelectedRoute);
1787
1788 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1789 dlg.ShowModal();
1790 }
1791 }
1792 break;
1793
1794 case ID_RT_MENU_SENDTONEWGPS:
1795 if (m_pSelectedRoute) {
1796 SendToGpsDlg dlg;
1797 dlg.SetRoute(m_pSelectedRoute);
1798
1799 dlg.Create(NULL, -1, _("Send to GPS") + _T( "..." ), _T(""));
1800 dlg.ShowModal();
1801 }
1802 break;
1803
1804 case ID_RT_MENU_SENDTOPEER:
1805 if (m_pSelectedRoute) {
1806 SendToPeerDlg dlg;
1807 dlg.SetRoute(m_pSelectedRoute);
1808
1809 // Perform initial scan, if necessary
1810
1811 // Check for stale cache...
1812 MdnsCache::GetInstance().Validate();
1813 if (MdnsCache::GetInstance().GetCache().empty())
1814 dlg.SetScanOnCreate(true);
1815
1816 dlg.SetScanTime(5); // seconds
1817 dlg.Create(NULL, -1, _("Send Route to OpenCPN Peer") + _T( "..." ),
1818 _T(""));
1819 dlg.ShowModal();
1820 }
1821 break;
1822
1823 case ID_PASTE_WAYPOINT:
1824 pupHandler_PasteWaypoint();
1825 break;
1826
1827 case ID_PASTE_ROUTE:
1828 pupHandler_PasteRoute();
1829 break;
1830
1831 case ID_PASTE_TRACK:
1832 pupHandler_PasteTrack();
1833 break;
1834
1835 case ID_RT_MENU_DELPOINT:
1836 if (m_pSelectedRoute) {
1837 if (m_pSelectedRoute->m_bIsInLayer) break;
1838
1839 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1840
1841 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1842 // Selected route may have been deleted as one-point route, so
1843 // check it
1844 if (g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
1845 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1846 } else
1847 pRoutePropDialog->Hide();
1848 }
1849
1850 if (RouteManagerDialog::getInstanceFlag()) {
1851 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1852 pRouteManagerDialog->UpdateWptListCtrl();
1853 pRouteManagerDialog->UpdateRouteListCtrl();
1854 }
1855 }
1856
1857 gFrame->InvalidateAllGL();
1858 gFrame->RefreshAllCanvas(true);
1859 }
1860
1861 break;
1862
1863 case ID_RT_MENU_REMPOINT:
1864 if (m_pSelectedRoute) {
1865 if (m_pSelectedRoute->m_bIsInLayer) break;
1866 g_pRouteMan->RemovePointFromRoute(m_pFoundRoutePoint, m_pSelectedRoute,
1867 parent->m_routeState);
1868 gFrame->InvalidateAllGL();
1869 gFrame->RefreshAllCanvas();
1870 }
1871 break;
1872
1873 case ID_RT_MENU_ACTPOINT:
1874 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1875 g_pRouteMan->ActivateRoutePoint(m_pSelectedRoute, m_pFoundRoutePoint);
1876 m_pSelectedRoute->m_bRtIsSelected = false;
1877 }
1878
1879 break;
1880
1881 case ID_RT_MENU_DEACTPOINT:
1882 break;
1883
1884 case ID_RT_MENU_ACTNXTPOINT:
1885 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1886 g_pRouteMan->ActivateNextPoint(m_pSelectedRoute, true);
1887 m_pSelectedRoute->m_bRtIsSelected = false;
1888 }
1889
1890 break;
1891
1892 case ID_RT_MENU_PROPERTIES: {
1893 parent->ShowRoutePropertiesDialog(_("Route Properties"),
1894 m_pSelectedRoute);
1895 break;
1896 }
1897
1898 case ID_TK_MENU_PROPERTIES: {
1899 parent->ShowTrackPropertiesDialog(m_pSelectedTrack);
1900 break;
1901 }
1902
1903 case ID_TK_MENU_DELETE: {
1904 int dlg_return = wxID_YES;
1905 if (g_bConfirmObjectDelete) {
1906 dlg_return = OCPNMessageBox(
1907 parent, _("Are you sure you want to delete this track?"),
1908 _("OpenCPN Track Delete"),
1909 (long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
1910 }
1911
1912 if (dlg_return == wxID_YES) {
1913 if (m_pSelectedTrack == g_pActiveTrack)
1914 m_pSelectedTrack = parent->parent_frame->TrackOff();
1915 g_pAIS->DeletePersistentTrack(m_pSelectedTrack);
1916 // pConfig->DeleteConfigTrack(m_pSelectedTrack);
1917 NavObj_dB::GetInstance().DeleteTrack(m_pSelectedTrack);
1918 RoutemanGui(*g_pRouteMan).DeleteTrack(m_pSelectedTrack);
1919
1920 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
1921 (pTrackPropDialog->IsShown()) &&
1922 (m_pSelectedTrack == pTrackPropDialog->GetTrack())) {
1923 pTrackPropDialog->Hide();
1924 }
1925
1926 if (RoutePropDlgImpl::getInstanceFlag() && pRouteManagerDialog &&
1927 pRouteManagerDialog->IsShown()) {
1928 pRouteManagerDialog->UpdateTrkListCtrl();
1929 pRouteManagerDialog->UpdateRouteListCtrl();
1930 }
1931 gFrame->InvalidateAllGL();
1932 gFrame->RefreshAllCanvas();
1933 }
1934 break;
1935 }
1936
1937 case ID_TK_MENU_SENDTOPEER:
1938 if (m_pSelectedTrack) {
1939 SendToPeerDlg dlg;
1940 dlg.SetTrack(m_pSelectedTrack);
1941
1942 // Perform initial scan, if necessary
1943
1944 // Check for stale cache...
1945 MdnsCache::GetInstance().Validate();
1946 if (MdnsCache::GetInstance().GetCache().empty())
1947 dlg.SetScanOnCreate(true);
1948
1949 dlg.SetScanTime(5); // seconds
1950 dlg.Create(NULL, -1, _("Send Track to OpenCPN Peer") + _T( "..." ),
1951 _T(""));
1952 dlg.ShowModal();
1953 }
1954 break;
1955
1956 case ID_RC_MENU_SCALE_IN:
1957 parent->parent_frame->DoStackDown(parent);
1958 parent->GetCanvasPointPix(zlat, zlon, &r);
1959 parent->WarpPointer(r.x, r.y);
1960 break;
1961
1962 case ID_RC_MENU_SCALE_OUT:
1963 parent->parent_frame->DoStackUp(parent);
1964 parent->GetCanvasPointPix(zlat, zlon, &r);
1965 parent->WarpPointer(r.x, r.y);
1966 break;
1967
1968 case ID_RC_MENU_ZOOM_IN:
1969 parent->SetVPScale(parent->GetVPScale() * 2);
1970 parent->GetCanvasPointPix(zlat, zlon, &r);
1971 parent->WarpPointer(r.x, r.y);
1972 break;
1973
1974 case ID_RC_MENU_ZOOM_OUT:
1975 parent->SetVPScale(parent->GetVPScale() / 2);
1976 parent->GetCanvasPointPix(zlat, zlon, &r);
1977 parent->WarpPointer(r.x, r.y);
1978 break;
1979
1980 case ID_RC_MENU_FINISH:
1981 parent->FinishRoute();
1982 // gFrame->SurfaceAllCanvasToolbars();
1983 parent->Refresh(false);
1984 g_FlushNavobjChanges = true;
1985 break;
1986
1987 case ID_DEF_ZERO_XTE:
1988 g_pRouteMan->ZeroCurrentXTEToActivePoint();
1989 break;
1990
1991 default: {
1992 // Look for PlugIn Context Menu selections
1993 // If found, make the callback
1994 ArrayOfPlugInMenuItems item_array =
1995 g_pi_manager->GetPluginContextMenuItemArray();
1996
1997 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1998 PlugInMenuItemContainer *pimis = item_array[i];
1999 int target_id = pimis->id;
2000
2001 // Check submenus, if present.
2002 if (pimis->pmenu_item->GetSubMenu()) {
2003 const wxMenuItemList &items =
2004 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
2005 for (wxMenuItemList::const_iterator it = items.begin();
2006 it != items.end(); ++it) {
2007 if ((*it)->GetId() == event.GetId()) {
2008 target_id = (*it)->GetId();
2009 break;
2010 }
2011 }
2012 }
2013
2014 if (pimis->m_pplugin && (target_id == event.GetId())) {
2015 int version_major = pimis->m_pplugin->GetAPIVersionMajor();
2016 int version_minor = pimis->m_pplugin->GetAPIVersionMinor();
2017 if ((version_major * 100) + version_minor >= 120) {
2018 std::string object_type;
2019 std::string object_ident;
2020
2021 if ((pimis->m_in_menu.IsSameAs("Waypoint")) && m_pFoundRoutePoint) {
2022 object_type = "Waypoint";
2023 object_ident = m_pFoundRoutePoint->m_GUID.ToStdString();
2024 } else if ((pimis->m_in_menu.IsSameAs("Route")) &&
2025 m_pSelectedRoute) {
2026 object_type = "Route";
2027 object_ident = m_pSelectedRoute->m_GUID.ToStdString();
2028 } else if ((pimis->m_in_menu.IsSameAs("Track")) &&
2029 m_pSelectedTrack) {
2030 object_type = "Track";
2031 object_ident = m_pSelectedTrack->m_GUID.ToStdString();
2032 } else if ((pimis->m_in_menu.IsSameAs("AIS")) && m_FoundAIS_MMSI) {
2033 object_type = "AIS";
2034 wxString sAIS = wxString::Format("%d", m_FoundAIS_MMSI);
2035 object_ident = sAIS.ToStdString();
2036 }
2037
2038 opencpn_plugin_120 *ppi =
2039 dynamic_cast<opencpn_plugin_120 *>(pimis->m_pplugin);
2040 if (ppi)
2041 ppi->OnContextMenuItemCallbackExt(target_id, object_ident,
2042 object_type, zlat, zlon);
2043
2044 } else {
2045 pimis->m_pplugin->OnContextMenuItemCallback(pimis->id);
2046 }
2047 }
2048 }
2049 break;
2050 }
2051 } // switch
2052
2053 // Chart Groups....
2054 if ((event.GetId() >= ID_DEF_MENU_GROUPBASE) &&
2055 (event.GetId() <=
2056 ID_DEF_MENU_GROUPBASE + (int)g_pGroupArray->GetCount())) {
2057 parent->SetGroupIndex(event.GetId() - ID_DEF_MENU_GROUPBASE);
2058 }
2059
2060 parent->InvalidateGL();
2061
2062 g_click_stop = 0; // Context menu was processed, all is well
2063}
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:4558
double GetDisplayScale()
Get the ratio of physical to logical pixel for the display.
Definition chcanv.h:821
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:462
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
Definition chcanv.cpp:5340
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4583
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:338
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:413
bool DeleteRoute(Route *pRoute)
Definition routeman.cpp:856
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.
virtual int GetAPIVersionMinor()
Returns the minor version number of the plugin API that this plugin supports.
virtual int GetAPIVersionMajor()
Returns the major version number of the plugin API that this plugin supports.
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.