Initializing a MouseInputSource

Hi!
I’m trying to hide the cursor while dragging a slider and then returning it to the same position after the mouse has been released. I figured MouseInputSource:: enableUnboundedMouseMovement() might help. How do I initialize a MouseInputSource object?

Thanks in advance!

You don’t initialise it. It is there from the framework.
But you have access in the MouseEvent, which makes sense, since you can have multiple MouseInputSources (physical, virtual, multi touch).

In

void mouseDown (const MouseEvent& event) override
{
    event.source.hideCursor();
}

…don’t forget to switch it back on :wink:

btw. instead of inheriting Slider, consider adding a MouseListener to that Slider

Ok thank you.
So, if I add a mouseListener to my Slider with .addMouseListener(), where am I able to specify the mouseDown function? I am working within the PluginEditor.

You create a mini-class that listens to the slider:

class DragCursorHide : private MouseListener
{
public:
    DragCursorHide (Component& c) : component (c)
    {
        component.addMouseListener (this);
    }
    virtual ~DragCursorHide ()
    {
        component.removeMouseListener (this);
    }
    void mouseDown (const MouseEvent& event) override
    {
        event.source.hideCursor();
        screenPosDown = event.getScreenPosition();
    }
    void mouseUp (const MouseEvent& event) override
    {
        event.source.setScreenPosition (screenPosDown);
        event.source.revealCursor();
    }

private:
    Component&   component;
    Point<float> screenDownPos;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DragCursorHide)
}

// use it:
Slider         foo;
DragCursorHide hide {foo};

Yes! Thank you, that does the job! I tried debugging this but I’m still left with this error:

‘this’ argument to member function ‘hideCursor’ has type ‘const juce::MouseInputSource’, but function is not marked const

What would you do?

Ah, that is annoying… it’s a result of the const MouseEvent reference…
You could use a const_cast, but that is actually frowned upon.
It seems to be legit from my point of view, but would want confirmation from one of the API authors.

Unless I’m missing some detail, you could just use Component::setMouseCursor(). So your mouseDown() would look like:

event.source.setMouseCursor (MouseCursor::NoCursor);

and then in mouseUp() you reset it with:

event.source.setMouseCursor (MouseCursor::NormalCursor);

Oh right, you’re brilliant.
We cannot use the event, and source as well as originalComponent are useless because of the constness of the event.

But we have the component captured, so you can use the

component.setCursor (MouseCursor::NoCursor);

What is still missing is access to the mouse source to reset the position…

In a situation without multiple mouse sources you can either use Desktop::setMousePosition() or ::getMainMouseSource() to get a non-const MouseInputSource.

That’s not really better than a const_cast IMHO, it already breaks on touch screens and will expose subtle bugs in other unforeseen situations.
Absolute worst case would be to iterate through the MouseInputSources until you find the one that triggered and use that pointer from the list, which is not const.

But that sounds like a horrible workaround.

EDIT: let me rephrase: what could go wrong using a const_cast?

Well, it’s not undefined behaviour at least. If you’re really concerned about working on multi-touch systems then using a combination of Desktop::getNumDraggingMouseSources() and Desktop::getDraggingMouseSource() will give you the correct MouseInputSource

Thanks for your contribution Ed!
I tried implementing some of your ideas and this is the resulting code: (it does work!)

#pragma once
#include <JuceHeader.h>

class MouseEvents : private MouseListener
{
public:
    MouseEvents (Component& c) : component (c)
    {
        component.addMouseListener (this, true);
    }
    virtual ~MouseEvents ()
    {
        component.removeMouseListener (this);
    }
     
    void mouseDown (const MouseEvent& event) override
    {
        component.setMouseCursor (MouseCursor::NoCursor);
        screenDownPos = Desktop::getInstance().getMousePosition();
        
    }
    void mouseUp (const MouseEvent& event) override
    {
        component.setMouseCursor(MouseCursor::ParentCursor);
        Desktop::getInstance().setMousePosition(screenDownPos);
    }

private:
    Component&   component;
    Point<int> screenDownPos;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseEvents)
};