I’m trying to draw on top of the MidiKeyboardComponent and still have the MKC respond to mouse events and am not having any luck passing those events captured by the opaque component on top of the MKC to the MKC. here’s my simplified code:
struct SeeThruWindow : public Component
{
SeeThruWindow() {}
~SeeThruWindow() {}
void paint(juce::Graphics &g) override {
if( mouseMovedOver ) {
g.setColour(Colours::red);
//draw a little red dot wherever our cursor is in the window
g.fillEllipse(mouse.getX()-2.5f, mouse.getY()-2.5f, 5, 5);
}
}
void mouseDown(const MouseEvent& event) override {
DBG( "SeeThruWindow mouseDown: " + event.getPosition().toString() );
if( Component* p = getParentComponent() ) {
p->mouseDown(event.getEventRelativeTo(p));
}
}
void mouseMove(const MouseEvent& event) override {
if( Component* p = getParentComponent() ) {
p->mouseMove(event.getEventRelativeTo(p));
}
mouse = event.getPosition();
repaint();
}
void mouseEnter(const MouseEvent& event) override { mouseMovedOver = true; }
void mouseExit( const MouseEvent& event) override { mouseMovedOver = false; mouse = {-5, -5}; repaint(); }
Point<int> mouse;
bool mouseMovedOver = false;
};
and now the component that has the SeeThruWindow and the MidiKeyboardComponent as children
class PianoRoll : public Component
{
public:
PianoRoll() : keyboard(*state, MidiKeyboardComponent::horizontalKeyboard)
{
addAndMakeVisible(keyboard);
addAndMakeVisible(seeThruWindow);
keyboard.setScrollButtonsVisible(false);
keyboard.setOctaveForMiddleC(4);
}
~PianoRoll() {}
void paint (Graphics& g) override { g.fillAll(Colours::white); }
void resized() override
{
auto r = getLocalBounds();
keyboard.setKeyWidth(float(r.getWidth()) / float(keyCount) );
seeThruWindow.setBounds(r);
FlexBox fb;
fb.flexDirection = FlexBox::Direction::column;
float def = 128.f; //25 key = 128.f
fb.items.add(FlexItem().withFlex((def-108.f) / def) );
fb.items.add(FlexItem( keyboard ).withFlex(108.f / def ) );
fb.performLayout(r);
}
void mouseDown(const MouseEvent &event) override
{
//we clicked on the SeeThruWindow
auto kb = keyboard.getBounds();
if( kb.contains(event.getPosition()) ) {
DBG( "Keyboard contains event position" );
auto n = keyboard.getNoteAtPosition(event.getPosition());
DBG( "key under cursor " + String(n) );
} else {
DBG( "keyboard does not contain event position" );
}
if( owner != nullptr )
owner->mouseDown(event);
}
void mouseMove(const MouseEvent &event) override
{
keyboard.mouseMove(event);
if( owner != nullptr )
owner->mouseMove(event);
}
void setOwner(Component* _owner) { owner = _owner; }
/** these are the types of midi controllers we can display, organized by number of WHITE KEYS */
enum class KeyCount {
KeyCount88 = 7*7 + 2 + 1,
KeyCount76 = 7*5 + 5 + 5,
KeyCount73 = 7*5 + 3 + 5,
KeyCount61 = 7*5 + 1,
KeyCount49 = 7*4 + 1,
KeyCount44 = 7*3 + 1 + 4,
KeyCount37 = 7*3 + 1,
KeyCount25 = 7*2 + 1,
};
struct KeyRange {
int lowKey;
int highKey;
};
/** these are the midi note ranges for each type of keyboard */
std::map<KeyCount, KeyRange> const KeyRanges{
{KeyCount::KeyCount88, {21, 21+87}},
{KeyCount::KeyCount76, {60-24-8, 60-24-8+75}},
{KeyCount::KeyCount73, {60-24-8, 60-24-8+72}},
{KeyCount::KeyCount61, {60-24, 60-24+60}},
{KeyCount::KeyCount49, {60-12, 60-12+48}},
{KeyCount::KeyCount44, {60-19, 60-19+43}},
{KeyCount::KeyCount37, {60-12, 60-12+36}},
{KeyCount::KeyCount25, {60-24, 60}}
};
/** this is how you set the number of visible keys on screen */
void setKeyCount( KeyCount k )
{
KeyRange const& range = KeyRanges.at(k);
keyboard.setAvailableRange(range.lowKey, range.highKey);
keyCount = k;
resized();
}
private:
SharedResourcePointer<MidiKeyboardState> state;
MidiKeyboardComponent keyboard;
SeeThruWindow seeThruWindow;
KeyCount keyCount = KeyCount::KeyCount88;
Component* owner = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PianoRoll)
};
and the relevant part of my main.cpp:
class MainWindow : public DocumentWindow
{
public:
MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
setUsingNativeTitleBar (true);
pianoRollWindow = new PianoRoll();
pianoRollWindow->setSize(600, 118);
pianoRollWindow->setKeyCount( PianoRoll::KeyCount::KeyCount25 );
setContentNonOwned(pianoRollWindow, true);
DocumentWindow::setResizable(true, true);
DocumentWindow::setResizeLimits(128, 128,
Desktop::getInstance().getDisplays().getMainDisplay().userArea.getWidth(),
Desktop::getInstance().getDisplays().getMainDisplay().userArea.getHeight());
centreWithSize (getWidth(), getHeight());
setVisible (true);
}
private:
ScopedPointer<PianoRoll> pianoRollWindow;
};
Whenever I click in the SeeThruWindow, the following is output to the console:
SeeThruWindow mouseDown: 329, 99
Keyboard contains event position
key under cursor -1
SeeThruWindow mouseDown: 260, 88
Keyboard contains event position
key under cursor -1
SeeThruWindow mouseDown: 337, 70
Keyboard contains event position
key under cursor -1
So, the mouse events are definitely within the bounds of the MidiKeyboardComponent instance. but for the life of me, I can’t figure out why MidiKeyboardComponent::getNoteAtPosition(Point<int> pos) just will not work with the position I’m passing.

