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