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