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 #pragma once 8 9 #include "vstgui/lib/vstguifwd.h" 10 #include "vstgui/lib/ccolor.h" 11 #include "vstgui/lib/cview.h" 12 #include "vstgui/lib/dispatchlist.h" 13 #include "vstgui/lib/itouchevent.h" 14 #include <array> 15 #include <bitset> 16 #include <map> 17 18 namespace VSTGUI { 19 20 //------------------------------------------------------------------------ 21 class KeyboardViewBase : public CView 22 { 23 public: 24 using NoteIndex = int16_t; 25 using NumNotes = uint8_t; 26 27 static constexpr NumNotes MaxNotes = 128; 28 29 enum class BitmapID 30 { 31 WhiteKeyPressed = 0, 32 WhiteKeyUnpressed, 33 BlackKeyPressed, 34 BlackKeyUnpressed, 35 WhiteKeyShadowLeft, 36 WhiteKeyShadowRight, 37 NumBitmaps 38 }; 39 40 KeyboardViewBase (); 41 42 void setKeyPressed (NoteIndex note, bool state); 43 44 virtual void setKeyRange (NoteIndex startNote, NumNotes numKeys); getKeyRangeStart()45 NoteIndex getKeyRangeStart () const { return startNote; } getNumKeys()46 NumNotes getNumKeys () const { return numKeys; } 47 NumNotes getNumWhiteKeys () const; 48 49 void setWhiteKeyWidth (CCoord width); 50 void setBlackKeyWidth (CCoord width); 51 void setBlackKeyHeight (CCoord height); 52 void setLineWidth (CCoord width); getWhiteKeyWidth()53 CCoord getWhiteKeyWidth () const { return whiteKeyWidth; } getBlackKeyWidth()54 CCoord getBlackKeyWidth () const { return blackKeyWidth; } getBlackKeyHeight()55 CCoord getBlackKeyHeight () const { return blackKeyHeight; } getLineWidth()56 CCoord getLineWidth () const { return lineWidth; } 57 58 void setFrameColor (CColor color); 59 void setFontColor (CColor color); 60 void setWhiteKeyColor (CColor color); 61 void setWhiteKeyPressedColor (CColor color); 62 void setBlackKeyColor (CColor color); 63 void setBlackKeyPressedColor (CColor color); getFrameColor()64 CColor getFrameColor () const { return frameColor; } getFontColor()65 CColor getFontColor () const { return fontColor; } getWhiteKeyColor()66 CColor getWhiteKeyColor () const { return whiteKeyColor; } getWhiteKeyPressedColor()67 CColor getWhiteKeyPressedColor () const { return whiteKeyPressedColor; } getBlackKeyColor()68 CColor getBlackKeyColor () const { return blackKeyColor; } getBlackKeyPressedColor()69 CColor getBlackKeyPressedColor () const { return blackKeyPressedColor; } 70 71 void setNoteNameFont (CFontDesc* font); getNoteNameFont()72 CFontDesc* getNoteNameFont () const { return noteNameFont; } 73 void setDrawNoteText (bool state); getDrawNoteText()74 bool getDrawNoteText () const { return drawNoteText; } 75 76 void setBitmap (BitmapID bID, CBitmap* bitmap); 77 CBitmap* getBitmap (BitmapID bID) const; 78 79 void setWhiteKeyBitmapInset (const CRect& inset); // TODO: uidesc 80 void setBlackKeyBitmapInset (const CRect& inset); // TODO: uidesc 81 getNoteRect(NoteIndex note)82 const CRect& getNoteRect (NoteIndex note) const { return noteRectCache[note]; } 83 bool isWhiteKey (NoteIndex note) const; 84 85 void drawRect (CDrawContext* context, const CRect& dirtyRect) override; 86 void setViewSize (const CRect& rect, bool invalid = true) override; 87 bool sizeToFit () override; 88 //------------------------------------------------------------------------ 89 protected: 90 using NoteRectCache = std::array<CRect, MaxNotes>; 91 92 void invalidNote (NoteIndex note); 93 94 NoteIndex pointToNote (const CPoint& p, bool ignoreY) const; getNoteRectCache()95 const NoteRectCache& getNoteRectCache () const { return noteRectCache; } 96 97 private: 98 void drawNote (CDrawContext* context, CRect& rect, NoteIndex note, bool isWhite) const; 99 CRect calcNoteRect (NoteIndex note) const; 100 void updateNoteRectCache () const; 101 void createBitmapCache (); 102 103 using BitmapArray = 104 std::array<SharedPointer<CBitmap>, static_cast<size_t> (BitmapID::NumBitmaps)>; 105 106 BitmapArray bitmaps; 107 SharedPointer<CBitmap> whiteKeyBitmapCache; 108 SharedPointer<CBitmap> blackKeyBitmapCache; 109 SharedPointer<CFontDesc> noteNameFont; 110 111 CRect whiteKeyBitmapInset; 112 CRect blackKeyBitmapInset; 113 114 CCoord whiteKeyWidth {30}; 115 CCoord blackKeyWidth {20}; 116 CCoord blackKeyHeight {20}; 117 CCoord lineWidth {1.}; 118 119 CColor frameColor {kBlackCColor}; 120 CColor fontColor {kBlackCColor}; 121 CColor whiteKeyColor {kWhiteCColor}; 122 CColor whiteKeyPressedColor {kGreyCColor}; 123 CColor blackKeyColor {kBlackCColor}; 124 CColor blackKeyPressedColor {kGreyCColor}; 125 126 NumNotes numKeys {88}; 127 NoteIndex startNote {21}; 128 bool drawNoteText {false}; 129 mutable bool noteRectCacheInvalid {true}; 130 mutable NoteRectCache noteRectCache; 131 std::bitset<MaxNotes> keyPressed {}; 132 }; 133 134 class KeyboardViewRangeSelector; 135 //------------------------------------------------------------------------ 136 struct IKeyboardViewKeyRangeChangedListener 137 { 138 virtual void onKeyRangeChanged (KeyboardViewRangeSelector*) = 0; 139 140 virtual ~IKeyboardViewKeyRangeChangedListener () noexcept = default; 141 }; 142 143 //------------------------------------------------------------------------ 144 class KeyboardViewRangeSelector : public KeyboardViewBase 145 { 146 public: 147 struct Range 148 { 149 NoteIndex position; 150 NumNotes length; positionRange151 Range (NoteIndex position = 0, NumNotes length = 0) : position (position), length (length) 152 { 153 } 154 bool operator!= (const Range& r) const 155 { 156 return position != r.position || length != r.length; 157 } 158 }; 159 160 KeyboardViewRangeSelector () = default; 161 162 void drawRect (CDrawContext* context, const CRect& dirtyRect) override; 163 164 void setKeyRange (NoteIndex startNote, NumNotes numKeys) override; 165 void setSelectionRange (const Range& range); 166 void setSelectionMinMax (NumNotes minRange, NumNotes maxRange); getSelectionRange()167 const Range& getSelectionRange () const { return selectionRange; } getSelectionMin()168 NumNotes getSelectionMin () const { return rangeMin; } getSelectionMax()169 NumNotes getSelectionMax () const { return rangeMax; } 170 NumNotes getNumWhiteKeysSelected () const; 171 172 void registerKeyRangeChangedListener (IKeyboardViewKeyRangeChangedListener* listener); 173 void unregisterKeyRangeChangedListener (IKeyboardViewKeyRangeChangedListener* listener); 174 175 //------------------------------------------------------------------------ 176 private: 177 DispatchList<IKeyboardViewKeyRangeChangedListener*> listeners; 178 179 Range selectionRange {0, 12}; 180 NumNotes rangeMin {12}; 181 NumNotes rangeMax {24}; 182 183 #if VSTGUI_TOUCH_EVENT_HANDLING 184 void onTouchEvent (ITouchEvent& event) override; 185 bool wantsMultiTouchEvents () const override; 186 void onTouchBegin (const ITouchEvent::TouchPair& touch, ITouchEvent& event); 187 void onTouchMove (const ITouchEvent::TouchPair& touch, ITouchEvent& event); 188 189 enum TouchMode {kUnknown, kMoveRange, kChangeRangeFront, kChangeRangeBack}; 190 191 Range selectionRangeOnTouchStart; 192 int32_t touchIds[2] {-1}; 193 TouchMode touchMode {kUnknown}; 194 NoteIndex touchStartNote[2]; 195 #else 196 CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; 197 CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; 198 CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; 199 CMouseEventResult onMouseCancel () override; 200 201 Range moveStartRange; 202 NoteIndex moveStartNote {-1}; 203 #endif 204 }; 205 206 //------------------------------------------------------------------------ 207 struct IKeyboardViewPlayerDelegate 208 { 209 using NoteIndex = KeyboardViewBase::NoteIndex; 210 211 virtual int32_t onNoteOn (NoteIndex note, double xPos, double yPos) = 0; 212 virtual void onNoteOff (NoteIndex note, int32_t noteID) = 0; 213 214 virtual void onNoteModulation (int32_t noteID, double xPos, double yPos) = 0; 215 216 virtual ~IKeyboardViewPlayerDelegate () noexcept = default; 217 }; 218 219 //------------------------------------------------------------------------ 220 struct KeyboardViewPlayerDelegate : public IKeyboardViewPlayerDelegate 221 { onNoteOnKeyboardViewPlayerDelegate222 int32_t onNoteOn (NoteIndex note, double xPos, double yPos) override { return -1; } onNoteOffKeyboardViewPlayerDelegate223 void onNoteOff (NoteIndex note, int32_t noteID) override {} onNoteModulationKeyboardViewPlayerDelegate224 void onNoteModulation (int32_t noteID, double xPos, double yPos) override {} 225 }; 226 227 //------------------------------------------------------------------------ 228 class KeyboardView : public KeyboardViewBase 229 { 230 public: 231 KeyboardView (); setDelegate(IKeyboardViewPlayerDelegate * delegate)232 void setDelegate (IKeyboardViewPlayerDelegate* delegate) { this->delegate = delegate; } 233 234 private: 235 double calcYParameter (NoteIndex note, CCoord y) const; 236 double calcXParameter (NoteIndex note, CCoord x) const; 237 #if VSTGUI_TOUCH_EVENT_HANDLING wantsMultiTouchEvents()238 bool wantsMultiTouchEvents () const override { return true; } 239 void onTouchEvent (ITouchEvent& event) override; 240 void onTouchBegin (const ITouchEvent::TouchPair& touch, ITouchEvent& event); 241 void onTouchMove (const ITouchEvent::TouchPair& touch, ITouchEvent& event); 242 void onTouchEnd (const ITouchEvent::TouchPair& touch, ITouchEvent& event); 243 244 struct NoteTouch 245 { 246 NoteIndex note; 247 int32_t noteID; NoteTouchNoteTouch248 NoteTouch (NoteIndex note) : note (note), noteID (-1) {} 249 }; 250 251 std::map<int32_t, NoteTouch> noteTouches; 252 #else 253 void doNoteOff (); 254 void doNoteOn (NoteIndex note, double yPos, double xPos); 255 256 CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; 257 CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; 258 CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; 259 CMouseEventResult onMouseCancel () override; 260 261 NoteIndex pressedNote {-1}; 262 int32_t noteID {-1}; 263 #endif 264 265 IKeyboardViewPlayerDelegate* delegate {nullptr}; 266 }; 267 268 //------------------------------------------------------------------------ 269 } // VSTGUI 270