OpenCPN Partial API docs
Loading...
Searching...
No Matches
gui_lib.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: OpenCPN Main wxWidgets Program
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
26#include <wx/artprov.h>
27#include <wx/dialog.h>
28#include <wx/sizer.h>
29#include <wx/statbmp.h>
30
31#include "gui_lib.h"
32#include "timers.h"
33#include "FontMgr.h"
34#include "OCPNPlatform.h"
35#include "ocpn_plugin.h"
36
37#ifdef __ANDROID__
38#include "androidUTIL.h"
39#include "qdebug.h"
40#endif
41
42extern bool g_bresponsive;
43extern OCPNPlatform* g_Platform;
44extern int g_GUIScaleFactor;
45
46wxFont* GetOCPNScaledFont(wxString item, int default_size) {
47 wxFont* dFont = FontMgr::Get().GetFont(item, default_size);
48 int req_size = dFont->GetPointSize();
49
50 if (g_bresponsive) {
51 // Adjust font size to be no smaller than xx mm actual size
52 double scaled_font_size = dFont->GetPointSize();
53
54 {
55 double points_per_mm =
56 g_Platform->getFontPointsperPixel() * g_Platform->GetDisplayDPmm();
57 double min_scaled_font_size =
58 3 * points_per_mm; // smaller than 3 mm is unreadable
59 int nscaled_font_size =
60 wxMax(wxRound(scaled_font_size), min_scaled_font_size);
61
62 if (req_size >= nscaled_font_size)
63 return dFont;
64 else {
65 wxFont* qFont = FontMgr::Get().FindOrCreateFont(
66 nscaled_font_size, dFont->GetFamily(), dFont->GetStyle(),
67 dFont->GetWeight());
68 return qFont;
69 }
70 }
71 }
72 return dFont;
73}
74
75wxFont GetOCPNGUIScaledFont(wxString item) {
76 wxFont* dFont = FontMgr::Get().GetFont(item, 0);
77 int req_size = dFont->GetPointSize();
78 wxFont qFont = *dFont;
79
80 if (g_bresponsive) {
81 double postmult = exp(g_GUIScaleFactor * (0.693 / 5.0)); // exp(2)
82 double scaled_font_size = dFont->GetPointSize() * postmult;
83
84 double points_per_mm =
85 g_Platform->getFontPointsperPixel() * g_Platform->GetDisplayDPmm();
86 double min_scaled_font_size =
87 3 * points_per_mm; // smaller than 3 mm is unreadable
88 int nscaled_font_size =
89 wxMax(wxRound(scaled_font_size), min_scaled_font_size);
90
91 // wxFont *qFont = wxTheFontList->FindOrCreateFont(
92 // nscaled_font_size,
93 // dFont->GetFamily(),
94 // dFont->GetStyle(),
95 // dFont->GetWeight());
96 qFont.SetPointSize(nscaled_font_size);
97 }
98
99 return qFont;
100}
101
102int OCPNMessageBox( wxWindow *parent, const wxString& message, const wxString& caption, int style,
103 int timeout_sec, int x, int y )
104{
105#ifdef __OCPN__ANDROID__
106 androidDisableRotation();
107 int style_mod = style;
108
109 auto dlg = new wxMessageDialog(parent, message, caption, style_mod);
110 int ret = dlg->ShowModal();
111 qDebug() << "OCPNMB-1 ret" << ret;
112
113 //int ret= dlg->GetReturnCode();
114
115 // Not sure why we need this, maybe on wx3?
116 if( ((style & wxYES_NO) == wxYES_NO) && (ret == wxID_OK))
117 ret = wxID_YES;
118
119 dlg->Destroy();
120
121 androidEnableRotation();
122 qDebug() << "OCPNMB-2 ret" << ret;
123 return ret;
124
125#else
126 int ret = wxID_OK;
127
128 TimedMessageBox tbox(parent, message, caption, style, timeout_sec, wxPoint( x, y ) );
129 ret = tbox.GetRetVal() ;
130#endif
131
132 return ret;
133}
134
135
136BEGIN_EVENT_TABLE(OCPNMessageDialog, wxDialog)
137EVT_BUTTON(wxID_YES, OCPNMessageDialog::OnYes)
138EVT_BUTTON(wxID_NO, OCPNMessageDialog::OnNo)
139EVT_BUTTON(wxID_CANCEL, OCPNMessageDialog::OnCancel)
140EVT_CLOSE(OCPNMessageDialog::OnClose)
141END_EVENT_TABLE()
142
143OCPNMessageDialog::OCPNMessageDialog(wxWindow* parent, const wxString& message,
144 const wxString& caption, long style,
145 const wxPoint& pos)
146 : wxDialog(parent, wxID_ANY, caption, pos, wxDefaultSize,
147 wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP) {
148 m_style = style;
149 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
150 SetFont(*qFont);
151
152 wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
153
154 wxBoxSizer* icon_text = new wxBoxSizer(wxHORIZONTAL);
155
156#if wxUSE_STATBMP
157 // 1) icon
158 if (style & wxICON_MASK) {
159 wxBitmap bitmap;
160 switch (style & wxICON_MASK) {
161 default:
162 wxFAIL_MSG(_T("incorrect log style"));
163 // fall through
164
165 case wxICON_ERROR:
166 bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX);
167 break;
168
169 case wxICON_INFORMATION:
170 bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX);
171 break;
172
173 case wxICON_WARNING:
174 bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX);
175 break;
176
177 case wxICON_QUESTION:
178 bitmap = wxArtProvider::GetIcon(wxART_QUESTION, wxART_MESSAGE_BOX);
179 break;
180 }
181 wxStaticBitmap* icon = new wxStaticBitmap(this, wxID_ANY, bitmap);
182 icon_text->Add(icon, 0, wxCENTER);
183 }
184#endif // wxUSE_STATBMP
185
186#if wxUSE_STATTEXT
187 // 2) text
188 icon_text->Add(CreateTextSizer(message), 0, wxALIGN_CENTER | wxLEFT, 10);
189
190 topsizer->Add(icon_text, 1, wxCENTER | wxLEFT | wxRIGHT | wxTOP, 10);
191#endif // wxUSE_STATTEXT
192
193 // 3) buttons
194 int AllButtonSizerFlags =
195 wxOK | wxCANCEL | wxYES | wxNO | wxHELP | wxNO_DEFAULT;
196 int center_flag = wxEXPAND;
197 if (style & wxYES_NO) center_flag = wxALIGN_CENTRE;
198 wxSizer* sizerBtn = CreateSeparatedButtonSizer(style & AllButtonSizerFlags);
199 if (sizerBtn) topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10);
200
201 SetAutoLayout(true);
202 SetSizer(topsizer);
203
204 topsizer->SetSizeHints(this);
205 topsizer->Fit(this);
206 wxSize size(GetSize());
207 if (size.x < size.y * 3 / 2) {
208 size.x = size.y * 3 / 2;
209 SetSize(size);
210 }
211
212 Centre(wxBOTH | wxCENTER_FRAME);
213}
214
215void OCPNMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event)) {
216 SetReturnCode(wxID_YES);
217 EndModal(wxID_YES);
218}
219
220void OCPNMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event)) {
221 SetReturnCode(wxID_NO);
222 EndModal(wxID_NO);
223}
224
225void OCPNMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) {
226 // Allow cancellation via ESC/Close button except if
227 // only YES and NO are specified.
228 if ((m_style & wxYES_NO) != wxYES_NO || (m_style & wxCANCEL)) {
229 SetReturnCode(wxID_CANCEL);
230 EndModal(wxID_CANCEL);
231 }
232}
233
234void OCPNMessageDialog::OnClose(wxCloseEvent& event) {
235 SetReturnCode(wxID_CANCEL);
236 EndModal(wxID_CANCEL);
237}
238
239BEGIN_EVENT_TABLE(TimedMessageBox, wxEvtHandler)
240EVT_TIMER(-1, TimedMessageBox::OnTimer)
241END_EVENT_TABLE()
242
243TimedMessageBox::TimedMessageBox(wxWindow* parent, const wxString& message,
244 const wxString& caption, long style,
245 int timeout_sec, const wxPoint& pos) {
246 ret_val = 0;
247 m_timer.SetOwner(this, -1);
248
249 if (timeout_sec > 0) m_timer.Start(timeout_sec * 1000, wxTIMER_ONE_SHOT);
250
251 dlg = new OCPNMessageDialog(parent, message, caption, style, pos);
252 dlg->ShowModal();
253
254 int ret = dlg->GetReturnCode();
255
256 // Not sure why we need this, maybe on wx3?
257 if (((style & wxYES_NO) == wxYES_NO) && (ret == wxID_OK)) ret = wxID_YES;
258
259 delete dlg;
260 dlg = NULL;
261
262 ret_val = ret;
263}
264
265TimedMessageBox::~TimedMessageBox() {}
266
267void TimedMessageBox::OnTimer(wxTimerEvent& evt) {
268 if (dlg) dlg->EndModal(wxID_CANCEL);
269}
270
271BEGIN_EVENT_TABLE(OCPN_TimedHTMLMessageDialog, wxDialog)
272EVT_BUTTON(wxID_YES, OCPN_TimedHTMLMessageDialog::OnYes)
273EVT_BUTTON(wxID_NO, OCPN_TimedHTMLMessageDialog::OnNo)
274EVT_BUTTON(wxID_CANCEL, OCPN_TimedHTMLMessageDialog::OnCancel)
275EVT_CLOSE(OCPN_TimedHTMLMessageDialog::OnClose)
276EVT_TIMER(-1, OCPN_TimedHTMLMessageDialog::OnTimer)
277END_EVENT_TABLE()
278
280 wxWindow* parent, const wxString& message, const wxString& caption,
281 int tSeconds, long style, bool bFixedFont, const wxPoint& pos)
282 : wxDialog(parent, wxID_ANY, caption, pos, wxDefaultSize,
283 wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP) {
284 m_style = style;
285 if (bFixedFont) {
286 wxFont* dFont = GetOCPNScaledFont_PlugIn(_("Dialog"));
287 double font_size = dFont->GetPointSize();
288 wxFont* qFont =
289 wxTheFontList->FindOrCreateFont(font_size, wxFONTFAMILY_TELETYPE,
290 dFont->GetStyle(), dFont->GetWeight());
291 SetFont(*qFont);
292 }
293
294 wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
295
296 msgWindow = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
297 wxHW_SCROLLBAR_AUTO | wxHW_NO_SELECTION);
298 msgWindow->SetBorders(30);
299
300 topsizer->Add(msgWindow, 1, wxEXPAND, 5);
301
302 wxString html;
303 html << message;
304
305 wxCharBuffer buf = html.ToUTF8();
306 if (buf.data()) // string OK?
307 msgWindow->SetPage(html);
308
309 // 3) buttons
310 int AllButtonSizerFlags =
311 wxOK | wxCANCEL | wxYES | wxNO | wxHELP | wxNO_DEFAULT;
312 int center_flag = wxEXPAND;
313 if (style & wxYES_NO) center_flag = wxALIGN_CENTRE;
314 wxSizer* sizerBtn = CreateSeparatedButtonSizer(style & AllButtonSizerFlags);
315 if (sizerBtn) topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10);
316
317 SetSizer(topsizer);
318
319 topsizer->Fit(this);
320
321 RecalculateSize();
322 // wxSize szyv = msgWindow->GetVirtualSize();
323
324 // SetClientSize(szyv.x + 20, szyv.y + 20);
325
326 CentreOnScreen();
327
328 // msgWindow->SetBackgroundColour(wxColour(191, 183, 180));
329 msgWindow->SetBackgroundColour(GetBackgroundColour());
330
331 m_timer.SetOwner(this, -1);
332
333 if (tSeconds > 0) m_timer.Start(tSeconds * 1000, wxTIMER_ONE_SHOT);
334}
335
336void OCPN_TimedHTMLMessageDialog::RecalculateSize(void) {
337 wxSize esize;
338 esize.x = GetCharWidth() * 60;
339 int sx, sy;
340 ::wxDisplaySize(&sx, &sy);
341 esize.x = wxMin(esize.x, sx * 6 / 10);
342 esize.y = -1;
343 SetClientSize(esize); // This will force a recalc of internal representation
344
345 int height1 = msgWindow->GetInternalRepresentation()->GetHeight();
346
347 int client_size_y =
348 wxMin(::wxGetDisplaySize().y - 100, height1 + 70); // Must fit on screen
349
350 SetClientSize(wxSize(
351 esize.x, client_size_y)); // constant is 2xBorders + a little slop.
352}
353
354void OCPN_TimedHTMLMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event)) {
355 SetReturnCode(wxID_YES);
356 if (IsModal())
357 EndModal(wxID_YES);
358 else
359 Hide();
360}
361
362void OCPN_TimedHTMLMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event)) {
363 SetReturnCode(wxID_NO);
364 if (IsModal())
365 EndModal(wxID_NO);
366 else
367 Hide();
368}
369
370void OCPN_TimedHTMLMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) {
371 // Allow cancellation via ESC/Close button except if
372 // only YES and NO are specified.
373 if ((m_style & wxYES_NO) != wxYES_NO || (m_style & wxCANCEL)) {
374 SetReturnCode(wxID_CANCEL);
375 EndModal(wxID_CANCEL);
376 }
377}
378
379void OCPN_TimedHTMLMessageDialog::OnClose(wxCloseEvent& event) {
380 SetReturnCode(wxID_CANCEL);
381 if (IsModal())
382 EndModal(wxID_CANCEL);
383 else
384 Hide();
385}
386
387void OCPN_TimedHTMLMessageDialog::OnTimer(wxTimerEvent& evt) {
388 if (IsModal())
389 EndModal(m_style & wxNO_DEFAULT ? wxID_NO : wxID_YES);
390 else
391 Hide();
392}
393
394
395// Auto timed popup Window implementation
396
397BEGIN_EVENT_TABLE(TimedPopupWin, wxWindow)
398EVT_PAINT(TimedPopupWin::OnPaint)
399EVT_TIMER(POPUP_TIMER, TimedPopupWin::OnTimer)
400
401END_EVENT_TABLE()
402
403// Define a constructor
404TimedPopupWin::TimedPopupWin(wxWindow *parent, int timeout)
405 : wxWindow(parent, wxID_ANY, wxPoint(0, 0), wxSize(1, 1), wxNO_BORDER) {
406 m_pbm = NULL;
407
408 m_timer_timeout.SetOwner(this, POPUP_TIMER);
409 m_timeout_sec = timeout;
410 isActive = false;
411 Hide();
412}
413
414TimedPopupWin::~TimedPopupWin() { delete m_pbm; }
415void TimedPopupWin::OnTimer(wxTimerEvent &event) {
416 if (IsShown()) Hide();
417}
418
419void TimedPopupWin::SetBitmap(wxBitmap &bmp) {
420 delete m_pbm;
421 m_pbm = new wxBitmap(bmp);
422
423 // Retrigger the auto timeout
424 if (m_timeout_sec > 0)
425 m_timer_timeout.Start(m_timeout_sec * 1000, wxTIMER_ONE_SHOT);
426}
427
428void TimedPopupWin::OnPaint(wxPaintEvent &event) {
429 int width, height;
430 GetClientSize(&width, &height);
431 wxPaintDC dc(this);
432
433 wxMemoryDC mdc;
434 mdc.SelectObject(*m_pbm);
435 dc.Blit(0, 0, width, height, &mdc, 0, 0);
436}