OpenCPN Partial API docs
Loading...
Searching...
No Matches
gui_lib.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 **************************************************************************/
19
25#include <wx/artprov.h>
26#include <wx/dialog.h>
27#include <wx/sizer.h>
28#include <wx/statbmp.h>
29#include <wx/statline.h>
30
31#include "model/gui_events.h"
32#include "gui_lib.h"
33#include "timers.h"
34#include "FontMgr.h"
35#include "OCPNPlatform.h"
36#include "ocpn_plugin.h"
37#include "displays.h"
38
39#ifdef __ANDROID__
40#include "androidUTIL.h"
41#include "qdebug.h"
42#endif
43
44extern bool g_bresponsive;
45extern OCPNPlatform* g_Platform;
46extern int g_GUIScaleFactor;
47
48CopyableText::CopyableText(wxWindow* parent, const char* text)
49 : wxTextCtrl(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize,
50 wxBORDER_NONE) {
51 SetEditable(false);
52 wxStaticText tmp(parent, wxID_ANY, text);
53 SetBackgroundColour(tmp.GetBackgroundColour());
54}
55
56wxFont* GetOCPNScaledFont(wxString item, int default_size) {
57 wxFont* dFont = FontMgr::Get().GetFont(item, default_size);
58 int req_size = dFont->GetPointSize();
59
60 if (g_bresponsive) {
61 // Adjust font size to be no smaller than xx mm actual size
62 double scaled_font_size = dFont->GetPointSize();
63
64 {
65 double points_per_mm =
66 g_Platform->getFontPointsperPixel() * g_Platform->GetDisplayDPmm();
67 double min_scaled_font_size =
68 3 * points_per_mm; // smaller than 3 mm is unreadable
69 int nscaled_font_size =
70 wxMax(wxRound(scaled_font_size), min_scaled_font_size);
71
72 if (req_size >= nscaled_font_size)
73 return dFont;
74 else {
75 wxFont* qFont = FontMgr::Get().FindOrCreateFont(
76 nscaled_font_size, dFont->GetFamily(), dFont->GetStyle(),
77 dFont->GetWeight());
78 return qFont;
79 }
80 }
81 }
82 return dFont;
83}
84
85wxFont GetOCPNGUIScaledFont(wxString item) {
86 wxFont* dFont = FontMgr::Get().GetFont(item, 0);
87 int req_size = dFont->GetPointSize();
88 wxFont qFont = *dFont;
89
90 if (g_bresponsive) {
91 double postmult = exp(g_GUIScaleFactor * (0.693 / 5.0)); // exp(2)
92 double scaled_font_size = dFont->GetPointSize() * postmult;
93
94 double points_per_mm =
95 g_Platform->getFontPointsperPixel() * g_Platform->GetDisplayDPmm();
96 double min_scaled_font_size =
97 3 * points_per_mm; // smaller than 3 mm is unreadable
98 int nscaled_font_size =
99 wxMax(wxRound(scaled_font_size), min_scaled_font_size);
100
101 // wxFont *qFont = wxTheFontList->FindOrCreateFont(
102 // nscaled_font_size,
103 // dFont->GetFamily(),
104 // dFont->GetStyle(),
105 // dFont->GetWeight());
106 qFont.SetPointSize(nscaled_font_size);
107 }
108
109 return qFont;
110}
111
112int OCPNMessageBox(wxWindow* parent, const wxString& message,
113 const wxString& caption, int style, int timeout_sec, int x,
114 int y) {
115#ifdef __OCPN__ANDROID__
116 androidDisableRotation();
117 int style_mod = style;
118
119 auto dlg = new wxMessageDialog(parent, message, caption, style_mod);
120 int ret = dlg->ShowModal();
121 qDebug() << "OCPNMB-1 ret" << ret;
122
123 // int ret= dlg->GetReturnCode();
124
125 // Not sure why we need this, maybe on wx3?
126 if (((style & wxYES_NO) == wxYES_NO) && (ret == wxID_OK)) ret = wxID_YES;
127
128 dlg->Destroy();
129
130 androidEnableRotation();
131 qDebug() << "OCPNMB-2 ret" << ret;
132 return ret;
133
134#else
135 int ret = wxID_OK;
136
137 TimedMessageBox tbox(parent, message, caption, style, timeout_sec,
138 wxPoint(x, y));
139 ret = tbox.GetRetVal();
140#endif
141
142 return ret;
143}
144
145BEGIN_EVENT_TABLE(OCPNMessageDialog, wxDialog)
146EVT_BUTTON(wxID_YES, OCPNMessageDialog::OnYes)
147EVT_BUTTON(wxID_NO, OCPNMessageDialog::OnNo)
148EVT_BUTTON(wxID_CANCEL, OCPNMessageDialog::OnCancel)
149EVT_CLOSE(OCPNMessageDialog::OnClose)
150END_EVENT_TABLE()
151
152OCPNMessageDialog::OCPNMessageDialog(wxWindow* parent, const wxString& message,
153 const wxString& caption, long style,
154 const wxPoint& pos)
155 : wxDialog(parent, wxID_ANY, caption, pos, wxDefaultSize,
156 wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP) {
157 m_style = style;
158 wxFont* qFont = GetOCPNScaledFont(_("Dialog"));
159 SetFont(*qFont);
160
161 wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL);
162
163 wxBoxSizer* icon_text = new wxBoxSizer(wxHORIZONTAL);
164
165#if wxUSE_STATBMP
166 // 1) icon
167 if (style & wxICON_MASK) {
168 wxBitmap bitmap;
169 switch (style & wxICON_MASK) {
170 default:
171 wxFAIL_MSG(_T("incorrect log style"));
172 // fall through
173
174 case wxICON_ERROR:
175 bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX);
176 break;
177
178 case wxICON_INFORMATION:
179 bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX);
180 break;
181
182 case wxICON_WARNING:
183 bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX);
184 break;
185
186 case wxICON_QUESTION:
187 bitmap = wxArtProvider::GetIcon(wxART_QUESTION, wxART_MESSAGE_BOX);
188 break;
189 }
190 wxStaticBitmap* icon = new wxStaticBitmap(this, wxID_ANY, bitmap);
191 icon_text->Add(icon, 0, wxCENTER);
192 }
193#endif // wxUSE_STATBMP
194
195#if wxUSE_STATTEXT
196 // 2) text
197 icon_text->Add(CreateTextSizer(message), 0, wxALIGN_CENTER | wxLEFT, 10);
198
199 topsizer->Add(icon_text, 1, wxCENTER | wxLEFT | wxRIGHT | wxTOP, 10);
200#endif // wxUSE_STATTEXT
201
202 // 3) buttons
203 int AllButtonSizerFlags =
204 wxOK | wxCANCEL | wxYES | wxNO | wxHELP | wxNO_DEFAULT;
205 int center_flag = wxEXPAND;
206 if (style & wxYES_NO) center_flag = wxALIGN_CENTRE;
207 wxSizer* sizerBtn = CreateSeparatedButtonSizer(style & AllButtonSizerFlags);
208 if (sizerBtn) topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10);
209
210 SetAutoLayout(true);
211 SetSizer(topsizer);
212
213 topsizer->SetSizeHints(this);
214 topsizer->Fit(this);
215 wxSize size(GetSize());
216 if (size.x < size.y * 3 / 2) {
217 size.x = size.y * 3 / 2;
218 SetSize(size);
219 }
220
221 Centre(wxBOTH | wxCENTER_FRAME);
222}
223
224void OCPNMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event)) {
225 SetReturnCode(wxID_YES);
226 EndModal(wxID_YES);
227}
228
229void OCPNMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event)) {
230 SetReturnCode(wxID_NO);
231 EndModal(wxID_NO);
232}
233
234void OCPNMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) {
235 // Allow cancellation via ESC/Close button except if
236 // only YES and NO are specified.
237 if ((m_style & wxYES_NO) != wxYES_NO || (m_style & wxCANCEL)) {
238 SetReturnCode(wxID_CANCEL);
239 EndModal(wxID_CANCEL);
240 }
241}
242
243void OCPNMessageDialog::OnClose(wxCloseEvent& event) {
244 SetReturnCode(wxID_CANCEL);
245 EndModal(wxID_CANCEL);
246}
247
248BEGIN_EVENT_TABLE(TimedMessageBox, wxEvtHandler)
249EVT_TIMER(-1, TimedMessageBox::OnTimer)
250END_EVENT_TABLE()
251
252TimedMessageBox::TimedMessageBox(wxWindow* parent, const wxString& message,
253 const wxString& caption, long style,
254 int timeout_sec, const wxPoint& pos) {
255 ret_val = 0;
256 m_timer.SetOwner(this, -1);
257
258 if (timeout_sec > 0) m_timer.Start(timeout_sec * 1000, wxTIMER_ONE_SHOT);
259
260 dlg = new OCPNMessageDialog(parent, message, caption, style, pos);
261 dlg->ShowModal();
262
263 int ret = dlg->GetReturnCode();
264
265 // Not sure why we need this, maybe on wx3?
266 if (((style & wxYES_NO) == wxYES_NO) && (ret == wxID_OK)) ret = wxID_YES;
267
268 delete dlg;
269 dlg = NULL;
270
271 ret_val = ret;
272}
273
274TimedMessageBox::~TimedMessageBox() {}
275
276void TimedMessageBox::OnTimer(wxTimerEvent& evt) {
277 if (dlg) dlg->EndModal(wxID_CANCEL);
278}
279
280// Auto timed popup Window implementation
281BEGIN_EVENT_TABLE(TimedPopupWin, wxWindow)
282EVT_PAINT(TimedPopupWin::OnPaint)
283EVT_TIMER(POPUP_TIMER, TimedPopupWin::OnTimer)
284
285END_EVENT_TABLE()
286
287// Define a constructor
288TimedPopupWin::TimedPopupWin(wxWindow* parent, int timeout)
289 : wxWindow(parent, wxID_ANY, wxPoint(0, 0), wxSize(1, 1), wxNO_BORDER) {
290 m_pbm = NULL;
291
292 m_timer_timeout.SetOwner(this, POPUP_TIMER);
293 m_timeout_sec = timeout;
294 isActive = false;
295 Hide();
296}
297
298TimedPopupWin::~TimedPopupWin() { delete m_pbm; }
299void TimedPopupWin::OnTimer(wxTimerEvent& event) {
300 if (IsShown()) Hide();
301}
302
303void TimedPopupWin::SetBitmap(wxBitmap& bmp) {
304 delete m_pbm;
305 m_pbm = new wxBitmap(bmp);
306
307 // Retrigger the auto timeout
308 if (m_timeout_sec > 0)
309 m_timer_timeout.Start(m_timeout_sec * 1000, wxTIMER_ONE_SHOT);
310}
311
312void TimedPopupWin::OnPaint(wxPaintEvent& event) {
313 int width, height;
314 GetClientSize(&width, &height);
315 wxPaintDC dc(this);
316
317 wxMemoryDC mdc;
318 mdc.SelectObject(*m_pbm);
319 dc.Blit(0, 0, width, height, &mdc, 0, 0);
320}
321
322class InfoButton::InfoFrame : public wxFrame {
323public:
324 explicit InfoFrame(wxWindow* parent, const char* header, const char* info)
325 : wxFrame(parent, wxID_ANY, info) {
326 auto flags = wxSizerFlags().Expand();
327 auto vbox = new wxBoxSizer(wxVERTICAL);
328 vbox->Add(new wxStaticText(this, wxID_ANY, info), flags.Border());
329 vbox->Add(new wxStaticLine(this, wxID_ANY), flags);
330 auto button_sizer = new wxStdDialogButtonSizer();
331 auto ok_btn = new wxButton(this, wxID_OK);
332 ok_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
333 [&](wxCommandEvent&) { Hide(); });
334 button_sizer->SetAffirmativeButton(ok_btn);
335 vbox->Add(button_sizer, flags.Border());
336 button_sizer->Realize();
337 SetSizer(vbox);
338 wxWindow::Layout();
339 Hide();
340 }
341};
342
343InfoButton::InfoButton(wxWindow* parent, bool touch, const char* header,
344 const char* info)
345 : wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
346 wxBU_EXACTFIT | wxBORDER_NONE),
347 m_icon(parent, "help-info.svg",
348 GuiEvents::GetInstance().color_scheme_change, touch),
349 m_info_frame(new InfoFrame(parent, header, info)) {
350 SetBitmap(m_icon.GetBitmap());
351 Bind(wxEVT_COMMAND_BUTTON_CLICKED, [&](wxCommandEvent&) {
352 m_info_frame->Fit();
353 m_info_frame->Show();
354 });
355}
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
Definition FontMgr.cpp:467
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Definition FontMgr.cpp:203
EventVar exchange point, a singleton.
Definition gui_events.h:31
Provides platform-specific support utilities for OpenCPN.
Misc GUI event vars, a singleton.
bool g_bresponsive
Flag to control adaptive UI scaling.
Definition ocpn_app.cpp:666
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
Definition gui_lib.cpp:56
wxFont GetOCPNGUIScaledFont(wxString item)
Retrieves a font optimized for touch and high-resolution interfaces.
Definition gui_lib.cpp:85
General purpose GUI support.
PlugIn Object Definition/API.