OpenCPN Partial API docs
Loading...
Searching...
No Matches
AISTargetQueryDialog.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2013 by David S. Register *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 ***************************************************************************
23 */
24
25#include <wx/wxprec.h>
26
27#include <wx/html/htmlwin.h>
28
29#include "AISTargetQueryDialog.h"
30#include "chcanv.h"
31#include "navutil.h"
32#include "ais.h"
33#include "FontMgr.h"
34#include "ais_target_data.h"
35#include "ais_decoder.h"
36#include "select.h"
37#include "routemanagerdialog.h"
38#include "OCPNPlatform.h"
39#include "track.h"
40#include "route_point.h"
41#include "ocpn_frame.h"
42
43extern AISTargetQueryDialog *g_pais_query_dialog_active;
44extern int g_ais_query_dialog_x;
45extern int g_ais_query_dialog_y;
46extern ColorScheme global_color_scheme;
47extern AisDecoder *g_pAIS;
48extern wxString g_default_wp_icon;
49extern Select *pSelect;
50extern MyConfig *pConfig;
51extern RouteManagerDialog *pRouteManagerDialog;
52extern std::vector<Track*> g_TrackList;
53extern OCPNPlatform *g_Platform;
54extern MyFrame *gFrame;
55
56#define xID_OK 10009
57#define xID_WPT_CREATE 10010
58#define xID_TRK_CREATE 10011
59IMPLEMENT_CLASS(AISTargetQueryDialog, wxDialog)
60// AISTargetQueryDialog event table definition
61BEGIN_EVENT_TABLE(AISTargetQueryDialog, wxFrame)
62EVT_BUTTON(xID_OK, AISTargetQueryDialog::OnIdOKClick)
63EVT_BUTTON(xID_WPT_CREATE, AISTargetQueryDialog::OnIdWptCreateClick)
64EVT_BUTTON(xID_TRK_CREATE, AISTargetQueryDialog::OnIdTrkCreateClick)
65EVT_CLOSE(AISTargetQueryDialog::OnClose)
66EVT_MOVE(AISTargetQueryDialog::OnMove)
67EVT_SIZE(AISTargetQueryDialog::OnSize)
68EVT_CHAR_HOOK(AISTargetQueryDialog::OnKey)
69END_EVENT_TABLE()
70
72
73AISTargetQueryDialog::AISTargetQueryDialog(wxWindow *parent, wxWindowID id,
74 const wxString &caption,
75 const wxPoint &pos,
76 const wxSize &size, long style) {
77 Init();
78 Create(parent, id, caption, pos, size, style);
79}
80
81AISTargetQueryDialog::~AISTargetQueryDialog() { delete m_pQueryTextCtl; }
82
84 m_MMSI = -1;
85 m_pQueryTextCtl = NULL;
86 m_nl = 0;
87 m_colorscheme = (ColorScheme)(-1);
88 m_okButton = NULL;
89 m_bsize_set = false;
90 m_bautoCentre = false;
91 m_bautosize = false;
92}
93void AISTargetQueryDialog::OnClose(wxCloseEvent &event) {
94 Destroy();
95 g_pais_query_dialog_active = NULL;
96}
97
98void AISTargetQueryDialog::OnIdOKClick(wxCommandEvent &event) { Close(); }
99
100void AISTargetQueryDialog::OnKey(wxKeyEvent &ke) {
101 if (ke.GetKeyCode() == WXK_ESCAPE)
102 Close(true);
103 else
104 ke.Skip();
105}
106
107void AISTargetQueryDialog::OnIdWptCreateClick(wxCommandEvent &event) {
108 if (m_MMSI != 0) { // Faulty MMSI could be reported as 0
109 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
110 if (td) {
111 wxString n0 = wxString::Format(wxT("%s"), td->ShipName);
112 n0.Replace(_T("@"), _T(" "));
113 n0.Trim();
114 wxString mmsi = wxString::Format(wxT("%i "), td->MMSI);
115 wxString n = _T("\"") + n0 + _T("\" ") + mmsi;
116 n.append(wxDateTime::Now().Format(wxT("%H:%M")));
117 // wxString n = wxString::Format(wxT("\"%s\" %i "),td->ShipName,
118 // td->MMSI).append(wxDateTime::Now().Format(wxT("%H:%M")));
119 RoutePoint *pWP =
120 new RoutePoint(td->Lat, td->Lon, g_default_wp_icon, n, wxEmptyString);
121 pWP->m_bIsolatedMark = true; // This is an isolated mark
122 pSelect->AddSelectableRoutePoint(td->Lat, td->Lon, pWP);
123 pConfig->AddNewWayPoint(pWP, -1); // use auto next num
124
125 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
126 pRouteManagerDialog->UpdateWptListCtrl();
127 gFrame->GetPrimaryCanvas()->undo->BeforeUndoableAction(
128 Undo_CreateWaypoint, pWP, Undo_HasParent, NULL);
129 gFrame->GetPrimaryCanvas()->undo->AfterUndoableAction(NULL);
130 Refresh(false);
131 }
132 }
133}
134
135void AISTargetQueryDialog::OnIdTrkCreateClick(wxCommandEvent &event) {
136 if (m_MMSI != 0) { // Faulty MMSI could be reported as 0
137 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
138 if (td) {
139 if (td->b_PersistTrack) // The target was tracked and the user wants to
140 // stop it
141 {
142 td->b_PersistTrack = false;
143 g_pAIS->m_persistent_tracks.erase(td->MMSI);
144 m_createTrkBtn->SetLabel(_("Record Track"));
145 } else {
146 TrackPoint *tp = NULL;
147 TrackPoint *tp1 = NULL;
148
149 Track *t = new Track();
150
151 t->SetName(wxString::Format(_T("AIS %s (%u) %s %s"),
152 td->GetFullName().c_str(), td->MMSI,
153 wxDateTime::Now().FormatISODate().c_str(),
154 wxDateTime::Now().FormatISOTime().c_str()));
155 for (const AISTargetTrackPoint &ptrack_point : td->m_ptrack) {
156 vector2D point(ptrack_point.m_lon, ptrack_point.m_lat);
157 tp1 = t->AddNewPoint(point, wxDateTime(ptrack_point.m_time).ToUTC());
158 if (tp) {
159 pSelect->AddSelectableTrackSegment(tp->m_lat, tp->m_lon, tp1->m_lat,
160 tp1->m_lon, tp, tp1, t);
161 }
162 tp = tp1;
163 }
164
165 g_TrackList.push_back(t);
166 pConfig->AddNewTrack(t);
167 // t->RebuildGUIDList(); // ensure the GUID list is
168 // intact and good
169
170 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
171 pRouteManagerDialog->UpdateTrkListCtrl();
172 Refresh(false);
173
174 if (wxID_YES ==
175 OCPNMessageBox(
176 NULL,
177 _("The recently captured track of this target has been "
178 "recorded.\nDo you want to continue recording until the end "
179 "of the current OpenCPN session?"),
180 _("OpenCPN Info"), wxYES_NO | wxCENTER, 60)) {
181 td->b_PersistTrack = true;
182 g_pAIS->m_persistent_tracks[td->MMSI] = t;
183 }
184 }
185 }
186 }
187}
188
189bool AISTargetQueryDialog::Create(wxWindow *parent, wxWindowID id,
190 const wxString &caption, const wxPoint &pos,
191 const wxSize &size, long style) {
192 // As a display optimization....
193 // if current color scheme is other than DAY,
194 // Then create the dialog ..WITHOUT.. borders and title bar.
195 // This way, any window decorations set by external themes, etc
196 // will not detract from night-vision
197
198 long wstyle = AIS_TARGET_QUERY_STYLE;
199 if ((global_color_scheme != GLOBAL_COLOR_SCHEME_DAY) &&
200 (global_color_scheme != GLOBAL_COLOR_SCHEME_RGB))
201 wstyle |= (wxNO_BORDER);
202
203 if (!wxFrame::Create(parent, id, caption, pos, size, wstyle)) return false;
204
205 m_parent = parent;
206
207 wxFont *dFont = FontMgr::Get().GetFont(_("AISTargetQuery"));
208 int font_size = wxMax(8, dFont->GetPointSize());
209 wxString face = dFont->GetFaceName();
210#ifdef __WXGTK__
211 face = _T("Monospace");
212#endif
213 m_basefont = FontMgr::Get().FindOrCreateFont(font_size, wxFONTFAMILY_MODERN,
214 wxFONTSTYLE_NORMAL,
215 dFont->GetWeight(), false, face);
216
217 SetFont(*m_basefont);
218 m_adjustedFontSize = dFont->GetPointSize();
219 m_control_font_size = dFont->GetPointSize();
220
221 CreateControls();
222
223 SetColorScheme(global_color_scheme);
224
225 // Set the maximum size of the entire settings dialog
226 wxSize sz = g_Platform->getDisplaySize();
227 SetSizeHints(50, 50, sz.x - 20, sz.y - 40);
228
229 if (!m_bautosize) {
230 Fit(); // Sets the horizontal size OK
231 Layout();
232 SetSize(-1, m_adjustedFontSize * 30); // Estimated vertical size
233 }
234
235 return true;
236}
237
238void AISTargetQueryDialog::SetMMSI(int mmsi) {
239 m_MMSI = mmsi;
240
241 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
242 AdjustBestSize(td.get());
243}
244
245void AISTargetQueryDialog::RecalculateSize() {
246 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
247 AdjustBestSize(td.get());
248 return;
249}
250
251void AISTargetQueryDialog::SetColorScheme(ColorScheme cs) {
252 DimeControl(this);
253 wxColor bg = GetBackgroundColour();
254 m_pQueryTextCtl->SetBackgroundColour(bg);
255 SetBackgroundColour(
256 bg); // This looks like non-sense, but is needed for __WXGTK__
257 // to get colours to propagate down the control's family tree.
258
259#ifdef __WXQT__
260 // wxQT has some trouble clearing the background of HTML window...
261 wxBitmap tbm(GetSize().x, GetSize().y, -1);
262 wxMemoryDC tdc(tbm);
263 // wxColour cback = GetGlobalColor( _T("YELO1") );
264 tdc.SetBackground(bg);
265 tdc.Clear();
266 m_pQueryTextCtl->SetBackgroundImage(tbm);
267#endif
268
269 if (cs != m_colorscheme) {
270 Refresh();
271 }
272 m_colorscheme = cs;
273}
274
275void AISTargetQueryDialog::CreateControls() {
276 wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
277 SetSizer(topSizer);
278
279 m_pQueryTextCtl =
280 new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
281 wxHW_SCROLLBAR_AUTO | wxHW_NO_SELECTION);
282 m_pQueryTextCtl->SetBorders(1);
283 topSizer->Add(m_pQueryTextCtl, 1, wxEXPAND, 5);
284
285 wxSizer *opt = new wxBoxSizer(wxHORIZONTAL);
286 m_createWptBtn = new wxButton(this, xID_WPT_CREATE, _("Create Waypoint"),
287 wxDefaultPosition, wxDefaultSize, 0);
288 opt->Add(m_createWptBtn, 0, wxALL | wxEXPAND, 5);
289
290 m_createTrkBtn = new wxButton(this, xID_TRK_CREATE, _("Record Track"),
291 wxDefaultPosition, wxDefaultSize, 0);
292 opt->Add(m_createTrkBtn, 0, wxALL | wxEXPAND, 5);
293 topSizer->Add(opt, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 5);
294
295 topSizer->Add(new wxButton(this, xID_OK, _("OK")), 0,
296 wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 5);
297
298 Fit();
299}
300
301void AISTargetQueryDialog::UpdateText() {
302 wxString html;
303
304 if (!m_pQueryTextCtl) return;
305
306 int scroll_x, scroll_y;
307 m_pQueryTextCtl->GetViewStart(&scroll_x, &scroll_y);
308
309 auto td = g_pAIS->Get_Target_Data_From_MMSI(m_MMSI);
310 // AdjustBestSize(td);
311
312 DimeControl(this);
313 wxColor bg = GetBackgroundColour();
314 m_pQueryTextCtl->SetBackgroundColour(bg);
315 SetBackgroundColour(bg);
316
317 if (td) {
318 if (td->b_PersistTrack)
319 m_createTrkBtn->SetLabel(_("Stop Tracking"));
320 else
321 m_createTrkBtn->SetLabel(_("Record Track"));
322
323 m_createWptBtn->Enable(td->b_positionOnceValid);
324 m_createTrkBtn->Enable(td->b_show_track);
325
326 RenderHTMLQuery(td.get());
327 }
328
329#ifdef __WXQT__
330 SetColorScheme(m_colorscheme);
331#endif
332
333 m_pQueryTextCtl->Scroll(scroll_x, scroll_y);
334}
335
336void AISTargetQueryDialog::OnMove(wxMoveEvent &event) {
337 // Record the dialog position
338 wxPoint p = event.GetPosition();
339 g_ais_query_dialog_x = p.x;
340 g_ais_query_dialog_y = p.y;
341
342 event.Skip();
343}
344
345void AISTargetQueryDialog::OnSize(wxSizeEvent &event) { event.Skip(); }
346
347void AISTargetQueryDialog::AdjustBestSize(AisTargetData *td) {
348 if (!td) return;
349
350 wxSize origSize = GetSize();
351
352 // First pass, try to set the size using the user specified font sizes
353 // completely
354 if (!m_bsize_set) {
355 Fit();
356 RenderHTMLQuery(td);
357 m_bsize_set = true;
358 }
359
360 int target_x = -1;
361 int target_y = -1;
362
363 // Width adjustments
364
365 if (m_bautosize) {
366 // Reduce the font size if necessary to eliminate horizontal scroll bars.
367 wxSize szv = m_pQueryTextCtl->GetVirtualSize();
368 if (szv.x > m_pQueryTextCtl->GetSize().x) {
369 while ((szv.x > m_pQueryTextCtl->GetSize().x) &&
370 (m_adjustedFontSize > 8)) { // fluff
371 m_adjustedFontSize--;
372
373 RenderHTMLQuery(td);
374 m_pQueryTextCtl->Refresh();
375 m_pQueryTextCtl->Update();
376 Layout();
377 szv = m_pQueryTextCtl->GetVirtualSize();
378 }
379
380 m_adjustedFontSize--;
381 }
382 } else {
383 wxSize szv = m_pQueryTextCtl->GetVirtualSize();
384 int csz = g_Platform->getDisplaySize().x * 8 / 10;
385 if ((szv.x) < csz) {
386 if (szv.x > m_pQueryTextCtl->GetSize().x) target_x = szv.x; // * 11/10;
387 }
388 }
389
390 // Now adjust the font size used for the control buttons.
391 // This adjustment makes sure that the two horizontal buttons are not wider
392 // than the platform display allows.
393
394 if (m_createWptBtn && m_createTrkBtn) {
395 wxSize psz = g_Platform->getDisplaySize();
396
397 wxScreenDC dc;
398 wxFont *tFont = FontMgr::Get().FindOrCreateFont(
399 m_control_font_size, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
400 m_basefont->GetWeight(), false, m_basefont->GetFaceName());
401 dc.SetFont(*tFont);
402
403 wxSize tsz = dc.GetTextExtent(m_createWptBtn->GetLabel() +
404 m_createTrkBtn->GetLabel());
405
406 float totalButtonWidth = tsz.x;
407
408 if (totalButtonWidth * 1.5 > psz.x) {
409 float delta = (float)totalButtonWidth * 2. / psz.x;
410
411 float font_size = m_control_font_size / delta;
412
413 wxFont *fp_font = FontMgr::Get().FindOrCreateFont(
414 font_size, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
415 m_basefont->GetWeight(), false, m_basefont->GetFaceName());
416
417 m_createWptBtn->SetFont(*fp_font);
418 m_createTrkBtn->SetFont(*fp_font);
419
420 m_control_font_size = font_size;
421 }
422 }
423
424 // Height adjustments
425 // Try to avoid vertical scroll bar if possible.
426
427 // Estimate the control button area height
428 int yb = 0;
429 if (m_createWptBtn) yb = m_createWptBtn->GetSize().y * 4;
430
431 wxSize szyv = m_pQueryTextCtl->GetVirtualSize();
432 int csz = g_Platform->getDisplaySize().y * 85 / 100;
433 if ((szyv.y + yb) < csz) {
434 if (szyv.y > m_pQueryTextCtl->GetSize().y)
435 target_y = (szyv.y * 11 / 10) + yb;
436 } else { // Probably going to be a vertical scroll bar, so adjust width
437 // slightly
438 target_y = csz;
439 target_x = szyv.x * 11 / 10;
440 }
441
442 SetSize(target_x, target_y);
443
444 wxSize nowSize = GetSize();
445
446 if (nowSize != origSize) {
447 if (m_bautoCentre) Centre();
448 }
449}
450
451void AISTargetQueryDialog::RenderHTMLQuery(AisTargetData *td) {
452 int font_size = m_adjustedFontSize;
453 wxFont *fp_font = FontMgr::Get().FindOrCreateFont(
454 font_size, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,
455 m_basefont->GetWeight(), false, m_basefont->GetFaceName());
456
457 SetFont(*fp_font);
458
459 int sizes[7];
460 for (int i = -2; i < 5; i++) {
461 sizes[i + 2] = fp_font->GetPointSize() + i + (i > 0 ? i : 0);
462 }
463
464 wxString html;
465 wxColor bg = GetBackgroundColour();
466 wxColor fg = GetForegroundColour();
467
468 html.Printf(
469 _T("<html><body bgcolor=#%02x%02x%02x><font ")
470 _T("color=#%02x%02x%02x><center>"),
471 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
472
473 html << td->BuildQueryResult();
474
475 html << _T("</center></font></body></html>");
476
477 m_pQueryTextCtl->SetFonts(fp_font->GetFaceName(), fp_font->GetFaceName(),
478 sizes);
479
480 wxCharBuffer buf = html.ToUTF8();
481 if (buf.data()) // string OK?
482 m_pQueryTextCtl->SetPage(html);
483}
AISTargetQueryDialog()
Constructors.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
void Init()
Initialise our variables.
Definition: select.h:51
Definition: track.h:79