OpenCPN Partial API docs
Loading...
Searching...
No Matches
mui_bar.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2018 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/wxprec.h>
25
26#ifndef WX_PRECOMP
27#include <wx/wx.h>
28#endif // precompiled headers
29
30#include <wx/statline.h>
31#include "ssfn.h"
32
33#include "model/config_vars.h"
34#include "model/idents.h"
35#include "model/svg_utils.h"
36
37#include "canvas_options.h"
38#include "chcanv.h"
39#include "color_handler.h"
40#include "detail_slider.h"
41#include "go_to_position_dlg.h"
42#include "mui_bar.h"
43#include "navutil.h"
44#include "navutil.h"
45#include "ocpn_platform.h"
46#include "pluginmanager.h"
47#include "styles.h"
48#include "tooltip.h"
49
50#ifdef ocpnUSE_GL
51#include "gl_chart_canvas.h"
52#endif
53
54#ifdef __ANDROID__
55#include "androidUTIL.h"
56#include "qdebug.h"
57#endif
58
59#ifdef ocpnUSE_GL
60extern GLenum g_texture_rectangle_format;
61#endif
62
63#define ID_SCALE_CANCEL 8301
64#define ID_SCALE_OK 8302
65#define ID_SCALECTRL 8303
66
67//------------------------------------------------------------------------------
68// External Static Storage
69//------------------------------------------------------------------------------
70
71static ssfn_t ctx; /* the renderer context */
72static ssfn_glyph_t* glyph; /* the returned rasterized bitmap */
73static inline void IgnoreRetval(size_t n) { (void)n; }
74
75static double getValue(int animationType, double t);
76
77// Helper classes
78
79class SetScaleDialog : public wxDialog {
80 DECLARE_EVENT_TABLE()
81
82public:
85 SetScaleDialog(wxWindow* parent, wxWindowID id = SYMBOL_GOTOPOS_IDNAME,
86 const wxString& caption = _("Set scale"),
87 const wxPoint& pos = wxDefaultPosition,
88 const wxSize& size = wxDefaultSize,
89 long style = wxDEFAULT_DIALOG_STYLE);
90
92
94 bool Create(wxWindow* parent, wxWindowID id = wxID_ANY,
95 const wxString& caption = _("Set scale"),
96 const wxPoint& pos = wxDefaultPosition,
97 const wxSize& size = wxDefaultSize,
98 long style = wxDEFAULT_DIALOG_STYLE);
99
100 void SetColorScheme(ColorScheme cs);
101
102 void CreateControls();
103
104 void OnSetScaleCancelClick(wxCommandEvent& event);
105 void OnSetScaleOKClick(wxCommandEvent& event);
106
108
109 wxTextCtrl* m_ScaleCtl;
110 wxButton* m_CancelButton;
111 wxButton* m_OKButton;
112};
113
114BEGIN_EVENT_TABLE(SetScaleDialog, wxDialog)
115EVT_BUTTON(ID_GOTOPOS_CANCEL, SetScaleDialog::OnSetScaleCancelClick)
116EVT_BUTTON(ID_GOTOPOS_OK, SetScaleDialog::OnSetScaleOKClick)
117END_EVENT_TABLE()
118
119
124
125SetScaleDialog::SetScaleDialog(wxWindow* parent, wxWindowID id,
126 const wxString& caption, const wxPoint& pos,
127 const wxSize& size, long style) {
128 long wstyle =
129 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT;
130
131 Create(parent, id, caption, pos, size, wstyle);
132}
133
134SetScaleDialog::~SetScaleDialog() {}
135
140bool SetScaleDialog::Create(wxWindow* parent, wxWindowID id,
141 const wxString& caption, const wxPoint& pos,
142 const wxSize& size, long style) {
143 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
144 wxDialog::Create(parent, id, caption, pos, size, style);
145
147 GetSizer()->SetSizeHints(this);
148 Centre();
149
150 return TRUE;
151}
152
158 SetScaleDialog* itemDialog1 = this;
159
160 wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
161 itemDialog1->SetSizer(itemBoxSizer2);
162
163 wxStaticBox* itemStaticBoxSizer4Static =
164 new wxStaticBox(itemDialog1, wxID_ANY, _("Chart Scale"));
165
166 wxStaticBoxSizer* itemStaticBoxSizer4 =
167 new wxStaticBoxSizer(itemStaticBoxSizer4Static, wxVERTICAL);
168 itemBoxSizer2->Add(itemStaticBoxSizer4, 0, wxEXPAND | wxALL, 5);
169
170 wxStaticText* itemStaticText5 = new wxStaticText(
171 itemDialog1, wxID_STATIC, "", wxDefaultPosition, wxDefaultSize, 0);
172 itemStaticBoxSizer4->Add(itemStaticText5, 0,
173 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
174
175 m_ScaleCtl = new wxTextCtrl(itemDialog1, ID_SCALECTRL, "", wxDefaultPosition,
176 wxSize(180, -1), 0);
177 itemStaticBoxSizer4->Add(
178 m_ScaleCtl, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
179
180 wxBoxSizer* itemBoxSizer16 = new wxBoxSizer(wxHORIZONTAL);
181 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
182
183 m_CancelButton = new wxButton(itemDialog1, ID_GOTOPOS_CANCEL, _("Cancel"),
184 wxDefaultPosition, wxDefaultSize, 0);
185 itemBoxSizer16->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
186
187 m_OKButton = new wxButton(itemDialog1, ID_GOTOPOS_OK, _("OK"),
188 wxDefaultPosition, wxDefaultSize, 0);
189 itemBoxSizer16->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
190 m_OKButton->SetDefault();
191
192 SetColorScheme((ColorScheme)0);
193}
194
195void SetScaleDialog::SetColorScheme(ColorScheme cs) { DimeControl(this); }
196
197void SetScaleDialog::OnSetScaleCancelClick(wxCommandEvent& event) {
198 Close();
199 event.Skip();
200}
201
202void SetScaleDialog::OnSetScaleOKClick(wxCommandEvent& event) {
203 SetReturnCode(wxID_OK);
204 EndModal(wxID_OK);
205 return;
206}
207
208//------------------------------------------------------------------------------
209// MUIButton
210//------------------------------------------------------------------------------
211
213 wxSize DoGetBestSize() const;
214
215public:
216 MUIButton();
217 MUIButton(wxWindow* parent, wxWindowID id = wxID_ANY,
218 float scale_factor = 1.0, const wxString& bitmapState0 = "",
219 const wxString& bitmapState1 = "",
220 const wxString& bitmapState2 = "",
221 const wxPoint& pos = wxDefaultPosition,
222 const wxSize& size = wxDefaultSize, long style = wxNO_BORDER);
223
224 bool Create(wxWindow* parent, wxWindowID id = wxID_ANY,
225 float scale_factor = 1.0, const wxString& bitmapState0 = "",
226 const wxString& bitmapState1 = "",
227 const wxString& bitmapState2 = "",
228 const wxPoint& pos = wxDefaultPosition,
229 const wxSize& size = wxDefaultSize, long style = wxNO_BORDER);
230
231 ~MUIButton();
232
233 void Init();
234 void CreateControls();
235
236 void SetState(int state);
237 int GetState() { return mState; }
238
239 void SetColorScheme(ColorScheme cs);
240 void OnSize(wxSizeEvent& event);
241 void OnLeftDown(wxMouseEvent& event);
242 void OnLeftUp(wxMouseEvent& event);
243
244 wxBitmap GetBitmapResource(const wxString& name);
245
246 wxIcon GetIconResource(const wxString& name);
247 wxBitmap GetButtonBitmap() { return m_bitmap; }
248
250 static bool ShowToolTips();
251 wxSize m_size;
252 wxPoint m_position;
253
254private:
255 wxString m_bitmapFileState0;
256 wxString m_bitmapFileState1;
257 wxString m_bitmapFileState2;
258 wxBitmap m_bitmap;
259 wxBitmap m_bitmapState0;
260 wxBitmap m_bitmapState1;
261 wxBitmap m_bitmapState2;
262
263 int mState;
264 float m_scaleFactor;
265 wxSize m_styleToolSize;
266 ColorScheme m_cs;
267};
268
269MUIButton::MUIButton() { Init(); }
270
271MUIButton::MUIButton(wxWindow* parent, wxWindowID id, float scale_factor,
272 const wxString& bitmap, const wxString& bitmapState1,
273 const wxString& bitmapState2, const wxPoint& pos,
274 const wxSize& size, long style) {
275 Init();
276
277 Create(parent, id, scale_factor, bitmap, bitmapState1, bitmapState2, pos,
278 size, style);
279}
280
281bool MUIButton::Create(wxWindow* parent, wxWindowID id, float scale_factor,
282 const wxString& bitmap, const wxString& bitmapState1,
283 const wxString& bitmapState2, const wxPoint& pos,
284 const wxSize& size, long style) {
285 m_bitmapFileState0 = bitmap;
286 m_bitmapFileState1 = bitmapState1;
287 m_bitmapFileState2 = bitmapState2;
288
289 m_scaleFactor = scale_factor;
290
291 m_styleToolSize = g_StyleManager->GetCurrentStyle()->GetToolSize();
292
293 // Arbitrarily boost the MUIButton default size above the style defined size.
294 // No good reason.....
295 m_styleToolSize = wxSize(m_styleToolSize.x * 1.25, m_styleToolSize.y * 1.25);
296
297 m_size = wxSize(m_styleToolSize.x * m_scaleFactor,
298 m_styleToolSize.y * m_scaleFactor);
299
300 CreateControls();
301 return true;
302}
303
304MUIButton::~MUIButton() {}
305
306void MUIButton::Init() {
307 mState = 0;
308 m_cs = (ColorScheme)-1; // GLOBAL_COLOR_SCHEME_RGB;
309}
310
311void MUIButton::CreateControls() {
312 // this->SetForegroundColour(wxColour(255, 255, 255));
313
314 // wxColour backColor = GetGlobalColor("GREY3");
315 // SetBackgroundColour(backColor);
316
317 // this->SetFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
318 // wxFONTWEIGHT_NORMAL, false, "Tahoma"));
319}
320
321void MUIButton::SetColorScheme(ColorScheme cs) {
322#if 1
323 if (m_cs != cs) {
324 wxColour backColor = GetGlobalColor("GREY3");
325 // SetBackgroundColour(backColor);
326
327 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
328
329 wxBitmap bmp = LoadSVG(m_bitmapFileState0, m_size.x, m_size.y);
330 m_bitmapState0 = style->SetBitmapBrightness(bmp, cs);
331
332 bmp = LoadSVG(m_bitmapFileState1, m_size.x, m_size.y);
333 if (bmp.IsOk())
334 m_bitmapState1 = style->SetBitmapBrightness(bmp, cs);
335 else
336 m_bitmapState1 = m_bitmapState0;
337
338 bmp = LoadSVG(m_bitmapFileState2, m_size.x, m_size.y);
339 if (bmp.IsOk())
340 m_bitmapState2 = style->SetBitmapBrightness(bmp, cs);
341 else
342 m_bitmapState2 = m_bitmapState0;
343
344 switch (mState) {
345 case 0:
346 default:
347 m_bitmap = m_bitmapState0;
348 break;
349
350 case 1:
351 m_bitmap = m_bitmapState1;
352 break;
353
354 case 2:
355 m_bitmap = m_bitmapState2;
356 break;
357 }
358
359 m_cs = cs;
360 }
361#endif
362}
363
364bool MUIButton::ShowToolTips() { return true; }
365
366void MUIButton::SetState(int state) {
367 switch (state) {
368 case 0:
369 default:
370 m_bitmap = m_bitmapState0;
371 break;
372
373 case 1:
374 m_bitmap = m_bitmapState1;
375 break;
376
377 case 2:
378 m_bitmap = m_bitmapState2;
379 break;
380 }
381
382 mState = state;
383}
384
385void MUIButton::OnSize(wxSizeEvent& event) {
386 if (m_bitmap.IsOk()) {
387 if (event.GetSize() == m_bitmap.GetSize()) return;
388 }
389
390 if (!m_bitmapFileState0.IsEmpty())
391 m_bitmapState0 =
392 LoadSVG(m_bitmapFileState0, event.GetSize().x, event.GetSize().y);
393
394 if (!m_bitmapFileState1.IsEmpty())
395 m_bitmapState1 =
396 LoadSVG(m_bitmapFileState1, event.GetSize().x, event.GetSize().y);
397 if (!m_bitmapState1.IsOk() || m_bitmapFileState1.IsEmpty())
398 m_bitmapState1 = m_bitmapState0;
399
400 if (!m_bitmapFileState2.IsEmpty())
401 m_bitmapState2 =
402 LoadSVG(m_bitmapFileState2, event.GetSize().x, event.GetSize().y);
403 if (!m_bitmapState2.IsOk() || m_bitmapFileState2.IsEmpty())
404 m_bitmapState2 = m_bitmapState0;
405
406 switch (mState) {
407 case 0:
408 default:
409 m_bitmap = m_bitmapState0;
410 break;
411
412 case 1:
413 m_bitmap = m_bitmapState1;
414 break;
415
416 case 2:
417 m_bitmap = m_bitmapState2;
418 break;
419 }
420}
421
422wxSize MUIButton::DoGetBestSize() const {
423 // wxSize labelSize = wxDefaultSize;
424 // GetTextExtent(m_Label, &labelSize.x, &labelSize.y);
425 // return wxSize(wxMax(40, labelSize.x + 20), wxMax(20, labelSize.y +
426 // 10));
427 return wxSize(m_styleToolSize.x * m_scaleFactor,
428 m_styleToolSize.y * m_scaleFactor);
429}
430
431//-----------------------------------------------------------------------
432// SSFN Utils
433//-----------------------------------------------------------------------
434static std::unordered_map<char, ssfn_glyph_t*> ssfn_glyph_map;
435
439ssfn_font_t* load_font(const char* filename) {
440 char* fontdata = NULL;
441 long int size;
442 FILE* f;
443#if HAS_ZLIB
444 unsigned char hdr[2];
445 gzFile g;
446#endif
447
448 f = fopen(filename, "rb");
449 if (!f) {
450 fprintf(stderr, "unable to load %s\n", filename);
451 return NULL;
452 }
453 size = 0;
454#if HAS_ZLIB
455 fread(&hdr, 2, 1, f);
456 if (hdr[0] == 0x1f && hdr[1] == 0x8b) {
457 fseek(f, -4L, SEEK_END);
458 fread(&size, 4, 1, f);
459 } else {
460 fseek(f, 0, SEEK_END);
461 size = ftell(f);
462 }
463 fclose(f);
464 g = gzopen(filename, "r");
465#else
466 fseek(f, 0, SEEK_END);
467 size = ftell(f);
468 fseek(f, 0, SEEK_SET);
469#endif
470 if (!size) {
471 fprintf(stderr, "unable to load %s\n", filename);
472 exit(3);
473 }
474 fontdata = (char*)malloc(size);
475 if (!fontdata) {
476 fprintf(stderr, "memory allocation error\n");
477 exit(2);
478 }
479#if HAS_ZLIB
480 gzread(g, fontdata, size);
481 gzclose(g);
482#else
483 IgnoreRetval(fread(fontdata, size, 1, f));
484 fclose(f);
485#endif
486
487 return (ssfn_font_t*)fontdata;
488}
489
490bool RenderGlyphToImageBuffer(unsigned char* buffer, ssfn_glyph_t* glyph,
491 int x_offset, int w, int h, int nominal_baseline,
492 wxColour& color, wxColour& back_color) {
493 unsigned char* src = glyph->data;
494 for (int i = 0; i < h; i++) {
495 for (int j = 0; j < glyph->w; j++) {
496 size_t index = i * w + j + x_offset;
497 index += (nominal_baseline - glyph->baseline) * w;
498 if (index > (size_t)h * (w - 1)) continue;
499 size_t didx = index * 3;
500
501 size_t sidx = i * glyph->pitch + j;
502 unsigned char d = src[sidx];
503 float dn = d / 256.;
504 buffer[didx] = (color.Red() * dn) + (back_color.Red() * (1 - dn));
505 buffer[didx + 1] = (color.Green() * dn) + (back_color.Green() * (1 - dn));
506 buffer[didx + 2] = (color.Blue() * dn) + (back_color.Blue() * (1 - dn));
507 }
508 }
509 return true;
510}
511
512bool RenderStringToBuffer(unsigned char* buffer, std::string s, int wbox,
513 int hbox, int nominal_baseline, wxColour color,
514 wxColour& back_color) {
515 int xpos = 0;
516 for (unsigned int i = 0; i < s.size(); i++) {
517 char key = s[i];
518 ssfn_glyph_t* glyph = 0;
519 // find the required glyph
520 if (auto findit = ssfn_glyph_map.find(key);
521 findit != ssfn_glyph_map.end()) {
522 glyph = findit->second;
523 } else {
524 glyph = ssfn_render(&ctx, key);
525 ssfn_glyph_map[key] = glyph;
526 }
527 RenderGlyphToImageBuffer(buffer, glyph, xpos, wbox, hbox, nominal_baseline,
528 color, back_color);
529 xpos += glyph->adv_x;
530 }
531 return true;
532}
533
534//------------------------------------------------------------------------------
535// MUITextButton
536//------------------------------------------------------------------------------
537
539public:
541 MUITextButton(wxWindow* parent, wxWindowID id, float scale_factor,
542 wxColor backColor, const wxString& text = "",
543 const wxPoint& pos = wxDefaultPosition,
544 const wxSize& size = wxDefaultSize, long style = wxNO_BORDER);
545
546 bool Create(wxWindow* parent, wxWindowID id, float scale_factor = 1.0,
547 const wxString& text = "", const wxPoint& pos = wxDefaultPosition,
548 const wxSize& size = wxDefaultSize, long style = wxNO_BORDER);
549
551
552 void Init();
553 wxSize GetSize() { return m_size; }
554 void SetState(int state);
555
556 void SetColorScheme(ColorScheme cs);
557 void OnSize(wxSizeEvent& event);
558 void OnLeftDown(wxMouseEvent& event);
559 void OnLeftUp(wxMouseEvent& event);
560 void SetText(const wxString& text);
561
562 wxBitmap GetButtonBitmap() { return m_bitmap; }
563 wxSize m_size;
564 wxPoint m_position;
565
566private:
567 void BuildBitmap();
568
569 wxString m_text;
570 wxBitmap m_bitmap;
571
572 int mState;
573 float m_scaleFactor;
574 wxSize m_styleToolSize;
575 ColorScheme m_cs;
576 int m_pixel_height;
577 int m_ssfn_status;
578 wxColor m_backgrounColor;
579};
580
581MUITextButton::MUITextButton() { Init(); }
582
583MUITextButton::MUITextButton(wxWindow* parent, wxWindowID id,
584 float scale_factor, wxColor backColor,
585 const wxString& text, const wxPoint& pos,
586 const wxSize& size, long style) {
587 m_backgrounColor = backColor;
588 Init();
589 Create(parent, id, scale_factor, text, pos, size, style);
590}
591
592bool MUITextButton::Create(wxWindow* parent, wxWindowID id, float scale_factor,
593 const wxString& text, const wxPoint& pos,
594 const wxSize& size, long style) {
595 m_text = text;
596
597 m_scaleFactor = scale_factor;
598
599 m_styleToolSize = g_StyleManager->GetCurrentStyle()->GetToolSize();
600
601 // Arbitrarily boost the MUITextButton default size above the style defined
602 // size. No good reason.....
603 m_styleToolSize = wxSize(m_styleToolSize.x * 1.25, m_styleToolSize.y * 1.25);
604
605 int height_ref = m_styleToolSize.y;
606
607 /* initialize the ssfn library, the context is zerod out */
608 memset(&ctx, 0, sizeof(ssfn_t));
609 wxString font_file = g_Platform->GetSharedDataDir() + "ssfndata/FreeSans.sfn";
610 std::string sfont = font_file.ToStdString();
611 ssfn_font_t* pssfn_font = NULL;
612 pssfn_font = load_font(sfont.c_str());
613 if (pssfn_font) ssfn_load(&ctx, pssfn_font);
614
615 m_pixel_height = height_ref / 2;
616 m_pixel_height *= m_scaleFactor;
617
618 /* select the typeface to use */
619 m_ssfn_status =
620 ssfn_select(&ctx, SSFN_FAMILY_SANS, NULL, /* family */
621 SSFN_STYLE_REGULAR, m_pixel_height, /* style and size */
622 SSFN_MODE_ALPHA /* rendering mode */
623 );
624
625 int wbox = 20;
626 int hbox = 20;
627
628 if (m_ssfn_status == SSFN_OK) {
629 std::string t = "1:888888";
630 ssfn_bbox(&ctx, (char*)t.c_str(), 0, &wbox, &hbox);
631 }
632
633 m_size = wxSize(hbox * 1.5, m_styleToolSize.y);
634 m_size.y *= m_scaleFactor;
635
636 return true;
637}
638MUITextButton::~MUITextButton() {
639 for (const auto& [key, value] : ssfn_glyph_map) {
640 free(value);
641 }
642 ssfn_glyph_map.clear();
643}
644
645void MUITextButton::Init() {
646 mState = 0;
647 m_cs = (ColorScheme)-1; // GLOBAL_COLOR_SCHEME_RGB;
648}
649
650void MUITextButton::SetText(const wxString& text) {
651 if (!m_text.IsSameAs(text)) {
652 m_text = text;
653 BuildBitmap();
654 }
655}
656
657void MUITextButton::SetColorScheme(ColorScheme cs) {
658 if (m_cs != cs) {
659 // wxColour backColor = GetGlobalColor("GREY3");
660 // SetBackgroundColour(backColor);
661
662 m_cs = cs;
663 }
664 BuildBitmap();
665}
666
667void MUITextButton::SetState(int state) { mState = state; }
668
669void MUITextButton::OnSize(wxSizeEvent& event) {
670 BuildBitmap();
671 return;
672}
673
674void MUITextButton::BuildBitmap() {
675 int width = m_size.x;
676 int height = m_size.y;
677
678 if (m_ssfn_status != SSFN_OK) return;
679
680 int wbox = 0;
681 int hbox = 0;
682 std::string t = m_text.ToStdString();
683 ssfn_bbox(&ctx, (char*)t.c_str(), 0, &wbox, &hbox);
684
685 ssfn_glyph_t* glyph = ssfn_render(&ctx, '0');
686 int baseline = glyph->baseline;
687 free(glyph);
688
689 unsigned char* image_data = (unsigned char*)calloc(1, wbox * hbox * 3);
690 for (int i = 0; i < wbox * hbox; i++) {
691 int idx = i * 3;
692 image_data[idx] = m_backgrounColor.Red();
693 image_data[idx + 1] = m_backgrounColor.Green();
694 image_data[idx + 2] = m_backgrounColor.Blue();
695 }
696
697 RenderStringToBuffer(image_data, t, wbox, hbox, baseline,
698 GetGlobalColor("CHWHT"), m_backgrounColor);
699
700 wxImage fimage = wxImage(wbox, hbox, image_data);
701 wxSize clip_size = wxSize(wbox, baseline + 2);
702 wxRect clip_rect = wxRect(0, 0, clip_size.x, clip_size.y);
703 wxImage clip_image = fimage.GetSubImage(clip_rect);
704
705 m_bitmap = wxBitmap(clip_image);
706}
707
708#define CANVAS_OPTIONS_ANIMATION_TIMER_1 800
709#define CANVAS_OPTIONS_TIMER 801
710
711//------------------------------------------------------------------------------
712// MUIBar Implementation
713//------------------------------------------------------------------------------
714
715// Define a constructor
716MUIBar::MUIBar() {}
717
718MUIBar::MUIBar(ChartCanvas* parent, int orientation, float size_factor,
719 wxWindowID id, const wxPoint& pos, const wxSize& size,
720 long style, const wxString& name) {
721 m_parentCanvas = parent;
722 m_orientation = orientation;
723
724 m_scaleFactor = size_factor;
725 m_cs = (ColorScheme)-1;
726 wxColour backColor = wxColor(*wxBLACK); // GetGlobalColor(m_backcolorString);
727
728 Init();
729 CreateControls();
730}
731
732MUIBar::~MUIBar() {
733 if (m_canvasOptions) {
734 m_canvasOptions->Destroy();
735 m_canvasOptions = 0;
736 }
737 delete m_zinButton;
738 delete m_zoutButton;
739 delete m_followButton;
740 delete m_menuButton;
741 delete m_scaleButton;
742 InvalidateBitmap();
743}
744
745void MUIBar::Init() {
746 m_zinButton = NULL;
747 m_zoutButton = NULL;
748 m_followButton = NULL;
749 m_menuButton = NULL;
750 m_scaleButton = NULL;
751
752 m_canvasOptions = NULL;
753 m_canvasOptionsAnimationTimer.SetOwner(this,
754 CANVAS_OPTIONS_ANIMATION_TIMER_1);
755 m_backcolor = GetGlobalColor("GREY3");
756 m_capture_size_y = 0;
757
758 m_COTopOffset = 60; // TODO should be below GPS/Compass
759
760 CanvasOptionTimer.SetOwner(this, CANVAS_OPTIONS_TIMER);
761 m_coAnimateByBitmaps = false;
762 m_bEffects = false; // true;
763#ifdef __ANDROID__
764 m_bEffects = false;
765#endif
766 m_texture = 0;
767 m_end_margin = m_parentCanvas->GetCharWidth() / 2;
768 m_scale = 0;
769}
770
771void MUIBar::SetColorScheme(ColorScheme cs) {
772 if (m_cs != cs) {
773 if (m_zinButton) m_zinButton->SetColorScheme(cs);
774 if (m_zoutButton) m_zoutButton->SetColorScheme(cs);
775 if (m_followButton) m_followButton->SetColorScheme(cs);
776 if (m_menuButton) m_menuButton->SetColorScheme(cs);
777
778 if (m_scaleButton) m_scaleButton->SetColorScheme(cs);
779
780 m_cs = cs;
781 InvalidateBitmap();
782 }
783}
784void MUIBar::InvalidateBitmap() {
785 m_bitmap = wxNullBitmap;
786
787#ifdef ocpnUSE_GL
788 if (g_bopengl) {
789 glDeleteTextures(1, &m_texture);
790 m_texture = 0;
791 }
792#endif
793}
794
795bool MUIBar::MouseEvent(wxMouseEvent& event) {
796 int x, y;
797 event.GetPosition(&x, &y);
798
799 // Check the regions
800 wxRect r = wxRect(m_screenPos, m_size);
801 if (r.Contains(x, y)) {
802 // Check for tooltip display on hover/move events
803 if (event.Moving() || event.Entering()) {
804 bool tooltipShown = false;
805
806 // Check follow button tooltip
807 if (m_followButton) {
808 wxRect rfollow(m_followButton->m_position.x,
809 m_followButton->m_position.y, m_followButton->m_size.x,
810 m_followButton->m_size.y);
811 rfollow.Offset(m_screenPos);
812 if (rfollow.Contains(x, y)) {
813 wxPoint screenPos = wxGetMousePosition();
814 screenPos.x += 15;
815 screenPos.y += 15;
817 m_parentCanvas, _("Follow Ship"), screenPos);
818 tooltipShown = true;
819 }
820 }
821
822 // Check menu button tooltip
823 if (!tooltipShown) {
824 wxRect rmenu(m_menuButton->m_position.x, m_menuButton->m_position.y,
825 m_menuButton->m_size.x, m_menuButton->m_size.y);
826 rmenu.Offset(m_screenPos);
827 if (rmenu.Contains(x, y)) {
828 wxPoint screenPos = wxGetMousePosition();
829 screenPos.x += 15;
830 screenPos.y += 15;
832 m_parentCanvas, _("Options Menu"), screenPos);
833 tooltipShown = true;
834 }
835 }
836
837 // Check zoom buttons tooltips if enabled
838 if (!tooltipShown && g_bShowMuiZoomButtons) {
839 wxRect rzin(m_zinButton->m_position.x, m_zinButton->m_position.y,
840 m_zinButton->m_size.x, m_zinButton->m_size.y);
841 rzin.Offset(m_screenPos);
842 if (rzin.Contains(x, y)) {
843 wxPoint screenPos = wxGetMousePosition();
844 screenPos.x += 15;
845 screenPos.y += 15;
847 _("Zoom In"), screenPos);
848 tooltipShown = true;
849 } else {
850 wxRect rzout(m_zoutButton->m_position.x, m_zoutButton->m_position.y,
851 m_zoutButton->m_size.x, m_zoutButton->m_size.y);
852 rzout.Offset(m_screenPos);
853 if (rzout.Contains(x, y)) {
854 wxPoint screenPos = wxGetMousePosition();
855 screenPos.x += 15;
856 screenPos.y += 15;
858 m_parentCanvas, _("Zoom Out"), screenPos);
859 tooltipShown = true;
860 }
861 }
862 }
863
864 // Check scale button tooltip
865 if (!tooltipShown && m_scaleButton) {
866 wxRect rscale(m_scaleButton->m_position.x, m_scaleButton->m_position.y,
867 m_scaleButton->m_size.x, m_scaleButton->m_size.y);
868 rscale.Offset(m_screenPos);
869 if (rscale.Contains(x, y)) {
870 wxPoint screenPos = wxGetMousePosition();
871 screenPos.x += 15;
872 screenPos.y += 15;
874 m_parentCanvas, _("Chart Scale"), screenPos);
875 tooltipShown = true;
876 }
877 }
878 }
879
880 // Check buttons for clicks
881 if (event.LeftDown()) {
882 if (g_bShowMuiZoomButtons) {
883 wxRect rzin(m_zinButton->m_position.x, m_zinButton->m_position.y,
884 m_zinButton->m_size.x, m_zinButton->m_size.y);
885 rzin.Offset(m_screenPos);
886 if (rzin.Contains(x, y)) {
887 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, ID_ZOOMIN);
888 m_parentCanvas->GetEventHandler()->AddPendingEvent(evt);
889 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
890 return true;
891 }
892
893 wxRect rzout(m_zoutButton->m_position.x, m_zoutButton->m_position.y,
894 m_zoutButton->m_size.x, m_zoutButton->m_size.y);
895 rzout.Offset(m_screenPos);
896 if (rzout.Contains(x, y)) {
897 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, ID_ZOOMOUT);
898 m_parentCanvas->GetEventHandler()->AddPendingEvent(evt);
899 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
900 }
901 }
902
903 if (m_followButton) {
904 wxRect rfollow(m_followButton->m_position.x,
905 m_followButton->m_position.y, m_followButton->m_size.x,
906 m_followButton->m_size.y);
907 rfollow.Offset(m_screenPos);
908 if (rfollow.Contains(x, y)) {
909 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, ID_FOLLOW);
910 m_parentCanvas->GetEventHandler()->AddPendingEvent(evt);
911 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
912 }
913 }
914
915 wxRect rmenu(m_menuButton->m_position.x, m_menuButton->m_position.y,
916 m_menuButton->m_size.x, m_menuButton->m_size.y);
917 rmenu.Offset(m_screenPos);
918 if (rmenu.Contains(x, y)) {
919 HandleMenuClick();
920 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
921 }
922 } else if (event.LeftUp()) {
923 if (m_scaleButton) {
924 wxRect rscale(m_scaleButton->m_position.x, m_scaleButton->m_position.y,
925 m_scaleButton->m_size.x, m_scaleButton->m_size.y);
926 rscale.Offset(m_screenPos);
927 if (rscale.Contains(x, y)) {
928 OnScaleSelected(event);
929 }
930 }
931 }
932 return true;
933 } else {
934 // Mouse is outside MUIBar - hide any tooltips
935 if (event.Moving() || event.Leaving()) {
937 }
938 }
939 return false;
940}
941
942void MUIBar::OnScaleSelected(wxMouseEvent& event) {
943 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
944 if (!pcc) return;
945
946 SetScaleDialog dlg(pcc);
947 dlg.Centre();
948 dlg.ShowModal();
949 if (dlg.GetReturnCode() == wxID_OK) {
950 wxString newScale = dlg.m_ScaleCtl->GetValue();
951 if (newScale.Contains(':')) newScale = newScale.AfterFirst(':');
952 double dScale;
953 if (newScale.ToDouble(&dScale)) {
954 // Try to constrain the scale to something reasonable
955 dScale = wxMin(dScale, 3e6);
956 dScale = wxMax(dScale, 1000);
957 double displayScaleNow = pcc->GetScaleValue();
958 double factor = displayScaleNow / dScale;
959 pcc->ZoomCanvasSimple(factor);
960
961 // Run the calculation again, to reduce roundoff error in large scale
962 // jumps.
963 displayScaleNow = pcc->GetScaleValue();
964 factor = displayScaleNow / dScale;
965 pcc->ZoomCanvasSimple(factor);
966 }
967 }
968}
969
970void MUIBar::SetCanvasENCAvailable(bool avail) {
971 m_CanvasENCAvail = avail;
972 if (m_canvasOptions) m_canvasOptions->SetENCAvailable(avail);
973}
974
975void MUIBar::CreateControls() {
976 wxString iconDir = g_Platform->GetSharedDataDir() + "uidata/MUI_flat/";
977
978 // Build one button to get sizes
979 MUIButton* tb = new MUIButton(m_parentCanvas, ID_ZOOMIN, m_scaleFactor,
980 iconDir + "MUI_zoom-in.svg");
981 wxSize button_size = tb->m_size;
982 delete tb;
983
984 if (m_orientation == wxHORIZONTAL) {
985 // Buttons
986
987 int xoff = 0;
988 if (g_bShowMuiZoomButtons) {
989 m_zinButton = new MUIButton(m_parentCanvas, ID_ZOOMIN, m_scaleFactor,
990 iconDir + "MUI_zoom-in.svg");
991 m_zinButton->m_position = wxPoint(xoff, 0);
992 xoff += m_zinButton->m_size.x;
993
994 m_zoutButton = new MUIButton(m_parentCanvas, ID_ZOOMOUT, m_scaleFactor,
995 iconDir + "MUI_zoom-out.svg");
996 m_zoutButton->m_position = wxPoint(xoff, 0);
997 xoff += m_zoutButton->m_size.x;
998 }
999
1000#ifndef __ANDROID__
1001 // Scale
1002
1003 m_scaleButton = new MUITextButton(m_parentCanvas, wxID_ANY, m_scaleFactor,
1004 GetBackgroundColor(), "1:400000");
1005
1006 m_scaleButton->m_position = wxPoint(xoff, 0);
1007 if (m_scaleButton->GetButtonBitmap().IsOk()) {
1008 int bm_pos_y = (m_scaleButton->GetSize().y -
1009 m_scaleButton->GetButtonBitmap().GetHeight()) /
1010 2;
1011 m_scaleButton->m_position = wxPoint(xoff, bm_pos_y);
1012 }
1013 xoff += m_scaleButton->m_size.x;
1014
1015 m_followButton = new MUIButton(
1016 m_parentCanvas, ID_FOLLOW, m_scaleFactor, iconDir + "MUI_follow.svg",
1017 iconDir + "MUI_follow_active.svg", iconDir + "MUI_follow_ahead.svg");
1018 m_followButton->m_position = wxPoint(xoff, 0);
1019 xoff += m_followButton->m_size.x;
1020#endif
1021
1022 m_menuButton = new MUIButton(m_parentCanvas, ID_MUI_MENU, m_scaleFactor,
1023 iconDir + "MUI_menu.svg");
1024 m_menuButton->m_position = wxPoint(xoff, 0);
1025 xoff += m_menuButton->m_size.x;
1026 m_size.x = xoff;
1027 m_size.y = button_size.y;
1028
1029 } else {
1030 int yoff = 0;
1031
1032 // Buttons
1033 if (g_bShowMuiZoomButtons) {
1034 m_zinButton = new MUIButton(m_parentCanvas, ID_ZOOMIN, m_scaleFactor,
1035 iconDir + "MUI_zoom-in.svg");
1036 m_zinButton->m_position = wxPoint(0, yoff);
1037 yoff += m_zinButton->m_size.y;
1038
1039 m_zoutButton = new MUIButton(m_parentCanvas, ID_ZOOMOUT, m_scaleFactor,
1040 iconDir + "MUI_zoom-out.svg");
1041 m_zoutButton->m_position = wxPoint(0, yoff);
1042 yoff += m_zoutButton->m_size.y;
1043 }
1044
1045#ifndef __ANDROID__
1046 m_followButton = new MUIButton(
1047 m_parentCanvas, ID_FOLLOW, m_scaleFactor, iconDir + "MUI_follow.svg",
1048 iconDir + "MUI_follow_active.svg", iconDir + "MUI_follow_ahead.svg");
1049 m_followButton->m_position = wxPoint(0, yoff);
1050 yoff += m_followButton->m_size.y;
1051#endif
1052
1053 m_menuButton = new MUIButton(m_parentCanvas, ID_MUI_MENU, m_scaleFactor,
1054 iconDir + "MUI_menu.svg");
1055 m_menuButton->m_position = wxPoint(0, yoff);
1056 yoff += m_menuButton->m_size.y;
1057
1058 m_size.y = yoff;
1059 m_size.x = button_size.x;
1060 }
1061}
1062
1063void MUIBar::SetBestPosition() {
1064 int x =
1065 (m_parentCanvas->GetClientSize().x - (m_size.x + (m_end_margin) * 2.00));
1066
1067 int bottomOffset = 6;
1068
1069 int y = m_parentCanvas->GetClientSize().y - m_size.y - bottomOffset;
1070 // if ( g_bopengl){
1071 // y -= m_parentCanvas->GetClientSize().y % 1;
1072 // }
1073
1074 wxPoint position = wxPoint(x, y);
1075 m_screenPos = position;
1076
1077 if (m_canvasOptions) {
1078 m_canvasOptions->Destroy();
1079 m_canvasOptions = 0;
1080 }
1081}
1082
1083void MUIBar::UpdateDynamicValues() {
1084 if (!m_scaleButton) return;
1085
1086 wxString scaleString;
1087 int scale = m_parentCanvas->GetScaleValue();
1088
1089 if (scale != m_scale) InvalidateBitmap();
1090 m_scale = scale;
1091
1092 if (scale < 1e6)
1093 scaleString.Printf("1:%d", scale);
1094 else
1095 scaleString.Printf("1:%4.1f M", scale / 1e6);
1096
1097 if (m_scaleButton) m_scaleButton->SetText(scaleString);
1098}
1099
1100void MUIBar::SetFollowButtonState(int state) {
1101 if (m_followButton && m_followButton->GetState() != state) {
1102 m_followButton->SetState(state);
1103 InvalidateBitmap();
1104 }
1105}
1106
1107void MUIBar::HandleMenuClick() {
1108 if (!m_canvasOptions) {
1109 m_canvasOptions = new CanvasOptions(m_parentCanvas);
1110
1111 // calculate best size for CanvasOptions dialog
1112
1113 wxPoint parentClientUpperRight =
1114 m_parentCanvas->ClientToScreen(wxPoint(m_parentCanvas->GetSize().x, 0));
1115 wxPoint muibar_top = m_parentCanvas->ClientToScreen(m_screenPos);
1116 int size_y = muibar_top.y - (parentClientUpperRight.y + m_COTopOffset);
1117 size_y -= m_parentCanvas->GetCharHeight();
1118 size_y = wxMax(size_y, 100); // ensure always big enough to see
1119
1120 m_canvasOptions->SetSize(wxSize(-1, size_y));
1121 m_canvasOptionsFullSize = m_canvasOptions->GetSize();
1122 m_canvasOptionsFullSize.x +=
1123 m_canvasOptions->GetCharWidth(); // Allow for scroll bar, since
1124 // sizer won't do it.
1125
1126 m_currentCOPos = m_parentCanvas->ClientToScreen(
1127 wxPoint(m_parentCanvas->GetSize().x, m_COTopOffset));
1128
1129 m_canvasOptions->Move(m_currentCOPos);
1130 m_canvasOptions->Hide();
1131 }
1132
1133 m_canvasOptions->SetENCAvailable(m_CanvasENCAvail);
1134
1135 if (m_canvasOptions->IsShown())
1136 PushCanvasOptions(); // hide it
1137 else {
1138 // Grab the backing bitmap, if available
1139
1140 if (m_coAnimateByBitmaps && m_capture_size_y) {
1141 int overShoot_x = m_canvasOptions->GetSize().x * 2 / 10; // 20%
1142 m_backingPoint =
1143 wxPoint(m_capturePoint.x - overShoot_x, m_capturePoint.y);
1144
1145 m_backingBitmap = wxBitmap(m_canvasOptionsFullSize.x + overShoot_x,
1146 m_capture_size_y, -1);
1147 wxMemoryDC mdcb;
1148 mdcb.SelectObject(m_backingBitmap);
1149 wxScreenDC sdc;
1150 mdcb.Blit(0, 0, m_canvasOptionsFullSize.x + overShoot_x, m_capture_size_y,
1151 &sdc, m_capturePoint.x - overShoot_x, m_capturePoint.y, wxCOPY);
1152 mdcb.SelectObject(wxNullBitmap);
1153 }
1154 PullCanvasOptions();
1155 }
1156}
1157
1158void MUIBar::CaptureCanvasOptionsBitmap() {
1159 m_coSequence = 0;
1160 CanvasOptionTimer.Start(100, wxTIMER_ONE_SHOT);
1161}
1162
1163void MUIBar::CaptureCanvasOptionsBitmapChain(wxTimerEvent& event) {
1164 if (m_coSequence == 0) {
1165 if (!m_canvasOptions) m_canvasOptions = new CanvasOptions(m_parentCanvas);
1166
1167 wxPoint parentClientUpperRight =
1168 m_parentCanvas->ClientToScreen(wxPoint(m_parentCanvas->GetSize().x, 0));
1169 wxRect rmui = m_parentCanvas->GetMUIBarRect();
1170 int size_y = rmui.y - (parentClientUpperRight.y + m_COTopOffset);
1171 size_y -= m_parentCanvas->GetCharHeight();
1172 size_y = wxMax(size_y, 100); // ensure always big enough to see
1173 m_capture_size_y = size_y;
1174
1175 m_canvasOptions->SetSize(wxSize(-1, size_y));
1176
1177 m_capturePoint = m_parentCanvas->ClientToScreen(
1178 wxPoint(m_parentCanvas->GetSize().x, m_COTopOffset));
1179 m_canvasOptions->Move(m_capturePoint);
1180 m_canvasOptions->Show();
1181
1182 m_coSequence++;
1183 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
1184 }
1185
1186 else if (m_coSequence == 1) {
1187 m_capturePoint = m_parentCanvas->ClientToScreen(
1188 wxPoint(m_parentCanvas->GetSize().x - m_canvasOptionsFullSize.x,
1189 m_COTopOffset));
1190 m_canvasOptions->Move(m_capturePoint);
1191
1192 m_coSequence++;
1193 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
1194 }
1195
1196 else if (m_coSequence == 2) {
1197 m_animateBitmap =
1198 wxBitmap(m_canvasOptions->GetSize().x, m_capture_size_y, -1);
1199 wxMemoryDC mdc(m_animateBitmap);
1200
1201 wxScreenDC sdc;
1202
1203 mdc.Blit(0, 0, m_canvasOptions->GetSize().x, m_capture_size_y, &sdc,
1204 m_capturePoint.x, m_capturePoint.y, wxCOPY);
1205 mdc.SelectObject(wxNullBitmap);
1206
1207 // delete m_canvasOptions;
1208 // m_canvasOptions = NULL;
1209 }
1210}
1211
1212wxBitmap& MUIBar::CreateBitmap(double displayScale) {
1213 if (m_bitmap.IsOk()) return m_bitmap;
1214
1215 // Make the bitmap
1216 int width = m_size.x;
1217 int height = m_size.y;
1218
1219 wxMemoryDC mdc;
1220 wxBitmap bm(width, height);
1221 mdc.SelectObject(bm);
1222 mdc.SetBackground(wxBrush(GetBackgroundColor()));
1223
1224 mdc.Clear();
1225
1226 wxBitmap bmd;
1227 if (g_bShowMuiZoomButtons) {
1228 wxBitmap bmd = m_zinButton->GetButtonBitmap();
1229 if (bmd.IsOk())
1230 mdc.DrawBitmap(bmd, m_zinButton->m_position.x, m_zinButton->m_position.y,
1231 false);
1232
1233 bmd = m_zoutButton->GetButtonBitmap();
1234 if (bmd.IsOk())
1235 mdc.DrawBitmap(bmd, m_zoutButton->m_position.x,
1236 m_zoutButton->m_position.y, false);
1237 }
1238
1239 if (m_scaleButton) {
1240 bmd = m_scaleButton->GetButtonBitmap();
1241 if (bmd.IsOk()) {
1242 int bm_pos_y = (m_scaleButton->GetSize().y - bmd.GetHeight()) / 2;
1243 int bm_pos_x = m_scaleButton->m_position.x +
1244 (m_scaleButton->GetSize().x - bmd.GetWidth()) / 2;
1245
1246 mdc.DrawBitmap(bmd, bm_pos_x, bm_pos_y, false);
1247 }
1248 }
1249
1250 if (m_followButton) {
1251 bmd = m_followButton->GetButtonBitmap();
1252 if (bmd.IsOk())
1253 mdc.DrawBitmap(bmd, m_followButton->m_position.x,
1254 m_followButton->m_position.y, false);
1255 }
1256
1257 if (m_menuButton) {
1258 bmd = m_menuButton->GetButtonBitmap();
1259 if (bmd.IsOk())
1260 mdc.DrawBitmap(bmd, m_menuButton->m_position.x,
1261 m_menuButton->m_position.y, false);
1262 }
1263
1264 mdc.SelectObject(wxNullBitmap);
1265
1266 m_bitmap = bm;
1267 return m_bitmap;
1268}
1269
1270void MUIBar::DrawGL(ocpnDC& gldc, double displayScale) {
1271#ifdef ocpnUSE_GL
1272
1273 wxColour backColor = GetBackgroundColor();
1274 gldc.SetBrush(wxBrush(backColor));
1275 gldc.SetPen(wxPen(backColor));
1276
1277 wxRect r = wxRect(m_screenPos, m_size);
1278 if (m_orientation == wxHORIZONTAL)
1279 gldc.DrawRoundedRectangle(
1280 (r.x - m_end_margin / 2) * displayScale, (r.y - 1) * displayScale,
1281 (r.width + m_end_margin) * displayScale, (r.height + 2) * displayScale,
1282 (m_end_margin * 1) * displayScale);
1283 else
1284 gldc.DrawRoundedRectangle((r.x - 1) * displayScale,
1285 (r.y - m_end_margin / 2) * displayScale,
1286 (r.width + 2) * displayScale,
1287 (r.height + 2 * m_end_margin) * displayScale,
1288 (m_end_margin * 1.5) * displayScale);
1289
1290 int width = m_size.x;
1291 int height = m_size.y;
1292
1293 CreateBitmap(displayScale);
1294
1295 // Make a GL texture
1296 if (!m_texture) {
1297 glGenTextures(1, &m_texture);
1298
1299 glBindTexture(g_texture_rectangle_format, m_texture);
1300 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
1301 GL_NEAREST);
1302 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
1303 GL_NEAREST);
1304 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_WRAP_S,
1305 GL_CLAMP_TO_EDGE);
1306 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_WRAP_T,
1307 GL_CLAMP_TO_EDGE);
1308 } else {
1309 glBindTexture(g_texture_rectangle_format, m_texture);
1310 }
1311
1312 // fill texture data
1313 if (m_bitmap.IsOk()) {
1314 wxImage image = m_bitmap.ConvertToImage();
1315 if (image.IsOk()) {
1316 unsigned char* d = image.GetData();
1317 if (d) {
1318 unsigned char* e = new unsigned char[4 * width * height];
1319 for (int y = 0; y < height; y++)
1320 for (int x = 0; x < width; x++) {
1321 int i = y * width + x;
1322 memcpy(e + 4 * i, d + 3 * i, 3);
1323 e[4 * i + 3] =
1324 255; // d[3*i + 2] == 255 ? 0:255; //255 - d[3 * i + 2];
1325 }
1326 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, width, height, 0,
1327 GL_RGBA, GL_UNSIGNED_BYTE, e);
1328 delete[] e;
1329 glDisable(g_texture_rectangle_format);
1330 glDisable(GL_BLEND);
1331 }
1332 }
1333 }
1334
1335 // Render the texture
1336 if (m_texture) {
1337 glEnable(g_texture_rectangle_format);
1338 glBindTexture(g_texture_rectangle_format, m_texture);
1339 glEnable(GL_BLEND);
1340
1341 int x0 = m_screenPos.x, x1 = x0 + width;
1342 int y0 = m_screenPos.y - 0, y1 = y0 + height;
1343 x0 *= displayScale;
1344 x1 *= displayScale;
1345 y0 *= displayScale;
1346 y1 *= displayScale;
1347
1348 float tx, ty;
1349 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format)
1350 tx = width, ty = height;
1351 else
1352 tx = ty = 1;
1353
1354 float coords[8];
1355 float uv[8];
1356
1357 // normal uv
1358 uv[0] = 0;
1359 uv[1] = 0;
1360 uv[2] = tx;
1361 uv[3] = 0;
1362 uv[4] = tx;
1363 uv[5] = ty;
1364 uv[6] = 0;
1365 uv[7] = ty;
1366
1367 // pixels
1368 coords[0] = x0;
1369 coords[1] = y0;
1370 coords[2] = x1;
1371 coords[3] = y0;
1372 coords[4] = x1;
1373 coords[5] = y1;
1374 coords[6] = x0;
1375 coords[7] = y1;
1376
1377 m_parentCanvas->GetglCanvas()->RenderTextures(gldc, coords, uv, 4,
1378 m_parentCanvas->GetpVP());
1379
1380 glDisable(g_texture_rectangle_format);
1381 glBindTexture(g_texture_rectangle_format, 0);
1382 glDisable(GL_BLEND);
1383 }
1384#endif
1385
1386 return;
1387}
1388
1389void MUIBar::DrawDC(ocpnDC& dc, double displayScale) {
1390 CreateBitmap(1.0);
1391 dc.DrawBitmap(m_bitmap, m_screenPos.x, m_screenPos.y, false);
1392}
1393
1394void MUIBar::ResetCanvasOptions() {
1395 delete m_canvasOptions;
1396 m_canvasOptions = NULL;
1397}
1398
1399void MUIBar::PullCanvasOptions() {
1400 // Target position
1401 int cox = m_parentCanvas->GetSize().x - m_canvasOptionsFullSize.x;
1402 int coy = m_COTopOffset;
1403 m_targetCOPos = m_parentCanvas->ClientToScreen(wxPoint(cox, coy));
1404
1405 if (!m_bEffects) {
1406 m_canvasOptions->Move(m_targetCOPos);
1407 m_canvasOptions->Show();
1408 return;
1409 }
1410
1411 // Capture the animation bitmap, if required..
1412
1413 if (m_coAnimateByBitmaps && !m_animateBitmap.IsOk()) {
1414 m_canvasOptions->Move(m_targetCOPos);
1415 m_canvasOptions->Show();
1416 CaptureCanvasOptionsBitmap();
1417 return;
1418 }
1419
1420 // Setup animation parameters
1421 // Start Position
1422 m_startCOPos = m_canvasOptions->GetPosition();
1423
1424 // Present Position
1425 m_currentCOPos = m_startCOPos;
1426
1427 m_animationType = CO_ANIMATION_CUBIC_REVERSE; // CO_ANIMATION_CUBIC_BACK_IN;
1428 m_animateSteps = 10;
1429 m_animationTotalTime = 200; // msec
1430
1431 m_pushPull = CO_PULL;
1432 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
1433 pcc->m_b_paint_enable = false;
1434
1435 // Start the animation....
1436 m_animateStep = 0;
1437 m_canvasOptionsAnimationTimer.Start(10, true);
1438 m_canvasOptions->Move(m_targetCOPos);
1439 m_canvasOptions->Hide();
1440}
1441
1442void MUIBar::PushCanvasOptions() {
1443 if (!m_bEffects) {
1444 m_canvasOptions->Hide();
1445 return;
1446 }
1447
1448 // Setup animation parameters
1449
1450 // Target position
1451 int cox = m_parentCanvas->GetSize().x;
1452 int coy = 20;
1453
1454 if (1)
1455 m_targetCOPos = m_parentCanvas->ClientToScreen(wxPoint(cox, coy));
1456 else
1457 m_targetCOPos = wxPoint(cox, coy);
1458
1459 // Start Position
1460 m_startCOPos = m_canvasOptions->GetPosition();
1461
1462 // Present Position
1463 m_currentCOPos = m_startCOPos;
1464
1465 // Animation type
1466 m_animationType = CO_ANIMATION_LINEAR;
1467 m_animateSteps = 5;
1468 m_animationTotalTime = 100; // msec
1469 m_pushPull = CO_PUSH;
1470 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
1471
1472 // Start the animation....
1473 m_animateStep = 0;
1474 m_canvasOptionsAnimationTimer.Start(10, true);
1475 m_canvasOptions->Show();
1476}
1477
1478void MUIBar::onCanvasOptionsAnimationTimerEvent(wxTimerEvent& event) {
1479 double progress = m_animateStep / (double)m_animateSteps;
1480 double valueX = getValue(m_animationType, progress);
1481
1482 double dx = (m_targetCOPos.x - m_startCOPos.x) * valueX;
1483
1484 wxPoint newPos = wxPoint(m_startCOPos.x + dx, m_currentCOPos.y);
1485
1486 int size_x;
1487 if (m_pushPull == CO_PULL)
1488 size_x = abs(dx);
1489 else
1490 size_x = (m_targetCOPos.x - m_startCOPos.x) - abs(dx);
1491
1492 if (!m_coAnimateByBitmaps) {
1493 m_canvasOptions->SetSize(newPos.x, newPos.y, size_x, wxDefaultCoord,
1494 wxSIZE_USE_EXISTING);
1495 // m_canvasOptions->GetSizer()->Layout();
1496 m_canvasOptions->Show();
1497 } else {
1498 m_canvasOptions->Hide();
1499 wxScreenDC sdc;
1500
1501 if (1 /*m_pushPull == CO_PULL*/) {
1502 // restore Backing bitmap, to cover any overshoot
1503 if (m_backingBitmap.IsOk()) {
1504 wxMemoryDC mdc_back(m_backingBitmap);
1505 sdc.Blit(m_backingPoint.x, m_backingPoint.y,
1506 m_backingBitmap.GetWidth() - size_x,
1507 m_backingBitmap.GetHeight(), &mdc_back, 0, 0, wxCOPY);
1508 }
1509 }
1510
1511 wxMemoryDC mdc(m_animateBitmap);
1512 sdc.Blit(newPos.x, newPos.y, size_x, m_animateBitmap.GetHeight(), &mdc, 0,
1513 0, wxCOPY);
1514 mdc.SelectObject(wxNullBitmap);
1515 }
1516
1517 m_currentCOPos = newPos;
1518
1519 double dt = m_animationTotalTime / m_animateSteps;
1520
1521 if (m_animateStep++ < m_animateSteps + 1) {
1522 m_canvasOptionsAnimationTimer.Start(dt, true);
1523 } else {
1524 m_currentCOPos = m_targetCOPos;
1525 m_canvasOptions->Show(m_pushPull == CO_PULL);
1526
1527 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
1528 if (pcc) {
1529 pcc->m_b_paint_enable = true;
1530
1531 if (m_pushPull == CO_PUSH) {
1532 delete m_canvasOptions;
1533 m_canvasOptions = NULL;
1534 }
1535#ifdef __WXOSX__
1536 if (m_pushPull == CO_PUSH) pcc->TriggerDeferredFocus();
1537#else
1538 pcc->TriggerDeferredFocus();
1539#endif
1540
1541 pcc->Refresh();
1542 }
1543 }
1544}
1545
1546// Animation support
1547
1548double bounceMaker(double t, double c, double a) {
1549 if (t == 1.0) return c;
1550 if (t < (4 / 11.0)) {
1551 return c * (7.5625 * t * t);
1552 } else if (t < (8 / 11.0)) {
1553 t -= (6 / 11.0);
1554 return -a * (1. - (7.5625 * t * t + .75)) + c;
1555 } else if (t < (10 / 11.0)) {
1556 t -= (9 / 11.0);
1557 return -a * (1. - (7.5625 * t * t + .9375)) + c;
1558 } else {
1559 t -= (21 / 22.0);
1560 return -a * (1. - (7.5625 * t * t + .984375)) + c;
1561 }
1562}
1563
1564double getValue(int animationType, double t) {
1565 double value = 0;
1566 double s = 1;
1567 double tp;
1568 switch (animationType) {
1570 default:
1571 value = t;
1572 break;
1573 case CO_ANIMATION_CUBIC:
1574 tp = t - 1.0;
1575 value = tp * tp * tp + 1;
1576 // value = t*t*t;
1577 break;
1579 tp = t - 1.0;
1580 value = tp * tp * tp + 1;
1581 break;
1583 value = bounceMaker(t, 1, s);
1584 break;
1585
1587 tp = t - 1.0;
1588 value = tp * tp * ((s + 1) * tp + s) + 1;
1589 break;
1590 }
1591
1592 return value;
1593}
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartCanvas * g_focusCanvas
Global instance.
Definition chcanv.cpp:1219
Generic Chart canvas base.
Represents the Canvas Options dialog.
ChartCanvas - Main chart display and interaction component.
Definition chcanv.h:157
static bool ShowToolTips()
Should we show tooltips?
Definition mui_bar.cpp:364
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Set scale"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE)
Creation.
Definition mui_bar.cpp:140
void CreateControls()
Definition mui_bar.cpp:157
wxTextCtrl * m_ScaleCtl
Should we show tooltips?
Definition mui_bar.cpp:109
SetScaleDialog()
Constructors.
Definition mui_bar.cpp:123
static TooltipManager & Get()
Get the singleton instance.
Definition tooltip.cpp:308
void HideTooltip()
Hide the current tooltip.
Definition tooltip.cpp:362
void ShowTooltipAtPosition(wxWindow *parent, const wxString &text, const wxPoint &position, bool hiviz=false)
Show tooltip at specified position in absolute screen coordinates (physical pixels).
Definition tooltip.cpp:315
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:60
Global color handling by name.
Global variables stored in configuration file.
Chart display details slider.
OpenGL chart rendering canvas.
Go to position dialog...
GUI constant definitions.
ssfn_font_t * load_font(const char *filename)
Load a font.
Definition mui_bar.cpp:439
MUI (Modern User Interface) Control bar.
@ CO_ANIMATION_CUBIC_REVERSE
Reversed cubic animation.
Definition mui_bar.h:48
@ CO_PULL
Pull animation.
Definition mui_bar.h:49
@ CO_ANIMATION_CUBIC_BACK_IN
Cubic animation with back-in effect.
Definition mui_bar.h:47
@ CO_ANIMATION_CUBIC
Cubic animation.
Definition mui_bar.h:45
@ CO_PUSH
Push animation.
Definition mui_bar.h:50
@ CO_ANIMATION_CUBIC_BOUNCE_IN
Cubic animation with bounce-in effect.
Definition mui_bar.h:46
@ CO_ANIMATION_LINEAR
Linear animation.
Definition mui_bar.h:43
Utility functions.
OpenCPN Platform specific support utilities.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Scalable Screen Font renderer in a single ANSI C/C++ header.
int ssfn_select(ssfn_t *ctx, int family, char *name, int style, int size, int mode)
Set up rendering parameters.
Definition ssfn.h:1060
int ssfn_load(ssfn_t *ctx, const ssfn_font_t *font)
Load a font or font collection into renderer context.
Definition ssfn.h:1015
ssfn_glyph_t * ssfn_render(ssfn_t *ctx, uint32_t unicode)
Glyph renderer.
Definition ssfn.h:1131
int ssfn_bbox(ssfn_t *ctx, char *str, int usekern, int *w, int *h)
Returns the bounding box of the rendered text.
Definition ssfn.h:1452
Definition ssfn.h:181
Chart Symbols.
wxBitmap LoadSVG(const wxString filename, const unsigned int width, const unsigned int height, wxBitmap *default_bitmap, bool use_cache)
Load SVG file and return it's bitmap representation of requested size In case file can't be loaded an...
Definition svg_utils.cpp:59
SVG utilities.