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