29 #include <wx/wxprec.h>
35 #include <wx/statline.h>
40 #include "OCPNPlatform.h"
41 #include "CanvasOptions.h"
42 #include "DetailSlider.h"
43 #include "GoToPositionDialog.h"
46 #include "svg_utils.h"
47 #include "model/idents.h"
48 #include "color_handler.h"
50 #include "pluginmanager.h"
53 #include "glChartCanvas.h"
56 #ifdef __OCPN__ANDROID__
57 #include "androidUTIL.h"
62 extern GLenum g_texture_rectangle_format;
72 extern bool g_bShowMuiZoomButtons;
73 extern bool g_bopengl;
79 double getValue(
int animationType,
double t);
83 #define ID_SCALE_CANCEL 8301
84 #define ID_SCALE_OK 8302
85 #define ID_SCALECTRL 8303
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);
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);
108 void SetColorScheme(ColorScheme cs);
112 void OnSetScaleCancelClick(wxCommandEvent& event);
113 void OnSetScaleOKClick(wxCommandEvent& event);
118 wxButton* m_CancelButton;
119 wxButton* m_OKButton;
123 EVT_BUTTON(ID_GOTOPOS_CANCEL, SetScaleDialog::OnSetScaleCancelClick)
124 EVT_BUTTON(ID_GOTOPOS_OK, SetScaleDialog::OnSetScaleOKClick)
134 const wxString& caption,
const wxPoint& pos,
135 const wxSize& size,
long style) {
137 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT;
139 Create(parent,
id, caption, pos, size, wstyle);
142 SetScaleDialog::~SetScaleDialog() {}
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);
155 GetSizer()->SetSizeHints(
this);
168 wxBoxSizer* itemBoxSizer2 =
new wxBoxSizer(wxVERTICAL);
169 itemDialog1->SetSizer(itemBoxSizer2);
171 wxStaticBox* itemStaticBoxSizer4Static =
172 new wxStaticBox(itemDialog1, wxID_ANY, _(
"Chart Scale"));
174 wxStaticBoxSizer* itemStaticBoxSizer4 =
175 new wxStaticBoxSizer(itemStaticBoxSizer4Static, wxVERTICAL);
176 itemBoxSizer2->Add(itemStaticBoxSizer4, 0, wxEXPAND | wxALL, 5);
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);
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);
188 wxBoxSizer* itemBoxSizer16 =
new wxBoxSizer(wxHORIZONTAL);
189 itemBoxSizer2->Add(itemBoxSizer16, 0, wxALIGN_RIGHT | wxALL, 5);
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);
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();
200 SetColorScheme((ColorScheme)0);
203 void SetScaleDialog::SetColorScheme(ColorScheme cs) { DimeControl(
this); }
205 void SetScaleDialog::OnSetScaleCancelClick(wxCommandEvent& event) {
210 void SetScaleDialog::OnSetScaleOKClick(wxCommandEvent& event) {
211 SetReturnCode(wxID_OK);
222 wxSize DoGetBestSize()
const;
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);
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);
245 void CreateControls();
247 void SetState(
int state);
248 int GetState(){
return mState; }
250 void SetColorScheme(ColorScheme cs);
251 void OnSize(wxSizeEvent& event);
252 void OnLeftDown(wxMouseEvent& event);
253 void OnLeftUp(wxMouseEvent& event);
255 wxBitmap GetBitmapResource(
const wxString& name);
257 wxIcon GetIconResource(
const wxString& name);
258 wxBitmap GetButtonBitmap(){
return m_bitmap; }
266 wxString m_bitmapFileState0;
267 wxString m_bitmapFileState1;
268 wxString m_bitmapFileState2;
270 wxBitmap m_bitmapState0;
271 wxBitmap m_bitmapState1;
272 wxBitmap m_bitmapState2;
276 wxSize m_styleToolSize;
280 MUIButton::MUIButton() { Init(); }
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) {
289 Create(parent,
id, scale_factor, bitmap, bitmapState1, bitmapState2, pos,
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;
301 m_scaleFactor = scale_factor;
303 m_styleToolSize = g_StyleManager->GetCurrentStyle()->GetToolSize();
307 m_styleToolSize = wxSize(m_styleToolSize.x * 1.25, m_styleToolSize.y * 1.25);
309 m_size = wxSize(m_styleToolSize.x * m_scaleFactor,
310 m_styleToolSize.y * m_scaleFactor);
316 MUIButton::~MUIButton() {}
318 void MUIButton::Init() {
320 m_cs = (ColorScheme)-1;
323 void MUIButton::CreateControls() {
333 void MUIButton::SetColorScheme(ColorScheme cs) {
336 wxColour backColor = GetGlobalColor(_T(
"GREY3"));
341 wxBitmap bmp = LoadSVG(m_bitmapFileState0, m_size.x, m_size.y);
342 m_bitmapState0 = style->SetBitmapBrightness(bmp, cs);
344 bmp = LoadSVG(m_bitmapFileState1, m_size.x, m_size.y);
346 m_bitmapState1 = style->SetBitmapBrightness(bmp, cs);
348 m_bitmapState1 = m_bitmapState0;
350 bmp = LoadSVG(m_bitmapFileState2, m_size.x, m_size.y);
352 m_bitmapState2 = style->SetBitmapBrightness(bmp, cs);
354 m_bitmapState2 = m_bitmapState0;
359 m_bitmap = m_bitmapState0;
363 m_bitmap = m_bitmapState1;
367 m_bitmap = m_bitmapState2;
378 void MUIButton::SetState(
int state) {
382 m_bitmap = m_bitmapState0;
386 m_bitmap = m_bitmapState1;
390 m_bitmap = m_bitmapState2;
397 void MUIButton::OnSize(wxSizeEvent& event) {
398 if (m_bitmap.IsOk()) {
399 if (event.GetSize() == m_bitmap.GetSize())
return;
402 if (!m_bitmapFileState0.IsEmpty())
404 LoadSVG(m_bitmapFileState0, event.GetSize().x, event.GetSize().y);
406 if (!m_bitmapFileState1.IsEmpty())
408 LoadSVG(m_bitmapFileState1, event.GetSize().x, event.GetSize().y);
409 if (!m_bitmapState1.IsOk() || m_bitmapFileState1.IsEmpty())
410 m_bitmapState1 = m_bitmapState0;
412 if (!m_bitmapFileState2.IsEmpty())
414 LoadSVG(m_bitmapFileState2, event.GetSize().x, event.GetSize().y);
415 if (!m_bitmapState2.IsOk() || m_bitmapFileState2.IsEmpty())
416 m_bitmapState2 = m_bitmapState0;
421 m_bitmap = m_bitmapState0;
425 m_bitmap = m_bitmapState1;
429 m_bitmap = m_bitmapState2;
435 wxSize MUIButton::DoGetBestSize()
const {
440 return wxSize(m_styleToolSize.x * m_scaleFactor,
441 m_styleToolSize.y * m_scaleFactor);
447 static std::unordered_map<char, ssfn_glyph_t *> ssfn_glyph_map;
455 char *fontdata = NULL;
459 unsigned char hdr[2];
463 f = fopen(filename,
"rb");
464 if(!f) { fprintf(stderr,
"unable to load %s\n", filename);
return NULL; }
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);
472 fseek(f, 0, SEEK_END);
476 g = gzopen(filename,
"r");
478 fseek(f, 0, SEEK_END);
480 fseek(f, 0, SEEK_SET);
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); }
486 gzread(g, fontdata, size);
489 fread(fontdata, size, 1, f);
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))
507 size_t didx = index * 3;
509 size_t sidx = i * glyph->pitch + j;
510 unsigned char d = src[sidx];
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));
520 bool RenderStringToBuffer(
unsigned char *buffer, std::string s,
521 int wbox,
int hbox,
int nominal_baseline,
522 wxColour color, wxColour &back_color) {
524 for (
unsigned int i=0; i < s.size(); i++) {
529 if (
auto findit = ssfn_glyph_map.find(key); findit != ssfn_glyph_map.end() ) {
530 glyph = findit->second;
532 glyph= ssfn_render(&ctx, key);
533 ssfn_glyph_map[key] = glyph;
535 RenderGlyphToImageBuffer( buffer, glyph, xpos, wbox, hbox,
536 nominal_baseline, color, back_color);
537 xpos += glyph->adv_x;
554 const wxString& text = wxEmptyString,
555 const wxPoint& pos = wxDefaultPosition,
556 const wxSize& size = wxDefaultSize,
long style = wxNO_BORDER);
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);
567 wxSize GetSize(){
return m_size;}
568 void SetState(
int state);
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);
576 wxBitmap GetButtonBitmap(){
return m_bitmap; }
588 wxSize m_styleToolSize;
592 wxColor m_backgrounColor;
596 MUITextButton::MUITextButton() { Init(); }
598 MUITextButton::MUITextButton(wxWindow* parent, wxWindowID
id,
float scale_factor,
599 wxColor backColor,
const wxString& text,
601 const wxSize& size,
long style) {
602 m_backgrounColor = backColor;
604 Create(parent,
id, scale_factor, text, pos, size, style);
607 bool MUITextButton::Create(wxWindow* parent, wxWindowID
id,
float scale_factor,
608 const wxString& text,
610 const wxSize& size,
long style) {
613 m_scaleFactor = scale_factor;
615 m_styleToolSize = g_StyleManager->GetCurrentStyle()->GetToolSize();
618 m_styleToolSize = wxSize(m_styleToolSize.x * 1.25, m_styleToolSize.y * 1.25);
620 int height_ref = m_styleToolSize.y;
623 memset(&ctx, 0,
sizeof(
ssfn_t));
624 wxString font_file = g_Platform->GetSharedDataDir() +
"ssfndata/FreeSans.sfn";
625 std::string sfont = font_file.ToStdString();
627 pssfn_font = load_font(sfont.c_str());
628 if (pssfn_font) ssfn_load(&ctx, pssfn_font);
630 m_pixel_height = height_ref / 2;
631 m_pixel_height *= m_scaleFactor;
635 ssfn_select(&ctx, SSFN_FAMILY_SANS, NULL,
636 SSFN_STYLE_REGULAR, m_pixel_height,
643 if (m_ssfn_status == SSFN_OK) {
644 std::string t =
"1:888888";
645 ssfn_bbox(&ctx, (
char*)t.c_str(), 0, &wbox, &hbox);
648 m_size = wxSize(hbox * 1.5, m_styleToolSize.y);
649 m_size.y *= m_scaleFactor;
653 MUITextButton::~MUITextButton() {
654 for (
const auto & [ key, value ] : ssfn_glyph_map) {
657 ssfn_glyph_map.clear();
660 void MUITextButton::Init() {
662 m_cs = (ColorScheme)-1;
665 void MUITextButton::SetText(
const wxString &text){
666 if (!m_text.IsSameAs(text)){
672 void MUITextButton::SetColorScheme(ColorScheme cs) {
683 void MUITextButton::SetState(
int state) {
687 void MUITextButton::OnSize(wxSizeEvent& event) {
693 void MUITextButton::BuildBitmap(){
694 int width = m_size.x;
695 int height = m_size.y;
697 if ( m_ssfn_status != SSFN_OK)
701 std::string t = m_text.ToStdString();
702 ssfn_bbox(&ctx, (
char *)t.c_str(), 0, &wbox, &hbox);
705 int baseline = glyph->baseline;
708 unsigned char *image_data = (
unsigned char *)calloc(1, wbox * hbox * 3);
709 for (
int i=0 ; i < wbox * hbox; i++){
711 image_data[idx] = m_backgrounColor.Red();
712 image_data[idx+1] = m_backgrounColor.Green();
713 image_data[idx+2] = m_backgrounColor.Blue();
716 RenderStringToBuffer( image_data, t, wbox, hbox,
717 baseline, GetGlobalColor(
"CHWHT"), m_backgrounColor );
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);
724 m_bitmap = wxBitmap(clip_image);
730 #define CANVAS_OPTIONS_ANIMATION_TIMER_1 800
731 #define CANVAS_OPTIONS_TIMER 801
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;
746 m_scaleFactor = size_factor;
747 m_cs = (ColorScheme)-1;
748 wxColour backColor = wxColor(*wxBLACK);
755 if (m_canvasOptions) {
756 m_canvasOptions->Destroy();
761 delete m_followButton;
763 delete m_scaleButton;
767 void MUIBar::Init() {
770 m_followButton = NULL;
772 m_scaleButton = NULL;
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;
782 CanvasOptionTimer.SetOwner(
this, CANVAS_OPTIONS_TIMER);
783 m_coAnimateByBitmaps =
false;
785 #ifdef __OCPN__ANDROID__
789 m_end_margin = m_parentCanvas->GetCharWidth()/2;
793 void MUIBar::SetColorScheme(ColorScheme cs) {
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);
801 if (m_scaleButton) m_scaleButton->SetColorScheme(cs);
807 void MUIBar::InvalidateBitmap() {
808 m_bitmap = wxNullBitmap;
812 glDeleteTextures(1, &m_texture);
818 bool MUIBar::MouseEvent(wxMouseEvent &event) {
820 event.GetPosition(&x, &y);
823 wxRect r = wxRect(m_screenPos, m_size);
824 if (r.Contains(x,y)) {
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();
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();
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();
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)) {
862 if (g_focusCanvas) g_focusCanvas->TriggerDeferredFocus();
865 else if (event.LeftUp()) {
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);
880 void MUIBar::OnScaleSelected(wxMouseEvent& event) {
887 if (dlg.GetReturnCode() == wxID_OK) {
888 wxString newScale = dlg.m_ScaleCtl->GetValue();
889 if (newScale.Contains(
':')) newScale = newScale.AfterFirst(
':');
891 if (newScale.ToDouble(&dScale)) {
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);
901 displayScaleNow = pcc->GetScaleValue();
902 factor = displayScaleNow / dScale;
903 pcc->DoZoomCanvas(factor,
false);
908 void MUIBar::SetCanvasENCAvailable(
bool avail) {
909 m_CanvasENCAvail = avail;
910 if (m_canvasOptions) m_canvasOptions->SetENCAvailable(avail);
913 void MUIBar::CreateControls() {
914 wxString iconDir = g_Platform->GetSharedDataDir() + _T(
"uidata/MUI_flat/");
916 if (m_orientation == wxHORIZONTAL) {
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;
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;
933 #ifndef __OCPN__ANDROID__
936 m_scaleButton =
new MUITextButton(m_parentCanvas, wxID_ANY, m_scaleFactor,
937 GetBackgroundColor(),
"1:400000");
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);
945 xoff += m_scaleButton->m_size.x;
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;
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;
960 m_size.y = m_zinButton->m_size.y;
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;
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;
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;
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;
995 m_size.x = m_zinButton->m_size.x;
1001 void MUIBar::SetBestPosition(
void) {
1002 int x = (m_parentCanvas->GetClientSize().x - (m_size.x + (m_end_margin) * 2.00));
1004 int bottomOffset = 6;
1007 int y = m_parentCanvas->GetClientSize().y - m_size.y - bottomOffset;
1012 wxPoint position = wxPoint(x, y);
1013 m_screenPos = position;
1015 if (m_canvasOptions) {
1016 m_canvasOptions->Destroy();
1017 m_canvasOptions = 0;
1022 void MUIBar::UpdateDynamicValues() {
1023 if (!m_scaleButton)
return;
1025 wxString scaleString;
1026 int scale = m_parentCanvas->GetScaleValue();
1028 if (
scale != m_scale)
1033 scaleString.Printf(_T(
"1:%d"),
scale);
1035 scaleString.Printf(_T(
"1:%4.1f M"),
scale / 1e6);
1037 if (m_scaleButton) m_scaleButton->SetText(scaleString);
1040 void MUIBar::SetFollowButtonState(
int state) {
1041 if (m_followButton && m_followButton->GetState() != state) {
1042 m_followButton->SetState(state);
1048 void MUIBar::HandleMenuClick(){
1049 if (!m_canvasOptions) {
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);
1061 m_canvasOptions->SetSize(wxSize(-1, size_y));
1062 m_canvasOptionsFullSize = m_canvasOptions->GetSize();
1063 m_canvasOptionsFullSize.x +=
1064 m_canvasOptions->GetCharWidth();
1067 m_currentCOPos = m_parentCanvas->ClientToScreen(
1068 wxPoint(m_parentCanvas->GetSize().x, m_COTopOffset));
1070 m_canvasOptions->Move(m_currentCOPos);
1071 m_canvasOptions->Hide();
1074 m_canvasOptions->SetENCAvailable(m_CanvasENCAvail);
1076 if (m_canvasOptions->IsShown())
1077 PushCanvasOptions();
1081 if (m_coAnimateByBitmaps && m_capture_size_y) {
1082 int overShoot_x = m_canvasOptions->GetSize().x * 2 / 10;
1084 wxPoint(m_capturePoint.x - overShoot_x, m_capturePoint.y);
1086 m_backingBitmap = wxBitmap(m_canvasOptionsFullSize.x + overShoot_x,
1087 m_capture_size_y, -1);
1089 mdcb.SelectObject(m_backingBitmap);
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);
1096 PullCanvasOptions();
1101 void MUIBar::CaptureCanvasOptionsBitmap() {
1103 CanvasOptionTimer.Start(100, wxTIMER_ONE_SHOT);
1106 void MUIBar::CaptureCanvasOptionsBitmapChain(wxTimerEvent& event) {
1107 if (m_coSequence == 0) {
1108 if (!m_canvasOptions) m_canvasOptions =
new CanvasOptions(m_parentCanvas);
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);
1116 m_capture_size_y = size_y;
1118 m_canvasOptions->SetSize(wxSize(-1, size_y));
1121 m_parentCanvas->ClientToScreen(wxPoint(m_parentCanvas->GetSize().x, m_COTopOffset));
1122 m_canvasOptions->Move(m_capturePoint);
1123 m_canvasOptions->Show();
1126 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
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);
1135 CanvasOptionTimer.Start(1, wxTIMER_ONE_SHOT);
1138 else if (m_coSequence == 2) {
1140 wxBitmap(m_canvasOptions->GetSize().x, m_capture_size_y, -1);
1141 wxMemoryDC mdc(m_animateBitmap);
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);
1155 wxBitmap &MUIBar::CreateBitmap(
double displayScale) {
1156 if (m_bitmap.IsOk())
1160 int width = m_size.x;
1161 int height = m_size.y;
1164 wxBitmap bm(width, height);
1165 mdc.SelectObject(bm);
1166 mdc.SetBackground(wxBrush(GetBackgroundColor()));
1171 if (g_bShowMuiZoomButtons) {
1172 wxBitmap bmd = m_zinButton->GetButtonBitmap();
1175 m_zinButton->m_position.x,
1176 m_zinButton->m_position.y,
1179 bmd = m_zoutButton->GetButtonBitmap();
1182 m_zoutButton->m_position.x,
1183 m_zoutButton->m_position.y,
1187 if (m_scaleButton) {
1188 bmd = m_scaleButton->GetButtonBitmap();
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;
1194 mdc.DrawBitmap(bmd, bm_pos_x, bm_pos_y,
false);
1198 if (m_followButton) {
1199 bmd = m_followButton->GetButtonBitmap();
1202 m_followButton->m_position.x, m_followButton->m_position.y,
1207 bmd = m_menuButton->GetButtonBitmap();
1210 m_menuButton->m_position.x, m_menuButton->m_position.y,
1214 mdc.SelectObject(wxNullBitmap);
1220 void MUIBar::DrawGL(
ocpnDC &gldc,
double displayScale) {
1223 wxColour backColor = GetBackgroundColor();
1224 gldc.SetBrush(wxBrush(backColor));
1225 gldc.SetPen(wxPen(backColor));
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);
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);
1241 int width = m_size.x;
1242 int height = m_size.y;
1244 CreateBitmap(displayScale);
1248 glGenTextures(1, &m_texture);
1250 glBindTexture(g_texture_rectangle_format, m_texture);
1251 glTexParameterf(g_texture_rectangle_format, GL_TEXTURE_MIN_FILTER,
1253 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_MAG_FILTER,
1255 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_WRAP_S,
1257 glTexParameteri(g_texture_rectangle_format, GL_TEXTURE_WRAP_T,
1260 glBindTexture(g_texture_rectangle_format, m_texture);
1265 if (m_bitmap.IsOk()) {
1266 wxImage image = m_bitmap.ConvertToImage();
1268 unsigned char* d = image.GetData();
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);
1278 glTexImage2D(g_texture_rectangle_format, 0, GL_RGBA, width, height, 0,
1279 GL_RGBA, GL_UNSIGNED_BYTE, e);
1281 glDisable(g_texture_rectangle_format);
1282 glDisable(GL_BLEND);
1289 glEnable(g_texture_rectangle_format);
1290 glBindTexture(g_texture_rectangle_format, m_texture);
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;
1299 if (GL_TEXTURE_RECTANGLE_ARB == g_texture_rectangle_format)
1300 tx = width, ty = height;
1327 m_parentCanvas->GetglCanvas()->RenderTextures(gldc, coords, uv, 4,
1328 m_parentCanvas->GetpVP());
1330 glDisable(g_texture_rectangle_format);
1331 glBindTexture(g_texture_rectangle_format, 0);
1332 glDisable(GL_BLEND);
1339 void MUIBar::DrawDC(
ocpnDC &dc,
double displayScale) {
1341 dc.DrawBitmap(m_bitmap, m_screenPos.x, m_screenPos.y,
false);
1344 void MUIBar::ResetCanvasOptions() {
1345 delete m_canvasOptions;
1346 m_canvasOptions = NULL;
1349 void MUIBar::PullCanvasOptions() {
1351 int cox = m_parentCanvas->GetSize().x - m_canvasOptionsFullSize.x;
1352 int coy = m_COTopOffset;
1353 m_targetCOPos = m_parentCanvas->ClientToScreen(wxPoint(cox, coy));
1356 m_canvasOptions->Move(m_targetCOPos);
1357 m_canvasOptions->Show();
1363 if (m_coAnimateByBitmaps && !m_animateBitmap.IsOk()) {
1364 m_canvasOptions->Move(m_targetCOPos);
1365 m_canvasOptions->Show();
1366 CaptureCanvasOptionsBitmap();
1372 m_startCOPos = m_canvasOptions->GetPosition();
1375 m_currentCOPos = m_startCOPos;
1377 m_animationType = CO_ANIMATION_CUBIC_REVERSE;
1378 m_animateSteps = 10;
1379 m_animationTotalTime = 200;
1381 m_pushPull = CO_PULL;
1383 pcc->m_b_paint_enable =
false;
1387 m_canvasOptionsAnimationTimer.Start(10,
true);
1388 m_canvasOptions->Move(m_targetCOPos);
1389 m_canvasOptions->Hide();
1392 void MUIBar::PushCanvasOptions() {
1394 m_canvasOptions->Hide();
1401 int cox = m_parentCanvas->GetSize().x;
1405 m_targetCOPos = m_parentCanvas->ClientToScreen(wxPoint(cox, coy));
1407 m_targetCOPos = wxPoint(cox, coy);
1410 m_startCOPos = m_canvasOptions->GetPosition();
1413 m_currentCOPos = m_startCOPos;
1416 m_animationType = CO_ANIMATION_LINEAR;
1418 m_animationTotalTime = 100;
1419 m_pushPull = CO_PUSH;
1424 m_canvasOptionsAnimationTimer.Start(10,
true);
1425 m_canvasOptions->Show();
1428 void MUIBar::onCanvasOptionsAnimationTimerEvent(wxTimerEvent& event) {
1429 double progress = m_animateStep / (double)m_animateSteps;
1430 double valueX = getValue(m_animationType, progress);
1432 double dx = (m_targetCOPos.x - m_startCOPos.x) * valueX;
1434 wxPoint newPos = wxPoint(m_startCOPos.x + dx, m_currentCOPos.y);
1437 if (m_pushPull == CO_PULL)
1440 size_x = (m_targetCOPos.x - m_startCOPos.x) - abs(dx);
1442 if (!m_coAnimateByBitmaps) {
1443 m_canvasOptions->SetSize(newPos.x, newPos.y, size_x, wxDefaultCoord,
1444 wxSIZE_USE_EXISTING);
1446 m_canvasOptions->Show();
1448 m_canvasOptions->Hide();
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);
1461 wxMemoryDC mdc(m_animateBitmap);
1462 sdc.Blit(newPos.x, newPos.y, size_x, m_animateBitmap.GetHeight(), &mdc, 0,
1464 mdc.SelectObject(wxNullBitmap);
1467 m_currentCOPos = newPos;
1469 double dt = m_animationTotalTime / m_animateSteps;
1471 if (m_animateStep++ < m_animateSteps + 1) {
1472 m_canvasOptionsAnimationTimer.Start(dt,
true);
1474 m_currentCOPos = m_targetCOPos;
1475 m_canvasOptions->Show(m_pushPull == CO_PULL);
1479 pcc->m_b_paint_enable =
true;
1481 if (m_pushPull == CO_PUSH) {
1482 delete m_canvasOptions;
1483 m_canvasOptions = NULL;
1486 if (m_pushPull == CO_PUSH) pcc->TriggerDeferredFocus();
1488 pcc->TriggerDeferredFocus();
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)) {
1504 return -a * (1. - (7.5625 * t * t + .75)) + c;
1505 }
else if (t < (10 / 11.0)) {
1507 return -a * (1. - (7.5625 * t * t + .9375)) + c;
1510 return -a * (1. - (7.5625 * t * t + .984375)) + c;
1514 double getValue(
int animationType,
double t) {
1518 switch (animationType) {
1519 case CO_ANIMATION_LINEAR:
1523 case CO_ANIMATION_CUBIC:
1525 value = tp * tp * tp + 1;
1528 case CO_ANIMATION_CUBIC_REVERSE:
1530 value = tp * tp * tp + 1;
1532 case CO_ANIMATION_CUBIC_BOUNCE_IN:
1533 value = bounceMaker(t, 1, s);
1536 case CO_ANIMATION_CUBIC_BACK_IN:
1538 value = tp * tp * ((s + 1) * tp + s) + 1;
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.
wxTextCtrl * m_ScaleCtl
Should we show tooltips?
SetScaleDialog()
Constructors.