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