Hi Fellow Jucers,
I am having a issue with a paint method. What I am trying to do is the write a custom class for a combination of a slider and a combobox. A piece of the graphics is done in LaF for the slider. The rest of the component is done inside the paint method of the class. The class itself derives from component.
To paint the component I use the paintEntireComponent inside the paint method of the PluginEditor class. The problem is that a part of the component paints also at the top of the screen. Far outside of the component bounds. Its like a copy but then at the wrong place. anyone have an idea why this happens? And why only to a part of the paint method inside ComboSlider.
the code:
Comboslider.h:
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "SynthLookAndFeel.h"
#include "SynthColourScheme.h"
class ComboSlider : public juce::Component
{
public:
ComboSlider();
~ComboSlider();
void paint(juce::Graphics& g) override;
void resized() override;
//----------------------------------------------------------------
//Combobox settings-----------------------------------------------
//----------------------------------------------------------------
void mouseDown(const juce::MouseEvent& event) override;
void setText(juce::String text);
juce::String getItemTextIfChanged(int);
int getItemID();
void switchMenuState();
bool getMenuState();
//----------------------------------------------------------------
//Slider settings-------------------------------------------------
//----------------------------------------------------------------
void setSliderRange(juce::Range<double> _sliderRange, double _sliderInterval);
void setDefaultSliderValue(int sliderDefaultValue);
void setSliderValue(double currentSliderValue);
float getSliderValue();
void addListener (juce::Slider::Listener *listener);
juce::Slider* getSlider();
private:
juce::Slider slider;
synthLookAndFeel_ComboSlider comboSliderLookAndFeel;
juce::PopupMenu popupMenu;
juce::String text;
SynthColourScheme colorScheme;
int currentItemID = 0;
bool menuActive = false;
double currentSliderValue;
};
ComboSlider.cpp:
#include "ComboSlider.h"
ComboSlider::ComboSlider() {
setSize(200, 200);
slider.setSliderStyle(juce::Slider::SliderStyle::LinearHorizontal);
slider.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, true, 0, 0);
slider.setLookAndFeel(&comboSliderLookAndFeel);
addAndMakeVisible(slider);
popupMenu.setLookAndFeel(&comboSliderLookAndFeel);
popupMenu.addItem(1, "Filter 1");
popupMenu.addItem(2, "Filter 2");
popupMenu.addItem(3, "Osc1");
}
ComboSlider::~ComboSlider() {
slider.setLookAndFeel(nullptr);
}
void ComboSlider::paint(juce::Graphics& g){
//drawBackground of the component
juce::Rectangle<float> background;
background.setBounds(getX(), getY(), getWidth(), getHeight());
g.setColour(colorScheme.getComboboxBackgroundColor());
g.fillRoundedRectangle(background, 3.0f);
//draw outerline of the component
juce::Rectangle<float> backgroundLine;
backgroundLine.setBounds(getX(), getY(), getWidth(), getHeight());
g.setColour(colorScheme.getComboboxDropHandleLineColor());
g.drawRect(backgroundLine);
//drawDropDownHandler
juce::Rectangle<int> arrowZone (this->getWidth() - 23, 0, 20, this->getHeight());
juce::Path path;
path.startNewSubPath ((float) arrowZone.getX() + 4.0f, (float) arrowZone.getCentreY() - 3.0f);
path.lineTo ((float) arrowZone.getCentreX()-1.0f, (float) arrowZone.getCentreY() + 2.0f);
path.lineTo ((float) arrowZone.getRight() - 6.0f, (float) arrowZone.getCentreY() - 3.0f);
path.closeSubPath();
//choose colors of the combobox handler. Depending on if the popup menu is active or not.
if (!menuActive){
g.setColour (colorScheme.getComboboxDropHandleColor());
} else {
g.setColour(juce::Colours::lightgrey);
}
g.strokePath (path, juce::PathStrokeType (2.0f));;
g.fillPath(path);
g.setOpacity(0.4);
g.drawLine(this->getWidth()-(this->getHeight()/2)-12, 0, this->getWidth()-(this->getHeight()/2)-12, this->getHeight());
}
void ComboSlider::resized(){
int x = -12;
int y = 0;
int width = getWidth()-(getHeight()/2);
int height = 30;
//slider->setBounds(-12, 0, getWidth()-(getHeight()/2), 30);
std::cout << "X: " << x << std::endl;
std::cout << "Y: " << y << std::endl;
std::cout << "Width: " << width << std::endl;
std::cout << "Height: " << height << std::endl;
slider.setBounds(x, y, width, height);
}
void ComboSlider::mouseDown(const juce::MouseEvent &event) {
switchMenuState();
repaint();
popupMenu.showMenuAsync(juce::PopupMenu::Options().withTargetComponent(this).withMinimumWidth(getWidth()), [&, this](int result) {
repaint();
std::cout << "text" << std::endl;
if (result != 0){
comboSliderLookAndFeel.setText(getItemTextIfChanged(result));
}
switchMenuState();
repaint();
});
}
void ComboSlider::setText(juce::String text) {
this->text = text;
std::cout << text << std::endl;
comboSliderLookAndFeel.setText(text);
}
juce::String ComboSlider::getItemTextIfChanged(int index){
for (juce::PopupMenu::MenuItemIterator iterator (popupMenu, true); iterator.next();)
{
auto& item = iterator.getItem();
if (item.itemID == index ){
return item.text;
currentItemID = item.itemID;
}
}
return "";
}
void ComboSlider::switchMenuState(){
if (!menuActive) {
menuActive = true;
} else{
menuActive = false;
}
}
//----------------------------------------------------------------
//Slider settings-------------------------------------------------
//----------------------------------------------------------------
void ComboSlider::setSliderRange(juce::Range<double> _sliderRange, double _sliderInterval) {
slider.setRange(_sliderRange, _sliderInterval);
}
void ComboSlider::setDefaultSliderValue(int sliderDefaultValue) {
}
void ComboSlider::addListener(juce::Slider::Listener *listener) {
slider.addListener(listener);
}
juce::Slider* ComboSlider::getSlider() {
return &slider;
}
PluginEditor.cpp
#include "PluginProcessor.h"
#include "PluginEditor.h"
//==============================================================================
SynthesizerAudioProcessorEditor::SynthesizerAudioProcessorEditor (SynthesizerAudioProcessor& p)
: AudioProcessorEditor (&p), audioProcessor (p)
{
// Make sure that before the constructor has finished, you've set the
// editor's size to whatever you need it to be.
setSize (1000, 800);
addAndMakeVisible(box);
}
SynthesizerAudioProcessorEditor::~SynthesizerAudioProcessorEditor()
{
box.setLookAndFeel(nullptr);
}
//==============================================================================
void SynthesizerAudioProcessorEditor::paint (juce::Graphics& g)
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll (colourScheme.getBackgroundColor());
g.setColour (juce::Colours::black);
g.setFont (15.0f);
g.drawText("Search Path: " + juce::File::getSpecialLocation(
juce::File::SpecialLocationType::userDesktopDirectory)
.getChildFile("Oval.png").getFullPathName(),
getLocalBounds().removeFromBottom(70), juce::Justification::centred, true);
box.paintEntireComponent(g, false);
}
void SynthesizerAudioProcessorEditor::resized()
{
// This is generally where you'll want to lay out the positions of any
// subcomponents in your editor..
box.setBounds(200, 200, 200, 30);
}


