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