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 "canvas_options.h"
42#include "DetailSlider.h"
43#include "GoToPositionDialog.h"
44#include "styles.h"
45#include "navutil.h"
46#include "model/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;
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, "", wxDefaultPosition, wxDefaultSize, 0);
181 itemStaticBoxSizer4->Add(itemStaticText5, 0,
182 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
183
184 m_ScaleCtl = new wxTextCtrl(itemDialog1, ID_SCALECTRL, "", wxDefaultPosition,
185 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("GREY3");
326 // SetBackgroundColour(backColor);
327
328 // this->SetFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
329 // wxFONTWEIGHT_NORMAL, false, "Tahoma"));
330}
331
332void MUIButton::SetColorScheme(ColorScheme cs) {
333#if 1
334 if (m_cs != cs) {
335 wxColour backColor = GetGlobalColor("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("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->ZoomCanvasSimple(factor);
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->ZoomCanvasSimple(factor);
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() + "uidata/MUI_flat/";
906
907 // Build one button to get sizes
908 MUIButton* tb = new MUIButton(m_parentCanvas, ID_ZOOMIN, m_scaleFactor,
909 iconDir + "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 + "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 + "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(
945 m_parentCanvas, ID_FOLLOW, m_scaleFactor, iconDir + "MUI_follow.svg",
946 iconDir + "MUI_follow_active.svg", iconDir + "MUI_follow_ahead.svg");
947 m_followButton->m_position = wxPoint(xoff, 0);
948 xoff += m_followButton->m_size.x;
949#endif
950
951 m_menuButton = new MUIButton(m_parentCanvas, ID_MUI_MENU, m_scaleFactor,
952 iconDir + "MUI_menu.svg");
953 m_menuButton->m_position = wxPoint(xoff, 0);
954 xoff += m_menuButton->m_size.x;
955 m_size.x = xoff;
956 m_size.y = button_size.y;
957
958 } else {
959 int yoff = 0;
960
961 // Buttons
962 if (g_bShowMuiZoomButtons) {
963 m_zinButton = new MUIButton(m_parentCanvas, ID_ZOOMIN, m_scaleFactor,
964 iconDir + "MUI_zoom-in.svg");
965 m_zinButton->m_position = wxPoint(0, yoff);
966 yoff += m_zinButton->m_size.y;
967
968 m_zoutButton = new MUIButton(m_parentCanvas, ID_ZOOMOUT, m_scaleFactor,
969 iconDir + "MUI_zoom-out.svg");
970 m_zoutButton->m_position = wxPoint(0, yoff);
971 yoff += m_zoutButton->m_size.y;
972 }
973
974#ifndef __OCPN__ANDROID__
975 m_followButton = new MUIButton(
976 m_parentCanvas, ID_FOLLOW, m_scaleFactor, iconDir + "MUI_follow.svg",
977 iconDir + "MUI_follow_active.svg", iconDir + "MUI_follow_ahead.svg");
978 m_followButton->m_position = wxPoint(0, yoff);
979 yoff += m_followButton->m_size.y;
980#endif
981
982 m_menuButton = new MUIButton(m_parentCanvas, ID_MUI_MENU, m_scaleFactor,
983 iconDir + "MUI_menu.svg");
984 m_menuButton->m_position = wxPoint(0, yoff);
985 yoff += m_menuButton->m_size.y;
986
987 m_size.y = yoff;
988 m_size.x = button_size.x;
989 }
990}
991
992void MUIBar::SetBestPosition(void) {
993 int x =
994 (m_parentCanvas->GetClientSize().x - (m_size.x + (m_end_margin) * 2.00));
995
996 int bottomOffset = 6;
997
998 int y = m_parentCanvas->GetClientSize().y - m_size.y - bottomOffset;
999 // if ( g_bopengl){
1000 // y -= m_parentCanvas->GetClientSize().y % 1;
1001 // }
1002
1003 wxPoint position = wxPoint(x, y);
1004 m_screenPos = position;
1005
1006 if (m_canvasOptions) {
1007 m_canvasOptions->Destroy();
1008 m_canvasOptions = 0;
1009 }
1010}
1011
1012void MUIBar::UpdateDynamicValues() {
1013 if (!m_scaleButton) return;
1014
1015 wxString scaleString;
1016 int scale = m_parentCanvas->GetScaleValue();
1017
1018 if (scale != m_scale) InvalidateBitmap();
1019 m_scale = scale;
1020
1021 if (scale < 1e6)
1022 scaleString.Printf("1:%d", scale);
1023 else
1024 scaleString.Printf("1:%4.1f M", scale / 1e6);
1025
1026 if (m_scaleButton) m_scaleButton->SetText(scaleString);
1027}
1028
1029void MUIBar::SetFollowButtonState(int state) {
1030 if (m_followButton && m_followButton->GetState() != state) {
1031 m_followButton->SetState(state);
1032 InvalidateBitmap();
1033 }
1034}
1035
1036void MUIBar::HandleMenuClick() {
1037 if (!m_canvasOptions) {
1038 m_canvasOptions = new CanvasOptions(m_parentCanvas);
1039
1040 // calculate best size for CanvasOptions dialog
1041
1042 wxPoint parentClientUpperRight =
1043 m_parentCanvas->ClientToScreen(wxPoint(m_parentCanvas->GetSize().x, 0));
1044 wxPoint muibar_top = m_parentCanvas->ClientToScreen(m_screenPos);
1045 int size_y = muibar_top.y - (parentClientUpperRight.y + m_COTopOffset);
1046 size_y -= m_parentCanvas->GetCharHeight();
1047 size_y = wxMax(size_y, 100); // ensure always big enough to see
1048
1049 m_canvasOptions->SetSize(wxSize(-1, size_y));
1050 m_canvasOptionsFullSize = m_canvasOptions->GetSize();
1051 m_canvasOptionsFullSize.x +=
1052 m_canvasOptions->GetCharWidth(); // Allow for scroll bar, since
1053 // sizer won't do it.
1054
1055 m_currentCOPos = m_parentCanvas->ClientToScreen(
1056 wxPoint(m_parentCanvas->GetSize().x, m_COTopOffset));
1057
1058 m_canvasOptions->Move(m_currentCOPos);
1059 m_canvasOptions->Hide();
1060 }
1061
1062 m_canvasOptions->SetENCAvailable(m_CanvasENCAvail);
1063
1064 if (m_canvasOptions->IsShown())
1065 PushCanvasOptions(); // hide it
1066 else {
1067 // Grab the backing bitmap, if available
1068
1069 if (m_coAnimateByBitmaps && m_capture_size_y) {
1070 int overShoot_x = m_canvasOptions->GetSize().x * 2 / 10; // 20%
1071 m_backingPoint =
1072 wxPoint(m_capturePoint.x - overShoot_x, m_capturePoint.y);
1073
1074 m_backingBitmap = wxBitmap(m_canvasOptionsFullSize.x + overShoot_x,
1075 m_capture_size_y, -1);
1076 wxMemoryDC mdcb;
1077 mdcb.SelectObject(m_backingBitmap);
1078 wxScreenDC sdc;
1079 mdcb.Blit(0, 0, m_canvasOptionsFullSize.x + overShoot_x, m_capture_size_y,
1080 &sdc, m_capturePoint.x - overShoot_x, m_capturePoint.y, wxCOPY);
1081 mdcb.SelectObject(wxNullBitmap);
1082 }
1083 PullCanvasOptions();
1084 }
1085}
1086
1087void MUIBar::CaptureCanvasOptionsBitmap() {
1088 m_coSequence = 0;
1089 CanvasOptionTimer.Start(100, wxTIMER_ONE_SHOT);
1090}
1091
1092void MUIBar::CaptureCanvasOptionsBitmapChain(wxTimerEvent& event) {
1093 if (m_coSequence == 0) {
1094 if (!m_canvasOptions) m_canvasOptions = new CanvasOptions(m_parentCanvas);
1095
1096 wxPoint parentClientUpperRight =
1097 m_parentCanvas->ClientToScreen(wxPoint(m_parentCanvas->GetSize().x, 0));
1098 wxRect rmui = m_parentCanvas->GetMUIBarRect();
1099 int size_y = rmui.y - (parentClientUpperRight.y + m_COTopOffset);
1100 size_y -= m_parentCanvas->GetCharHeight();
1101 size_y = wxMax(size_y, 100); // ensure always big enough to see
1102 m_capture_size_y = size_y;
1103
1104 m_canvasOptions->SetSize(wxSize(-1, size_y));
1105
1106 m_capturePoint = m_parentCanvas->ClientToScreen(
1107 wxPoint(m_parentCanvas->GetSize().x, m_COTopOffset));
1108 m_canvasOptions->Move(m_capturePoint);
1109 m_canvasOptions->Show();
1110
1111 m_coSequence++;
1112 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
1113 }
1114
1115 else if (m_coSequence == 1) {
1116 m_capturePoint = m_parentCanvas->ClientToScreen(
1117 wxPoint(m_parentCanvas->GetSize().x - m_canvasOptionsFullSize.x,
1118 m_COTopOffset));
1119 m_canvasOptions->Move(m_capturePoint);
1120
1121 m_coSequence++;
1122 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
1123 }
1124
1125 else if (m_coSequence == 2) {
1126 m_animateBitmap =
1127 wxBitmap(m_canvasOptions->GetSize().x, m_capture_size_y, -1);
1128 wxMemoryDC mdc(m_animateBitmap);
1129
1130 wxScreenDC sdc;
1131
1132 mdc.Blit(0, 0, m_canvasOptions->GetSize().x, m_capture_size_y, &sdc,
1133 m_capturePoint.x, m_capturePoint.y, wxCOPY);
1134 mdc.SelectObject(wxNullBitmap);
1135
1136 // delete m_canvasOptions;
1137 // m_canvasOptions = NULL;
1138 }
1139}
1140
1141wxBitmap& MUIBar::CreateBitmap(double displayScale) {
1142 if (m_bitmap.IsOk()) return m_bitmap;
1143
1144 // Make the bitmap
1145 int width = m_size.x;
1146 int height = m_size.y;
1147
1148 wxMemoryDC mdc;
1149 wxBitmap bm(width, height);
1150 mdc.SelectObject(bm);
1151 mdc.SetBackground(wxBrush(GetBackgroundColor()));
1152
1153 mdc.Clear();
1154
1155 wxBitmap bmd;
1156 if (g_bShowMuiZoomButtons) {
1157 wxBitmap bmd = m_zinButton->GetButtonBitmap();
1158 if (bmd.IsOk())
1159 mdc.DrawBitmap(bmd, m_zinButton->m_position.x, m_zinButton->m_position.y,
1160 false);
1161
1162 bmd = m_zoutButton->GetButtonBitmap();
1163 if (bmd.IsOk())
1164 mdc.DrawBitmap(bmd, m_zoutButton->m_position.x,
1165 m_zoutButton->m_position.y, false);
1166 }
1167
1168 if (m_scaleButton) {
1169 bmd = m_scaleButton->GetButtonBitmap();
1170 if (bmd.IsOk()) {
1171 int bm_pos_y = (m_scaleButton->GetSize().y - bmd.GetHeight()) / 2;
1172 int bm_pos_x = m_scaleButton->m_position.x +
1173 (m_scaleButton->GetSize().x - bmd.GetWidth()) / 2;
1174
1175 mdc.DrawBitmap(bmd, bm_pos_x, bm_pos_y, false);
1176 }
1177 }
1178
1179 if (m_followButton) {
1180 bmd = m_followButton->GetButtonBitmap();
1181 if (bmd.IsOk())
1182 mdc.DrawBitmap(bmd, m_followButton->m_position.x,
1183 m_followButton->m_position.y, false);
1184 }
1185
1186 if (m_menuButton) {
1187 bmd = m_menuButton->GetButtonBitmap();
1188 if (bmd.IsOk())
1189 mdc.DrawBitmap(bmd, m_menuButton->m_position.x,
1190 m_menuButton->m_position.y, false);
1191 }
1192
1193 mdc.SelectObject(wxNullBitmap);
1194
1195 m_bitmap = bm;
1196 return m_bitmap;
1197}
1198
1199void MUIBar::DrawGL(ocpnDC& gldc, double displayScale) {
1200#ifdef ocpnUSE_GL
1201
1202 wxColour backColor = GetBackgroundColor();
1203 gldc.SetBrush(wxBrush(backColor));
1204 gldc.SetPen(wxPen(backColor));
1205
1206 wxRect r = wxRect(m_screenPos, m_size);
1207 if (m_orientation == wxHORIZONTAL)
1208 gldc.DrawRoundedRectangle(
1209 (r.x - m_end_margin / 2) * displayScale, (r.y - 1) * displayScale,
1210 (r.width + m_end_margin) * displayScale, (r.height + 2) * displayScale,
1211 (m_end_margin * 1) * displayScale);
1212 else
1213 gldc.DrawRoundedRectangle((r.x - 1) * displayScale,
1214 (r.y - m_end_margin / 2) * displayScale,
1215 (r.width + 2) * displayScale,
1216 (r.height + 2 * m_end_margin) * displayScale,
1217 (m_end_margin * 1.5) * displayScale);
1218
1219 int width = m_size.x;
1220 int height = m_size.y;
1221
1222 CreateBitmap(displayScale);
1223
1224 // Make a GL texture
1225 if (!m_texture) {
1226 glGenTextures(1, &m_texture);
1227
1228 glBindTexture(g_texture_rectangle_format, m_texture);
1229 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
1230 GL_NEAREST);
1231 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
1232 GL_NEAREST);
1233 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_WRAP_S,
1234 GL_CLAMP_TO_EDGE);
1235 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_WRAP_T,
1236 GL_CLAMP_TO_EDGE);
1237 } else {
1238 glBindTexture(g_texture_rectangle_format, m_texture);
1239 }
1240
1241 // fill texture data
1242 if (m_bitmap.IsOk()) {
1243 wxImage image = m_bitmap.ConvertToImage();
1244 if (image.IsOk()) {
1245 unsigned char* d = image.GetData();
1246 if (d) {
1247 unsigned char* e = new unsigned char[4 * width * height];
1248 for (int y = 0; y < height; y++)
1249 for (int x = 0; x < width; x++) {
1250 int i = y * width + x;
1251 memcpy(e + 4 * i, d + 3 * i, 3);
1252 e[4 * i + 3] =
1253 255; // d[3*i + 2] == 255 ? 0:255; //255 - d[3 * i + 2];
1254 }
1255 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, width, height, 0,
1256 GL_RGBA, GL_UNSIGNED_BYTE, e);
1257 delete[] e;
1258 glDisable(g_texture_rectangle_format);
1259 glDisable(GL_BLEND);
1260 }
1261 }
1262 }
1263
1264 // Render the texture
1265 if (m_texture) {
1266 glEnable(g_texture_rectangle_format);
1267 glBindTexture(g_texture_rectangle_format, m_texture);
1268 glEnable(GL_BLEND);
1269
1270 int x0 = m_screenPos.x, x1 = x0 + width;
1271 int y0 = m_screenPos.y - 0, y1 = y0 + height;
1272 x0 *= displayScale;
1273 x1 *= displayScale;
1274 y0 *= displayScale;
1275 y1 *= displayScale;
1276
1277 float tx, ty;
1278 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format)
1279 tx = width, ty = height;
1280 else
1281 tx = ty = 1;
1282
1283 float coords[8];
1284 float uv[8];
1285
1286 // normal uv
1287 uv[0] = 0;
1288 uv[1] = 0;
1289 uv[2] = tx;
1290 uv[3] = 0;
1291 uv[4] = tx;
1292 uv[5] = ty;
1293 uv[6] = 0;
1294 uv[7] = ty;
1295
1296 // pixels
1297 coords[0] = x0;
1298 coords[1] = y0;
1299 coords[2] = x1;
1300 coords[3] = y0;
1301 coords[4] = x1;
1302 coords[5] = y1;
1303 coords[6] = x0;
1304 coords[7] = y1;
1305
1306 m_parentCanvas->GetglCanvas()->RenderTextures(gldc, coords, uv, 4,
1307 m_parentCanvas->GetpVP());
1308
1309 glDisable(g_texture_rectangle_format);
1310 glBindTexture(g_texture_rectangle_format, 0);
1311 glDisable(GL_BLEND);
1312 }
1313#endif
1314
1315 return;
1316}
1317
1318void MUIBar::DrawDC(ocpnDC& dc, double displayScale) {
1319 CreateBitmap(1.0);
1320 dc.DrawBitmap(m_bitmap, m_screenPos.x, m_screenPos.y, false);
1321}
1322
1323void MUIBar::ResetCanvasOptions() {
1324 delete m_canvasOptions;
1325 m_canvasOptions = NULL;
1326}
1327
1328void MUIBar::PullCanvasOptions() {
1329 // Target position
1330 int cox = m_parentCanvas->GetSize().x - m_canvasOptionsFullSize.x;
1331 int coy = m_COTopOffset;
1332 m_targetCOPos = m_parentCanvas->ClientToScreen(wxPoint(cox, coy));
1333
1334 if (!m_bEffects) {
1335 m_canvasOptions->Move(m_targetCOPos);
1336 m_canvasOptions->Show();
1337 return;
1338 }
1339
1340 // Capture the animation bitmap, if required..
1341
1342 if (m_coAnimateByBitmaps && !m_animateBitmap.IsOk()) {
1343 m_canvasOptions->Move(m_targetCOPos);
1344 m_canvasOptions->Show();
1345 CaptureCanvasOptionsBitmap();
1346 return;
1347 }
1348
1349 // Setup animation parameters
1350 // Start Position
1351 m_startCOPos = m_canvasOptions->GetPosition();
1352
1353 // Present Position
1354 m_currentCOPos = m_startCOPos;
1355
1356 m_animationType = CO_ANIMATION_CUBIC_REVERSE; // CO_ANIMATION_CUBIC_BACK_IN;
1357 m_animateSteps = 10;
1358 m_animationTotalTime = 200; // msec
1359
1360 m_pushPull = CO_PULL;
1361 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
1362 pcc->m_b_paint_enable = false;
1363
1364 // Start the animation....
1365 m_animateStep = 0;
1366 m_canvasOptionsAnimationTimer.Start(10, true);
1367 m_canvasOptions->Move(m_targetCOPos);
1368 m_canvasOptions->Hide();
1369}
1370
1371void MUIBar::PushCanvasOptions() {
1372 if (!m_bEffects) {
1373 m_canvasOptions->Hide();
1374 return;
1375 }
1376
1377 // Setup animation parameters
1378
1379 // Target position
1380 int cox = m_parentCanvas->GetSize().x;
1381 int coy = 20;
1382
1383 if (1)
1384 m_targetCOPos = m_parentCanvas->ClientToScreen(wxPoint(cox, coy));
1385 else
1386 m_targetCOPos = wxPoint(cox, coy);
1387
1388 // Start Position
1389 m_startCOPos = m_canvasOptions->GetPosition();
1390
1391 // Present Position
1392 m_currentCOPos = m_startCOPos;
1393
1394 // Animation type
1395 m_animationType = CO_ANIMATION_LINEAR;
1396 m_animateSteps = 5;
1397 m_animationTotalTime = 100; // msec
1398 m_pushPull = CO_PUSH;
1399 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
1400
1401 // Start the animation....
1402 m_animateStep = 0;
1403 m_canvasOptionsAnimationTimer.Start(10, true);
1404 m_canvasOptions->Show();
1405}
1406
1407void MUIBar::onCanvasOptionsAnimationTimerEvent(wxTimerEvent& event) {
1408 double progress = m_animateStep / (double)m_animateSteps;
1409 double valueX = getValue(m_animationType, progress);
1410
1411 double dx = (m_targetCOPos.x - m_startCOPos.x) * valueX;
1412
1413 wxPoint newPos = wxPoint(m_startCOPos.x + dx, m_currentCOPos.y);
1414
1415 int size_x;
1416 if (m_pushPull == CO_PULL)
1417 size_x = abs(dx);
1418 else
1419 size_x = (m_targetCOPos.x - m_startCOPos.x) - abs(dx);
1420
1421 if (!m_coAnimateByBitmaps) {
1422 m_canvasOptions->SetSize(newPos.x, newPos.y, size_x, wxDefaultCoord,
1423 wxSIZE_USE_EXISTING);
1424 // m_canvasOptions->GetSizer()->Layout();
1425 m_canvasOptions->Show();
1426 } else {
1427 m_canvasOptions->Hide();
1428 wxScreenDC sdc;
1429
1430 if (1 /*m_pushPull == CO_PULL*/) {
1431 // restore Backing bitmap, to cover any overshoot
1432 if (m_backingBitmap.IsOk()) {
1433 wxMemoryDC mdc_back(m_backingBitmap);
1434 sdc.Blit(m_backingPoint.x, m_backingPoint.y,
1435 m_backingBitmap.GetWidth() - size_x,
1436 m_backingBitmap.GetHeight(), &mdc_back, 0, 0, wxCOPY);
1437 }
1438 }
1439
1440 wxMemoryDC mdc(m_animateBitmap);
1441 sdc.Blit(newPos.x, newPos.y, size_x, m_animateBitmap.GetHeight(), &mdc, 0,
1442 0, wxCOPY);
1443 mdc.SelectObject(wxNullBitmap);
1444 }
1445
1446 m_currentCOPos = newPos;
1447
1448 double dt = m_animationTotalTime / m_animateSteps;
1449
1450 if (m_animateStep++ < m_animateSteps + 1) {
1451 m_canvasOptionsAnimationTimer.Start(dt, true);
1452 } else {
1453 m_currentCOPos = m_targetCOPos;
1454 m_canvasOptions->Show(m_pushPull == CO_PULL);
1455
1456 auto pcc = dynamic_cast<ChartCanvas*>(m_parentCanvas);
1457 if (pcc) {
1458 pcc->m_b_paint_enable = true;
1459
1460 if (m_pushPull == CO_PUSH) {
1461 delete m_canvasOptions;
1462 m_canvasOptions = NULL;
1463 }
1464#ifdef __WXOSX__
1465 if (m_pushPull == CO_PUSH) pcc->TriggerDeferredFocus();
1466#else
1467 pcc->TriggerDeferredFocus();
1468#endif
1469
1470 pcc->Refresh();
1471 }
1472 }
1473}
1474
1475// Animation support
1476
1477double bounceMaker(double t, double c, double a) {
1478 if (t == 1.0) return c;
1479 if (t < (4 / 11.0)) {
1480 return c * (7.5625 * t * t);
1481 } else if (t < (8 / 11.0)) {
1482 t -= (6 / 11.0);
1483 return -a * (1. - (7.5625 * t * t + .75)) + c;
1484 } else if (t < (10 / 11.0)) {
1485 t -= (9 / 11.0);
1486 return -a * (1. - (7.5625 * t * t + .9375)) + c;
1487 } else {
1488 t -= (21 / 22.0);
1489 return -a * (1. - (7.5625 * t * t + .984375)) + c;
1490 }
1491}
1492
1493double getValue(int animationType, double t) {
1494 double value = 0;
1495 double s = 1;
1496 double tp;
1497 switch (animationType) {
1498 case CO_ANIMATION_LINEAR:
1499 default:
1500 value = t;
1501 break;
1502 case CO_ANIMATION_CUBIC:
1503 tp = t - 1.0;
1504 value = tp * tp * tp + 1;
1505 // value = t*t*t;
1506 break;
1507 case CO_ANIMATION_CUBIC_REVERSE:
1508 tp = t - 1.0;
1509 value = tp * tp * tp + 1;
1510 break;
1511 case CO_ANIMATION_CUBIC_BOUNCE_IN:
1512 value = bounceMaker(t, 1, s);
1513 break;
1514
1515 case CO_ANIMATION_CUBIC_BACK_IN:
1516 tp = t - 1.0;
1517 value = tp * tp * ((s + 1) * tp + s) + 1;
1518 break;
1519 }
1520
1521 return value;
1522}
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartCanvas * g_focusCanvas
Global instance.
Definition chcanv.cpp:1194
Generic Chart canvas base.
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:60
Global color handling by name.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Definition ssfn.h:176
SVG utilities.