Tchick/Source/PlayPanel.cpp
2026-02-04 11:51:22 +01:00

161 lines
5.7 KiB
C++

/*
==============================================================================
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);
}
}
}