OpenCPN Partial API docs
Loading...
Searching...
No Matches
mark_info.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 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 "config.h"
25
26// For compilers that support precompilation, includes "wx/wx.h".
27#include <wx/wxprec.h>
28
29#ifndef WX_PRECOMP
30#include <wx/wx.h>
31#endif
32
33#include <wx/arrimpl.cpp>
34#include <wx/datetime.h>
35#include <wx/clipbrd.h>
36#include <wx/print.h>
37#include <wx/printdlg.h>
38#include <wx/stattext.h>
39#include <wx/clrpicker.h>
40#include <wx/bmpbuttn.h>
41
42#include "model/config_vars.h"
43#include "model/georef.h"
44#include "model/navobj_db.h"
45#include "model/navutil_base.h"
46#include "model/own_ship.h"
48#include "model/route.h"
49#include "model/routeman.h"
50#include "model/select.h"
51#include "model/svg_utils.h"
52
53#include "chcanv.h"
54#include "gui_lib.h"
55#include "mark_info.h"
56#include "navutil.h"
57#include "ocpn_frame.h"
58#include "ocpn_platform.h"
59#include "pluginmanager.h"
60#include "routemanagerdialog.h"
61#include "route_prop_dlg_impl.h"
62#include "styles.h"
63#include "tcmgr.h"
64#include "tc_win.h"
65#include "ui_utils.h"
66
67#ifdef __ANDROID__
68#include "androidUTIL.h"
69#include <QtWidgets/QScroller>
70#endif
71
72#define EXTENDED_PROP_PAGE 2 // Index of the extended properties page
73
74WX_DEFINE_OBJARRAY(ArrayOfBitmaps);
75
77
78OCPNIconCombo::OCPNIconCombo(wxWindow* parent, wxWindowID id,
79 const wxString& value, const wxPoint& pos,
80 const wxSize& size, int n,
81 const wxString choices[], long style,
82 const wxValidator& validator, const wxString& name)
83 : wxOwnerDrawnComboBox(parent, id, value, pos, size, n, choices, style,
84 validator, name) {
85 double fontHeight =
86 GetFont().GetPointSize() / g_Platform->getFontPointsperPixel();
87 itemHeight = (int)wxRound(fontHeight);
88}
89
90OCPNIconCombo::~OCPNIconCombo() {}
91
92void OCPNIconCombo::OnDrawItem(wxDC& dc, const wxRect& rect, int item,
93 int flags) const {
94 int offset_x = bmpArray[item].GetWidth();
95 int bmpHeight = bmpArray[item].GetHeight();
96 dc.DrawBitmap(bmpArray[item], rect.x, rect.y + (rect.height - bmpHeight) / 2,
97 true);
98
99 if (flags & wxODCB_PAINTING_CONTROL) {
100 wxString text = GetValue();
101 int margin_x = 2;
102
103#if wxCHECK_VERSION(2, 9, 0)
104 if (ShouldUseHintText()) {
105 text = GetHint();
106 wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
107 dc.SetTextForeground(col);
108 }
109
110 margin_x = GetMargins().x;
111#endif
112
113 dc.DrawText(text, rect.x + margin_x + offset_x,
114 (rect.height - dc.GetCharHeight()) / 2 + rect.y);
115 } else {
116 dc.DrawText(GetVListBoxComboPopup()->GetString(item), rect.x + 2 + offset_x,
117 (rect.height - dc.GetCharHeight()) / 2 + rect.y);
118 }
119}
120
121wxCoord OCPNIconCombo::OnMeasureItem(size_t item) const {
122 int bmpHeight = bmpArray[item].GetHeight();
123
124 return wxMax(itemHeight, bmpHeight);
125}
126
127wxCoord OCPNIconCombo::OnMeasureItemWidth(size_t item) const { return -1; }
128
129int OCPNIconCombo::Append(const wxString& item, wxBitmap bmp) {
130 bmpArray.Add(bmp);
131 int idx = wxOwnerDrawnComboBox::Append(item);
132
133 return idx;
134}
135
136void OCPNIconCombo::Clear() {
137 wxOwnerDrawnComboBox::Clear();
138 bmpArray.Clear();
139}
140
141//-------------------------------------------------------------------------------
142//
143// Mark Properties Dialog Implementation
144//
145//-------------------------------------------------------------------------------
150// DEFINE_EVENT_TYPE(EVT_LLCHANGE) // events from LatLonTextCtrl
151const wxEventType EVT_LLCHANGE = wxNewEventType();
152//------------------------------------------------------------------------------
153// LatLonTextCtrl Window Implementation
154//------------------------------------------------------------------------------
155BEGIN_EVENT_TABLE(LatLonTextCtrl, wxWindow)
156END_EVENT_TABLE()
157
158// constructor
159LatLonTextCtrl::LatLonTextCtrl(wxWindow* parent, wxWindowID id,
160 const wxString& value, const wxPoint& pos,
161 const wxSize& size, long style,
162 const wxValidator& validator,
163 const wxString& name)
164 : wxTextCtrl(parent, id, value, pos, size, style, validator, name) {
165 m_pParentEventHandler = parent->GetEventHandler();
166}
167
168void LatLonTextCtrl::OnKillFocus(wxFocusEvent& event) {
169 // Send an event to the Parent Dialog
170 wxCommandEvent up_event(EVT_LLCHANGE, GetId());
171 up_event.SetEventObject((wxObject*)this);
172 m_pParentEventHandler->AddPendingEvent(up_event);
173}
174
175//-------------------------------------------------------------------------------
176//
177// Mark Information Dialog Implementation
178//
179//-------------------------------------------------------------------------------
180BEGIN_EVENT_TABLE(MarkInfoDlg, DIALOG_PARENT)
181EVT_BUTTON(wxID_OK, MarkInfoDlg::OnMarkInfoOKClick)
182EVT_BUTTON(wxID_CANCEL, MarkInfoDlg::OnMarkInfoCancelClick)
183EVT_BUTTON(ID_BTN_DESC_BASIC, MarkInfoDlg::OnExtDescriptionClick)
184EVT_BUTTON(ID_DEFAULT, MarkInfoDlg::DefautlBtnClicked)
185EVT_BUTTON(ID_BTN_SHOW_TIDES, MarkInfoDlg::ShowTidesBtnClicked)
186EVT_COMBOBOX(ID_BITMAPCOMBOCTRL, MarkInfoDlg::OnBitmapCombClick)
187EVT_CHECKBOX(ID_CHECKBOX_SCAMIN_VIS, MarkInfoDlg::OnSelectScaMinExt)
188EVT_TEXT(ID_DESCR_CTR_DESC, MarkInfoDlg::OnDescChangedExt)
189EVT_TEXT(ID_DESCR_CTR_BASIC, MarkInfoDlg::OnDescChangedBasic)
190EVT_TEXT(ID_LATCTRL, MarkInfoDlg::OnPositionCtlUpdated)
191EVT_TEXT(ID_LONCTRL, MarkInfoDlg::OnPositionCtlUpdated)
192EVT_CHOICE(ID_WPT_RANGERINGS_NO, MarkInfoDlg::OnWptRangeRingsNoChange)
193// the HTML listbox's events
194EVT_HTML_LINK_CLICKED(wxID_ANY, MarkInfoDlg::OnHtmlLinkClicked)
195EVT_COMMAND(wxID_ANY, EVT_LAYOUT_RESIZE, MarkInfoDlg::OnLayoutResize)
196EVT_CLOSE(MarkInfoDlg::OnClose)
197
198// EVT_CHOICE( ID_WAYPOINTRANGERINGS, MarkInfoDef::OnWaypointRangeRingSelect )
199END_EVENT_TABLE()
200
201MarkInfoDlg::MarkInfoDlg(wxWindow* parent, wxWindowID id, const wxString& title,
202 const wxPoint& pos, const wxSize& size, long style) {
203 DIALOG_PARENT::Create(parent, id, title, pos, size, style);
204
205 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
206 SetFont(*qFont);
207 int metric = GetCharHeight();
208
209#ifdef __ANDROID__
210 // Set Dialog Font by custom crafted Qt Stylesheet.
211 wxString wqs = getFontQtStylesheet(qFont);
212 wxCharBuffer sbuf = wqs.ToUTF8();
213 QString qsb = QString(sbuf.data());
214 QString qsbq = getQtStyleSheet(); // basic scrollbars, etc
215 this->GetHandle()->setStyleSheet(qsb + qsbq); // Concatenated style sheets
216 wxScreenDC sdc;
217 if (sdc.IsOk()) sdc.GetTextExtent("W", NULL, &metric, NULL, NULL, qFont);
218#endif
219 Create();
220 m_pMyLinkList = NULL;
221 SetColorScheme((ColorScheme)0);
222 m_pRoutePoint = NULL;
223 m_SaveDefaultDlg = NULL;
224 CenterOnScreen();
225
226#ifdef __WXOSX__
227 Connect(wxEVT_ACTIVATE, wxActivateEventHandler(MarkInfoDlg::OnActivate), NULL,
228 this);
229#endif
230}
231
232void MarkInfoDlg::OnActivate(wxActivateEvent& event) {
233 auto pWin = dynamic_cast<DIALOG_PARENT*>(event.GetEventObject());
234 long int style = pWin->GetWindowStyle();
235 if (event.GetActive())
236 pWin->SetWindowStyle(style | wxSTAY_ON_TOP);
237 else
238 pWin->SetWindowStyle(style ^ wxSTAY_ON_TOP);
239}
240
241void MarkInfoDlg::initialize_images() {
242 wxString iconDir = g_Platform->GetSharedDataDir() + "uidata/MUI_flat/";
243 _img_MUI_settings_svg = LoadSVG(iconDir + "MUI_settings.svg",
244 2 * GetCharHeight(), 2 * GetCharHeight());
245
246 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
247 wxBitmap tide = style->GetIcon("tidesml");
248 wxImage tide1 = tide.ConvertToImage();
249 wxImage tide1s = tide1.Scale(m_sizeMetric * 3 / 2, m_sizeMetric * 3 / 2,
250 wxIMAGE_QUALITY_HIGH);
251 m_bmTide = wxBitmap(tide1s);
252
253 return;
254}
255
256void MarkInfoDlg::Create() {
257 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
258 SetFont(*qFont);
259 m_sizeMetric = GetCharHeight();
260
261#ifdef __ANDROID__
262 // Set Dialog Font by custom crafted Qt Stylesheet.
263
264 wxString wqs = getFontQtStylesheet(qFont);
265 wxCharBuffer sbuf = wqs.ToUTF8();
266 QString qsb = QString(sbuf.data());
267
268 QString qsbq = getAdjustedDialogStyleSheet(); // basic scrollbars, etc
269
270 this->GetHandle()->setStyleSheet(qsb + qsbq); // Concatenated style sheets
271
272 wxScreenDC sdc;
273 if (sdc.IsOk())
274 sdc.GetTextExtent("W", NULL, &m_sizeMetric, NULL, NULL, qFont);
275
276#endif
277
278 initialize_images();
279
280 wxBoxSizer* bSizer1;
281 bSizer1 = new wxBoxSizer(wxVERTICAL);
282 SetSizer(bSizer1);
283 bSizer1->SetSizeHints(this); // set size hints to honour minimum size
284
285 // Notebook with fixed width tabs
286 m_notebookProperties = new wxNotebook(this, wxID_ANY, wxDefaultPosition,
287 wxDefaultSize, wxNB_FIXEDWIDTH);
288
289 m_panelBasicProperties = new wxScrolledWindow(
290 m_notebookProperties, wxID_ANY, wxDefaultPosition, wxDefaultSize,
291 wxHSCROLL | wxVSCROLL | wxTAB_TRAVERSAL);
292#ifdef __ANDROID__
293 m_panelBasicProperties->GetHandle()->setStyleSheet(
294 getAdjustedDialogStyleSheet());
295#endif
296
297 // Basic panel
298 m_panelBasicProperties->SetScrollRate(0, 2);
299 m_notebookProperties->AddPage(m_panelBasicProperties, _("Basic"), true);
300 bSizerBasicProperties = new wxBoxSizer(wxVERTICAL);
301 m_panelBasicProperties->SetSizer(bSizerBasicProperties);
302
303 // Layer notification
304 m_staticTextLayer = new wxStaticText(
305 m_panelBasicProperties, wxID_ANY,
306 _("This waypoint is part of a layer and can't be edited"),
307 wxDefaultPosition, wxDefaultSize, 0);
308 m_staticTextLayer->Enable(false);
309 bSizerBasicProperties->Add(m_staticTextLayer, 0, wxALL, 5);
310
311 // Basic properties grid layout
312 wxPanel* props_panel = new wxPanel(m_panelBasicProperties);
313 FormGrid* props_sizer = new FormGrid(this);
314 props_panel->SetSizer(props_sizer);
315 bSizerBasicProperties->Add(props_panel, 0, wxALL | wxEXPAND, 16);
316 int label_size = m_sizeMetric * 4;
317
318 // Name property
319 m_textName = new TextField(props_panel, _("Name"));
320
321 // Show name checkbox
322 wxStaticText* name_cb_label =
323 new wxStaticText(props_panel, wxID_ANY, _("Show waypoint name"));
324 m_checkBoxShowName =
325 new wxCheckBox(props_panel, wxID_ANY, "", wxDefaultPosition,
326 wxDefaultSize, wxALIGN_CENTER_VERTICAL);
327 m_checkBoxShowName->Bind(wxEVT_CHECKBOX,
328 &MarkInfoDlg::OnShowWaypointNameSelectBasic, this);
329 props_sizer->Add(name_cb_label, 0, wxALIGN_TOP);
330 props_sizer->Add(m_checkBoxShowName, 0, wxEXPAND);
331
332 // Icon property (with icon scaling)
333 int icon_size = m_sizeMetric * 2;
334 icon_size = wxMax(icon_size, (32 * g_MarkScaleFactorExp) + 4);
335 m_bcomboBoxIcon =
336 new OCPNIconCombo(props_panel, wxID_ANY, _("Combo!"), wxDefaultPosition,
337 wxDefaultSize, 0, NULL, wxCB_READONLY);
338 m_bcomboBoxIcon->SetPopupMaxHeight(::wxGetDisplaySize().y / 2);
339 m_bcomboBoxIcon->SetMinSize(wxSize(-1, icon_size));
340
341 wxStaticText* icon_label = new wxStaticText(props_panel, wxID_ANY, _("Icon"));
342 icon_label->SetMinSize(wxSize(label_size, -1));
343 props_sizer->Add(icon_label, 0, wxALIGN_CENTER_VERTICAL);
344 props_sizer->Add(m_bcomboBoxIcon, 0, wxEXPAND);
345
346 // Lat/lon properties
347 m_textLatitude = new TextField(props_panel, _("Latitude"));
348 m_textLongitude = new TextField(props_panel, _("Longitude"));
349 props_sizer->Fit(props_panel);
350
351 // Description box
352 wxStaticBox* desc_box =
353 new wxStaticBox(m_panelBasicProperties, wxID_ANY, _("Description"));
354 wxStaticBoxSizer* desc_sizer = new wxStaticBoxSizer(desc_box, wxHORIZONTAL);
355 bSizerBasicProperties->Add(desc_sizer, 1, wxALL | wxEXPAND, 8);
356 m_textDescription = new wxTextCtrl(m_panelBasicProperties, ID_DESCR_CTR_BASIC,
357 "", wxDefaultPosition, wxDefaultSize,
358 wxTE_MULTILINE | wxTE_READONLY);
359 m_textDescription->SetMinSize(wxSize(-1, 80));
360 desc_sizer->Add(m_textDescription, 1, wxEXPAND);
361
362 // Description expand button
363 m_buttonExtDescription =
364 new wxButton(m_panelBasicProperties, ID_BTN_DESC_BASIC, "...",
365 wxDefaultPosition, wxSize(GetCharHeight() * 15 / 10, -1), 0);
366 desc_sizer->Add(m_buttonExtDescription, 0, wxEXPAND);
367
368 // Links box
369 wxStaticBox* links_box =
370 new wxStaticBox(m_panelBasicProperties, wxID_ANY, _("Links"));
371 wxStaticBoxSizer* links_sizer = new wxStaticBoxSizer(links_box, wxHORIZONTAL);
372 bSizerBasicProperties->Add(links_sizer, 1, wxALL | wxEXPAND, 8);
373
374#ifndef __ANDROID__ // wxSimpleHtmlListBox is broken on Android....
375 m_htmlList = new wxSimpleHtmlListBox(m_panelBasicProperties, wxID_ANY,
376 wxDefaultPosition, wxDefaultSize, 0);
377 links_sizer->Add(m_htmlList, 1, wxEXPAND);
378#else
379
380 m_scrolledWindowLinks =
381 new wxScrolledWindow(m_panelBasicProperties, wxID_ANY, wxDefaultPosition,
382 wxSize(-1, 100), wxHSCROLL | wxVSCROLL);
383 m_scrolledWindowLinks->SetMinSize(wxSize(-1, 80));
384 m_scrolledWindowLinks->SetScrollRate(2, 2);
385 links_sizer->Add(m_scrolledWindowLinks, 1, wxEXPAND);
386
387 bSizerLinks = new wxBoxSizer(wxVERTICAL);
388 m_scrolledWindowLinks->SetSizer(bSizerLinks);
389
390 m_menuLink = new wxMenu();
391 wxMenuItem* m_menuItemDelete;
392 m_menuItemDelete = new wxMenuItem(m_menuLink, wxID_ANY, wxString(_("Delete")),
393 "", wxITEM_NORMAL);
394 m_menuLink->Append(m_menuItemDelete);
395
396 wxMenuItem* m_menuItemEdit;
397 m_menuItemEdit = new wxMenuItem(m_menuLink, wxID_ANY, wxString(_("Edit")), "",
398 wxITEM_NORMAL);
399 m_menuLink->Append(m_menuItemEdit);
400
401 wxMenuItem* m_menuItemAdd;
402 m_menuItemAdd = new wxMenuItem(m_menuLink, wxID_ANY, wxString(_("Add new")),
403 "", wxITEM_NORMAL);
404 m_menuLink->Append(m_menuItemAdd);
405
406 wxBoxSizer* bSizer9 = new wxBoxSizer(wxHORIZONTAL);
407
408 m_buttonAddLink =
409 new wxButton(m_panelBasicProperties, wxID_ANY, _("Add new"),
410 wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
411 bSizer9->Add(m_buttonAddLink, 0, wxALL, 5);
412
413 m_buttonAddLink->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
414 wxCommandEventHandler(MarkInfoDlg::OnAddLink), NULL,
415 this);
416
417 links_sizer->Add(bSizer9, 0, wxEXPAND, 5);
418
419#endif
420
421 m_panelDescription =
422 new wxPanel(m_notebookProperties, wxID_ANY, wxDefaultPosition,
423 wxDefaultSize, wxTAB_TRAVERSAL);
424 wxBoxSizer* bSizer15;
425 bSizer15 = new wxBoxSizer(wxVERTICAL);
426
427 m_textCtrlExtDescription =
428 new wxTextCtrl(m_panelDescription, ID_DESCR_CTR_DESC, "",
429 wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
430 bSizer15->Add(m_textCtrlExtDescription, 1, wxALL | wxEXPAND, 5);
431
432 m_panelDescription->SetSizer(bSizer15);
433 m_notebookProperties->AddPage(m_panelDescription, _("Description"), false);
434
437
438 m_panelExtendedProperties = new wxScrolledWindow(
439 m_notebookProperties, wxID_ANY, wxDefaultPosition, wxDefaultSize,
440 wxHSCROLL | wxVSCROLL | wxTAB_TRAVERSAL);
441#ifdef __ANDROID__
442 m_panelExtendedProperties->GetHandle()->setStyleSheet(
443 getAdjustedDialogStyleSheet());
444#endif
445
446 m_panelExtendedProperties->SetScrollRate(0, 2);
447
448 wxBoxSizer* fSizerExtProperties = new wxBoxSizer(wxVERTICAL);
449 m_panelExtendedProperties->SetSizer(fSizerExtProperties);
450 m_notebookProperties->AddPage(m_panelExtendedProperties, _("Extended"),
451 false);
452
453 sbSizerExtProperties = new wxStaticBoxSizer(
454 wxVERTICAL, m_panelExtendedProperties, _("Extended Properties"));
455 wxFlexGridSizer* gbSizerInnerExtProperties = new wxFlexGridSizer(3, 0, 0);
456 gbSizerInnerExtProperties->AddGrowableCol(2);
457 gbSizerInnerExtProperties->SetFlexibleDirection(wxBOTH);
458 gbSizerInnerExtProperties->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
459
460 m_checkBoxVisible = new wxCheckBox(sbSizerExtProperties->GetStaticBox(),
461 ID_CHECKBOX_VIS_EXT, "");
462 gbSizerInnerExtProperties->Add(m_checkBoxVisible);
463 wxStaticText* m_staticTextVisible = new wxStaticText(
464 sbSizerExtProperties->GetStaticBox(), wxID_ANY, _("Show on chart"));
465 gbSizerInnerExtProperties->Add(m_staticTextVisible);
466 gbSizerInnerExtProperties->Add(0, 0, 1, wxEXPAND, 0);
467
468 m_checkBoxScaMin = new wxCheckBox(sbSizerExtProperties->GetStaticBox(),
469 ID_CHECKBOX_SCAMIN_VIS, "");
470 gbSizerInnerExtProperties->Add(m_checkBoxScaMin, 0, wxALIGN_CENTRE_VERTICAL,
471 0);
472 m_staticTextScaMin = new wxStaticText(sbSizerExtProperties->GetStaticBox(),
473 wxID_ANY, _("Show at scale > 1 :"));
474 gbSizerInnerExtProperties->Add(m_staticTextScaMin, 0, wxALIGN_CENTRE_VERTICAL,
475 0);
476 m_textScaMin = new wxTextCtrl(sbSizerExtProperties->GetStaticBox(), wxID_ANY);
477 gbSizerInnerExtProperties->Add(m_textScaMin, 0, wxALL | wxEXPAND, 5);
478
479 m_checkBoxShowNameExt =
480 new wxCheckBox(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "");
481 m_checkBoxShowNameExt->Bind(wxEVT_CHECKBOX,
482 &MarkInfoDlg::OnShowWaypointNameSelectExt, this);
483 gbSizerInnerExtProperties->Add(m_checkBoxShowNameExt);
484 m_staticTextShowNameExt = new wxStaticText(
485 sbSizerExtProperties->GetStaticBox(), wxID_ANY, _("Show waypoint name"));
486
487 gbSizerInnerExtProperties->Add(m_staticTextShowNameExt);
488 gbSizerInnerExtProperties->Add(0, 0, 1, wxEXPAND, 0);
489
490 sbRangeRingsExtProperties = new wxStaticBoxSizer(
491 wxVERTICAL, sbSizerExtProperties->GetStaticBox(), _("Range rings"));
492 wxFlexGridSizer* gbRRExtProperties = new wxFlexGridSizer(4, 0, 0);
493 gbRRExtProperties->AddGrowableCol(0);
494 gbRRExtProperties->AddGrowableCol(1);
495 gbRRExtProperties->AddGrowableCol(3);
496 m_staticTextRR1 = new wxStaticText(sbSizerExtProperties->GetStaticBox(),
497 wxID_ANY, _("Number"));
498 gbRRExtProperties->Add(m_staticTextRR1, 0, wxLEFT, 5);
499 m_staticTextRR2 = new wxStaticText(sbSizerExtProperties->GetStaticBox(),
500 wxID_ANY, _("Distance"));
501 gbRRExtProperties->Add(m_staticTextRR2, 0, wxLEFT, 5);
502 gbRRExtProperties->Add(0, 0, 1, wxEXPAND, 5); // a spacer
503 m_staticTextRR4 = new wxStaticText(sbSizerExtProperties->GetStaticBox(),
504 wxID_ANY, _("Color"));
505 gbRRExtProperties->Add(m_staticTextRR4, 0, wxLEFT, 5);
506
507 wxString rrAlt[] = {_("None"), "1", "2", "3", "4", "5",
508 "6", "7", "8", "9", "10"};
509 m_ChoiceWaypointRangeRingsNumber =
510 new wxChoice(sbSizerExtProperties->GetStaticBox(), ID_WPT_RANGERINGS_NO,
511 wxDefaultPosition, wxDefaultSize, 11, rrAlt);
512
513 gbRRExtProperties->Add(m_ChoiceWaypointRangeRingsNumber, 0, wxALL | wxEXPAND,
514 5);
515 m_textWaypointRangeRingsStep =
516 new wxTextCtrl(sbSizerExtProperties->GetStaticBox(), wxID_ANY, _("0.05"),
517 wxDefaultPosition, wxDefaultSize, 0);
518 gbRRExtProperties->Add(m_textWaypointRangeRingsStep, 0, wxALL | wxEXPAND, 5);
519
520 wxString pDistUnitsStrings[] = {_("NMi"), _("km")};
521 m_RangeRingUnits =
522 new wxChoice(sbSizerExtProperties->GetStaticBox(), wxID_ANY,
523 wxDefaultPosition, wxDefaultSize, 2, pDistUnitsStrings);
524 gbRRExtProperties->Add(m_RangeRingUnits, 0, wxALIGN_CENTRE_VERTICAL, 0);
525
526 m_PickColor = new wxColourPickerCtrl(sbSizerExtProperties->GetStaticBox(),
527 wxID_ANY, wxColour(0, 0, 0),
528 wxDefaultPosition, wxDefaultSize, 0);
529 gbRRExtProperties->Add(m_PickColor, 0, wxALL | wxEXPAND, 5);
530 sbRangeRingsExtProperties->Add(
531 gbRRExtProperties, 1,
532 wxLEFT | wxTOP | wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
533
534 sbSizerExtProperties->GetStaticBox()->Layout();
535
536 wxFlexGridSizer* gbSizerInnerExtProperties2 = new wxFlexGridSizer(2, 0, 0);
537 gbSizerInnerExtProperties2->AddGrowableCol(1);
538
539 m_staticTextGuid =
540 new wxStaticText(sbSizerExtProperties->GetStaticBox(), wxID_ANY,
541 _("GUID"), wxDefaultPosition, wxDefaultSize, 0);
542 gbSizerInnerExtProperties2->Add(m_staticTextGuid, 0, wxALIGN_CENTRE_VERTICAL,
543 0);
544 m_textCtrlGuid =
545 new wxTextCtrl(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "",
546 wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
547 m_textCtrlGuid->SetEditable(false);
548 gbSizerInnerExtProperties2->Add(m_textCtrlGuid, 0, wxALL | wxEXPAND, 5);
549
550 wxFlexGridSizer* gbSizerInnerExtProperties1 = new wxFlexGridSizer(3, 0, 0);
551 gbSizerInnerExtProperties1->AddGrowableCol(1);
552
553 m_staticTextTideStation =
554 new wxStaticText(sbSizerExtProperties->GetStaticBox(), wxID_ANY,
555 _("Tide Station"), wxDefaultPosition, wxDefaultSize, 0);
556 gbSizerInnerExtProperties1->Add(m_staticTextTideStation, 0,
557 wxALIGN_CENTRE_VERTICAL, 5);
558
559#ifdef __ANDROID__
560 m_choiceTideChoices.Add(" ");
561 m_comboBoxTideStation =
562 new wxChoice(sbSizerExtProperties->GetStaticBox(), wxID_ANY,
563 wxDefaultPosition, wxDefaultSize, m_choiceTideChoices);
564
565 gbSizerInnerExtProperties1->Add(
566 m_comboBoxTideStation, 0, wxALL | wxEXPAND | wxALIGN_CENTRE_VERTICAL, 5);
567
568#else
569 m_comboBoxTideStation =
570 new wxComboBox(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "",
571 wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
572 gbSizerInnerExtProperties1->Add(
573 m_comboBoxTideStation, 0, wxALL | wxEXPAND | wxALIGN_CENTRE_VERTICAL, 5);
574#endif
575 m_comboBoxTideStation->SetToolTip(
576 _("Associate this waypoint with a tide station to quickly access tide "
577 "predictions. Select from nearby stations or leave empty for no "
578 "association."));
579
580 m_buttonShowTides = new wxBitmapButton(
581 sbSizerExtProperties->GetStaticBox(), ID_BTN_SHOW_TIDES, m_bmTide,
582 wxDefaultPosition, m_bmTide.GetSize(), 0);
583 gbSizerInnerExtProperties1->Add(m_buttonShowTides, 0,
584 wxALL | wxALIGN_CENTRE_VERTICAL, 5);
585
586 m_staticTextArrivalRadius = new wxStaticText(
587 sbSizerExtProperties->GetStaticBox(), wxID_ANY, _("Arrival Radius"));
588 gbSizerInnerExtProperties1->Add(m_staticTextArrivalRadius, 0,
589 wxALIGN_CENTRE_VERTICAL, 0);
590 m_textArrivalRadius =
591 new wxTextCtrl(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "",
592 wxDefaultPosition, wxDefaultSize, 0);
593 m_textArrivalRadius->SetToolTip(
594 _("Distance from the waypoint at which OpenCPN will consider the "
595 "waypoint reached. Used for automatic waypoint advancement during "
596 "active navigation."));
597 gbSizerInnerExtProperties1->Add(m_textArrivalRadius, 0, wxALL | wxEXPAND, 5);
598 m_staticTextArrivalUnits =
599 new wxStaticText(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "",
600 wxDefaultPosition, wxDefaultSize, 0);
601 gbSizerInnerExtProperties1->Add(m_staticTextArrivalUnits, 0,
602 wxALIGN_CENTRE_VERTICAL, 0);
603
604 m_staticTextPlSpeed =
605 new wxStaticText(sbSizerExtProperties->GetStaticBox(), wxID_ANY,
606 _("Planned Speed"), wxDefaultPosition, wxDefaultSize, 0);
607 gbSizerInnerExtProperties1->Add(m_staticTextPlSpeed, 0,
608 wxALIGN_CENTRE_VERTICAL, 0);
610 new wxTextCtrl(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "",
611 wxDefaultPosition, wxDefaultSize, 0);
612 m_textCtrlPlSpeed->SetToolTip(_(
613 "Enter the planned vessel speed for the leg FOLLOWING this waypoint. "
614 "This speed is used when traveling FROM this waypoint TO the next "
615 "waypoint in the route. The value is used to calculate estimated time "
616 "of arrival at the next waypoint based on the ETD from this waypoint.\n\n"
617 "If left blank, the route's default speed will be used for this leg. "
618 "Individual waypoint speeds override the route-level speed setting."));
619 gbSizerInnerExtProperties1->Add(m_textCtrlPlSpeed, 0, wxALL | wxEXPAND, 5);
620 m_staticTextPlSpeedUnits =
621 new wxStaticText(sbSizerExtProperties->GetStaticBox(), wxID_ANY,
622 getUsrSpeedUnit(), wxDefaultPosition, wxDefaultSize, 0);
623 gbSizerInnerExtProperties1->Add(m_staticTextPlSpeedUnits, 0,
624 wxALIGN_CENTRE_VERTICAL, 0);
625
626 // The value of m_staticTextEtd is updated in UpdateProperties() based on
627 // the date/time format specified in the "Options" dialog.
628 m_staticTextEtd = new wxStaticText(sbSizerExtProperties->GetStaticBox(),
629 wxID_ANY, _("ETD"));
630 gbSizerInnerExtProperties1->Add(m_staticTextEtd, 0, wxALIGN_CENTRE_VERTICAL,
631 0);
632 wxBoxSizer* bsTimestamp = new wxBoxSizer(wxHORIZONTAL);
634 new wxCheckBox(sbSizerExtProperties->GetStaticBox(), wxID_ANY, "");
635 m_cbEtdPresent->SetToolTip(
636 _("Enable to manually set a planned departure time (ETD) for this "
637 "waypoint.\n"
638 "When checked, the specified date and time will be used instead of the "
639 "automatically calculated ETD. This affects ETA calculations for "
640 "subsequent waypoints in the route."));
641 bsTimestamp->Add(m_cbEtdPresent, 0, wxALL | wxEXPAND, 5);
642 m_EtdDatePickerCtrl = new wxDatePickerCtrl(
643 sbSizerExtProperties->GetStaticBox(), ID_ETA_DATEPICKERCTRL,
644 wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DEFAULT,
645 wxDefaultValidator);
646 m_EtdDatePickerCtrl->SetToolTip(_(
647 "Select the planned departure date (ETD) for this waypoint.\nUsed "
648 "together with the time control to calculate arrival times at subsequent "
649 "waypoints.\nETD information is only used for route planning "
650 "and does not affect navigation."));
651 bsTimestamp->Add(m_EtdDatePickerCtrl, 0, wxALL | wxEXPAND, 5);
652
653#ifdef __WXGTK__
655 new TimeCtrl(sbSizerExtProperties->GetStaticBox(), ID_ETA_TIMEPICKERCTRL,
656 wxDefaultDateTime, wxDefaultPosition, wxDefaultSize);
657#else
658 m_EtdTimePickerCtrl = new wxTimePickerCtrl(
659 sbSizerExtProperties->GetStaticBox(), ID_ETA_TIMEPICKERCTRL,
660 wxDefaultDateTime, wxDefaultPosition, wxDefaultSize, wxDP_DEFAULT,
661 wxDefaultValidator);
662#endif
663
664 bsTimestamp->Add(m_EtdTimePickerCtrl, 0, wxALL | wxEXPAND, 5);
665 gbSizerInnerExtProperties1->Add(bsTimestamp, 0, wxEXPAND, 0);
666 sbSizerExtProperties->Add(gbSizerInnerExtProperties, 0, wxALL | wxEXPAND, 5);
667 sbSizerExtProperties->Add(sbRangeRingsExtProperties, 0, wxALL | wxEXPAND, 5);
668 sbSizerExtProperties->Add(gbSizerInnerExtProperties2, 0, wxALL | wxEXPAND, 5);
669 sbSizerExtProperties->Add(gbSizerInnerExtProperties1, 0, wxALL | wxEXPAND, 5);
670
671 fSizerExtProperties->Add(sbSizerExtProperties, 1, wxALL | wxEXPAND);
672
673 //-----------------
674 bSizer1->Add(m_notebookProperties, 1, wxEXPAND);
675
676 wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
677 bSizer1->Add(btnSizer, 0, wxEXPAND, 0);
678
679 DefaultsBtn =
680 new wxBitmapButton(this, ID_DEFAULT, _img_MUI_settings_svg,
681 wxDefaultPosition, _img_MUI_settings_svg.GetSize(), 0);
682 btnSizer->Add(DefaultsBtn, 0, wxALL | wxALIGN_LEFT | wxALIGN_BOTTOM, 5);
683 btnSizer->Add(0, 0, 1, wxEXPAND); // spacer
684
685 m_sdbSizerButtons = new wxStdDialogButtonSizer();
686 m_buttonOkay = new wxButton(this, wxID_OK);
687 m_sdbSizerButtons->AddButton(m_buttonOkay);
688 m_sdbSizerButtons->AddButton(new wxButton(this, wxID_CANCEL, _("Cancel")));
689 m_sdbSizerButtons->Realize();
690 btnSizer->Add(m_sdbSizerButtons, 0, wxALL, 5);
691
692 // SetMinSize(wxSize(-1, 600));
693
694 // Connect Events
695 m_textLatitude->Connect(
696 wxEVT_CONTEXT_MENU,
697 wxCommandEventHandler(MarkInfoDlg::OnRightClickLatLon), NULL, this);
698 m_textLongitude->Connect(
699 wxEVT_CONTEXT_MENU,
700 wxCommandEventHandler(MarkInfoDlg::OnRightClickLatLon), NULL, this);
701#ifndef __ANDROID__ // wxSimpleHtmlListBox is broken on Android....
702 m_htmlList->Connect(wxEVT_RIGHT_DOWN,
703 wxMouseEventHandler(MarkInfoDlg::m_htmlListContextMenu),
704 NULL, this);
705#else
706#endif
707 m_notebookProperties->Connect(
708 wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
709 wxNotebookEventHandler(MarkInfoDlg::OnNotebookPageChanged), NULL, this);
710 // m_EtdTimePickerCtrl->Connect( wxEVT_TIME_CHANGED, wxDateEventHandler(
711 // MarkInfoDlg::OnTimeChanged ), NULL, this ); m_EtdDatePickerCtrl->Connect(
712 // wxEVT_DATE_CHANGED, wxDateEventHandler( MarkInfoDlg::OnTimeChanged ), NULL,
713 // this );
714 m_comboBoxTideStation->Connect(
715 wxEVT_COMMAND_COMBOBOX_SELECTED,
716 wxCommandEventHandler(MarkInfoDlg::OnTideStationCombobox), NULL, this);
717}
718
719void MarkInfoDlg::OnClose(wxCloseEvent& event) {
720 Hide();
721 event.Veto();
722 if (m_pRoutePoint) m_pRoutePoint->m_bRPIsBeingEdited = false;
723}
724
725#define TIDESTATION_BATCH_SIZE 10
726
727void MarkInfoDlg::OnTideStationCombobox(wxCommandEvent& event) {
728 int count = m_comboBoxTideStation->GetCount();
729 int sel = m_comboBoxTideStation->GetSelection();
730 if (sel == count - 1) {
731 wxString n;
732 int i = 0;
733 for (auto ts : m_tss) {
734 if (i == count + TIDESTATION_BATCH_SIZE) {
735 break;
736 }
737 if (i > count) {
738 n = wxString::FromUTF8(ts.second->IDX_station_name);
739 m_comboBoxTideStation->Append(n);
740 }
741 i++;
742 }
743 }
744}
745
746void MarkInfoDlg::OnNotebookPageChanged(wxNotebookEvent& event) {
747 if (event.GetSelection() == EXTENDED_PROP_PAGE) {
748 if (m_lasttspos.IsSameAs(m_textLatitude->GetValue() +
749 m_textLongitude->GetValue())) {
750 return;
751 }
752 m_lasttspos = m_textLatitude->GetValue() + m_textLongitude->GetValue();
753 double lat = fromDMM(m_textLatitude->GetValue());
754 double lon = fromDMM(m_textLongitude->GetValue());
755 m_tss = ptcmgr->GetStationsForLL(lat, lon);
756 wxString s = m_comboBoxTideStation->GetStringSelection();
757 wxString n;
758 int i = 0;
759 m_comboBoxTideStation->Clear();
760 m_comboBoxTideStation->Append("");
761 for (auto ts : m_tss) {
762 if (i == TIDESTATION_BATCH_SIZE) {
763 break;
764 }
765 i++;
766 n = wxString::FromUTF8(ts.second->IDX_station_name);
767 m_comboBoxTideStation->Append(n);
768 if (s == n) {
769 m_comboBoxTideStation->SetSelection(i);
770 }
771 }
772 if (m_comboBoxTideStation->GetStringSelection() != s) {
773 m_comboBoxTideStation->Insert(s, 1);
774 m_comboBoxTideStation->SetSelection(1);
775 }
776 }
777}
778
779void MarkInfoDlg::RecalculateSize() {
780#ifdef __ANDROID__
781
782 Layout();
783
784 wxSize dsize = GetParent()->GetClientSize();
785
786 wxSize esize;
787
788 esize.x = GetCharHeight() * 20;
789 esize.y = GetCharHeight() * 40;
790 // qDebug() << "esizeA" << esize.x << esize.y;
791
792 esize.y = wxMin(esize.y, dsize.y - (2 * GetCharHeight()));
793 esize.x = wxMin(esize.x, dsize.x - (1 * GetCharHeight()));
794 SetSize(wxSize(esize.x, esize.y));
795 // qDebug() << "esize" << esize.x << esize.y;
796
797 wxSize fsize = GetSize();
798 fsize.y = wxMin(fsize.y, dsize.y - (2 * GetCharHeight()));
799 fsize.x = wxMin(fsize.x, dsize.x - (1 * GetCharHeight()));
800 // qDebug() << "fsize" << fsize.x << fsize.y;
801
802 // And finally, not too tall...
803 fsize.y = wxMin(fsize.y, (25 * GetCharHeight()));
804
805 SetSize(wxSize(-1, fsize.y));
806
807 m_defaultClientSize = GetClientSize();
808 Center();
809#else
810 wxSize dsize = GetParent()->GetClientSize();
811 SetSize(-1, wxMax(GetSize().y, dsize.y / 1.5));
812#endif
813}
814
815MarkInfoDlg::~MarkInfoDlg() {
816 // Disconnect Events
817 m_textLatitude->Disconnect(
818 wxEVT_CONTEXT_MENU,
819 wxCommandEventHandler(MarkInfoDlg::OnRightClickLatLon), NULL, this);
820 m_textLongitude->Disconnect(
821 wxEVT_CONTEXT_MENU,
822 wxCommandEventHandler(MarkInfoDlg::OnRightClickLatLon), NULL, this);
823#ifndef __ANDROID__ // wxSimpleHtmlListBox is broken on Android....
824 m_htmlList->Disconnect(
825 wxEVT_RIGHT_DOWN, wxMouseEventHandler(MarkInfoDlg::m_htmlListContextMenu),
826 NULL, this);
827#else
828#endif
829
830 m_notebookProperties->Disconnect(
831 wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
832 wxNotebookEventHandler(MarkInfoDlg::OnNotebookPageChanged), NULL, this);
833 m_EtdTimePickerCtrl->Disconnect(
834 wxEVT_TIME_CHANGED, wxDateEventHandler(MarkInfoDlg::OnTimeChanged), NULL,
835 this);
836 m_EtdDatePickerCtrl->Disconnect(
837 wxEVT_DATE_CHANGED, wxDateEventHandler(MarkInfoDlg::OnTimeChanged), NULL,
838 this);
839
840#ifdef __ANDROID__
841 androidEnableBackButton(true);
842#endif
843}
844
845void MarkInfoDlg::InitialFocus() {
846 m_textName->SetFocus();
847 m_textName->SetInsertionPointEnd();
848}
849
850void MarkInfoDlg::SetColorScheme(ColorScheme cs) { DimeControl(this); }
851
852void MarkInfoDlg::ClearData() {
853 m_pRoutePoint = NULL;
854 UpdateProperties();
855}
856
857void MarkInfoDlg::SetRoutePoint(RoutePoint* pRP) {
858 m_pRoutePoint = pRP;
859 if (m_pRoutePoint) {
860 m_lat_save = m_pRoutePoint->m_lat;
861 m_lon_save = m_pRoutePoint->m_lon;
862 m_IconName_save = m_pRoutePoint->GetIconName();
863 m_bShowName_save = m_pRoutePoint->m_bShowName;
864 m_bIsVisible_save = m_pRoutePoint->m_bIsVisible;
865 m_Name_save = m_pRoutePoint->GetName();
866 m_Description_save = m_pRoutePoint->m_MarkDescription;
867 m_bUseScaMin_save = m_pRoutePoint->GetUseSca();
868 m_iScaminVal_save = m_pRoutePoint->GetScaMin();
869
870 if (m_pMyLinkList) delete m_pMyLinkList;
871 m_pMyLinkList = new HyperlinkList();
872 for (Hyperlink* link : *m_pRoutePoint->m_HyperlinkList) {
873 Hyperlink* h = new Hyperlink();
874 h->DescrText = link->DescrText;
875 h->Link = link->Link;
876 h->LType = link->LType;
877
878 m_pMyLinkList->push_back(h);
879 }
880 }
881}
882
883void MarkInfoDlg::UpdateHtmlList() {
884#ifndef __ANDROID__ // wxSimpleHtmlListBox is broken on Android....
885 GetSimpleBox()->Clear();
886 int NbrOfLinks = m_pRoutePoint->m_HyperlinkList->size();
887
888 if (NbrOfLinks > 0) {
889 auto& list = m_pRoutePoint->m_HyperlinkList;
890 for (auto it = list->begin(); it != list->end(); ++it) {
891 Hyperlink* link = *it;
892 wxString s =
893 wxString::Format("<a href='%s'>%s</a>", link->Link, link->DescrText);
894 GetSimpleBox()->AppendString(s);
895 }
896 }
897#else
898 // Clear the list
899 wxWindowList kids = m_scrolledWindowLinks->GetChildren();
900 for (unsigned int i = 0; i < kids.GetCount(); i++) {
901 wxWindowListNode* node = kids.Item(i);
902 wxWindow* win = node->GetData();
903
904 auto link_win = dynamic_cast<wxHyperlinkCtrl*>(win);
905 if (link_win) {
906 link_win->Disconnect(
907 wxEVT_COMMAND_HYPERLINK,
908 wxHyperlinkEventHandler(MarkInfoDlg::OnHyperLinkClick));
909 link_win->Disconnect(
910 wxEVT_RIGHT_DOWN,
911 wxMouseEventHandler(MarkInfoDlg::m_htmlListContextMenu));
912 win->Destroy();
913 }
914 }
915
916 for (Hyperlink* link : *m_pRoutePoint->m_HyperlinkList) {
917 wxString Link = link->Link;
918 wxString Descr = link->DescrText;
919
920 wxHyperlinkCtrl* ctrl = new wxHyperlinkCtrl(
921 m_scrolledWindowLinks, wxID_ANY, Descr, Link, wxDefaultPosition,
922 wxDefaultSize, wxNO_BORDER | wxHL_CONTEXTMENU | wxHL_ALIGN_LEFT);
923 ctrl->Connect(wxEVT_COMMAND_HYPERLINK,
924 wxHyperlinkEventHandler(MarkInfoDlg::OnHyperLinkClick), NULL,
925 this);
926 if (!m_pRoutePoint->m_bIsInLayer)
927 ctrl->Connect(wxEVT_RIGHT_DOWN,
928 wxMouseEventHandler(MarkInfoDlg::m_htmlListContextMenu),
929 NULL, this);
930
931 bSizerLinks->Add(ctrl, 1, wxALL | wxEXPAND, 5);
932 }
933
934 // Integrate all of the rebuilt hyperlink controls
935 m_scrolledWindowLinks->Layout();
936#endif
937}
938
939void MarkInfoDlg::OnHyperLinkClick(wxHyperlinkEvent& event) {
940 wxString url = event.GetURL();
941 url.Replace(" ", "%20");
942 if (g_Platform) g_Platform->platformLaunchDefaultBrowser(url);
943}
944
945void MarkInfoDlg::OnHtmlLinkClicked(wxHtmlLinkEvent& event) {
946 // Windows has trouble handling local file URLs with embedded anchor
947 // points, e.g file://testfile.html#point1 The trouble is with the
948 // wxLaunchDefaultBrowser with verb "open" Workaround is to probe the
949 // registry to get the default browser, and open directly
950 //
951 // But, we will do this only if the URL contains the anchor point
952 // character '#' What a hack......
953
954#ifdef __WXMSW__
955 wxString cc = event.GetLinkInfo().GetHref().c_str();
956 if (cc.Find("#") != wxNOT_FOUND) {
957 wxRegKey RegKey(wxString("HKEY_CLASSES_ROOT\\HTTP\\shell\\open\\command"));
958 if (RegKey.Exists()) {
959 wxString command_line;
960 RegKey.QueryValue(wxString(""), command_line);
961
962 // Remove "
963 command_line.Replace(wxString("\""), wxString(""));
964
965 // Strip arguments
966 int l = command_line.Find(".exe");
967 if (wxNOT_FOUND == l) l = command_line.Find(".EXE");
968
969 if (wxNOT_FOUND != l) {
970 wxString cl = command_line.Mid(0, l + 4);
971 cl += " ";
972 cc.Prepend("\"");
973 cc.Append("\"");
974 cl += cc;
975 wxExecute(cl); // Async, so Fire and Forget...
976 }
977 }
978 } else {
979 wxString url = event.GetLinkInfo().GetHref().c_str();
980 url.Replace(" ", "%20");
981 ::wxLaunchDefaultBrowser(url);
982 event.Skip();
983 }
984#else
985 wxString url = event.GetLinkInfo().GetHref().c_str();
986 url.Replace(" ", "%20");
987 if (g_Platform) g_Platform->platformLaunchDefaultBrowser(url);
988
989 event.Skip();
990#endif
991}
992
993void MarkInfoDlg::OnLayoutResize(wxCommandEvent& event) {
994 m_panelBasicProperties->Layout();
995 this->Layout();
996}
997
998void MarkInfoDlg::OnDescChangedExt(wxCommandEvent& event) {
999 if (m_panelDescription->IsShownOnScreen()) {
1000 m_textDescription->ChangeValue(m_textCtrlExtDescription->GetValue());
1001 }
1002 event.Skip();
1003}
1004void MarkInfoDlg::OnDescChangedBasic(wxCommandEvent& event) {
1005 if (m_panelBasicProperties->IsShownOnScreen()) {
1006 m_textCtrlExtDescription->ChangeValue(m_textDescription->GetValue());
1007 }
1008 event.Skip();
1009}
1010
1011void MarkInfoDlg::OnExtDescriptionClick(wxCommandEvent& event) {
1012 long pos = m_textDescription->GetInsertionPoint();
1013 m_notebookProperties->SetSelection(1);
1014 m_textCtrlExtDescription->SetInsertionPoint(pos);
1015 event.Skip();
1016}
1017
1018void MarkInfoDlg::OnShowWaypointNameSelectBasic(wxCommandEvent& event) {
1019 m_checkBoxShowNameExt->SetValue(m_checkBoxShowName->GetValue());
1020 event.Skip();
1021}
1022void MarkInfoDlg::OnShowWaypointNameSelectExt(wxCommandEvent& event) {
1023 m_checkBoxShowName->SetValue(m_checkBoxShowNameExt->GetValue());
1024 event.Skip();
1025}
1026
1027void MarkInfoDlg::OnWptRangeRingsNoChange(wxCommandEvent& event) {
1028 if (!m_pRoutePoint->m_bIsInLayer) {
1029 m_textWaypointRangeRingsStep->Enable(
1030 (bool)(m_ChoiceWaypointRangeRingsNumber->GetSelection() != 0));
1031 m_PickColor->Enable(
1032 (bool)(m_ChoiceWaypointRangeRingsNumber->GetSelection() != 0));
1033 }
1034}
1035
1036void MarkInfoDlg::OnSelectScaMinExt(wxCommandEvent& event) {
1037 if (!m_pRoutePoint->m_bIsInLayer) {
1038 m_textScaMin->Enable(m_checkBoxScaMin->GetValue());
1039 }
1040}
1041
1042void MarkInfoDlg::OnPositionCtlUpdated(wxCommandEvent& event) {
1043 // Fetch the control values, convert to degrees
1044 double lat = fromDMM(m_textLatitude->GetValue());
1045 double lon = fromDMM(m_textLongitude->GetValue());
1046 if (!m_pRoutePoint->m_bIsInLayer) {
1047 m_pRoutePoint->SetPosition(lat, lon);
1048 pSelect->ModifySelectablePoint(lat, lon, (void*)m_pRoutePoint,
1049 SELTYPE_ROUTEPOINT);
1050 }
1051 // Update the mark position dynamically
1052 gFrame->RefreshAllCanvas();
1053}
1054
1055void MarkInfoDlg::m_htmlListContextMenu(wxMouseEvent& event) {
1056#ifndef __ANDROID__
1057 // SimpleHtmlList->HitTest doesn't seem to work under msWin, so we use a
1058 // custom made version
1059 wxPoint pos = event.GetPosition();
1060 i_htmlList_item = -1;
1061 for (int i = 0; i < (int)GetSimpleBox()->GetCount(); i++) {
1062 wxRect rect = GetSimpleBox()->GetItemRect(i);
1063 if (rect.Contains(pos)) {
1064 i_htmlList_item = i;
1065 break;
1066 }
1067 }
1068
1069 wxMenu* popup = new wxMenu();
1070 if ((GetSimpleBox()->GetCount()) > 0 && (i_htmlList_item > -1) &&
1071 (i_htmlList_item < (int)GetSimpleBox()->GetCount())) {
1072 popup->Append(ID_RCLK_MENU_DELETE_LINK, _("Delete"));
1073 popup->Append(ID_RCLK_MENU_EDIT_LINK, _("Edit"));
1074 }
1075 popup->Append(ID_RCLK_MENU_ADD_LINK, _("Add New"));
1076
1077 m_contextObject = event.GetEventObject();
1078 popup->Connect(
1079 wxEVT_COMMAND_MENU_SELECTED,
1080 wxCommandEventHandler(MarkInfoDlg::On_html_link_popupmenu_Click), NULL,
1081 this);
1082 PopupMenu(popup);
1083 delete popup;
1084#else
1085
1086 m_pEditedLink = dynamic_cast<wxHyperlinkCtrl*>(event.GetEventObject());
1087
1088 if (m_pEditedLink) {
1089 wxString url = m_pEditedLink->GetURL();
1090 wxString label = m_pEditedLink->GetLabel();
1091 i_htmlList_item = -1;
1092 HyperlinkList* hyperlinklist = m_pRoutePoint->m_HyperlinkList;
1093 int i = 0;
1094 for (Hyperlink* link : *hyperlinklist) {
1095 if (link->DescrText == label) {
1096 i_htmlList_item = i;
1097 break;
1098 }
1099 i++;
1100 }
1101
1102 wxFont sFont = GetOCPNGUIScaledFont(_("Menu"));
1103
1104 wxMenu* popup = new wxMenu();
1105 {
1106 wxMenuItem* menuItemDelete =
1107 new wxMenuItem(popup, ID_RCLK_MENU_DELETE_LINK, wxString(_("Delete")),
1108 "", wxITEM_NORMAL);
1109#ifdef __WXQT__
1110 menuItemDelete->SetFont(sFont);
1111#endif
1112 popup->Append(menuItemDelete);
1113
1114 wxMenuItem* menuItemEdit =
1115 new wxMenuItem(popup, ID_RCLK_MENU_EDIT_LINK, wxString(_("Edit")), "",
1116 wxITEM_NORMAL);
1117#ifdef __WXQT__
1118 menuItemEdit->SetFont(sFont);
1119#endif
1120 popup->Append(menuItemEdit);
1121 }
1122
1123 wxMenuItem* menuItemAdd =
1124 new wxMenuItem(popup, ID_RCLK_MENU_ADD_LINK, wxString(_("Add New")), "",
1125 wxITEM_NORMAL);
1126#ifdef __WXQT__
1127 menuItemAdd->SetFont(sFont);
1128#endif
1129 popup->Append(menuItemAdd);
1130
1131 m_contextObject = event.GetEventObject();
1132 popup->Connect(
1133 wxEVT_COMMAND_MENU_SELECTED,
1134 wxCommandEventHandler(MarkInfoDlg::On_html_link_popupmenu_Click), NULL,
1135 this);
1136 wxPoint p = m_scrolledWindowLinks->GetPosition();
1137 p.x += m_scrolledWindowLinks->GetSize().x / 2;
1138 PopupMenu(popup, p);
1139 delete popup;
1140
1141 // m_scrolledWindowLinks->PopupMenu( m_menuLink,
1142 // m_pEditedLink->GetPosition().x /*+ event.GetPosition().x*/,
1143 // m_pEditedLink->GetPosition().y /*+ event.GetPosition().y*/ );
1144 }
1145/*
1146 wxPoint pos = event.GetPosition();
1147 i_htmlList_item = -1;
1148 for( int i=0; i < (int)GetSimpleBox()->GetCount(); i++ )
1149 {
1150 wxRect rect = GetSimpleBox()->GetItemRect( i );
1151 if( rect.Contains( pos) ){
1152 i_htmlList_item = i;
1153 break;
1154 }
1155 }
1156
1157 */
1158#endif
1159}
1160
1161void MarkInfoDlg::OnAddLink(wxCommandEvent& event) {
1162 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED);
1163 evt.SetId(ID_RCLK_MENU_ADD_LINK);
1164
1165 On_html_link_popupmenu_Click(evt);
1166}
1167
1168void MarkInfoDlg::On_html_link_popupmenu_Click(wxCommandEvent& event) {
1169 switch (event.GetId()) {
1170 case ID_RCLK_MENU_DELETE_LINK: {
1171 auto it = m_pRoutePoint->m_HyperlinkList->begin() + i_htmlList_item;
1172 m_pRoutePoint->m_HyperlinkList->erase(it);
1173 UpdateHtmlList();
1174 break;
1175 }
1176 case ID_RCLK_MENU_EDIT_LINK: {
1177 auto it = m_pRoutePoint->m_HyperlinkList->begin() + i_htmlList_item;
1178 Hyperlink* link = *it;
1179 LinkPropImpl* LinkPropDlg = new LinkPropImpl(this);
1180 LinkPropDlg->m_textCtrlLinkDescription->SetValue(link->DescrText);
1181 LinkPropDlg->m_textCtrlLinkUrl->SetValue(link->Link);
1182 DimeControl(LinkPropDlg);
1183 LinkPropDlg->ShowWindowModalThenDo([this, LinkPropDlg,
1184 link](int retcode) {
1185 if (retcode == wxID_OK) {
1186 link->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1187 auto it = m_pRoutePoint->m_HyperlinkList->begin() + i_htmlList_item;
1188 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1189 *it = link;
1190 UpdateHtmlList();
1191 }
1192 });
1193 break;
1194 }
1195 case ID_RCLK_MENU_ADD_LINK: {
1196 LinkPropImpl* LinkPropDlg = new LinkPropImpl(this);
1197 LinkPropDlg->m_textCtrlLinkDescription->SetValue("");
1198 LinkPropDlg->m_textCtrlLinkUrl->SetValue("");
1199 DimeControl(LinkPropDlg);
1200 LinkPropDlg->ShowWindowModalThenDo([this, LinkPropDlg](int retcode) {
1201 if (retcode == wxID_OK) {
1202 Hyperlink* link = new Hyperlink;
1203 link->DescrText = LinkPropDlg->m_textCtrlLinkDescription->GetValue();
1204 link->Link = LinkPropDlg->m_textCtrlLinkUrl->GetValue();
1205 // Check if decent
1206 if (link->DescrText == "") {
1207 link->DescrText = link->Link;
1208 }
1209 if (link->Link == "") {
1210 delete link;
1211 } else {
1212 m_pRoutePoint->m_HyperlinkList->push_back(link);
1213 }
1214 UpdateHtmlList();
1215 }
1216 });
1217 break;
1218 }
1219 }
1220 event.Skip();
1221}
1222
1223void MarkInfoDlg::OnRightClickLatLon(wxCommandEvent& event) {
1224 wxMenu* popup = new wxMenu();
1225 popup->Append(ID_RCLK_MENU_COPY, _("Copy"));
1226 popup->Append(ID_RCLK_MENU_COPY_LL, _("Copy lat/long"));
1227 popup->Append(ID_RCLK_MENU_PASTE, _("Paste"));
1228 popup->Append(ID_RCLK_MENU_PASTE_LL, _("Paste lat/long"));
1229 m_contextObject = event.GetEventObject();
1230 popup->Connect(wxEVT_COMMAND_MENU_SELECTED,
1231 wxCommandEventHandler(MarkInfoDlg::OnCopyPasteLatLon), NULL,
1232 this);
1233
1234 PopupMenu(popup);
1235 delete popup;
1236}
1237
1238void MarkInfoDlg::OnCopyPasteLatLon(wxCommandEvent& event) {
1239 // Fetch the control values, convert to degrees
1240 double lat = fromDMM(m_textLatitude->GetValue());
1241 double lon = fromDMM(m_textLongitude->GetValue());
1242
1243 wxString result;
1244
1245 switch (event.GetId()) {
1246 case ID_RCLK_MENU_PASTE: {
1247 if (wxTheClipboard->Open()) {
1248 wxTextDataObject data;
1249 wxTheClipboard->GetData(data);
1250 result = data.GetText();
1251 ((wxTextCtrl*)m_contextObject)->SetValue(result);
1252 wxTheClipboard->Close();
1253 }
1254 return;
1255 }
1256 case ID_RCLK_MENU_PASTE_LL: {
1257 if (wxTheClipboard->Open()) {
1258 wxTextDataObject data;
1259 wxTheClipboard->GetData(data);
1260 result = data.GetText();
1261
1262 PositionParser pparse(result);
1263
1264 if (pparse.IsOk()) {
1265 m_textLatitude->SetValue(pparse.GetLatitudeString());
1266 m_textLongitude->SetValue(pparse.GetLongitudeString());
1267 }
1268 wxTheClipboard->Close();
1269 }
1270 return;
1271 }
1272 case ID_RCLK_MENU_COPY: {
1273 result = ((wxTextCtrl*)m_contextObject)->GetValue();
1274 break;
1275 }
1276 case ID_RCLK_MENU_COPY_LL: {
1277 result << toSDMM(1, lat, true) << '\t';
1278 result << toSDMM(2, lon, true);
1279 break;
1280 }
1281 }
1282
1283 if (wxTheClipboard->Open()) {
1284 wxTextDataObject* data = new wxTextDataObject;
1285 data->SetText(result);
1286 wxTheClipboard->SetData(data);
1287 wxTheClipboard->Close();
1288 }
1289}
1290
1291void MarkInfoDlg::DefautlBtnClicked(wxCommandEvent& event) {
1292 m_SaveDefaultDlg = new SaveDefaultsDialog(this);
1293 m_SaveDefaultDlg->Center();
1294 DimeControl(m_SaveDefaultDlg);
1295 int retcode = m_SaveDefaultDlg->ShowModal();
1296
1297 {
1298 if (retcode == wxID_OK) {
1299 double value;
1300 if (m_SaveDefaultDlg->IconCB->GetValue()) {
1301 g_default_wp_icon =
1302 *pWayPointMan->GetIconKey(m_bcomboBoxIcon->GetSelection());
1303 }
1304 if (m_SaveDefaultDlg->RangRingsCB->GetValue()) {
1305 g_iWaypointRangeRingsNumber =
1306 m_ChoiceWaypointRangeRingsNumber->GetSelection();
1307 if (m_textWaypointRangeRingsStep->GetValue().ToDouble(&value))
1308 g_fWaypointRangeRingsStep = fromUsrDistance(value, -1);
1309 g_colourWaypointRangeRingsColour = m_PickColor->GetColour();
1310 }
1311 if (m_SaveDefaultDlg->ArrivalRCB->GetValue())
1312 if (m_textArrivalRadius->GetValue().ToDouble(&value))
1313 g_n_arrival_circle_radius = fromUsrDistance(value, -1);
1314 if (m_SaveDefaultDlg->ScaleCB->GetValue()) {
1315 g_iWpt_ScaMin = wxAtoi(m_textScaMin->GetValue());
1316 g_bUseWptScaMin = m_checkBoxScaMin->GetValue();
1317 }
1318 if (m_SaveDefaultDlg->NameCB->GetValue()) {
1319 g_bShowWptName = m_checkBoxShowName->GetValue();
1320 }
1321 }
1322 m_SaveDefaultDlg = NULL;
1323 }
1324}
1325
1326void MarkInfoDlg::OnMarkInfoCancelClick(wxCommandEvent& event) {
1327 if (m_pRoutePoint) {
1328 m_pRoutePoint->SetVisible(m_bIsVisible_save);
1329 m_pRoutePoint->SetNameShown(m_bShowName_save);
1330 m_pRoutePoint->SetPosition(m_lat_save, m_lon_save);
1331 m_pRoutePoint->SetIconName(m_IconName_save);
1332 m_pRoutePoint->ReLoadIcon();
1333 m_pRoutePoint->SetName(m_Name_save);
1334 m_pRoutePoint->m_MarkDescription = m_Description_save;
1335 m_pRoutePoint->SetUseSca(m_bUseScaMin_save);
1336 m_pRoutePoint->SetScaMin(m_iScaminVal_save);
1337
1338 m_pRoutePoint->m_HyperlinkList->clear();
1339
1340 int NbrOfLinks = m_pMyLinkList->size();
1341 if (NbrOfLinks > 0) {
1342 for (Hyperlink* link : *m_pMyLinkList) {
1343 Hyperlink* h = new Hyperlink();
1344 h->DescrText = link->DescrText;
1345 h->Link = link->Link;
1346 h->LType = link->LType;
1347
1348 m_pRoutePoint->m_HyperlinkList->push_back(h);
1349 }
1350 }
1351 }
1352
1353 m_lasttspos.Clear();
1354
1355#ifdef __WXGTK__
1356 gFrame->Raise();
1357#endif
1358
1359 Show(false);
1360 delete m_pMyLinkList;
1361 m_pMyLinkList = NULL;
1362 SetClientSize(m_defaultClientSize);
1363
1364#ifdef __ANDROID__
1365 androidEnableBackButton(true);
1366#endif
1367
1368 event.Skip();
1369}
1370
1371void MarkInfoDlg::OnMarkInfoOKClick(wxCommandEvent& event) {
1372 if (m_pRoutePoint) {
1373 m_pRoutePoint->m_wxcWaypointRangeRingsColour = m_PickColor->GetColour();
1374
1375 OnPositionCtlUpdated(event);
1376 SaveChanges(); // write changes to globals and update config
1377 }
1378
1379#ifdef __WXGTK__
1380 gFrame->Raise();
1381#endif
1382
1383 Show(false);
1384
1385 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
1386 pRouteManagerDialog->UpdateWptListCtrl();
1387
1388 if (pRoutePropDialog && pRoutePropDialog->IsShown())
1389 pRoutePropDialog->UpdatePoints();
1390
1391 SetClientSize(m_defaultClientSize);
1392
1393#ifdef __ANDROID__
1394 androidEnableBackButton(true);
1395#endif
1396
1397 event.Skip();
1398}
1399
1400bool MarkInfoDlg::UpdateProperties(bool positionOnly) {
1401 if (m_pRoutePoint) {
1402 m_textLatitude->SetValue(::toSDMM(1, m_pRoutePoint->m_lat));
1403 m_textLongitude->SetValue(::toSDMM(2, m_pRoutePoint->m_lon));
1404 m_lat_save = m_pRoutePoint->m_lat;
1405 m_lon_save = m_pRoutePoint->m_lon;
1406 m_textName->SetValue(m_pRoutePoint->GetName());
1407 m_textDescription->ChangeValue(m_pRoutePoint->m_MarkDescription);
1408 m_textCtrlExtDescription->ChangeValue(m_pRoutePoint->m_MarkDescription);
1409 m_checkBoxShowName->SetValue(m_pRoutePoint->m_bShowName);
1410 m_checkBoxShowNameExt->SetValue(m_pRoutePoint->m_bShowName);
1411 m_checkBoxVisible->SetValue(m_pRoutePoint->m_bIsVisible);
1412 m_checkBoxScaMin->SetValue(m_pRoutePoint->GetUseSca());
1413 m_textScaMin->SetValue(
1414 wxString::Format("%i", (int)m_pRoutePoint->GetScaMin()));
1415 m_textCtrlGuid->SetValue(m_pRoutePoint->m_GUID);
1416 m_ChoiceWaypointRangeRingsNumber->SetSelection(
1417 m_pRoutePoint->GetWaypointRangeRingsNumber());
1418 wxString buf;
1419 buf.Printf("%.3f",
1420 toUsrDistance(m_pRoutePoint->GetWaypointRangeRingsStep(), -1));
1421 m_textWaypointRangeRingsStep->SetValue(buf);
1422 m_staticTextArrivalUnits->SetLabel(getUsrDistanceUnit());
1423 buf.Printf("%.3f",
1424 toUsrDistance(m_pRoutePoint->GetWaypointArrivalRadius(), -1));
1425 m_textArrivalRadius->SetValue(buf);
1426
1427 int nUnits = m_pRoutePoint->GetWaypointRangeRingsStepUnits();
1428 m_RangeRingUnits->SetSelection(nUnits);
1429
1430 wxColour col = m_pRoutePoint->m_wxcWaypointRangeRingsColour;
1431 m_PickColor->SetColour(col);
1432
1433 if (m_pRoutePoint->m_bIsInRoute) {
1434 if (m_name_validator) m_name_validator.reset();
1435 m_name_validator =
1436 std::make_unique<RoutePointNameValidator>(m_pRoutePoint);
1437 m_textName->SetValidator(*m_name_validator);
1438 m_textName->Bind(wxEVT_TEXT, &TextField::OnTextChanged, m_textName);
1439 m_textName->Bind(wxEVT_KILL_FOCUS, &MarkInfoDlg::OnFocusEvent, this);
1440 } else {
1441 m_textName->SetValidator();
1442 m_textName->Unbind(wxEVT_TEXT, &TextField::OnTextChanged, m_textName);
1443 m_textName->Unbind(wxEVT_KILL_FOCUS, &MarkInfoDlg::OnFocusEvent, this);
1444 }
1445
1446 if (m_comboBoxTideStation->GetStringSelection() !=
1447 m_pRoutePoint->m_TideStation) {
1448 m_comboBoxTideStation->Clear();
1449 m_comboBoxTideStation->Append("");
1450 if (!m_pRoutePoint->m_TideStation.IsEmpty()) {
1451 m_comboBoxTideStation->Append(m_pRoutePoint->m_TideStation);
1452 m_comboBoxTideStation->SetSelection(1);
1453 }
1454 }
1455
1456 m_staticTextPlSpeedUnits->SetLabel(getUsrSpeedUnit());
1457 if (m_pRoutePoint->GetPlannedSpeed() > .01) {
1458 m_textCtrlPlSpeed->SetValue(wxString::Format(
1459 "%.1f", toUsrSpeed(m_pRoutePoint->GetPlannedSpeed())));
1460 } else {
1461 m_textCtrlPlSpeed->SetValue("");
1462 }
1463
1464 bool isLastWaypoint = false;
1465 if (m_pRoutePoint && m_pRoutePoint->m_bIsInRoute) {
1466 // Get routes containing this waypoint
1467 wxArrayPtrVoid* pRouteArray =
1468 g_pRouteMan->GetRouteArrayContaining(m_pRoutePoint);
1469 if (pRouteArray) {
1470 isLastWaypoint = true;
1471 // Check if this waypoint is the last across all routes.
1472 for (unsigned int i = 0; i < pRouteArray->GetCount(); i++) {
1473 Route* route = (Route*)pRouteArray->Item(i);
1474 if (route->GetLastPoint()->m_GUID != m_pRoutePoint->m_GUID) {
1475 isLastWaypoint = false;
1476 break;
1477 }
1478 }
1479 delete pRouteArray;
1480 }
1481 }
1482 wxDateTime etd;
1483 etd = m_pRoutePoint->GetManualETD();
1484 if (isLastWaypoint) {
1485 // If this is the last waypoint in a route, uncheck the checkbox and set
1486 // the date/time to empty, as the ETD is meaningless.
1487 etd = wxDateTime();
1488 }
1489 if (etd.IsValid()) {
1490 m_cbEtdPresent->SetValue(true);
1491 wxString dtFormat = ocpn::getUsrDateTimeFormat();
1492 if (dtFormat == "Local Time") {
1493 // The ETD is in UTC and needs to be converted to local time for display
1494 // purpose.
1495 etd.MakeFromUTC();
1496 } else if (dtFormat == "UTC") {
1497 // The date/time is already in UTC.
1498 } else {
1499 // This code path is not expected to be reached, unless
1500 // the global date/time format is enhanced in the future
1501 // to include new format options.
1502 wxLogError(
1503 "MarkInfoDlg::UpdateProperties. Unexpected date/time format: %s",
1504 dtFormat);
1505 etd = wxInvalidDateTime;
1506 }
1507 m_EtdDatePickerCtrl->SetValue(etd.GetDateOnly());
1508 m_EtdTimePickerCtrl->SetValue(etd);
1509 } else {
1510 m_cbEtdPresent->SetValue(false);
1511 }
1512 // Inherit the date/time format from the user settings.
1513 m_staticTextEtd->SetLabel(
1514 wxString::Format("%s (%s)", _("ETD"), ocpn::getUsrDateTimeFormat()));
1515
1516 m_staticTextPlSpeed->Show(m_pRoutePoint->m_bIsInRoute);
1517 m_textCtrlPlSpeed->Show(m_pRoutePoint->m_bIsInRoute);
1518 m_staticTextEtd->Show(m_pRoutePoint->m_bIsInRoute);
1519 m_EtdDatePickerCtrl->Show(m_pRoutePoint->m_bIsInRoute);
1520 m_EtdTimePickerCtrl->Show(m_pRoutePoint->m_bIsInRoute);
1521 m_cbEtdPresent->Show(m_pRoutePoint->m_bIsInRoute);
1522 m_staticTextPlSpeedUnits->Show(m_pRoutePoint->m_bIsInRoute);
1523 m_staticTextArrivalRadius->Show(m_pRoutePoint->m_bIsInRoute);
1524 m_staticTextArrivalUnits->Show(m_pRoutePoint->m_bIsInRoute);
1525 m_textArrivalRadius->Show(m_pRoutePoint->m_bIsInRoute);
1526
1527 if (positionOnly) return true;
1528
1529 // Layer or not?
1530 if (m_pRoutePoint->m_bIsInLayer) {
1531 m_staticTextLayer->Enable();
1532 m_staticTextLayer->Show(true);
1533 m_textName->SetEditable(false);
1534 m_textDescription->SetEditable(false);
1535 m_textCtrlExtDescription->SetEditable(false);
1536 m_textLatitude->SetEditable(false);
1537 m_textLongitude->SetEditable(false);
1538 m_bcomboBoxIcon->Enable(false);
1539 m_checkBoxShowName->Enable(false);
1540 m_checkBoxVisible->Enable(false);
1541 m_textArrivalRadius->SetEditable(false);
1542 m_checkBoxScaMin->Enable(false);
1543 m_textScaMin->SetEditable(false);
1544 m_checkBoxShowNameExt->Enable(false);
1545 m_ChoiceWaypointRangeRingsNumber->Enable(false);
1546 m_textWaypointRangeRingsStep->SetEditable(false);
1547 m_PickColor->Enable(false);
1548 DefaultsBtn->Enable(false);
1549 m_EtdDatePickerCtrl->Enable(false);
1550 m_EtdTimePickerCtrl->Enable(false);
1551 m_cbEtdPresent->Enable(false);
1552 m_notebookProperties->SetSelection(0); // Show Basic page
1553 m_comboBoxTideStation->Enable(false);
1554 } else {
1555 m_staticTextLayer->Enable(false);
1556 m_staticTextLayer->Show(false);
1557 m_textName->SetEditable(true);
1558 m_textDescription->SetEditable(true);
1559 m_textCtrlExtDescription->SetEditable(true);
1560 m_textLatitude->SetEditable(true);
1561 m_textLongitude->SetEditable(true);
1562 m_bcomboBoxIcon->Enable(true);
1563 m_checkBoxShowName->Enable(true);
1564 m_checkBoxVisible->Enable(true);
1565 m_textArrivalRadius->SetEditable(true);
1566 m_checkBoxScaMin->Enable(true);
1567 m_textScaMin->SetEditable(true);
1568 m_checkBoxShowNameExt->Enable(true);
1569 m_ChoiceWaypointRangeRingsNumber->Enable(true);
1570 m_textWaypointRangeRingsStep->SetEditable(true);
1571 m_PickColor->Enable(true);
1572 DefaultsBtn->Enable(true);
1573 m_notebookProperties->SetSelection(0);
1574 m_comboBoxTideStation->Enable(true);
1575
1576 // If this is the last waypoint in a route, disable the ETD as it does not
1577 // make sense to have an ETD for the last waypoint in a route.
1578 m_EtdDatePickerCtrl->Enable(!isLastWaypoint);
1579 m_EtdTimePickerCtrl->Enable(!isLastWaypoint);
1580 m_cbEtdPresent->Enable(!isLastWaypoint);
1581 }
1582
1583 // Fill the icon selector combo box
1584 m_bcomboBoxIcon->Clear();
1585 // Iterate on the Icon Descriptions, filling in the combo control
1586 bool fillCombo = m_bcomboBoxIcon->GetCount() == 0;
1587
1588 if (fillCombo) {
1589 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
1590 wxString* ps = pWayPointMan->GetIconDescription(i);
1591 wxBitmap bmp =
1592 pWayPointMan->GetIconBitmapForList(i, 2 * GetCharHeight());
1593
1594 m_bcomboBoxIcon->Append(*ps, bmp);
1595 }
1596 }
1597 // find the correct item in the combo box
1598 int iconToSelect = -1;
1599 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
1600 if (*pWayPointMan->GetIconKey(i) == m_pRoutePoint->GetIconName()) {
1601 iconToSelect = i;
1602 m_bcomboBoxIcon->Select(iconToSelect);
1603 break;
1604 }
1605 }
1606 wxCommandEvent ev;
1607 OnShowWaypointNameSelectBasic(ev);
1608 OnWptRangeRingsNoChange(ev);
1609 OnSelectScaMinExt(ev);
1610 UpdateHtmlList();
1611 }
1612
1613#ifdef __ANDROID__
1614 androidEnableBackButton(false);
1615#endif
1616
1617 Fit();
1618 // SetMinSize(wxSize(-1, 600));
1619 RecalculateSize();
1620
1621 return true;
1622}
1623
1624// Focus event handler to validate the dialog.
1625void MarkInfoDlg::OnFocusEvent(wxFocusEvent& event) {
1626 bool is_valid = Validate();
1627 m_buttonOkay->Enable(is_valid);
1628 event.Skip();
1629}
1630
1631void MarkInfoDlg::OnBitmapCombClick(wxCommandEvent& event) {
1632 wxString* icon_name =
1633 pWayPointMan->GetIconKey(m_bcomboBoxIcon->GetSelection());
1634 if (icon_name && icon_name->Length()) m_pRoutePoint->SetIconName(*icon_name);
1635 m_pRoutePoint->ReLoadIcon();
1636 SaveChanges();
1637 // pConfig->UpdateWayPoint( m_pRoutePoint );
1638}
1639
1640void MarkInfoDlg::ValidateMark() {
1641 // Look in the master list of Waypoints to see if the currently selected
1642 // waypoint is still valid It may have been deleted as part of a route
1643 bool b_found = false;
1644 for (RoutePoint* rp : *pWayPointMan->GetWaypointList()) {
1645 if (m_pRoutePoint == rp) {
1646 b_found = true;
1647 break;
1648 }
1649 }
1650 if (!b_found) m_pRoutePoint = NULL;
1651}
1652
1653bool MarkInfoDlg::SaveChanges() {
1654 if (m_pRoutePoint) {
1655 if (m_pRoutePoint->m_bIsInLayer) return true;
1656 if (!this->Validate()) return false; // prevent invalid save
1657
1658 // Get User input Text Fields
1659 m_pRoutePoint->SetName(m_textName->GetValue());
1660 m_pRoutePoint->SetWaypointArrivalRadius(m_textArrivalRadius->GetValue());
1661 m_pRoutePoint->SetScaMin(m_textScaMin->GetValue());
1662 m_pRoutePoint->SetUseSca(m_checkBoxScaMin->GetValue());
1663 m_pRoutePoint->m_MarkDescription = m_textDescription->GetValue();
1664 m_pRoutePoint->SetVisible(m_checkBoxVisible->GetValue());
1665 m_pRoutePoint->m_bShowName = m_checkBoxShowName->GetValue();
1666 m_pRoutePoint->SetPosition(fromDMM(m_textLatitude->GetValue()),
1667 fromDMM(m_textLongitude->GetValue()));
1668 wxString* icon_name =
1669 pWayPointMan->GetIconKey(m_bcomboBoxIcon->GetSelection());
1670 if (icon_name && icon_name->Length())
1671 m_pRoutePoint->SetIconName(*icon_name);
1672 m_pRoutePoint->ReLoadIcon();
1673 m_pRoutePoint->SetShowWaypointRangeRings(
1674 (bool)(m_ChoiceWaypointRangeRingsNumber->GetSelection() != 0));
1675 m_pRoutePoint->SetWaypointRangeRingsNumber(
1676 m_ChoiceWaypointRangeRingsNumber->GetSelection());
1677 double value;
1678 if (m_textWaypointRangeRingsStep->GetValue().ToDouble(&value))
1679 m_pRoutePoint->SetWaypointRangeRingsStep(fromUsrDistance(value, -1));
1680 if (m_textArrivalRadius->GetValue().ToDouble(&value))
1681 m_pRoutePoint->SetWaypointArrivalRadius(fromUsrDistance(value, -1));
1682
1683 if (m_RangeRingUnits->GetSelection() != wxNOT_FOUND)
1684 m_pRoutePoint->SetWaypointRangeRingsStepUnits(
1685 m_RangeRingUnits->GetSelection());
1686
1687 m_pRoutePoint->m_TideStation = m_comboBoxTideStation->GetStringSelection();
1688 if (m_textCtrlPlSpeed->GetValue() == "") {
1689 m_pRoutePoint->SetPlannedSpeed(0.0);
1690 } else {
1691 double spd;
1692 if (m_textCtrlPlSpeed->GetValue().ToDouble(&spd)) {
1693 m_pRoutePoint->SetPlannedSpeed(fromUsrSpeed(spd));
1694 }
1695 }
1696
1697 if (m_cbEtdPresent->GetValue()) {
1698 wxDateTime dt = m_EtdDatePickerCtrl->GetValue();
1699 wxDateTime t = m_EtdTimePickerCtrl->GetValue();
1700 int hour = t.GetHour();
1701 dt.SetHour(hour);
1702 dt.SetMinute(m_EtdTimePickerCtrl->GetValue().GetMinute());
1703 dt.SetSecond(m_EtdTimePickerCtrl->GetValue().GetSecond());
1704 if (dt.IsValid()) {
1705 // The date/time in the UI is specified according to the global settings
1706 // in Options -> Date/Time format. The date/time format is either "Local
1707 // Time" or "UTC". If the date/time format is "Local Time", convert to
1708 // UTC. Otherwise, it is already in UTC.
1709 wxString dtFormat = ocpn::getUsrDateTimeFormat();
1710 if (dtFormat == "Local Time") {
1711 m_pRoutePoint->SetETD(dt.MakeUTC());
1712 } else if (dtFormat == "UTC") {
1713 m_pRoutePoint->SetETD(dt);
1714 } else {
1715 // This code path should never be reached, as the date/time format is
1716 // either "Local Time" or "UTC".
1717 // In the future, other date/time formats may be supported in
1718 // global settings (Options -> Display -> Date/Time Format).
1719 // When/if this happens, this code will need to be updated to
1720 // handle the new formats.
1721 wxLogError(
1722 "Failed to configured ETD. Unsupported date/time format: %s",
1723 dtFormat);
1724 m_pRoutePoint->SetETD(wxInvalidDateTime);
1725 }
1726 }
1727 } else {
1728 m_pRoutePoint->SetETD(wxInvalidDateTime);
1729 }
1730
1731 if (m_pRoutePoint->m_bIsInRoute) {
1732 // Update the route segment selectables
1733 pSelect->UpdateSelectableRouteSegments(m_pRoutePoint);
1734
1735 // Get an array of all routes using this point
1736 wxArrayPtrVoid* pEditRouteArray =
1737 g_pRouteMan->GetRouteArrayContaining(m_pRoutePoint);
1738
1739 if (pEditRouteArray) {
1740 for (unsigned int ir = 0; ir < pEditRouteArray->GetCount(); ir++) {
1741 Route* pr = (Route*)pEditRouteArray->Item(ir);
1742 pr->FinalizeForRendering();
1743 pr->UpdateSegmentDistances();
1744
1745 // pConfig->UpdateRoute(pr);
1746 NavObj_dB::GetInstance().UpdateRoute(pr);
1747 }
1748 delete pEditRouteArray;
1749 }
1750 } else {
1751 // pConfig->UpdateWayPoint(m_pRoutePoint);
1752 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePoint);
1753 }
1754 }
1755 return true;
1756}
1757
1758SaveDefaultsDialog::SaveDefaultsDialog(MarkInfoDlg* parent)
1759 : wxDialog(parent, wxID_ANY, _("Save some defaults")) {
1760 //(*Initialize(SaveDefaultsDialog)
1761 this->SetSizeHints(wxDefaultSize, wxDefaultSize);
1762
1763 wxBoxSizer* bSizer1 = new wxBoxSizer(wxVERTICAL);
1764 wxStdDialogButtonSizer* StdDialogButtonSizer1;
1765
1766 StaticText1 =
1767 new wxStaticText(this, wxID_ANY,
1768 _("Check which properties of current waypoint\n should "
1769 "be set as default for NEW waypoints."));
1770 bSizer1->Add(StaticText1, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 5);
1771
1772 wxFlexGridSizer* fgSizer1 = new wxFlexGridSizer(2);
1773
1774 wxString s =
1775 (g_pMarkInfoDialog->m_checkBoxShowName->GetValue() ? _("Do use")
1776 : _("Don't use"));
1777 NameCB =
1778 new wxCheckBox(this, wxID_ANY, _("Show Waypoint Name"), wxDefaultPosition,
1779 wxDefaultSize, 0, wxDefaultValidator);
1780 fgSizer1->Add(NameCB, 0, wxALL, 5);
1781 stName = new wxStaticText(this, wxID_ANY, "[" + s + "]", wxDefaultPosition,
1782 wxDefaultSize, 0);
1783 stName->Wrap(-1);
1784 fgSizer1->Add(stName, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
1785
1786 s = g_pMarkInfoDialog->m_pRoutePoint->GetIconName();
1787 IconCB = new wxCheckBox(this, wxID_ANY, _("Icon"));
1788 fgSizer1->Add(IconCB, 0, wxALL, 5);
1789 stIcon = new wxStaticText(this, wxID_ANY, "[" + s + "]", wxDefaultPosition,
1790 wxDefaultSize, 0);
1791 stIcon->Wrap(-1);
1792 fgSizer1->Add(stIcon, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
1793
1794 s = (g_pMarkInfoDialog->m_ChoiceWaypointRangeRingsNumber->GetSelection()
1795 ? _("Do use") +
1796 wxString::Format(
1797 " (%i) ",
1798 g_pMarkInfoDialog->m_ChoiceWaypointRangeRingsNumber
1799 ->GetSelection())
1800 : _("Don't use"));
1801 RangRingsCB = new wxCheckBox(this, wxID_ANY, _("Range rings"));
1802 fgSizer1->Add(RangRingsCB, 0, wxALL, 5);
1803 stRR = new wxStaticText(this, wxID_ANY, "[" + s + "]", wxDefaultPosition,
1804 wxDefaultSize, 0);
1805 stRR->Wrap(-1);
1806 fgSizer1->Add(stRR, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
1807
1808 s = (g_pMarkInfoDialog->m_textArrivalRadius->GetValue());
1809 ArrivalRCB = new wxCheckBox(this, wxID_ANY, _("Arrival radius"));
1810 fgSizer1->Add(ArrivalRCB, 0, wxALL, 5);
1811 stArrivalR = new wxStaticText(
1812 this, wxID_ANY,
1813 wxString::Format("[%s %s]", s.c_str(), getUsrDistanceUnit().c_str()),
1814 wxDefaultPosition, wxDefaultSize, 0);
1815 stArrivalR->Wrap(-1);
1816 fgSizer1->Add(stArrivalR, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL,
1817 5);
1818
1819 s = (g_pMarkInfoDialog->m_checkBoxScaMin->GetValue()
1820 ? _("Show only if") + " < " +
1821 g_pMarkInfoDialog->m_textScaMin->GetValue()
1822 : _("Show always"));
1823 ScaleCB = new wxCheckBox(this, wxID_ANY, _("Show only at scale"));
1824 fgSizer1->Add(ScaleCB, 0, wxALL, 5);
1825 stScale = new wxStaticText(this, wxID_ANY, "[" + s + "]", wxDefaultPosition,
1826 wxDefaultSize, 0);
1827 stScale->Wrap(-1);
1828 fgSizer1->Add(stScale, 0, wxALL | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);
1829
1830 bSizer1->Add(fgSizer1, 0, wxALL | wxEXPAND, 5);
1831
1832 StdDialogButtonSizer1 = new wxStdDialogButtonSizer();
1833 StdDialogButtonSizer1->AddButton(new wxButton(this, wxID_OK));
1834 StdDialogButtonSizer1->AddButton(
1835 new wxButton(this, wxID_CANCEL, _("Cancel")));
1836 StdDialogButtonSizer1->Realize();
1837 bSizer1->Add(StdDialogButtonSizer1, 0, wxALL | wxEXPAND, 5);
1838
1839 SetSizer(bSizer1);
1840 Fit();
1841 Layout();
1842
1843#ifdef __ANDROID__
1844 SetSize(parent->GetSize());
1845#endif
1846
1847 Center();
1848}
1849
1850void MarkInfoDlg::ShowTidesBtnClicked(wxCommandEvent& event) {
1851 if (m_comboBoxTideStation->GetSelection() < 1) {
1852 return;
1853 }
1854 IDX_entry* pIDX = (IDX_entry*)ptcmgr->GetIDX_entry(
1855 ptcmgr->GetStationIDXbyName(m_comboBoxTideStation->GetStringSelection(),
1856 fromDMM(m_textLatitude->GetValue()),
1857 fromDMM(m_textLongitude->GetValue())));
1858 if (pIDX) {
1859 TCWin* pCwin = new TCWin(gFrame->GetPrimaryCanvas(), 0, 0, pIDX);
1860 pCwin->Show();
1861 } else {
1862 wxString msg(_("Tide Station not found"));
1863 msg += ":\n";
1864 msg += m_comboBoxTideStation->GetStringSelection();
1865 OCPNMessageBox(NULL, msg, _("OpenCPN Info"), wxOK | wxCENTER, 10);
1866 }
1867}
Generic Chart canvas base.
Grid layout with 2 columns for form labels and fields.
Definition form_grid.h:28
Represents an index entry for tidal and current data.
Definition idx_entry.h:48
Class LinkPropImpl.
Dialog for displaying and editing waypoint properties.
Definition mark_info.h:203
wxDatePickerCtrl * m_EtdDatePickerCtrl
Date picker control for setting the Estimated Time of Departure (ETD).
Definition mark_info.h:372
wxStaticText * m_staticTextEtd
Label for the Estimated Time of Departure field.
Definition mark_info.h:327
wxCheckBox * m_cbEtdPresent
Checkbox control that enables/disables manual ETD setting for a waypoint.
Definition mark_info.h:285
wxTextCtrl * m_textCtrlPlSpeed
Text control for waypoint planned speed.
Definition mark_info.h:360
wxTimePickerCtrl * m_EtdTimePickerCtrl
Time picker control for setting the Estimated Time of Departure (ETD).
Definition mark_info.h:383
Custom combobox for selecting waypoint icons.
Definition mark_info.h:151
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this waypoint.
wxColour m_wxcWaypointRangeRingsColour
Color for the range rings display.
wxString m_MarkDescription
Description text for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxString m_GUID
Globally Unique Identifier for the waypoint.
wxDateTime GetManualETD()
Retrieves the manually set Estimated Time of Departure for this waypoint, in UTC.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
double GetPlannedSpeed()
Return the planned speed associated with this waypoint.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
wxString m_TideStation
Associated tide station identifier.
void SetETD(const wxDateTime &etd)
Sets the Estimated Time of Departure for this waypoint, in UTC.
Represents a navigational route in the navigation system.
Definition route.h:99
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
Definition routeman.cpp:150
Dialog for saving default waypoint properties.
Definition mark_info.h:456
Definition tc_win.h:44
Text field with validator and error handler.
Definition field_text.h:38
void OnTextChanged(wxCommandEvent &event)
Text changed event handler.
Global variables stored in configuration file.
OpenCPN Georef utility.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:59
wxFont GetOCPNGUIScaledFont(wxString item)
Retrieves a font optimized for touch and high-resolution interfaces.
Definition gui_lib.cpp:88
General purpose GUI support.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Definition mark_info.cpp:76
const wxEventType EVT_LLCHANGE
Waypoint properties maintenance dialog.
const wxEventType EVT_LLCHANGE
wxString getUsrDateTimeFormat()
Return the date/time format to use when formatting date/time strings.
Definition datetime.cpp:41
MySQL based storage for routes, tracks, etc.
Utility functions.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
Navigation Utility Functions without GUI dependencies.
OpenCPN top window.
OpenCPN Platform specific support utilities.
Position, course, speed, etc.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
String positions parsing.
Route abstraction.
wxColour g_colourWaypointRangeRingsColour
Global instance.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
Route properties dialog.
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
Route Manager.
Manage routes dialog.
Select * pSelect
Global instance.
Definition select.cpp:36
Selected route, segment, waypoint, etc.
Chart Symbols.
wxBitmap LoadSVG(const wxString filename, const unsigned int width, const unsigned int height, wxBitmap *default_bitmap, bool use_cache)
Load SVG file and return it's bitmap representation of requested size In case file can't be loaded an...
Definition svg_utils.cpp:59
SVG utilities.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Definition tcmgr.cpp:42
Tide and Current Manager @TODO Add original author copyright.
GUI library utils and events.