36#include "model/config_vars.h"
37#include "model/cutil.h"
38#include "model/wx28compat.h"
46#include "OCPNPlatform.h"
47#include "color_handler.h"
49#include "ocpn_frame.h"
51#ifdef __OCPN__ANDROID__
53#include "androidUTIL.h"
57#include "glChartCanvas.h"
60#include <wx/arrimpl.cpp>
61WX_DEFINE_OBJARRAY(RectArray);
68extern int g_GUIScaleFactor;
70extern float g_toolbar_scalefactor;
78BEGIN_EVENT_TABLE(
Piano, wxEvtHandler)
79EVT_TIMER(PIANO_EVENT_TIMER, Piano::onTimerEvent)
84 m_parentCanvas = parent;
89 m_hover_icon_last = -1;
93 m_gotPianoDown =
false;
101 m_pVizIconBmp = NULL;
102 m_pInVizIconBmp = NULL;
103 m_pPolyIconBmp = NULL;
104 m_pSkewIconBmp = NULL;
105 m_pTmercIconBmp = NULL;
107 SetColorScheme(GLOBAL_COLOR_SCHEME_RGB);
109 m_eventTimer.SetOwner(
this, PIANO_EVENT_TIMER);
111 m_tex = m_tex_piano_height = 0;
112 m_piano_mode = PIANO_MODE_LEGACY;
116 if (m_pInVizIconBmp)
delete m_pInVizIconBmp;
117 if (m_pPolyIconBmp)
delete m_pPolyIconBmp;
118 if (m_pSkewIconBmp)
delete m_pSkewIconBmp;
119 if (m_pTmercIconBmp)
delete m_pTmercIconBmp;
120 if (m_pVizIconBmp)
delete m_pVizIconBmp;
123void Piano::Paint(
int y, wxDC &dc, wxDC *shapeDC) {
125 Paint(y, odc, shapeDC);
128void Piano::Paint(
int y,
ocpnDC &dc, wxDC *shapeDC) {
130 shapeDC->SetBackground(*wxBLACK_BRUSH);
131 shapeDC->SetBrush(*wxWHITE_BRUSH);
132 shapeDC->SetPen(*wxWHITE_PEN);
137 if (!style->chartStatusWindowTransparent) {
138 dc.SetPen(*wxTRANSPARENT_PEN);
139 dc.SetBrush(m_backBrush);
140 dc.DrawRectangle(0, y, m_parentCanvas->GetClientSize().x, GetHeight());
145 int nKeys = m_composite_array.size();
147 wxPen ppPen(GetGlobalColor(_T(
"CHBLK")), 1, wxPENSTYLE_SOLID);
150 for (
int i = 0; i < nKeys; i++) {
151 int chart_family = m_composite_array[i].chart_family;
152 int chart_type = m_composite_array[i].chart_type;
154 bool selected = IsAnyActiveChartInPianoKeyElement(m_composite_array[i]);
156 if (chart_type == CHART_TYPE_CM93 || chart_type == CHART_TYPE_CM93COMP) {
158 dc.SetBrush(m_scBrush);
160 dc.SetBrush(m_cBrush);
161 }
else if (chart_type == CHART_TYPE_MBTILES) {
163 dc.SetBrush(m_tileBrush);
165 dc.SetBrush(m_utileBrush);
166 }
else if (chart_family == CHART_FAMILY_VECTOR) {
168 dc.SetBrush(m_svBrush);
170 dc.SetBrush(m_vBrush);
173 dc.SetBrush(m_srBrush);
175 dc.SetBrush(m_rBrush);
178 if (m_bBusy) dc.SetBrush(m_unavailableBrush);
180 wxRect box = KeyRect[i];
184 dc.DrawRoundedRectangle(box.x, box.y, box.width, box.height,
187 shapeDC->DrawRoundedRectangle(box.x, box.y, box.width, box.height,
190 dc.DrawRectangle(box.x, box.y, box.width, box.height);
191 if (shapeDC) shapeDC->DrawRectangle(box);
194 if (IsAllEclipsedChartInPianoKeyElement(m_composite_array[i])) {
196 dc.SetBrush(m_backBrush);
198 dc.DrawRoundedRectangle(box.x + w, box.y + w, box.width - (2 * w),
199 box.height - (2 * w), box.height / 5 - 1);
204 if (InArray(m_noshow_index_array, key_db_index) && m_pInVizIconBmp &&
205 m_pInVizIconBmp->IsOk())
206 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pInVizIconBmp),
207 box.x + 4, box.y + 3,
false);
210 if (InArray(m_skew_index_array, key_db_index) && m_pSkewIconBmp &&
211 m_pSkewIconBmp->IsOk())
212 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pSkewIconBmp),
213 box.x + box.width - m_pSkewIconBmp->GetWidth() - 4,
217 if (InArray(m_tmerc_index_array, key_db_index) && m_pTmercIconBmp &&
218 m_pTmercIconBmp->IsOk())
219 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pTmercIconBmp),
220 box.x + box.width - m_pTmercIconBmp->GetWidth() - 4,
224 if (InArray(m_poly_index_array, key_db_index) && m_pPolyIconBmp &&
225 m_pPolyIconBmp->IsOk())
226 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pPolyIconBmp),
227 box.x + box.width - m_pPolyIconBmp->GetWidth() - 4,
234static void SetColor(
unsigned char color[4],
const wxBrush &brush)
236 const wxColour &c = brush.GetColour();
237 color[0] = c.Red(), color[1] = c.Green(), color[2] = c.Blue(), color[3] = 255;
244void Piano::BuildGLTexture() {
248 if (!m_pInVizIconBmp || !m_pTmercIconBmp || !m_pSkewIconBmp ||
256 if (style->chartStatusWindowTransparent)
257 tbackBrush = wxColour(1, 1, 1);
259 tbackBrush = m_backBrush;
261 wxBrush brushes[] = {m_scBrush, m_cBrush, m_svBrush,
262 m_vBrush, m_srBrush, m_rBrush,
263 m_tileBrush, m_utileBrush, m_unavailableBrush};
268 m_texPitch = ((2 * m_ref) + (2 * m_pad));
270 m_tex_piano_height = h;
271 m_texw = m_texPitch * 3;
273 m_texh = ((
sizeof brushes) / (
sizeof *brushes)) * h;
276 m_texh = NextPow2(m_texh);
277 m_texw = NextPow2(m_texw);
279 if (!m_tex) glGenTextures(1, (GLuint *)&m_tex);
281 glBindTexture(GL_TEXTURE_2D, m_tex);
282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
285 wxBitmap bmp(m_texw, m_texh);
288 dc.SetPen(*wxTRANSPARENT_PEN);
289 dc.SetBrush(tbackBrush);
290 dc.DrawRectangle(0, 0, m_texw, m_texh);
293 double nominal_line_width_pix = floor(g_Platform->GetDisplayDPmm() / 2.0);
295 nominal_line_width_pix = wxMax(1.0, nominal_line_width_pix);
298 wxPen ppPen(GetGlobalColor(_T(
"CHBLK")), nominal_line_width_pix,
301 for (
unsigned int b = 0; b < (
sizeof brushes) / (
sizeof *brushes); b++) {
302 unsigned int x = 0, y = h * b;
304 dc.SetBrush(brushes[b]);
307 dc.DrawRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v);
310 dc.DrawRoundedRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v, m_radius);
315 dc.DrawRoundedRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v, m_radius);
316 dc.SetBrush(m_backBrush);
317 dc.DrawRoundedRectangle(x + m_pad + w, y + v + w, (2 * m_ref) - (2 * w),
319 m_radius * (h - 2 * v - 2 * w) /
323 dc.SelectObject(wxNullBitmap);
325 wxImage image = bmp.ConvertToImage();
327 unsigned char *data =
new unsigned char[4 * m_texw * m_texh], *d = data,
328 *e = image.GetData(), *a = image.GetAlpha();
329 for (
unsigned int i = 0; i < m_texw * m_texh; i++) {
330 if (style->chartStatusWindowTransparent && e[0] == 1 && e[1] == 1 &&
336 memcpy(d, e, 3), d += 4, e += 3;
339 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_texw, m_texh, 0, GL_RGBA,
340 GL_UNSIGNED_BYTE, data);
344 wxBitmap *bitmaps[] = {m_pInVizIconBmp, m_pTmercIconBmp, m_pSkewIconBmp,
347 for (
unsigned int i = 0; i < 4; i++) {
348 int iw = bitmaps[i]->GetWidth(), ih = bitmaps[i]->GetHeight();
350 wxImage im = bitmaps[i]->ConvertToImage();
351 unsigned char *data =
new unsigned char[4 * iw * ih], *d = data,
352 *e = im.GetData(), *a = im.GetAlpha();
353 for (
int j = 0; j < iw * ih; j++) {
354 memcpy(d, e, 3), d += 3, e += 3;
358 int off = ((
sizeof brushes) / (
sizeof *brushes)) * h + m_ref * i;
359 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, off, iw, ih, GL_RGBA, GL_UNSIGNED_BYTE,
366void Piano::DrawGL(
int off) {
return DrawGLSL(off); }
367void Piano::DrawGLSL(
int off) {
369 unsigned int w = m_parentCanvas->GetClientSize().x *
370 m_parentCanvas->GetContentScaleFactor();
372 unsigned int endx = 0;
374 if (
static_cast<int>(m_tex_piano_height) != h) BuildGLTexture();
376 if (
static_cast<int>(m_tex_piano_height) != h)
return;
378 int y1 = off, y2 = y1 + h;
380 int nKeys = m_composite_array.size();
384 float *texcoords =
new float[(nKeys * 3 + 1) * 4 * 2],
385 *coords =
new float[(nKeys * 3 + 1) * 4 * 2];
390 for (
int i = 0; i < nKeys; i++) {
392 int chart_family = m_composite_array[i].chart_family;
393 int chart_type = m_composite_array[i].chart_type;
395 if (chart_type == CHART_TYPE_CM93 || chart_type == CHART_TYPE_CM93COMP)
397 else if (chart_type == CHART_TYPE_MBTILES)
399 else if (chart_family == CHART_FAMILY_VECTOR)
404 if (!IsAnyActiveChartInPianoKeyElement(m_composite_array[i]))
407 wxRect box = KeyRect[i];
408 float y = h * b, v1 = (y + .5) / m_texh, v2 = (y + h - .5) / m_texh;
412 const float texcord[6] = {0,
417 (float)m_texPitch - 1};
421 if (IsAllEclipsedChartInPianoKeyElement(m_composite_array[i]))
430 int x1 = box.x, x2 = x1 + box.width, w = 2 * uindex + 1;
431 while (x1 + w > x2 - w && uindex > 0) uindex--, w -= 2;
435 int x[6] = {x1 - 3, x1 + m_ref, x2 - m_ref, x2 + 3};
439 int avg = (x[1] + x[2]) / 2;
443 for (
int i = 0; i < 3; i++) {
444 float u1 = ((uindex * m_texPitch) + texcord[2 * i] + .5) / m_texw,
445 u2 = ((uindex * m_texPitch) + texcord[2 * i + 1] + .5) / m_texw;
446 int x1 = x[i], x2 = x[i + 1];
447 texcoords[tc++] = u1, texcoords[tc++] = v1, coords[vc++] = x1,
449 texcoords[tc++] = u2, texcoords[tc++] = v1, coords[vc++] = x2,
451 texcoords[tc++] = u2, texcoords[tc++] = v2, coords[vc++] = x2,
453 texcoords[tc++] = u1, texcoords[tc++] = v2, coords[vc++] = x1,
461 if (!style->chartStatusWindowTransparent && endx < w) {
462 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = endx,
464 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = w,
466 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = w,
468 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = endx,
472 glBindTexture(GL_TEXTURE_2D, m_tex);
474 glEnable(GL_TEXTURE_2D);
477 m_parentCanvas->GetglCanvas()->RenderTextures(
478 m_parentCanvas->GetglCanvas()->m_gldc, coords, texcoords, vc / 2,
479 m_parentCanvas->GetpVP());
485 if (GetPianoMode() == PIANO_MODE_LEGACY) {
487 for (
int i = 0; i < nKeys; i++) {
488 int key_db_index = m_composite_array[i].dbindex_list[0];
490 if (-1 == key_db_index)
continue;
492 wxRect box = KeyRect[i];
494 wxBitmap *bitmaps[] = {m_pInVizIconBmp, m_pTmercIconBmp, m_pSkewIconBmp,
497 if (InArray(m_noshow_index_array, key_db_index))
500 if (InArray(m_skew_index_array, key_db_index))
502 else if (InArray(m_tmerc_index_array, key_db_index))
504 else if (InArray(m_poly_index_array, key_db_index))
510 int x1, y1, iw = bitmaps[index]->GetWidth(),
511 ih = bitmaps[index]->GetHeight();
512 if (InArray(m_noshow_index_array, key_db_index))
513 x1 = box.x + 4, y1 = box.y + 3;
515 x1 = box.x + box.width - iw - 4, y1 = box.y + 2;
518 int x2 = x1 + iw, y2 = y1 + ih;
520 wxBrush brushes[] = {m_scBrush, m_cBrush, m_svBrush,
521 m_vBrush, m_srBrush, m_rBrush,
522 m_tileBrush, m_utileBrush, m_unavailableBrush};
524 float yoff = ((
sizeof brushes) / (
sizeof *brushes)) * h + 16 * index;
525 float u1 = 0, u2 = (float)iw / m_texw;
526 float v1 = yoff / m_texh, v2 = (yoff + ih) / m_texh;
528 texcoords[tc++] = u1, texcoords[tc++] = v1, coords[vc++] = x1,
530 texcoords[tc++] = u2, texcoords[tc++] = v1, coords[vc++] = x2,
532 texcoords[tc++] = u2, texcoords[tc++] = v2, coords[vc++] = x2,
534 texcoords[tc++] = u1, texcoords[tc++] = v2, coords[vc++] = x1,
537 glEnable(GL_TEXTURE_2D);
538 glBindTexture(GL_TEXTURE_2D, m_tex);
541 m_parentCanvas->GetglCanvas()->RenderTextures(
542 m_parentCanvas->GetglCanvas()->m_gldc, coords, texcoords, vc / 2,
543 m_parentCanvas->GetpVP());
548 glDisable(GL_TEXTURE_2D);
554void Piano::SetColorScheme(ColorScheme cs) {
557 m_backBrush = wxBrush(GetGlobalColor(_T(
"UIBDR")), wxBRUSHSTYLE_SOLID);
559 m_rBrush = wxBrush(GetGlobalColor(_T(
"BLUE2")),
562 wxBrush(GetGlobalColor(_T(
"BLUE1")), wxBRUSHSTYLE_SOLID);
564 m_vBrush = wxBrush(GetGlobalColor(_T(
"GREEN2")),
566 m_svBrush = wxBrush(GetGlobalColor(_T(
"GREEN1")),
569 m_utileBrush = wxBrush(GetGlobalColor(_T(
"VIO01")),
572 wxBrush(GetGlobalColor(_T(
"VIO02")), wxBRUSHSTYLE_SOLID);
574 m_cBrush = wxBrush(GetGlobalColor(_T(
"YELO2")),
577 wxBrush(GetGlobalColor(_T(
"YELO1")), wxBRUSHSTYLE_SOLID);
579 m_unavailableBrush = wxBrush(GetGlobalColor(_T(
"UINFD")),
582 m_tex_piano_height = 0;
585void Piano::ShowBusy(
bool busy) {
592 for (
auto &index : m_active_index_array) {
593 auto found = find(pke.dbindex_list.begin(), pke.dbindex_list.end(), index);
594 if (found != pke.dbindex_list.end())
return true;
600 bool bfound_all =
true;
601 for (
auto &index : pke.dbindex_list) {
602 auto found = find(m_eclipsed_index_array.begin(),
603 m_eclipsed_index_array.end(), index);
604 if (found == m_eclipsed_index_array.end()) bfound_all =
false;
609void Piano::SetKeyArray(std::vector<int> ¢er_array,
610 std::vector<int> &full_array) {
613 if (center_array.size()) {
614 int refd = m_parentCanvas->GetCharWidth();
616 int nkeys = center_array.size();
617 int key_width = (m_width_avail / refd) / nkeys;
619 m_piano_mode = PIANO_MODE_COMPOSITE;
620 m_key_array = full_array;
622 m_piano_mode = PIANO_MODE_LEGACY;
623 m_key_array = center_array;
626 m_piano_mode = PIANO_MODE_LEGACY;
631 m_composite_array.clear();
633 if (m_piano_mode == PIANO_MODE_COMPOSITE) {
634 for (
size_t i = 0; i < m_key_array.size(); i++) {
636 ChartData->GetChartTableEntry(m_key_array[i]);
637 int scale = cte.GetScale();
638 auto order = std::pow(10, std::floor(std::log10(
scale)));
641 int chart_type = cte.GetChartType();
642 int chart_family = cte.GetChartFamily();
648 if ((cte.GetChartFamily() == CHART_FAMILY_VECTOR) ||
649 ((cte.GetChartFamily() == CHART_FAMILY_RASTER) &&
650 (cte.GetChartType() != CHART_TYPE_MBTILES))) {
652 return ((
scale == pke.chart_scale) &&
653 (chart_family == pke.chart_family));
655 auto found = find_if(m_composite_array.begin(), m_composite_array.end(),
657 if (found == m_composite_array.end()) {
659 new_pke.chart_scale =
scale;
660 new_pke.chart_family = (ChartFamilyEnum)cte.GetChartFamily();
661 new_pke.chart_type = (ChartTypeEnum)cte.GetChartType();
662 new_pke.dbindex_list.push_back(m_key_array[i]);
663 m_composite_array.push_back(new_pke);
666 ex_pke.dbindex_list.push_back(m_key_array[i]);
670 new_pke.chart_scale =
scale;
671 new_pke.chart_family = (ChartFamilyEnum)cte.GetChartFamily();
672 new_pke.chart_type = (ChartTypeEnum)cte.GetChartType();
673 new_pke.dbindex_list.push_back(m_key_array[i]);
674 m_composite_array.push_back(new_pke);
678 for (
size_t i = 0; i < m_key_array.size(); i++) {
680 ChartData->GetChartTableEntry(m_key_array[i]);
681 int scale = cte.GetScale();
682 int chart_type = cte.GetChartType();
684 new_pke.chart_scale =
scale;
685 new_pke.chart_family = (ChartFamilyEnum)cte.GetChartFamily();
686 new_pke.chart_type = (ChartTypeEnum)cte.GetChartType();
687 new_pke.dbindex_list.push_back(m_key_array[i]);
688 m_composite_array.push_back(new_pke);
693 std::sort(m_composite_array.begin(), m_composite_array.end(),
695 return a.chart_scale < b.chart_scale;
699void Piano::SetNoshowIndexArray(std::vector<int> array) {
700 m_noshow_index_array = array;
703void Piano::AddNoshowIndexArray(std::vector<int> array) {
704 for (
unsigned int i = 0; i < array.size(); i++) {
705 m_noshow_index_array.push_back(array[i]);
709void Piano::SetActiveKeyArray(std::vector<int> array) {
710 m_active_index_array = array;
713void Piano::SetEclipsedIndexArray(std::vector<int> array) {
714 m_eclipsed_index_array = array;
717void Piano::SetSkewIndexArray(std::vector<int> array) {
718 m_skew_index_array = array;
721void Piano::SetTmercIndexArray(std::vector<int> array) {
722 m_tmerc_index_array = array;
725void Piano::SetPolyIndexArray(std::vector<int> array) {
726 m_poly_index_array = array;
729bool Piano::InArray(std::vector<int> &array,
int key) {
730 for (
unsigned int ino = 0; ino < array.size(); ino++)
731 if (array[ino] == key)
return true;
735wxString Piano::GetStateHash() {
738 for (
unsigned int i = 0; i < m_key_array.size(); i++) {
740 a.Printf(_T(
"%dK"), m_key_array[i]);
743 for (
unsigned int i = 0; i < m_noshow_index_array.size(); i++) {
745 a.Printf(_T(
"%dN"), m_noshow_index_array[i]);
748 for (
unsigned int i = 0; i < m_active_index_array.size(); i++) {
750 a.Printf(_T(
"%dA"), m_active_index_array[i]);
753 for (
unsigned int i = 0; i < m_eclipsed_index_array.size(); i++) {
755 a.Printf(_T(
"%dE"), m_eclipsed_index_array[i]);
758 for (
unsigned int i = 0; i < m_skew_index_array.size(); i++) {
760 a.Printf(_T(
"%dW"), m_skew_index_array[i]);
763 for (
unsigned int i = 0; i < m_tmerc_index_array.size(); i++) {
765 a.Printf(_T(
"%dM"), m_tmerc_index_array[i]);
768 for (
unsigned int i = 0; i < m_poly_index_array.size(); i++) {
770 a.Printf(_T(
"%dP"), m_poly_index_array[i]);
777wxString &Piano::GenerateAndStoreNewHash() {
778 m_hash = GetStateHash();
782wxString &Piano::GetStoredHash() {
return m_hash; }
784void Piano::FormatKeys(
void) {
786 int width = m_parentCanvas->GetClientSize().x;
788 if (g_bopengl) width *= m_parentCanvas->GetContentScaleFactor();
790 width *= m_parentCanvas->GetContentScaleFactor();
794 wxSize mui_tool_size = g_StyleManager->GetCurrentStyle()->GetToolSize();
796 mui_tool_size = wxSize(mui_tool_size.x * 1.25, mui_tool_size.y * 1.25);
798 int mui_bar_width_est = mui_tool_size.x * 8 * g_toolbar_scalefactor;
800 if (m_parentCanvas->GetClientSize().x < m_parentCanvas->GetClientSize().y) {
811 m_width_avail = width;
813 int height = GetHeight();
815 int nKeys = m_composite_array.size();
816 int kw = style->chartStatusIconWidth;
818 if (!kw) kw = width / nKeys;
827 for (
int i = 0; i < nKeys; i++) {
828 wxRect r((i * kw) + 3, 2, kw - 6, height - 4);
829 KeyRect.push_back(r);
830 m_width = r.x + r.width;
836wxPoint Piano::GetKeyOrigin(
int key_index) {
837 if ((key_index >= 0) && (key_index <= (
int)m_key_array.size() - 1)) {
838 wxRect box = KeyRect[key_index];
839 return wxPoint(box.x, box.y);
841 return wxPoint(-1, -1);
844bool Piano::MouseEvent(wxMouseEvent &event) {
846 event.GetPosition(&x, &y);
855 int ytop = m_parentCanvas->GetCanvasHeight() - GetHeight();
857 if (!g_bopengl) ytop = m_parentCanvas->GetClientSize().y - GetHeight();
860 if (event.Leaving() || (y < ytop) || (x > GetWidth())) {
861 if (m_bleaving)
return false;
869 int sel_dbindex = -1;
871 for (
int i = 0; i < m_nRegions; i++) {
872 if (KeyRect[i].Contains(x, 6)) {
874 sel_dbindex = m_key_array[i];
880 if (event.LeftDown()) {
881 if (-1 != sel_index) {
882 m_action = DEFERRED_KEY_CLICK_DOWN;
884 m_eventTimer.Start(10, wxTIMER_ONE_SHOT);
887 if (event.LeftUp()) {
888 if (-1 != sel_index) {
889 m_click_sel_index = sel_index;
890 if (!m_eventTimer.IsRunning()) {
891 m_action = DEFERRED_KEY_CLICK_UP;
892 m_eventTimer.Start(10, wxTIMER_ONE_SHOT);
895 }
else if (event.RightDown()) {
896 if (sel_index != m_hover_last) {
898 m_parentCanvas->HandlePianoRollover(
899 sel_index, m_composite_array[sel_index].dbindex_list,
900 m_composite_array[sel_index].dbindex_list.size(),
901 m_composite_array[sel_index].chart_scale);
902 m_hover_last = sel_index;
907 }
else if (event.ButtonUp()) {
908 m_parentCanvas->ClearPianoRollover();
913 m_parentCanvas->ClearPianoRollover();
915 }
else if (event.LeftDown()) {
916 if (-1 != sel_index) {
917 m_parentCanvas->HandlePianoClick(
918 sel_index, m_composite_array[sel_index].dbindex_list);
920 m_parentCanvas->Raise();
923 }
else if (event.RightDown()) {
924 if (-1 != sel_index) {
925 m_parentCanvas->HandlePianoRClick(
926 x, y, sel_index, m_composite_array[sel_index].dbindex_list);
927 m_parentCanvas->Raise();
930 }
else if (!event.ButtonUp()) {
931 if (sel_index != m_hover_last) {
933 m_parentCanvas->HandlePianoRollover(
934 sel_index, m_composite_array[sel_index].dbindex_list,
935 m_composite_array[sel_index].dbindex_list.size(),
936 m_composite_array[sel_index].chart_scale);
938 m_hover_last = sel_index;
957void Piano::ResetRollover(
void) {
959 m_hover_icon_last = -1;
961 m_gotPianoDown =
false;
964int Piano::GetHeight() {
967 if (g_bopengl) height *= m_parentCanvas->GetContentScaleFactor();
970 double size_mult = exp(g_GUIScaleFactor * 0.0953101798043);
972 height = wxMin(height, 100);
973 height = wxMax(height, 10);
975 height *= g_Platform->GetDisplayDensityFactor();
977#ifdef __OCPN__ANDROID__
978 height = wxMax(height, 4 * g_Platform->GetDisplayDPmm());
986int Piano::GetWidth() {
return m_width; }
988void Piano::onTimerEvent(wxTimerEvent &event) {
990 case DEFERRED_KEY_CLICK_DOWN:
991 m_gotPianoDown =
true;
993 case DEFERRED_KEY_CLICK_UP:
995 if ((m_hover_last >= 0) || !m_gotPianoDown) {
996 m_parentCanvas->ClearPianoRollover();
999 m_parentCanvas->HandlePianoClick(
1001 m_composite_array[m_click_sel_index].dbindex_list);
1002 m_gotPianoDown =
false;
1005 case INFOWIN_TIMEOUT:
1006 m_parentCanvas->ClearPianoRollover();
ChartCanvas - Main chart display and interaction component.
Manages the chart database and provides access to chart data.
Device context class that can use either wxDC or OpenGL for drawing.
PlugIn Object Definition/API.
double OCPN_GetDisplayContentScaleFactor()
Gets content scaling factor for current display.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Represents an entry in the chart table, containing information about a single chart.