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