1 //------------------------------------------------------------------------
2 // This file is part of VSTGUI. It is subject to the license terms
3 // in the LICENSE file found in the top-level directory of this
4 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
5 // Flags : clang-format SMTGSequencer
6
7 #include "keyboardview.h"
8 #include "vstgui/lib/cbitmap.h"
9 #include "vstgui/lib/coffscreencontext.h"
10 #include "vstgui/uidescription/detail/uiviewcreatorattributes.h"
11 #include "vstgui/uidescription/iviewcreator.h"
12 #include "vstgui/uidescription/uiattributes.h"
13 #include "vstgui/uidescription/uiviewcreator.h"
14 #include "vstgui/uidescription/uiviewfactory.h"
15
16 //------------------------------------------------------------------------
17 namespace VSTGUI {
18
19 //------------------------------------------------------------------------
KeyboardView()20 KeyboardView::KeyboardView ()
21 {
22 setDrawNoteText (true);
23 }
24
25 //------------------------------------------------------------------------
calcYParameter(NoteIndex note,CCoord y) const26 double KeyboardView::calcYParameter (NoteIndex note, CCoord y) const
27 {
28 if (note == -1)
29 return 0.f;
30 y -= getViewSize ().top;
31 auto r = getNoteRect (note);
32 return y / r.getHeight ();
33 }
34
35 //------------------------------------------------------------------------
calcXParameter(NoteIndex note,CCoord x) const36 double KeyboardView::calcXParameter (NoteIndex note, CCoord x) const
37 {
38 if (note == -1)
39 return 0.f;
40 auto r = getNoteRect (note);
41 x -= r.left;
42 return x / r.getWidth ();
43 }
44
45 #if VSTGUI_TOUCH_EVENT_HANDLING
46 //------------------------------------------------------------------------
onTouchEvent(ITouchEvent & event)47 void KeyboardView::onTouchEvent (ITouchEvent& event)
48 {
49 for (auto touch : event)
50 {
51 if (touch.second.target != 0 && touch.second.target != this)
52 continue;
53 switch (touch.second.state)
54 {
55 case ITouchEvent::kBegan:
56 {
57 onTouchBegin (touch, event);
58 break;
59 }
60 case ITouchEvent::kMoved:
61 {
62 if (touch.second.target == this)
63 {
64 onTouchMove (touch, event);
65 }
66 break;
67 }
68 case ITouchEvent::kCanceled:
69 case ITouchEvent::kEnded:
70 {
71 if (touch.second.target == this)
72 {
73 onTouchEnd (touch, event);
74 }
75 break;
76 }
77 case ITouchEvent::kNoChange:
78 case ITouchEvent::kUndefined: break;
79 }
80 }
81 }
82
83 //------------------------------------------------------------------------
onTouchBegin(const ITouchEvent::TouchPair & touch,ITouchEvent & event)84 void KeyboardView::onTouchBegin (const ITouchEvent::TouchPair& touch, ITouchEvent& event)
85 {
86 CPoint where (touch.second.location);
87 frameToLocal (where);
88 auto note = pointToNote (where, false);
89 if (note >= 0)
90 {
91 for (auto nt : noteTouches)
92 {
93 if (nt.second.note == note)
94 {
95 // currently no multiple touches for the same note
96 return;
97 }
98 }
99 // TODO: velocity
100 NoteTouch noteTouch (note);
101 event.setTouchTarget (touch.first, this, false);
102 setKeyPressed (note, true);
103 if (delegate)
104 noteTouch.noteID = delegate->onNoteOn (note, calcXParameter (note, where.x),
105 calcYParameter (note, where.y));
106 noteTouches.insert (std::pair<int32_t, NoteTouch> (touch.first, noteTouch));
107 }
108 }
109
110 //------------------------------------------------------------------------
onTouchMove(const ITouchEvent::TouchPair & touch,ITouchEvent & event)111 void KeyboardView::onTouchMove (const ITouchEvent::TouchPair& touch, ITouchEvent& event)
112 {
113 CPoint where (touch.second.location);
114 frameToLocal (where);
115 auto note = pointToNote (where, false);
116 auto noteTouch = noteTouches.find (touch.first);
117 if (noteTouch != noteTouches.end ())
118 {
119 if (note != noteTouch->second.note)
120 {
121 auto noteOff = noteTouch->second.note;
122 auto noteOffID = noteTouch->second.noteID;
123 setKeyPressed (noteTouch->second.note, false);
124 if (note >= 0)
125 {
126 noteTouch->second.note = note;
127 setKeyPressed (noteTouch->second.note, true);
128 if (delegate)
129 noteTouch->second.noteID = delegate->onNoteOn (
130 note, calcXParameter (note, where.x), calcYParameter (note, where.y));
131 }
132 else
133 {
134 noteTouches.erase (noteTouch);
135 }
136 if (delegate)
137 delegate->onNoteOff (noteOff, noteOffID);
138 }
139 else if (note == noteTouch->second.note)
140 {
141 if (delegate)
142 {
143 delegate->onNoteModulation (noteTouch->second.noteID,
144 calcXParameter (note, where.x),
145 calcYParameter (note, where.y));
146 }
147 }
148 }
149 }
150
151 //------------------------------------------------------------------------
onTouchEnd(const ITouchEvent::TouchPair & touch,ITouchEvent & event)152 void KeyboardView::onTouchEnd (const ITouchEvent::TouchPair& touch, ITouchEvent& event)
153 {
154 event.unsetTouchTarget (touch.first, this);
155 auto noteTouch = noteTouches.find (touch.first);
156 if (noteTouch != noteTouches.end ())
157 {
158 setKeyPressed (noteTouch->second.note, false);
159 if (delegate)
160 delegate->onNoteOff (noteTouch->second.note, noteTouch->second.noteID);
161 noteTouches.erase (noteTouch);
162 }
163 }
164 #else
165 //------------------------------------------------------------------------
doNoteOff()166 void KeyboardView::doNoteOff ()
167 {
168 if (pressedNote != -1)
169 {
170 if (delegate)
171 delegate->onNoteOff (pressedNote, noteID);
172 else
173 setKeyPressed (pressedNote, false);
174 noteID = -1;
175 pressedNote = -1;
176 }
177 }
178
179 //------------------------------------------------------------------------
doNoteOn(int16_t note,double yPos,double xPos)180 void KeyboardView::doNoteOn (int16_t note, double yPos, double xPos)
181 {
182 pressedNote = note;
183 if (pressedNote != -1)
184 {
185 if (delegate)
186 noteID = delegate->onNoteOn (pressedNote, yPos, xPos);
187 else
188 setKeyPressed (pressedNote, true);
189 }
190 }
191
192 //------------------------------------------------------------------------
onMouseDown(CPoint & where,const CButtonState & buttons)193 CMouseEventResult KeyboardView::onMouseDown (CPoint& where, const CButtonState& buttons)
194 {
195 if (buttons.isLeftButton ())
196 {
197 auto note = pointToNote (where, false);
198 if (note != -1)
199 {
200 doNoteOn (note, calcXParameter (note, where.x), calcYParameter (note, where.y));
201 }
202 return kMouseEventHandled;
203 }
204 return kMouseEventNotHandled;
205 }
206
207 //------------------------------------------------------------------------
onMouseMoved(CPoint & where,const CButtonState & buttons)208 CMouseEventResult KeyboardView::onMouseMoved (CPoint& where, const CButtonState& buttons)
209 {
210 if (buttons.isLeftButton ())
211 {
212 auto note = pointToNote (where, false);
213 if (note == pressedNote)
214 {
215 if (delegate)
216 {
217 delegate->onNoteModulation (noteID, calcXParameter (note, where.x),
218 calcYParameter (note, where.y));
219 }
220 }
221 else
222 {
223 doNoteOff ();
224 doNoteOn (note, calcXParameter (note, where.x), calcYParameter (note, where.y));
225 }
226 }
227 return kMouseEventHandled;
228 }
229
230 //------------------------------------------------------------------------
onMouseUp(CPoint & where,const CButtonState & buttons)231 CMouseEventResult KeyboardView::onMouseUp (CPoint& where, const CButtonState& buttons)
232 {
233 if (buttons.isLeftButton ())
234 {
235 doNoteOff ();
236 return kMouseEventHandled;
237 }
238 return kMouseEventNotHandled;
239 }
240
241 //------------------------------------------------------------------------
onMouseCancel()242 CMouseEventResult KeyboardView::onMouseCancel ()
243 {
244 doNoteOff ();
245 return kMouseEventHandled;
246 }
247
248 #endif
249
250 //------------------------------------------------------------------------
registerKeyRangeChangedListener(IKeyboardViewKeyRangeChangedListener * listener)251 void KeyboardViewRangeSelector::registerKeyRangeChangedListener (
252 IKeyboardViewKeyRangeChangedListener* listener)
253 {
254 listeners.add (listener);
255 }
256
257 //------------------------------------------------------------------------
unregisterKeyRangeChangedListener(IKeyboardViewKeyRangeChangedListener * listener)258 void KeyboardViewRangeSelector::unregisterKeyRangeChangedListener (
259 IKeyboardViewKeyRangeChangedListener* listener)
260 {
261 listeners.remove (listener);
262 }
263
264 //------------------------------------------------------------------------
drawRect(CDrawContext * context,const CRect & dirtyRect)265 void KeyboardViewRangeSelector::drawRect (CDrawContext* context, const CRect& dirtyRect)
266 {
267 KeyboardViewBase::drawRect (context, dirtyRect);
268
269 auto r1 = getNoteRect (selectionRange.position);
270 auto r2 = getNoteRect (selectionRange.position + selectionRange.length);
271
272 r1.offset (-r1.getWidth (), 0);
273 r2.offset (r2.getWidth (), 0);
274 r1.left = getViewSize ().left;
275 r2.right = getViewSize ().right;
276 r1.bottom = getViewSize ().bottom;
277 r2.bottom = getViewSize ().bottom;
278
279 context->setFillColor (CColor (0, 0, 0, 110));
280 if (!r1.isEmpty ())
281 context->drawRect (r1, kDrawFilled);
282 if (!r2.isEmpty ())
283 context->drawRect (r2, kDrawFilled);
284 }
285
286 //------------------------------------------------------------------------
setKeyRange(NoteIndex startNote,NumNotes numKeys)287 void KeyboardViewRangeSelector::setKeyRange (NoteIndex startNote, NumNotes numKeys)
288 {
289 KeyboardViewBase::setKeyRange (startNote, numKeys);
290 if (selectionRange.position < getKeyRangeStart ())
291 selectionRange.position = getKeyRangeStart ();
292 }
293
294 //------------------------------------------------------------------------
setSelectionRange(const Range & _range)295 void KeyboardViewRangeSelector::setSelectionRange (const Range& _range)
296 {
297 if (selectionRange != _range)
298 {
299 selectionRange = _range;
300 invalid ();
301 listeners.forEach ([this] (auto& listener) { listener->onKeyRangeChanged (this); });
302 }
303 }
304
305 //------------------------------------------------------------------------
setSelectionMinMax(NumNotes minRange,NumNotes maxRange)306 void KeyboardViewRangeSelector::setSelectionMinMax (NumNotes minRange, NumNotes maxRange)
307 {
308 rangeMin = minRange;
309 rangeMax = maxRange;
310 }
311
312 //------------------------------------------------------------------------
getNumWhiteKeysSelected() const313 auto KeyboardViewRangeSelector::getNumWhiteKeysSelected () const -> NumNotes
314 {
315 NumNotes whiteKeys = 0;
316 for (auto i = selectionRange.position; i <= selectionRange.position + selectionRange.length;
317 ++i)
318 {
319 if (isWhiteKey (i))
320 whiteKeys++;
321 }
322 return whiteKeys;
323 }
324
325 #if VSTGUI_TOUCH_EVENT_HANDLING
326 //------------------------------------------------------------------------
onTouchBegin(const ITouchEvent::TouchPair & touch,ITouchEvent & event)327 void KeyboardViewRangeSelector::onTouchBegin (const ITouchEvent::TouchPair& touch,
328 ITouchEvent& event)
329 {
330 CPoint where (touch.second.location);
331 frameToLocal (where);
332 auto note = pointToNote (where, false);
333 if (note >= 0)
334 {
335 if (touchIds[0] == -1)
336 {
337 if (note <= selectionRange.position ||
338 note > selectionRange.position + selectionRange.length)
339 {
340 touchIds[0] = touch.first;
341 touchStartNote[0] = note;
342 touchMode = note <= selectionRange.position ? kChangeRangeFront : kChangeRangeBack;
343 event.setTouchTarget (touch.first, this, false);
344 selectionRangeOnTouchStart = selectionRange;
345 }
346 else if (note > selectionRange.position &&
347 note < selectionRange.position + selectionRange.length)
348 {
349 touchIds[0] = touch.first;
350 touchStartNote[0] = note;
351 touchMode = kMoveRange;
352 event.setTouchTarget (touch.first, this, false);
353 selectionRangeOnTouchStart = selectionRange;
354 }
355 }
356 else
357 {
358 if (touchMode != kMoveRange)
359 {
360 }
361 else if (note > touchStartNote[0])
362 {
363 touchIds[1] = touch.first;
364 touchStartNote[1] = note;
365 event.setTouchTarget (touch.first, this, false);
366 touchMode = kChangeRangeFront;
367 }
368 }
369 }
370 }
371
372 //------------------------------------------------------------------------
bound(int32_t value,int32_t min,int32_t max)373 static int32_t bound (int32_t value, int32_t min, int32_t max)
374 {
375 if (value < min)
376 value = min;
377 else if (value > max)
378 value = max;
379 return value;
380 }
381
382 //------------------------------------------------------------------------
onTouchMove(const ITouchEvent::TouchPair & touch,ITouchEvent & event)383 void KeyboardViewRangeSelector::onTouchMove (const ITouchEvent::TouchPair& touch,
384 ITouchEvent& event)
385 {
386 CPoint where (touch.second.location);
387 frameToLocal (where);
388 auto note = pointToNote (where, true);
389 if (touchIds[0] == touch.first)
390 {
391 if (touchMode == kMoveRange || touchMode == kChangeRangeFront)
392 {
393 if (note >= 0)
394 {
395 auto move = note - touchStartNote[0];
396 auto newRangeStart =
397 bound (selectionRangeOnTouchStart.position + move, getKeyRangeStart (),
398 (getKeyRangeStart () + getNumKeys ()) - selectionRange.length);
399 if (!isWhiteKey (newRangeStart))
400 newRangeStart++;
401 auto length = selectionRange.length;
402 if (touchMode == kChangeRangeFront)
403 {
404 length = selectionRange.length + (selectionRange.position - newRangeStart);
405 if (length < rangeMin || length > rangeMax)
406 return;
407 }
408 setSelectionRange (Range (newRangeStart, length));
409 }
410 }
411 else if (touchMode == kChangeRangeBack)
412 {
413 if (note >= 0)
414 {
415 auto move = note - touchStartNote[0];
416 auto length = selectionRangeOnTouchStart.length + move;
417 if (!isWhiteKey (selectionRange.position + length))
418 length++;
419 if (length < rangeMin || length > rangeMax)
420 return;
421 setSelectionRange (Range (selectionRange.position, length));
422 }
423 }
424 }
425 else
426 {
427 }
428 }
429
430 //------------------------------------------------------------------------
onTouchEvent(ITouchEvent & event)431 void KeyboardViewRangeSelector::onTouchEvent (ITouchEvent& event)
432 {
433 for (auto touch : event)
434 {
435 if (touch.second.target != 0 && touch.second.target != this)
436 continue;
437 switch (touch.second.state)
438 {
439 case ITouchEvent::kBegan:
440 {
441 if (touchIds[0] != -1 && touchIds[1] != -1)
442 continue;
443 onTouchBegin (touch, event);
444 break;
445 }
446 case ITouchEvent::kCanceled:
447 case ITouchEvent::kEnded:
448 {
449 if (touch.second.target == this)
450 {
451 if (touchIds[0] == touch.first)
452 {
453 touchIds[0] = -1;
454 }
455 else
456 {
457 touchIds[1] = -1;
458 }
459 event.unsetTouchTarget (touch.first, this);
460 }
461 break;
462 }
463 case ITouchEvent::kMoved:
464 {
465 if (touch.second.target == this)
466 {
467 onTouchMove (touch, event);
468 }
469 break;
470 }
471 case ITouchEvent::kNoChange:
472 case ITouchEvent::kUndefined: break;
473 }
474 }
475 }
476
477 //------------------------------------------------------------------------
wantsMultiTouchEvents() const478 bool KeyboardViewRangeSelector::wantsMultiTouchEvents () const
479 {
480 return true;
481 }
482 #else
483
484 //------------------------------------------------------------------------
onMouseDown(CPoint & where,const CButtonState & buttons)485 CMouseEventResult KeyboardViewRangeSelector::onMouseDown (CPoint& where,
486 const CButtonState& buttons)
487 {
488 if (buttons.isLeftButton ())
489 {
490 moveStartRange = selectionRange;
491 moveStartNote = pointToNote (where, true);
492 if (moveStartNote < selectionRange.position ||
493 moveStartNote >= selectionRange.position + selectionRange.length)
494 {
495 auto middle = selectionRange.length / 2;
496 if (moveStartNote < middle)
497 moveStartRange.position = 0;
498 else
499 moveStartRange.position = moveStartNote - middle;
500 return onMouseMoved (where, buttons);
501 }
502 return kMouseEventHandled;
503 }
504 return kMouseEventNotHandled;
505 }
506
507 //------------------------------------------------------------------------
onMouseMoved(CPoint & where,const CButtonState & buttons)508 CMouseEventResult KeyboardViewRangeSelector::onMouseMoved (CPoint& where,
509 const CButtonState& buttons)
510 {
511 if (buttons.isLeftButton () && moveStartNote != -1)
512 {
513 auto note = pointToNote (where, true);
514 if (note != -1)
515 {
516 auto offset = note - moveStartNote;
517 Range r = moveStartRange;
518 if (static_cast<NoteIndex> (r.position) + offset < 0)
519 r.position = 0;
520 else if (static_cast<NoteIndex> (r.position + r.length) + offset >= MaxNotes)
521 r.position = (MaxNotes - 1) - r.length;
522 else
523 r.position += offset;
524 setSelectionRange (r);
525 }
526 }
527 return kMouseEventHandled;
528 }
529
530 //------------------------------------------------------------------------
onMouseUp(CPoint & where,const CButtonState & buttons)531 CMouseEventResult KeyboardViewRangeSelector::onMouseUp (CPoint& where, const CButtonState& buttons)
532 {
533 if (buttons.isLeftButton ())
534 moveStartNote = -1;
535 return kMouseEventHandled;
536 }
537
538 //------------------------------------------------------------------------
onMouseCancel()539 CMouseEventResult KeyboardViewRangeSelector::onMouseCancel ()
540 {
541 moveStartNote = -1;
542 return kMouseEventHandled;
543 }
544
545 #endif
546
547 //------------------------------------------------------------------------
548 //------------------------------------------------------------------------
549 //------------------------------------------------------------------------
KeyboardViewBase()550 KeyboardViewBase::KeyboardViewBase () : CView (CRect (0, 0, 0, 0)), noteNameFont (kSystemFont)
551 {
552 }
553
554 //------------------------------------------------------------------------
setViewSize(const CRect & rect,bool invalid)555 void KeyboardViewBase::setViewSize (const CRect& rect, bool invalid)
556 {
557 CView::setViewSize (rect, invalid);
558 noteRectCacheInvalid = true;
559 }
560
561 //------------------------------------------------------------------------
sizeToFit()562 bool KeyboardViewBase::sizeToFit ()
563 {
564 if (noteRectCacheInvalid)
565 updateNoteRectCache ();
566
567 auto r = getNoteRect (startNote + numKeys - 1);
568 r.setWidth (r.right);
569 r.setHeight (getViewSize ().getHeight ());
570 r.originize ();
571
572 setViewSize (r);
573 setMouseableArea (r);
574 return true;
575 }
576
577 //------------------------------------------------------------------------
getNumWhiteKeys() const578 auto KeyboardViewBase::getNumWhiteKeys () const -> NumNotes
579 {
580 NumNotes whiteKeys = 0;
581 for (NoteIndex i = startNote; i <= startNote + numKeys; ++i)
582 {
583 if (isWhiteKey (i))
584 whiteKeys++;
585 }
586 return whiteKeys;
587 }
588
589 //------------------------------------------------------------------------
setKeyRange(NoteIndex _startNote,NumNotes _numKeys)590 void KeyboardViewBase::setKeyRange (NoteIndex _startNote, NumNotes _numKeys)
591 {
592 vstgui_assert (_startNote >= 0 && _numKeys >= 0);
593 if (_startNote < 0 || _numKeys < 0)
594 return;
595
596 if (static_cast<int32_t> (_numKeys) + static_cast<int32_t> (_startNote) >=
597 static_cast<int32_t> (MaxNotes))
598 {
599 _numKeys = (MaxNotes - 1) - _startNote;
600 }
601 startNote = _startNote;
602 numKeys = _numKeys;
603 noteRectCacheInvalid = true;
604 invalid ();
605 }
606
607 //------------------------------------------------------------------------
setNoteNameFont(CFontDesc * font)608 void KeyboardViewBase::setNoteNameFont (CFontDesc* font)
609 {
610 if (font != noteNameFont)
611 {
612 noteNameFont = font;
613 if (drawNoteText)
614 invalid ();
615 }
616 }
617
618 //------------------------------------------------------------------------
setDrawNoteText(bool state)619 void KeyboardViewBase::setDrawNoteText (bool state)
620 {
621 if (state != drawNoteText)
622 {
623 drawNoteText = state;
624 invalid ();
625 }
626 }
627
628 //------------------------------------------------------------------------
setWhiteKeyWidth(CCoord width)629 void KeyboardViewBase::setWhiteKeyWidth (CCoord width)
630 {
631 if (whiteKeyWidth != width)
632 {
633 whiteKeyWidth = width;
634 whiteKeyBitmapCache = nullptr;
635 noteRectCacheInvalid = true;
636 invalid ();
637 }
638 }
639
640 //------------------------------------------------------------------------
setBlackKeyWidth(CCoord width)641 void KeyboardViewBase::setBlackKeyWidth (CCoord width)
642 {
643 if (blackKeyWidth != width)
644 {
645 blackKeyWidth = width;
646 blackKeyBitmapCache = nullptr;
647 noteRectCacheInvalid = true;
648 invalid ();
649 }
650 }
651
652 //------------------------------------------------------------------------
setBlackKeyHeight(CCoord height)653 void KeyboardViewBase::setBlackKeyHeight (CCoord height)
654 {
655 if (blackKeyHeight != height)
656 {
657 blackKeyHeight = height;
658 noteRectCacheInvalid = true;
659 invalid ();
660 }
661 }
662
663 //------------------------------------------------------------------------
setLineWidth(CCoord width)664 void KeyboardViewBase::setLineWidth (CCoord width)
665 {
666 if (lineWidth != width)
667 {
668 lineWidth = width;
669 invalid ();
670 }
671 }
672
673 //------------------------------------------------------------------------
setFrameColor(CColor color)674 void KeyboardViewBase::setFrameColor (CColor color)
675 {
676 if (frameColor != color)
677 {
678 frameColor = color;
679 invalid ();
680 }
681 }
682
683 //------------------------------------------------------------------------
setFontColor(CColor color)684 void KeyboardViewBase::setFontColor (CColor color)
685 {
686 if (fontColor != color)
687 {
688 fontColor = color;
689 invalid ();
690 }
691 }
692
693 //------------------------------------------------------------------------
setWhiteKeyColor(CColor color)694 void KeyboardViewBase::setWhiteKeyColor (CColor color)
695 {
696 if (whiteKeyColor != color)
697 {
698 whiteKeyColor = color;
699 invalid ();
700 }
701 }
702
703 //------------------------------------------------------------------------
setWhiteKeyPressedColor(CColor color)704 void KeyboardViewBase::setWhiteKeyPressedColor (CColor color)
705 {
706 if (whiteKeyPressedColor != color)
707 {
708 whiteKeyPressedColor = color;
709 invalid ();
710 }
711 }
712
713 //------------------------------------------------------------------------
setBlackKeyColor(CColor color)714 void KeyboardViewBase::setBlackKeyColor (CColor color)
715 {
716 if (blackKeyColor != color)
717 {
718 blackKeyColor = color;
719 invalid ();
720 }
721 }
722
723 //------------------------------------------------------------------------
setBlackKeyPressedColor(CColor color)724 void KeyboardViewBase::setBlackKeyPressedColor (CColor color)
725 {
726 if (blackKeyPressedColor != color)
727 {
728 blackKeyPressedColor = color;
729 invalid ();
730 }
731 }
732
733 //------------------------------------------------------------------------
createBitmapCache()734 void KeyboardViewBase::createBitmapCache ()
735 {
736 auto whiteKeyBitmap = getBitmap (BitmapID::WhiteKeyUnpressed);
737 auto blackKeyBitmap = getBitmap (BitmapID::BlackKeyUnpressed);
738 if (!whiteKeyBitmap || !blackKeyBitmap)
739 return;
740
741 if (auto offscreen = COffscreenContext::create (getFrame (), whiteKeyWidth, getHeight ()))
742 {
743 offscreen->beginDraw ();
744 CRect r (0, 0, whiteKeyWidth, getHeight ());
745 r.left -= whiteKeyBitmapInset.left;
746 r.right += whiteKeyBitmapInset.right;
747 r.top -= whiteKeyBitmapInset.top;
748 r.bottom += whiteKeyBitmapInset.bottom;
749 whiteKeyBitmap->draw (offscreen, r);
750 offscreen->endDraw ();
751 whiteKeyBitmapCache = offscreen->getBitmap ();
752 }
753
754 if (auto offscreen = COffscreenContext::create (getFrame (), blackKeyWidth, blackKeyHeight))
755 {
756 offscreen->beginDraw ();
757 CRect r (0, 0, blackKeyWidth, blackKeyHeight);
758 r.left -= blackKeyBitmapInset.left;
759 r.right += blackKeyBitmapInset.right;
760 r.top -= blackKeyBitmapInset.top;
761 r.bottom += blackKeyBitmapInset.bottom;
762 blackKeyBitmap->draw (offscreen, r);
763 offscreen->endDraw ();
764 blackKeyBitmapCache = offscreen->getBitmap ();
765 }
766 }
767
768 //------------------------------------------------------------------------
drawRect(CDrawContext * context,const CRect & dirtyRect)769 void KeyboardViewBase::drawRect (CDrawContext* context, const CRect& dirtyRect)
770 {
771 if (noteRectCacheInvalid)
772 updateNoteRectCache ();
773
774 if (whiteKeyBitmapCache == nullptr || blackKeyBitmapCache == nullptr)
775 createBitmapCache ();
776
777 context->setLineWidth (lineWidth == -1 ? context->getHairlineSize () : lineWidth);
778 context->setFrameColor (frameColor);
779 context->setFontColor (fontColor);
780 context->setFont (noteNameFont);
781 context->setDrawMode (kAntiAliasing | kNonIntegralMode);
782
783 for (NoteIndex i = startNote; i <= startNote + numKeys; i++)
784 {
785 if (isWhiteKey (i) == false)
786 continue;
787 CRect r = getNoteRect (i);
788 if (dirtyRect.rectOverlap (r) == false)
789 continue;
790 drawNote (context, r, i, true);
791 if (drawNoteText && i % 12 == 0)
792 {
793 char text[5];
794 snprintf (text, 4, "C%d", (i / 12) - 2);
795 r.top = r.bottom - context->getFont ()->getSize () - 10;
796 context->drawString (text, r);
797 }
798 }
799 for (NoteIndex i = startNote; i <= startNote + numKeys; i++)
800 {
801 if (isWhiteKey (i) == true)
802 continue;
803 CRect r = getNoteRect (i);
804 if (dirtyRect.rectOverlap (r) == false)
805 continue;
806 drawNote (context, r, i, false);
807 }
808 }
809
810 //------------------------------------------------------------------------
drawNote(CDrawContext * context,CRect & rect,NoteIndex note,bool isWhite) const811 void KeyboardViewBase::drawNote (CDrawContext* context, CRect& rect, NoteIndex note,
812 bool isWhite) const
813 {
814 CBitmap* keyBitmap = nullptr;
815 CRect bitmapRect (rect);
816 if (isWhite)
817 {
818 bitmapRect.left -= whiteKeyBitmapInset.left;
819 bitmapRect.right += whiteKeyBitmapInset.right;
820 bitmapRect.top -= whiteKeyBitmapInset.top;
821 bitmapRect.bottom += whiteKeyBitmapInset.bottom;
822 }
823 else
824 {
825 bitmapRect.left -= blackKeyBitmapInset.left;
826 bitmapRect.right += blackKeyBitmapInset.right;
827 bitmapRect.top -= blackKeyBitmapInset.top;
828 bitmapRect.bottom += blackKeyBitmapInset.bottom;
829 }
830
831 if (keyPressed[note])
832 keyBitmap = getBitmap (isWhite ? BitmapID::WhiteKeyPressed : BitmapID::BlackKeyPressed);
833 else
834 {
835 if (isWhite)
836 {
837 if (whiteKeyBitmapCache && whiteKeyBitmapCache->getWidth () == bitmapRect.getWidth () &&
838 whiteKeyBitmapCache->getHeight () == bitmapRect.getHeight ())
839 keyBitmap = whiteKeyBitmapCache;
840 else
841 keyBitmap = getBitmap (BitmapID::WhiteKeyUnpressed);
842 }
843 else
844 {
845 if (blackKeyBitmapCache && blackKeyBitmapCache->getWidth () == bitmapRect.getWidth () &&
846 blackKeyBitmapCache->getHeight () == bitmapRect.getHeight ())
847 keyBitmap = blackKeyBitmapCache;
848 else
849 keyBitmap = getBitmap (BitmapID::BlackKeyUnpressed);
850 }
851 }
852
853 if (keyBitmap)
854 {
855 keyBitmap->draw (context, bitmapRect);
856 }
857 else
858 {
859 if (keyPressed[note])
860 context->setFillColor (isWhite ? whiteKeyPressedColor : blackKeyPressedColor);
861 else
862 context->setFillColor (isWhite ? whiteKeyColor : blackKeyColor);
863 context->drawRect (rect, isWhite ? kDrawFilledAndStroked : kDrawFilled);
864 }
865 if (keyPressed[note] && isWhite)
866 {
867 NoteIndex otherNote;
868 if (note > startNote)
869 {
870 otherNote = note - 1;
871 if (!isWhiteKey (otherNote))
872 otherNote--;
873 if (keyPressed[otherNote] == false)
874 {
875 if (auto b = getBitmap (BitmapID::WhiteKeyShadowLeft))
876 {
877 b->draw (context, bitmapRect);
878 }
879 }
880 }
881
882 if (note < startNote + numKeys)
883 {
884 otherNote = note + 1;
885 if (!isWhiteKey (otherNote))
886 otherNote++;
887 if (keyPressed[otherNote] == false)
888 {
889 if (auto b = getBitmap (BitmapID::WhiteKeyShadowRight))
890 {
891 b->draw (context, bitmapRect);
892 }
893 }
894 }
895 }
896 }
897
898 //------------------------------------------------------------------------
calcNoteRect(NoteIndex note) const899 CRect KeyboardViewBase::calcNoteRect (NoteIndex note) const
900 {
901 CRect result;
902 if (note >= startNote && note <= startNote + numKeys)
903 {
904 for (NoteIndex i = startNote + 1; i <= note; i++)
905 {
906 bool isWhite = isWhiteKey (i);
907 if (isWhite)
908 {
909 result.left += whiteKeyWidth;
910 }
911 }
912 if (isWhiteKey (note))
913 {
914 result.setWidth (whiteKeyWidth);
915 result.setHeight (getViewSize ().getHeight ());
916 }
917 else
918 {
919 result.left += whiteKeyWidth - blackKeyWidth / 2;
920 result.setWidth (blackKeyWidth);
921 result.setHeight (blackKeyHeight);
922 }
923 }
924 result.offset (getViewSize ().left, getViewSize ().top);
925 return result;
926 }
927
928 //------------------------------------------------------------------------
updateNoteRectCache() const929 void KeyboardViewBase::updateNoteRectCache () const
930 {
931 for (NoteIndex i = 0; i < MaxNotes; ++i)
932 noteRectCache[i] = calcNoteRect (i);
933
934 CRect r = getNoteRect (startNote + numKeys);
935 CCoord space = getViewSize ().right - r.right;
936 if (space > 0)
937 {
938 space = fabs (space / 2.);
939 for (NoteIndex i = startNote + 1; i <= startNote + numKeys; ++i)
940 noteRectCache[i].offset (space, 0);
941 noteRectCache[startNote].right += space;
942 noteRectCache[startNote + numKeys].right = getViewSize ().right;
943 }
944 noteRectCacheInvalid = false;
945 }
946
947 //------------------------------------------------------------------------
pointToNote(const CPoint & p,bool ignoreY) const948 auto KeyboardViewBase::pointToNote (const CPoint& p, bool ignoreY) const -> NoteIndex
949 {
950 if (noteRectCacheInvalid)
951 updateNoteRectCache ();
952 NoteIndex result = 0;
953 for (auto r : getNoteRectCache ())
954 {
955 if (!ignoreY)
956 {
957 if (r.pointInside (p))
958 {
959 if (isWhiteKey (result))
960 {
961 if (getNoteRect (result + 1).pointInside (p))
962 return result + 1;
963 }
964 return result;
965 }
966 }
967 else if (p.x >= r.left && p.x < r.right)
968 {
969 if (isWhiteKey (result))
970 {
971 auto r2 = getNoteRect (result + 1);
972 if (p.x >= r2.left && p.x < r2.right)
973 return result + 1;
974 }
975 return result;
976 }
977 result++;
978 }
979 return -1;
980 }
981
982 //------------------------------------------------------------------------
invalidNote(NoteIndex note)983 void KeyboardViewBase::invalidNote (NoteIndex note)
984 {
985 if (noteRectCacheInvalid)
986 updateNoteRectCache ();
987 invalidRect (getNoteRect (note));
988 }
989
990 //------------------------------------------------------------------------
setKeyPressed(NoteIndex note,bool state)991 void KeyboardViewBase::setKeyPressed (NoteIndex note, bool state)
992 {
993 vstgui_assert (note >= 0);
994 if (note < 0)
995 return;
996
997 if (keyPressed[note] != state)
998 {
999 keyPressed[note] = state;
1000 invalidNote (note);
1001 if (isWhiteKey (note))
1002 {
1003 if (note > startNote)
1004 {
1005 NoteIndex prevKey = note - 1;
1006 if (!isWhiteKey (prevKey))
1007 prevKey--;
1008 invalidNote (prevKey);
1009 }
1010 if (note < startNote + numKeys)
1011 {
1012 NoteIndex nextKey = note + 1;
1013 if (!isWhiteKey (nextKey))
1014 nextKey++;
1015 invalidNote (nextKey);
1016 }
1017 }
1018 }
1019 }
1020
1021 //------------------------------------------------------------------------
isWhiteKey(NoteIndex note) const1022 bool KeyboardViewBase::isWhiteKey (NoteIndex note) const
1023 {
1024 note = note % 12;
1025 return note == 0 || note == 2 || note == 4 || note == 5 || note == 7 || note == 9 || note == 11;
1026 }
1027
1028 //------------------------------------------------------------------------
setWhiteKeyBitmapInset(const CRect & inset)1029 void KeyboardViewBase::setWhiteKeyBitmapInset (const CRect& inset)
1030 {
1031 whiteKeyBitmapInset = inset;
1032 }
1033
1034 //------------------------------------------------------------------------
setBlackKeyBitmapInset(const CRect & inset)1035 void KeyboardViewBase::setBlackKeyBitmapInset (const CRect& inset)
1036 {
1037 blackKeyBitmapInset = inset;
1038 }
1039
1040 //------------------------------------------------------------------------
setBitmap(BitmapID bID,CBitmap * bitmap)1041 void KeyboardViewBase::setBitmap (BitmapID bID, CBitmap* bitmap)
1042 {
1043 bitmaps[static_cast<size_t> (bID)] = bitmap;
1044 invalid ();
1045 }
1046
1047 //------------------------------------------------------------------------
getBitmap(BitmapID bID) const1048 CBitmap* KeyboardViewBase::getBitmap (BitmapID bID) const
1049 {
1050 return bitmaps[static_cast<size_t> (bID)];
1051 }
1052
1053 //------------------------------------------------------------------------
1054 //------------------------------------------------------------------------
1055 //------------------------------------------------------------------------
1056 static const std::string kAttrWhiteKeyPressed = "white-key-pressed";
1057 static const std::string kAttrWhiteKeyUnpressed = "white-key-unpressed";
1058 static const std::string kAttrBlackKeyPressed = "black-key-pressed";
1059 static const std::string kAttrBlackKeyUnpressed = "black-key-unpressed";
1060 static const std::string kAttrWhiteKeyShadowLeft = "white-key-shadow-left";
1061 static const std::string kAttrWhiteKeyShadowRight = "white-key-shadow-right";
1062 static const std::string kAttrWhiteKeyWidth = "white-key-width";
1063 static const std::string kAttrBlackKeyWidth = "black-key-width";
1064 static const std::string kAttrBlackKeyHeight = "black-key-height";
1065 static const std::string kAttrWhiteKeyColor = "white-key-color";
1066 static const std::string kAttrWhiteKeyPressedColor = "white-key-pressed-color";
1067 static const std::string kAttrBlackKeyColor = "black-key-color";
1068 static const std::string kAttrBlackKeyPressedColor = "black-key-pressed-color";
1069 static const std::string kAttrStartNote = "start-note";
1070 static const std::string kAttrNumKeys = "num-keys";
1071 static const std::string kAttrNoteNameFont = "note-name-font";
1072 static const std::string kAttrDrawNoteText = "draw-note-text";
1073
1074 using UIViewCreator::stringToColor;
1075 using UIViewCreator::stringToBitmap;
1076 using UIViewCreator::bitmapToString;
1077 using UIViewCreator::colorToString;
1078
1079 //-----------------------------------------------------------------------------
1080 class KeyboardViewBaseCreator : public ViewCreatorAdapter
1081 {
1082 public:
1083 using ViewType = KeyboardViewBase;
1084
getBaseViewName() const1085 IdStringPtr getBaseViewName () const override { return UIViewCreator::kCView; }
getAttributeNames(std::list<std::string> & attributeNames) const1086 bool getAttributeNames (std::list<std::string>& attributeNames) const override
1087 {
1088 attributeNames.push_back (kAttrWhiteKeyPressed);
1089 attributeNames.push_back (kAttrWhiteKeyUnpressed);
1090 attributeNames.push_back (kAttrBlackKeyPressed);
1091 attributeNames.push_back (kAttrBlackKeyUnpressed);
1092 attributeNames.push_back (kAttrWhiteKeyShadowLeft);
1093 attributeNames.push_back (kAttrWhiteKeyShadowRight);
1094 attributeNames.push_back (kAttrWhiteKeyWidth);
1095 attributeNames.push_back (kAttrBlackKeyWidth);
1096 attributeNames.push_back (kAttrBlackKeyHeight);
1097 attributeNames.push_back (UIViewCreator::kAttrFrameColor);
1098 attributeNames.push_back (UIViewCreator::kAttrFontColor);
1099 attributeNames.push_back (kAttrWhiteKeyColor);
1100 attributeNames.push_back (kAttrWhiteKeyPressedColor);
1101 attributeNames.push_back (kAttrBlackKeyColor);
1102 attributeNames.push_back (kAttrBlackKeyPressedColor);
1103 attributeNames.push_back (UIViewCreator::kAttrFrameWidth);
1104 attributeNames.push_back (kAttrStartNote);
1105 attributeNames.push_back (kAttrNumKeys);
1106 attributeNames.push_back (kAttrDrawNoteText);
1107 attributeNames.push_back (kAttrNoteNameFont);
1108 return true;
1109 }
getAttributeType(const std::string & attributeName) const1110 AttrType getAttributeType (const std::string& attributeName) const override
1111 {
1112 auto bitmapID = attrNameToBitmapID (attributeName);
1113 if (bitmapID != ViewType::BitmapID::NumBitmaps)
1114 return kBitmapType;
1115 if (attributeName == kAttrWhiteKeyWidth)
1116 return kFloatType;
1117 if (attributeName == kAttrBlackKeyWidth)
1118 return kFloatType;
1119 if (attributeName == kAttrBlackKeyHeight)
1120 return kFloatType;
1121 if (attributeName == kAttrStartNote)
1122 return kIntegerType;
1123 if (attributeName == kAttrNumKeys)
1124 return kIntegerType;
1125 if (attributeName == kAttrDrawNoteText)
1126 return kBooleanType;
1127 if (attributeName == kAttrNoteNameFont)
1128 return kFontType;
1129 if (attributeName == UIViewCreator::kAttrFrameWidth)
1130 return kFloatType;
1131 if (attributeName == UIViewCreator::kAttrFrameColor)
1132 return kColorType;
1133 if (attributeName == UIViewCreator::kAttrFontColor)
1134 return kColorType;
1135 if (attributeName == kAttrWhiteKeyColor)
1136 return kColorType;
1137 if (attributeName == kAttrWhiteKeyPressedColor)
1138 return kColorType;
1139 if (attributeName == kAttrBlackKeyColor)
1140 return kColorType;
1141 if (attributeName == kAttrBlackKeyPressedColor)
1142 return kColorType;
1143 return kUnknownType;
1144 }
getAttributeValue(CView * view,const std::string & attributeName,std::string & stringValue,const IUIDescription * desc) const1145 bool getAttributeValue (CView* view, const std::string& attributeName, std::string& stringValue,
1146 const IUIDescription* desc) const override
1147 {
1148 auto kv = dynamic_cast<ViewType*> (view);
1149 if (!kv)
1150 return false;
1151 auto bitmapID = attrNameToBitmapID (attributeName);
1152 if (bitmapID != ViewType::BitmapID::NumBitmaps)
1153 {
1154 stringValue = "";
1155 if (auto bitmap = kv->getBitmap (bitmapID))
1156 bitmapToString (bitmap, stringValue, desc);
1157 return true;
1158 }
1159 if (attributeName == UIViewCreator::kAttrFrameColor)
1160 {
1161 colorToString (kv->getFrameColor (), stringValue, desc);
1162 return true;
1163 }
1164 if (attributeName == UIViewCreator::kAttrFontColor)
1165 {
1166 colorToString (kv->getFontColor (), stringValue, desc);
1167 return true;
1168 }
1169 if (attributeName == kAttrWhiteKeyColor)
1170 {
1171 colorToString (kv->getWhiteKeyColor (), stringValue, desc);
1172 return true;
1173 }
1174 if (attributeName == kAttrWhiteKeyPressedColor)
1175 {
1176 colorToString (kv->getWhiteKeyPressedColor (), stringValue, desc);
1177 return true;
1178 }
1179 if (attributeName == kAttrBlackKeyColor)
1180 {
1181 colorToString (kv->getBlackKeyColor (), stringValue, desc);
1182 return true;
1183 }
1184 if (attributeName == kAttrBlackKeyPressedColor)
1185 {
1186 colorToString (kv->getBlackKeyPressedColor (), stringValue, desc);
1187 return true;
1188 }
1189 if (attributeName == kAttrWhiteKeyWidth)
1190 {
1191 stringValue = numberToString (kv->getWhiteKeyWidth ());
1192 return true;
1193 }
1194 if (attributeName == kAttrBlackKeyWidth)
1195 {
1196 stringValue = numberToString (kv->getBlackKeyWidth ());
1197 return true;
1198 }
1199 if (attributeName == kAttrBlackKeyHeight)
1200 {
1201 stringValue = numberToString (kv->getBlackKeyHeight ());
1202 return true;
1203 }
1204 if (attributeName == kAttrStartNote)
1205 {
1206 stringValue = numberToString<int32_t> (kv->getKeyRangeStart ());
1207 return true;
1208 }
1209 if (attributeName == kAttrNumKeys)
1210 {
1211 stringValue = numberToString<int32_t> (kv->getNumKeys ());
1212 return true;
1213 }
1214 if (attributeName == UIViewCreator::kAttrFrameWidth)
1215 {
1216 stringValue = numberToString (kv->getLineWidth ());
1217 return true;
1218 }
1219 if (attributeName == kAttrDrawNoteText)
1220 {
1221 stringValue = kv->getDrawNoteText () ? "true" : "false";
1222 return true;
1223 }
1224 if (attributeName == kAttrNoteNameFont)
1225 {
1226 UTF8StringPtr fontName = desc->lookupFontName (kv->getNoteNameFont ());
1227 if (fontName)
1228 {
1229 stringValue = fontName;
1230 return true;
1231 }
1232 return false;
1233 }
1234 return false;
1235 }
apply(CView * view,const UIAttributes & attributes,const IUIDescription * desc) const1236 bool apply (CView* view, const UIAttributes& attributes,
1237 const IUIDescription* desc) const override
1238 {
1239 auto kv = dynamic_cast<ViewType*> (view);
1240 if (!kv)
1241 return false;
1242 CBitmap* bitmap;
1243 if (stringToBitmap (attributes.getAttributeValue (kAttrWhiteKeyPressed), bitmap, desc))
1244 kv->setBitmap (ViewType::BitmapID::WhiteKeyPressed, bitmap);
1245 if (stringToBitmap (attributes.getAttributeValue (kAttrWhiteKeyUnpressed), bitmap, desc))
1246 kv->setBitmap (ViewType::BitmapID::WhiteKeyUnpressed, bitmap);
1247 if (stringToBitmap (attributes.getAttributeValue (kAttrBlackKeyPressed), bitmap, desc))
1248 kv->setBitmap (ViewType::BitmapID::BlackKeyPressed, bitmap);
1249 if (stringToBitmap (attributes.getAttributeValue (kAttrBlackKeyUnpressed), bitmap, desc))
1250 kv->setBitmap (ViewType::BitmapID::BlackKeyUnpressed, bitmap);
1251 if (stringToBitmap (attributes.getAttributeValue (kAttrWhiteKeyShadowLeft), bitmap, desc))
1252 kv->setBitmap (ViewType::BitmapID::WhiteKeyShadowLeft, bitmap);
1253 if (stringToBitmap (attributes.getAttributeValue (kAttrWhiteKeyShadowRight), bitmap, desc))
1254 kv->setBitmap (ViewType::BitmapID::WhiteKeyShadowRight, bitmap);
1255
1256 CColor color;
1257 if (stringToColor (attributes.getAttributeValue (UIViewCreator::kAttrFrameColor), color,
1258 desc))
1259 kv->setFrameColor (color);
1260 if (stringToColor (attributes.getAttributeValue (UIViewCreator::kAttrFontColor), color,
1261 desc))
1262 kv->setFontColor (color);
1263 if (stringToColor (attributes.getAttributeValue (kAttrWhiteKeyColor), color, desc))
1264 kv->setWhiteKeyColor (color);
1265 if (stringToColor (attributes.getAttributeValue (kAttrWhiteKeyPressedColor), color, desc))
1266 kv->setWhiteKeyPressedColor (color);
1267 if (stringToColor (attributes.getAttributeValue (kAttrBlackKeyColor), color, desc))
1268 kv->setBlackKeyColor (color);
1269 if (stringToColor (attributes.getAttributeValue (kAttrBlackKeyPressedColor), color, desc))
1270 kv->setBlackKeyPressedColor (color);
1271
1272 CCoord c;
1273 if (attributes.getDoubleAttribute (kAttrWhiteKeyWidth, c))
1274 kv->setWhiteKeyWidth (c);
1275 if (attributes.getDoubleAttribute (kAttrBlackKeyWidth, c))
1276 kv->setBlackKeyWidth (c);
1277 if (attributes.getDoubleAttribute (kAttrBlackKeyHeight, c))
1278 kv->setBlackKeyHeight (c);
1279 if (attributes.getDoubleAttribute (UIViewCreator::kAttrFrameWidth, c))
1280 kv->setLineWidth (c);
1281 auto startNote = static_cast<int32_t> (kv->getKeyRangeStart ());
1282 auto numKeys = static_cast<int32_t> (kv->getNumKeys ());
1283 attributes.getIntegerAttribute (kAttrStartNote, startNote);
1284 attributes.getIntegerAttribute (kAttrNumKeys, numKeys);
1285 kv->setKeyRange (startNote, numKeys);
1286 bool b;
1287 if (attributes.getBooleanAttribute (kAttrDrawNoteText, b))
1288 kv->setDrawNoteText (b);
1289 if (auto fontName = attributes.getAttributeValue (kAttrNoteNameFont))
1290 kv->setNoteNameFont (desc->getFont (fontName->data ()));
1291
1292 return true;
1293 }
1294
getAttributeValueRange(const std::string & attributeName,double & minValue,double & maxValue) const1295 bool getAttributeValueRange (const std::string& attributeName, double& minValue,
1296 double& maxValue) const override
1297 {
1298 if (attributeName == kAttrNumKeys)
1299 {
1300 minValue = 12;
1301 maxValue = KeyboardViewBase::MaxNotes - 1;
1302 return true;
1303 }
1304 return false;
1305 }
1306
1307 //-----------------------------------------------------------------------------
1308 // TODO: this is a clone see uiviewcreator.cpp
1309 template <typename T>
numberToString(T value)1310 static std::string numberToString (T value)
1311 {
1312 std::stringstream str;
1313 str << value;
1314 return str.str ();
1315 }
1316
attrNameToBitmapID(const std::string & attributeName)1317 static ViewType::BitmapID attrNameToBitmapID (const std::string& attributeName)
1318 {
1319 if (attributeName == kAttrWhiteKeyPressed)
1320 return ViewType::BitmapID::WhiteKeyPressed;
1321 if (attributeName == kAttrWhiteKeyUnpressed)
1322 return ViewType::BitmapID::WhiteKeyUnpressed;
1323 if (attributeName == kAttrBlackKeyPressed)
1324 return ViewType::BitmapID::BlackKeyPressed;
1325 if (attributeName == kAttrBlackKeyUnpressed)
1326 return ViewType::BitmapID::BlackKeyUnpressed;
1327 if (attributeName == kAttrWhiteKeyShadowLeft)
1328 return ViewType::BitmapID::WhiteKeyShadowLeft;
1329 if (attributeName == kAttrWhiteKeyShadowRight)
1330 return ViewType::BitmapID::WhiteKeyShadowRight;
1331 return ViewType::BitmapID::NumBitmaps;
1332 }
1333 };
1334
1335 //------------------------------------------------------------------------
1336 class KeyboardViewCreator : public KeyboardViewBaseCreator
1337 {
1338 public:
KeyboardViewCreator()1339 KeyboardViewCreator () { UIViewFactory::registerViewCreator (*this); }
getViewName() const1340 IdStringPtr getViewName () const override { return "KeyboardView"; }
getDisplayName() const1341 UTF8StringPtr getDisplayName () const override { return "Keyboard"; }
create(const UIAttributes & attributes,const IUIDescription * description) const1342 CView* create (const UIAttributes& attributes, const IUIDescription* description) const override
1343 {
1344 return new KeyboardView ();
1345 }
1346 };
1347 KeyboardViewCreator __gKeyboardViewCreator;
1348
1349 static const std::string kAttrSelectionRangeMin = "sel-range-min";
1350 static const std::string kAttrSelectionRangeMax = "sel-range-max";
1351 //------------------------------------------------------------------------
1352 class KeyboardViewRangeSelectorCreator : public KeyboardViewBaseCreator
1353 {
1354 public:
KeyboardViewRangeSelectorCreator()1355 KeyboardViewRangeSelectorCreator () { UIViewFactory::registerViewCreator (*this); }
getViewName() const1356 IdStringPtr getViewName () const override { return "KeyboardViewRangeSelector"; }
getDisplayName() const1357 UTF8StringPtr getDisplayName () const override { return "Keyboard Range Selector"; }
create(const UIAttributes & attributes,const IUIDescription * description) const1358 CView* create (const UIAttributes& attributes, const IUIDescription* description) const override
1359 {
1360 return new KeyboardViewRangeSelector ();
1361 }
getAttributeNames(std::list<std::string> & attributeNames) const1362 bool getAttributeNames (std::list<std::string>& attributeNames) const override
1363 {
1364 attributeNames.push_back (kAttrSelectionRangeMin);
1365 attributeNames.push_back (kAttrSelectionRangeMax);
1366 return KeyboardViewBaseCreator::getAttributeNames (attributeNames);
1367 }
getAttributeType(const std::string & attributeName) const1368 AttrType getAttributeType (const std::string& attributeName) const override
1369 {
1370 if (attributeName == kAttrSelectionRangeMin)
1371 return kIntegerType;
1372 if (attributeName == kAttrSelectionRangeMax)
1373 return kIntegerType;
1374 return KeyboardViewBaseCreator::getAttributeType (attributeName);
1375 }
getAttributeValue(CView * view,const std::string & attributeName,std::string & stringValue,const IUIDescription * desc) const1376 bool getAttributeValue (CView* view, const std::string& attributeName, std::string& stringValue,
1377 const IUIDescription* desc) const override
1378 {
1379 auto kb = dynamic_cast<KeyboardViewRangeSelector*> (view);
1380 if (!kb)
1381 return false;
1382 if (attributeName == kAttrSelectionRangeMin)
1383 {
1384 stringValue = numberToString<int32_t> (kb->getSelectionMin ());
1385 return true;
1386 }
1387 if (attributeName == kAttrSelectionRangeMax)
1388 {
1389 stringValue = numberToString<int32_t> (kb->getSelectionMax ());
1390 return true;
1391 }
1392 return KeyboardViewBaseCreator::getAttributeValue (view, attributeName, stringValue, desc);
1393 }
apply(CView * view,const UIAttributes & attributes,const IUIDescription * desc) const1394 bool apply (CView* view, const UIAttributes& attributes,
1395 const IUIDescription* desc) const override
1396 {
1397 auto kb = dynamic_cast<KeyboardViewRangeSelector*> (view);
1398 if (!kb)
1399 return false;
1400 auto selMin = static_cast<int32_t> (kb->getSelectionMin ());
1401 auto selMax = static_cast<int32_t> (kb->getSelectionMax ());
1402 attributes.getIntegerAttribute (kAttrSelectionRangeMin, selMin);
1403 attributes.getIntegerAttribute (kAttrSelectionRangeMax, selMax);
1404 kb->setSelectionMinMax (selMin, selMax);
1405 return KeyboardViewBaseCreator::apply (view, attributes, desc);
1406 }
1407 };
1408 KeyboardViewRangeSelectorCreator __gKeyboardViewRangeSelectorCreator;
1409
1410 //------------------------------------------------------------------------
1411 } // VSTGUI
1412