OpenCPN Partial API docs
Loading...
Searching...
No Matches
MUIBar.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: MUI Control Bar
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2018 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 ***************************************************************************
25 *
26 *
27 */
28
29#include <wx/wxprec.h>
30
31#ifndef WX_PRECOMP
32#include <wx/wx.h>
33#endif // precompiled headers
34
35#include <wx/statline.h>
36
37#include "chcanv.h"
38#include "MUIBar.h"
39#include "OCPNPlatform.h"
40#include "CanvasOptions.h"
41#include "DetailSlider.h"
42#include "GoToPositionDialog.h"
43#include "styles.h"
44#include "navutil.h"
45#include "svg_utils.h"
46#include "idents.h"
47#include "color_handler.h"
48
49#ifdef __OCPN__ANDROID__
50#include "androidUTIL.h"
51#include "qdebug.h"
52#endif
53
54//------------------------------------------------------------------------------
55// External Static Storage
56//------------------------------------------------------------------------------
57
58extern OCPNPlatform* g_Platform;
59extern ChartCanvas* g_focusCanvas;
60extern ocpnStyle::StyleManager* g_StyleManager;
61extern bool g_bShowMuiZoomButtons;
62
63double getValue(int animationType, double t);
64
65// Helper classes
66
67#define ID_SCALE_CANCEL 8301
68#define ID_SCALE_OK 8302
69#define ID_SCALECTRL 8303
70
71class SetScaleDialog : public wxDialog {
72 DECLARE_EVENT_TABLE()
73
74public:
77 SetScaleDialog(wxWindow* parent, wxWindowID id = SYMBOL_GOTOPOS_IDNAME,
78 const wxString& caption = _("Set scale"),
79 const wxPoint& pos = wxDefaultPosition,
80 const wxSize& size = wxDefaultSize,
81 long style = wxDEFAULT_DIALOG_STYLE);
82
84
86 bool Create(wxWindow* parent, wxWindowID id = wxID_ANY,
87 const wxString& caption = _("Set scale"),
88 const wxPoint& pos = wxDefaultPosition,
89 const wxSize& size = wxDefaultSize,
90 long style = wxDEFAULT_DIALOG_STYLE);
91
92 void SetColorScheme(ColorScheme cs);
93
94 void CreateControls();
95
96 void OnSetScaleCancelClick(wxCommandEvent& event);
97 void OnSetScaleOKClick(wxCommandEvent& event);
98
100
101 wxTextCtrl* m_ScaleCtl;
102 wxButton* m_CancelButton;
103 wxButton* m_OKButton;
104};
105
106BEGIN_EVENT_TABLE(SetScaleDialog, wxDialog)
107EVT_BUTTON(ID_GOTOPOS_CANCEL, SetScaleDialog::OnSetScaleCancelClick)
108EVT_BUTTON(ID_GOTOPOS_OK, SetScaleDialog::OnSetScaleOKClick)
109END_EVENT_TABLE()
110
111
116
117SetScaleDialog::SetScaleDialog(wxWindow* parent, wxWindowID id,
118 const wxString& caption, const wxPoint& pos,
119 const wxSize& size, long style) {
120 long wstyle =
121 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT;
122
123 Create(parent, id, caption, pos, size, wstyle);
124}
125
126SetScaleDialog::~SetScaleDialog() {}
127
132bool SetScaleDialog::Create(wxWindow* parent, wxWindowID id,
133 const wxString& caption, const wxPoint& pos,
134 const wxSize& size, long style) {
135 SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
136 wxDialog::Create(parent, id, caption, pos, size, style);
137
139 GetSizer()->SetSizeHints(this);
140 Centre();
141
142 return TRUE;
143}
144
150 SetScaleDialog* itemDialog1 = this;
151
152 wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
153 itemDialog1->SetSizer(itemBoxSizer2);
154
155 wxStaticBox* itemStaticBoxSizer4Static =
156 new wxStaticBox(itemDialog1, wxID_ANY, _("Chart Scale"));
157
158 wxStaticBoxSizer* itemStaticBoxSizer4 =
159 new wxStaticBoxSizer(itemStaticBoxSizer4Static, wxVERTICAL);
160 itemBoxSizer2->Add(itemStaticBoxSizer4, 0, wxEXPAND | wxALL, 5);
161
162 wxStaticText* itemStaticText5 = new wxStaticText(
163 itemDialog1, wxID_STATIC, _T(""), wxDefaultPosition, wxDefaultSize, 0);
164 itemStaticBoxSizer4->Add(itemStaticText5, 0,
165 wxALIGN_LEFT | wxLEFT | wxRIGHT | wxTOP, 5);
166
167 m_ScaleCtl = new wxTextCtrl(itemDialog1, ID_SCALECTRL, _T(""),
168 wxDefaultPosition, wxSize(180, -1), 0);
169 itemStaticBoxSizer4->Add(
170 m_ScaleCtl, 0, wxALIGN_LEFT | wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
171
172 wxBoxSizer* itemBoxSizer16 = new wxBoxSizer(wxHORIZONTAL);
173 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
174
175 m_CancelButton = new wxButton(itemDialog1, ID_GOTOPOS_CANCEL, _("Cancel"),
176 wxDefaultPosition, wxDefaultSize, 0);
177 itemBoxSizer16->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
178
179 m_OKButton = new wxButton(itemDialog1, ID_GOTOPOS_OK, _("OK"),
180 wxDefaultPosition, wxDefaultSize, 0);
181 itemBoxSizer16->Add(m_OKButton, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
182 m_OKButton->SetDefault();
183
184 SetColorScheme((ColorScheme)0);
185}
186
187void SetScaleDialog::SetColorScheme(ColorScheme cs) { DimeControl(this); }
188
189void SetScaleDialog::OnSetScaleCancelClick(wxCommandEvent& event) {
190 Close();
191 event.Skip();
192}
193
194void SetScaleDialog::OnSetScaleOKClick(wxCommandEvent& event) {
195 SetReturnCode(wxID_OK);
196 EndModal(wxID_OK);
197 return;
198}
199
200//------------------------------------------------------------------------------
201// MUIButton Static Storage
202//------------------------------------------------------------------------------
203
204class MUIButton : public wxWindow {
205 DECLARE_DYNAMIC_CLASS(MUIButton)
206 DECLARE_EVENT_TABLE()
207
208 wxSize DoGetBestSize() const;
209
210public:
211 MUIButton();
212 MUIButton(wxWindow* parent, wxWindowID id = wxID_ANY,
213 float scale_factor = 1.0,
214 const wxString& bitmapState0 = wxEmptyString,
215 const wxString& bitmapState1 = wxEmptyString,
216 const wxString& bitmapState2 = wxEmptyString,
217 const wxPoint& pos = wxDefaultPosition,
218 const wxSize& size = wxDefaultSize, long style = wxNO_BORDER);
219
220 bool Create(wxWindow* parent, wxWindowID id = wxID_ANY,
221 float scale_factor = 1.0,
222 const wxString& bitmapState0 = wxEmptyString,
223 const wxString& bitmapState1 = wxEmptyString,
224 const wxString& bitmapState2 = wxEmptyString,
225 const wxPoint& pos = wxDefaultPosition,
226 const wxSize& size = wxDefaultSize, long style = wxNO_BORDER);
227
228 ~MUIButton();
229
230 void Init();
231 void CreateControls();
232
233 void SetState(int state);
234
235 void SetColorScheme(ColorScheme cs);
236 void OnSize(wxSizeEvent& event);
237 void OnPaint(wxPaintEvent& event);
238 void OnLeftDown(wxMouseEvent& event);
239 void OnLeftUp(wxMouseEvent& event);
240
241 wxBitmap GetBitmapResource(const wxString& name);
242
243 wxIcon GetIconResource(const wxString& name);
244
246 static bool ShowToolTips();
247
248private:
249 wxString m_bitmapFileState0;
250 wxString m_bitmapFileState1;
251 wxString m_bitmapFileState2;
252 wxBitmap m_bitmap;
253 wxBitmap m_bitmapState0;
254 wxBitmap m_bitmapState1;
255 wxBitmap m_bitmapState2;
256
257 int mState;
258 float m_scaleFactor;
259 wxSize m_styleToolSize;
260 ColorScheme m_cs;
261};
262
263IMPLEMENT_DYNAMIC_CLASS(MUIButton, wxWindow)
264
265BEGIN_EVENT_TABLE(MUIButton, wxWindow)
266
267EVT_SIZE(MUIButton::OnSize)
268EVT_PAINT(MUIButton::OnPaint)
269EVT_LEFT_DOWN(MUIButton::OnLeftDown)
270EVT_LEFT_UP(MUIButton::OnLeftUp)
271
272END_EVENT_TABLE()
273
274MUIButton::MUIButton() { Init(); }
275
276MUIButton::MUIButton(wxWindow* parent, wxWindowID id, float scale_factor,
277 const wxString& bitmap, const wxString& bitmapState1,
278 const wxString& bitmapState2, const wxPoint& pos,
279 const wxSize& size, long style) {
280 Init();
281 Create(parent, id, scale_factor, bitmap, bitmapState1, bitmapState2, pos,
282 size, style);
283}
284
285bool MUIButton::Create(wxWindow* parent, wxWindowID id, float scale_factor,
286 const wxString& bitmap, const wxString& bitmapState1,
287 const wxString& bitmapState2, const wxPoint& pos,
288 const wxSize& size, long style) {
289 wxWindow::Create(parent, id, pos, size, style);
290 m_bitmapFileState0 = bitmap;
291 m_bitmapFileState1 = bitmapState1;
292 m_bitmapFileState2 = bitmapState2;
293
294 m_scaleFactor = scale_factor;
295
296 m_styleToolSize = g_StyleManager->GetCurrentStyle()->GetToolSize();
297
298 // Arbitrarily boost the MUIButton default size above the style defined size.
299 // No good reason.....
300 m_styleToolSize = wxSize(m_styleToolSize.x * 1.25, m_styleToolSize.y * 1.25);
301
302 CreateControls();
303 return true;
304}
305
306MUIButton::~MUIButton() {}
307
308void MUIButton::Init() {
309 mState = 0;
310 m_cs = (ColorScheme)-1; // GLOBAL_COLOR_SCHEME_RGB;
311}
312
313void MUIButton::CreateControls() {
314 this->SetForegroundColour(wxColour(255, 255, 255));
315
316 wxColour backColor = GetGlobalColor(_T("GREY3"));
317 SetBackgroundColour(backColor);
318
319 this->SetFont(wxFont(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
320 wxFONTWEIGHT_BOLD, false, wxT("Tahoma")));
321}
322
323void MUIButton::SetColorScheme(ColorScheme cs) {
324 if (m_cs != cs) {
325 wxColour backColor = GetGlobalColor(_T("GREY3"));
326 SetBackgroundColour(backColor);
327
328 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
329
330 wxBitmap bmp = LoadSVG(m_bitmapFileState0, GetSize().x, GetSize().y);
331 m_bitmapState0 = style->SetBitmapBrightness(bmp, cs);
332
333 bmp = LoadSVG(m_bitmapFileState1, GetSize().x, GetSize().y);
334 if (bmp.IsOk())
335 m_bitmapState1 = style->SetBitmapBrightness(bmp, cs);
336 else
337 m_bitmapState1 = m_bitmapState0;
338
339 bmp = LoadSVG(m_bitmapFileState2, GetSize().x, GetSize().y);
340 if (bmp.IsOk())
341 m_bitmapState2 = style->SetBitmapBrightness(bmp, cs);
342 else
343 m_bitmapState2 = m_bitmapState0;
344
345 switch (mState) {
346 case 0:
347 default:
348 m_bitmap = m_bitmapState0;
349 break;
350
351 case 1:
352 m_bitmap = m_bitmapState1;
353 break;
354
355 case 2:
356 m_bitmap = m_bitmapState2;
357 break;
358 }
359
360 m_cs = cs;
361 }
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 Refresh();
385}
386
387void MUIButton::OnSize(wxSizeEvent& event) {
388 if (m_bitmap.IsOk()) {
389 if (event.GetSize() == m_bitmap.GetSize()) return;
390 }
391
392 if (!m_bitmapFileState0.IsEmpty())
393 m_bitmapState0 =
394 LoadSVG(m_bitmapFileState0, event.GetSize().x, event.GetSize().y);
395
396 if (!m_bitmapFileState1.IsEmpty())
397 m_bitmapState1 =
398 LoadSVG(m_bitmapFileState1, event.GetSize().x, event.GetSize().y);
399 if (!m_bitmapState1.IsOk() || m_bitmapFileState1.IsEmpty())
400 m_bitmapState1 = m_bitmapState0;
401
402 if (!m_bitmapFileState2.IsEmpty())
403 m_bitmapState2 =
404 LoadSVG(m_bitmapFileState2, event.GetSize().x, event.GetSize().y);
405 if (!m_bitmapState2.IsOk() || m_bitmapFileState2.IsEmpty())
406 m_bitmapState2 = m_bitmapState0;
407
408 switch (mState) {
409 case 0:
410 default:
411 m_bitmap = m_bitmapState0;
412 break;
413
414 case 1:
415 m_bitmap = m_bitmapState1;
416 break;
417
418 case 2:
419 m_bitmap = m_bitmapState2;
420 break;
421 }
422}
423
424wxBitmap MUIButton::GetBitmapResource(const wxString& name) {
425 // Bitmap retrieval
426 wxUnusedVar(name);
427 return wxNullBitmap;
428}
429
430wxIcon MUIButton::GetIconResource(const wxString& name) {
431 // Icon retrieval
432 wxUnusedVar(name);
433 return wxNullIcon;
434}
435
436wxSize MUIButton::DoGetBestSize() const {
437 // wxSize labelSize = wxDefaultSize;
438 // GetTextExtent(m_Label, &labelSize.x, &labelSize.y);
439 // return wxSize(wxMax(40, labelSize.x + 20), wxMax(20, labelSize.y +
440 // 10));
441 return wxSize(m_styleToolSize.x * m_scaleFactor,
442 m_styleToolSize.y * m_scaleFactor);
443}
444
445void MUIButton::OnPaint(wxPaintEvent& event) {
446 wxPaintDC dc(this);
447
448 if (m_bitmap.IsOk()) {
449 dc.DrawBitmap(m_bitmap, 0, 0, true);
450 }
451
452#if 0
453 wxBufferedPaintDC dc(this);
454
455 wxRect clientRect = GetClientRect();
456 wxRect gradientRect = clientRect;
457 gradientRect.SetHeight(gradientRect.GetHeight()/2 + ((GetCapture() == this) ? 1 : 0));
458 if(GetCapture() != this)
459 {
460 dc.GradientFillLinear(gradientRect,
461 m_GradientTopStartColour, m_GradientTopEndColour, wxSOUTH);
462 }
463 else
464 {
465 dc.SetPen(wxPen(m_PressedColourTop));
466 dc.SetBrush(wxBrush(m_PressedColourTop));
467 dc.DrawRectangle(gradientRect);
468 }
469
470 gradientRect.Offset(0, gradientRect.GetHeight());
471
472 if(GetCapture() != this)
473 {
474 dc.GradientFillLinear(gradientRect,
475 m_GradientBottomStartColour, m_GradientBottomEndColour, wxSOUTH);
476 }
477 else
478 {
479 dc.SetPen(wxPen(m_PressedColourBottom));
480 dc.SetBrush(wxBrush(m_PressedColourBottom));
481 dc.DrawRectangle(gradientRect);
482 }
483 dc.SetPen(wxPen(GetBackgroundColour()));
484 dc.SetBrush(*wxTRANSPARENT_BRUSH);
485 dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
486 dc.SetFont(GetFont());
487 dc.SetTextForeground(GetForegroundColour());
488 if(GetCapture() == this)
489 {
490 clientRect.Offset(1, 1);
491 }
492 dc.DrawLabel(m_Label, clientRect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);
493#endif
494}
495
496#if 1
497void MUIButton::OnLeftDown(wxMouseEvent& event) { event.Skip(); }
498
499void MUIButton::OnLeftUp(wxMouseEvent& event) {
500 if (GetClientRect().Contains(event.GetPosition())) {
501 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, GetId());
502 GetParent()->GetEventHandler()->AddPendingEvent(evt);
503 }
504 event.Skip();
505}
506#endif
507
508#define CANVAS_OPTIONS_ANIMATION_TIMER_1 800
509#define CANVAS_OPTIONS_TIMER 801
510
511//------------------------------------------------------------------------------
512// MUIBar Window Implementation
513//------------------------------------------------------------------------------
514BEGIN_EVENT_TABLE(MUIBar, wxFrame)
515EVT_TIMER(CANVAS_OPTIONS_ANIMATION_TIMER_1,
516 MUIBar::onCanvasOptionsAnimationTimerEvent)
517// EVT_PAINT ( MUIBar::OnPaint )
518EVT_SIZE(MUIBar::OnSize)
519EVT_MENU(-1, MUIBar::OnToolLeftClick)
520EVT_TIMER(CANVAS_OPTIONS_TIMER, MUIBar::CaptureCanvasOptionsBitmapChain)
521
522END_EVENT_TABLE()
523
524// Define a constructor
525MUIBar::MUIBar() {}
526
527MUIBar::MUIBar(ChartCanvas* parent, int orientation, float size_factor,
528 wxWindowID id, const wxPoint& pos, const wxSize& size,
529 long style, const wxString& name) {
530 m_parentCanvas = parent;
531 m_orientation = orientation;
532
533 // SetBackgroundStyle( wxBG_STYLE_TRANSPARENT );
534 // wxWindow::Create(parent, id, pos, size, style, name);
535 // long mstyle = wxSIMPLE_BORDER;
536 long mstyle = wxNO_BORDER | wxFRAME_NO_TASKBAR | wxFRAME_SHAPED |
537 wxFRAME_FLOAT_ON_PARENT;
538
539#ifdef __WXOSX__
540 mstyle |= wxFRAME_TOOL_WINDOW;
541#endif
542
543 m_scaleFactor = size_factor;
544 m_cs = (ColorScheme)-1;
545
546 wxFrame::Create(parent, id, _T(""), pos, size, mstyle, name);
547 Init();
548 CreateControls();
549 // Show();
550}
551
552MUIBar::~MUIBar() {
553 if (m_canvasOptions) {
554 m_canvasOptions->Destroy();
555 m_canvasOptions = 0;
556 }
557 if (m_scaleTextBox)
558 m_scaleTextBox->Unbind(wxEVT_LEFT_DOWN, &MUIBar::OnScaleSelected, this);
559}
560
561void MUIBar::Init() {
562 m_zinButton = NULL;
563 m_zoutButton = NULL;
564 m_followButton = NULL;
565 m_menuButton = NULL;
566
567 m_canvasOptions = NULL;
568 m_canvasOptionsAnimationTimer.SetOwner(this,
569 CANVAS_OPTIONS_ANIMATION_TIMER_1);
570 m_backcolorString = _T("GREY3");
571 m_scaleTextBox = NULL;
572 m_capture_size_y = 0;
573
574 m_COTopOffset = 60; // TODO should be below GPS/Compass
575
576 CanvasOptionTimer.SetOwner(this, CANVAS_OPTIONS_TIMER);
577 m_coAnimateByBitmaps = false;
578 m_bEffects = true;
579#ifdef __OCPN__ANDROID__
580 m_bEffects = false;
581#endif
582}
583
584void MUIBar::SetColorScheme(ColorScheme cs) {
585 if (m_cs != cs) {
586 wxColour backColor = GetGlobalColor(m_backcolorString);
587 SetBackgroundColour(backColor);
588
589 if (m_zinButton) m_zinButton->SetColorScheme(cs);
590 if (m_zoutButton) m_zoutButton->SetColorScheme(cs);
591 if (m_followButton) m_followButton->SetColorScheme(cs);
592 if (m_menuButton) m_menuButton->SetColorScheme(cs);
593
594 if (m_scaleTextBox) {
595 wxColour textbackColor = GetGlobalColor(_T("GREY1"));
596 m_scaleTextBox->SetForegroundColour(textbackColor);
597 }
598 Refresh();
599 m_cs = cs;
600 }
601}
602
603void MUIBar::OnScaleSelected(wxMouseEvent& event) {
604 ChartCanvas* pcc = wxDynamicCast(m_parent, ChartCanvas);
605 if (!pcc) return;
606
607 SetScaleDialog dlg(pcc);
608 dlg.Centre();
609 dlg.ShowModal();
610 if (dlg.GetReturnCode() == wxID_OK) {
611 wxString newScale = dlg.m_ScaleCtl->GetValue();
612 if (newScale.Contains(':')) newScale = newScale.AfterFirst(':');
613 double dScale;
614 if (newScale.ToDouble(&dScale)) {
615 // Try to constrain the scale to something reasonable
616 dScale = wxMin(dScale, 3e6);
617 dScale = wxMax(dScale, 1000);
618 double displayScaleNow = pcc->GetScaleValue();
619 double factor = displayScaleNow / dScale;
620 pcc->DoZoomCanvas(factor, false);
621
622 // Run the calculation again, to reduce roundoff error in large scale
623 // jumps.
624 displayScaleNow = pcc->GetScaleValue();
625 factor = displayScaleNow / dScale;
626 pcc->DoZoomCanvas(factor, false);
627 }
628 }
629}
630
631void MUIBar::SetCanvasENCAvailable(bool avail) {
632 m_CanvasENCAvail = avail;
633 if (m_canvasOptions) m_canvasOptions->SetENCAvailable(avail);
634}
635
636void MUIBar::CreateControls() {
637 // SetBackgroundStyle( wxBG_STYLE_TRANSPARENT );
638
639 wxColour backColor = GetGlobalColor(m_backcolorString);
640 SetBackgroundColour(backColor);
641 wxBoxSizer* topSizer;
642
643 wxString iconDir = g_Platform->GetSharedDataDir() + _T("uidata/MUI_flat/");
644
645 if (m_orientation == wxHORIZONTAL) {
646 topSizer = new wxBoxSizer(wxVERTICAL);
647 SetSizer(topSizer);
648
649 wxBoxSizer* barSizer = new wxBoxSizer(wxHORIZONTAL);
650 topSizer->Add(barSizer, 0, wxEXPAND);
651
652 // Buttons
653
654 if (g_bShowMuiZoomButtons) {
655 m_zinButton = new MUIButton(this, ID_ZOOMIN, m_scaleFactor,
656 iconDir + _T("MUI_zoom-in.svg"));
657 barSizer->Add(m_zinButton, 0, wxSHAPED);
658
659 m_zoutButton = new MUIButton(this, ID_ZOOMOUT, m_scaleFactor,
660 iconDir + _T("MUI_zoom-out.svg"));
661 barSizer->Add(m_zoutButton, 0, wxSHAPED);
662
663 barSizer->AddSpacer(2);
664 }
665
666#ifndef __OCPN__ANDROID__
667 // Scale
668 m_scaleTextBox = new wxStaticText(this, wxID_ANY, _T("1:400000"));
669 wxColour textbackColor = GetGlobalColor(_T("GREY1"));
670 m_scaleTextBox->SetForegroundColour(textbackColor);
671 barSizer->Add(m_scaleTextBox, 0, wxALIGN_CENTER_VERTICAL);
672 m_scaleTextBox->Bind(wxEVT_LEFT_DOWN, &MUIBar::OnScaleSelected, this);
673
674 barSizer->AddSpacer(5);
675
676 m_followButton = new MUIButton(this, ID_FOLLOW, m_scaleFactor,
677 iconDir + _T("MUI_follow.svg"),
678 iconDir + _T("MUI_follow_active.svg"),
679 iconDir + _T("MUI_follow_ahead.svg"));
680 barSizer->Add(m_followButton, 0, wxSHAPED);
681
682 barSizer->AddSpacer(2);
683#endif
684 m_menuButton = new MUIButton(this, ID_MUI_MENU, m_scaleFactor,
685 iconDir + _T("MUI_menu.svg"));
686 barSizer->Add(m_menuButton, 0, wxSHAPED);
687 } else {
688 topSizer = new wxBoxSizer(wxVERTICAL);
689 SetSizer(topSizer);
690
691 wxBoxSizer* barSizer = new wxBoxSizer(wxVERTICAL);
692 topSizer->Add(barSizer, 0, wxEXPAND);
693
694 // Buttons
695 if (g_bShowMuiZoomButtons) {
696 m_zinButton = new MUIButton(this, ID_ZOOMIN, m_scaleFactor,
697 iconDir + _T("MUI_zoom-in.svg"));
698 barSizer->Add(m_zinButton, 1, wxSHAPED);
699
700 m_zoutButton = new MUIButton(this, ID_ZOOMOUT, m_scaleFactor,
701 iconDir + _T("MUI_zoom-out.svg"));
702 barSizer->Add(m_zoutButton, 1, wxSHAPED);
703
704 barSizer->AddSpacer(5);
705 }
706
707#ifndef __OCPN__ANDROID__
708 m_followButton = new MUIButton(this, ID_FOLLOW, m_scaleFactor,
709 iconDir + _T("MUI_follow.svg"),
710 iconDir + _T("MUI_follow_active.svg"),
711 iconDir + _T("MUI_follow_ahead.svg"));
712 barSizer->Add(m_followButton, 1, wxSHAPED);
713
714 barSizer->AddSpacer(5);
715#endif
716
717 m_menuButton = new MUIButton(this, ID_MUI_MENU, m_scaleFactor,
718 iconDir + _T("MUI_menu.svg"));
719 barSizer->Add(m_menuButton, 1, wxALIGN_RIGHT | wxSHAPED);
720 }
721
722 // topSizer->SetSizeHints( this );
723 topSizer->Fit(this);
724}
725
726void MUIBar::SetBestPosition(void) {
727#if 0 // for wxWindow
728 int x = (m_parent->GetClientSize().x - GetSize().x) / 2;
729 if(x > 0){
730 int bottomOffset = 0;
731
732 ChartCanvas *pcc = wxDynamicCast(m_parent, ChartCanvas);
733 bottomOffset += pcc->GetPianoHeight();
734
735 int y = m_parent->GetClientSize().y - GetSize().y - bottomOffset;
736 SetSize(x, y, -1, -1, wxSIZE_USE_EXISTING);
737 }
738
739#else // for wxDialog
740 int x = (m_parent->GetClientSize().x - (GetSize().x * 1.00));
741
742#ifndef __WXGTK__ // Adjust for wxNO_BORDER canvas window style
743 x -= 2;
744#endif
745
746 // if(x > 0)
747 {
748 int bottomOffset = 2;
749
750 ChartCanvas* pcc = wxDynamicCast(m_parent, ChartCanvas);
751 // bottomOffset += pcc->GetPianoHeight();
752
753 int y = m_parent->GetClientSize().y - GetSize().y - bottomOffset;
754
755 wxPoint m_position = wxPoint(x, y);
756 wxPoint screenPos = pcc->ClientToScreen(m_position);
757
758 // GTK sometimes has trouble with ClientToScreen() if executed in the
759 // context of an event handler The position of the window is calculated
760 // incorrectly if a deferred Move() has not been processed yet. So work
761 // around this here...
762
763#ifdef __WXGTK__
764 wxPoint pp = m_parent->GetPosition();
765 wxPoint ppg = m_parent->GetParent()->GetScreenPosition();
766 wxPoint screen_pos_fix = ppg + pp + m_position;
767 screenPos.x = screen_pos_fix.x;
768#endif
769
770 Move(screenPos);
771
772 if (m_canvasOptions) {
773 m_canvasOptions->Destroy();
774 m_canvasOptions = 0;
775 }
776 Show();
777 }
778#endif
779}
780
781void MUIBar::OnSize(wxSizeEvent& event) {
782 // int buttonSize = event.GetSize().y / 2;
783 Layout();
784
785#if !defined(__WXMAC__) && !defined(__OCPN__ANDROID__)
786 if (1) {
787 wxBitmap m_MaskBmp = wxBitmap(GetSize().x, GetSize().y);
788 wxMemoryDC sdc(m_MaskBmp);
789 sdc.SetBackground(*wxWHITE_BRUSH);
790 sdc.Clear();
791 sdc.SetBrush(*wxBLACK_BRUSH);
792 sdc.SetPen(*wxBLACK_PEN);
793 sdc.DrawRoundedRectangle(0, 0, m_MaskBmp.GetWidth(), m_MaskBmp.GetHeight(),
794 5);
795 sdc.SelectObject(wxNullBitmap);
796 SetShape(wxRegion(m_MaskBmp, *wxWHITE, 0));
797 }
798#endif
799}
800
801void MUIBar::UpdateDynamicValues() {
802 if (!m_scaleTextBox) return;
803
804 wxString scaleString;
805 int scale = m_parentCanvas->GetScaleValue();
806 if (scale < 1e6)
807 scaleString.Printf(_T("1:%d"), scale);
808 else
809 scaleString.Printf(_T("1:%4.1f MM"), scale / 1e6);
810
811 if (m_scaleTextBox) m_scaleTextBox->SetLabel(scaleString);
812}
813
814void MUIBar::SetFollowButtonState(int state) {
815 if (m_followButton) m_followButton->SetState(state);
816}
817
818void MUIBar::OnToolLeftClick(wxCommandEvent& event) {
819 // Handle the MUIButton clicks here
820 ChartCanvas* pcc = wxDynamicCast(m_parent, ChartCanvas);
821
822 switch (event.GetId()) {
823 case ID_ZOOMIN:
824 case ID_ZOOMOUT: {
825 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, event.GetId());
826 GetParent()->GetEventHandler()->AddPendingEvent(evt);
827
828 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
829 break;
830 }
831
832 case ID_FOLLOW: {
833 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, event.GetId());
834 GetParent()->GetEventHandler()->AddPendingEvent(evt);
835
836 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
837 break;
838 }
839
840 case ID_MUI_MENU: {
841 if (!m_canvasOptions) {
842 m_canvasOptions = new CanvasOptions(m_parent);
843
844 // calculate best size for CanvasOptions dialog
845
846 wxPoint parentClientUpperRight =
847 m_parent->ClientToScreen(wxPoint(m_parent->GetSize().x, 0));
848 wxRect rmui = m_parentCanvas->GetMUIBarRect();
849 int size_y = rmui.y - (parentClientUpperRight.y + m_COTopOffset);
850 size_y -= GetCharHeight();
851 size_y = wxMax(size_y, 100); // ensure always big enough to see
852
853 m_canvasOptions->SetSize(wxSize(-1, size_y));
854 m_canvasOptionsFullSize = m_canvasOptions->GetSize();
855 m_canvasOptionsFullSize.x +=
856 m_canvasOptions->GetCharWidth(); // Allow for scroll bar, since
857 // sizer won't do it.
858
859 if (1)
860 m_currentCOPos = m_parent->ClientToScreen(
861 wxPoint(m_parent->GetSize().x, m_COTopOffset));
862 else
863 m_currentCOPos = wxPoint(m_parent->GetSize().x, 20);
864
865 m_canvasOptions->Move(m_currentCOPos);
866 m_canvasOptions->Hide();
867 }
868
869 m_canvasOptions->SetENCAvailable(m_CanvasENCAvail);
870
871 if (m_canvasOptions->IsShown())
872 PushCanvasOptions(); // hide it
873 else {
874 // Grab the backing bitmap, if available
875
876 if (m_coAnimateByBitmaps && m_capture_size_y) {
877 int overShoot_x = m_canvasOptions->GetSize().x * 2 / 10; // 20%
878 m_backingPoint =
879 wxPoint(m_capturePoint.x - overShoot_x, m_capturePoint.y);
880
881 m_backingBitmap = wxBitmap(m_canvasOptionsFullSize.x + overShoot_x,
882 m_capture_size_y, -1);
883 wxMemoryDC mdcb;
884 mdcb.SelectObject(m_backingBitmap);
885 wxScreenDC sdc;
886 mdcb.Blit(0, 0, m_canvasOptionsFullSize.x + overShoot_x,
887 m_capture_size_y, &sdc, m_capturePoint.x - overShoot_x,
888 m_capturePoint.y, wxCOPY);
889 mdcb.SelectObject(wxNullBitmap);
890 }
891 PullCanvasOptions();
892 }
893
894 break;
895 }
896
897 default:
898 break;
899 }
900 // event.Skip();
901}
902
903void MUIBar::CaptureCanvasOptionsBitmap() {
904 m_coSequence = 0;
905 CanvasOptionTimer.Start(100, wxTIMER_ONE_SHOT);
906}
907
908void MUIBar::CaptureCanvasOptionsBitmapChain(wxTimerEvent& event) {
909 if (m_coSequence == 0) {
910 if (!m_canvasOptions) m_canvasOptions = new CanvasOptions(m_parent);
911
912 wxPoint parentClientUpperRight =
913 m_parent->ClientToScreen(wxPoint(m_parent->GetSize().x, 0));
914 wxRect rmui = m_parentCanvas->GetMUIBarRect();
915 int size_y = rmui.y - (parentClientUpperRight.y + m_COTopOffset);
916 size_y -= GetCharHeight();
917 size_y = wxMax(size_y, 100); // ensure always big enough to see
918 m_capture_size_y = size_y;
919
920 m_canvasOptions->SetSize(wxSize(-1, size_y));
921
922 m_capturePoint =
923 m_parent->ClientToScreen(wxPoint(m_parent->GetSize().x, m_COTopOffset));
924 m_canvasOptions->Move(m_capturePoint);
925 m_canvasOptions->Show();
926
927 m_coSequence++;
928 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
929 }
930
931 else if (m_coSequence == 1) {
932 m_capturePoint = m_parent->ClientToScreen(wxPoint(
933 m_parent->GetSize().x - m_canvasOptionsFullSize.x, m_COTopOffset));
934 m_canvasOptions->Move(m_capturePoint);
935
936 m_coSequence++;
937 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
938 }
939
940 else if (m_coSequence == 2) {
941 m_animateBitmap =
942 wxBitmap(m_canvasOptions->GetSize().x, m_capture_size_y, -1);
943 wxMemoryDC mdc(m_animateBitmap);
944
945 wxScreenDC sdc;
946
947 mdc.Blit(0, 0, m_canvasOptions->GetSize().x, m_capture_size_y, &sdc,
948 m_capturePoint.x, m_capturePoint.y, wxCOPY);
949 mdc.SelectObject(wxNullBitmap);
950
951 // delete m_canvasOptions;
952 // m_canvasOptions = NULL;
953 }
954}
955
956void MUIBar::OnEraseBackground(wxEraseEvent& event) {}
957
958void MUIBar::OnPaint(wxPaintEvent& event) {
959 return;
960
961 int width, height;
962 GetClientSize(&width, &height);
963 wxPaintDC dc(this);
964
965 // dc.SetBackgroundMode(wxTRANSPARENT);
966 // dc.SetBackground(*wxTRANSPARENT_BRUSH);
967
968 // dc.SetPen( *wxTRANSPARENT_PEN );
969 // dc.SetBrush( *wxTRANSPARENT_BRUSH );
970 // dc.DrawRectangle( 0, 0, width, height);
971
972 wxColour backColor = GetGlobalColor(m_backcolorString);
973
974 dc.SetBrush(wxBrush(backColor /*wxColour(200, 200, 200)*/));
975 dc.SetPen(wxPen(backColor));
976 dc.DrawRoundedRectangle(0, 0, width - 10, height - 10, 8);
977}
978
979void MUIBar::ResetCanvasOptions() {
980 delete m_canvasOptions;
981 m_canvasOptions = NULL;
982}
983
984void MUIBar::PullCanvasOptions() {
985 // Target position
986 int cox = m_parent->GetSize().x - m_canvasOptionsFullSize.x;
987 int coy = m_COTopOffset;
988 m_targetCOPos = m_parent->ClientToScreen(wxPoint(cox, coy));
989
990 if (!m_bEffects) {
991 m_canvasOptions->Move(m_targetCOPos);
992 m_canvasOptions->Show();
993 return;
994 }
995
996 // Capture the animation bitmap, if required..
997
998 if (m_coAnimateByBitmaps && !m_animateBitmap.IsOk()) {
999 m_canvasOptions->Move(m_targetCOPos);
1000 m_canvasOptions->Show();
1001 CaptureCanvasOptionsBitmap();
1002 return;
1003 }
1004
1005 // Setup animation parameters
1006 // Start Position
1007 m_startCOPos = m_canvasOptions->GetPosition();
1008
1009 // Present Position
1010 m_currentCOPos = m_startCOPos;
1011
1012 m_animationType = CO_ANIMATION_CUBIC_REVERSE; // CO_ANIMATION_CUBIC_BACK_IN;
1013 m_animateSteps = 10;
1014 m_animationTotalTime = 200; // msec
1015
1016 m_pushPull = CO_PULL;
1017 ChartCanvas* pcc = wxDynamicCast(m_parent, ChartCanvas);
1018 pcc->m_b_paint_enable = false;
1019
1020 // Start the animation....
1021 m_animateStep = 0;
1022 m_canvasOptionsAnimationTimer.Start(10, true);
1023 m_canvasOptions->Move(m_targetCOPos);
1024 m_canvasOptions->Hide();
1025}
1026
1027void MUIBar::PushCanvasOptions() {
1028 if (!m_bEffects) {
1029 m_canvasOptions->Hide();
1030 return;
1031 }
1032
1033 // Setup animation parameters
1034
1035 // Target position
1036 int cox = m_parent->GetSize().x;
1037 int coy = 20;
1038
1039 if (1)
1040 m_targetCOPos = m_parent->ClientToScreen(wxPoint(cox, coy));
1041 else
1042 m_targetCOPos = wxPoint(cox, coy);
1043
1044 // Start Position
1045 m_startCOPos = m_canvasOptions->GetPosition();
1046
1047 // Present Position
1048 m_currentCOPos = m_startCOPos;
1049
1050 // Animation type
1051 m_animationType = CO_ANIMATION_LINEAR;
1052 m_animateSteps = 5;
1053 m_animationTotalTime = 100; // msec
1054 m_pushPull = CO_PUSH;
1055 ChartCanvas* pcc = wxDynamicCast(m_parent, ChartCanvas);
1056
1057 // Start the animation....
1058 m_animateStep = 0;
1059 m_canvasOptionsAnimationTimer.Start(10, true);
1060 m_canvasOptions->Show();
1061}
1062
1063void MUIBar::onCanvasOptionsAnimationTimerEvent(wxTimerEvent& event) {
1064 double progress = m_animateStep / (double)m_animateSteps;
1065 double valueX = getValue(m_animationType, progress);
1066
1067 double dx = (m_targetCOPos.x - m_startCOPos.x) * valueX;
1068
1069 wxPoint newPos = wxPoint(m_startCOPos.x + dx, m_currentCOPos.y);
1070
1071 int size_x;
1072 if (m_pushPull == CO_PULL)
1073 size_x = abs(dx);
1074 else
1075 size_x = (m_targetCOPos.x - m_startCOPos.x) - abs(dx);
1076
1077 if (!m_coAnimateByBitmaps) {
1078 m_canvasOptions->SetSize(newPos.x, newPos.y, size_x, wxDefaultCoord,
1079 wxSIZE_USE_EXISTING);
1080 // m_canvasOptions->GetSizer()->Layout();
1081 m_canvasOptions->Show();
1082 } else {
1083 m_canvasOptions->Hide();
1084 wxScreenDC sdc;
1085
1086 if (1 /*m_pushPull == CO_PULL*/) {
1087 // restore Backing bitmap, to cover any overshoot
1088 if (m_backingBitmap.IsOk()) {
1089 wxMemoryDC mdc_back(m_backingBitmap);
1090 sdc.Blit(m_backingPoint.x, m_backingPoint.y,
1091 m_backingBitmap.GetWidth() - size_x,
1092 m_backingBitmap.GetHeight(), &mdc_back, 0, 0, wxCOPY);
1093 }
1094 }
1095
1096 wxMemoryDC mdc(m_animateBitmap);
1097 sdc.Blit(newPos.x, newPos.y, size_x, m_animateBitmap.GetHeight(), &mdc, 0,
1098 0, wxCOPY);
1099 mdc.SelectObject(wxNullBitmap);
1100 }
1101
1102 m_currentCOPos = newPos;
1103
1104 double dt = m_animationTotalTime / m_animateSteps;
1105
1106 if (m_animateStep++ < m_animateSteps + 1) {
1107 m_canvasOptionsAnimationTimer.Start(dt, true);
1108 } else {
1109 m_currentCOPos = m_targetCOPos;
1110 m_canvasOptions->Show(m_pushPull == CO_PULL);
1111
1112 ChartCanvas* pcc = wxDynamicCast(m_parent, ChartCanvas);
1113 if (pcc) {
1114 pcc->m_b_paint_enable = true;
1115
1116 if (m_pushPull == CO_PUSH) {
1117 delete m_canvasOptions;
1118 m_canvasOptions = NULL;
1119 }
1120#ifdef __WXOSX__
1121 if (m_pushPull == CO_PUSH) pcc->TriggerDeferredFocus();
1122#else
1123 pcc->TriggerDeferredFocus();
1124#endif
1125
1126 pcc->Refresh();
1127 }
1128 }
1129}
1130
1131// Animation support
1132
1133double bounceMaker(double t, double c, double a) {
1134 if (t == 1.0) return c;
1135 if (t < (4 / 11.0)) {
1136 return c * (7.5625 * t * t);
1137 } else if (t < (8 / 11.0)) {
1138 t -= (6 / 11.0);
1139 return -a * (1. - (7.5625 * t * t + .75)) + c;
1140 } else if (t < (10 / 11.0)) {
1141 t -= (9 / 11.0);
1142 return -a * (1. - (7.5625 * t * t + .9375)) + c;
1143 } else {
1144 t -= (21 / 22.0);
1145 return -a * (1. - (7.5625 * t * t + .984375)) + c;
1146 }
1147}
1148
1149double getValue(int animationType, double t) {
1150 double value = 0;
1151 double s = 1;
1152 double tp;
1153 switch (animationType) {
1154 case CO_ANIMATION_LINEAR:
1155 default:
1156 value = t;
1157 break;
1158 case CO_ANIMATION_CUBIC:
1159 tp = t - 1.0;
1160 value = tp * tp * tp + 1;
1161 // value = t*t*t;
1162 break;
1163 case CO_ANIMATION_CUBIC_REVERSE:
1164 tp = t - 1.0;
1165 value = tp * tp * tp + 1;
1166 break;
1167 case CO_ANIMATION_CUBIC_BOUNCE_IN:
1168 value = bounceMaker(t, 1, s);
1169 break;
1170
1171 case CO_ANIMATION_CUBIC_BACK_IN:
1172 tp = t - 1.0;
1173 value = tp * tp * ((s + 1) * tp + s) + 1;
1174 break;
1175 }
1176
1177 return value;
1178}
Definition: MUIBar.h:56
static bool ShowToolTips()
Should we show tooltips?
Definition: MUIBar.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: MUIBar.cpp:132
void CreateControls()
Definition: MUIBar.cpp:149
wxTextCtrl * m_ScaleCtl
Should we show tooltips?
Definition: MUIBar.cpp:101
SetScaleDialog()
Constructors.
Definition: MUIBar.cpp:115
Definition: Quilt.cpp:864