Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sq #238

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

sq #238

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 3 additions & 24 deletions packages/react-juce/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/react-juce/src/lib/Backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ NativeMethods.dispatchViewEvent = function dispatchEvent(
return;
}

// mouseEnter and mouseLeave events do not bubble
// https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseenter_event
if ((eventType === "onMouseEnter") || (eventType === "onMouseLeave")) {
event.stopPropagation();
}

__bubbleEvent(instance, eventType, event);
}
};
Expand Down
23 changes: 23 additions & 0 deletions react_juce/core/ReactApplicationRoot.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ namespace reactjuce
bool keyPressed(const juce::KeyPress& key) override;
#endif

juce::Component* componentUnderMouse;

void mouseDrag(const juce::MouseEvent &e) override {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used to translate mouseDrags into enter and exit events

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm interesting, won't ReactAppRoot not get this callback if the mouse is dragged over a child component? https://docs.juce.com/master/classComponent.html#aff01e4d339bda474a66984b709044b63

Or is AppRoot getting this callback at all times?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see View::mouseDrag I forward child drag events onto ReactAppRoot::mouseDrag.

but yes, its pretty ugly. Another way to handle it would be making ReactAppRoot a mouse listener for all its children I suppose.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks! Finally coming back around to this, sorry for the delay.

So, reading this through again with a better understanding, I actually think this is quite like the way juce implements its own drag and drop patterns, except here we're sort of re-implementing it with ReactAppRoot == DragAndDropContainer and View == DragAndDropTarget. (See https://github.com/juce-framework/JUCE/blob/b8206e3604ebaca64779bf19f1613c373b9adf4f/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp)

This has me thinking then, especially in the context of the approach we laid out in the drag and drop issue (see #60 (comment)), that perhaps we should just merge this goal into that work. The approach laid out in that issue is basically 1 step away from solving this problem here, and we can nudge the dragstart/dragmove/dragend callbacks that each View will receive (because its a DragAndDropTarget) to correctly send mouseenter/mouseleave callbacks as well.

What do you think?

auto* newComponentUnderMouse = getComponentAt(e.x, e.y);

if (componentUnderMouse != newComponentUnderMouse){
// The old target may need a mouseLeave event now
if (componentUnderMouse != nullptr) {
if (auto v = dynamic_cast<View*>(componentUnderMouse)){
v->checkMouseEnter(e.getEventRelativeTo(v));
}
}

// The new target may need a mouseEnter event now
if (auto v = dynamic_cast<View*>(newComponentUnderMouse)){
v->checkMouseEnter(e.getEventRelativeTo(v));
}

}

componentUnderMouse = newComponentUnderMouse;
}

//==============================================================================
/** Evaluates a javascript bundle file in the EcmascriptEngine.
*
Expand Down
38 changes: 36 additions & 2 deletions react_juce/core/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,18 +248,52 @@ namespace reactjuce

void View::mouseEnter (const juce::MouseEvent& e)
{
dispatchViewEvent("onMouseEnter", detail::makeViewEventObject(e, *this));
if (!wasMouseOver)
{
dispatchViewEvent("onMouseEnter", detail::makeViewEventObject(e, *this));
}

wasMouseOver = true;
}

void View::mouseExit (const juce::MouseEvent& e)
{
dispatchViewEvent("onMouseLeave", detail::makeViewEventObject(e, *this));
if (!reallyContains(e.getPosition(), true))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reallyContains returns true even if the mouse is over one of this components children.

{
if (wasMouseOver)
{
dispatchViewEvent("onMouseLeave", detail::makeViewEventObject(e, *this));
}

wasMouseOver = false;
} else {
wasMouseOver = true;
}
}

void View::checkMouseEnter(const juce::MouseEvent& e)
{
bool isMouseOverNow = reallyContains(e.getPosition(), true);

if (!wasMouseOver && isMouseOverNow){
mouseEnter(e);
} else if (wasMouseOver && !isMouseOverNow) {
mouseExit(e);
}
}

void View::mouseDrag (const juce::MouseEvent& e)
{
// TODO: mouseDrag isn't a dom event... is it?
dispatchViewEvent("onMouseDrag", detail::makeViewEventObject(e, *this));

// mouseDrags are always dispatched to the component originaly clicked
// so send this up to the ReactApplicationRoot to check for necessary
// enter and leave events. Maybe this should ReactApplicationRoot should just
// be a mouseListener for all its children instead?
if (auto* parent = findParentComponentOfClass<ReactApplicationRoot>())
parent->mouseDrag(e.getEventRelativeTo(parent));

}

void View::mouseDoubleClick (const juce::MouseEvent& e)
Expand Down
4 changes: 3 additions & 1 deletion react_juce/core/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ namespace reactjuce
/** Invokes an "exported" native method on the View instance */
juce::var invokeMethod(const juce::String &method, const juce::var::NativeFunctionArgs &args);

void checkMouseEnter(const juce::MouseEvent& e);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really be called something like checkMouseEnterAndExit.

protected:
//==============================================================================
/** Exports/Registers a method on this View instance so it may be called
Expand All @@ -114,11 +115,12 @@ namespace reactjuce
//==============================================================================
juce::NamedValueSet props;
juce::Rectangle<float> cachedFloatBounds;

private:
//==============================================================================
juce::Uuid _viewId;
juce::Identifier _refId;
bool wasMouseOver = false;


std::unordered_map<juce::String, juce::var::NativeFunction> nativeMethods;

Expand Down