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