Can ColourSelector show its current colour, or get a LookAndFeel?

gui

#1

Hi Juce team,

I was wondering if it were possible to expand on ColourSelector. I would love for it to show me the currently selected colour over the hue and colour space gradients. Right now when I open my colour selector with a given colour, I have no idea “where” that is, which makes picking a new colour really hard.

Another solution would be to open up ColourSelector for its own LookAndFeelMethods too. That way I could do this myself.

~ Stijn
Moditone


#2

If ColourSelector doesn’t have any LookAndFeel methods you could just create a new class that inherits from ColourSelector and override its paint() method?


#3

You couldn’t, because ColourSelector uses all kinds of subclasses and internal state I would need access to. More importantly, that’s not how JUCE is set up, the LookAndFeel basically exists for this.


#4

Okay I hadn’t looked in detail at the ColourSelector class before… you’re right it does have 10 or so subclasses… which i guess is the same reason there’s no L&F methods for ColourSelector because you’d need to have 6 methods for each of the GUI parts of the selector.

But if you really need a solution there’d be no harm in taking a copy of juce_ColourSelector.h/.cpp and just rewriting all the painting methods. More of a work around than a solution but if it works what’s the harm?


#5

Can you show a picture of the current ColourSelector and add some annotations to it showing what you want it to display that its not displaying?


#6

So here’s a screenshot of the colour picker of Affinity Photo (sure Photoshop basically looks the same). As you can see, on top of the hue slider as well as the colour space square, there’s two circles denoting where the hue and saturation+brightness of the currently selected colour are.

image

To contrast, below is the colour picker of our own product, using JUCE’s ColourSelector. Whenever I open the picker it looks like this, not showing me what the currently set colour is. That way it’s really hard to find a colour that is “close to the one I already have”. Something that a colour picker if very often used for.

image

Sure, I could write my own colour picker component, or hack away at JUCE’s one, but this seems like such a common use case for colour pickers that I’m actually surprised JUCE’s doesn’t behave like this.


#7

Um… that’s exactly how the JUCE colour selector does behave!

I’ve no idea how you mangled it so that it behaves differently in your own software, but try any demo app (e.g. in the demo runner under DialogsDemo, click CalloutBox) and you’ll see it working like you describe.


#8

Did you by chance forget to set a colour, by calling ColourSelector::setCurrentColour()?
I just tried here on Mac, and it works, if I do that:


#9

@jules Well, that explains the surprise! I haven’t actually touched the selector itself in anyway, just instantiated it and added it to the component structure. I’ll take a look at it today, really curious as to why it’s behaving differently now.

@daniel Yeah, I am calling setCurrentColour(), so that couldn’t be it. I’ll report back when I get some more information.


#10

maybe share the code for how you’re calling it?


#11

Sure! It’s all wrapped in a custom component:

class Selector :
    public juce::Component,
    public juce::ChangeListener
{
public:
    Selector(const juce::Colour& colour);
        
public:
    std::function<void(const juce::Colour&)> onChange;
        
private:
    // ChangeListener
    void changeListenerCallback(juce::ChangeBroadcaster* source) final;
        
    // Component
    void resized() final;
    
private:
    juce::ColourSelector selector;
};

Selector::Selector(const juce::Colour& colour) :
    selector(juce::ColourSelector::showColourspace | juce::ColourSelector::showAlphaChannel, 0, 0)
{
    selector.setCurrentColour(colour);
    selector.addChangeListener(this);
    addAndMakeVisible(selector);
    
    setSize(200, 200);
}

void Selector::changeListenerCallback(juce::ChangeBroadcaster* source)
{
    if (onChange)
        onChange(selector.getCurrentColour());
}

void Selector::resized()
{
    selector.setBounds(getLocalBounds());
}

Which is then shown using a callout box:

void MyComponent::mouseDown(const juce::MouseEvent& event)
{
    selector = new Selector(colour);
    selector->onChange = [&](auto& c){ /* ... */ };
    juce::CallOutBox::launchAsynchronously(selector, getScreenBounds(), nullptr);
}

#12

So apparently, the ColourSpaceMarker component has a width and height of 0 (after addAndMakeVisible() and setBounds ofc). Its position does seem to make sense, but obviously with a zero size they won’t show.

Investigating further…

[EDIT]

AHA! I’ve set the edgeGap and gapAroundColourSpaceComponent to 0, which is also used to compute the marker sizes. Not something that’s clear from the documentation at all. And frankly I’d like those gaps to stay at 0 and still have my markers, but I understand why it works like this (the gaps are need to cover the marker outside the colour space).


#13

why not try something simple like this:

void Foo::colorSelectorHelper(juce::StringRef name, juce::Colour currentColor)
{
    ColourSelector* cs = new ColourSelector();
    cs->setName( name );
    cs->setCurrentColour( currentColor );
    cs->addChangeListener(changeListener);
    cs->setColour(ColourSelector::backgroundColourId, Colours::transparentBlack);
    cs->setSize(300, 400);
    CallOutBox::launchAsynchronously(cs, changeListener->getScreenBounds(), nullptr);
}

void Bar::changeListenerCallback(ChangeBroadcaster* source)
{
    /* pass Color message where it needs to go*/
    if (ColourSelector* cs = dynamic_cast <ColourSelector*> (source))
    {
        const String& name = cs->getName();
        if (name == ColorPickerTypes::NoteOnColor)
        {
            doSomethingWithColor( cs->getCurrentColour() );
        }

don’t forget to setSize() your ColorSelector before you launch it.


#14

Because I’d like to add more than just the juce::ColourSelector to the contents of the callout box later, specific to our application. :slight_smile:


#15

ok, but why not just test using that ^ approach first to get the o to appear for the color you’re passing in. or even do Daniel’s test in MainContentComponent to verify you’re getting the correct default behavior to begin with.


#16

Thanks - it does seem a bit silly that it’s not smarter about their size - it should at least give them a minimum size! I’ll sort that out and push something to develop shortly…


#17

Great! Thanks, Jules. :slight_smile: