Rounded corner slider with LookAndFeel class

Hello,

I would like to have a slider with a rounded corner. I declared a custom class based on LookAndFeel_V4. Then I override the function drawLinearSlider. I copy all the code from the original one.

I just add this change:

        if (slider.isBar())
        {
            g.setColour(slider.findColour(Slider::trackColourId));
            //g.fillRect(slider.isHorizontal() ? Rectangle<float>(static_cast<float> (x), (float)y + 0.5f, sliderPos - (float)x, (float)height - 1.0f)
            //   : Rectangle<float>((float)x + 0.5f, sliderPos, (float)width - 1.0f, (float)y + ((float)height - sliderPos)));
            g.fillRoundedRectangle(slider.isHorizontal() ? Rectangle<float>(static_cast<float> (x), (float)y + 0.5f, sliderPos - (float)x, (float)height - 1.0f)
                : Rectangle<float>((float)x + 0.5f, sliderPos, (float)width - 1.0f, (float)y + ((float)height - sliderPos)), 5);
        }

So now I have a rounded slider:

slide_issue

But I am not able to find a way to have a rounded boundary for the widget. The only rounded rectangle is for the data inside, not the background frame.

Thanks for the help,
Arthur.

Sadly, this is not in the LookAndFeel. I had a similar issue, I wanted to hide the outline. The outline is drawn in the paint() function in juce_Slider.cpp. I had to comment out a chunk of code in order to handle the outlines of linear sliders by myself. See the commented out section below. You can then, in your look and feel function, handle the outline yourself.

If you don’t want to modify your JUCE codebase, I suppose another way might be to set the slider’s outline colour to transparent, i.e. mySlider.setColour (Slider::textBoxOutlineColourId, Colours::transparentblack) - and then it will draw an invisible outline. I didn’t try this myself.

    void paint (Graphics& g, LookAndFeel& lf)
    {
        if (style != IncDecButtons)
        {
            if (isRotary())
            {
                auto sliderPos = (float) owner.valueToProportionOfLength (lastCurrentValue);
                jassert (sliderPos >= 0 && sliderPos <= 1.0f);

                lf.drawRotarySlider (g,
                                     sliderRect.getX(), sliderRect.getY(),
                                     sliderRect.getWidth(), sliderRect.getHeight(),
                                     sliderPos, rotaryParams.startAngleRadians,
                                     rotaryParams.endAngleRadians, owner);
            }
            else
            {
                lf.drawLinearSlider (g,
                                     sliderRect.getX(), sliderRect.getY(),
                                     sliderRect.getWidth(), sliderRect.getHeight(),
                                     getLinearSliderPos (lastCurrentValue),
                                     getLinearSliderPos (lastValueMin),
                                     getLinearSliderPos (lastValueMax),
                                     style, owner);
            }

            // why this is done here and not in the lookAndFeel I have no idea
            // it makes it impossible change outline on a linearBar
            /*
            if ((style == LinearBar || style == LinearBarVertical) && valueBox == nullptr)
            {
                g.setColour (owner.findColour (Slider::textBoxOutlineColourId));
                g.drawRect (0, 0, owner.getWidth(), owner.getHeight(), 1);
            }
            */
        }
    }
2 Likes

The transparent outline is probably the simplest thing, but you could also use paintOverChildren() (?)

I don’t want to modify the JUCE codebase if I can. So far I have the official git repository as a git submodule in my project.

I suppose another way might be to set the slider’s outline colour to transparent

It will remove this rectangle background, but it means that the widget looks weird when the value is 0. The widget will be completely invisible. I will try to do that but adding the code to draw the background rounded rectangle in the LookAndFeel class.

If you make the outline transparant there is nothing holding you back drawing your own rounded outline in the LookAndFeel. Actually straightforward i would say.
But i agree that the outline drawing should have been part of the LookAndFeel to begin with.

Yes, the @stephenk solution is working great at the beginning.

I try to do complicated things at the beginning. I tried to add a patch file in my visual studio project to modify the Juce directory. My idea was basically to apply the patch in the pre-build custom step, build the project and revert the patch in the post-build step to keep clean my Juce origin submodule. Problem is that I am a newbie with Windows dev. I am able to get a working result with the patch command from Linux but I was not able to do it properly on Windows :(.

I finally just apply the transparent trick in my LookAndFeel class:

             }
         }
+
+        if (slider.isBar())
+        {
+            // back up current outline colour
+            Colour tmp = slider.findColour(Slider::textBoxOutlineColourId);
+
+            // set current border as with transparent colour.
+            slider.setColour(Slider::textBoxOutlineColourId, Colours::transparentWhite);
+
+            // restore the initial colour and redraw the rounded slider border
+            g.setColour(tmp);
+            g.drawRoundedRectangle(slider.getLocalBounds().toFloat(), 6, 4);
+        }
     }
 };

Thanks for your help.

2 Likes