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