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