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