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 if (!g_bBasicMenus || (seltype != SELTYPE_ROUTECREATE)) {
604 if (g_pAIS) {
605 if (parent->GetShowAIS() &&
606 (seltype & SELTYPE_AISTARGET &&
607 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_AISTARGET))) {
608 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
609 if (!g_bBasicMenus && myptarget) {
610 name = myptarget->GetFullName();
611 if (name.IsEmpty()) name.Printf("%d", m_FoundAIS_MMSI);
612 name.Prepend(" ( ").Append(" )");
613 } else
614 name = wxEmptyString;
615 menuAIS = new wxMenu(_("AIS") + name);
616 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_QUERY, _("Target Query..."));
617 if (myptarget && myptarget->bCPA_Valid &&
618 (myptarget->n_alert_state != AIS_ALERT_SET)) {
619 if (myptarget->b_show_AIS_CPA)
620 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_CPA, _("Hide Target CPA"));
621 else
622 MenuAppend1(menuAIS, ID_DEF_MENU_AIS_CPA, _("Show Target CPA"));
623 }
624 MenuAppend1(menuAIS, ID_DEF_MENU_AISTARGETLIST, _("Target List..."));
625 if (myptarget->Class != AIS_METEO /*g_bAISShowTracks*/) {
626 if (myptarget && !myptarget->b_PersistTrack) {
627 if (myptarget->b_show_track)
628 MenuAppend1(menuAIS, ID_DEF_MENU_AISSHOWTRACK,
629 _("Hide Target Track"));
630 else
631 MenuAppend1(menuAIS, ID_DEF_MENU_AISSHOWTRACK,
632 _("Show Target Track"));
633 }
634 }
635
636 MenuAppend1(menuAIS, ID_DEF_MENU_COPY_MMSI, _("Copy Target MMSI"));
637 menuAIS->AppendSeparator();
638
639 if (!parent->GetVP().b_quilt) {
640 if ((parent->m_singleChart &&
641 (parent->m_singleChart->GetChartFamily() ==
642 CHART_FAMILY_VECTOR))) {
643 MenuAppend1(menuAIS, ID_DEF_MENU_QUERY, _("Object Query..."));
644 }
645
646 } else {
647 ChartBase *pChartTest =
648 parent->m_pQuilt->GetChartAtPix(parent->GetVP(), wxPoint(x, y));
649 if ((pChartTest &&
650 (pChartTest->GetChartFamily() == CHART_FAMILY_VECTOR))) {
651 MenuAppend1(menuAIS, ID_DEF_MENU_QUERY, _("Object Query..."));
652 }
653 }
654
655 menuFocus = menuAIS;
656 } else {
657 bool enable_list = true;
658#ifdef __ANDROID__
659 double char_x = gFrame->GetSize().x / gFrame->GetCharWidth();
660 double char_y = gFrame->GetSize().y / gFrame->GetCharWidth();
661 double char_min = wxMin(char_x, char_y);
662 if (char_min < 100) enable_list = false;
663 // Another filter for phones, especially
664 double size_x = gFrame->GetSize().x / g_androidDPmm;
665 double size_y = gFrame->GetSize().y / g_androidDPmm;
666 if (wxMin(size_x, size_y) < 100) // it is a phone..
667 enable_list = false;
668#endif
669 if (enable_list)
670 MenuAppend1(contextMenu, ID_DEF_MENU_AISTARGETLIST,
671 _("AIS target list") + "...");
672
673 wxString nextCPAstatus = g_bCPAWarn ? _("Hide") : _("Show");
674 MenuAppend1(contextMenu, ID_DEF_MENU_AIS_CPAWARNING,
675 _menuText(nextCPAstatus + " " + _("CPA alarm "), "W"));
676 }
677 }
678 }
679 if (g_enable_root_menu_debug) {
680 wxMenuItem *subItemDebug =
681 contextMenu->AppendSubMenu(subMenuDebug, _("Debug"));
682 if (g_btouch) contextMenu->AppendSeparator();
683 SetMenuItemFont1(subItemDebug);
684 }
685
686 if (seltype & SELTYPE_ROUTESEGMENT &&
687 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_ROUTE)) {
688 if (!g_bBasicMenus && m_pSelectedRoute) {
689 name = m_pSelectedRoute->m_RouteNameString;
690 if (name.IsEmpty()) name = _("Unnamed Route");
691 name.Prepend(" ( ").Append(" )");
692 } else
693 name = wxEmptyString;
694 bool blay = false;
695 if (m_pSelectedRoute && m_pSelectedRoute->m_bIsInLayer) blay = true;
696
697 if (blay) {
698 menuRoute = new wxMenu(_("Layer Route") + name);
699 MenuAppend1(menuRoute, ID_RT_MENU_PROPERTIES, _("Properties") + "...");
700 if (m_pSelectedRoute) {
701 if (m_pSelectedRoute->IsActive()) {
702 int indexActive = m_pSelectedRoute->GetIndexOf(
703 m_pSelectedRoute->m_pRouteActivePoint);
704 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints()) {
705 MenuAppend1(menuRoute, ID_RT_MENU_ACTNXTPOINT,
706 _("Activate Next Waypoint"));
707 }
708 MenuAppend1(menuRoute, ID_RT_MENU_DEACTIVATE, _("Deactivate"));
709 MenuAppend1(menuRoute, ID_DEF_ZERO_XTE, _("Zero XTE"));
710 } else {
711 MenuAppend1(menuRoute, ID_RT_MENU_ACTIVATE, _("Activate"));
712 }
713 }
714 } else {
715 menuRoute = new wxMenu(_("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 MenuAppend1(menuRoute, ID_RT_MENU_INSERT, _("Insert Waypoint"));
732 MenuAppend1(menuRoute, ID_RT_MENU_APPEND, _("Append Waypoint"));
733 if (!(seltype & SELTYPE_ROUTEPOINT) && m_pSelectedRoute) {
734 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
735 if (m_SelectedIdx > 1 &&
736 m_SelectedIdx < m_pSelectedRoute->GetnPoints() - 1)
737 MenuAppend1(menuRoute, ID_RT_MENU_SPLIT_LEG, _("Split around Leg"));
738 }
739 MenuAppend1(menuRoute, ID_RT_MENU_COPY, _("Copy as KML") + "...");
740 MenuAppend1(menuRoute, ID_RT_MENU_DELETE, _("Delete") + "...");
741 MenuAppend1(menuRoute, ID_RT_MENU_REVERSE, _("Reverse..."));
742 if (m_pSelectedRoute) {
743 if (m_pSelectedRoute->AreWaypointNamesVisible())
744 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
745 _("Hide Waypoint Names"));
746 else
747 MenuAppend1(menuRoute, ID_RT_MENU_SHOWNAMES,
748 _("Show Waypoint Names"));
749 }
750 MenuAppend1(menuRoute, ID_RT_MENU_RESEQUENCE,
751 _("Resequence Waypoints..."));
752
753 // #ifndef __ANDROID__
754 wxString port = parent->FindValidUploadPort();
755 parent->m_active_upload_port = port;
756 wxString item = _("Send to GPS");
757 if (!port.IsEmpty()) {
758 item.Append(" ( ");
759 item.Append(port);
760 item.Append(" )");
761 }
762 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOGPS, item);
763
764 if (!port.IsEmpty()) {
765 wxString item = _("Send to new GPS");
766 MenuAppend1(menuRoute, ID_RT_MENU_SENDTONEWGPS, item);
767 }
768 // #endif
769 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
770 MenuAppend1(menuRoute, ID_RT_MENU_SENDTOPEER, itemstp);
771 }
772 // Eventually set this menu as the "focused context menu"
773 if (menuFocus != menuAIS) menuFocus = menuRoute;
774 }
775
776 if (seltype & SELTYPE_TRACKSEGMENT &&
777 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_TRACK)) {
778 name = wxEmptyString;
779 if (!g_bBasicMenus && m_pSelectedTrack)
780 name = " ( " + m_pSelectedTrack->GetName(true) + " )";
781 else
782 name = wxEmptyString;
783 bool blay = false;
784 if (m_pSelectedTrack && m_pSelectedTrack->m_bIsInLayer) blay = true;
785
786 if (blay) {
787 menuTrack = new wxMenu(_("Layer Track") + name);
788 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES, _("Properties") + "...");
789 } else {
790 menuTrack = new wxMenu(_("Track") + name);
791 MenuAppend1(menuTrack, ID_TK_MENU_PROPERTIES, _("Properties") + "...");
792 MenuAppend1(menuTrack, ID_TK_MENU_COPY, _("Copy as KML"));
793 MenuAppend1(menuTrack, ID_TK_MENU_DELETE, _("Delete") + "...");
794 }
795
796 wxString itemstp = SYMBOL_STP_TITLE; // Send to Peer
797 MenuAppend1(menuTrack, ID_TK_MENU_SENDTOPEER, itemstp);
798
799 // Eventually set this menu as the "focused context menu"
800 if (menuFocus != menuAIS) menuFocus = menuTrack;
801 }
802
803 if (seltype & SELTYPE_ROUTEPOINT &&
804 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_WAYPOINT)) {
805 if (!g_bBasicMenus && m_pFoundRoutePoint) {
806 name = m_pFoundRoutePoint->GetName();
807 if (name.IsEmpty()) name = _("Unnamed Waypoint");
808 name.Prepend(" ( ").Append(" )");
809 } else
810 name = wxEmptyString;
811 bool blay = false;
812 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
813
814 if (blay) {
815 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
816 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
817
818 if (m_pSelectedRoute && m_pSelectedRoute->IsActive())
819 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
820 } else {
821 menuWaypoint = new wxMenu(_("Waypoint") + name);
822 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
823 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
824 if (m_pSelectedRoute->m_pRouteActivePoint != m_pFoundRoutePoint)
825 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTPOINT, _("Activate"));
826 }
827
828 if (m_pSelectedRoute && m_pSelectedRoute->IsActive()) {
829 if (m_pSelectedRoute->m_pRouteActivePoint == m_pFoundRoutePoint) {
830 int indexActive = m_pSelectedRoute->GetIndexOf(
831 m_pSelectedRoute->m_pRouteActivePoint);
832 if ((indexActive + 1) <= m_pSelectedRoute->GetnPoints())
833 MenuAppend1(menuWaypoint, ID_RT_MENU_ACTNXTPOINT,
834 _("Activate Next Waypoint"));
835 }
836 }
837 if (m_pSelectedRoute && m_pSelectedRoute->GetnPoints() > 2) {
838 MenuAppend1(menuWaypoint, ID_RT_MENU_REMPOINT, _("Remove from Route"));
839
840 m_SelectedIdx = m_pSelectedRoute->GetIndexOf(m_pFoundRoutePoint);
841 if (m_SelectedIdx > 1 && m_SelectedIdx < m_pSelectedRoute->GetnPoints())
842 MenuAppend1(menuWaypoint, ID_RT_MENU_SPLIT_WPT,
843 _("Split Route at Waypoint"));
844 }
845
846 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
847
848 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != "mob")
849 MenuAppend1(menuWaypoint, ID_RT_MENU_DELPOINT, _("Delete"));
850
851 // #ifndef __ANDROID__
852 wxString port = parent->FindValidUploadPort();
853 parent->m_active_upload_port = port;
854 wxString item = _("Send to GPS");
855 if (!port.IsEmpty()) {
856 item.Append(" ( ");
857 item.Append(port);
858 item.Append(" )");
859 }
860 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
861
862 if (!port.IsEmpty()) {
863 wxString item = _("Send to new GPS");
864 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTONEWGPS, item);
865 }
866
867 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
868 SYMBOL_STP_TITLE); // Send to Peer
869 }
870
871 // Eventually set this menu as the "focused context menu"
872 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
873 }
874
875 if (seltype & SELTYPE_MARKPOINT &&
876 !(GetContextMenuMask() & CONTEXT_MENU_DISABLE_WAYPOINT)) {
877 if (!g_bBasicMenus && m_pFoundRoutePoint) {
878 name = m_pFoundRoutePoint->GetName();
879 if (name.IsEmpty()) name = _("Unnamed Mark");
880 name.Prepend(" ( ").Append(" )");
881 } else
882 name = wxEmptyString;
883 bool blay = false;
884 if (m_pFoundRoutePoint && m_pFoundRoutePoint->m_bIsInLayer) blay = true;
885
886 if (blay) {
887 menuWaypoint = new wxMenu(_("Layer Waypoint") + name);
888 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
889 } else {
890 menuWaypoint = new wxMenu(_("Mark") + name);
891 MenuAppend1(menuWaypoint, ID_WP_MENU_PROPERTIES, _("Properties") + "...");
892
893 if (!g_pRouteMan->GetpActiveRoute())
894 MenuAppend1(menuWaypoint, ID_WP_MENU_GOTO, _("Navigate To This"));
895
896 MenuAppend1(menuWaypoint, ID_WPT_MENU_COPY, _("Copy as KML"));
897
898 if (m_pFoundRoutePoint && m_pFoundRoutePoint->GetIconName() != "mob")
899 MenuAppend1(menuWaypoint, ID_WP_MENU_DELPOINT, _("Delete"));
900
901 // #ifndef __ANDROID__
902 wxString port = parent->FindValidUploadPort();
903 parent->m_active_upload_port = port;
904 wxString item = _("Send to GPS");
905 if (!port.IsEmpty()) {
906 item.Append(" ( ");
907 item.Append(port);
908 item.Append(" )");
909 }
910 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOGPS, item);
911
912 MenuAppend1(menuWaypoint, ID_WPT_MENU_SENDTOPEER,
913 SYMBOL_STP_TITLE); // Send to Peer
914 // #endif
915
916 if ((m_pFoundRoutePoint == pAnchorWatchPoint1) ||
917 (m_pFoundRoutePoint == pAnchorWatchPoint2))
918 MenuAppend1(menuWaypoint, ID_WP_MENU_CLEAR_ANCHORWATCH,
919 _("Clear Anchor Watch"));
920 else {
921 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
922 ((NULL == pAnchorWatchPoint1) || (NULL == pAnchorWatchPoint2))) {
923 double dist;
924 double brg;
925 DistanceBearingMercator(m_pFoundRoutePoint->m_lat,
926 m_pFoundRoutePoint->m_lon, gLat, gLon, &brg,
927 &dist);
928 if (dist * 1852. <= g_nAWMax)
929 MenuAppend1(menuWaypoint, ID_WP_MENU_SET_ANCHORWATCH,
930 _("Set Anchor Watch"));
931 }
932 }
933 }
934 // Eventually set this menu as the "focused context menu"
935 if (menuFocus != menuAIS) menuFocus = menuWaypoint;
936 }
937
938 // Add plugin context items to the correct menu
939 AddPluginContextMenuItems(contextMenu, menuRoute, menuTrack, menuWaypoint,
940 menuAIS);
941
942 /*add the relevant submenus*/
943 enum { WPMENU = 1, TKMENU = 2, RTMENU = 4, MMMENU = 8 };
944 int sub_menu = 0;
945 if (!g_bBasicMenus && menuFocus != contextMenu) {
946 if (global_color_scheme != GLOBAL_COLOR_SCHEME_DUSK &&
947 global_color_scheme != GLOBAL_COLOR_SCHEME_NIGHT) {
948 menuFocus->AppendSeparator();
949 }
950
951 wxMenuItem *subMenu1;
952 if (menuWaypoint && menuFocus != menuWaypoint) {
953 subMenu1 =
954 menuFocus->AppendSubMenu(menuWaypoint, menuWaypoint->GetTitle());
955 SetMenuItemFont1(subMenu1);
956 sub_menu |= WPMENU;
957#ifdef __WXMSW__
958 menuWaypoint->SetTitle(wxEmptyString);
959#endif
960 }
961 if (menuTrack && menuFocus != menuTrack) {
962 subMenu1 = menuFocus->AppendSubMenu(menuTrack, menuTrack->GetTitle());
963 SetMenuItemFont1(subMenu1);
964 sub_menu |= TKMENU;
965#ifdef __WXMSW__
966 menuTrack->SetTitle(wxEmptyString);
967#endif
968 }
969 if (menuRoute && menuFocus != menuRoute) {
970 subMenu1 = menuFocus->AppendSubMenu(menuRoute, menuRoute->GetTitle());
971 SetMenuItemFont1(subMenu1);
972 sub_menu |= RTMENU;
973#ifdef __WXMSW__
974 menuRoute->SetTitle(wxEmptyString);
975#endif
976 }
977 subMenu1 = menuFocus->AppendSubMenu(contextMenu, _("Main Menu"));
978 SetMenuItemFont1(subMenu1);
979 sub_menu |= MMMENU;
980 }
981
982 if (!subMenuChart->GetMenuItemCount()) contextMenu->Destroy(subItemChart);
983
984 // Add the Tide/Current selections if the item was not activated by shortcut
985 // in right-click handlers
986 bool bsep = false;
987 if (seltype & SELTYPE_TIDEPOINT) {
988 menuFocus->AppendSeparator();
989 bsep = true;
990 MenuAppend1(menuFocus, ID_DEF_MENU_TIDEINFO, _("Show Tide Information"));
991 }
992
993 if (seltype & SELTYPE_CURRENTPOINT) {
994 if (!bsep) menuFocus->AppendSeparator();
995 MenuAppend1(menuFocus, ID_DEF_MENU_CURRENTINFO,
996 _("Show Current Information"));
997 }
998
999 // Invoke the correct focused drop-down menu
1000
1001#ifdef __ANDROID__
1002 androidEnableBackButton(false);
1003 androidEnableOptionsMenu(false);
1004
1005 setMenuStyleSheet(menuRoute, GetOCPNGUIScaledFont(_("Menu")));
1006 setMenuStyleSheet(menuWaypoint, GetOCPNGUIScaledFont(_("Menu")));
1007 setMenuStyleSheet(menuTrack, GetOCPNGUIScaledFont(_("Menu")));
1008 setMenuStyleSheet(menuAIS, GetOCPNGUIScaledFont(_("Menu")));
1009#endif
1010
1011 parent->PopupMenu(menuFocus, x, y);
1012
1013#ifdef __ANDROID__
1014 androidEnableBackButton(true);
1015 androidEnableOptionsMenu(true);
1016#endif
1017
1018 /* Cleanup if necessary.
1019 Do not delete menus witch are submenu as they will be deleted by their parent
1020 menu. This could create a crash*/
1021 delete menuAIS;
1022 if (!(sub_menu & MMMENU)) delete contextMenu;
1023 if (!(sub_menu & RTMENU)) delete menuRoute;
1024 if (!(sub_menu & TKMENU)) delete menuTrack;
1025 if (!(sub_menu & WPMENU)) delete menuWaypoint;
1026}
1027
1028void CanvasMenuHandler::AddPluginContextMenuItems(wxMenu *contextMenu,
1029 wxMenu *menuRoute,
1030 wxMenu *menuTrack,
1031 wxMenu *menuWaypoint,
1032 wxMenu *menuAIS) {
1033 // Give the plugins a chance to update their menu items
1034 g_pi_manager->PrepareAllPluginContextMenus();
1035
1036 // Add PlugIn Context Menu items
1037 ArrayOfPlugInMenuItems item_array =
1038 g_pi_manager->GetPluginContextMenuItemArray();
1039
1040 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1041 PlugInMenuItemContainer *pimis = item_array[i];
1042 if (!pimis->b_viz) continue;
1043
1044 wxMenu *submenu = NULL;
1045 if (pimis->pmenu_item->GetSubMenu()) {
1046 // Create a clone of the submenu referenced in the PlugInMenuItemContainer
1047 auto submenu_proto = pimis->pmenu_item->GetSubMenu();
1048 submenu = new wxMenu();
1049 const wxMenuItemList &items =
1050 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1051 for (wxMenuItemList::const_iterator it = items.begin(); it != items.end();
1052 ++it) {
1053 int id = (*it)->GetId();
1054 wxMenuItem *psmi =
1055 new wxMenuItem(submenu, id, (*it)->GetItemLabelText(),
1056 (*it)->GetHelp(), (*it)->GetKind());
1057
1058#ifdef __WXMSW__
1059 psmi->SetFont(m_scaledFont);
1060#endif
1061
1062#ifdef __ANDROID__
1063 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1064 psmi->SetFont(sFont);
1065#endif
1066
1067 PrepareMenuItem(psmi);
1068 submenu->Append(psmi);
1069 psmi->Check((*it)->IsChecked());
1070 }
1071 }
1072
1073 wxMenuItem *pmi = new wxMenuItem(
1074 contextMenu, pimis->id, pimis->pmenu_item->GetItemLabelText(),
1075 pimis->pmenu_item->GetHelp(), pimis->pmenu_item->GetKind(), submenu);
1076#ifdef __WXMSW__
1077 pmi->SetFont(m_scaledFont);
1078#endif
1079
1080#ifdef __ANDROID__
1081 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1082 pmi->SetFont(sFont);
1083#endif
1084
1085 PrepareMenuItem(pmi);
1086
1087 wxMenu *dst = contextMenu;
1088 if (pimis->m_in_menu == "Waypoint")
1089 dst = menuWaypoint;
1090 else if (pimis->m_in_menu == "Route")
1091 dst = menuRoute;
1092 else if (pimis->m_in_menu == "Track")
1093 dst = menuTrack;
1094 else if (pimis->m_in_menu == "AIS")
1095 dst = menuAIS;
1096
1097 if (dst != NULL) {
1098 dst->Append(pmi);
1099 dst->Enable(pimis->id, !pimis->b_grey);
1100 }
1101 }
1102}
1103
1104void CanvasMenuHandler::PopupMenuHandler(wxCommandEvent &event) {
1105 RoutePoint *pLast;
1106
1107 wxPoint r;
1108 double zlat, zlon;
1109
1110 int splitMode = 0; // variables for split
1111 bool dupFirstWpt = true, showRPD;
1112
1113 parent->GetCanvasPixPoint(popx * parent->GetDisplayScale(),
1114 popy * parent->GetDisplayScale(), zlat, zlon);
1115
1116 switch (event.GetId()) {
1117 case ID_DEF_MENU_MAX_DETAIL:
1118 vLat = zlat;
1119 vLon = zlon;
1120 parent->ClearbFollow();
1121
1122 parent->parent_frame->DoChartUpdate();
1123
1124 parent->SelectChartFromStack(0, false, CHART_TYPE_DONTCARE,
1125 CHART_FAMILY_RASTER);
1126 break;
1127
1128 case ID_DEF_MENU_SCALE_IN:
1129 parent->DoCanvasStackDelta(-1);
1130 break;
1131
1132 case ID_DEF_MENU_SCALE_OUT:
1133 parent->DoCanvasStackDelta(1);
1134 break;
1135
1136 case ID_UNDO:
1137 parent->undo->UndoLastAction();
1138 parent->InvalidateGL();
1139 parent->Refresh(false);
1140 break;
1141
1142 case ID_REDO:
1143 parent->undo->RedoNextAction();
1144 parent->InvalidateGL();
1145 parent->Refresh(false);
1146 break;
1147
1148 case ID_DEF_MENU_MOVE_BOAT_HERE:
1149 gLat = zlat;
1150 gLon = zlon;
1151 gFrame->UpdateStatusBar();
1152 break;
1153
1154 case ID_DEF_MENU_GOTO_HERE: {
1155 RoutePoint *pWP_dest = new RoutePoint(zlat, zlon, g_default_wp_icon,
1156 wxEmptyString, wxEmptyString);
1157 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP_dest);
1158
1159 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1160 wxEmptyString, wxEmptyString);
1161 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1162
1163 Route *temp_route = new Route();
1164 pRouteList->push_back(temp_route);
1165
1166 temp_route->AddPoint(pWP_src);
1167 temp_route->AddPoint(pWP_dest);
1168
1169 pSelect->AddSelectableRouteSegment(gLat, gLon, zlat, zlon, pWP_src,
1170 pWP_dest, temp_route);
1171
1172 temp_route->m_RouteNameString = _("Temporary GOTO Route");
1173 temp_route->m_RouteStartString = _("Here");
1174 ;
1175 temp_route->m_RouteEndString = _("There");
1176
1177 temp_route->m_bDeleteOnArrival = true;
1178
1179 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1180
1181 g_pRouteMan->ActivateRoute(temp_route, pWP_dest);
1182
1183 break;
1184 }
1185
1186 case ID_DEF_MENU_DROP_WP: {
1187 RoutePoint *pWP = new RoutePoint(zlat, zlon, g_default_wp_icon,
1188 wxEmptyString, wxEmptyString);
1189 pWP->m_bIsolatedMark = true; // This is an isolated mark
1190 pSelect->AddSelectableRoutePoint(zlat, zlon, pWP);
1191 NavObj_dB::GetInstance().InsertRoutePoint(pWP);
1192
1193 if (!RoutePointGui(*pWP).IsVisibleSelectable(this->parent))
1194 RoutePointGui(*pWP).ShowScaleWarningMessage(parent);
1195
1196 if (RouteManagerDialog::getInstanceFlag()) {
1197 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1198 pRouteManagerDialog->UpdateWptListCtrl();
1199 }
1200 }
1201
1202 parent->undo->BeforeUndoableAction(Undo_CreateWaypoint, pWP,
1203 Undo_HasParent, NULL);
1204 parent->undo->AfterUndoableAction(NULL);
1205 gFrame->RefreshAllCanvas(false);
1206 gFrame->InvalidateAllGL();
1207 g_FlushNavobjChanges = true;
1208 break;
1209 }
1210
1211 case ID_DEF_MENU_NEW_RT: {
1212 parent->StartRoute();
1213 break;
1214 }
1215
1216 case ID_DEF_MENU_AISTARGETLIST:
1217 parent->ShowAISTargetList();
1218 break;
1219
1220 case ID_DEF_MENU_AIS_CPAWARNING:
1221 parent->ToggleCPAWarn();
1222 break;
1223
1224 case ID_WP_MENU_GOTO: {
1225 RoutePoint *pWP_src = new RoutePoint(gLat, gLon, g_default_wp_icon,
1226 wxEmptyString, wxEmptyString);
1227 pSelect->AddSelectableRoutePoint(gLat, gLon, pWP_src);
1228
1229 Route *temp_route = new Route();
1230 pRouteList->push_back(temp_route);
1231
1232 temp_route->AddPoint(pWP_src);
1233 temp_route->AddPoint(m_pFoundRoutePoint);
1234 m_pFoundRoutePoint->SetShared(true);
1235
1236 pSelect->AddSelectableRouteSegment(gLat, gLon, m_pFoundRoutePoint->m_lat,
1237 m_pFoundRoutePoint->m_lon, pWP_src,
1238 m_pFoundRoutePoint, temp_route);
1239
1240 wxString name = m_pFoundRoutePoint->GetName();
1241 if (name.IsEmpty()) name = _("(Unnamed Waypoint)");
1242 wxString rteName = _("Go to ");
1243 rteName.Append(name);
1244 temp_route->m_RouteNameString = rteName;
1245 temp_route->m_RouteStartString = _("Here");
1246 ;
1247 temp_route->m_RouteEndString = name;
1248 temp_route->m_bDeleteOnArrival = true;
1249
1250 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1251
1252 g_pRouteMan->ActivateRoute(temp_route, m_pFoundRoutePoint);
1253
1254 break;
1255 }
1256
1257 case ID_DEF_MENU_COGUP:
1258 parent->SetUpMode(COURSE_UP_MODE);
1259 break;
1260
1261 case ID_DEF_MENU_HEADUP:
1262 parent->SetUpMode(HEAD_UP_MODE);
1263 break;
1264
1265 case ID_DEF_MENU_NORTHUP:
1266 parent->SetUpMode(NORTH_UP_MODE);
1267 break;
1268
1269 case ID_DEF_MENU_TOGGLE_FULL:
1270 gFrame->ToggleFullScreen();
1271 break;
1272
1273 case ID_DEF_MENU_GOTOPOSITION:
1274 if (NULL == pGoToPositionDialog) // There is one global instance of the
1275 // Go To Position Dialog
1277 pGoToPositionDialog->SetCanvas(parent);
1278 pGoToPositionDialog->CheckPasteBufferForPosition();
1279 pGoToPositionDialog->Show();
1280 break;
1281
1282 case ID_WP_MENU_DELPOINT: {
1283 if (m_pFoundRoutePoint == pAnchorWatchPoint1) {
1284 pAnchorWatchPoint1 = NULL;
1285 g_AW1GUID.Clear();
1286 } else if (m_pFoundRoutePoint == pAnchorWatchPoint2) {
1287 pAnchorWatchPoint2 = NULL;
1288 g_AW2GUID.Clear();
1289 }
1290
1291 if (m_pFoundRoutePoint && !(m_pFoundRoutePoint->m_bIsInLayer) &&
1292 (m_pFoundRoutePoint->GetIconName() != "mob")) {
1293 // If the WP belongs to an invisible route, we come here instead of to
1294 // ID_RT_MENU_DELPOINT
1295 // Check it, and if so then remove the point from its routes
1296 wxArrayPtrVoid *proute_array =
1297 g_pRouteMan->GetRouteArrayContaining(m_pFoundRoutePoint);
1298 if (proute_array) {
1299 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1300 delete proute_array;
1301 } else {
1302 parent->undo->BeforeUndoableAction(
1303 Undo_DeleteWaypoint, m_pFoundRoutePoint, Undo_IsOrphanded,
1304 NULL /*m_pFoundPoint*/);
1305 NavObj_dB::GetInstance().DeleteRoutePoint(m_pFoundRoutePoint);
1306 pSelect->DeleteSelectablePoint(m_pFoundRoutePoint,
1307 SELTYPE_ROUTEPOINT);
1308 if (NULL != pWayPointMan)
1309 pWayPointMan->RemoveRoutePoint(m_pFoundRoutePoint);
1310 parent->undo->AfterUndoableAction(NULL);
1311 }
1312
1313 if (g_pMarkInfoDialog) {
1314 g_pMarkInfoDialog->ClearData();
1315 }
1316
1317 if (RouteManagerDialog::getInstanceFlag()) {
1318 if (pRouteManagerDialog) {
1319 if (pRouteManagerDialog->IsShown())
1320 pRouteManagerDialog->UpdateWptListCtrl();
1321 }
1322 }
1323
1324 gFrame->RefreshAllCanvas(false);
1325 gFrame->InvalidateAllGL();
1326 }
1327 break;
1328 }
1329 case ID_WP_MENU_PROPERTIES:
1330 parent->ShowMarkPropertiesDialog(m_pFoundRoutePoint);
1331 break;
1332
1333 case ID_WP_MENU_CLEAR_ANCHORWATCH: {
1334 wxString guid = wxEmptyString;
1335 if (pAnchorWatchPoint1 == m_pFoundRoutePoint) {
1336 pAnchorWatchPoint1 = NULL;
1337 guid = g_AW1GUID;
1338 g_AW1GUID.Clear();
1339 } else if (pAnchorWatchPoint2 == m_pFoundRoutePoint) {
1340 pAnchorWatchPoint2 = NULL;
1341 guid = g_AW2GUID;
1342 g_AW2GUID.Clear();
1343 }
1344 if (!guid.IsEmpty()) {
1345 wxJSONValue v;
1346 v["GUID"] = guid;
1347 wxString msg_id("OCPN_ANCHOR_WATCH_CLEARED");
1348 SendJSONMessageToAllPlugins(msg_id, v);
1349 }
1350 break;
1351 }
1352
1353 case ID_WP_MENU_SET_ANCHORWATCH: {
1354 wxString guid = wxEmptyString;
1355 if (pAnchorWatchPoint1 == NULL) {
1356 pAnchorWatchPoint1 = m_pFoundRoutePoint;
1357 g_AW1GUID = pAnchorWatchPoint1->m_GUID;
1358 guid = g_AW1GUID;
1359 wxString nn;
1360 nn = m_pFoundRoutePoint->GetName();
1361 if (nn.IsNull()) {
1362 nn.Printf("%d m", g_nAWDefault);
1363 m_pFoundRoutePoint->SetName(nn);
1364 }
1365 } else if (pAnchorWatchPoint2 == NULL) {
1366 pAnchorWatchPoint2 = m_pFoundRoutePoint;
1367 g_AW2GUID = pAnchorWatchPoint2->m_GUID;
1368 guid = g_AW2GUID;
1369 wxString nn;
1370 nn = m_pFoundRoutePoint->GetName();
1371 if (nn.IsNull()) {
1372 nn.Printf("%d m", g_nAWDefault);
1373 m_pFoundRoutePoint->SetName(nn);
1374 }
1375 }
1376 if (!guid.IsEmpty()) {
1377 wxJSONValue v;
1378 v["GUID"] = guid;
1379 wxString msg_id("OCPN_ANCHOR_WATCH_SET");
1380 SendJSONMessageToAllPlugins(msg_id, v);
1381 }
1382 break;
1383 }
1384
1385 case ID_DEF_MENU_ACTIVATE_MEASURE:
1386 parent->StartMeasureRoute();
1387 break;
1388
1389 case ID_DEF_MENU_DEACTIVATE_MEASURE:
1390 parent->CancelMeasureRoute();
1391 // gFrame->SurfaceAllCanvasToolbars();
1392 parent->InvalidateGL();
1393 parent->Refresh(false);
1394 break;
1395
1396 case ID_DEF_MENU_CM93OFFSET_DIALOG: {
1397 if (NULL == g_pCM93OffsetDialog) {
1398 g_pCM93OffsetDialog = new CM93OffsetDialog(parent->parent_frame);
1399 }
1400
1401 cm93compchart *pch = NULL;
1402 if (!parent->GetVP().b_quilt && parent->m_singleChart &&
1403 (parent->m_singleChart->GetChartType() == CHART_TYPE_CM93COMP)) {
1404 pch = (cm93compchart *)parent->m_singleChart;
1405 }
1406
1407 if (g_pCM93OffsetDialog) {
1408 g_pCM93OffsetDialog->SetCM93Chart(pch);
1409 g_pCM93OffsetDialog->Show();
1410 g_pCM93OffsetDialog->UpdateMCOVRList(parent->GetVP());
1411 }
1412
1413 break;
1414 }
1415 case ID_DEF_MENU_QUERY: {
1416 parent->ShowObjectQueryWindow(popx, popy, zlat, zlon);
1417 break;
1418 }
1419 case ID_DEF_MENU_AIS_QUERY: {
1420 ShowAISTargetQueryDialog(parent, m_FoundAIS_MMSI);
1421 break;
1422 }
1423
1424 case ID_DEF_MENU_AIS_CPA: {
1425 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1426 if (myptarget) myptarget->Toggle_AIS_CPA();
1427 break;
1428 }
1429
1430 case ID_DEF_MENU_AISSHOWTRACK: {
1431 auto myptarget = g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI);
1432 if (myptarget) myptarget->ToggleShowTrack();
1433 break;
1434 }
1435
1436 case ID_DEF_MENU_COPY_MMSI: {
1437 // Write MMSI # as text to the clipboard
1438 if (wxTheClipboard->Open()) {
1439 wxTheClipboard->SetData(
1440 new wxTextDataObject(wxString::Format("%09d", m_FoundAIS_MMSI)));
1441 wxTheClipboard->Close();
1442 }
1443 break;
1444 }
1445
1446 case ID_DEF_MENU_QUILTREMOVE: {
1447 if (parent->GetVP().b_quilt) {
1448 int dbIndex = parent->m_pQuilt->GetChartdbIndexAtPix(
1449 parent->GetVP(), wxPoint(popx, popy));
1450 parent->RemoveChartFromQuilt(dbIndex);
1451
1452 parent->ReloadVP();
1453 }
1454
1455 break;
1456 }
1457
1458 case ID_DEF_MENU_CURRENTINFO: {
1459 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1460 parent->Refresh(false);
1461
1462 break;
1463 }
1464
1465 case ID_DEF_MENU_TIDEINFO: {
1466 parent->DrawTCWindow(popx, popy, (void *)m_pIDXCandidate);
1467 parent->Refresh(false);
1468
1469 break;
1470 }
1471
1472 case ID_DGB_MENU_NMEA_WINDOW:
1473 m_nmea_log->Show();
1474 m_nmea_log->Raise();
1475 break;
1476
1477 case ID_RT_MENU_REVERSE: {
1478 if (m_pSelectedRoute->m_bIsInLayer) break;
1479
1480 int ask_return =
1481 OCPNMessageBox(parent, g_pRouteMan->GetRouteReverseMessage(),
1482 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1483
1484 if (ask_return != wxID_CANCEL) {
1485 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1486 m_pSelectedRoute->Reverse(ask_return == wxID_YES);
1487 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1488
1489 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1490
1491 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1492 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute);
1493 // pNew->UpdateProperties();
1494 }
1495 gFrame->InvalidateAllGL();
1496 gFrame->RefreshAllCanvas();
1497 }
1498 break;
1499 }
1500
1501 case ID_RT_MENU_SHOWNAMES: {
1502 if (m_pSelectedRoute) {
1503 m_pSelectedRoute->ShowWaypointNames(
1504 !m_pSelectedRoute->AreWaypointNamesVisible());
1505 }
1506
1507 break;
1508 }
1509
1510 case ID_RT_MENU_RESEQUENCE: {
1511 if (m_pSelectedRoute) {
1512 if (m_pSelectedRoute->m_bIsInLayer) break;
1513
1514 int ask_return =
1515 OCPNMessageBox(parent, g_pRouteMan->GetRouteResequenceMessage(),
1516 _("Rename Waypoints?"), wxYES_NO | wxCANCEL);
1517
1518 if (ask_return != wxID_CANCEL) {
1519 m_pSelectedRoute->RenameRoutePoints();
1520 }
1521
1522 gFrame->InvalidateAllGL();
1523 gFrame->RefreshAllCanvas();
1524 }
1525
1526 break;
1527 }
1528
1529 case ID_RT_MENU_DELETE: {
1530 bool confirmed = RouteGui::OnDelete(parent);
1531
1532 if (confirmed) {
1533 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1534 g_pRouteMan->DeactivateRoute();
1535
1536 if (m_pSelectedRoute->m_bIsInLayer) break;
1537
1538 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1539 if (!g_pRouteMan->DeleteRoute(m_pSelectedRoute)) break;
1540
1541 if (RouteManagerDialog::getInstanceFlag()) {
1542 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1543 pRouteManagerDialog->UpdateRouteListCtrl();
1544 }
1545
1546 if (g_pMarkInfoDialog && g_pMarkInfoDialog->IsShown()) {
1547 g_pMarkInfoDialog->ValidateMark();
1548 g_pMarkInfoDialog->UpdateProperties();
1549 }
1550
1551 parent->undo->InvalidateUndo();
1552
1553 gFrame->InvalidateAllGL();
1554 gFrame->RefreshAllCanvas();
1555 }
1556 break;
1557 }
1558
1559 case ID_RT_MENU_ACTIVATE: {
1560 if (g_pRouteMan->GetpActiveRoute()) g_pRouteMan->DeactivateRoute();
1561
1562 // If this is an auto-created MOB route, always select the second point
1563 // (the MOB)
1564 // as the destination.
1565 RoutePoint *best_point;
1566 if (m_pSelectedRoute) {
1567 if (wxNOT_FOUND == m_pSelectedRoute->m_RouteNameString.Find("MOB")) {
1568 best_point = g_pRouteMan->FindBestActivatePoint(
1569 m_pSelectedRoute, gLat, gLon, gCog, gSog);
1570 } else
1571 best_point = m_pSelectedRoute->GetPoint(2);
1572
1573 g_pRouteMan->ActivateRoute(m_pSelectedRoute, best_point);
1574 m_pSelectedRoute->m_bRtIsSelected = false;
1575 }
1576
1577 break;
1578 }
1579
1580 case ID_RT_MENU_DEACTIVATE:
1581 g_pRouteMan->DeactivateRoute();
1582 m_pSelectedRoute->m_bRtIsSelected = false;
1583
1584 break;
1585
1586 case ID_RT_MENU_INSERT: {
1587 if (m_pSelectedRoute->m_bIsInLayer) break;
1588 bool rename = false;
1589 m_pSelectedRoute->InsertPointAfter(m_pFoundRoutePoint, zlat, zlon,
1590 rename);
1591
1592 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1593 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1594
1595 pSelect->AddAllSelectableRouteSegments(m_pSelectedRoute);
1596 pSelect->AddAllSelectableRoutePoints(m_pSelectedRoute);
1597
1598 // As a special case (which comes up often)...
1599 // If the inserted waypoint is on the active leg of an active route
1600 /* if(m_pSelectedRoute->m_bRtIsActive)
1601 {
1602 if(m_pSelectedRoute->m_nRouteActivePoint == np + 1)
1603 {
1604 pNew_Point = m_pSelectedRoute->GetPoint(np + 2);
1605 pRouteMan->ActivateRoutePoint(m_pSelectedRoute, pNew_Point);
1606 }
1607 }
1608 */
1609 NavObj_dB::GetInstance().UpdateRoute(m_pSelectedRoute);
1610
1611 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1612 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1613 }
1614
1615 break;
1616 }
1617
1618 case ID_RT_MENU_APPEND:
1619
1620 if (m_pSelectedRoute->m_bIsInLayer) break;
1621
1622 parent->m_pMouseRoute = m_pSelectedRoute;
1623 parent->m_routeState = m_pSelectedRoute->GetnPoints() + 1;
1624 parent->m_pMouseRoute->m_lastMousePointIndex =
1625 m_pSelectedRoute->GetnPoints();
1626 parent->m_pMouseRoute->SetHiLite(50);
1627
1628 pLast = m_pSelectedRoute->GetLastPoint();
1629
1630 parent->m_prev_rlat = pLast->m_lat;
1631 parent->m_prev_rlon = pLast->m_lon;
1632 parent->m_prev_pMousePoint = pLast;
1633
1634 parent->m_bAppendingRoute = true;
1635
1636 parent->SetCursor(*parent->pCursorPencil);
1637#ifdef __ANDROID__
1638 androidSetRouteAnnunciator(true);
1639#endif
1640
1641 parent->HideGlobalToolbar();
1642
1643 break;
1644
1645 case ID_RT_MENU_SPLIT_LEG: // split route around a leg
1646 splitMode++;
1647 dupFirstWpt = false;
1648 case ID_RT_MENU_SPLIT_WPT: // split route at a wpt
1649
1650 showRPD = (pRoutePropDialog && pRoutePropDialog->IsShown());
1651
1652 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute)
1653 g_pRouteMan->DeactivateRoute();
1654
1655 m_pHead = new Route();
1656 m_pTail = new Route();
1657 m_pHead->CloneRoute(m_pSelectedRoute, 1, m_SelectedIdx, _("_A"));
1658 m_pTail->CloneRoute(m_pSelectedRoute, m_SelectedIdx + splitMode,
1659 m_pSelectedRoute->GetnPoints(), _("_B"), dupFirstWpt);
1660 pRouteList->push_back(m_pHead);
1661 NavObj_dB::GetInstance().InsertRoute(m_pHead);
1662
1663 pRouteList->push_back(m_pTail);
1664 NavObj_dB::GetInstance().InsertRoute(m_pTail);
1665
1666 NavObj_dB::GetInstance().DeleteRoute(m_pSelectedRoute);
1667
1668 pSelect->DeleteAllSelectableRoutePoints(m_pSelectedRoute);
1669 pSelect->DeleteAllSelectableRouteSegments(m_pSelectedRoute);
1670 g_pRouteMan->DeleteRoute(m_pSelectedRoute);
1671 pSelect->AddAllSelectableRouteSegments(m_pTail);
1672 pSelect->AddAllSelectableRoutePoints(m_pTail);
1673 pSelect->AddAllSelectableRouteSegments(m_pHead);
1674 pSelect->AddAllSelectableRoutePoints(m_pHead);
1675
1676 if (showRPD) {
1677 pRoutePropDialog->SetRouteAndUpdate(m_pHead);
1678 pRoutePropDialog->Show();
1679 }
1680 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog &&
1681 (pRouteManagerDialog->IsShown()))
1682 pRouteManagerDialog->UpdateRouteListCtrl();
1683 break;
1684
1685 case ID_RT_MENU_COPY:
1686 if (m_pSelectedRoute) Kml::CopyRouteToClipboard(m_pSelectedRoute);
1687 break;
1688
1689 case ID_TK_MENU_COPY:
1690 if (m_pSelectedTrack) Kml::CopyTrackToClipboard(m_pSelectedTrack);
1691 break;
1692
1693 case ID_WPT_MENU_COPY:
1694 if (m_pFoundRoutePoint) Kml::CopyWaypointToClipboard(m_pFoundRoutePoint);
1695 break;
1696
1697 case ID_WPT_MENU_SENDTOGPS:
1698 if (m_pFoundRoutePoint) {
1699 if (parent->m_active_upload_port.Length())
1700 RoutePointGui(*m_pFoundRoutePoint)
1701 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), NULL);
1702 else {
1703 SendToGpsDlg dlg;
1704 dlg.SetWaypoint(m_pFoundRoutePoint);
1705 wxFont fo = GetOCPNGUIScaledFont(_("Dialog"));
1706 dlg.SetFont(fo);
1707
1708 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1709 dlg.ShowModal();
1710 }
1711 }
1712 break;
1713
1714 case ID_WPT_MENU_SENDTONEWGPS:
1715 if (m_pFoundRoutePoint) {
1716 SendToGpsDlg dlg;
1717 dlg.SetWaypoint(m_pFoundRoutePoint);
1718
1719 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1720 dlg.ShowModal();
1721 }
1722 break;
1723
1724 case ID_WPT_MENU_SENDTOPEER:
1725 if (m_pFoundRoutePoint) {
1726 SendToPeerDlg dlg;
1727 dlg.SetWaypoint(m_pFoundRoutePoint);
1728
1729 // Perform initial scan, if necessary
1730
1731 // Check for stale cache...
1732 MdnsCache::GetInstance().Validate();
1733 if (MdnsCache::GetInstance().GetCache().empty())
1734 dlg.SetScanOnCreate(true);
1735
1736 dlg.SetScanTime(5); // seconds
1737 dlg.Create(NULL, -1, _("Send Waypoint to OpenCPN Peer") + "...", "");
1738 dlg.ShowModal();
1739 }
1740 break;
1741
1742 case ID_RT_MENU_SENDTOGPS:
1743 if (m_pSelectedRoute) {
1744 if (parent->m_active_upload_port.Length())
1745 RouteGui(*m_pSelectedRoute)
1746 .SendToGPS(parent->m_active_upload_port.BeforeFirst(' '), true,
1747 NULL);
1748 else {
1749 SendToGpsDlg dlg;
1750 dlg.SetRoute(m_pSelectedRoute);
1751
1752 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1753 dlg.ShowModal();
1754 }
1755 }
1756 break;
1757
1758 case ID_RT_MENU_SENDTONEWGPS:
1759 if (m_pSelectedRoute) {
1760 SendToGpsDlg dlg;
1761 dlg.SetRoute(m_pSelectedRoute);
1762
1763 dlg.Create(NULL, -1, _("Send to GPS") + "...", "");
1764 dlg.ShowModal();
1765 }
1766 break;
1767
1768 case ID_RT_MENU_SENDTOPEER:
1769 if (m_pSelectedRoute) {
1770 SendToPeerDlg dlg;
1771 dlg.SetRoute(m_pSelectedRoute);
1772
1773 // Perform initial scan, if necessary
1774
1775 // Check for stale cache...
1776 MdnsCache::GetInstance().Validate();
1777 if (MdnsCache::GetInstance().GetCache().empty())
1778 dlg.SetScanOnCreate(true);
1779
1780 dlg.SetScanTime(5); // seconds
1781 dlg.Create(NULL, -1, _("Send Route to OpenCPN Peer") + "...", "");
1782 dlg.ShowModal();
1783 }
1784 break;
1785
1786 case ID_PASTE_WAYPOINT:
1787 pupHandler_PasteWaypoint();
1788 break;
1789
1790 case ID_PASTE_ROUTE:
1791 pupHandler_PasteRoute();
1792 break;
1793
1794 case ID_PASTE_TRACK:
1795 pupHandler_PasteTrack();
1796 break;
1797
1798 case ID_RT_MENU_DELPOINT:
1799 if (m_pSelectedRoute) {
1800 if (m_pSelectedRoute->m_bIsInLayer) break;
1801
1802 pWayPointMan->DestroyWaypoint(m_pFoundRoutePoint);
1803
1804 if (pRoutePropDialog && (pRoutePropDialog->IsShown())) {
1805 // Selected route may have been deleted as one-point route, so
1806 // check it
1807 if (g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
1808 pRoutePropDialog->SetRouteAndUpdate(m_pSelectedRoute, true);
1809 } else
1810 pRoutePropDialog->Hide();
1811 }
1812
1813 if (RouteManagerDialog::getInstanceFlag()) {
1814 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
1815 pRouteManagerDialog->UpdateWptListCtrl();
1816 pRouteManagerDialog->UpdateRouteListCtrl();
1817 }
1818 }
1819
1820 gFrame->InvalidateAllGL();
1821 gFrame->RefreshAllCanvas(true);
1822 }
1823
1824 break;
1825
1826 case ID_RT_MENU_REMPOINT:
1827 if (m_pSelectedRoute) {
1828 if (m_pSelectedRoute->m_bIsInLayer) break;
1829 g_pRouteMan->RemovePointFromRoute(m_pFoundRoutePoint, m_pSelectedRoute,
1830 parent->m_routeState);
1831 gFrame->InvalidateAllGL();
1832 gFrame->RefreshAllCanvas();
1833 }
1834 break;
1835
1836 case ID_RT_MENU_ACTPOINT:
1837 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1838 g_pRouteMan->ActivateRoutePoint(m_pSelectedRoute, m_pFoundRoutePoint);
1839 m_pSelectedRoute->m_bRtIsSelected = false;
1840 }
1841
1842 break;
1843
1844 case ID_RT_MENU_DEACTPOINT:
1845 break;
1846
1847 case ID_RT_MENU_ACTNXTPOINT:
1848 if (g_pRouteMan->GetpActiveRoute() == m_pSelectedRoute) {
1849 g_pRouteMan->ActivateNextPoint(m_pSelectedRoute, true);
1850 m_pSelectedRoute->m_bRtIsSelected = false;
1851 }
1852
1853 break;
1854
1855 case ID_RT_MENU_PROPERTIES: {
1856 parent->ShowRoutePropertiesDialog(_("Route Properties"),
1857 m_pSelectedRoute);
1858 break;
1859 }
1860
1861 case ID_TK_MENU_PROPERTIES: {
1862 parent->ShowTrackPropertiesDialog(m_pSelectedTrack);
1863 break;
1864 }
1865
1866 case ID_TK_MENU_DELETE: {
1867 int dlg_return = wxID_YES;
1868 if (g_bConfirmObjectDelete) {
1869 dlg_return = OCPNMessageBox(
1870 parent, _("Are you sure you want to delete this track?"),
1871 _("OpenCPN Track Delete"),
1872 (long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
1873 }
1874
1875 if (dlg_return == wxID_YES) {
1876 if (m_pSelectedTrack == g_pActiveTrack)
1877 m_pSelectedTrack = parent->parent_frame->TrackOff();
1878 g_pAIS->DeletePersistentTrack(m_pSelectedTrack);
1879 // pConfig->DeleteConfigTrack(m_pSelectedTrack);
1880 NavObj_dB::GetInstance().DeleteTrack(m_pSelectedTrack);
1881 RoutemanGui(*g_pRouteMan).DeleteTrack(m_pSelectedTrack);
1882
1883 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
1884 (pTrackPropDialog->IsShown()) &&
1885 (m_pSelectedTrack == pTrackPropDialog->GetTrack())) {
1886 pTrackPropDialog->Hide();
1887 }
1888
1889 if (RoutePropDlgImpl::getInstanceFlag() && pRouteManagerDialog &&
1890 pRouteManagerDialog->IsShown()) {
1891 pRouteManagerDialog->UpdateTrkListCtrl();
1892 pRouteManagerDialog->UpdateRouteListCtrl();
1893 }
1894 gFrame->InvalidateAllGL();
1895 gFrame->RefreshAllCanvas();
1896 }
1897 break;
1898 }
1899
1900 case ID_TK_MENU_SENDTOPEER:
1901 if (m_pSelectedTrack) {
1902 SendToPeerDlg dlg;
1903 dlg.SetTrack(m_pSelectedTrack);
1904
1905 // Perform initial scan, if necessary
1906
1907 // Check for stale cache...
1908 MdnsCache::GetInstance().Validate();
1909 if (MdnsCache::GetInstance().GetCache().empty())
1910 dlg.SetScanOnCreate(true);
1911
1912 dlg.SetScanTime(5); // seconds
1913 dlg.Create(NULL, -1, _("Send Track to OpenCPN Peer") + "...", "");
1914 dlg.ShowModal();
1915 }
1916 break;
1917
1918 case ID_RC_MENU_SCALE_IN:
1919 parent->parent_frame->DoStackDown(parent);
1920 parent->GetCanvasPointPix(zlat, zlon, &r);
1921 parent->WarpPointer(r.x, r.y);
1922 break;
1923
1924 case ID_RC_MENU_SCALE_OUT:
1925 parent->parent_frame->DoStackUp(parent);
1926 parent->GetCanvasPointPix(zlat, zlon, &r);
1927 parent->WarpPointer(r.x, r.y);
1928 break;
1929
1930 case ID_RC_MENU_ZOOM_IN:
1931 parent->SetVPScale(parent->GetVPScale() * 2);
1932 parent->GetCanvasPointPix(zlat, zlon, &r);
1933 parent->WarpPointer(r.x, r.y);
1934 break;
1935
1936 case ID_RC_MENU_ZOOM_OUT:
1937 parent->SetVPScale(parent->GetVPScale() / 2);
1938 parent->GetCanvasPointPix(zlat, zlon, &r);
1939 parent->WarpPointer(r.x, r.y);
1940 break;
1941
1942 case ID_RC_MENU_FINISH:
1943 parent->FinishRoute();
1944 // gFrame->SurfaceAllCanvasToolbars();
1945 parent->Refresh(false);
1946 g_FlushNavobjChanges = true;
1947 break;
1948
1949 case ID_DEF_ZERO_XTE:
1950 g_pRouteMan->ZeroCurrentXTEToActivePoint();
1951 break;
1952
1953 default: {
1954 // Look for PlugIn Context Menu selections
1955 // If found, make the callback
1956 ArrayOfPlugInMenuItems item_array =
1957 g_pi_manager->GetPluginContextMenuItemArray();
1958
1959 for (unsigned int i = 0; i < item_array.GetCount(); i++) {
1960 PlugInMenuItemContainer *pimis = item_array[i];
1961 int target_id = pimis->id;
1962
1963 // Check submenus, if present.
1964 if (pimis->pmenu_item->GetSubMenu()) {
1965 const wxMenuItemList &items =
1966 pimis->pmenu_item->GetSubMenu()->GetMenuItems();
1967 for (wxMenuItemList::const_iterator it = items.begin();
1968 it != items.end(); ++it) {
1969 if ((*it)->GetId() == event.GetId()) {
1970 target_id = (*it)->GetId();
1971 break;
1972 }
1973 }
1974 }
1975
1976 if (pimis->m_pplugin && (target_id == event.GetId())) {
1977 if (pimis->extended) {
1978 std::string object_type;
1979 std::string object_ident;
1980
1981 if ((pimis->m_in_menu.IsSameAs("Waypoint")) && m_pFoundRoutePoint) {
1982 object_type = "Waypoint";
1983 object_ident = m_pFoundRoutePoint->m_GUID.ToStdString();
1984 } else if ((pimis->m_in_menu.IsSameAs("Route")) &&
1985 m_pSelectedRoute) {
1986 object_type = "Route";
1987 object_ident = m_pSelectedRoute->m_GUID.ToStdString();
1988 } else if ((pimis->m_in_menu.IsSameAs("Track")) &&
1989 m_pSelectedTrack) {
1990 object_type = "Track";
1991 object_ident = m_pSelectedTrack->m_GUID.ToStdString();
1992 } else if ((pimis->m_in_menu.IsSameAs("AIS")) && m_FoundAIS_MMSI) {
1993 object_type = "AIS";
1994 wxString sAIS = wxString::Format("%d", m_FoundAIS_MMSI);
1995 object_ident = sAIS.ToStdString();
1996 }
1997
1998 opencpn_plugin_120 *ppi =
1999 dynamic_cast<opencpn_plugin_120 *>(pimis->m_pplugin);
2000 if (ppi)
2001 ppi->OnContextMenuItemCallbackExt(target_id, object_ident,
2002 object_type, zlat, zlon);
2003 } else {
2004 pimis->m_pplugin->OnContextMenuItemCallback(pimis->id);
2005 }
2006 }
2007 }
2008 break;
2009 }
2010 } // switch
2011
2012 // Chart Groups....
2013 if ((event.GetId() >= ID_DEF_MENU_GROUPBASE) &&
2014 (event.GetId() <=
2015 ID_DEF_MENU_GROUPBASE + (int)g_pGroupArray->GetCount())) {
2016 parent->SetGroupIndex(event.GetId() - ID_DEF_MENU_GROUPBASE);
2017 }
2018
2019 parent->InvalidateGL();
2020
2021 g_click_stop = 0; // Context menu was processed, all is well
2022}
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
AIS target definitions.
Canvas context (right click) menu handler.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
Definition chartdbs.cpp:56
Basic chart info storage.
Generic Chart canvas base.
double GetDisplayDIPMult(wxWindow *win)
Get the display scaling factor for DPI-aware rendering.
Dialog for managing CM93 chart offsets.
Definition cm93.h:539
Base class for all chart types.
Definition chartbase.h:125
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:157
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4495
double GetDisplayScale()
Get the ratio of physical to logical pixel for the display.
Definition chcanv.h:860
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
Definition chcanv.h:472
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
Definition chcanv.cpp:5307
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4520
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
Definition chcanv.cpp:13606
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.