I can’t share it 'cause it’s set up to use ComponentBuilder… but it’s fairly simple…
I created a base class CSwitchComponent…
class CSwitchComponent : public Slider
{
public:
CSwitchComponent();
~CSwitchComponent();
void paint (Graphics& g) override;
void mouseDown (const MouseEvent& event) override;
void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder);
int getNumberOfPoles() const noexcept { return m_iNumberOfPoles; }
Image getImage (int iPole) const noexcept;
void setImages (const String& szPole1Path, const String& szPole2Path, const String& szPole3Path);
bool areImagesLoaded() const noexcept { return m_bImagesLoaded; }
int getSwitchPosition() const noexcept;
protected:
CSliderSwitchLookAndFeel m_Look;
bool m_bIsHorizontal;
double m_dSliderMin;
double m_dSliderMax;
double m_dSliderDefault;
private:
StringArray m_ImagePathArray;
int m_iNumberOfPoles;
bool m_bImagesLoaded;
Image m_Pole1Image; // Left or Top
Image m_Pole2Image; // Center (for 3 pole, Right for 2 pole)
Image m_Pole3Image; // Right or Bottom (for 3 pole, not used for 2 pole)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CSwitchComponent)
};
You can either have 3 separate Image objects or create an OwnedArray of Images…
I have 2 other classes: CHorizontalSwitchComponent & CVerticalSwitchComponent derived from CSwitchComponent which initialize the Slider either Horizontal or Vertical
void CHorizontalSwitchComponent::init()
{
setSliderStyle (Slider::SliderStyle::LinearHorizontal);
CSwitchComponent::setPopupDisplayEnabled (false, getParentComponent());
m_bIsHorizontal = true;
}
The CSwitchComponent constructor initializes the Slider and sets the LookAndFeel class….
CSwitchComponent::CSwitchComponent() : m_bIsHorizontal (true),
m_dSliderMin (0.0),
m_dSliderMax (100.0),
m_dSliderDefault (0.0),
m_iNumberOfPoles (2),
m_bImagesLoaded (false)
{
setRange (m_dSliderMin, m_dSliderMax, 1.0);
setValue (m_dSliderDefault);
setTextBoxStyle (Slider::NoTextBox, true, 70, 35);
setLookAndFeel (&m_Look);
}
in CSwitchComponent::setImages() check all the images are the same size and set the size of the object to the image size.
The other 2 relevant methods:
Image CSwitchComponent::getImage (int iPole) const noexcept
{
switch (iPole)
{
case 1: return m_Pole1Image;
case 2: return m_Pole2Image;
case 3: return m_Pole3Image;
}
return m_Pole1Image;
}
int CSwitchComponent::getSwitchPosition() const noexcept
{
double dSliderValue = getValue();
double division = 100.0 / (double) m_iNumberOfPoles;
for (int i = 0; i < m_iNumberOfPoles; ++i)
{
if ((dSliderValue >= division * (double) i) && (dSliderValue <= division * (double) (i + 1)))
return i + 1;
}
return -1;
}
and in the LookAndFeel…
void CSliderSwitchLookAndFeel::drawLinearSlider (Graphics& g, int x, int y, int width, int height,
float sliderPos, float minSliderPos, float maxSliderPos,
const Slider::SliderStyle style, Slider& slider)
{
CSwitchComponent* pSliderSwitch = dynamic_cast<CSwitchComponent*>(&slider);
if (pSliderSwitch != nullptr)
{
int iNumberOfPoles = pSliderSwitch->getNumberOfPoles();
if (! pSliderSwitch->areImagesLoaded())
{
LookAndFeel_V3::drawLinearSlider (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
return;
}
// Only worry about 2 and 3 poles for now...
if (iNumberOfPoles < 2 || iNumberOfPoles > 3)
return;
Image theImage;
theImage = pSliderSwitch->getImage (pSliderSwitch->getSwitchPosition());
if (theImage.isValid())
{
g.drawImage (theImage, 0, 0, theImage.getWidth(), theImage.getHeight(), 0, 0, theImage.getWidth(), theImage.getHeight());
}
return;
}
LookAndFeel_V3::drawLinearSlider (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
}
That should get you going.
Rail