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 "model/ais_decoder.h"
43#include "model/config_vars.h"
44#include "model/georef.h"
45#include "model/gui_vars.h"
46#include "model/mdns_cache.h"
47#include "model/navobj_db.h"
48#include "model/own_ship.h"
49#include "model/plugin_comm.h"
50#include "model/route.h"
51#include "model/routeman.h"
52#include "model/select.h"
53#include "model/track.h"
54
55#include "ais.h"
56#include "canvas_menu.h"
57#include "chartdb.h"
58#include "chartdbs.h"
59#include "chcanv.h"
60#include "cm93.h" // for chart outline draw
61#include "go_to_position_dlg.h"
62#include "kml.h"
63#include "mark_info.h"
64#include "ocpn_platform.h"
65#include "peer_client_dlg.h"
66#include "pluginmanager.h"
67#include "quilt.h"
68#include "route_gui.h"
69#include "routemanagerdialog.h"
70#include "routeman_gui.h"
71#include "route_point_gui.h"
72#include "route_prop_dlg_impl.h"
73#include "s52plib.h"
74#include "s57chart.h" // for ArrayOfS57Obj
75#include "send_to_gps_dlg.h"
76#include "send_to_peer_dlg.h"
77#include "styles.h"
78#include "tcmgr.h"
79#include "top_frame.h"
80#include "track_gui.h"
81#include "track_prop_dlg.h"
82#include "undo.h"
83#include "user_colors.h"
84
85#ifdef __ANDROID__
86#include "androidUTIL.h"
87#endif
88
89// Constants for right click menus
90enum {
91 ID_DEF_MENU_MAX_DETAIL = 1,
92 ID_DEF_MENU_SCALE_IN,
93 ID_DEF_MENU_SCALE_OUT,
94 ID_DEF_MENU_DROP_WP,
95 ID_DEF_MENU_NEW_RT,
96 ID_DEF_MENU_QUERY,
97 ID_DEF_MENU_MOVE_BOAT_HERE,
98 ID_DEF_MENU_GOTO_HERE,
99 ID_DEF_MENU_GOTOPOSITION,
100 ID_WP_MENU_GOTO,
101 ID_WP_MENU_DELPOINT,
102 ID_WP_MENU_PROPERTIES,
103 ID_RT_MENU_ACTIVATE,
104 ID_RT_MENU_DEACTIVATE,
105 ID_RT_MENU_INSERT,
106 ID_RT_MENU_APPEND,
107 ID_RT_MENU_COPY,
108 ID_RT_MENU_SPLIT_LEG,
109 ID_RT_MENU_SPLIT_WPT,
110 ID_TK_MENU_COPY,
111 ID_WPT_MENU_COPY,
112 ID_WPT_MENU_SENDTOGPS,
113 ID_WPT_MENU_SENDTONEWGPS,
114 ID_WPT_MENU_SENDTOPEER,
115 ID_PASTE_WAYPOINT,
116 ID_PASTE_ROUTE,
117 ID_PASTE_TRACK,
118 ID_RT_MENU_DELETE,
119 ID_RT_MENU_REVERSE,
120 ID_RT_MENU_DELPOINT,
121 ID_RT_MENU_ACTPOINT,
122 ID_RT_MENU_DEACTPOINT,
123 ID_RT_MENU_ACTNXTPOINT,
124 ID_RT_MENU_REMPOINT,
125 ID_RT_MENU_PROPERTIES,
126 ID_RT_MENU_SENDTOGPS,
127 ID_RT_MENU_SENDTONEWGPS,
128 ID_RT_MENU_SHOWNAMES,
129 ID_RT_MENU_RESEQUENCE,
130 ID_RT_MENU_SENDTOPEER,
131 ID_WP_MENU_SET_ANCHORWATCH,
132 ID_WP_MENU_CLEAR_ANCHORWATCH,
133 ID_DEF_MENU_AISTARGETLIST,
134 ID_DEF_MENU_AIS_CPAWARNING,
135
136 ID_RC_MENU_SCALE_IN,
137 ID_RC_MENU_SCALE_OUT,
138 ID_RC_MENU_ZOOM_IN,
139 ID_RC_MENU_ZOOM_OUT,
140 ID_RC_MENU_FINISH,
141 ID_DEF_MENU_AIS_QUERY,
142 ID_DEF_MENU_AIS_CPA,
143 ID_DEF_MENU_AISSHOWTRACK,
144 ID_DEF_MENU_ACTIVATE_MEASURE,
145 ID_DEF_MENU_DEACTIVATE_MEASURE,
146 ID_DEF_MENU_COPY_MMSI,
147
148 ID_UNDO,
149 ID_REDO,
150
151 ID_DEF_MENU_CM93OFFSET_DIALOG,
152
153 ID_TK_MENU_PROPERTIES,
154 ID_TK_MENU_DELETE,
155 ID_TK_MENU_SENDTOPEER,
156 ID_WP_MENU_ADDITIONAL_INFO,
157
158 ID_DEF_MENU_QUILTREMOVE,
159 ID_DEF_MENU_COGUP,
160 ID_DEF_MENU_NORTHUP,
161 ID_DEF_MENU_HEADUP,
162 ID_DEF_MENU_TOGGLE_FULL,
163 ID_DEF_MENU_TIDEINFO,
164 ID_DEF_MENU_CURRENTINFO,
165 ID_DEF_ZERO_XTE,
166
167 ID_DEF_MENU_DEBUG,
168 ID_DGB_MENU_NMEA_WINDOW,
169
170 ID_DEF_MENU_GROUPBASE, // Must be last entry, as chart group identifiers are
171 // created dynamically
172
173 ID_DEF_MENU_LAST
174};
175
176// Helper to create menu label + hotkey string when registering menus
177static wxString _menuText(wxString name, wxString shortcut) {
178 wxString menutext;
179 menutext << name;
180#ifndef __ANDROID__
181 menutext << "\t" << shortcut;
182#endif
183 return menutext;
184}
185
186//------------------------------------------------------------------------------
187// CanvasMenuHandler Implementation
188//------------------------------------------------------------------------------
189int CanvasMenuHandler::GetNextContextMenuId() {
190 return ID_DEF_MENU_LAST +
191 100; // Allowing for 100 dynamic menu item identifiers
192}
193
194wxFont CanvasMenuHandler::m_scaledFont;
195
196// Define a constructor for my canvas
197CanvasMenuHandler::CanvasMenuHandler(ChartCanvas *parentCanvas,
198 Route *selectedRoute, Track *selectedTrack,
199 RoutePoint *selectedPoint,
200 int selectedAIS_MMSI,
201 void *selectedTCIndex, wxWindow *nmea_log)
202 : m_nmea_log(nmea_log) {
203 parent = parentCanvas;
204 m_pSelectedRoute = selectedRoute;
205 m_pSelectedTrack = selectedTrack;
206 m_pFoundRoutePoint = selectedPoint;
207 m_FoundAIS_MMSI = selectedAIS_MMSI;
208 m_pIDXCandidate = selectedTCIndex;
209 if (!m_scaledFont.IsOk()) {
210 wxFont *qFont = GetOCPNScaledFont(_("Menu"));
211 m_scaledFont = *qFont;
212 }
213
214 m_DIPFactor = g_Platform->GetDisplayDIPMult(wxTheApp->GetTopWindow());
215}
216
217CanvasMenuHandler::~CanvasMenuHandler() {}
218
219//-------------------------------------------------------------------------------
220// Popup Menu Handling
221//-------------------------------------------------------------------------------
222
223void CanvasMenuHandler::PrepareMenuItem(wxMenuItem *item) {
224#if defined(__WXMSW__)
225 wxColour ctrl_back_color = GetGlobalColor("DILG1"); // Control Background
226 item->SetBackgroundColour(ctrl_back_color);
227 wxColour menu_text_color = GetGlobalColor("UITX1");
228 item->SetTextColour(menu_text_color);
229#endif
230}
231
232void CanvasMenuHandler::MenuPrepend1(wxMenu *menu, int id, wxString label) {
233 wxMenuItem *item = new wxMenuItem(menu, id, label);
234#if defined(__WXMSW__)
235 item->SetFont(m_scaledFont);
236#endif
237
238#ifdef __ANDROID__
239 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
240 item->SetFont(sFont);
241#endif
242
243 PrepareMenuItem(item);
244
245 if (g_btouch) menu->InsertSeparator(0);
246 menu->Prepend(item);
247}
248
249void CanvasMenuHandler::MenuAppend1(wxMenu *menu, int id, wxString label) {
250 wxMenuItem *item = new wxMenuItem(menu, id, label);
251#if defined(__WXMSW__)
252 item->SetFont(m_scaledFont);
253#endif
254
255#ifdef __ANDROID__
256 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
257 item->SetFont(sFont);
258#endif
259
260 PrepareMenuItem(item);
261
262 menu->Append(item);
263 if (g_btouch) menu->AppendSeparator();
264}
265
266void CanvasMenuHandler::SetMenuItemFont1(wxMenuItem *item) {
267#if defined(__WXMSW__)
268 item->SetFont(m_scaledFont);
269#endif
270
271#if defined(__ANDROID__)
272 wxFont *qFont = GetOCPNScaledFont(_("Menu"));
273 item->SetFont(*qFont);
274#endif
275
276 PrepareMenuItem(item);
277}
278
279void CanvasMenuHandler::CanvasPopupMenu(int x, int y, int seltype) {
280 wxMenu *contextMenu = new wxMenu;
281 wxMenu *menuWaypoint = NULL;
282 wxMenu *menuRoute = NULL;
283 wxMenu *menuTrack = NULL;
284 wxMenu *menuAIS = NULL;
285
286 wxMenu *subMenuChart = new wxMenu;
287 wxMenu *subMenuUndo = new wxMenu("Undo...Ctrl-Z");
288
289#ifdef __WXOSX__
290 wxMenu *subMenuRedo = new wxMenu("Redo...Shift-Ctrl-Z");
291#else
292 wxMenu *subMenuRedo = new wxMenu("Redo...Ctrl-Y");
293#endif
294 wxMenu *subMenuDebug = new wxMenu("");
295 MenuAppend1(subMenuDebug, ID_DGB_MENU_NMEA_WINDOW, _("Show Data Monitor"));
296
297 wxMenu *menuFocus = contextMenu; // This is the one that will be shown
298
299 popx = x;
300 popy = y;
301
302 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
303 bool bsubMenus = false;
304
305 if (bsubMenus) {
306 if (parent->undo->AnythingToUndo()) {
307 // Undo SubMenu
308 wxMenuItem *subMenuItemundo =
309 contextMenu->AppendSubMenu(subMenuUndo, _("Undo"));
310
311 wxString undoItem;
312 undoItem << _("Undo") << " "
313 << parent->undo->GetNextUndoableAction()->Description();
314 MenuAppend1(subMenuUndo, ID_UNDO, undoItem);
315 }
316 if (parent->undo->AnythingToRedo()) {
317 // Redo SubMenu
318 wxMenuItem *subMenuItemRedo =
319 contextMenu->AppendSubMenu(subMenuRedo, _("Redo"));
320
321 wxString redoItem;
322 redoItem << _("Redo") << " "
323 << parent->undo->GetNextRedoableAction()->Description();
324 MenuAppend1(subMenuRedo, ID_REDO, redoItem);
325 }
326 } else {
327 if (parent->undo->AnythingToUndo()) {
328 wxString undoItem;
329 undoItem << _("Undo") << " "
330 << parent->undo->GetNextUndoableAction()->Description();
331 MenuAppend1(contextMenu, ID_UNDO, _menuText(undoItem, "Ctrl-Z"));
332 }
333
334 if (parent->undo->AnythingToRedo()) {
335 wxString redoItem;
336 redoItem << _("Redo") << " "
337 << parent->undo->GetNextRedoableAction()->Description();
338#ifdef __WXOSX__
339 MenuAppend1(contextMenu, ID_REDO, _menuText(redoItem, "Shift-Ctrl-Z"));
340#else
341 MenuAppend1(contextMenu, ID_REDO, _menuText(redoItem, "Ctrl-Y"));
342#endif
343 }
344 }
345 }
346
347 if (seltype == SELTYPE_ROUTECREATE) {
348 MenuAppend1(contextMenu, ID_RC_MENU_FINISH,
349 _menuText(_("End Route"), "Esc"));
350 }
351
352 if (!parent->m_pMouseRoute) {
353 if (parent->m_bMeasure_Active)
354 MenuAppend1(contextMenu, ID_DEF_MENU_DEACTIVATE_MEASURE,
355 _menuText(_("Measure Off"), "Esc"));
356 else
357 MenuAppend1(contextMenu, ID_DEF_MENU_ACTIVATE_MEASURE,
358 _menuText(_("Measure"), "M"));
359 }
360
361 bool ais_areanotice = false;
362 if (g_pAIS && parent->GetShowAIS() && g_bShowAreaNotices) {
363 float vp_scale = parent->GetVPScale();
364
365 for (const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
366 auto target_data = target.second;
367 if (!target_data->area_notices.empty()) {
368 for (auto &ani : target_data->area_notices) {
369 Ais8_001_22 &area_notice = ani.second;
370 BoundingBox bbox;
371
372 for (Ais8_001_22_SubAreaList::iterator sa =
373 area_notice.sub_areas.begin();
374 sa != area_notice.sub_areas.end(); ++sa) {
375 switch (sa->shape) {
376 case AIS8_001_22_SHAPE_CIRCLE: {
377 wxPoint target_point;
378 parent->GetCanvasPointPix(sa->latitude, sa->longitude,
379 &target_point);
380 bbox.Expand(target_point);
381 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
382 break;
383 }
384 case AIS8_001_22_SHAPE_RECT:
385 case AIS8_001_22_SHAPE_POLYGON:
386 case AIS8_001_22_SHAPE_POLYLINE: {
387 double lat = sa->latitude;
388 double lon = sa->longitude;
389 for (int i = 0; i < 4; ++i) {
390 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
391 &lat, &lon);
392 wxPoint target_point;
393 parent->GetCanvasPointPix(lat, lon, &target_point);
394 bbox.Expand(target_point);
395 }
396 break;
397 }
398 case AIS8_001_22_SHAPE_SECTOR: {
399 double lat1 = sa->latitude;
400 double lon1 = sa->longitude;
401 double lat, lon;
402 wxPoint target_point;
403 parent->GetCanvasPointPix(lat1, lon1, &target_point);
404 bbox.Expand(target_point);
405 for (int i = 0; i < 18; ++i) {
406 ll_gc_ll(
407 lat1, lon1,
408 sa->left_bound_deg +
409 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
410 sa->radius_m / 1852.0, &lat, &lon);
411 parent->GetCanvasPointPix(lat, lon, &target_point);
412 bbox.Expand(target_point);
413 }
414 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
415 &lat, &lon);
416 parent->GetCanvasPointPix(lat, lon, &target_point);
417 bbox.Expand(target_point);
418 break;
419 }
420 }
421 }
422
423 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
424 ais_areanotice = true;
425 break;
426 }
427 }
428 }
429 }
430 }
431
432 int nChartStack = 0;
433 if (parent->GetpCurrentStack())
434 nChartStack = parent->GetpCurrentStack()->nEntry;
435
436 if (!parent->GetVP().b_quilt) {
437 if (nChartStack > 1) {
438 MenuAppend1(contextMenu, ID_DEF_MENU_MAX_DETAIL, _("Max Detail Here"));
439 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_IN,
440 _menuText(_("Scale In"), "Ctrl-Left"));
441 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_OUT,
442 _menuText(_("Scale Out"), "Ctrl-Right"));
443 }
444
445 if ((parent->m_singleChart &&
446 (parent->m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)) ||
447 ais_areanotice) {
448 MenuAppend1(contextMenu, ID_DEF_MENU_QUERY, _("Object Query") + "...");
449 }
450
451 } else {
452 ChartBase *pChartTest =
453 parent->m_pQuilt->GetChartAtPix(parent->GetVP(), wxPoint(x, y));
454 if ((pChartTest && (pChartTest->GetChartFamily() == CHART_FAMILY_VECTOR)) ||
455 ais_areanotice) {
456 MenuAppend1(contextMenu, ID_DEF_MENU_QUERY, _("Object Query") + "...");
457 } else {
458#ifndef __ANDROID__
459 if (!g_bBasicMenus && (nChartStack > 1)) {
460 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_IN,
461 _menuText(_("Scale In"), "Ctrl-Left"));
462 MenuAppend1(contextMenu, ID_DEF_MENU_SCALE_OUT,
463 _menuText(_("Scale Out"), "Ctrl-Right"));
464 }
465#endif
466 }
467 }
468
469 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
470 bool b_dm_add = true;
471 if (g_btouch && parent->IsMeasureActive()) b_dm_add = false;
472
473 if (b_dm_add) {
474 MenuAppend1(contextMenu, ID_DEF_MENU_DROP_WP,
475 _menuText(_("Drop Mark"), "Ctrl-M"));
476 MenuAppend1(contextMenu, ID_DEF_MENU_NEW_RT,
477 _menuText(_("New Route..."), "Ctrl-R"));
478 }
479
480 if (!bGPSValid)
481 MenuAppend1(contextMenu, ID_DEF_MENU_MOVE_BOAT_HERE, _("Move Boat Here"));
482 }
483
484 if (!g_bBasicMenus && !g_pRouteMan->GetpActiveRoute() &&
485 (!(seltype & SELTYPE_MARKPOINT) ||
486 (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer)))
487 MenuAppend1(contextMenu, ID_DEF_MENU_GOTO_HERE, _("Navigate To Here"));
488
489 if (!g_bBasicMenus)
490 MenuAppend1(contextMenu, ID_DEF_MENU_GOTOPOSITION,
491 _("Center view") + "...");
492
493 if (!g_bBasicMenus) {
494 if (parent->GetVP().b_quilt) {
495 if (parent->GetUpMode() == NORTH_UP_MODE) {
496 MenuAppend1(contextMenu, ID_DEF_MENU_COGUP, _("Course Up Mode"));
497 if (!std::isnan(gHdt))
498 MenuAppend1(contextMenu, ID_DEF_MENU_HEADUP, _("Heading Up Mode"));
499 } else {
500 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("North Up Mode"));
501 }
502 } else {
503 if (parent->m_singleChart &&
504 (fabs(parent->m_singleChart->GetChartSkew()) > .01) && !g_bskew_comp)
505 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("Chart Up Mode"));
506 else
507 MenuAppend1(contextMenu, ID_DEF_MENU_NORTHUP, _("North Up Mode"));
508 }
509 }
510
511 if (!g_bBasicMenus) {
512 bool full_toggle_added = false;
513#ifndef __ANDROID__
514 if (g_btouch) {
515 MenuAppend1(contextMenu, ID_DEF_MENU_TOGGLE_FULL,
516 _("Toggle Full Screen"));
517 full_toggle_added = true;
518 }
519
520 if (!full_toggle_added) {
521 // if(gFrame->IsFullScreen())
522 MenuAppend1(contextMenu, ID_DEF_MENU_TOGGLE_FULL,
523 _("Toggle Full Screen"));
524 }
525#endif
526
527 if (g_pRouteMan->IsAnyRouteActive() &&
528 g_pRouteMan->GetCurrentXTEToActivePoint() > 0.)
529 MenuAppend1(contextMenu, ID_DEF_ZERO_XTE, _("Zero XTE"));
530
531 Kml *kml = new Kml;
532 int pasteBuffer = kml->ParsePasteBuffer();
533 if (pasteBuffer != KML_PASTE_INVALID) {
534 switch (pasteBuffer) {
535 case KML_PASTE_WAYPOINT: {
536 MenuAppend1(contextMenu, ID_PASTE_WAYPOINT, _("Paste Waypoint"));
537 break;
538 }
539 case KML_PASTE_ROUTE: {
540 MenuAppend1(contextMenu, ID_PASTE_ROUTE, _("Paste Route"));
541 break;
542 }
543 case KML_PASTE_TRACK: {
544 MenuAppend1(contextMenu, ID_PASTE_TRACK, _("Paste Track"));
545 break;
546 }
547 case KML_PASTE_ROUTE_TRACK: {
548 MenuAppend1(contextMenu, ID_PASTE_ROUTE, _("Paste Route"));
549 MenuAppend1(contextMenu, ID_PASTE_TRACK, _("Paste Track"));
550 break;
551 }
552 }
553 }
554 delete kml;
555
556 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
557 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
558 MenuAppend1(contextMenu, ID_DEF_MENU_CM93OFFSET_DIALOG,
559 _("CM93 Offset Dialog..."));
560 }
561
562 } // if( !g_bBasicMenus){
563
564#ifndef __ANDROID__
565// TODO stack
566// if( ( parent->GetVP().b_quilt ) && ( pCurrentStack &&
567// pCurrentStack->b_valid ) ) {
568// int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
569// parent->GetVP(), wxPoint( popx, popy ) ); if( dbIndex != -1 )
570// MenuAppend1( contextMenu, ID_DEF_MENU_QUILTREMOVE, _( "Hide This
571// Chart" ) );
572// }
573#endif
574
575#ifdef __WXMSW__
576 // If we dismiss the context menu without action, we need to discard some
577 // mouse events.... Eat the next 2 button events, which happen as down-up on
578 // MSW XP
579 g_click_stop = 2;
580#endif
581
582 // ChartGroup SubMenu
583 wxMenuItem *subItemChart =
584 contextMenu->AppendSubMenu(subMenuChart, _("Chart Groups"));
585 if (g_btouch) contextMenu->AppendSeparator();
586
587 SetMenuItemFont1(subItemChart);
588
589 if (g_pGroupArray->GetCount()) {
590#ifdef __WXMSW__
591 MenuAppend1(subMenuChart, wxID_CANCEL, _("temporary"));
592#endif
593 wxMenuItem *subItem0 = subMenuChart->AppendRadioItem(
594 ID_DEF_MENU_GROUPBASE, _("All Active Charts"));
595
596 SetMenuItemFont1(subItem0);
597
598 for (unsigned int i = 0; i < g_pGroupArray->GetCount(); i++) {
599 subItem0 = subMenuChart->AppendRadioItem(
600 ID_DEF_MENU_GROUPBASE + i + 1, g_pGroupArray->Item(i)->m_group_name);
601 SetMenuItemFont1(subItem0);
602 }
603
604#ifdef __WXMSW__
605 subMenuChart->Remove(wxID_CANCEL);
606#endif
607 subMenuChart->Check(ID_DEF_MENU_GROUPBASE + parent->m_groupIndex, true);
608 }
609
610 // This is the default context menu
611 menuFocus = contextMenu;
612
613 wxString name;
614 std::unique_ptr<HostApi> host_api = GetHostApi();
615 auto *api_121 = dynamic_cast<HostApi121 *>(host_api.get());
616 if (api_121) {
617 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
618 if (g_pAIS) {
619 if (api_121 && parent->GetShowAIS() &&
620 (seltype & SELTYPE_AISTARGET &&
621 !(api_121->GetContextMenuMask() &
622 api_121->kContextMenuDisableAistarget))) {
623 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
624 if (!g_bBasicMenus && myptarget) {
625 name = myptarget->GetFullName();
626 if (name.IsEmpty()) name.Printf("%d", m_FoundAIS_MMSI);
627 name.Prepend(" ( ").Append(" )");
628 } else
629 name = wxEmptyString;
630 menuAIS = new wxMenu(_("AIS") + name);
631 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_QUERY, _("Target Query..."));
632 if (myptarget && myptarget->bCPA_Valid &&
633 (myptarget->n_alert_state != AIS_ALERT_SET)) {
634 if (myptarget->b_show_AIS_CPA)
635 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_CPA, _("Hide Target CPA"));
636 else
637 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_CPA, _("Show Target CPA"));
638 }
639 MenuAppend1(menuAIS, ID_DEF_MENU_AISTARGETLIST, _("Target List..."));
640 if (myptarget->Class != AIS_METEO /*g_bAISShowTracks*/) {
641 if (myptarget && !myptarget->b_PersistTrack) {
642 if (myptarget->b_show_track)
643 MenuAppend1(menuAIS, ID_DEF_MENU_AISSHOWTRACK,
644 _("Hide Target Track"));
645 else
646 MenuAppend1(menuAIS, ID_DEF_MENU_AISSHOWTRACK,
647 _("Show Target Track"));
648 }
649 }
650
651 MenuAppend1(menuAIS, ID_DEF_MENU_COPY_MMSI, _("Copy Target MMSI"));
652 menuAIS->AppendSeparator();
653
654 if (!parent->GetVP().b_quilt) {
655 if ((parent->m_singleChart &&
656 (parent->m_singleChart->GetChartFamily() ==
657 CHART_FAMILY_VECTOR))) {
658 MenuAppend1(menuAIS, ID_DEF_MENU_QUERY, _("Object Query..."));
659 }
660
661 } else {
662 ChartBase *pChartTest =
663 parent->m_pQuilt->GetChartAtPix(parent->GetVP(), wxPoint(x, y));
664 if ((pChartTest &&
665 (pChartTest->GetChartFamily() == CHART_FAMILY_VECTOR))) {
666 MenuAppend1(menuAIS, ID_DEF_MENU_QUERY, _("Object Query..."));
667 }
668 }
669
670 menuFocus = menuAIS;
671 } else {
672 bool enable_list = true;
673#ifdef __ANDROID__
674 double char_x = wxTheApp->GetTopWindow()->GetSize().x /
675 wxTheApp->GetTopWindow()->GetCharWidth();
676 double char_y = wxTheApp->GetTopWindow()->GetSize().y /
677 wxTheApp->GetTopWindow()->GetCharWidth();
678 double char_min = wxMin(char_x, char_y);
679 if (char_min < 100) enable_list = false;
680 // Another filter for phones, especially
681 double size_x = wxTheApp->GetTopWindow()->GetSize().x / g_androidDPmm;
682 double size_y = wxTheApp->GetTopWindow()->GetSize().y / g_androidDPmm;
683 if (wxMin(size_x, size_y) < 100) // it is a phone..
684 enable_list = false;
685#endif
686 if (enable_list)
687 MenuAppend1(contextMenu, ID_DEF_MENU_AISTARGETLIST,
688 _("AIS target list") + "...");
689
690 wxString nextCPAstatus = g_bCPAWarn ? _("Hide") : _("Show");
691 MenuAppend1(contextMenu, ID_DEF_MENU_AIS_CPAWARNING,
692 _menuText(nextCPAstatus + " " + _("CPA alarm "), "W"));
693 }
694 }
695 }
696 if (g_enable_root_menu_debug) {
697 wxMenuItem *subItemDebug =
698 contextMenu->AppendSubMenu(subMenuDebug, _("Debug"));
699 if (g_btouch) contextMenu->AppendSeparator();
700 SetMenuItemFont1(subItemDebug);
701 }
702
703 if (seltype & SELTYPE_ROUTESEGMENT &&
704 !(api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute)) {
705 if (!g_bBasicMenus && m_pSelectedRoute) {
706 name = m_pSelectedRoute->m_RouteNameString;
707 if (name.IsEmpty()) name = _("Unnamed Route");
708 name.Prepend(" ( ").Append(" )");
709 } else
710 name = wxEmptyString;
711 bool blay = false;
712 if (m_pSelectedRoute && m_pSelectedRoute->m_bIsInLayer) blay = true;
713
714 if (blay) {
715 menuRoute = new wxMenu(_("Layer Route") + name);
716 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES, _("Properties") + "...");
717 if (m_pSelectedRoute) {
718 if (m_pSelectedRoute->IsActive()) {
719 int indexActive = m_pSelectedRoute->GetIndexOf(
720 m_pSelectedRoute->m_pRouteActivePoint);
721 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
722 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
723 _("Activate Next Waypoint"));
724 }
725 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
726 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
727 } else {
728 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
729 }
730 }
731 } else {
732 menuRoute = new wxMenu(_("Route") + name);
733 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES, _("Properties") + "...");
734 if (m_pSelectedRoute) {
735 if (m_pSelectedRoute->IsActive()) {
736 int indexActive = m_pSelectedRoute->GetIndexOf(
737 m_pSelectedRoute->m_pRouteActivePoint);
738 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
739 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
740 _("Activate Next Waypoint"));
741 }
742 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
743 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
744 } else {
745 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
746 }
747 }
748 MenuAppend1(menuRoute, ID_RT_MENU_INSERT, _("Insert Waypoint"));
749 MenuAppend1(menuRoute, ID_RT_MENU_APPEND, _("Append Waypoint"));
750 if (!(seltype & SELTYPE_ROUTEPOINT) && m_pSelectedRoute) {
751 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
752 if (m_SelectedIdx > 1 &&
753 m_SelectedIdx < m_pSelectedRoute->GetnPoints() - 1)
754 MenuAppend1(menuRoute, ID_RT_MENU_SPLIT_LEG, _("Split around Leg"));
755 }
756 MenuAppend1(menuRoute, ID_RT_MENU_COPY, _("Copy as KML") + "...");
757 MenuAppend1(menuRoute, ID_RT_MENU_DELETE, _("Delete") + "...");
758 MenuAppend1(menuRoute, ID_RT_MENU_REVERSE, _("Reverse..."));
759 if (m_pSelectedRoute) {
760 if (m_pSelectedRoute->AreWaypointNamesVisible())
761 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
762 _("Hide Waypoint Names"));
763 else
764 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
765 _("Show Waypoint Names"));
766 }
767 MenuAppend1(menuRoute, ID_RT_MENU_RESEQUENCE,
768 _("Resequence Waypoints..."));
769
770 // #ifndef __ANDROID__
771 wxString port = parent->FindValidUploadPort();
772 parent->m_active_upload_port = port;
773 wxString item = _("Send to GPS");
774 if (!port.IsEmpty()) {
775 item.Append(" ( ");
776 item.Append(port);
777 item.Append(" )");
778 }
779 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOGPS, item);
780
781 if (!port.IsEmpty()) {
782 wxString item = _("Send to new GPS");
783 MenuAppend1(menuRoute, ID_RT_MENU_SENDTONEWGPS, item);
784 }
785 // #endif
786 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
787 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOPEER, itemstp);
788 }
789 // Eventually set this menu as the "focused context menu"
790 if (menuFocus != menuAIS) menuFocus = menuRoute;
791 }
792
793 if (seltype & SELTYPE_TRACKSEGMENT &&
794 !(api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack)) {
795 name = wxEmptyString;
796 if (!g_bBasicMenus && m_pSelectedTrack)
797 name = " ( " + m_pSelectedTrack->GetName(true) + " )";
798 else
799 name = wxEmptyString;
800 bool blay = false;
801 if (m_pSelectedTrack && m_pSelectedTrack->m_bIsInLayer) blay = true;
802
803 if (blay) {
804 menuTrack = new wxMenu(_("Layer Track") + name);
805 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES, _("Properties") + "...");
806 } else {
807 menuTrack = new wxMenu(_("Track") + name);
808 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES, _("Properties") + "...");
809 MenuAppend1(menuTrack, ID_TK_MENU_COPY, _("Copy as KML"));
810 MenuAppend1(menuTrack, ID_TK_MENU_DELETE, _("Delete") + "...");
811 }
812
813 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
814 MenuAppend1(menuTrack, ID_TK_MENU_SENDTOPEER, itemstp);
815
816 // Eventually set this menu as the "focused context menu"
817 if (menuFocus != menuAIS) menuFocus = menuTrack;
818 }
819
820 if (seltype & SELTYPE_ROUTEPOINT &&
821 !(api_121->GetContextMenuMask() &
822 api_121->kContextMenuDisableWaypoint)) {
823 if (!g_bBasicMenus && m_pFoundRoutePoint) {
824 name = m_pFoundRoutePoint->GetName();
825 if (name.IsEmpty()) name = _("Unnamed Waypoint");
826 name.Prepend(" ( ").Append(" )");
827 } else
828 name = wxEmptyString;
829 bool blay = false;
830 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
831
832 if (blay) {
833 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
834 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
835 _("Properties") + "...");
836
837 if (m_pSelectedRoute && m_pSelectedRoute->IsActive())
838 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
839 } else {
840 menuWaypoint = new wxMenu(_("Waypoint") + name);
841 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
842 _("Properties") + "...");
843 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
844 if (m_pSelectedRoute->m_pRouteActivePoint != m_pFoundRoutePoint)
845 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
846 }
847
848 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
849 if (m_pSelectedRoute->m_pRouteActivePoint == m_pFoundRoutePoint) {
850 int indexActive = m_pSelectedRoute->GetIndexOf(
851 m_pSelectedRoute->m_pRouteActivePoint);
852 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints())
853 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTNXTPOINT,
854 _("Activate Next Waypoint"));
855 }
856 }
857 if (m_pSelectedRoute && m_pSelectedRoute->GetnPoints() > 2) {
858 MenuAppend1(menuWaypoint, ID_RT_MENU_REMPOINT,
859 _("Remove from Route"));
860
861 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
862 if (m_SelectedIdx > 1 &&
863 m_SelectedIdx < m_pSelectedRoute->GetnPoints())
864 MenuAppend1(menuWaypoint, ID_RT_MENU_SPLIT_WPT,
865 _("Split Route at Waypoint"));
866 }
867
868 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
869
870 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != "mob")
871 MenuAppend1(menuWaypoint, ID_RT_MENU_DELPOINT, _("Delete"));
872
873 // #ifndef __ANDROID__
874 wxString port = parent->FindValidUploadPort();
875 parent->m_active_upload_port = port;
876 wxString item = _("Send to GPS");
877 if (!port.IsEmpty()) {
878 item.Append(" ( ");
879 item.Append(port);
880 item.Append(" )");
881 }
882 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
883
884 if (!port.IsEmpty()) {
885 wxString item = _("Send to new GPS");
886 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTONEWGPS, item);
887 }
888
889 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
890 SYMBOL_STP_TITLE); // Send to Peer
891 }
892
893 // Eventually set this menu as the "focused context menu"
894 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
895 }
896
897 if (seltype & SELTYPE_MARKPOINT &&
898 !(api_121->GetContextMenuMask() &
899 api_121->kContextMenuDisableWaypoint)) {
900 if (!g_bBasicMenus && m_pFoundRoutePoint) {
901 name = m_pFoundRoutePoint->GetName();
902 if (name.IsEmpty()) name = _("Unnamed Mark");
903 name.Prepend(" ( ").Append(" )");
904 } else
905 name = wxEmptyString;
906 bool blay = false;
907 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
908
909 if (blay) {
910 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
911 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
912 _("Properties") + "...");
913 } else {
914 menuWaypoint = new wxMenu(_("Mark") + name);
915 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES,
916 _("Properties") + "...");
917
918 if (!g_pRouteMan->GetpActiveRoute())
919 MenuAppend1(menuWaypoint, ID_WP_MENU_GOTO, _("Navigate To This"));
920
921 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
922
923 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != "mob")
924 MenuAppend1(menuWaypoint, ID_WP_MENU_DELPOINT, _("Delete"));
925
926 // #ifndef __ANDROID__
927 wxString port = parent->FindValidUploadPort();
928 parent->m_active_upload_port = port;
929 wxString item = _("Send to GPS");
930 if (!port.IsEmpty()) {
931 item.Append(" ( ");
932 item.Append(port);
933 item.Append(" )");
934 }
935 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
936
937 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
938 SYMBOL_STP_TITLE); // Send to Peer
939 // #endif
940
941 if ((m_pFoundRoutePoint == pAnchorWatchPoint1) ||
942 (m_pFoundRoutePoint == pAnchorWatchPoint2))
943 MenuAppend1(menuWaypoint, ID_WP_MENU_CLEAR_ANCHORWATCH,
944 _("Clear Anchor Watch"));
945 else {
946 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
947 ((NULL == pAnchorWatchPoint1) || (NULL == pAnchorWatchPoint2))) {
948 double dist;
949 double brg;
950 DistanceBearingMercator(m_pFoundRoutePoint->m_lat,
951 m_pFoundRoutePoint->m_lon, gLat, gLon, &brg,
952 &dist);
953 if (dist * 1852. <= g_nAWMax)
954 MenuAppend1(menuWaypoint, ID_WP_MENU_SET_ANCHORWATCH,
955 _("Set Anchor Watch"));
956 }
957 }
958 }
959 // Eventually set this menu as the "focused context menu"
960 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
961 }
962
963 // Add plugin context items to the correct menu
964 AddPluginContextMenuItems(contextMenu, menuRoute, menuTrack, menuWaypoint,
965 menuAIS);
966
967 /*add the relevant submenus*/
968 enum { WPMENU = 1, TKMENU = 2, RTMENU = 4, MMMENU = 8 };
969 int sub_menu = 0;
970 if (!g_bBasicMenus && menuFocus != contextMenu) {
971 if (global_color_scheme != GLOBAL_COLOR_SCHEME_DUSK &&
972 global_color_scheme != GLOBAL_COLOR_SCHEME_NIGHT) {
973 menuFocus->AppendSeparator();
974 }
975
976 wxMenuItem *subMenu1;
977 if (menuWaypoint && menuFocus != menuWaypoint) {
978 subMenu1 =
979 menuFocus->AppendSubMenu(menuWaypoint, menuWaypoint->GetTitle());
980 SetMenuItemFont1(subMenu1);
981 sub_menu |= WPMENU;
982#ifdef __WXMSW__
983 menuWaypoint->SetTitle(wxEmptyString);
984#endif
985 }
986 if (menuTrack && menuFocus != menuTrack) {
987 subMenu1 = menuFocus->AppendSubMenu(menuTrack, menuTrack->GetTitle());
988 SetMenuItemFont1(subMenu1);
989 sub_menu |= TKMENU;
990#ifdef __WXMSW__
991 menuTrack->SetTitle(wxEmptyString);
992#endif
993 }
994 if (menuRoute && menuFocus != menuRoute) {
995 subMenu1 = menuFocus->AppendSubMenu(menuRoute, menuRoute->GetTitle());
996 SetMenuItemFont1(subMenu1);
997 sub_menu |= RTMENU;
998#ifdef __WXMSW__
999 menuRoute->SetTitle(wxEmptyString);
1000#endif
1001 }
1002 subMenu1 = menuFocus->AppendSubMenu(contextMenu, _("Main Menu"));
1003 SetMenuItemFont1(subMenu1);
1004 sub_menu |= MMMENU;
1005 }
1006
1007 if (!subMenuChart->GetMenuItemCount()) contextMenu->Destroy(subItemChart);
1008
1009 // Add the Tide/Current selections if the item was not activated by
1010 // shortcut in right-click handlers
1011 bool bsep = false;
1012 if (seltype & SELTYPE_TIDEPOINT) {
1013 menuFocus->AppendSeparator();
1014 bsep = true;
1015 MenuAppend1(menuFocus, ID_DEF_MENU_TIDEINFO, _("Show Tide Information"));
1016 }
1017
1018 if (seltype & SELTYPE_CURRENTPOINT) {
1019 if (!bsep) menuFocus->AppendSeparator();
1020 MenuAppend1(menuFocus, ID_DEF_MENU_CURRENTINFO,
1021 _("Show Current Information"));
1022 }
1023
1024 // Invoke the correct focused drop-down menu
1025
1026#ifdef __ANDROID__
1027 androidEnableBackButton(false);
1028 androidEnableOptionsMenu(false);
1029
1030 setMenuStyleSheet(menuRoute, GetOCPNGUIScaledFont(_("Menu")));
1031 setMenuStyleSheet(menuWaypoint, GetOCPNGUIScaledFont(_("Menu")));
1032 setMenuStyleSheet(menuTrack, GetOCPNGUIScaledFont(_("Menu")));
1033 setMenuStyleSheet(menuAIS, GetOCPNGUIScaledFont(_("Menu")));
1034#endif
1035
1036 parent->PopupMenu(menuFocus, x, y);
1037
1038#ifdef __ANDROID__
1039 androidEnableBackButton(true);
1040 androidEnableOptionsMenu(true);
1041#endif
1042
1043 /* Cleanup if necessary.
1044 Do not delete menus witch are submenu as they will be deleted by their
1045 parent menu. This could create a crash*/
1046 delete menuAIS;
1047 if (!(sub_menu & MMMENU)) delete contextMenu;
1048 if (!(sub_menu & RTMENU)) delete menuRoute;
1049 if (!(sub_menu & TKMENU)) delete menuTrack;
1050 if (!(sub_menu & WPMENU)) delete menuWaypoint;
1051 } // api_121
1052}
1053
1054void CanvasMenuHandler::AddPluginContextMenuItems(wxMenu *contextMenu,
1055 wxMenu *menuRoute,
1056 wxMenu *menuTrack,
1057 wxMenu *menuWaypoint,
1058 wxMenu *menuAIS) {
1059 // Give the plugins a chance to update their menu items
1060 g_pi_manager->PrepareAllPluginContextMenus();
1061
1062 // Add PlugIn Context Menu items
1063 ArrayOfPlugInMenuItems item_array =
1064 g_pi_manager->GetPluginContextMenuItemArray();
1065
1066 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1067 PlugInMenuItemContainer *pimis = item_array[i];
1068 if (!pimis->b_viz) continue;
1069
1070 wxMenu *submenu = NULL;
1071 if (pimis->pmenu_item->GetSubMenu()) {
1072 // Create a clone of the submenu referenced in the PlugInMenuItemContainer
1073 auto submenu_proto = pimis->pmenu_item->GetSubMenu();
1074 submenu = new wxMenu();
1075 const wxMenuItemList &items =
1076 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1077 for (wxMenuItemList::const_iterator it = items.begin(); it != items.end();
1078 ++it) {
1079 int id = (*it)->GetId();
1080 wxMenuItem *psmi =
1081 new wxMenuItem(submenu, id, (*it)->GetItemLabelText(),
1082 (*it)->GetHelp(), (*it)->GetKind());
1083
1084#ifdef __WXMSW__
1085 psmi->SetFont(m_scaledFont);
1086#endif
1087
1088#ifdef __ANDROID__
1089 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1090 psmi->SetFont(sFont);
1091#endif
1092
1093 PrepareMenuItem(psmi);
1094 submenu->Append(psmi);
1095 psmi->Check((*it)->IsChecked());
1096 }
1097 }
1098
1099 wxMenuItem *pmi = new wxMenuItem(
1100 contextMenu, pimis->id, pimis->pmenu_item->GetItemLabelText(),
1101 pimis->pmenu_item->GetHelp(), pimis->pmenu_item->GetKind(), submenu);
1102#ifdef __WXMSW__
1103 pmi->SetFont(m_scaledFont);
1104#endif
1105
1106#ifdef __ANDROID__
1107 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1108 pmi->SetFont(sFont);
1109#endif
1110
1111 PrepareMenuItem(pmi);
1112
1113 wxMenu *dst = contextMenu;
1114 if (pimis->m_in_menu == "Waypoint")
1115 dst = menuWaypoint;
1116 else if (pimis->m_in_menu == "Route")
1117 dst = menuRoute;
1118 else if (pimis->m_in_menu == "Track")
1119 dst = menuTrack;
1120 else if (pimis->m_in_menu == "AIS")
1121 dst = menuAIS;
1122
1123 if (dst != NULL) {
1124 dst->Append(pmi);
1125 dst->Enable(pimis->id, !pimis->b_grey);
1126 }
1127 }
1128}
1129
1130void CanvasMenuHandler::PopupMenuHandler(wxCommandEvent &event) {
1131 RoutePoint *pLast;
1132
1133 wxPoint r;
1134 double zlat, zlon;
1135
1136 int splitMode = 0; // variables for split
1137 bool dupFirstWpt = true, showRPD;
1138
1139 parent->GetCanvasPixPoint(popx * parent->GetDisplayScale(),
1140 popy * parent->GetDisplayScale(), zlat, zlon);
1141
1142 switch (event.GetId()) {
1143 case ID_DEF_MENU_MAX_DETAIL:
1144 vLat = zlat;
1145 vLon = zlon;
1146 parent->ClearbFollow();
1147
1148 top_frame::Get()->DoChartUpdate();
1149
1150 parent->SelectChartFromStack(0, false, CHART_TYPE_DONTCARE,
1151 CHART_FAMILY_RASTER);
1152 break;
1153
1154 case ID_DEF_MENU_SCALE_IN:
1155 parent->DoCanvasStackDelta(-1);
1156 break;
1157
1158 case ID_DEF_MENU_SCALE_OUT:
1159 parent->DoCanvasStackDelta(1);
1160 break;
1161
1162 case ID_UNDO:
1163 parent->undo->UndoLastAction();
1164 parent->InvalidateGL();
1165 parent->Refresh(false);
1166 break;
1167
1168 case ID_REDO:
1169 parent->undo->RedoNextAction();
1170 parent->InvalidateGL();
1171 parent->Refresh(false);
1172 break;
1173
1174 case ID_DEF_MENU_MOVE_BOAT_HERE:
1175 gLat = zlat;
1176 gLon = zlon;
1177 top_frame::Get()->UpdateStatusBar();
1178 break;
1179
1180 case ID_DEF_MENU_GOTO_HERE: {
1181 RoutePoint *pWP_dest = new RoutePoint(zlat, zlon, g_default_wp_icon,
1182 wxEmptyString, wxEmptyString);
1183 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP_dest);
1184
1185 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1186 wxEmptyString, wxEmptyString);
1187 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1188
1189 Route *temp_route = new Route();
1190 pRouteList->push_back(temp_route);
1191
1192 temp_route->AddPoint(pWP_src);
1193 temp_route->AddPoint(pWP_dest);
1194
1195 pSelect->AddSelectableRouteSegment(gLat, gLon, zlat, zlon, pWP_src,
1196 pWP_dest, temp_route);
1197
1198 temp_route->m_RouteNameString = _("Temporary GOTO Route");
1199 temp_route->m_RouteStartString = _("Here");
1200 ;
1201 temp_route->m_RouteEndString = _("There");
1202
1203 temp_route->m_bDeleteOnArrival = true;
1204
1205 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1206
1207 g_pRouteMan->ActivateRoute(temp_route, pWP_dest);
1208
1209 break;
1210 }
1211
1212 case ID_DEF_MENU_DROP_WP: {
1213 RoutePoint *pWP = new RoutePoint(zlat, zlon, g_default_wp_icon,
1214 wxEmptyString, wxEmptyString);
1215 pWP->m_bIsolatedMark = true; // This is an isolated mark
1216 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP);
1217 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1218
1219 if (!RoutePointGui(*pWP).IsVisibleSelectable(this->parent))
1220 RoutePointGui(*pWP).ShowScaleWarningMessage(parent);
1221
1222 if (RouteManagerDialog::getInstanceFlag()) {
1223 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1224 pRouteManagerDialog->UpdateWptListCtrl();
1225 }
1226 }
1227
1228 parent->undo->BeforeUndoableAction(Undo_CreateWaypoint, pWP,
1229 Undo_HasParent, NULL);
1230 parent->undo->AfterUndoableAction(NULL);
1231 top_frame::Get()->RefreshAllCanvas(false);
1232 top_frame::Get()->InvalidateAllGL();
1233 g_FlushNavobjChanges = true;
1234 break;
1235 }
1236
1237 case ID_DEF_MENU_NEW_RT: {
1238 parent->StartRoute();
1239 break;
1240 }
1241
1242 case ID_DEF_MENU_AISTARGETLIST:
1243 parent->ShowAISTargetList();
1244 break;
1245
1246 case ID_DEF_MENU_AIS_CPAWARNING:
1247 parent->ToggleCPAWarn();
1248 break;
1249
1250 case ID_WP_MENU_GOTO: {
1251 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1252 wxEmptyString, wxEmptyString);
1253 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1254
1255 Route *temp_route = new Route();
1256 pRouteList->push_back(temp_route);
1257
1258 temp_route->AddPoint(pWP_src);
1259 temp_route->AddPoint(m_pFoundRoutePoint);
1260 m_pFoundRoutePoint->SetShared(true);
1261
1262 pSelect->AddSelectableRouteSegment(gLat, gLon, m_pFoundRoutePoint->m_lat,
1263 m_pFoundRoutePoint->m_lon, pWP_src,
1264 m_pFoundRoutePoint, temp_route);
1265
1266 wxString name = m_pFoundRoutePoint->GetName();
1267 if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
1268 wxString rteName = _("Go to ");
1269 rteName.Append(name);
1270 temp_route->m_RouteNameString = rteName;
1271 temp_route->m_RouteStartString = _("Here");
1272 ;
1273 temp_route->m_RouteEndString = name;
1274 temp_route->m_bDeleteOnArrival = true;
1275
1276 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1277
1278 g_pRouteMan->ActivateRoute(temp_route, m_pFoundRoutePoint);
1279
1280 break;
1281 }
1282
1283 case ID_DEF_MENU_COGUP:
1284 parent->SetUpMode(COURSE_UP_MODE);
1285 break;
1286
1287 case ID_DEF_MENU_HEADUP:
1288 parent->SetUpMode(HEAD_UP_MODE);
1289 break;
1290
1291 case ID_DEF_MENU_NORTHUP:
1292 parent->SetUpMode(NORTH_UP_MODE);
1293 break;
1294
1295 case ID_DEF_MENU_TOGGLE_FULL:
1296 top_frame::Get()->ToggleFullScreen();
1297 break;
1298
1299 case ID_DEF_MENU_GOTOPOSITION:
1300 if (NULL == pGoToPositionDialog) // There is one global instance of the
1301 // Go To Position Dialog
1303 pGoToPositionDialog->SetCanvas(parent);
1304 pGoToPositionDialog->CheckPasteBufferForPosition();
1305 pGoToPositionDialog->Show();
1306 break;
1307
1308 case ID_WP_MENU_DELPOINT: {
1309 if (m_pFoundRoutePoint == pAnchorWatchPoint1) {
1310 pAnchorWatchPoint1 = NULL;
1311 g_AW1GUID.Clear();
1312 } else if (m_pFoundRoutePoint == pAnchorWatchPoint2) {
1313 pAnchorWatchPoint2 = NULL;
1314 g_AW2GUID.Clear();
1315 }
1316
1317 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
1318 (m_pFoundRoutePoint->GetIconName() != "mob")) {
1319 // If the WP belongs to an invisible route, we come here instead of to
1320 // ID_RT_MENU_DELPOINT
1321 // Check it, and if so then remove the point from its routes
1322 wxArrayPtrVoid *proute_array =
1323 g_pRouteMan->GetRouteArrayContaining(m_pFoundRoutePoint);
1324 if (proute_array) {
1325 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1326 delete proute_array;
1327 } else {
1328 parent->undo->BeforeUndoableAction(
1329 Undo_DeleteWaypoint, m_pFoundRoutePoint, Undo_IsOrphanded,
1330 NULL /*m_pFoundPoint*/);
1331 NavObj_dB::GetInstance().DeleteRoutePoint(m_pFoundRoutePoint);
1332 pSelect->DeleteSelectablePoint(m_pFoundRoutePoint,
1333 SELTYPE_ROUTEPOINT);
1334 if (NULL != pWayPointMan)
1335 pWayPointMan->RemoveRoutePoint(m_pFoundRoutePoint);
1336 parent->undo->AfterUndoableAction(NULL);
1337 }
1338
1339 if (g_pMarkInfoDialog) {
1340 g_pMarkInfoDialog->ClearData();
1341 }
1342
1343 if (RouteManagerDialog::getInstanceFlag()) {
1344 if (pRouteManagerDialog) {
1345 if (pRouteManagerDialog->IsShown())
1346 pRouteManagerDialog->UpdateWptListCtrl();
1347 }
1348 }
1349 top_frame::Get()->RefreshAllCanvas(false);
1350 top_frame::Get()->InvalidateAllGL();
1351 }
1352 break;
1353 }
1354 case ID_WP_MENU_PROPERTIES:
1355 parent->ShowMarkPropertiesDialog(m_pFoundRoutePoint);
1356 break;
1357
1358 case ID_WP_MENU_CLEAR_ANCHORWATCH: {
1359 wxString guid = wxEmptyString;
1360 if (pAnchorWatchPoint1 == m_pFoundRoutePoint) {
1361 pAnchorWatchPoint1 = NULL;
1362 guid = g_AW1GUID;
1363 g_AW1GUID.Clear();
1364 } else if (pAnchorWatchPoint2 == m_pFoundRoutePoint) {
1365 pAnchorWatchPoint2 = NULL;
1366 guid = g_AW2GUID;
1367 g_AW2GUID.Clear();
1368 }
1369 if (!guid.IsEmpty()) {
1370 wxJSONValue v;
1371 v["GUID"] = guid;
1372 wxString msg_id("OCPN_ANCHOR_WATCH_CLEARED");
1373 SendJSONMessageToAllPlugins(msg_id, v);
1374 }
1375 break;
1376 }
1377
1378 case ID_WP_MENU_SET_ANCHORWATCH: {
1379 wxString guid = wxEmptyString;
1380 if (pAnchorWatchPoint1 == NULL) {
1381 pAnchorWatchPoint1 = m_pFoundRoutePoint;
1382 g_AW1GUID = pAnchorWatchPoint1->m_GUID;
1383 guid = g_AW1GUID;
1384 wxString nn;
1385 nn = m_pFoundRoutePoint->GetName();
1386 if (nn.IsNull()) {
1387 nn.Printf("%d m", g_nAWDefault);
1388 m_pFoundRoutePoint->SetName(nn);
1389 }
1390 } else if (pAnchorWatchPoint2 == NULL) {
1391 pAnchorWatchPoint2 = m_pFoundRoutePoint;
1392 g_AW2GUID = pAnchorWatchPoint2->m_GUID;
1393 guid = g_AW2GUID;
1394 wxString nn;
1395 nn = m_pFoundRoutePoint->GetName();
1396 if (nn.IsNull()) {
1397 nn.Printf("%d m", g_nAWDefault);
1398 m_pFoundRoutePoint->SetName(nn);
1399 }
1400 }
1401 if (!guid.IsEmpty()) {
1402 wxJSONValue v;
1403 v["GUID"] = guid;
1404 wxString msg_id("OCPN_ANCHOR_WATCH_SET");
1405 SendJSONMessageToAllPlugins(msg_id, 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, _("_A"));
1683 m_pTail->CloneRoute(m_pSelectedRoute, m_SelectedIdx + 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_121.cpp:838
Canvas context (right click) menu handler.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:60
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:173
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4547
double GetDisplayScale()
Get the ratio of physical to logical pixel for the display.
Definition chcanv.h:884
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
Definition chcanv.cpp:5359
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:183
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4572
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
Definition chcanv.cpp:13746
Definition kml.h:50
void Validate()
Check that all entries are accessible, remove stale ones.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
Definition route.h:99
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:203
wxString m_RouteStartString
Name or description of the route's starting point.
Definition route.h:252
bool m_bDeleteOnArrival
Flag indicating whether the route should be deleted once navigation reaches the end.
Definition route.h:268
wxString m_RouteEndString
Name or description of the route's ending point.
Definition route.h:257
RoutePoint * m_pRouteActivePoint
Pointer to the currently active waypoint within this route.
Definition route.h:214
wxString m_RouteNameString
User-assigned name for the route.
Definition route.h:247
wxString m_GUID
Globally unique identifier for this route.
Definition route.h:273
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
Definition route.h:278
int m_lastMousePointIndex
Index of the most recently interacted with route point.
Definition route.h:298
bool ActivateRoutePoint(Route *pA, RoutePoint *pRP)
Activates a specific waypoint within a route for navigation.
Definition routeman.cpp:286
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
Definition routeman.cpp:150
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
Definition routeman.cpp:357
bool DeleteRoute(Route *pRoute)
Definition routeman.cpp:762
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
Definition routeman.cpp:222
Dialog for sending routes/waypoints to a GPS device.
Dialog for sending navigation objects to peer devices.
Represents a track, which is a series of connected track points.
Definition track.h:117
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Represents a composite CM93 chart covering multiple scales.
Definition cm93.h:416
virtual void OnContextMenuItemCallback(int id)
Handles context menu item selection.
The JSON value class implementation.
Definition jsonval.h:84
CM93OffsetDialog * g_pCM93OffsetDialog
Global instance.
Definition cm93.cpp:73
Class cm93chart and helpers – CM93 chart state.
Global variables stored in configuration file.
OpenCPN Georef utility.
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:99
Recorded track abstraction.
Track and Trackpoint drawing stuff.
TrackPropDlg * pTrackPropDialog
Global instance.
Track Properties Dialog.
Framework for Undo features.