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