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