OpenCPN Partial API docs
Loading...
Searching...
No Matches
piano.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Chart Bar Window
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 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#include "dychart.h"
35
36#include "chcanv.h"
37#include "piano.h"
38#include "chartdb.h"
39#include "chartbase.h"
40#include "styles.h"
41#include "ocpndc.h"
42#include "cutil.h"
43#include "wx28compat.h"
44#include "OCPNPlatform.h"
45#include "color_handler.h"
46#include "ocpn_plugin.h"
47#include "ocpn_frame.h"
48
49#ifdef __OCPN__ANDROID__
50#include "qdebug.h"
51#include "androidUTIL.h"
52#endif
53
54#ifdef ocpnUSE_GL
55#include "glChartCanvas.h"
56#endif
57
58#include <wx/arrimpl.cpp>
59WX_DEFINE_OBJARRAY(RectArray);
60
61//------------------------------------------------------------------------------
62// External Static Storage
63//------------------------------------------------------------------------------
64extern ChartDB *ChartData;
65extern ocpnStyle::StyleManager *g_StyleManager;
66extern bool g_btouch;
67extern int g_GUIScaleFactor;
68extern bool g_bopengl;
69
70extern OCPNPlatform *g_Platform;
71extern MyFrame *gFrame;
72extern BasePlatform *g_BasePlatform;
73
74//------------------------------------------------------------------------------
75// Piano Window Implementation
76//------------------------------------------------------------------------------
77BEGIN_EVENT_TABLE(Piano, wxEvtHandler)
78EVT_TIMER(PIANO_EVENT_TIMER, Piano::onTimerEvent)
79END_EVENT_TABLE()
80
81// Define a constructor
82Piano::Piano(ChartCanvas *parent) {
83 m_parentCanvas = parent;
84
85 m_index_last = -1;
86 m_iactive = -1;
87
88 m_hover_icon_last = -1;
89 m_hover_last = -1;
90 m_brounded = false;
91 m_bBusy = false;
92 m_gotPianoDown = false;
93
94 m_nRegions = 0;
95 m_width = 0;
96
97 //> SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // on WXMSW, this prevents
98 //flashing on color scheme change
99
100 m_pVizIconBmp = NULL;
101 m_pInVizIconBmp = NULL;
102 m_pPolyIconBmp = NULL;
103 m_pSkewIconBmp = NULL;
104 m_pTmercIconBmp = NULL;
105
106 SetColorScheme(GLOBAL_COLOR_SCHEME_RGB); // default
107
108 m_eventTimer.SetOwner(this, PIANO_EVENT_TIMER);
109
110 m_tex = m_tex_piano_height = 0;
111}
112
113Piano::~Piano() {
114 if (m_pInVizIconBmp) delete m_pInVizIconBmp;
115 if (m_pPolyIconBmp) delete m_pPolyIconBmp;
116 if (m_pSkewIconBmp) delete m_pSkewIconBmp;
117 if (m_pTmercIconBmp) delete m_pTmercIconBmp;
118 if (m_pVizIconBmp) delete m_pVizIconBmp;
119}
120
121void Piano::Paint(int y, wxDC &dc, wxDC *shapeDC) {
122 ocpnDC odc(dc);
123 Paint(y, odc, shapeDC);
124}
125
126void Piano::Paint(int y, ocpnDC &dc, wxDC *shapeDC) {
127 if (shapeDC) {
128 shapeDC->SetBackground(*wxBLACK_BRUSH);
129 shapeDC->SetBrush(*wxWHITE_BRUSH);
130 shapeDC->SetPen(*wxWHITE_PEN);
131 shapeDC->Clear();
132 }
133
134 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
135 if (!style->chartStatusWindowTransparent) {
136 dc.SetPen(*wxTRANSPARENT_PEN);
137 dc.SetBrush(m_backBrush);
138 dc.DrawRectangle(0, y, m_parentCanvas->GetClientSize().x, GetHeight());
139 }
140
141 // Create the Piano Keys
142
143 int nKeys = m_key_array.size();
144
145 wxPen ppPen(GetGlobalColor(_T("CHBLK")), 1, wxPENSTYLE_SOLID);
146 dc.SetPen(ppPen);
147
148 for (int i = 0; i < nKeys; i++) {
149 int key_db_index = m_key_array[i];
150
151 if (-1 == key_db_index) continue;
152
153 bool selected = InArray(m_active_index_array, key_db_index);
154
155 if (ChartData->GetDBChartType(key_db_index) == CHART_TYPE_CM93 ||
156 ChartData->GetDBChartType(key_db_index) == CHART_TYPE_CM93COMP) {
157 if (selected)
158 dc.SetBrush(m_scBrush);
159 else
160 dc.SetBrush(m_cBrush);
161 } else if (ChartData->GetDBChartType(key_db_index) == CHART_TYPE_MBTILES) {
162 if (selected)
163 dc.SetBrush(m_tileBrush);
164 else
165 dc.SetBrush(m_utileBrush);
166 } else if (ChartData->GetDBChartFamily(key_db_index) ==
167 CHART_FAMILY_VECTOR) {
168 if (selected)
169 dc.SetBrush(m_svBrush);
170 else
171 dc.SetBrush(m_vBrush);
172 } else { // Raster Chart
173 if (selected)
174 dc.SetBrush(m_srBrush);
175 else
176 dc.SetBrush(m_rBrush);
177 }
178
179 if (m_bBusy) dc.SetBrush(m_unavailableBrush);
180
181 wxRect box = KeyRect[i];
182 box.y += y;
183
184 if (m_brounded) {
185 dc.DrawRoundedRectangle(box.x, box.y, box.width, box.height,
186 box.height / 5);
187 if (shapeDC)
188 shapeDC->DrawRoundedRectangle(box.x, box.y, box.width, box.height,
189 box.height / 5);
190 } else {
191 dc.DrawRectangle(box.x, box.y, box.width, box.height);
192 if (shapeDC) shapeDC->DrawRectangle(box);
193 }
194
195 if (InArray(m_eclipsed_index_array, key_db_index)) {
196 dc.SetBrush(m_backBrush);
197 int w = 3;
198 dc.DrawRoundedRectangle(box.x + w, box.y + w, box.width - (2 * w),
199 box.height - (2 * w), box.height / 5 - 1);
200 }
201
202 // Look in the current noshow array for this index
203 if (InArray(m_noshow_index_array, key_db_index) && m_pInVizIconBmp &&
204 m_pInVizIconBmp->IsOk())
205 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pInVizIconBmp),
206 box.x + 4, box.y + 3, false);
207
208 // Look in the current skew array for this index
209 if (InArray(m_skew_index_array, key_db_index) && m_pSkewIconBmp &&
210 m_pSkewIconBmp->IsOk())
211 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pSkewIconBmp),
212 box.x + box.width - m_pSkewIconBmp->GetWidth() - 4,
213 box.y + 2, false);
214
215 // Look in the current tmerc array for this index
216 if (InArray(m_tmerc_index_array, key_db_index) && m_pTmercIconBmp &&
217 m_pTmercIconBmp->IsOk())
218 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pTmercIconBmp),
219 box.x + box.width - m_pTmercIconBmp->GetWidth() - 4,
220 box.y + 2, false);
221
222 // Look in the current poly array for this index
223 if (InArray(m_poly_index_array, key_db_index) && m_pPolyIconBmp &&
224 m_pPolyIconBmp->IsOk())
225 dc.DrawBitmap(ConvertTo24Bit(dc.GetBrush().GetColour(), *m_pPolyIconBmp),
226 box.x + box.width - m_pPolyIconBmp->GetWidth() - 4,
227 box.y + 2, false);
228 }
229}
230
231#if 0
232static void SetColor(unsigned char color[4], const wxBrush &brush)
233{
234 const wxColour &c = brush.GetColour();
235 color[0] = c.Red(), color[1] = c.Green(), color[2] = c.Blue(), color[3] = 255;
236}
237#endif
238
239// build a texture to hold minimum sized rectangles and icons used to render the
240// chart bar this texture is only updated if the color scheme or chart bar
241// height change
242void Piano::BuildGLTexture() {
243#ifdef ocpnUSE_GL
244
245 // Defer building until auxiliary bitmaps have been loaded
246 if (!m_pInVizIconBmp || !m_pTmercIconBmp || !m_pSkewIconBmp ||
247 !m_pPolyIconBmp)
248 return;
249
250 int h = GetHeight();
251
252 wxBrush tbackBrush; // transparent back brush
253 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
254 if (style->chartStatusWindowTransparent)
255 tbackBrush = wxColour(1, 1, 1);
256 else
257 tbackBrush = m_backBrush;
258
259 wxBrush brushes[] = {m_scBrush, m_cBrush, m_svBrush,
260 m_vBrush, m_srBrush, m_rBrush,
261 m_tileBrush, m_utileBrush, m_unavailableBrush};
262
263 m_ref = h;
264 m_pad = h / 7; // spacing between buttons
265 m_radius = h / 4;
266 m_texPitch = ((2 * m_ref) + (2 * m_pad));
267
268 m_tex_piano_height = h;
269 m_texw = m_texPitch * 3;
270
271 m_texh = ((sizeof brushes) / (sizeof *brushes)) * h;
272 m_texh += 4 * m_ref; // for icons;
273
274 m_texh = NextPow2(m_texh);
275 m_texw = NextPow2(m_texw);
276
277 if (!m_tex) glGenTextures(1, &m_tex);
278
279 glBindTexture(GL_TEXTURE_2D, m_tex);
280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
282
283 wxBitmap bmp(m_texw, m_texh);
284 wxMemoryDC dc(bmp);
285
286 dc.SetPen(*wxTRANSPARENT_PEN);
287 dc.SetBrush(tbackBrush);
288 dc.DrawRectangle(0, 0, m_texw, m_texh);
289
290 // 0.5 mm nominal, but not less than 1 pixel
291 double nominal_line_width_pix = floor(g_Platform->GetDisplayDPmm() / 2.0);
292 nominal_line_width_pix *= OCPN_GetWinDIPScaleFactor();
293 nominal_line_width_pix = wxMax(1.0, nominal_line_width_pix);
294
295 // draw the needed rectangles
296 wxPen ppPen(GetGlobalColor(_T("CHBLK")), nominal_line_width_pix,
297 wxPENSTYLE_SOLID);
298 dc.SetPen(ppPen);
299 for (unsigned int b = 0; b < (sizeof brushes) / (sizeof *brushes); b++) {
300 unsigned int x = 0, y = h * b;
301
302 dc.SetBrush(brushes[b]);
303
304 int v = 2;
305 dc.DrawRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v);
306
307 x += m_texPitch;
308 dc.DrawRoundedRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v, m_radius);
309
310 int w = m_ref / 6; // border width of eclipsed chart
311
312 x += m_texPitch;
313 dc.DrawRoundedRectangle(x + m_pad, y + v, 2 * m_ref, h - 2 * v, m_radius);
314 dc.SetBrush(m_backBrush);
315 dc.DrawRoundedRectangle(x + m_pad + w, y + v + w, (2 * m_ref) - (2 * w),
316 h - 2 * v - 2 * w,
317 m_radius * (h - 2 * v - 2 * w) /
318 (h - 2 * v)); // slightly smaller radius
319 }
320
321 dc.SelectObject(wxNullBitmap);
322
323 wxImage image = bmp.ConvertToImage();
324
325 unsigned char *data = new unsigned char[4 * m_texw * m_texh], *d = data,
326 *e = image.GetData(), *a = image.GetAlpha();
327 for (unsigned int i = 0; i < m_texw * m_texh; i++) {
328 if (style->chartStatusWindowTransparent && e[0] == 1 && e[1] == 1 &&
329 e[2] == 1)
330 d[3] = 0;
331 else
332 d[3] = 255;
333
334 memcpy(d, e, 3), d += 4, e += 3;
335 }
336
337 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_texw, m_texh, 0, GL_RGBA,
338 GL_UNSIGNED_BYTE, data);
339 delete[] data;
340
341 // put the bitmaps in below
342 wxBitmap *bitmaps[] = {m_pInVizIconBmp, m_pTmercIconBmp, m_pSkewIconBmp,
343 m_pPolyIconBmp};
344
345 for (unsigned int i = 0; i < 4; i++) {
346 int iw = bitmaps[i]->GetWidth(), ih = bitmaps[i]->GetHeight();
347
348 wxImage im = bitmaps[i]->ConvertToImage();
349 unsigned char *data = new unsigned char[4 * iw * ih], *d = data,
350 *e = im.GetData(), *a = im.GetAlpha();
351 for (int j = 0; j < iw * ih; j++) {
352 memcpy(d, e, 3), d += 3, e += 3;
353 *d = *a, d++, a++;
354 }
355
356 int off = ((sizeof brushes) / (sizeof *brushes)) * h + m_ref * i;
357 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, off, iw, ih, GL_RGBA, GL_UNSIGNED_BYTE,
358 data);
359 delete[] data;
360 }
361#endif
362}
363
364void Piano::DrawGL(int off) {
365#ifdef ocpnUSE_GL
366 unsigned int w = m_parentCanvas->GetClientSize().x * m_parentCanvas->GetContentScaleFactor();
367 int h = GetHeight();
368 int endx = 0;
369
370 if (m_tex_piano_height != h) BuildGLTexture();
371
372 if (m_tex_piano_height != h) return;
373
374 int y1 = off, y2 = y1 + h;
375
376 int nKeys = m_key_array.size();
377
378 // we could cache the coordinates and recompute only when the piano hash
379 // changes, but the performance is already fast enough at this point
380 float *texcoords = new float[(nKeys * 3 + 1) * 4 * 2],
381 *coords = new float[(nKeys * 3 + 1) * 4 * 2];
382
383 int tc = 0, vc = 0;
384
385 // draw the keys
386 for (int i = 0; i < nKeys; i++) {
387 int key_db_index = m_key_array[i];
388
389 int b;
390 if (ChartData->GetDBChartType(key_db_index) == CHART_TYPE_CM93 ||
391 ChartData->GetDBChartType(key_db_index) == CHART_TYPE_CM93COMP)
392 b = 0;
393 else if (ChartData->GetDBChartType(key_db_index) == CHART_TYPE_MBTILES)
394 b = 6;
395 else if (ChartData->GetDBChartFamily(key_db_index) == CHART_FAMILY_VECTOR)
396 b = 2;
397 else // Raster Chart
398 b = 4;
399
400 if (!InArray(m_active_index_array, key_db_index)) b++;
401
402 wxRect box = KeyRect[i];
403 float y = h * b, v1 = (y + .5) / m_texh, v2 = (y + h - .5) / m_texh;
404
405 // texcord contains the texture pixel coordinates in the texture for the
406 // three rectangle parts
407 const float texcord[6] = {0,
408 (float)m_ref - 1,
409 (float)m_ref,
410 (float)m_ref,
411 (float)m_ref + 1,
412 (float)m_texPitch - 1};
413 int uindex;
414 if (m_brounded) {
415 if (InArray(m_eclipsed_index_array, key_db_index))
416 uindex = 2;
417 else
418 uindex = 1;
419 } else
420 uindex = 0;
421
422 // if the chart is too narrow.. we maybe render the "wrong" rectangle
423 // because it can be thinner
424 int x1 = box.x, x2 = x1 + box.width, w = 2 * uindex + 1;
425 while (x1 + w > x2 - w && uindex > 0) uindex--, w -= 2;
426
427 // the minimal width rectangles are texture mapped to the
428 // width needed by mapping 3 quads: left middle and right
429 int x[6] = {x1 - 3, x1 + m_ref, x2 - m_ref, x2 + 3};
430
431 // adjust for very narrow keys
432 if (x[1] > x[2]) {
433 int avg = (x[1] + x[2]) / 2;
434 x[1] = x[2] = avg;
435 }
436
437 for (int i = 0; i < 3; i++) {
438 float u1 = ((uindex * m_texPitch) + texcord[2 * i] + .5) / m_texw,
439 u2 = ((uindex * m_texPitch) + texcord[2 * i + 1] + .5) / m_texw;
440 int x1 = x[i], x2 = x[i + 1];
441 texcoords[tc++] = u1, texcoords[tc++] = v1, coords[vc++] = x1,
442 coords[vc++] = y1;
443 texcoords[tc++] = u2, texcoords[tc++] = v1, coords[vc++] = x2,
444 coords[vc++] = y1;
445 texcoords[tc++] = u2, texcoords[tc++] = v2, coords[vc++] = x2,
446 coords[vc++] = y2;
447 texcoords[tc++] = u1, texcoords[tc++] = v2, coords[vc++] = x1,
448 coords[vc++] = y2;
449 }
450 endx = x[3];
451 }
452
453 // if not transparent, fill the rest of the chart bar with the background
454 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
455 if (!style->chartStatusWindowTransparent && endx < w) {
456 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = endx,
457 coords[vc++] = y1;
458 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = w,
459 coords[vc++] = y1;
460 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = w,
461 coords[vc++] = y2;
462 texcoords[tc++] = 0, texcoords[tc++] = 0, coords[vc++] = endx,
463 coords[vc++] = y2;
464 }
465
466 glBindTexture(GL_TEXTURE_2D, m_tex);
467
468#if not defined(USE_ANDROID_GLES2) && not defined(ocpnUSE_GLSL)
469 if (style->chartStatusWindowTransparent) {
470 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
471 glColor4ub(255, 255, 255,
472 200); // perhaps we could allow the style to set this
473 glEnable(GL_BLEND);
474 } else
475 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
476#endif
477
478 glEnable(GL_TEXTURE_2D);
479
480#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
481 glEnable(GL_BLEND);
482 m_parentCanvas->GetglCanvas()->RenderTextures(
483 m_parentCanvas->GetglCanvas()->m_gldc,
484 coords, texcoords, vc / 2, m_parentCanvas->GetpVP());
485 glDisable(GL_BLEND);
486
487#else
488 glEnableClientState(GL_VERTEX_ARRAY);
489 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
490
491 glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
492 glVertexPointer(2, GL_FLOAT, 0, coords);
493 glDrawArrays(GL_QUADS, 0, vc / 2);
494
495 // draw the bitmaps
496 vc = tc = 0;
497 for (int i = 0; i < nKeys; i++) {
498 int key_db_index = m_key_array[i];
499
500 if (-1 == key_db_index) continue;
501
502 wxRect box = KeyRect[i];
503
504 wxBitmap *bitmaps[] = {m_pInVizIconBmp, m_pTmercIconBmp, m_pSkewIconBmp,
505 m_pPolyIconBmp};
506 int index;
507 if (InArray(m_noshow_index_array, key_db_index))
508 index = 0;
509 else {
510 if (InArray(m_skew_index_array, key_db_index))
511 index = 2;
512 else if (InArray(m_tmerc_index_array, key_db_index))
513 index = 1;
514 else if (InArray(m_poly_index_array, key_db_index))
515 index = 3;
516 else
517 continue;
518 }
519
520 int x1, y1, iw = bitmaps[index]->GetWidth(),
521 ih = bitmaps[index]->GetHeight();
522 if (InArray(m_noshow_index_array, key_db_index))
523 x1 = box.x + 4, y1 = box.y + 3;
524 else
525 x1 = box.x + box.width - iw - 4, y1 = box.y + 2;
526
527 y1 += off;
528 int x2 = x1 + iw, y2 = y1 + ih;
529
530 wxBrush brushes[] = {m_scBrush, m_cBrush, m_svBrush,
531 m_vBrush, m_srBrush, m_rBrush,
532 m_tileBrush, m_utileBrush, m_unavailableBrush};
533
534 float yoff = ((sizeof brushes) / (sizeof *brushes)) * h + 16 * index;
535 float u1 = 0, u2 = (float)iw / m_texw;
536 float v1 = yoff / m_texh, v2 = (yoff + ih) / m_texh;
537
538 texcoords[tc++] = u1, texcoords[tc++] = v1, coords[vc++] = x1,
539 coords[vc++] = y1;
540 texcoords[tc++] = u2, texcoords[tc++] = v1, coords[vc++] = x2,
541 coords[vc++] = y1;
542 texcoords[tc++] = u2, texcoords[tc++] = v2, coords[vc++] = x2,
543 coords[vc++] = y2;
544 texcoords[tc++] = u1, texcoords[tc++] = v2, coords[vc++] = x1,
545 coords[vc++] = y2;
546 }
547 glEnable(GL_BLEND);
548 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
549
550 glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
551 glVertexPointer(2, GL_FLOAT, 0, coords);
552 glDrawArrays(GL_QUADS, 0, vc / 2);
553#endif
554
555 glDisable(GL_BLEND);
556
557#if not defined(USE_ANDROID_GLES2) && not defined(ocpnUSE_GLSL)
558 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
559 glDisableClientState(GL_VERTEX_ARRAY);
560#endif
561 delete[] texcoords;
562 delete[] coords;
563
564 glDisable(GL_TEXTURE_2D);
565#endif
566}
567
568void Piano::SetColorScheme(ColorScheme cs) {
569 // Recreate the local brushes
570
571 m_backBrush = wxBrush(GetGlobalColor(_T("UIBDR")), wxBRUSHSTYLE_SOLID);
572
573 m_rBrush = wxBrush(GetGlobalColor(_T("BLUE2")),
574 wxBRUSHSTYLE_SOLID); // Raster Chart unselected
575 m_srBrush =
576 wxBrush(GetGlobalColor(_T("BLUE1")), wxBRUSHSTYLE_SOLID); // and selected
577
578 m_vBrush = wxBrush(GetGlobalColor(_T("GREEN2")),
579 wxBRUSHSTYLE_SOLID); // Vector Chart unselected
580 m_svBrush = wxBrush(GetGlobalColor(_T("GREEN1")),
581 wxBRUSHSTYLE_SOLID); // and selected
582
583 m_utileBrush = wxBrush(GetGlobalColor(_T("VIO01")),
584 wxBRUSHSTYLE_SOLID); // MBTiles Chart unselected
585 m_tileBrush =
586 wxBrush(GetGlobalColor(_T("VIO02")), wxBRUSHSTYLE_SOLID); // and selected
587
588 m_cBrush = wxBrush(GetGlobalColor(_T("YELO2")),
589 wxBRUSHSTYLE_SOLID); // CM93 Chart unselected
590 m_scBrush =
591 wxBrush(GetGlobalColor(_T("YELO1")), wxBRUSHSTYLE_SOLID); // and selected
592
593 m_unavailableBrush = wxBrush(GetGlobalColor(_T("UINFD")),
594 wxBRUSHSTYLE_SOLID); // and unavailable
595
596 m_tex_piano_height = 0; // force texture to update
597}
598
599void Piano::ShowBusy(bool busy) {
600 m_bBusy = busy;
601 // Refresh( true );
602 // Update();
603}
604
605void Piano::SetKeyArray(std::vector<int> array) { m_key_array = array; }
606
607void Piano::SetNoshowIndexArray(std::vector<int> array) {
608 m_noshow_index_array = array;
609}
610
611void Piano::AddNoshowIndexArray(std::vector<int> array) {
612 for (unsigned int i = 0; i < array.size(); i++) {
613 m_noshow_index_array.push_back(array[i]);
614 }
615}
616
617void Piano::SetActiveKeyArray(std::vector<int> array) {
618 m_active_index_array = array;
619}
620
621void Piano::SetEclipsedIndexArray(std::vector<int> array) {
622 m_eclipsed_index_array = array;
623}
624
625void Piano::SetSkewIndexArray(std::vector<int> array) {
626 m_skew_index_array = array;
627}
628
629void Piano::SetTmercIndexArray(std::vector<int> array) {
630 m_tmerc_index_array = array;
631}
632
633void Piano::SetPolyIndexArray(std::vector<int> array) {
634 m_poly_index_array = array;
635}
636
637bool Piano::InArray(std::vector<int> &array, int key) {
638 for (unsigned int ino = 0; ino < array.size(); ino++)
639 if (array[ino] == key) return true;
640 return false;
641}
642
643wxString Piano::GetStateHash() {
644 wxString hash;
645
646 for (unsigned int i = 0; i < m_key_array.size(); i++) {
647 wxString a;
648 a.Printf(_T("%dK"), m_key_array[i]);
649 hash += a;
650 }
651 for (unsigned int i = 0; i < m_noshow_index_array.size(); i++) {
652 wxString a;
653 a.Printf(_T("%dN"), m_noshow_index_array[i]);
654 hash += a;
655 }
656 for (unsigned int i = 0; i < m_active_index_array.size(); i++) {
657 wxString a;
658 a.Printf(_T("%dA"), m_active_index_array[i]);
659 hash += a;
660 }
661 for (unsigned int i = 0; i < m_eclipsed_index_array.size(); i++) {
662 wxString a;
663 a.Printf(_T("%dE"), m_eclipsed_index_array[i]);
664 hash += a;
665 }
666 for (unsigned int i = 0; i < m_skew_index_array.size(); i++) {
667 wxString a;
668 a.Printf(_T("%dW"), m_skew_index_array[i]);
669 hash += a;
670 }
671 for (unsigned int i = 0; i < m_tmerc_index_array.size(); i++) {
672 wxString a;
673 a.Printf(_T("%dM"), m_tmerc_index_array[i]);
674 hash += a;
675 }
676 for (unsigned int i = 0; i < m_poly_index_array.size(); i++) {
677 wxString a;
678 a.Printf(_T("%dP"), m_poly_index_array[i]);
679 hash += a;
680 }
681
682 return hash;
683}
684
685wxString &Piano::GenerateAndStoreNewHash() {
686 m_hash = GetStateHash();
687 return m_hash;
688}
689
690wxString &Piano::GetStoredHash() { return m_hash; }
691
692void Piano::FormatKeys(void) {
693 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
694 int width = m_parentCanvas->GetClientSize().x * m_parentCanvas->GetContentScaleFactor();
695 int height = GetHeight();
696 width *= g_btouch ? 0.98f : 0.6f;
697
698 int nKeys = m_key_array.size();
699 int kw = style->chartStatusIconWidth;
700 if (nKeys) {
701 if (!kw) kw = width / nKeys;
702
703 kw = wxMin(kw, (width * 3 / 4) / nKeys);
704 kw = wxMax(kw, 6);
705
706 // Build the Key Regions
707
708 KeyRect.clear();
709 m_width = 0;
710 for (int i = 0; i < nKeys; i++) {
711 wxRect r((i * kw) + 3, 2, kw - 6, height - 4);
712 KeyRect.push_back(r);
713 m_width = r.x + r.width;
714 }
715 }
716 m_nRegions = nKeys;
717}
718
719wxPoint Piano::GetKeyOrigin(int key_index) {
720 if ((key_index >= 0) && (key_index <= (int)m_key_array.size() - 1)) {
721 wxRect box = KeyRect[key_index];
722 return wxPoint(box.x, box.y);
723 } else
724 return wxPoint(-1, -1);
725}
726
727bool Piano::MouseEvent(wxMouseEvent &event) {
728 int x, y;
729 event.GetPosition(&x, &y);
730 x *= OCPN_GetDisplayContentScaleFactor();
731 y *= OCPN_GetDisplayContentScaleFactor();
732
733 if (event.Leaving() || y < m_parentCanvas->GetCanvasHeight() - GetHeight()) {
734 if (m_bleaving) return false;
735 m_bleaving = true;
736 } else
737 m_bleaving = false;
738
739 // Check the regions
740
741 int sel_index = -1;
742 int sel_dbindex = -1;
743
744 for (int i = 0; i < m_nRegions; i++) {
745 if (KeyRect[i].Contains(x, 6)) {
746 sel_index = i;
747 sel_dbindex = m_key_array[i];
748 break;
749 }
750 }
751
752 if (g_btouch) {
753 if (event.LeftDown()) {
754 if (-1 != sel_index) {
755 m_action = DEFERRED_KEY_CLICK_DOWN;
756 ShowBusy(true);
757 m_eventTimer.Start(10, wxTIMER_ONE_SHOT);
758 }
759 }
760 if (event.LeftUp()) {
761 if (-1 != sel_index) {
762 m_click_sel_index = sel_index;
763 m_click_sel_dbindex = sel_dbindex;
764 if (!m_eventTimer.IsRunning()) {
765 m_action = DEFERRED_KEY_CLICK_UP;
766 m_eventTimer.Start(10, wxTIMER_ONE_SHOT);
767 }
768 }
769 } else if (event.RightDown()) {
770 if (sel_index != m_hover_last) {
771 m_parentCanvas->HandlePianoRollover(sel_index, sel_dbindex);
772 m_hover_last = sel_index;
773
774 // m_action = INFOWIN_TIMEOUT;
775 // m_eventTimer.Start(3000, wxTIMER_ONE_SHOT);
776 }
777 } else if (event.ButtonUp()) {
778 m_parentCanvas->HandlePianoRollover(-1, -1);
779 ResetRollover();
780 }
781 } else {
782 if (m_bleaving) {
783 m_parentCanvas->HandlePianoRollover(-1, -1);
784 ResetRollover();
785 } else if (event.LeftDown()) {
786 if (-1 != sel_index) {
787 m_parentCanvas->HandlePianoClick(sel_index, sel_dbindex);
788 m_parentCanvas->Raise();
789 } else
790 return false;
791 } else if (event.RightDown()) {
792 if (-1 != sel_index) {
793 m_parentCanvas->HandlePianoRClick(x, y, sel_index, sel_dbindex);
794 m_parentCanvas->Raise();
795 } else
796 return false;
797 } else if (!event.ButtonUp()) {
798 if (sel_index != m_hover_last) {
799 m_parentCanvas->HandlePianoRollover(sel_index, sel_dbindex);
800 m_hover_last = sel_index;
801 }
802 }
803 }
804
805 return true;
806
807 /*
808 Todo:
809 Could do something like this to better encapsulate the pianowin
810 Allows us to get rid of global statics...
811
812 wxCommandEvent ev(MyPianoEvent); // Private event
813 ..set up event to specify action...SelectChart, etc
814 ::PostEvent(pEventReceiver, ev); // event receiver passed to ctor
815
816 */
817}
818
819void Piano::ResetRollover(void) {
820 m_index_last = -1;
821 m_hover_icon_last = -1;
822 m_hover_last = -1;
823 m_gotPianoDown = false;
824}
825
826int Piano::GetHeight() {
827 int height = 22 * m_parentCanvas->GetContentScaleFactor(); // default desktop value
828 if (g_btouch) {
829 double size_mult = exp(g_GUIScaleFactor * 0.0953101798043); // ln(1.1)
830 height *= size_mult;
831 height = wxMin(height, 100); // absolute boundaries
832 height = wxMax(height, 10);
833 }
834 height *= g_Platform->GetDisplayDensityFactor();
835
836#ifdef __OCPN__ANDROID__
837 height = wxMax(height, 4 * g_Platform->GetDisplayDPmm());
838#endif
839
840 height /= g_BasePlatform->GetDisplayDIPMult(gFrame);
841
842 return height;
843}
844
845int Piano::GetWidth() { return m_width; }
846
847void Piano::onTimerEvent(wxTimerEvent &event) {
848 switch (m_action) {
849 case DEFERRED_KEY_CLICK_DOWN:
850 m_gotPianoDown = true;
851 break;
852 case DEFERRED_KEY_CLICK_UP:
853 ShowBusy(false);
854 if ((m_hover_last >= 0) || !m_gotPianoDown) { // turn it off, and return
855 m_parentCanvas->HandlePianoRollover(-1, -1);
856 ResetRollover();
857 } else {
858 m_parentCanvas->HandlePianoClick(m_click_sel_index,
859 m_click_sel_dbindex);
860 m_gotPianoDown = false;
861 }
862 break;
863 case INFOWIN_TIMEOUT:
864 m_parentCanvas->HandlePianoRollover(-1, -1);
865 ResetRollover();
866 break;
867 default:
868 break;
869 }
870}
Definition: piano.h:49
Definition: ocpndc.h:55