/* ============================================================================== Copyright 2022 Nicolas Chambert This program is free software : you can redistribute itand /or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.If not, see < http://www.gnu.org/licenses/>. ============================================================================== */ /* ============================================================================== Gestion du bouton play et du volume. ============================================================================== */ #include "PlayPanel.h" #include "Metronome.h" #include "Figures.h" void RoundButtonLookAndFeel::drawButtonBackground(juce::Graphics& g, juce::Button& button, const juce::Colour& backgroundColour, bool isMouseOverButton, bool isButtonDown) { // version addapté du LookAndFeel_V4 auto baseColour = backgroundColour.withMultipliedSaturation(button.hasKeyboardFocus(true) ? 1.3f : 0.9f) .withMultipliedAlpha(button.isEnabled() ? 0.9f : 0.5f); if (isButtonDown || isMouseOverButton) baseColour = baseColour.contrasting(isButtonDown ? 0.2f : 0.1f); auto width = (float)button.getWidth() - 1.0f; auto height = (float)button.getHeight() - 1.0f; if (width > 0 && height > 0) { // on viens dessiner un cercle auto rect = button.getLocalBounds(); float rwidth = rect.getWidth() < rect.getHeight() ? (float)rect.getWidth() - 25.0f : (float)rect.getHeight() - 25.0f; g.setGradientFill(juce::ColourGradient::vertical(juce::Colours::lightgrey, 0.0f, juce::Colours::lightgrey.darker(0.1f), height)); g.fillEllipse(rect.getCentreX() - rwidth / 2, rect.getCentreY() - rwidth / 2, rwidth, rwidth); g.setGradientFill(juce::ColourGradient::vertical(baseColour, 0.0f, baseColour.darker(0.1f), height)); g.drawEllipse(rect.getCentreX() - rwidth / 2, rect.getCentreY() - rwidth / 2, rwidth, rwidth, 4); } } PlayPanel::PlayPanel(juce::Colour c) : backgroundColour(c) { // initialisation de l'interface lef.reset(new RoundButtonLookAndFeel()); // Le dessin du bouton play est dans un svg auto doc = juce::XmlDocument::parse(SVGFigures::play); auto image = juce::Drawable::createFromSVG(*doc); addComponent(volume); addComponent(playButton); playButton.setRadioGroupId(1); playButton.setImages(image.get()); playButton.setToggleState(false, juce::NotificationType::dontSendNotification); playButton.setColour(juce::TextButton::buttonColourId, juce::Colours::lightgreen); playButton.setColour(juce::TextButton::textColourOffId, juce::Colours::black); playButton.setLookAndFeel(lef.get()); volume.setRange(-100, 6); // on prend -100db en min, et on s'autorise à amplifier le sample à +6db volume.setValue(0); // valeur initiale à 0db volume.setSliderStyle(juce::Slider::SliderStyle::LinearVertical); volume.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, true, 0, 0); volume.setColour(juce::Slider::thumbColourId, backgroundColour); volume.setColour(juce::Slider::trackColourId, juce::Colours::green); } PlayPanel::~PlayPanel() { // evite une fuite mémoire à la fermeture due au L&F playButton.setLookAndFeel(nullptr); } void PlayPanel::addComponent(juce::Component& c) { addAndMakeVisible(c); c.setColour(juce::TextButton::buttonColourId, backgroundColour); c.setColour(juce::TextButton::textColourOffId, juce::Colours::black); } void PlayPanel::paint(juce::Graphics& g) { g.fillAll(backgroundColour); } void PlayPanel::resized() { // On gêre le placement via une grille 3 collones // la première colonne est vide et sert de "marge" juce::Grid vpgrid; using Track = juce::Grid::TrackInfo; using Fr = juce::Grid::Fr; vpgrid.templateRows = { Track(Fr(1)) }; vpgrid.templateColumns = { Track(Fr(1)), Track(Fr(5)), Track(Fr(1)) }; vpgrid.items = { juce::GridItem(), juce::GridItem(playButton), juce::GridItem(volume) }; vpgrid.performLayout(getLocalBounds()); } void PlayPanel::init(Metronome& metro) { // On établi les liaisons entre le Metronome et les composants graphique playButton.onClick = [&, this]() { play(metro); }; volume.setValue(juce::Decibels::gainToDecibels(metro.getGain())); // On récupère la valeur initiale du gain volume.onValueChange = [&, this] { double db = volume.getValue(); metro.setGain((float)juce::Decibels::decibelsToGain(db)); }; } void PlayPanel::play(Metronome& metro) { // lance la lecture ou met en pause playState = playState == PlayState::playing ? PlayState::stopped : PlayState::playing; if (playState == PlayState::stopped) { // en cas de stop, on remet les compteurs à zero sur le metronome metro.reset(); } // On modifie la couleur du bouton en fonction de l'état playButton.setColour(juce::TextButton::buttonColourId, playState == PlayState::playing ? juce::Colours::green : juce::Colours::lightgreen); } void PlayPanel::highlight() { // Met le bouton en surbrillance sur le temps // la variable highlightFrames decompte 6 frames sur un timer de 20ms soit 120ms if (playState == PlayState::playing) { if (highlightFrames > 0) { playButton.setColour(juce::TextButton::buttonColourId, juce::Colours::orangered); highlightFrames--; } else { playButton.setColour(juce::TextButton::buttonColourId, juce::Colours::green); } } }