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