How To Make Click&Drag Number Box Slider (Without the Slider)?


#1

I don’t know how this type of UI element is called but I need a simple Number or BumberBox on wich i can change the value with draging (horizontal or vertical).
what is the best way of doing this?
greets!


#2

You can get that behaviour with a slider if you tweak its options - have a look at some of the variations of slider shown in the demo app on the ‘widgets’ page


#3

Create a Component with a hidden Slider.

Rail


#4

well… how can i do this?


#5

thanks but there is not one single example on how to change the values by draging on the number box…
what would be the workaround for this?


#6

I’d have thought the LinearBarHorizontal style would do pretty much what you need? If you really don’t want it to show the bar you could make it transparent or give it a custom look+feel to make it look exactly how you want.


#7

is the LookAndFeel_V2::getSliderLayout() the right thing to override?


#8

You can see all the relevant lookandfeel methods in the Slider::LookAndFeelMethods class. Which ones you implement will obviously depend on what you want to do.


#9

ah yes! LinearBarHorizontal with Alpha = 0 does it!!
but how can I get rid of the outline? where is it located?

many thanks!


Another slider suggestion -> pure label style
#10

No idea offhand, you can probably find it in the lookandfeel methods somewhere. Or set its colour to transparent.


#11

ok thank you very much! found it.
if someone is interested:

you have to override
drawLabel (Graphics& g, Label& label)
this is how mine looks:

void OtherLookAndFeel::drawLabel (Graphics& g, Label& label)
{
    g.fillAll (label.findColour (Label::backgroundColourId));
    
    if (! label.isBeingEdited())
    {
        const float alpha = label.isEnabled() ? 1.0f : 0.5f;
        Font font (getLabelFont (label));
        font.setHeight (fontHeight);
        g.setColour (label.findColour (Label::textColourId).withMultipliedAlpha (alpha));
        g.setFont (font);
        
        Rectangle<int> textArea (label.getBorderSize().subtractedFrom (label.getLocalBounds()));
        
        g.drawFittedText (label.getText(), textArea, label.getJustificationType(),
                          jmax (1, (int) (textArea.getHeight() / font.getHeight())),
                          label.getMinimumHorizontalScale());
        
        g.setColour (Colours::transparentBlack);
    }
    else if (label.isEnabled())
    {
        g.setColour (Colours::transparentBlack);
    }
    
    g.drawRect (label.getLocalBounds());
}

and in the custom l+f:

setColour (Slider::thumbColourId, Colours::transparentBlack); //
setColour (Slider::trackColourId, Colours::transparentBlack); //
setColour (Slider::backgroundColourId, Colours::transparentBlack); //


#12

I’ll give you the header of my class… which should give you some ideas… my class has some additional functionality you won’t require…

class CNumericLabelLF : public LookAndFeel_V3
{
public:
    CNumericLabelLF() {};

    void drawLinearSliderBackground (Graphics& , int , int , int , int , float , float , float , const Slider::SliderStyle , Slider& ) override
    {
    }

    void drawLinearSliderThumb (Graphics& , int , int , int , int , float , float , float , const Slider::SliderStyle , Slider& ) override
    {
    }

    Font getLabelFont (Label& label) override
    {
        return label.getFont().withHeight (11.0);
    }

private:

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CNumericLabelLF)
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CNumericSlider;

class CNumericLabel : public Label,
                      public Slider::Listener
{
public:

    CNumericLabel (const String& componentName = String(), const String& labelText = String());
    ~CNumericLabel();

    void resized() override;

    void sliderValueChanged (Slider* slider) override;
    void sliderDragEnded (Slider* slider) override;

    void setRange (int iMin, int iMax);

    void setDoubleClickReturnValue (int iDefault);

    void setValue (int iNewValue);

    void setIsTopValue (bool bIsMaxLabel)       { m_bIsMaxValue = bIsMaxLabel;          }

    int  getValue() noexcept                    { return m_iValue;                      }

    void setOppositeValue (int iOppositeValue)  { m_iOppositeValue = iOppositeValue;    }

    ////////////////////////////////////////////////////////////////////////////

    class CNumericSlider : public Slider
    {
    public:

        CNumericSlider (CNumericLabel* pOwner) : m_pOwner (pOwner)
        {
            setTextBoxStyle (Slider::NoTextBox, false, 70, 20);
            setSliderSnapsToMousePosition (false);
        }

        ~CNumericSlider() {}

        void mouseDown (const MouseEvent& event) override
        {
            unfocusAllComponents();

            Slider::mouseDown (event);
        }

        void mouseEnter (const MouseEvent& event) override
        {
            m_pOwner->setColour (Label::outlineColourId, Colours::grey);

            Slider::mouseEnter (event);
        }

        void mouseExit (const MouseEvent& event) override
        {
            m_pOwner->setColour (Label::outlineColourId, Colour (0x1000282));

            Slider::mouseExit (event);
        }

    private:

        CNumericLabel*  m_pOwner;


        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CNumericSlider)
    };

    ////////////////////////////////////////////////////////////////////////////

    //==============================================================================
    /** Receives callbacks when a CNumericLabel object changes.
	 */
    class  Listener
    {
    public:

        virtual ~Listener() {}

        /** Called when a CNumericLabel object is changed.
         */
        virtual void labelChanged (CNumericLabel* label) = 0;

        virtual void labelDragEnded (CNumericLabel* ) {}
    };

    /** Adds a listener to receive callbacks when the value changes.
     */
    void addListener (Listener* const listener);

    /** Removes a listener that was previously added with addListener(). */
    void removeListener (Listener* const listener);

    /** Updates the CNumericLabel's listeners.
     Call this to explicitly tell any registerd listeners that the value has changed.
	 */
	void updateListeners();

private:

    int     m_iValue;
    int     m_iMinValue;
    int     m_iMaxValue;
    int     m_iDefaultValue;

    bool    m_bIsMaxValue;
    int     m_iOppositeValue;

    ScopedPointer<CNumericSlider>   m_pHiddenSlider;

    CNumericLabelLF m_Look;

    ListenerList<Listener> m_Listeners;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CNumericLabel)
};

typedef CNumericLabel::Listener CNumericLabelListener;

Cheers,

Rail


#13

thank you very much for sharing this!!