29 #include <wx/wxprec.h>
36 #include "model/config_vars.h"
37 #include "model/cutil.h"
38 #include "model/wx28compat.h"
43 #include "chartbase.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>
61 WX_DEFINE_OBJARRAY(RectArray);
68 extern int g_GUIScaleFactor;
69 extern bool g_bopengl;
70 extern float g_toolbar_scalefactor;
79 BEGIN_EVENT_TABLE(
Piano, wxEvtHandler)
80 EVT_TIMER(PIANO_EVENT_TIMER, Piano::onTimerEvent)
85 m_parentCanvas = parent;
90 m_hover_icon_last = -1;
94 m_gotPianoDown =
false;
102 m_pVizIconBmp = NULL;
103 m_pInVizIconBmp = NULL;
104 m_pPolyIconBmp = NULL;
105 m_pSkewIconBmp = NULL;
106 m_pTmercIconBmp = NULL;
108 SetColorScheme(GLOBAL_COLOR_SCHEME_RGB);
110 m_eventTimer.SetOwner(
this, PIANO_EVENT_TIMER);
112 m_tex = m_tex_piano_height = 0;
113 m_piano_mode = PIANO_MODE_LEGACY;
117 if (m_pInVizIconBmp)
delete m_pInVizIconBmp;
118 if (m_pPolyIconBmp)
delete m_pPolyIconBmp;
119 if (m_pSkewIconBmp)
delete m_pSkewIconBmp;
120 if (m_pTmercIconBmp)
delete m_pTmercIconBmp;
121 if (m_pVizIconBmp)
delete m_pVizIconBmp;
124 void Piano::Paint(
int y, wxDC &dc, wxDC *shapeDC) {
126 Paint(y, odc, shapeDC);
129 void Piano::Paint(
int y,
ocpnDC &dc, wxDC *shapeDC) {
131 shapeDC->SetBackground(*wxBLACK_BRUSH);
132 shapeDC->SetBrush(*wxWHITE_BRUSH);
133 shapeDC->SetPen(*wxWHITE_PEN);
138 if (!style->chartStatusWindowTransparent) {
139 dc.SetPen(*wxTRANSPARENT_PEN);
140 dc.SetBrush(m_backBrush);
141 dc.DrawRectangle(0, y, m_parentCanvas->GetClientSize().x, GetHeight());
146 int nKeys = m_composite_array.size();
148 wxPen ppPen(GetGlobalColor(_T(
"CHBLK")), 1, wxPENSTYLE_SOLID);
151 for (
int i = 0; i < nKeys; i++) {
152 int chart_family = m_composite_array[i].chart_family;
153 int chart_type = m_composite_array[i].chart_type;
155 bool selected = IsAnyActiveChartInPianoKeyElement(m_composite_array[i]);
157 if (chart_type == CHART_TYPE_CM93 ||
158 chart_type == CHART_TYPE_CM93COMP) {
160 dc.SetBrush(m_scBrush);
162 dc.SetBrush(m_cBrush);
163 }
else if (chart_type == CHART_TYPE_MBTILES) {
165 dc.SetBrush(m_tileBrush);
167 dc.SetBrush(m_utileBrush);
168 }
else if (chart_family == CHART_FAMILY_VECTOR) {
170 dc.SetBrush(m_svBrush);
172 dc.SetBrush(m_vBrush);
175 dc.SetBrush(m_srBrush);
177 dc.SetBrush(m_rBrush);
180 if (m_bBusy) dc.SetBrush(m_unavailableBrush);
182 wxRect box = KeyRect[i];
186 dc.DrawRoundedRectangle(box.x, box.y, box.width, box.height,
189 shapeDC->DrawRoundedRectangle(box.x, box.y, box.width, box.height,
192 dc.DrawRectangle(box.x, box.y, box.width, box.height);
193 if (shapeDC) shapeDC->DrawRectangle(box);
196 if (IsAllEclipsedChartInPianoKeyElement(m_composite_array[i])) {
198 dc.SetBrush(m_backBrush);
200 dc.DrawRoundedRectangle(box.x + w, box.y + w, box.width - (2 * w),
201 box.height - (2 * w), box.height / 5 - 1);
206 if (InArray(m_noshow_index_array, key_db_index) && m_pInVizIconBmp &&
207 m_pInVizIconBmp->IsOk())
208 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pInVizIconBmp),
209 box.x + 4, box.y + 3,
false);
212 if (InArray(m_skew_index_array, key_db_index) && m_pSkewIconBmp &&
213 m_pSkewIconBmp->IsOk())
214 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pSkewIconBmp),
215 box.x + box.width - m_pSkewIconBmp->GetWidth() - 4,
219 if (InArray(m_tmerc_index_array, key_db_index) && m_pTmercIconBmp &&
220 m_pTmercIconBmp->IsOk())
221 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pTmercIconBmp),
222 box.x + box.width - m_pTmercIconBmp->GetWidth() - 4,
226 if (InArray(m_poly_index_array, key_db_index) && m_pPolyIconBmp &&
227 m_pPolyIconBmp->IsOk())
228 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pPolyIconBmp),
229 box.x + box.width - m_pPolyIconBmp->GetWidth() - 4,
236 static void SetColor(
unsigned char color[4],
const wxBrush &brush)
238 const wxColour &c = brush.GetColour();
239 color[0] = c.Red(), color[1] = c.Green(), color[2] = c.Blue(), color[3] = 255;
246 void Piano::BuildGLTexture() {
250 if (!m_pInVizIconBmp || !m_pTmercIconBmp || !m_pSkewIconBmp ||
258 if (style->chartStatusWindowTransparent)
259 tbackBrush = wxColour(1, 1, 1);
261 tbackBrush = m_backBrush;
263 wxBrush brushes[] = {m_scBrush, m_cBrush, m_svBrush,
264 m_vBrush, m_srBrush, m_rBrush,
265 m_tileBrush, m_utileBrush, m_unavailableBrush};
270 m_texPitch = ((2 * m_ref) + (2 * m_pad));
272 m_tex_piano_height = h;
273 m_texw = m_texPitch * 3;
275 m_texh = ((
sizeof brushes) / (
sizeof *brushes)) * h;
278 m_texh = NextPow2(m_texh);
279 m_texw = NextPow2(m_texw);
281 if (!m_tex) glGenTextures(1, (GLuint *)&m_tex);
283 glBindTexture(GL_TEXTURE_2D, m_tex);
284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
285 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
287 wxBitmap bmp(m_texw, m_texh);
290 dc.SetPen(*wxTRANSPARENT_PEN);
291 dc.SetBrush(tbackBrush);
292 dc.DrawRectangle(0, 0, m_texw, m_texh);
295 double nominal_line_width_pix = floor(g_Platform->GetDisplayDPmm() / 2.0);
296 nominal_line_width_pix *= OCPN_GetWinDIPScaleFactor();
297 nominal_line_width_pix = wxMax(1.0, nominal_line_width_pix);
300 wxPen ppPen(GetGlobalColor(_T(
"CHBLK")), nominal_line_width_pix,
303 for (
unsigned int b = 0; b < (
sizeof brushes) / (
sizeof *brushes); b++) {
304 unsigned int x = 0, y = h * b;
306 dc.SetBrush(brushes[b]);
309 dc.DrawRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v);
312 dc.DrawRoundedRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v, m_radius);
317 dc.DrawRoundedRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v, m_radius);
318 dc.SetBrush(m_backBrush);
319 dc.DrawRoundedRectangle(x + m_pad + w, y + v + w, (2 * m_ref) - (2 * w),
321 m_radius * (h - 2 * v - 2 * w) /
325 dc.SelectObject(wxNullBitmap);
327 wxImage image = bmp.ConvertToImage();
329 unsigned char *data =
new unsigned char[4 * m_texw * m_texh], *d = data,
330 *e = image.GetData(), *a = image.GetAlpha();
331 for (
unsigned int i = 0; i < m_texw * m_texh; i++) {
332 if (style->chartStatusWindowTransparent && e[0] == 1 && e[1] == 1 &&
338 memcpy(d, e, 3), d += 4, e += 3;
341 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_texw, m_texh, 0, GL_RGBA,
342 GL_UNSIGNED_BYTE, data);
346 wxBitmap *bitmaps[] = {m_pInVizIconBmp, m_pTmercIconBmp, m_pSkewIconBmp,
349 for (
unsigned int i = 0; i < 4; i++) {
350 int iw = bitmaps[i]->GetWidth(), ih = bitmaps[i]->GetHeight();
352 wxImage im = bitmaps[i]->ConvertToImage();
353 unsigned char *data =
new unsigned char[4 * iw * ih], *d = data,
354 *e = im.GetData(), *a = im.GetAlpha();
355 for (
int j = 0; j < iw * ih; j++) {
356 memcpy(d, e, 3), d += 3, e += 3;
360 int off = ((
sizeof brushes) / (
sizeof *brushes)) * h + m_ref * i;
361 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, off, iw, ih, GL_RGBA, GL_UNSIGNED_BYTE,
368 void Piano::DrawGL(
int off) {
369 return DrawGLSL(off);
371 void Piano::DrawGLSL(
int off) {
373 unsigned int w = m_parentCanvas->GetClientSize().x *
374 m_parentCanvas->GetContentScaleFactor();
376 unsigned int endx = 0;
378 if (
static_cast<int>(m_tex_piano_height) != h) BuildGLTexture();
380 if (
static_cast<int>(m_tex_piano_height) != h)
return;
382 int y1 = off, y2 = y1 + h;
384 int nKeys = m_composite_array.size();
388 float *texcoords =
new float[(nKeys * 3 + 1) * 4 * 2],
389 *coords =
new float[(nKeys * 3 + 1) * 4 * 2];
394 for (
int i = 0; i < nKeys; i++) {
396 int chart_family = m_composite_array[i].chart_family;
397 int chart_type = m_composite_array[i].chart_type;
399 if (chart_type == CHART_TYPE_CM93 || chart_type == CHART_TYPE_CM93COMP)
401 else if (chart_type == CHART_TYPE_MBTILES)
403 else if (chart_family == CHART_FAMILY_VECTOR)
408 if (!IsAnyActiveChartInPianoKeyElement(m_composite_array[i]))
411 wxRect box = KeyRect[i];
412 float y = h * b, v1 = (y + .5) / m_texh, v2 = (y + h - .5) / m_texh;
416 const float texcord[6] = {0,
421 (float)m_texPitch - 1};
425 if (IsAllEclipsedChartInPianoKeyElement(m_composite_array[i]))
434 int x1 = box.x, x2 = x1 + box.width, w = 2 * uindex + 1;
435 while (x1 + w > x2 - w && uindex > 0) uindex--, w -= 2;
439 int x[6] = {x1 - 3, x1 + m_ref, x2 - m_ref, x2 + 3};
443 int avg = (x[1] + x[2]) / 2;
447 for (
int i = 0; i < 3; i++) {
448 float u1 = ((uindex * m_texPitch) + texcord[2 * i] + .5) / m_texw,
449 u2 = ((uindex * m_texPitch) + texcord[2 * i + 1] + .5) / m_texw;
450 int x1 = x[i], x2 = x[i + 1];
451 texcoords[tc++] = u1, texcoords[tc++] = v1, coords[vc++] = x1,
453 texcoords[tc++] = u2, texcoords[tc++] = v1, coords[vc++] = x2,
455 texcoords[tc++] = u2, texcoords[tc++] = v2, coords[vc++] = x2,
457 texcoords[tc++] = u1, texcoords[tc++] = v2, coords[vc++] = x1,
465 if (!style->chartStatusWindowTransparent && endx < w) {
466 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = endx,
468 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = w,
470 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = w,
472 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = endx,
476 glBindTexture(GL_TEXTURE_2D, m_tex);
478 glEnable(GL_TEXTURE_2D);
481 m_parentCanvas->GetglCanvas()->RenderTextures(
482 m_parentCanvas->GetglCanvas()->m_gldc, coords, texcoords, vc / 2,
483 m_parentCanvas->GetpVP());
489 if (GetPianoMode() == PIANO_MODE_LEGACY) {
491 for (
int i = 0; i < nKeys; i++) {
492 int key_db_index = m_composite_array[i].dbindex_list[0];
494 if (-1 == key_db_index)
continue;
496 wxRect box = KeyRect[i];
498 wxBitmap *bitmaps[] = {m_pInVizIconBmp, m_pTmercIconBmp, m_pSkewIconBmp,
501 if (InArray(m_noshow_index_array, key_db_index))
504 if (InArray(m_skew_index_array, key_db_index))
506 else if (InArray(m_tmerc_index_array, key_db_index))
508 else if (InArray(m_poly_index_array, key_db_index))
514 int x1, y1, iw = bitmaps[index]->GetWidth(),
515 ih = bitmaps[index]->GetHeight();
516 if (InArray(m_noshow_index_array, key_db_index))
517 x1 = box.x + 4, y1 = box.y + 3;
519 x1 = box.x + box.width - iw - 4, y1 = box.y + 2;
522 int x2 = x1 + iw, y2 = y1 + ih;
524 wxBrush brushes[] = {m_scBrush, m_cBrush, m_svBrush,
525 m_vBrush, m_srBrush, m_rBrush,
526 m_tileBrush, m_utileBrush, m_unavailableBrush};
528 float yoff = ((
sizeof brushes) / (
sizeof *brushes)) * h + 16 * index;
529 float u1 = 0, u2 = (float)iw / m_texw;
530 float v1 = yoff / m_texh, v2 = (yoff + ih) / m_texh;
532 texcoords[tc++] = u1, texcoords[tc++] = v1, coords[vc++] = x1,
534 texcoords[tc++] = u2, texcoords[tc++] = v1, coords[vc++] = x2,
536 texcoords[tc++] = u2, texcoords[tc++] = v2, coords[vc++] = x2,
538 texcoords[tc++] = u1, texcoords[tc++] = v2, coords[vc++] = x1,
541 glEnable(GL_TEXTURE_2D);
542 glBindTexture(GL_TEXTURE_2D, m_tex);
545 m_parentCanvas->GetglCanvas()->RenderTextures(
546 m_parentCanvas->GetglCanvas()->m_gldc, coords, texcoords, vc / 2,
547 m_parentCanvas->GetpVP());
552 glDisable(GL_TEXTURE_2D);
558 void Piano::SetColorScheme(ColorScheme cs) {
561 m_backBrush = wxBrush(GetGlobalColor(_T(
"UIBDR")), wxBRUSHSTYLE_SOLID);
563 m_rBrush = wxBrush(GetGlobalColor(_T(
"BLUE2")),
566 wxBrush(GetGlobalColor(_T(
"BLUE1")), wxBRUSHSTYLE_SOLID);
568 m_vBrush = wxBrush(GetGlobalColor(_T(
"GREEN2")),
570 m_svBrush = wxBrush(GetGlobalColor(_T(
"GREEN1")),
573 m_utileBrush = wxBrush(GetGlobalColor(_T(
"VIO01")),
576 wxBrush(GetGlobalColor(_T(
"VIO02")), wxBRUSHSTYLE_SOLID);
578 m_cBrush = wxBrush(GetGlobalColor(_T(
"YELO2")),
581 wxBrush(GetGlobalColor(_T(
"YELO1")), wxBRUSHSTYLE_SOLID);
583 m_unavailableBrush = wxBrush(GetGlobalColor(_T(
"UINFD")),
586 m_tex_piano_height = 0;
589 void Piano::ShowBusy(
bool busy) {
596 for (
auto &index : m_active_index_array){
597 auto found = find(pke.dbindex_list.begin(), pke.dbindex_list.end(), index);
598 if (found != pke.dbindex_list.end())
605 bool bfound_all =
true;
606 for (
auto &index : pke.dbindex_list){
607 auto found = find(m_eclipsed_index_array.begin(), m_eclipsed_index_array.end(), index);
608 if (found == m_eclipsed_index_array.end())
614 void Piano::SetKeyArray(std::vector<int> ¢er_array, std::vector<int> &full_array) {
617 if (center_array.size()) {
618 int refd = m_parentCanvas->GetCharWidth();
620 int nkeys = center_array.size();
621 int key_width = (m_width_avail / refd) / nkeys;
623 m_piano_mode = PIANO_MODE_COMPOSITE;
624 m_key_array = full_array;
626 m_piano_mode = PIANO_MODE_LEGACY;
627 m_key_array = center_array;
630 m_piano_mode = PIANO_MODE_LEGACY;
636 m_composite_array.clear();
638 if (m_piano_mode == PIANO_MODE_COMPOSITE) {
639 for (
size_t i = 0; i < m_key_array.size(); i++) {
640 const ChartTableEntry &cte = ChartData->GetChartTableEntry(m_key_array[i]);
641 int scale = cte.GetScale();
642 auto order = std::pow(10, std::floor(std::log10(
scale)));
645 int chart_type = cte.GetChartType();
646 int chart_family = cte.GetChartFamily();
652 if ((cte.GetChartFamily() == CHART_FAMILY_VECTOR) ||
653 ((cte.GetChartFamily() == CHART_FAMILY_RASTER) &&
654 (cte.GetChartType() != CHART_TYPE_MBTILES))) {
656 return ((
scale == pke.chart_scale) && (chart_family == pke.chart_family));
658 auto found = find_if(m_composite_array.begin(), m_composite_array.end(),
660 if (found == m_composite_array.end()) {
662 new_pke.chart_scale =
scale;
663 new_pke.chart_family = (ChartFamilyEnum)cte.GetChartFamily();
664 new_pke.chart_type = (ChartTypeEnum)cte.GetChartType();
665 new_pke.dbindex_list.push_back(m_key_array[i]);
666 m_composite_array.push_back(new_pke);
669 ex_pke.dbindex_list.push_back(m_key_array[i]);
673 new_pke.chart_scale =
scale;
674 new_pke.chart_family = (ChartFamilyEnum)cte.GetChartFamily();
675 new_pke.chart_type = (ChartTypeEnum)cte.GetChartType();
676 new_pke.dbindex_list.push_back(m_key_array[i]);
677 m_composite_array.push_back(new_pke);
682 for (
size_t i = 0; i < m_key_array.size(); i++) {
683 const ChartTableEntry &cte = ChartData->GetChartTableEntry(m_key_array[i]);
684 int scale = cte.GetScale();
685 int chart_type = cte.GetChartType();
687 new_pke.chart_scale =
scale;
688 new_pke.chart_family = (ChartFamilyEnum)cte.GetChartFamily();
689 new_pke.chart_type = (ChartTypeEnum)cte.GetChartType();
690 new_pke.dbindex_list.push_back(m_key_array[i]);
691 m_composite_array.push_back(new_pke);
696 std::sort(m_composite_array.begin(),m_composite_array.end(),
701 void Piano::SetNoshowIndexArray(std::vector<int> array) {
702 m_noshow_index_array = array;
705 void Piano::AddNoshowIndexArray(std::vector<int> array) {
706 for (
unsigned int i = 0; i < array.size(); i++) {
707 m_noshow_index_array.push_back(array[i]);
711 void Piano::SetActiveKeyArray(std::vector<int> array) {
712 m_active_index_array = array;
715 void Piano::SetEclipsedIndexArray(std::vector<int> array) {
716 m_eclipsed_index_array = array;
719 void Piano::SetSkewIndexArray(std::vector<int> array) {
720 m_skew_index_array = array;
723 void Piano::SetTmercIndexArray(std::vector<int> array) {
724 m_tmerc_index_array = array;
727 void Piano::SetPolyIndexArray(std::vector<int> array) {
728 m_poly_index_array = array;
731 bool Piano::InArray(std::vector<int> &array,
int key) {
732 for (
unsigned int ino = 0; ino < array.size(); ino++)
733 if (array[ino] == key)
return true;
737 wxString Piano::GetStateHash() {
740 for (
unsigned int i = 0; i < m_key_array.size(); i++) {
742 a.Printf(_T(
"%dK"), m_key_array[i]);
745 for (
unsigned int i = 0; i < m_noshow_index_array.size(); i++) {
747 a.Printf(_T(
"%dN"), m_noshow_index_array[i]);
750 for (
unsigned int i = 0; i < m_active_index_array.size(); i++) {
752 a.Printf(_T(
"%dA"), m_active_index_array[i]);
755 for (
unsigned int i = 0; i < m_eclipsed_index_array.size(); i++) {
757 a.Printf(_T(
"%dE"), m_eclipsed_index_array[i]);
760 for (
unsigned int i = 0; i < m_skew_index_array.size(); i++) {
762 a.Printf(_T(
"%dW"), m_skew_index_array[i]);
765 for (
unsigned int i = 0; i < m_tmerc_index_array.size(); i++) {
767 a.Printf(_T(
"%dM"), m_tmerc_index_array[i]);
770 for (
unsigned int i = 0; i < m_poly_index_array.size(); i++) {
772 a.Printf(_T(
"%dP"), m_poly_index_array[i]);
779 wxString &Piano::GenerateAndStoreNewHash() {
780 m_hash = GetStateHash();
784 wxString &Piano::GetStoredHash() {
return m_hash; }
786 void Piano::FormatKeys(
void) {
788 int width = m_parentCanvas->GetClientSize().x;
791 width *= m_parentCanvas->GetContentScaleFactor();
793 width *= m_parentCanvas->GetContentScaleFactor();
797 wxSize mui_tool_size = g_StyleManager->GetCurrentStyle()->GetToolSize();
799 mui_tool_size = wxSize(mui_tool_size.x * 1.25, mui_tool_size.y * 1.25);
801 int mui_bar_width_est = mui_tool_size.x * 8 * g_toolbar_scalefactor;
803 if (m_parentCanvas->GetClientSize().x < m_parentCanvas->GetClientSize().y){
814 m_width_avail = width;
816 int height = GetHeight();
818 int nKeys = m_composite_array.size();
819 int kw = style->chartStatusIconWidth;
821 if (!kw) kw = width / nKeys;
830 for (
int i = 0; i < nKeys; i++) {
831 wxRect r((i * kw) + 3, 2, kw - 6, height - 4);
832 KeyRect.push_back(r);
833 m_width = r.x + r.width;
839 wxPoint Piano::GetKeyOrigin(
int key_index) {
840 if ((key_index >= 0) && (key_index <= (
int)m_key_array.size() - 1)) {
841 wxRect box = KeyRect[key_index];
842 return wxPoint(box.x, box.y);
844 return wxPoint(-1, -1);
847 bool Piano::MouseEvent(wxMouseEvent &event) {
849 event.GetPosition(&x, &y);
852 x *= OCPN_GetDisplayContentScaleFactor();
853 y *= OCPN_GetDisplayContentScaleFactor();
856 y *= OCPN_GetDisplayContentScaleFactor();
858 int ytop = m_parentCanvas->GetCanvasHeight() - GetHeight();
861 ytop = m_parentCanvas->GetClientSize().y - GetHeight();
864 if (event.Leaving() || (y < ytop) || (x > GetWidth())) {
865 if (m_bleaving)
return false;
873 int sel_dbindex = -1;
875 for (
int i = 0; i < m_nRegions; i++) {
876 if (KeyRect[i].Contains(x, 6)) {
878 sel_dbindex = m_key_array[i];
884 if (event.LeftDown()) {
885 if (-1 != sel_index) {
886 m_action = DEFERRED_KEY_CLICK_DOWN;
888 m_eventTimer.Start(10, wxTIMER_ONE_SHOT);
891 if (event.LeftUp()) {
892 if (-1 != sel_index) {
893 m_click_sel_index = sel_index;
894 if (!m_eventTimer.IsRunning()) {
895 m_action = DEFERRED_KEY_CLICK_UP;
896 m_eventTimer.Start(10, wxTIMER_ONE_SHOT);
899 }
else if (event.RightDown()) {
900 if (sel_index != m_hover_last) {
902 m_parentCanvas->HandlePianoRollover(sel_index,
903 m_composite_array[sel_index].dbindex_list,
904 m_composite_array[sel_index].dbindex_list.size(),
905 m_composite_array[sel_index].chart_scale );
906 m_hover_last = sel_index;
911 }
else if (event.ButtonUp()) {
912 m_parentCanvas->ClearPianoRollover();
917 m_parentCanvas->ClearPianoRollover();
919 }
else if (event.LeftDown()) {
920 if (-1 != sel_index) {
921 m_parentCanvas->HandlePianoClick(sel_index,
922 m_composite_array[sel_index].dbindex_list);
924 m_parentCanvas->Raise();
927 }
else if (event.RightDown()) {
928 if (-1 != sel_index) {
929 m_parentCanvas->HandlePianoRClick(x, y, sel_index,
930 m_composite_array[sel_index].dbindex_list);
931 m_parentCanvas->Raise();
934 }
else if (!event.ButtonUp()) {
935 if (sel_index != m_hover_last) {
937 m_parentCanvas->HandlePianoRollover(sel_index,
938 m_composite_array[sel_index].dbindex_list,
939 m_composite_array[sel_index].dbindex_list.size(),
940 m_composite_array[sel_index].chart_scale );
942 m_hover_last = sel_index;
961 void Piano::ResetRollover(
void) {
963 m_hover_icon_last = -1;
965 m_gotPianoDown =
false;
968 int Piano::GetHeight() {
972 height *= m_parentCanvas->GetContentScaleFactor();
975 double size_mult = exp(g_GUIScaleFactor * 0.0953101798043);
977 height = wxMin(height, 100);
978 height = wxMax(height, 10);
980 height *= g_Platform->GetDisplayDensityFactor();
982 #ifdef __OCPN__ANDROID__
983 height = wxMax(height, 4 * g_Platform->GetDisplayDPmm());
986 height /= g_BasePlatform->GetDisplayDIPMult(gFrame);
991 int Piano::GetWidth() {
return m_width; }
993 void Piano::onTimerEvent(wxTimerEvent &event) {
995 case DEFERRED_KEY_CLICK_DOWN:
996 m_gotPianoDown =
true;
998 case DEFERRED_KEY_CLICK_UP:
1000 if ((m_hover_last >= 0) || !m_gotPianoDown) {
1001 m_parentCanvas->ClearPianoRollover();
1004 m_parentCanvas->HandlePianoClick(m_click_sel_index,
1005 m_composite_array[m_click_sel_index].dbindex_list);
1006 m_gotPianoDown =
false;
1009 case INFOWIN_TIMEOUT:
1010 m_parentCanvas->ClearPianoRollover();