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"
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 "go_to_position_dlg.h"
59#include "kml.h"
60#include "mark_info.h"
61#include "ocpn_frame.h"
62#include "ocpn_platform.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 "route_prop_dlg_impl.h"
71#include "s52plib.h"
72#include "s57chart.h" // for ArrayOfS57Obj
73#include "send_to_gps_dlg.h"
74#include "send_to_peer_dlg.h"
75#include "styles.h"
76#include "tcmgr.h"
77#include "track_gui.h"
78#include "track_prop_dlg.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("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, _("Object Query") + "...");
436 }
437
438 } else {
439 ChartBase *pChartTest =
440 parent->m_pQuilt->GetChartAtPix(parent->GetVP(), wxPoint(x, y));
441 if ((pChartTest && (pChartTest->GetChartFamily() == CHART_FAMILY_VECTOR)) ||
442 ais_areanotice) {
443 MenuAppend1(contextMenu, ID_DEF_MENU_QUERY, _("Object Query") + "...");
444 } else {
445#ifndef __ANDROID__
446 if (!g_bBasicMenus && (nChartStack > 1)) {
447 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_IN,
448 _menuText(_("Scale In"), "Ctrl-Left"));
449 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_OUT,
450 _menuText(_("Scale Out"), "Ctrl-Right"));
451 }
452#endif
453 }
454 }
455
456 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
457 bool b_dm_add = true;
458 if (g_btouch && parent->IsMeasureActive()) b_dm_add = false;
459
460 if (b_dm_add) {
461 MenuAppend1(contextMenu, ID_DEF_MENU_DROP_WP,
462 _menuText(_("Drop Mark"), "Ctrl-M"));
463 MenuAppend1(contextMenu, ID_DEF_MENU_NEW_RT,
464 _menuText(_("New Route..."), "Ctrl-R"));
465 }
466
467 if (!bGPSValid)
468 MenuAppend1(contextMenu, ID_DEF_MENU_MOVE_BOAT_HERE, _("Move Boat Here"));
469 }
470
471 if (!g_bBasicMenus && !g_pRouteMan->GetpActiveRoute() &&
472 (!(seltype & SELTYPE_MARKPOINT) ||
473 (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer)))
474 MenuAppend1(contextMenu, ID_DEF_MENU_GOTO_HERE, _("Navigate To Here"));
475
476 if (!g_bBasicMenus)
477 MenuAppend1(contextMenu, ID_DEF_MENU_GOTOPOSITION,
478 _("Center view") + "...");
479
480 if (!g_bBasicMenus) {
481 if (parent->GetVP().b_quilt) {
482 if (parent->GetUpMode() == NORTH_UP_MODE) {
483 MenuAppend1(contextMenu, ID_DEF_MENU_COGUP, _("Course Up Mode"));
484 if (!std::isnan(gHdt))
485 MenuAppend1(contextMenu, ID_DEF_MENU_HEADUP, _("Heading Up Mode"));
486 } else {
487 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("North Up Mode"));
488 }
489 } else {
490 if (parent->m_singleChart &&
491 (fabs(parent->m_singleChart->GetChartSkew()) > .01) && !g_bskew_comp)
492 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("Chart Up Mode"));
493 else
494 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("North Up Mode"));
495 }
496 }
497
498 if (!g_bBasicMenus) {
499 bool full_toggle_added = false;
500#ifndef __ANDROID__
501 if (g_btouch) {
502 MenuAppend1(contextMenu, ID_DEF_MENU_TOGGLE_FULL,
503 _("Toggle Full Screen"));
504 full_toggle_added = true;
505 }
506
507 if (!full_toggle_added) {
508 // if(gFrame->IsFullScreen())
509 MenuAppend1(contextMenu, ID_DEF_MENU_TOGGLE_FULL,
510 _("Toggle Full Screen"));
511 }
512#endif
513
514 if (g_pRouteMan->IsAnyRouteActive() &&
515 g_pRouteMan->GetCurrentXTEToActivePoint() > 0.)
516 MenuAppend1(contextMenu, ID_DEF_ZERO_XTE, _("Zero XTE"));
517
518 Kml *kml = new Kml;
519 int pasteBuffer = kml->ParsePasteBuffer();
520 if (pasteBuffer != KML_PASTE_INVALID) {
521 switch (pasteBuffer) {
522 case KML_PASTE_WAYPOINT: {
523 MenuAppend1(contextMenu, ID_PASTE_WAYPOINT, _("Paste Waypoint"));
524 break;
525 }
526 case KML_PASTE_ROUTE: {
527 MenuAppend1(contextMenu, ID_PASTE_ROUTE, _("Paste Route"));
528 break;
529 }
530 case KML_PASTE_TRACK: {
531 MenuAppend1(contextMenu, ID_PASTE_TRACK, _("Paste Track"));
532 break;
533 }
534 case KML_PASTE_ROUTE_TRACK: {
535 MenuAppend1(contextMenu, ID_PASTE_ROUTE, _("Paste Route"));
536 MenuAppend1(contextMenu, ID_PASTE_TRACK, _("Paste Track"));
537 break;
538 }
539 }
540 }
541 delete kml;
542
543 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
544 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
545 MenuAppend1(contextMenu, ID_DEF_MENU_CM93OFFSET_DIALOG,
546 _("CM93 Offset Dialog..."));
547 }
548
549 } // if( !g_bBasicMenus){
550
551#ifndef __ANDROID__
552// TODO stack
553// if( ( parent->GetVP().b_quilt ) && ( pCurrentStack &&
554// pCurrentStack->b_valid ) ) {
555// int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
556// parent->GetVP(), wxPoint( popx, popy ) ); if( dbIndex != -1 )
557// MenuAppend1( contextMenu, ID_DEF_MENU_QUILTREMOVE, _( "Hide This
558// Chart" ) );
559// }
560#endif
561
562#ifdef __WXMSW__
563 // If we dismiss the context menu without action, we need to discard some
564 // mouse events.... Eat the next 2 button events, which happen as down-up on
565 // MSW XP
566 g_click_stop = 2;
567#endif
568
569 // ChartGroup SubMenu
570 wxMenuItem *subItemChart =
571 contextMenu->AppendSubMenu(subMenuChart, _("Chart Groups"));
572 if (g_btouch) contextMenu->AppendSeparator();
573
574 SetMenuItemFont1(subItemChart);
575
576 if (g_pGroupArray->GetCount()) {
577#ifdef __WXMSW__
578 MenuAppend1(subMenuChart, wxID_CANCEL, _("temporary"));
579#endif
580 wxMenuItem *subItem0 = subMenuChart->AppendRadioItem(
581 ID_DEF_MENU_GROUPBASE, _("All Active Charts"));
582
583 SetMenuItemFont1(subItem0);
584
585 for (unsigned int i = 0; i < g_pGroupArray->GetCount(); i++) {
586 subItem0 = subMenuChart->AppendRadioItem(
587 ID_DEF_MENU_GROUPBASE + i + 1, g_pGroupArray->Item(i)->m_group_name);
588 SetMenuItemFont1(subItem0);
589 }
590
591#ifdef __WXMSW__
592 subMenuChart->Remove(wxID_CANCEL);
593#endif
594 subMenuChart->Check(ID_DEF_MENU_GROUPBASE + parent->m_groupIndex, true);
595 }
596
597 // This is the default context menu
598 menuFocus = contextMenu;
599
600 wxString name;
601 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
602 if (g_pAIS) {
603 if (parent->GetShowAIS() &&
604 (seltype & SELTYPE_AISTARGET &&
605 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_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 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_ROUTE)) {
686 if (!g_bBasicMenus && m_pSelectedRoute) {
687 name = m_pSelectedRoute->m_RouteNameString;
688 if (name.IsEmpty()) name = _("Unnamed Route");
689 name.Prepend(" ( ").Append(" )");
690 } else
691 name = wxEmptyString;
692 bool blay = false;
693 if (m_pSelectedRoute && m_pSelectedRoute->m_bIsInLayer) blay = true;
694
695 if (blay) {
696 menuRoute = new wxMenu(_("Layer Route") + name);
697 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES, _("Properties") + "...");
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, _("Properties") + "...");
715 if (m_pSelectedRoute) {
716 if (m_pSelectedRoute->IsActive()) {
717 int indexActive = m_pSelectedRoute->GetIndexOf(
718 m_pSelectedRoute->m_pRouteActivePoint);
719 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
720 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
721 _("Activate Next Waypoint"));
722 }
723 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
724 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
725 } else {
726 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
727 }
728 }
729 MenuAppend1(menuRoute, ID_RT_MENU_INSERT, _("Insert Waypoint"));
730 MenuAppend1(menuRoute, ID_RT_MENU_APPEND, _("Append Waypoint"));
731 if (!(seltype & SELTYPE_ROUTEPOINT) && m_pSelectedRoute) {
732 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
733 if (m_SelectedIdx > 1 &&
734 m_SelectedIdx < m_pSelectedRoute->GetnPoints() - 1)
735 MenuAppend1(menuRoute, ID_RT_MENU_SPLIT_LEG, _("Split around Leg"));
736 }
737 MenuAppend1(menuRoute, ID_RT_MENU_COPY, _("Copy as KML") + "...");
738 MenuAppend1(menuRoute, ID_RT_MENU_DELETE, _("Delete") + "...");
739 MenuAppend1(menuRoute, ID_RT_MENU_REVERSE, _("Reverse..."));
740 if (m_pSelectedRoute) {
741 if (m_pSelectedRoute->AreWaypointNamesVisible())
742 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
743 _("Hide Waypoint Names"));
744 else
745 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
746 _("Show Waypoint Names"));
747 }
748 MenuAppend1(menuRoute, ID_RT_MENU_RESEQUENCE,
749 _("Resequence Waypoints..."));
750
751 // #ifndef __ANDROID__
752 wxString port = parent->FindValidUploadPort();
753 parent->m_active_upload_port = port;
754 wxString item = _("Send to GPS");
755 if (!port.IsEmpty()) {
756 item.Append(" ( ");
757 item.Append(port);
758 item.Append(" )");
759 }
760 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOGPS, item);
761
762 if (!port.IsEmpty()) {
763 wxString item = _("Send to new GPS");
764 MenuAppend1(menuRoute, ID_RT_MENU_SENDTONEWGPS, item);
765 }
766 // #endif
767 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
768 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOPEER, itemstp);
769 }
770 // Eventually set this menu as the "focused context menu"
771 if (menuFocus != menuAIS) menuFocus = menuRoute;
772 }
773
774 if (seltype & SELTYPE_TRACKSEGMENT &&
775 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_TRACK)) {
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, _("Properties") + "...");
787 } else {
788 menuTrack = new wxMenu(_("Track") + name);
789 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES, _("Properties") + "...");
790 MenuAppend1(menuTrack, ID_TK_MENU_COPY, _("Copy as KML"));
791 MenuAppend1(menuTrack, ID_TK_MENU_DELETE, _("Delete") + "...");
792 }
793
794 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
795 MenuAppend1(menuTrack, ID_TK_MENU_SENDTOPEER, itemstp);
796
797 // Eventually set this menu as the "focused context menu"
798 if (menuFocus != menuAIS) menuFocus = menuTrack;
799 }
800
801 if (seltype & SELTYPE_ROUTEPOINT &&
802 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_WAYPOINT)) {
803 if (!g_bBasicMenus && m_pFoundRoutePoint) {
804 name = m_pFoundRoutePoint->GetName();
805 if (name.IsEmpty()) name = _("Unnamed Waypoint");
806 name.Prepend(" ( ").Append(" )");
807 } else
808 name = wxEmptyString;
809 bool blay = false;
810 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
811
812 if (blay) {
813 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
814 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
815
816 if (m_pSelectedRoute && m_pSelectedRoute->IsActive())
817 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
818 } else {
819 menuWaypoint = new wxMenu(_("Waypoint") + name);
820 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
821 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
822 if (m_pSelectedRoute->m_pRouteActivePoint != m_pFoundRoutePoint)
823 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
824 }
825
826 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
827 if (m_pSelectedRoute->m_pRouteActivePoint == m_pFoundRoutePoint) {
828 int indexActive = m_pSelectedRoute->GetIndexOf(
829 m_pSelectedRoute->m_pRouteActivePoint);
830 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints())
831 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTNXTPOINT,
832 _("Activate Next Waypoint"));
833 }
834 }
835 if (m_pSelectedRoute && m_pSelectedRoute->GetnPoints() > 2) {
836 MenuAppend1(menuWaypoint, ID_RT_MENU_REMPOINT, _("Remove from Route"));
837
838 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
839 if (m_SelectedIdx > 1 && m_SelectedIdx < m_pSelectedRoute->GetnPoints())
840 MenuAppend1(menuWaypoint, ID_RT_MENU_SPLIT_WPT,
841 _("Split Route at Waypoint"));
842 }
843
844 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
845
846 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != "mob")
847 MenuAppend1(menuWaypoint, ID_RT_MENU_DELPOINT, _("Delete"));
848
849 // #ifndef __ANDROID__
850 wxString port = parent->FindValidUploadPort();
851 parent->m_active_upload_port = port;
852 wxString item = _("Send to GPS");
853 if (!port.IsEmpty()) {
854 item.Append(" ( ");
855 item.Append(port);
856 item.Append(" )");
857 }
858 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
859
860 if (!port.IsEmpty()) {
861 wxString item = _("Send to new GPS");
862 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTONEWGPS, item);
863 }
864
865 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
866 SYMBOL_STP_TITLE); // Send to Peer
867 }
868
869 // Eventually set this menu as the "focused context menu"
870 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
871 }
872
873 if (seltype & SELTYPE_MARKPOINT &&
874 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_WAYPOINT)) {
875 if (!g_bBasicMenus && m_pFoundRoutePoint) {
876 name = m_pFoundRoutePoint->GetName();
877 if (name.IsEmpty()) name = _("Unnamed Mark");
878 name.Prepend(" ( ").Append(" )");
879 } else
880 name = wxEmptyString;
881 bool blay = false;
882 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
883
884 if (blay) {
885 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
886 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
887 } else {
888 menuWaypoint = new wxMenu(_("Mark") + name);
889 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
890
891 if (!g_pRouteMan->GetpActiveRoute())
892 MenuAppend1(menuWaypoint, ID_WP_MENU_GOTO, _("Navigate To This"));
893
894 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
895
896 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != "mob")
897 MenuAppend1(menuWaypoint, ID_WP_MENU_DELPOINT, _("Delete"));
898
899 // #ifndef __ANDROID__
900 wxString port = parent->FindValidUploadPort();
901 parent->m_active_upload_port = port;
902 wxString item = _("Send to GPS");
903 if (!port.IsEmpty()) {
904 item.Append(" ( ");
905 item.Append(port);
906 item.Append(" )");
907 }
908 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
909
910 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
911 SYMBOL_STP_TITLE); // Send to Peer
912 // #endif
913
914 if ((m_pFoundRoutePoint == pAnchorWatchPoint1) ||
915 (m_pFoundRoutePoint == pAnchorWatchPoint2))
916 MenuAppend1(menuWaypoint, ID_WP_MENU_CLEAR_ANCHORWATCH,
917 _("Clear Anchor Watch"));
918 else {
919 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
920 ((NULL == pAnchorWatchPoint1) || (NULL == pAnchorWatchPoint2))) {
921 double dist;
922 double brg;
923 DistanceBearingMercator(m_pFoundRoutePoint->m_lat,
924 m_pFoundRoutePoint->m_lon, gLat, gLon, &brg,
925 &dist);
926 if (dist * 1852. <= g_nAWMax)
927 MenuAppend1(menuWaypoint, ID_WP_MENU_SET_ANCHORWATCH,
928 _("Set Anchor Watch"));
929 }
930 }
931 }
932 // Eventually set this menu as the "focused context menu"
933 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
934 }
935
936 // Add plugin context items to the correct menu
937 AddPluginContextMenuItems(contextMenu, menuRoute, menuTrack, menuWaypoint,
938 menuAIS);
939
940 /*add the relevant submenus*/
941 enum { WPMENU = 1, TKMENU = 2, RTMENU = 4, MMMENU = 8 };
942 int sub_menu = 0;
943 if (!g_bBasicMenus && menuFocus != contextMenu) {
944 if (global_color_scheme != GLOBAL_COLOR_SCHEME_DUSK &&
945 global_color_scheme != GLOBAL_COLOR_SCHEME_NIGHT) {
946 menuFocus->AppendSeparator();
947 }
948
949 wxMenuItem *subMenu1;
950 if (menuWaypoint && menuFocus != menuWaypoint) {
951 subMenu1 =
952 menuFocus->AppendSubMenu(menuWaypoint, menuWaypoint->GetTitle());
953 SetMenuItemFont1(subMenu1);
954 sub_menu |= WPMENU;
955#ifdef __WXMSW__
956 menuWaypoint->SetTitle(wxEmptyString);
957#endif
958 }
959 if (menuTrack && menuFocus != menuTrack) {
960 subMenu1 = menuFocus->AppendSubMenu(menuTrack, menuTrack->GetTitle());
961 SetMenuItemFont1(subMenu1);
962 sub_menu |= TKMENU;
963#ifdef __WXMSW__
964 menuTrack->SetTitle(wxEmptyString);
965#endif
966 }
967 if (menuRoute && menuFocus != menuRoute) {
968 subMenu1 = menuFocus->AppendSubMenu(menuRoute, menuRoute->GetTitle());
969 SetMenuItemFont1(subMenu1);
970 sub_menu |= RTMENU;
971#ifdef __WXMSW__
972 menuRoute->SetTitle(wxEmptyString);
973#endif
974 }
975 subMenu1 = menuFocus->AppendSubMenu(contextMenu, _("Main Menu"));
976 SetMenuItemFont1(subMenu1);
977 sub_menu |= MMMENU;
978 }
979
980 if (!subMenuChart->GetMenuItemCount()) contextMenu->Destroy(subItemChart);
981
982 // Add the Tide/Current selections if the item was not activated by shortcut
983 // in right-click handlers
984 bool bsep = false;
985 if (seltype & SELTYPE_TIDEPOINT) {
986 menuFocus->AppendSeparator();
987 bsep = true;
988 MenuAppend1(menuFocus, ID_DEF_MENU_TIDEINFO, _("Show Tide Information"));
989 }
990
991 if (seltype & SELTYPE_CURRENTPOINT) {
992 if (!bsep) menuFocus->AppendSeparator();
993 MenuAppend1(menuFocus, ID_DEF_MENU_CURRENTINFO,
994 _("Show Current Information"));
995 }
996
997 // Invoke the correct focused drop-down menu
998
999#ifdef __ANDROID__
1000 androidEnableBackButton(false);
1001 androidEnableOptionsMenu(false);
1002
1003 setMenuStyleSheet(menuRoute, GetOCPNGUIScaledFont(_("Menu")));
1004 setMenuStyleSheet(menuWaypoint, GetOCPNGUIScaledFont(_("Menu")));
1005 setMenuStyleSheet(menuTrack, GetOCPNGUIScaledFont(_("Menu")));
1006 setMenuStyleSheet(menuAIS, GetOCPNGUIScaledFont(_("Menu")));
1007#endif
1008
1009 parent->PopupMenu(menuFocus, x, y);
1010
1011#ifdef __ANDROID__
1012 androidEnableBackButton(true);
1013 androidEnableOptionsMenu(true);
1014#endif
1015
1016 /* Cleanup if necessary.
1017 Do not delete menus witch are submenu as they will be deleted by their parent
1018 menu. This could create a crash*/
1019 delete menuAIS;
1020 if (!(sub_menu & MMMENU)) delete contextMenu;
1021 if (!(sub_menu & RTMENU)) delete menuRoute;
1022 if (!(sub_menu & TKMENU)) delete menuTrack;
1023 if (!(sub_menu & WPMENU)) delete menuWaypoint;
1024}
1025
1026void CanvasMenuHandler::AddPluginContextMenuItems(wxMenu *contextMenu,
1027 wxMenu *menuRoute,
1028 wxMenu *menuTrack,
1029 wxMenu *menuWaypoint,
1030 wxMenu *menuAIS) {
1031 // Give the plugins a chance to update their menu items
1032 g_pi_manager->PrepareAllPluginContextMenus();
1033
1034 // Add PlugIn Context Menu items
1035 ArrayOfPlugInMenuItems item_array =
1036 g_pi_manager->GetPluginContextMenuItemArray();
1037
1038 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1039 PlugInMenuItemContainer *pimis = item_array[i];
1040 if (!pimis->b_viz) continue;
1041
1042 wxMenu *submenu = NULL;
1043 if (pimis->pmenu_item->GetSubMenu()) {
1044 // Create a clone of the submenu referenced in the PlugInMenuItemContainer
1045 auto submenu_proto = pimis->pmenu_item->GetSubMenu();
1046 submenu = new wxMenu();
1047 const wxMenuItemList &items =
1048 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1049 for (wxMenuItemList::const_iterator it = items.begin(); it != items.end();
1050 ++it) {
1051 int id = (*it)->GetId();
1052 wxMenuItem *psmi =
1053 new wxMenuItem(submenu, id, (*it)->GetItemLabelText(),
1054 (*it)->GetHelp(), (*it)->GetKind());
1055
1056#ifdef __WXMSW__
1057 psmi->SetFont(m_scaledFont);
1058#endif
1059
1060#ifdef __ANDROID__
1061 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1062 psmi->SetFont(sFont);
1063#endif
1064
1065 PrepareMenuItem(psmi);
1066 submenu->Append(psmi);
1067 psmi->Check((*it)->IsChecked());
1068 }
1069 }
1070
1071 wxMenuItem *pmi = new wxMenuItem(
1072 contextMenu, pimis->id, pimis->pmenu_item->GetItemLabelText(),
1073 pimis->pmenu_item->GetHelp(), pimis->pmenu_item->GetKind(), submenu);
1074#ifdef __WXMSW__
1075 pmi->SetFont(m_scaledFont);
1076#endif
1077
1078#ifdef __ANDROID__
1079 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1080 pmi->SetFont(sFont);
1081#endif
1082
1083 PrepareMenuItem(pmi);
1084
1085 wxMenu *dst = contextMenu;
1086 if (pimis->m_in_menu == "Waypoint")
1087 dst = menuWaypoint;
1088 else if (pimis->m_in_menu == "Route")
1089 dst = menuRoute;
1090 else if (pimis->m_in_menu == "Track")
1091 dst = menuTrack;
1092 else if (pimis->m_in_menu == "AIS")
1093 dst = menuAIS;
1094
1095 if (dst != NULL) {
1096 dst->Append(pmi);
1097 dst->Enable(pimis->id, !pimis->b_grey);
1098 }
1099 }
1100}
1101
1102void CanvasMenuHandler::PopupMenuHandler(wxCommandEvent &event) {
1103 RoutePoint *pLast;
1104
1105 wxPoint r;
1106 double zlat, zlon;
1107
1108 int splitMode = 0; // variables for split
1109 bool dupFirstWpt = true, showRPD;
1110
1111 parent->GetCanvasPixPoint(popx * parent->GetDisplayScale(),
1112 popy * parent->GetDisplayScale(), zlat, zlon);
1113
1114 switch (event.GetId()) {
1115 case ID_DEF_MENU_MAX_DETAIL:
1116 vLat = zlat;
1117 vLon = zlon;
1118 parent->ClearbFollow();
1119
1120 parent->parent_frame->DoChartUpdate();
1121
1122 parent->SelectChartFromStack(0, false, CHART_TYPE_DONTCARE,
1123 CHART_FAMILY_RASTER);
1124 break;
1125
1126 case ID_DEF_MENU_SCALE_IN:
1127 parent->DoCanvasStackDelta(-1);
1128 break;
1129
1130 case ID_DEF_MENU_SCALE_OUT:
1131 parent->DoCanvasStackDelta(1);
1132 break;
1133
1134 case ID_UNDO:
1135 parent->undo->UndoLastAction();
1136 parent->InvalidateGL();
1137 parent->Refresh(false);
1138 break;
1139
1140 case ID_REDO:
1141 parent->undo->RedoNextAction();
1142 parent->InvalidateGL();
1143 parent->Refresh(false);
1144 break;
1145
1146 case ID_DEF_MENU_MOVE_BOAT_HERE:
1147 gLat = zlat;
1148 gLon = zlon;
1149 gFrame->UpdateStatusBar();
1150 break;
1151
1152 case ID_DEF_MENU_GOTO_HERE: {
1153 RoutePoint *pWP_dest = new RoutePoint(zlat, zlon, g_default_wp_icon,
1154 wxEmptyString, wxEmptyString);
1155 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP_dest);
1156
1157 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1158 wxEmptyString, wxEmptyString);
1159 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1160
1161 Route *temp_route = new Route();
1162 pRouteList->push_back(temp_route);
1163
1164 temp_route->AddPoint(pWP_src);
1165 temp_route->AddPoint(pWP_dest);
1166
1167 pSelect->AddSelectableRouteSegment(gLat, gLon, zlat, zlon, pWP_src,
1168 pWP_dest, temp_route);
1169
1170 temp_route->m_RouteNameString = _("Temporary GOTO Route");
1171 temp_route->m_RouteStartString = _("Here");
1172 ;
1173 temp_route->m_RouteEndString = _("There");
1174
1175 temp_route->m_bDeleteOnArrival = true;
1176
1177 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1178
1179 g_pRouteMan->ActivateRoute(temp_route, pWP_dest);
1180
1181 break;
1182 }
1183
1184 case ID_DEF_MENU_DROP_WP: {
1185 RoutePoint *pWP = new RoutePoint(zlat, zlon, g_default_wp_icon,
1186 wxEmptyString, wxEmptyString);
1187 pWP->m_bIsolatedMark = true; // This is an isolated mark
1188 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP);
1189 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1190
1191 if (!RoutePointGui(*pWP).IsVisibleSelectable(this->parent))
1192 RoutePointGui(*pWP).ShowScaleWarningMessage(parent);
1193
1194 if (RouteManagerDialog::getInstanceFlag()) {
1195 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1196 pRouteManagerDialog->UpdateWptListCtrl();
1197 }
1198 }
1199
1200 parent->undo->BeforeUndoableAction(Undo_CreateWaypoint, pWP,
1201 Undo_HasParent, NULL);
1202 parent->undo->AfterUndoableAction(NULL);
1203 gFrame->RefreshAllCanvas(false);
1204 gFrame->InvalidateAllGL();
1205 g_FlushNavobjChanges = true;
1206 break;
1207 }
1208
1209 case ID_DEF_MENU_NEW_RT: {
1210 parent->StartRoute();
1211 break;
1212 }
1213
1214 case ID_DEF_MENU_AISTARGETLIST:
1215 parent->ShowAISTargetList();
1216 break;
1217
1218 case ID_DEF_MENU_AIS_CPAWARNING:
1219 parent->ToggleCPAWarn();
1220 break;
1221
1222 case ID_WP_MENU_GOTO: {
1223 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1224 wxEmptyString, wxEmptyString);
1225 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1226
1227 Route *temp_route = new Route();
1228 pRouteList->push_back(temp_route);
1229
1230 temp_route->AddPoint(pWP_src);
1231 temp_route->AddPoint(m_pFoundRoutePoint);
1232 m_pFoundRoutePoint->SetShared(true);
1233
1234 pSelect->AddSelectableRouteSegment(gLat, gLon, m_pFoundRoutePoint->m_lat,
1235 m_pFoundRoutePoint->m_lon, pWP_src,
1236 m_pFoundRoutePoint, temp_route);
1237
1238 wxString name = m_pFoundRoutePoint->GetName();
1239 if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
1240 wxString rteName = _("Go to ");
1241 rteName.Append(name);
1242 temp_route->m_RouteNameString = rteName;
1243 temp_route->m_RouteStartString = _("Here");
1244 ;
1245 temp_route->m_RouteEndString = name;
1246 temp_route->m_bDeleteOnArrival = true;
1247
1248 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1249
1250 g_pRouteMan->ActivateRoute(temp_route, m_pFoundRoutePoint);
1251
1252 break;
1253 }
1254
1255 case ID_DEF_MENU_COGUP:
1256 parent->SetUpMode(COURSE_UP_MODE);
1257 break;
1258
1259 case ID_DEF_MENU_HEADUP:
1260 parent->SetUpMode(HEAD_UP_MODE);
1261 break;
1262
1263 case ID_DEF_MENU_NORTHUP:
1264 parent->SetUpMode(NORTH_UP_MODE);
1265 break;
1266
1267 case ID_DEF_MENU_TOGGLE_FULL:
1268 gFrame->ToggleFullScreen();
1269 break;
1270
1271 case ID_DEF_MENU_GOTOPOSITION:
1272 if (NULL == pGoToPositionDialog) // There is one global instance of the
1273 // Go To Position Dialog
1275 pGoToPositionDialog->SetCanvas(parent);
1276 pGoToPositionDialog->CheckPasteBufferForPosition();
1277 pGoToPositionDialog->Show();
1278 break;
1279
1280 case ID_WP_MENU_DELPOINT: {
1281 if (m_pFoundRoutePoint == pAnchorWatchPoint1) {
1282 pAnchorWatchPoint1 = NULL;
1283 g_AW1GUID.Clear();
1284 } else if (m_pFoundRoutePoint == pAnchorWatchPoint2) {
1285 pAnchorWatchPoint2 = NULL;
1286 g_AW2GUID.Clear();
1287 }
1288
1289 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
1290 (m_pFoundRoutePoint->GetIconName() != "mob")) {
1291 // If the WP belongs to an invisible route, we come here instead of to
1292 // ID_RT_MENU_DELPOINT
1293 // Check it, and if so then remove the point from its routes
1294 wxArrayPtrVoid *proute_array =
1295 g_pRouteMan->GetRouteArrayContaining(m_pFoundRoutePoint);
1296 if (proute_array) {
1297 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1298 delete proute_array;
1299 } else {
1300 parent->undo->BeforeUndoableAction(
1301 Undo_DeleteWaypoint, m_pFoundRoutePoint, Undo_IsOrphanded,
1302 NULL /*m_pFoundPoint*/);
1303 NavObj_dB::GetInstance().DeleteRoutePoint(m_pFoundRoutePoint);
1304 pSelect->DeleteSelectablePoint(m_pFoundRoutePoint,
1305 SELTYPE_ROUTEPOINT);
1306 if (NULL != pWayPointMan)
1307 pWayPointMan->RemoveRoutePoint(m_pFoundRoutePoint);
1308 parent->undo->AfterUndoableAction(NULL);
1309 }
1310
1311 if (g_pMarkInfoDialog) {
1312 g_pMarkInfoDialog->ClearData();
1313 }
1314
1315 if (RouteManagerDialog::getInstanceFlag()) {
1316 if (pRouteManagerDialog) {
1317 if (pRouteManagerDialog->IsShown())
1318 pRouteManagerDialog->UpdateWptListCtrl();
1319 }
1320 }
1321
1322 gFrame->RefreshAllCanvas(false);
1323 gFrame->InvalidateAllGL();
1324 }
1325 break;
1326 }
1327 case ID_WP_MENU_PROPERTIES:
1328 parent->ShowMarkPropertiesDialog(m_pFoundRoutePoint);
1329 break;
1330
1331 case ID_WP_MENU_CLEAR_ANCHORWATCH: {
1332 wxString guid = wxEmptyString;
1333 if (pAnchorWatchPoint1 == m_pFoundRoutePoint) {
1334 pAnchorWatchPoint1 = NULL;
1335 guid = g_AW1GUID;
1336 g_AW1GUID.Clear();
1337 } else if (pAnchorWatchPoint2 == m_pFoundRoutePoint) {
1338 pAnchorWatchPoint2 = NULL;
1339 guid = g_AW2GUID;
1340 g_AW2GUID.Clear();
1341 }
1342 if (!guid.IsEmpty()) {
1343 wxJSONValue v;
1344 v["GUID"] = guid;
1345 wxString msg_id("OCPN_ANCHOR_WATCH_CLEARED");
1346 SendJSONMessageToAllPlugins(msg_id, v);
1347 }
1348 break;
1349 }
1350
1351 case ID_WP_MENU_SET_ANCHORWATCH: {
1352 wxString guid = wxEmptyString;
1353 if (pAnchorWatchPoint1 == NULL) {
1354 pAnchorWatchPoint1 = m_pFoundRoutePoint;
1355 g_AW1GUID = pAnchorWatchPoint1->m_GUID;
1356 guid = g_AW1GUID;
1357 wxString nn;
1358 nn = m_pFoundRoutePoint->GetName();
1359 if (nn.IsNull()) {
1360 nn.Printf("%d m", g_nAWDefault);
1361 m_pFoundRoutePoint->SetName(nn);
1362 }
1363 } else if (pAnchorWatchPoint2 == NULL) {
1364 pAnchorWatchPoint2 = m_pFoundRoutePoint;
1365 g_AW2GUID = pAnchorWatchPoint2->m_GUID;
1366 guid = g_AW2GUID;
1367 wxString nn;
1368 nn = m_pFoundRoutePoint->GetName();
1369 if (nn.IsNull()) {
1370 nn.Printf("%d m", g_nAWDefault);
1371 m_pFoundRoutePoint->SetName(nn);
1372 }
1373 }
1374 if (!guid.IsEmpty()) {
1375 wxJSONValue v;
1376 v["GUID"] = guid;
1377 wxString msg_id("OCPN_ANCHOR_WATCH_SET");
1378 SendJSONMessageToAllPlugins(msg_id, v);
1379 }
1380 break;
1381 }
1382
1383 case ID_DEF_MENU_ACTIVATE_MEASURE:
1384 parent->StartMeasureRoute();
1385 break;
1386
1387 case ID_DEF_MENU_DEACTIVATE_MEASURE:
1388 parent->CancelMeasureRoute();
1389 // gFrame->SurfaceAllCanvasToolbars();
1390 parent->InvalidateGL();
1391 parent->Refresh(false);
1392 break;
1393
1394 case ID_DEF_MENU_CM93OFFSET_DIALOG: {
1395 if (NULL == g_pCM93OffsetDialog) {
1396 g_pCM93OffsetDialog = new CM93OffsetDialog(parent->parent_frame);
1397 }
1398
1399 cm93compchart *pch = NULL;
1400 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
1401 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
1402 pch = (cm93compchart *)parent->m_singleChart;
1403 }
1404
1405 if (g_pCM93OffsetDialog) {
1406 g_pCM93OffsetDialog->SetCM93Chart(pch);
1407 g_pCM93OffsetDialog->Show();
1408 g_pCM93OffsetDialog->UpdateMCOVRList(parent->GetVP());
1409 }
1410
1411 break;
1412 }
1413 case ID_DEF_MENU_QUERY: {
1414 parent->ShowObjectQueryWindow(popx, popy, zlat, zlon);
1415 break;
1416 }
1417 case ID_DEF_MENU_AIS_QUERY: {
1418 ShowAISTargetQueryDialog(parent, m_FoundAIS_MMSI);
1419 break;
1420 }
1421
1422 case ID_DEF_MENU_AIS_CPA: {
1423 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1424 if (myptarget) myptarget->Toggle_AIS_CPA();
1425 break;
1426 }
1427
1428 case ID_DEF_MENU_AISSHOWTRACK: {
1429 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1430 if (myptarget) myptarget->ToggleShowTrack();
1431 break;
1432 }
1433
1434 case ID_DEF_MENU_COPY_MMSI: {
1435 // Write MMSI # as text to the clipboard
1436 if (wxTheClipboard->Open()) {
1437 wxTheClipboard->SetData(
1438 new wxTextDataObject(wxString::Format("%09d", m_FoundAIS_MMSI)));
1439 wxTheClipboard->Close();
1440 }
1441 break;
1442 }
1443
1444 case ID_DEF_MENU_QUILTREMOVE: {
1445 if (parent->GetVP().b_quilt) {
1446 int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
1447 parent->GetVP(), wxPoint(popx, popy));
1448 parent->RemoveChartFromQuilt(dbIndex);
1449
1450 parent->ReloadVP();
1451 }
1452
1453 break;
1454 }
1455
1456 case ID_DEF_MENU_CURRENTINFO: {
1457 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1458 parent->Refresh(false);
1459
1460 break;
1461 }
1462
1463 case ID_DEF_MENU_TIDEINFO: {
1464 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1465 parent->Refresh(false);
1466
1467 break;
1468 }
1469
1470 case ID_DGB_MENU_NMEA_WINDOW:
1471 m_nmea_log->Show();
1472 m_nmea_log->Raise();
1473 break;
1474
1475 case ID_RT_MENU_REVERSE: {
1476 if (m_pSelectedRoute->m_bIsInLayer) break;
1477
1478 int ask_return =
1479 OCPNMessageBox(parent, g_pRouteMan->GetRouteReverseMessage(),
1480 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1481
1482 if (ask_return != wxID_CANCEL) {
1483 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1484 m_pSelectedRoute->Reverse(ask_return == wxID_YES);
1485 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1486
1487 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1488
1489 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1490 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute);
1491 // pNew->UpdateProperties();
1492 }
1493 gFrame->InvalidateAllGL();
1494 gFrame->RefreshAllCanvas();
1495 }
1496 break;
1497 }
1498
1499 case ID_RT_MENU_SHOWNAMES: {
1500 if (m_pSelectedRoute) {
1501 m_pSelectedRoute->ShowWaypointNames(
1502 !m_pSelectedRoute->AreWaypointNamesVisible());
1503 }
1504
1505 break;
1506 }
1507
1508 case ID_RT_MENU_RESEQUENCE: {
1509 if (m_pSelectedRoute) {
1510 if (m_pSelectedRoute->m_bIsInLayer) break;
1511
1512 int ask_return =
1513 OCPNMessageBox(parent, g_pRouteMan->GetRouteResequenceMessage(),
1514 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1515
1516 if (ask_return != wxID_CANCEL) {
1517 m_pSelectedRoute->RenameRoutePoints();
1518 }
1519
1520 gFrame->InvalidateAllGL();
1521 gFrame->RefreshAllCanvas();
1522 }
1523
1524 break;
1525 }
1526
1527 case ID_RT_MENU_DELETE: {
1528 bool confirmed = RouteGui::OnDelete(parent);
1529
1530 if (confirmed) {
1531 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1532 g_pRouteMan->DeactivateRoute();
1533
1534 if (m_pSelectedRoute->m_bIsInLayer) break;
1535
1536 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1537 if (!g_pRouteMan->DeleteRoute(m_pSelectedRoute)) break;
1538
1539 if (RouteManagerDialog::getInstanceFlag()) {
1540 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1541 pRouteManagerDialog->UpdateRouteListCtrl();
1542 }
1543
1544 if (g_pMarkInfoDialog && g_pMarkInfoDialog->IsShown()) {
1545 g_pMarkInfoDialog->ValidateMark();
1546 g_pMarkInfoDialog->UpdateProperties();
1547 }
1548
1549 parent->undo->InvalidateUndo();
1550
1551 gFrame->InvalidateAllGL();
1552 gFrame->RefreshAllCanvas();
1553 }
1554 break;
1555 }
1556
1557 case ID_RT_MENU_ACTIVATE: {
1558 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1559
1560 // If this is an auto-created MOB route, always select the second point
1561 // (the MOB)
1562 // as the destination.
1563 RoutePoint *best_point;
1564 if (m_pSelectedRoute) {
1565 if (wxNOT_FOUND == m_pSelectedRoute->m_RouteNameString.Find("MOB")) {
1566 best_point = g_pRouteMan->FindBestActivatePoint(
1567 m_pSelectedRoute, gLat, gLon, gCog, gSog);
1568 } else
1569 best_point = m_pSelectedRoute->GetPoint(2);
1570
1571 g_pRouteMan->ActivateRoute(m_pSelectedRoute, best_point);
1572 m_pSelectedRoute->m_bRtIsSelected = false;
1573 }
1574
1575 break;
1576 }
1577
1578 case ID_RT_MENU_DEACTIVATE:
1579 g_pRouteMan->DeactivateRoute();
1580 m_pSelectedRoute->m_bRtIsSelected = false;
1581
1582 break;
1583
1584 case ID_RT_MENU_INSERT: {
1585 if (m_pSelectedRoute->m_bIsInLayer) break;
1586 bool rename = false;
1587 m_pSelectedRoute->InsertPointAfter(m_pFoundRoutePoint, zlat, zlon,
1588 rename);
1589
1590 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1591 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1592
1593 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1594 pSelect->AddAllSelectableRoutePoints(m_pSelectedRoute);
1595
1596 // As a special case (which comes up often)...
1597 // If the inserted waypoint is on the active leg of an active route
1598 /* if(m_pSelectedRoute->m_bRtIsActive)
1599 {
1600 if(m_pSelectedRoute->m_nRouteActivePoint == np + 1)
1601 {
1602 pNew_Point = m_pSelectedRoute->GetPoint(np + 2);
1603 pRouteMan->ActivateRoutePoint(m_pSelectedRoute, pNew_Point);
1604 }
1605 }
1606 */
1607 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1608
1609 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1610 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1611 }
1612
1613 break;
1614 }
1615
1616 case ID_RT_MENU_APPEND:
1617
1618 if (m_pSelectedRoute->m_bIsInLayer) break;
1619
1620 parent->m_pMouseRoute = m_pSelectedRoute;
1621 parent->m_routeState = m_pSelectedRoute->GetnPoints() + 1;
1622 parent->m_pMouseRoute->m_lastMousePointIndex =
1623 m_pSelectedRoute->GetnPoints();
1624 parent->m_pMouseRoute->SetHiLite(50);
1625
1626 pLast = m_pSelectedRoute->GetLastPoint();
1627
1628 parent->m_prev_rlat = pLast->m_lat;
1629 parent->m_prev_rlon = pLast->m_lon;
1630 parent->m_prev_pMousePoint = pLast;
1631
1632 parent->m_bAppendingRoute = true;
1633
1634 parent->SetCursor(*parent->pCursorPencil);
1635#ifdef __ANDROID__
1636 androidSetRouteAnnunciator(true);
1637#endif
1638
1639 parent->HideGlobalToolbar();
1640
1641 break;
1642
1643 case ID_RT_MENU_SPLIT_LEG: // split route around a leg
1644 splitMode++;
1645 dupFirstWpt = false;
1646 case ID_RT_MENU_SPLIT_WPT: // split route at a wpt
1647
1648 showRPD = (pRoutePropDialog && pRoutePropDialog->IsShown());
1649
1650 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1651 g_pRouteMan->DeactivateRoute();
1652
1653 m_pHead = new Route();
1654 m_pTail = new Route();
1655 m_pHead->CloneRoute(m_pSelectedRoute, 1, m_SelectedIdx, _("_A"));
1656 m_pTail->CloneRoute(m_pSelectedRoute, m_SelectedIdx + splitMode,
1657 m_pSelectedRoute->GetnPoints(), _("_B"), dupFirstWpt);
1658 pRouteList->push_back(m_pHead);
1659 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1660
1661 pRouteList->push_back(m_pTail);
1662 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1663
1664 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1665
1666 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1667 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1668 g_pRouteMan->DeleteRoute(m_pSelectedRoute);
1669 pSelect->AddAllSelectableRouteSegments(m_pTail);
1670 pSelect->AddAllSelectableRoutePoints(m_pTail);
1671 pSelect->AddAllSelectableRouteSegments(m_pHead);
1672 pSelect->AddAllSelectableRoutePoints(m_pHead);
1673
1674 if (showRPD) {
1675 pRoutePropDialog->SetRouteAndUpdate(m_pHead);
1676 pRoutePropDialog->Show();
1677 }
1678 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog &&
1679 (pRouteManagerDialog->IsShown()))
1680 pRouteManagerDialog->UpdateRouteListCtrl();
1681 break;
1682
1683 case ID_RT_MENU_COPY:
1684 if (m_pSelectedRoute) Kml::CopyRouteToClipboard(m_pSelectedRoute);
1685 break;
1686
1687 case ID_TK_MENU_COPY:
1688 if (m_pSelectedTrack) Kml::CopyTrackToClipboard(m_pSelectedTrack);
1689 break;
1690
1691 case ID_WPT_MENU_COPY:
1692 if (m_pFoundRoutePoint) Kml::CopyWaypointToClipboard(m_pFoundRoutePoint);
1693 break;
1694
1695 case ID_WPT_MENU_SENDTOGPS:
1696 if (m_pFoundRoutePoint) {
1697 if (parent->m_active_upload_port.Length())
1698 RoutePointGui(*m_pFoundRoutePoint)
1699 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), NULL);
1700 else {
1701 SendToGpsDlg dlg;
1702 dlg.SetWaypoint(m_pFoundRoutePoint);
1703 wxFont fo = GetOCPNGUIScaledFont(_("Dialog"));
1704 dlg.SetFont(fo);
1705
1706 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1707 dlg.ShowModal();
1708 }
1709 }
1710 break;
1711
1712 case ID_WPT_MENU_SENDTONEWGPS:
1713 if (m_pFoundRoutePoint) {
1714 SendToGpsDlg dlg;
1715 dlg.SetWaypoint(m_pFoundRoutePoint);
1716
1717 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1718 dlg.ShowModal();
1719 }
1720 break;
1721
1722 case ID_WPT_MENU_SENDTOPEER:
1723 if (m_pFoundRoutePoint) {
1724 SendToPeerDlg dlg;
1725 dlg.SetWaypoint(m_pFoundRoutePoint);
1726
1727 // Perform initial scan, if necessary
1728
1729 // Check for stale cache...
1730 MdnsCache::GetInstance().Validate();
1731 if (MdnsCache::GetInstance().GetCache().empty())
1732 dlg.SetScanOnCreate(true);
1733
1734 dlg.SetScanTime(5); // seconds
1735 dlg.Create(NULL, -1, _("Send Waypoint to OpenCPN Peer") + "...", "");
1736 dlg.ShowModal();
1737 }
1738 break;
1739
1740 case ID_RT_MENU_SENDTOGPS:
1741 if (m_pSelectedRoute) {
1742 if (parent->m_active_upload_port.Length())
1743 RouteGui(*m_pSelectedRoute)
1744 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), true,
1745 NULL);
1746 else {
1747 SendToGpsDlg dlg;
1748 dlg.SetRoute(m_pSelectedRoute);
1749
1750 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1751 dlg.ShowModal();
1752 }
1753 }
1754 break;
1755
1756 case ID_RT_MENU_SENDTONEWGPS:
1757 if (m_pSelectedRoute) {
1758 SendToGpsDlg dlg;
1759 dlg.SetRoute(m_pSelectedRoute);
1760
1761 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1762 dlg.ShowModal();
1763 }
1764 break;
1765
1766 case ID_RT_MENU_SENDTOPEER:
1767 if (m_pSelectedRoute) {
1768 SendToPeerDlg dlg;
1769 dlg.SetRoute(m_pSelectedRoute);
1770
1771 // Perform initial scan, if necessary
1772
1773 // Check for stale cache...
1774 MdnsCache::GetInstance().Validate();
1775 if (MdnsCache::GetInstance().GetCache().empty())
1776 dlg.SetScanOnCreate(true);
1777
1778 dlg.SetScanTime(5); // seconds
1779 dlg.Create(NULL, -1, _("Send Route to OpenCPN Peer") + "...", "");
1780 dlg.ShowModal();
1781 }
1782 break;
1783
1784 case ID_PASTE_WAYPOINT:
1785 pupHandler_PasteWaypoint();
1786 break;
1787
1788 case ID_PASTE_ROUTE:
1789 pupHandler_PasteRoute();
1790 break;
1791
1792 case ID_PASTE_TRACK:
1793 pupHandler_PasteTrack();
1794 break;
1795
1796 case ID_RT_MENU_DELPOINT:
1797 if (m_pSelectedRoute) {
1798 if (m_pSelectedRoute->m_bIsInLayer) break;
1799
1800 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1801
1802 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1803 // Selected route may have been deleted as one-point route, so
1804 // check it
1805 if (g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
1806 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1807 } else
1808 pRoutePropDialog->Hide();
1809 }
1810
1811 if (RouteManagerDialog::getInstanceFlag()) {
1812 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1813 pRouteManagerDialog->UpdateWptListCtrl();
1814 pRouteManagerDialog->UpdateRouteListCtrl();
1815 }
1816 }
1817
1818 gFrame->InvalidateAllGL();
1819 gFrame->RefreshAllCanvas(true);
1820 }
1821
1822 break;
1823
1824 case ID_RT_MENU_REMPOINT:
1825 if (m_pSelectedRoute) {
1826 if (m_pSelectedRoute->m_bIsInLayer) break;
1827 g_pRouteMan->RemovePointFromRoute(m_pFoundRoutePoint, m_pSelectedRoute,
1828 parent->m_routeState);
1829 gFrame->InvalidateAllGL();
1830 gFrame->RefreshAllCanvas();
1831 }
1832 break;
1833
1834 case ID_RT_MENU_ACTPOINT:
1835 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1836 g_pRouteMan->ActivateRoutePoint(m_pSelectedRoute, m_pFoundRoutePoint);
1837 m_pSelectedRoute->m_bRtIsSelected = false;
1838 }
1839
1840 break;
1841
1842 case ID_RT_MENU_DEACTPOINT:
1843 break;
1844
1845 case ID_RT_MENU_ACTNXTPOINT:
1846 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1847 g_pRouteMan->ActivateNextPoint(m_pSelectedRoute, true);
1848 m_pSelectedRoute->m_bRtIsSelected = false;
1849 }
1850
1851 break;
1852
1853 case ID_RT_MENU_PROPERTIES: {
1854 parent->ShowRoutePropertiesDialog(_("Route Properties"),
1855 m_pSelectedRoute);
1856 break;
1857 }
1858
1859 case ID_TK_MENU_PROPERTIES: {
1860 parent->ShowTrackPropertiesDialog(m_pSelectedTrack);
1861 break;
1862 }
1863
1864 case ID_TK_MENU_DELETE: {
1865 int dlg_return = wxID_YES;
1866 if (g_bConfirmObjectDelete) {
1867 dlg_return = OCPNMessageBox(
1868 parent, _("Are you sure you want to delete this track?"),
1869 _("OpenCPN Track Delete"),
1870 (long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
1871 }
1872
1873 if (dlg_return == wxID_YES) {
1874 if (m_pSelectedTrack == g_pActiveTrack)
1875 m_pSelectedTrack = parent->parent_frame->TrackOff();
1876 g_pAIS->DeletePersistentTrack(m_pSelectedTrack);
1877 // pConfig->DeleteConfigTrack(m_pSelectedTrack);
1878 NavObj_dB::GetInstance().DeleteTrack(m_pSelectedTrack);
1879 RoutemanGui(*g_pRouteMan).DeleteTrack(m_pSelectedTrack);
1880
1881 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
1882 (pTrackPropDialog->IsShown()) &&
1883 (m_pSelectedTrack == pTrackPropDialog->GetTrack())) {
1884 pTrackPropDialog->Hide();
1885 }
1886
1887 if (RoutePropDlgImpl::getInstanceFlag() && pRouteManagerDialog &&
1888 pRouteManagerDialog->IsShown()) {
1889 pRouteManagerDialog->UpdateTrkListCtrl();
1890 pRouteManagerDialog->UpdateRouteListCtrl();
1891 }
1892 gFrame->InvalidateAllGL();
1893 gFrame->RefreshAllCanvas();
1894 }
1895 break;
1896 }
1897
1898 case ID_TK_MENU_SENDTOPEER:
1899 if (m_pSelectedTrack) {
1900 SendToPeerDlg dlg;
1901 dlg.SetTrack(m_pSelectedTrack);
1902
1903 // Perform initial scan, if necessary
1904
1905 // Check for stale cache...
1906 MdnsCache::GetInstance().Validate();
1907 if (MdnsCache::GetInstance().GetCache().empty())
1908 dlg.SetScanOnCreate(true);
1909
1910 dlg.SetScanTime(5); // seconds
1911 dlg.Create(NULL, -1, _("Send Track to OpenCPN Peer") + "...", "");
1912 dlg.ShowModal();
1913 }
1914 break;
1915
1916 case ID_RC_MENU_SCALE_IN:
1917 parent->parent_frame->DoStackDown(parent);
1918 parent->GetCanvasPointPix(zlat, zlon, &r);
1919 parent->WarpPointer(r.x, r.y);
1920 break;
1921
1922 case ID_RC_MENU_SCALE_OUT:
1923 parent->parent_frame->DoStackUp(parent);
1924 parent->GetCanvasPointPix(zlat, zlon, &r);
1925 parent->WarpPointer(r.x, r.y);
1926 break;
1927
1928 case ID_RC_MENU_ZOOM_IN:
1929 parent->SetVPScale(parent->GetVPScale() * 2);
1930 parent->GetCanvasPointPix(zlat, zlon, &r);
1931 parent->WarpPointer(r.x, r.y);
1932 break;
1933
1934 case ID_RC_MENU_ZOOM_OUT:
1935 parent->SetVPScale(parent->GetVPScale() / 2);
1936 parent->GetCanvasPointPix(zlat, zlon, &r);
1937 parent->WarpPointer(r.x, r.y);
1938 break;
1939
1940 case ID_RC_MENU_FINISH:
1941 parent->FinishRoute();
1942 // gFrame->SurfaceAllCanvasToolbars();
1943 parent->Refresh(false);
1944 g_FlushNavobjChanges = true;
1945 break;
1946
1947 case ID_DEF_ZERO_XTE:
1948 g_pRouteMan->ZeroCurrentXTEToActivePoint();
1949 break;
1950
1951 default: {
1952 // Look for PlugIn Context Menu selections
1953 // If found, make the callback
1954 ArrayOfPlugInMenuItems item_array =
1955 g_pi_manager->GetPluginContextMenuItemArray();
1956
1957 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1958 PlugInMenuItemContainer *pimis = item_array[i];
1959 int target_id = pimis->id;
1960
1961 // Check submenus, if present.
1962 if (pimis->pmenu_item->GetSubMenu()) {
1963 const wxMenuItemList &items =
1964 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1965 for (wxMenuItemList::const_iterator it = items.begin();
1966 it != items.end(); ++it) {
1967 if ((*it)->GetId() == event.GetId()) {
1968 target_id = (*it)->GetId();
1969 break;
1970 }
1971 }
1972 }
1973
1974 if (pimis->m_pplugin && (target_id == event.GetId())) {
1975 if (pimis->extended) {
1976 std::string object_type;
1977 std::string object_ident;
1978
1979 if ((pimis->m_in_menu.IsSameAs("Waypoint")) && m_pFoundRoutePoint) {
1980 object_type = "Waypoint";
1981 object_ident = m_pFoundRoutePoint->m_GUID.ToStdString();
1982 } else if ((pimis->m_in_menu.IsSameAs("Route")) &&
1983 m_pSelectedRoute) {
1984 object_type = "Route";
1985 object_ident = m_pSelectedRoute->m_GUID.ToStdString();
1986 } else if ((pimis->m_in_menu.IsSameAs("Track")) &&
1987 m_pSelectedTrack) {
1988 object_type = "Track";
1989 object_ident = m_pSelectedTrack->m_GUID.ToStdString();
1990 } else if ((pimis->m_in_menu.IsSameAs("AIS")) && m_FoundAIS_MMSI) {
1991 object_type = "AIS";
1992 wxString sAIS = wxString::Format("%d", m_FoundAIS_MMSI);
1993 object_ident = sAIS.ToStdString();
1994 }
1995
1996 opencpn_plugin_120 *ppi =
1997 dynamic_cast<opencpn_plugin_120 *>(pimis->m_pplugin);
1998 if (ppi)
1999 ppi->OnContextMenuItemCallbackExt(target_id, object_ident,
2000 object_type, zlat, zlon);
2001 } else {
2002 pimis->m_pplugin->OnContextMenuItemCallback(pimis->id);
2003 }
2004 }
2005 }
2006 break;
2007 }
2008 } // switch
2009
2010 // Chart Groups....
2011 if ((event.GetId() >= ID_DEF_MENU_GROUPBASE) &&
2012 (event.GetId() <=
2013 ID_DEF_MENU_GROUPBASE + (int)g_pGroupArray->GetCount())) {
2014 parent->SetGroupIndex(event.GetId() - ID_DEF_MENU_GROUPBASE);
2015 }
2016
2017 parent->InvalidateGL();
2018
2019 g_click_stop = 0; // Context menu was processed, all is well
2020}
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
AIS target definitions.
Canvas context (right click) menu handler.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:56
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:157
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4416
double GetDisplayScale()
Get the ratio of physical to logical pixel for the display.
Definition chcanv.h:860
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:472
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
Definition chcanv.cpp:5228
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4441
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
Definition chcanv.cpp:13525
Definition kml.h:50
void Validate()
Check that all entries are accessible, remove stale ones.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
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:99
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:203
wxString m_RouteStartString
Name or description of the route's starting point.
Definition route.h:252
bool m_bDeleteOnArrival
Flag indicating whether the route should be deleted once navigation reaches the end.
Definition route.h:268
wxString m_RouteEndString
Name or description of the route's ending point.
Definition route.h:257
RoutePoint * m_pRouteActivePoint
Pointer to the currently active waypoint within this route.
Definition route.h:214
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:247
wxString m_GUID
Globally unique identifier for this route.
Definition route.h:273
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
Definition route.h:278
int m_lastMousePointIndex
Index of the most recently interacted with route point.
Definition route.h:298
bool ActivateRoutePoint(Route *pA, RoutePoint *pRP)
Activates a specific waypoint within a route for navigation.
Definition routeman.cpp:286
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
Definition routeman.cpp:150
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
Definition routeman.cpp:357
bool DeleteRoute(Route *pRoute)
Definition routeman.cpp:762
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:222
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:117
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.
OpenCPN Georef utility.
GoToPositionDialog * pGoToPositionDialog
Global instance.
Go to position dialog...
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:59
wxFont GetOCPNGUIScaledFont(wxString item)
Retrieves a font optimized for touch and high-resolution interfaces.
Definition gui_lib.cpp:88
double vLat
Virtual lat from chcanv popup.
Definition gui_vars.cpp:72
double vLon
Virtual lon from chcanv popup.
Definition gui_vars.cpp:73
double g_androidDPmm
Only used used by ANDROID
Definition gui_vars.cpp:66
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Definition mark_info.cpp:76
Waypoint properties maintenance dialog.
mDNS host lookups cache.
MySQL based storage for routes, tracks, etc.
OpenCPN top window.
OpenCPN Platform specific support utilities.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
Definition own_ship.cpp:34
double gHdt
True heading in degrees (0-359.99).
Definition own_ship.cpp:30
double gLat
Vessel's current latitude in decimal degrees.
Definition own_ship.cpp:26
double gCog
Course over ground in degrees (0-359.99).
Definition own_ship.cpp:28
double gSog
Speed over ground in knots.
Definition own_ship.cpp:29
double gLon
Vessel's current longitude in decimal degrees.
Definition own_ship.cpp:27
Position, course, speed, etc.
Confirm peer transfer PIN code dialog.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Chart quilt support.
Route abstraction.
Route drawing stuff.
Purpose: Track and Trackpoint drawing stuff.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
Route properties dialog.
RoutePoint * pAnchorWatchPoint2
Global instance.
Definition routeman.cpp:64
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
RouteList * pRouteList
Global instance.
Definition routeman.cpp:66
RoutePoint * pAnchorWatchPoint1
Global instance.
Definition routeman.cpp:63
Route Manager.
Routeman drawing stuff.
Manage routes dialog.
S57 Chart Object.
Select * pSelect
Global instance.
Definition select.cpp:36
Selected route, segment, waypoint, etc.
Send route/waypoint to GPS dialog.
Send Route/Waypoint/Track to peer dialog.
Chart Symbols.
Tide and Current Manager @TODO Add original author copyright.
ActiveTrack * g_pActiveTrack
global instance
Definition track.cpp:99
Recorded track abstraction.
Track and Trackpoint drawing stuff.
TrackPropDlg * pTrackPropDialog
Global instance.
Track Properties Dialog.
Framework for Undo features.