diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..61e646b --- /dev/null +++ b/.clang-format @@ -0,0 +1,83 @@ +# Google C/C++ Code Style settings +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# Author: Kehan Xue, kehan.xue (at) gmail.com + +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never # To avoid conflict, set this "Never" and each "if statement" should include brace when coding +AllowShortLambdasOnASingleLine: Inline +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterStruct: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 80 +CompactNamespaces: false +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false # Make sure the * or & align on the left +EmptyLineBeforeAccessModifier: LogicalBlock +FixNamespaceComments: true +IncludeBlocks: Preserve +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Left +ReflowComments: false +# SeparateDefinitionBlocks: Always # Only support since clang-format 14 +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: c++11 +TabWidth: 4 +UseTab: Always \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 8851e64..cb168bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "docs"] - path = docs - url = git@github.com:k147-studio/docs.git [submodule "JUCE"] path = JUCE - url = https://github.com/juce-framework/JUCE.git + url = https://github.com/k147-studio/JUCE.git diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/docs b/docs deleted file mode 160000 index 80463c5..0000000 --- a/docs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 80463c5e6fd68b4b4966701ce6b1dfa24e52da98 diff --git a/include/AccountComponent.h b/include/AccountComponent.h index 77ae47d..bd2756a 100644 --- a/include/AccountComponent.h +++ b/include/AccountComponent.h @@ -2,28 +2,33 @@ #include -class AccountComponent : public juce::Component -{ +class AccountComponent : public Component { public: - AccountComponent(); - void paint(juce::Graphics&) override; - void resized() override; + AccountComponent(); + void paint(Graphics&) override; + void resized() override; private: - void apiResponseReceived(const juce::String& content); - void saveSettings(); - void importSettings(); - void changePassword(); + void apiResponseReceived(const String& content); + void saveSettings(); + void importSettings(); - juce::Label titleLabel; - juce::Label responseLabel; + void setupLabels(); + void setupButtons(); + void setupGrid(); - juce::Label emailLabel, usernameLabel; - juce::Label emailValueLabel, usernameValueLabel; + Label titleLabel{"titleLabel", "Mon compte"}; + Label responseLabel{"responseLabel", "En attente de réponse..."}; - juce::TextButton saveButton, importButton, changePasswordButton; + Label emailLabel{"emailLabel", "Adresse mail :"}; + Label usernameLabel{"usernameLabel", "Nom d'utilisateur :"}; + Label emailValueLabel{"emailValueLabel", "utilisateur@example.com"}; + Label usernameValueLabel{"usernameValueLabel", "NomUtilisateur"}; - juce::Grid grid; + TextButton saveButton{"Sauvegarder les réglages"}; + TextButton importButton{"Importer les réglages"}; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AccountComponent) -}; + Grid grid; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AccountComponent) +}; \ No newline at end of file diff --git a/include/BasePedalComponent.h b/include/BasePedalComponent.h index ed61d3f..3997706 100644 --- a/include/BasePedalComponent.h +++ b/include/BasePedalComponent.h @@ -7,89 +7,88 @@ * @brief Base class for pedal components. * This class provides a common interface and functionality for all pedal components. */ -class BasePedalComponent : public EffectComponent -{ +class BasePedalComponent : public EffectComponent { public: - /** - * @brief Initializes a new instance of the BasePedalComponent class. - * @param effect The effect associated with this pedal component. - */ - BasePedalComponent(AbstractEffect* effect); - - /** - * @brief Destroys the instance of the BasePedalComponent class. - */ - ~BasePedalComponent() override; - - /** - * @brief Paints the component. - * @param g The JUCE graphics context that paints the component. - */ - void paint(juce::Graphics &g) override; - - /** - * @brief Resizes the component. - */ - void resized() override; + /** + * @brief Initializes a new instance of the BasePedalComponent class. + * @param effect The effect associated with this pedal component. + */ + BasePedalComponent(AbstractEffect* effect); + + /** + * @brief Destroys the instance of the BasePedalComponent class. + */ + ~BasePedalComponent() override; + + /** + * @brief Paints the component. + * @param g The JUCE graphics context that paints the component. + */ + void paint(Graphics& g) override; + + /** + * @brief Resizes the component. + */ + void resized() override; protected: - /** - * @brief The default width of the component. - */ - const float DEFAULT_WIDTH = 200.0f; - - /** - * @brief The default height of the component. - */ - const float DEFAULT_HEIGHT = 300.0f; - - /** - * @brief The main layout for the pedal component. - */ - juce::Grid pedalLayout; - - /** - * @brief The primary color of the pedal component. Used as background color. - */ - juce::Colour primaryColor; - - /** - * @brief The secondary color of the pedal component. Used as background color. - */ - juce::Colour secondaryColor; - - /** - * @brief The layout for the pedal settings. - */ - PedalSettingsLayoutComponent* settingsLayout; - - /** - * @brief The label for the pedal name. - */ - juce::Label* pedalLabel; - - /** - * @brief The button to enable/disable the pedal. - */ - juce::ImageButton enablePedalButton; - - /** - * @brief The indicator for the pedal power status. - */ - PedalPowerIndicatorComponent* isEnabledIndicator; - - /** - * @brief Tells if the pedal is enabled or not. - */ - bool* isEnabled; - - /** - * @brief Called when the enable button is clicked. - */ - void onEnableButtonClicked(); - - /** - * @brief Initializes the pedal layout to display it. - */ - void initializePedal(); + /** + * @brief The default width of the component. + */ + const float DEFAULT_WIDTH = 200.0f; + + /** + * @brief The default height of the component. + */ + const float DEFAULT_HEIGHT = 300.0f; + + /** + * @brief The main layout for the pedal component. + */ + Grid pedalLayout; + + /** + * @brief The primary color of the pedal component. Used as background color. + */ + Colour primaryColor; + + /** + * @brief The secondary color of the pedal component. Used as background color. + */ + Colour secondaryColor; + + /** + * @brief The layout for the pedal settings. + */ + PedalSettingsLayoutComponent* settingsLayout; + + /** + * @brief The label for the pedal name. + */ + Label* pedalLabel; + + /** + * @brief The button to enable/disable the pedal. + */ + ImageButton enablePedalButton; + + /** + * @brief The indicator for the pedal power status. + */ + PedalPowerIndicatorComponent* isEnabledIndicator; + + /** + * @brief Tells if the pedal is enabled or not. + */ + bool* isEnabled; + + /** + * @brief Called when the enable button is clicked. + */ + void onEnableButtonClicked(); + + /** + * @brief Initializes the pedal layout to display it. + */ + void initializePedal(); }; diff --git a/include/ConnectionComponent.h b/include/ConnectionComponent.h deleted file mode 100644 index bd55dd9..0000000 --- a/include/ConnectionComponent.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include - -/** - * @brief Represents a graphical component that contains and displays the login form. - */ -class LoginComponent final : public juce::Component { - public: - /** - * @brief Initializes a new instance of the LoginComponent class. - */ - LoginComponent(); - - /** - * @brief Destroys the instance of the LoginComponent class. - */ - ~LoginComponent() override; - - /** - * @brief Determines how to display the component. - * @param g The JUCE graphics context that paints the component. - */ - void paint(juce::Graphics &g) override; - - /** - * @brief Determines what to do when the component is resized. - */ - void resized() override; - private: - /** - * @brief The username field. - */ - juce::TextEditor usernameField; - - /** - * @brief The password field. - */ - juce::TextEditor passwordField; - - /** - * @brief The login button. - */ - juce::TextButton loginButton; - - /** - * @brief The skip button. - */ - juce::TextButton skipButton; - - /** - * @brief Determines what to do when the skip button is clicked. - */ - void skipButtonClicked(); - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LoginComponent) -}; \ No newline at end of file diff --git a/include/DelayEffect.h b/include/DelayEffect.h index babd770..06d00bd 100644 --- a/include/DelayEffect.h +++ b/include/DelayEffect.h @@ -9,84 +9,86 @@ */ class DelayEffect : public AbstractEffect { public: - /** - * @brief Initializes a new instance of the DelayEffect class. - */ - DelayEffect(); + /** + * @brief Initializes a new instance of the DelayEffect class. + */ + DelayEffect(); - /** - * @brief Destroys the instance of the DelayEffect class. - */ - ~DelayEffect() override; + /** + * @brief Destroys the instance of the DelayEffect class. + */ + ~DelayEffect() override; - /** - * @brief Applies the delay effect to the given audio buffer. - * @param bufferToFill The audio buffer to apply the effect to. - */ - void apply(const AudioSourceChannelInfo &bufferToFill) override; + /** + * @brief Applies the delay effect to the given audio buffer. + * @param bufferToFill The audio buffer to apply the effect to. + */ + void apply(const AudioSourceChannelInfo& bufferToFill) override; - /** - * @brief Sets the rate of the delay effect. - * @param rate The rate of the delay effect. - */ - void setRate(float rate); + /** + * @brief Sets the rate of the delay effect. + * @param rate The rate of the delay effect. + */ + void setRate(float rate); - /** - * @brief Sets the delay of the effect. - * @param delay The delay of the effect. - */ - void setDelay(float delay); + /** + * @brief Sets the delay of the effect. + * @param delay The delay of the effect. + */ + void setDelay(float delay); - /** - * @brief Compares the effect with another given effect. - * @param effect The effect to compare with. - * @return True if the effect is equal to the given effect, false otherwise. - */ - bool operator==(const AbstractEffect *effect) override; + /** + * @brief Compares the effect with another given effect. + * @param effect The effect to compare with. + * @return True if the effect is equal to the given effect, false otherwise. + */ + bool operator==(const AbstractEffect* effect) override; - /** - * @brief Gets the type name of the effect for serialization purposes. - * @return A string representing the effect type. - */ - [[nodiscard]] String getEffectType() const override { return "DelayEffect"; } + /** + * @brief Gets the type name of the effect for serialization purposes. + * @return A string representing the effect type. + */ + [[nodiscard]] String getEffectType() const override { + return "DelayEffect"; + } - /** - * @brief Serializes the delay effect to a JSON object. - * @return JSON object containing serialized effect data. - */ - [[nodiscard]] var toJSON() const override { - auto obj = AbstractEffect::toJSON(); - if (auto *dynamicObj = obj.getDynamicObject()) { - dynamicObj->setProperty("rate", rate); - dynamicObj->setProperty("delay", delay); - } - return obj; - } + /** + * @brief Serializes the delay effect to a JSON object. + * @return JSON object containing serialized effect data. + */ + [[nodiscard]] var toJSON() const override { + auto obj = AbstractEffect::toJSON(); + if (auto* dynamicObj = obj.getDynamicObject()) { + dynamicObj->setProperty("rate", rate); + dynamicObj->setProperty("delay", delay); + } + return obj; + } - /** - * @brief Deserializes the delay effect from a JSON object. - * @param json JSON object containing serialized effect data. - */ - void fromJSON(const var &json) override { - AbstractEffect::fromJSON(json); + /** + * @brief Deserializes the delay effect from a JSON object. + * @param json JSON object containing serialized effect data. + */ + void fromJSON(const var& json) override { + AbstractEffect::fromJSON(json); - if (const auto *obj = json.getDynamicObject()) { - rate = static_cast(obj->getProperty("rate")); - delay = static_cast(obj->getProperty("delay")); - } - } + if (const auto* obj = json.getDynamicObject()) { + rate = static_cast(obj->getProperty("rate")); + delay = static_cast(obj->getProperty("delay")); + } + } private: - /** - * @brief The rate of the delay. - */ - float rate; + /** + * @brief The rate of the delay. + */ + float rate; - /** - * @brief The delay of the effect. - */ - float delay; + /** + * @brief The delay of the effect. + */ + float delay; - std::vector circularBuffer; - int writePosition = 0; + std::vector circularBuffer; + int writePosition = 0; }; diff --git a/include/LoginComponent.h b/include/LoginComponent.h new file mode 100644 index 0000000..2d545cb --- /dev/null +++ b/include/LoginComponent.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +class LoginComponent final : public Component { +public: + LoginComponent(); + ~LoginComponent() override; + + void paint(Graphics&) override; + void resized() override; + +private: + void setupFields(); + void setupButtons(); + void layoutComponents(); + void skipButtonClicked(); + + TextEditor usernameField; + TextEditor passwordField; + TextButton loginButton{"Login"}; + TextButton skipButton{"Skip"}; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LoginComponent) +}; \ No newline at end of file diff --git a/include/MainComponent.h b/include/MainComponent.h index 647c1db..645f75f 100644 --- a/include/MainComponent.h +++ b/include/MainComponent.h @@ -1,7 +1,7 @@ #pragma once #include "BottomMenuBarComponent.h" -#include "ConnectionComponent.h" +#include "LoginComponent.h" #include "Manager.h" #include "PedalboardComponent.h" #include "TopMenuBarComponent.h" diff --git a/include/ToggleButtonComponent.h b/include/ToggleButtonComponent.h index 3cd17df..6b2e9b3 100644 --- a/include/ToggleButtonComponent.h +++ b/include/ToggleButtonComponent.h @@ -2,10 +2,9 @@ #include -class ToggleButtonComponent : public ToggleButton -{ +class ToggleButtonComponent : public ToggleButton { public: - ToggleButtonComponent(); - ~ToggleButtonComponent() override; - void paint(juce::Graphics& g) override; -}; \ No newline at end of file + ToggleButtonComponent(); + ~ToggleButtonComponent() override; + void paint(Graphics& g) override; +}; diff --git a/include/TopMenuBarComponent.h b/include/TopMenuBarComponent.h index 5778bbe..ad810ad 100644 --- a/include/TopMenuBarComponent.h +++ b/include/TopMenuBarComponent.h @@ -1,61 +1,38 @@ #pragma once -#include -#include - +#include +#include "AccountComponent.h" #include "ModalOverlayComponent.h" #include "SettingsComponent.h" -#include "AccountComponent.h" -/** - * @brief Represents a graphical component that contains and displays the top menu bar. - */ -class TopMenuBarComponent : public juce::Component { - public: - /** - * @brief Initializes a new instance of the TopMenuBarComponent class. - */ - explicit TopMenuBarComponent(juce::AudioDeviceManager& deviceManager, bool* isMuted = nullptr); - - /** - * @brief Destroys the instance of the TopMenuBarComponent class. - */ - ~TopMenuBarComponent() override; - - /** - * @brief Determines how to display the component. - * @param g The JUCE graphics context that paints the component. - */ - void paint(juce::Graphics &g) override; - - /** - * @brief Determines what to do when the component is resized. - */ - void resized() override; - - private: - /** - * @brief The flexBox component that contains the menu items. - */ - juce::FlexBox flexBox; - - ModalOverlayComponent* modalOverlay; - - /** - * @brief The image button to open settings. - */ - juce::ImageButton settingsButton; - SettingsComponent* settingsComponent; - - juce::ImageButton accountButton; - AccountComponent* accountComponent; - - bool* isSoundMuted = nullptr; - juce::ImageButton muteButton; - - void openSettingsPopup(juce::AudioDeviceManager& deviceManager); - void openAccountPopup(); - void toggleMute(); - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TopMenuBarComponent) -}; \ No newline at end of file +class TopMenuBarComponent : public Component { +public: + explicit TopMenuBarComponent(AudioDeviceManager& deviceManager, + bool* isMuted = nullptr); + ~TopMenuBarComponent() override; + + void paint(Graphics& g) override; + void resized() override; + +private: + int buttonSize = 32; + float gap = 16; + + FlexBox flexBox; + + ImageButton accountButton; + ImageButton muteButton; + ImageButton settingsButton; + + AccountComponent* accountComponent; + ModalOverlayComponent* modalOverlay; + SettingsComponent* settingsComponent; + + bool* isSoundMuted = nullptr; + + void openSettingsPopup(AudioDeviceManager& deviceManager); + void openAccountPopup(); + void toggleMute(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TopMenuBarComponent) +}; diff --git a/resources/icons/export.png b/resources/icons/export.png new file mode 100644 index 0000000..69f11e2 Binary files /dev/null and b/resources/icons/export.png differ diff --git a/resources/icons/mute.png b/resources/icons/mute.png index 76b5156..88dc4e0 100644 Binary files a/resources/icons/mute.png and b/resources/icons/mute.png differ diff --git a/resources/icons/power.png b/resources/icons/power.png index 26bfb45..dcfe593 100644 Binary files a/resources/icons/power.png and b/resources/icons/power.png differ diff --git a/resources/icons/settings.png b/resources/icons/settings.png index 912e5b0..2071f27 100644 Binary files a/resources/icons/settings.png and b/resources/icons/settings.png differ diff --git a/resources/icons/sync.png b/resources/icons/sync.png new file mode 100644 index 0000000..cba8294 Binary files /dev/null and b/resources/icons/sync.png differ diff --git a/resources/icons/unmute.png b/resources/icons/unmute.png index 84bb7f7..d1e4d79 100644 Binary files a/resources/icons/unmute.png and b/resources/icons/unmute.png differ diff --git a/resources/icons/xmark.png b/resources/icons/xmark.png new file mode 100644 index 0000000..4937ee7 Binary files /dev/null and b/resources/icons/xmark.png differ diff --git a/src/Main.cpp b/src/Main.cpp index a403b1a..895ebdb 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,91 +1,80 @@ #include - #include "EffectsFactory.h" #include "MainComponent.h" class GuiAppApplication final : public JUCEApplication { public: - GuiAppApplication() = default; - - // We inject these as compile definitions from the CMakeLists.txt - // If you've enabled the juce header with `juce_generate_juce_header()` - // you could `#include ` and use `ProjectInfo::projectName` etc. instead. - const String getApplicationName() override { return JUCE_APPLICATION_NAME_STRING; } - const String getApplicationVersion() override { return JUCE_APPLICATION_VERSION_STRING; } - bool moreThanOneInstanceAllowed() override { return false; } - - void initialise(const String &commandLine) override { - // This method is where you should put your application's initialisation code.. - ignoreUnused(commandLine); - - mainWindow = std::make_unique(getApplicationName()); - } - - void shutdown() override { - mainWindow = nullptr; // (deletes our window) - } - - void systemRequestedQuit() override { - // This is called when the app is being asked to quit: you can ignore this - // request and let the app carry on running, or call quit() to allow the app to close. - quit(); - } - - void anotherInstanceStarted(const String &commandLine) override { - // When another instance of the app is launched while this one is running, - // this method is invoked, and the commandLine parameter tells you what - // the other instance's command-line arguments were. - ignoreUnused(commandLine); - } - - /* - This class implements the desktop window that contains an instance of - our MainComponent class. - */ - class MainWindow final : public DocumentWindow { - public: - explicit MainWindow (String name) - : DocumentWindow (name, - Desktop::getInstance().getDefaultLookAndFeel() - .findColour (backgroundColourId), - allButtons) - { - setUsingNativeTitleBar (true); - Pedalboard* pedalboard = new Pedalboard(); - pedalboard->appendAll(EffectsFactory::createAllEffects()); - Manager* manager = new Manager(pedalboard); - setContentOwned (new MainComponent(*manager), true); + GuiAppApplication() = default; + + const String getApplicationName() override { + return JUCE_APPLICATION_NAME_STRING; + } + + const String getApplicationVersion() override { + return JUCE_APPLICATION_VERSION_STRING; + } + + bool moreThanOneInstanceAllowed() override { return false; } + + void initialise(const String& commandLine) override { + // This method is where you should put your application's initialisation code.. + ignoreUnused(commandLine); + + mainWindow = std::make_unique(getApplicationName()); + } + + void shutdown() override { + mainWindow = nullptr; // (deletes our window) + } + + void systemRequestedQuit() override { + // This is called when the app is being asked to quit: you can ignore this + // request and let the app carry on running, or call quit() to allow the app to close. + quit(); + } + + void anotherInstanceStarted(const String& commandLine) override { + // When another instance of the app is launched while this one is running, + // this method is invoked, and the commandLine parameter tells you what + // the other instance's command-line arguments were. + ignoreUnused(commandLine); + } + + class MainWindow final : public DocumentWindow { + public: + explicit MainWindow(const String& name) : + DocumentWindow( + name, Desktop::getInstance().getDefaultLookAndFeel().findColour( + backgroundColourId), allButtons) { + setUsingNativeTitleBar(true); + Pedalboard* pedalboard = new Pedalboard(); + pedalboard->appendAll(EffectsFactory::createAllEffects()); + Manager* manager = new Manager(pedalboard); + setContentOwned(new MainComponent(*manager), true); #if JUCE_IOS || JUCE_ANDROID setFullScreen (true); #else - setResizable(false, false); - centreWithSize(1280, 720); + setResizable(true, true); + setSize(1280, 854); + centreWithSize(1280, 854); #endif + Component::setVisible(true); + } - Component::setVisible(true); - } - - void closeButtonPressed() override { - // This is called when the user tries to close this window. Here, we'll just - // ask the app to quit when this happens, but you can change this to do - // whatever you need. - getInstance()->systemRequestedQuit(); - } - - /* Note: Be careful if you override any DocumentWindow methods - the base - class uses a lot of them, so by overriding you might break its functionality. - It's best to do all your work in your content component instead, but if - you really have to override any DocumentWindow methods, make sure your - subclass also calls the superclass's method. - */ + void closeButtonPressed() override { + // This is called when the user tries to close this window. Here, we'll just + // ask the app to quit when this happens, but you can change this to do + // whatever you need. + getInstance()->systemRequestedQuit(); + } - // private: - // JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow) - }; + private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainWindow) + }; private: - std::unique_ptr mainWindow; + std::unique_ptr mainWindow; }; // This macro generates the main() routine that launches the app. diff --git a/src/MainComponent.cpp b/src/MainComponent.cpp index 1d3a185..275967a 100644 --- a/src/MainComponent.cpp +++ b/src/MainComponent.cpp @@ -1,84 +1,71 @@ #include "MainComponent.h" -#include "SettingsComponent.h" #include "ResourceManager.h" - - - -MainComponent::MainComponent(const Manager &manager): pedalboardComponent(manager.getPedalboard()), - topMenuBarComponent(this->deviceManager, &isSoundMuted), manager(manager) -{ - setAudioChannels(2, 2); - - Image background = ResourceManager::loadImage("resources/images/background.png"); - if (background.isValid()) { - backgroundImage.setImage(background); - backgroundImage.setImagePlacement(juce::RectanglePlacement::stretchToFit); - addAndMakeVisible(backgroundImage); - } else { - DBG("Erreur : image de fond introuvable ou invalide."); - } - - pedalboardContainer.setViewedComponent(&pedalboardComponent, true); - pedalboardContainer.setScrollBarsShown(true, false); - - addAndMakeVisible(pedalboardContainer); - addAndMakeVisible(topMenuBarComponent); - addAndMakeVisible(bottomMenuBarComponent); - addAndMakeVisible(connectionComponent); +MainComponent::MainComponent(const Manager& manager): + pedalboardComponent(manager.getPedalboard()), + topMenuBarComponent(this->deviceManager, &isSoundMuted), manager(manager) { + setAudioChannels(2, 2); + + const Image background = ResourceManager::loadImage( + "resources/images/background.png"); + if (background.isValid()) { + backgroundImage.setImage(background); + backgroundImage.setImagePlacement(RectanglePlacement::stretchToFit); + addAndMakeVisible(backgroundImage); + } else { + DBG("Error : resources/images/background.png not found."); + } + + pedalboardContainer.setViewedComponent(&pedalboardComponent, true); + pedalboardContainer.setScrollBarsShown(true, false); + + addAndMakeVisible(pedalboardContainer); + addAndMakeVisible(topMenuBarComponent); + addAndMakeVisible(bottomMenuBarComponent); + addAndMakeVisible(connectionComponent); } //============================================================================== -void MainComponent::paint (juce::Graphics& g) -{ -} - -void MainComponent::resized() -{ - // This is called when the MainComponent is resized. - // If you add any child components, this is where you should - // update their positions. - backgroundImage.setBounds(getLocalBounds()); - connectionComponent.setBounds(getLocalBounds()); - - int pedalboardWidth = getWidth(); - int pedalboardHeight = pedalboardComponent.getRequiredHeight(getWidth()); - pedalboardComponent.setSize(pedalboardWidth, pedalboardHeight); - - using Track = juce::Grid::TrackInfo; - using Px = juce::Grid::Px; - using Fr = juce::Grid::Fr; - grid.templateRows = { Track (Px (50)), Track (Fr(1)) }; - grid.templateColumns = { Track (Fr(1)) }; - grid.items = { - juce::GridItem(topMenuBarComponent), - juce::GridItem(pedalboardContainer) - }; - grid.performLayout(getLocalBounds()); +void MainComponent::paint(Graphics& g) {} + +void MainComponent::resized() { + backgroundImage.setBounds(getLocalBounds()); + connectionComponent.setBounds(getLocalBounds()); + + int pedalboardWidth = getWidth(); + int pedalboardHeight = pedalboardComponent.getRequiredHeight(getWidth()); + pedalboardComponent.setSize(pedalboardWidth, pedalboardHeight); + + using Track = Grid::TrackInfo; + using Px = Grid::Px; + using Fr = Grid::Fr; + grid.templateRows = {Track(Px(50)), Track(Fr(1))}; + grid.templateColumns = {Track(Fr(1))}; + grid.items = { + GridItem(topMenuBarComponent), + GridItem(pedalboardContainer) + }; + grid.performLayout(getLocalBounds()); } -void MainComponent::prepareToPlay(int samplesPerBlockExpected, double sampleRate) { - +void MainComponent::prepareToPlay(int samplesPerBlockExpected, + double sampleRate) {} + +void MainComponent::getNextAudioBlock( + const AudioSourceChannelInfo& bufferToFill) { + if (!this->isSoundMuted) { + if (&bufferToFill == nullptr) { + return; + } + if (bufferToFill.buffer == nullptr) { + return; + } + this->manager.apply(bufferToFill); + } else { + bufferToFill.clearActiveBufferRegion(); + } } -void MainComponent::getNextAudioBlock(const AudioSourceChannelInfo &bufferToFill) { - if (!this->isSoundMuted) - { - if (&bufferToFill == nullptr) { - return; - } - if (bufferToFill.buffer == nullptr) { - return; - } - this->manager.apply(bufferToFill); - } - else - { - bufferToFill.clearActiveBufferRegion(); - } -} - -void MainComponent::releaseResources() { -} +void MainComponent::releaseResources() {} diff --git a/src/components/AccountComponent.cpp b/src/components/AccountComponent.cpp index c5a0f2d..09662e2 100644 --- a/src/components/AccountComponent.cpp +++ b/src/components/AccountComponent.cpp @@ -1,122 +1,104 @@ #include "AccountComponent.h" #include "ApiClient.h" -AccountComponent::AccountComponent() -{ - // --- Titre --- - titleLabel.setText("Mon compte", juce::dontSendNotification); - titleLabel.setFont(juce::Font(24.0f, juce::Font::bold)); - titleLabel.setJustificationType(juce::Justification::centred); - addAndMakeVisible(titleLabel); - - // --- Labels de champs --- - emailLabel.setText("Adresse mail :", juce::dontSendNotification); - usernameLabel.setText("Nom d'utilisateur :", juce::dontSendNotification); - - for (auto* label : { &emailLabel, &usernameLabel }) - { - label->setFont(juce::Font(16.0f)); - label->setJustificationType(juce::Justification::centredLeft); - addAndMakeVisible(*label); - } - - // --- Valeurs (non éditables) --- - emailValueLabel.setText("utilisateur@example.com", juce::dontSendNotification); - usernameValueLabel.setText("NomUtilisateur", juce::dontSendNotification); - - for (auto* val : { &emailValueLabel, &usernameValueLabel }) - { - val->setFont(juce::Font(16.0f)); - val->setJustificationType(juce::Justification::centredLeft); - val->setColour(juce::Label::textColourId, juce::Colours::black); - addAndMakeVisible(*val); - } - - // --- Boutons --- - saveButton.setButtonText("Sauvegarder les réglages"); - importButton.setButtonText("Importer les réglages"); - changePasswordButton.setButtonText("Changer le mot de passe"); - - saveButton.onClick = [this]() { saveSettings(); }; - importButton.onClick = [this]() { importSettings(); }; - changePasswordButton.onClick = [this]() { changePassword(); }; - - for (auto* button : { &saveButton, &importButton, &changePasswordButton }) - addAndMakeVisible(*button); - - // --- Label de réponse (API ou autres actions) --- - responseLabel.setFont(juce::Font(14.0f)); - responseLabel.setJustificationType(juce::Justification::centred); - responseLabel.setColour(juce::Label::textColourId, juce::Colours::darkgrey); - responseLabel.setText("En attente de réponse...", juce::dontSendNotification); - addAndMakeVisible(responseLabel); - - // --- Appel API fictif --- - auto replyFunc = [this](const juce::String& content) { - apiResponseReceived(content); - }; - ApiClient::runHTTP({ "https://dummyjson.com/test" }, replyFunc); +namespace { +constexpr float titleFontSize = 24.0f; +constexpr float labelFontSize = 16.0f; +constexpr float responseFontSize = 14.0f; } -void AccountComponent::paint(juce::Graphics& g) -{ - g.fillAll(juce::Colours::lightgrey); +AccountComponent::AccountComponent() { + setupLabels(); + setupButtons(); + setupGrid(); + + // Dummy API call + auto replyFunc = [this](const String& content) { + apiResponseReceived(content); + }; + ApiClient::runHTTP({"https://dummyjson.com/test"}, replyFunc); +} + +void AccountComponent::setupLabels() { + titleLabel.setFont(FontOptions(titleFontSize, Font::bold)); + titleLabel.setJustificationType(Justification::centred); + addAndMakeVisible(titleLabel); + + for (auto* label : {&emailLabel, &usernameLabel}) { + label->setFont(FontOptions(labelFontSize)); + label->setJustificationType(Justification::centredLeft); + addAndMakeVisible(*label); + } + + for (auto* val : {&emailValueLabel, &usernameValueLabel}) { + val->setFont(FontOptions(labelFontSize)); + val->setJustificationType(Justification::centredLeft); + val->setColour(Label::textColourId, Colours::black); + addAndMakeVisible(*val); + } + + responseLabel.setFont(FontOptions(responseFontSize)); + responseLabel.setJustificationType(Justification::centred); + responseLabel.setColour(Label::textColourId, Colours::darkgrey); + addAndMakeVisible(responseLabel); +} + +void AccountComponent::setupButtons() { + saveButton.onClick = [this] { saveSettings(); }; + importButton.onClick = [this] { importSettings(); }; + + for (auto* button : {&saveButton, &importButton}) + addAndMakeVisible(*button); +} + +void AccountComponent::setupGrid() { + using namespace juce; + grid.templateRows = { + Grid::TrackInfo(40_px), // Title + Grid::TrackInfo(30_px), // Email label + Grid::TrackInfo(30_px), // Email value + Grid::TrackInfo(30_px), // Username label + Grid::TrackInfo(30_px), // Username value + Grid::TrackInfo(20_px), // Spacer + Grid::TrackInfo(40_px), // Change password button + Grid::TrackInfo(40_px), // Save button + Grid::TrackInfo(40_px), // Import button + Grid::TrackInfo(30_px) // Response label + }; + + grid.templateColumns = {Grid::TrackInfo(1_fr)}; + + grid.items = { + GridItem(titleLabel), + GridItem(emailLabel), + GridItem(emailValueLabel), + GridItem(usernameLabel), + GridItem(usernameValueLabel), + GridItem().withArea(6, 1), // Spacer + GridItem(saveButton), + GridItem(importButton), + GridItem(responseLabel) + }; } -void AccountComponent::resized() -{ - using namespace juce; - - grid.templateRows = { - Grid::TrackInfo(40_px), // Titre - Grid::TrackInfo(30_px), // Label email - Grid::TrackInfo(30_px), // Valeur email - Grid::TrackInfo(30_px), // Label username - Grid::TrackInfo(30_px), // Valeur username - Grid::TrackInfo(20_px), - Grid::TrackInfo(40_px), // Bouton changer mdp - Grid::TrackInfo(40_px), // Bouton sauvegarder - Grid::TrackInfo(40_px), // Bouton importer - Grid::TrackInfo(30_px) // Label réponse - }; - - grid.templateColumns = { Grid::TrackInfo(1_fr) }; - - grid.items = { - GridItem(titleLabel), - GridItem(emailLabel), - GridItem(emailValueLabel), - GridItem(usernameLabel), - GridItem(usernameValueLabel), - GridItem().withArea(6, 1), // espacement - GridItem(changePasswordButton), - GridItem(saveButton), - GridItem(importButton), - GridItem(responseLabel) - }; - - grid.performLayout(getLocalBounds().reduced(40)); +void AccountComponent::paint(Graphics& g) { + g.fillAll(Colours::lightgrey); } -void AccountComponent::apiResponseReceived(const juce::String& content) -{ - responseLabel.setText("Réponse API : " + content, juce::dontSendNotification); +void AccountComponent::resized() { + grid.performLayout(getLocalBounds().reduced(40)); } -void AccountComponent::saveSettings() -{ - responseLabel.setText("✅ Réglages sauvegardés !", juce::dontSendNotification); +void AccountComponent::apiResponseReceived(const String& content) { + responseLabel.setText("Réponse API : " + content, dontSendNotification); } -void AccountComponent::importSettings() -{ - emailValueLabel.setText("import@example.com", juce::dontSendNotification); - usernameValueLabel.setText("UtilisateurImporté", juce::dontSendNotification); - responseLabel.setText("📥 Réglages importés", juce::dontSendNotification); +void AccountComponent::saveSettings() { + responseLabel.setText("✅ Réglages sauvegardés !", dontSendNotification); } -void AccountComponent::changePassword() -{ - // Action fictive pour changer le mot de passe - responseLabel.setText("🔐 Redirection vers le changement de mot de passe...", juce::dontSendNotification); +void AccountComponent::importSettings() { + emailValueLabel.setText("import@example.com", dontSendNotification); + usernameValueLabel.setText("UtilisateurImporté", dontSendNotification); + responseLabel.setText("📥 Réglages importés", dontSendNotification); } diff --git a/src/components/LoginComponent.cpp b/src/components/LoginComponent.cpp index 0325044..77dbaaa 100644 --- a/src/components/LoginComponent.cpp +++ b/src/components/LoginComponent.cpp @@ -1,36 +1,49 @@ -#include "ConnectionComponent.h" +#include "LoginComponent.h" LoginComponent::LoginComponent() { - usernameField.setTextToShowWhenEmpty("Username", juce::Colours::grey); - passwordField.setTextToShowWhenEmpty("Password", juce::Colours::grey); - passwordField.setPasswordCharacter('*'); - skipButton.setButtonText("Skip"); - loginButton.setButtonText("Login"); - skipButton.onClick = [this] { skipButtonClicked(); }; + setupFields(); + setupButtons(); + layoutComponents(); } LoginComponent::~LoginComponent() = default; -void LoginComponent::skipButtonClicked() { - //addAndMakeVisible(new PedalboardComponent(manager.getPedalboard())); - setVisible(false); +void LoginComponent::setupFields() { + usernameField.setTextToShowWhenEmpty("Username", Colours::grey); + passwordField.setTextToShowWhenEmpty("Password", Colours::grey); + passwordField.setPasswordCharacter('*'); + addAndMakeVisible(usernameField); + addAndMakeVisible(passwordField); +} + +void LoginComponent::setupButtons() { + loginButton.onClick = [] { + // TODO: Implement login logic + }; + skipButton.onClick = [this] { skipButtonClicked(); }; + addAndMakeVisible(loginButton); + addAndMakeVisible(skipButton); } -void LoginComponent::paint(juce::Graphics &g) { - g.fillAll(juce::Colours::white); - addAndMakeVisible(usernameField); - addAndMakeVisible(passwordField); - addAndMakeVisible(loginButton); - addAndMakeVisible(skipButton); +void LoginComponent::paint(Graphics& g) { + g.fillAll(Colours::white); } void LoginComponent::resized() { - const auto area = getLocalBounds().reduced(50); - const auto halfWidth = area.getWidth() / 2; - const auto halfHeight = area.getHeight() / 2; - - usernameField.setBounds(halfWidth - 100, halfHeight - 80, 300, 40); - passwordField.setBounds(halfWidth - 100, halfHeight - 30, 300, 40); - loginButton.setBounds(halfWidth - 100, halfHeight + 30, 300, 40); - skipButton.setBounds(halfWidth - 100, halfHeight + 80, 300, 40); + layoutComponents(); +} + +void LoginComponent::layoutComponents() { + auto area = getLocalBounds().reduced(50); + auto halfWidth = area.getWidth() / 2; + auto halfHeight = area.getHeight() / 2; + + usernameField.setBounds(halfWidth - 100, halfHeight - 80, 300, 40); + passwordField.setBounds(halfWidth - 100, halfHeight - 30, 300, 40); + loginButton.setBounds(halfWidth - 100, halfHeight + 30, 300, 40); + skipButton.setBounds(halfWidth - 100, halfHeight + 80, 300, 40); +} + +void LoginComponent::skipButtonClicked() { + setVisible(false); } \ No newline at end of file diff --git a/src/components/TopMenuBarComponent.cpp b/src/components/TopMenuBarComponent.cpp index 970fe4e..322d024 100644 --- a/src/components/TopMenuBarComponent.cpp +++ b/src/components/TopMenuBarComponent.cpp @@ -1,136 +1,148 @@ #include "AccountComponent.h" +#include "ModalOverlayComponent.h" #include "PopupContentComponent.h" #include "SettingsComponent.h" #include "TopMenuBarComponent.h" - -#include "ModalOverlayComponent.h" #include "ResourceManager.h" - -TopMenuBarComponent::TopMenuBarComponent(juce::AudioDeviceManager& deviceManager, bool* isSoundMuted) -{ - this->isSoundMuted = isSoundMuted; - - - juce::Image settingsImage = ResourceManager::loadImage("resources/icons/settings.png"); - if (settingsImage.isValid()) { - settingsButton.setImages(true, true, true,settingsImage, 1.0f, {},settingsImage, 1.0f, {},settingsImage, 1.0f, {}); - settingsButton.setSize(settingsImage.getWidth(), settingsImage.getHeight()); - addAndMakeVisible(settingsButton); - } else { - DBG("Erreur : image settings.png introuvable ou invalide."); - } - - juce::Image accountImage = ResourceManager::loadImage("resources/icons/account.png"); - if (accountImage.isValid()) { - accountButton.setImages(true, true, true,accountImage, 1.0f, {}, accountImage, 1.0f, {},accountImage, 1.0f, {}); - accountButton.setSize(accountImage.getWidth(), accountImage.getHeight()); - addAndMakeVisible(accountButton); - } else { - DBG("Erreur : image account.png introuvable ou invalide."); - } - - juce::Image muteImage = ResourceManager::loadImage("resources/icons/unmute.png"); - if (muteImage.isValid()) { - muteButton.setImages(true, true, true, muteImage, 1.0f, {}, muteImage, 1.0f, {}, muteImage, 1.0f, {}); - muteButton.setSize(muteImage.getWidth(), muteImage.getHeight()); - addAndMakeVisible(muteButton); - } else { - DBG("Erreur : image mute.png introuvable ou invalide."); - } - - - #if !JUCE_IOS - settingsButton.onClick = [this, &deviceManager]() { openSettingsPopup(deviceManager); }; - #endif - accountButton.onClick = [this]() { openAccountPopup(); }; - muteButton.onClick = [this]() { toggleMute(); }; - - settingsButton.setBounds(0, 0, 100, 50); - accountButton.setBounds(0, 0, 100, 50); - muteButton.setBounds(0, 0, 100, 50); - flexBox.justifyContent = juce::FlexBox::JustifyContent::flexEnd; - flexBox.alignItems = juce::FlexBox::AlignItems::center; - flexBox.items.add( - juce::FlexItem(muteButton).withWidth(muteButton.getWidth()).withHeight(muteButton.getHeight())); - flexBox.items.add( - juce::FlexItem(settingsButton).withWidth(settingsButton.getWidth()).withHeight(settingsButton.getHeight())); - flexBox.items.add( - juce::FlexItem(accountButton).withWidth(accountButton.getWidth()).withHeight(accountButton.getHeight())); +TopMenuBarComponent::TopMenuBarComponent(AudioDeviceManager& deviceManager, + bool* isMuted) { + this->isSoundMuted = isMuted; + + Image settingsImage = ResourceManager::loadImage( + "resources/icons/settings.png"); + if (settingsImage.isValid()) { + settingsButton.setImages(true, true, true, settingsImage, 1.0f, {}, + settingsImage, 1.0f, {}, settingsImage, 1.0f, + {}); + settingsButton.setSize(settingsImage.getWidth(), + settingsImage.getHeight()); + addAndMakeVisible(settingsButton); + } else { + DBG("Erreur : image settings.png introuvable ou invalide."); + } + + Image accountImage = ResourceManager::loadImage( + "resources/icons/account.png"); + if (accountImage.isValid()) { + accountButton.setImages(true, true, true, accountImage, 1.0f, {}, + accountImage, 1.0f, {}, accountImage, 1.0f, {}); + accountButton.setSize(accountImage.getWidth(), + accountImage.getHeight()); + addAndMakeVisible(accountButton); + } else { + DBG("Erreur : image account.png introuvable ou invalide."); + } + + Image muteImage = ResourceManager::loadImage("resources/icons/unmute.png"); + if (muteImage.isValid()) { + muteButton.setImages(true, true, true, muteImage, 1.0f, {}, muteImage, + 1.0f, {}, muteImage, 1.0f, {}); + muteButton.setSize(muteImage.getWidth(), muteImage.getHeight()); + addAndMakeVisible(muteButton); + } else { + DBG("Erreur : image mute.png introuvable ou invalide."); + } + +#if !JUCE_IOS + settingsButton.onClick = [this, &deviceManager] { + openSettingsPopup(deviceManager); + }; +#endif + accountButton.onClick = [this] { openAccountPopup(); }; + muteButton.onClick = [this] { toggleMute(); }; + + flexBox.justifyContent = FlexBox::JustifyContent::flexEnd; + flexBox.alignItems = FlexBox::AlignItems::center; + flexBox.items.add( + FlexItem(muteButton).withWidth(buttonSize).withHeight(buttonSize). + withMargin({0, gap, 0, 0})); + flexBox.items.add( + FlexItem(settingsButton).withWidth(buttonSize).withHeight(buttonSize). + withMargin({0, gap, 0, 0})); + flexBox.items.add( + FlexItem(accountButton).withWidth(buttonSize).withHeight(buttonSize). + withMargin({0, gap, 0, 0})); } TopMenuBarComponent::~TopMenuBarComponent() = default; -void TopMenuBarComponent::paint(juce::Graphics& g) -{ +void TopMenuBarComponent::paint(Graphics& g) { + const ColourGradient gradient(Colours::black, 0, 0, + Colours::transparentBlack, 0, + static_cast(getHeight()), false); + g.setGradientFill(gradient); + g.fillAll(); + + const FontOptions font("Times New Roman", 24.0f, Font::bold | Font::italic); + g.setFont(font); + g.setColour(Colours::white); + const int topMargin = (getHeight() - 24) / 2; + + g.drawText("kAmp", gap, topMargin, 80, 24, Justification::left); } -void TopMenuBarComponent::resized() -{ - auto* mainWindow = getTopLevelComponent(); - if (mainWindow == nullptr) - return; - if (modalOverlay != nullptr) - { - modalOverlay->setBounds(mainWindow->getLocalBounds()); - } - if (settingsComponent != nullptr) - { - settingsComponent->setBounds(mainWindow->getLocalBounds()); - } - if (accountComponent != nullptr) - { - accountComponent->setBounds(mainWindow->getLocalBounds()); - } - flexBox.performLayout(getLocalBounds()); +void TopMenuBarComponent::resized() { + auto* mainWindow = getTopLevelComponent(); + if (mainWindow == nullptr) + return; + if (modalOverlay != nullptr) { + modalOverlay->setBounds(mainWindow->getLocalBounds()); + } + if (settingsComponent != nullptr) { + settingsComponent->setBounds(mainWindow->getLocalBounds()); + } + if (accountComponent != nullptr) { + accountComponent->setBounds(mainWindow->getLocalBounds()); + } + flexBox.performLayout(getLocalBounds()); } -void TopMenuBarComponent::openSettingsPopup(juce::AudioDeviceManager& deviceManager) -{ - settingsComponent = new SettingsComponent(deviceManager); - auto* mainWindow = getTopLevelComponent(); - if (mainWindow == nullptr) - return; +void TopMenuBarComponent::openSettingsPopup(AudioDeviceManager& deviceManager) { + settingsComponent = new SettingsComponent(deviceManager); + auto* mainWindow = getTopLevelComponent(); + if (mainWindow == nullptr) + return; - modalOverlay = new ModalOverlayComponent("Audio settings", settingsComponent); - mainWindow->addAndMakeVisible(modalOverlay); - modalOverlay->setBounds(mainWindow->getLocalBounds()); + modalOverlay = new ModalOverlayComponent("Audio settings", + settingsComponent); + mainWindow->addAndMakeVisible(modalOverlay); + modalOverlay->setBounds(mainWindow->getLocalBounds()); } -void TopMenuBarComponent::openAccountPopup() -{ - accountComponent = new AccountComponent(); - auto* mainWindow = getTopLevelComponent(); - if (mainWindow == nullptr) - return; +void TopMenuBarComponent::openAccountPopup() { + accountComponent = new AccountComponent(); + auto* mainWindow = getTopLevelComponent(); + if (mainWindow == nullptr) + return; - modalOverlay = new ModalOverlayComponent("Account", accountComponent); - mainWindow->addAndMakeVisible(modalOverlay); - modalOverlay->setBounds(mainWindow->getLocalBounds()); + modalOverlay = new ModalOverlayComponent("Account", accountComponent); + mainWindow->addAndMakeVisible(modalOverlay); + modalOverlay->setBounds(mainWindow->getLocalBounds()); } -void TopMenuBarComponent::toggleMute() -{ - if (*this->isSoundMuted) - { - juce::Image muteImage = ResourceManager::loadImage("resources/icons/unmute.png"); - if (muteImage.isValid()) { - muteButton.setImages(false, true, true, muteImage, 1.0f, {}, muteImage, 1.0f, {}, muteImage, 1.0f, {}); - addAndMakeVisible(muteButton); - } else { - DBG("Erreur : image mute.png introuvable ou invalide."); - } - } - else - { - juce::Image muteImage = ResourceManager::loadImage("resources/icons/mute.png"); - if (muteImage.isValid()) { - muteButton.setImages(false, true, true, muteImage, 1.0f, {}, muteImage, 1.0f, {}, muteImage, 1.0f, {}); - addAndMakeVisible(muteButton); - } else { - DBG("Erreur : image mute.png introuvable ou invalide."); - } - } - *(this->isSoundMuted) = !(*(this->isSoundMuted)); +void TopMenuBarComponent::toggleMute() { + if (*this->isSoundMuted) { + Image muteImage = ResourceManager::loadImage( + "resources/icons/unmute.png"); + if (muteImage.isValid()) { + muteButton.setImages(false, true, true, muteImage, 1.0f, {}, + muteImage, 1.0f, {}, muteImage, 1.0f, {}); + addAndMakeVisible(muteButton); + } else { + DBG("Erreur : image mute.png introuvable ou invalide."); + } + } else { + Image muteImage = + ResourceManager::loadImage("resources/icons/mute.png"); + if (muteImage.isValid()) { + muteButton.setImages(false, true, true, muteImage, 1.0f, {}, + muteImage, 1.0f, {}, muteImage, 1.0f, {}); + addAndMakeVisible(muteButton); + } else { + DBG("Erreur : image mute.png introuvable ou invalide."); + } + } + *(this->isSoundMuted) = !(*(this->isSoundMuted)); } diff --git a/src/components/effects/BasePedalComponent.cpp b/src/components/effects/BasePedalComponent.cpp index c72108a..9409b25 100644 --- a/src/components/effects/BasePedalComponent.cpp +++ b/src/components/effects/BasePedalComponent.cpp @@ -1,68 +1,68 @@ #include "BasePedalComponent.h" #include "ResourceManager.h" -BasePedalComponent::BasePedalComponent(AbstractEffect* effect) : EffectComponent(effect) -{ - isEnabled = effect->isEnabled; +BasePedalComponent::BasePedalComponent(AbstractEffect* effect) : + EffectComponent(effect) { + isEnabled = effect->isEnabled; } BasePedalComponent::~BasePedalComponent() = default; -void BasePedalComponent::paint(juce::Graphics &g) { - g.setColour(primaryColor); - g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), 15); +void BasePedalComponent::paint(Graphics& g) { + g.setColour(primaryColor); + g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), 15); } void BasePedalComponent::resized() { - pedalLayout.performLayout(getLocalBounds()); + pedalLayout.performLayout(getLocalBounds()); } void BasePedalComponent::onEnableButtonClicked() { - *isEnabled = !(*isEnabled); - enablePedalButton.setToggleState(*isEnabled, juce::dontSendNotification); - isEnabledIndicator->togglePower(*isEnabled); + *isEnabled = !(*isEnabled); + enablePedalButton.setToggleState(*isEnabled, dontSendNotification); + isEnabledIndicator->togglePower(*isEnabled); } void BasePedalComponent::initializePedal() { - isEnabledIndicator = new PedalPowerIndicatorComponent(*isEnabled); - pedalLabel = new juce::Label(); - pedalLabel->setText(getEffect()->effectName, juce::dontSendNotification); - pedalLabel->setJustificationType(juce::Justification::centred); - pedalLabel->setFont(juce::Font(30.0f, juce::Font::bold)); + isEnabledIndicator = new PedalPowerIndicatorComponent(*isEnabled); + pedalLabel = new Label(); + pedalLabel->setText(getEffect()->effectName, dontSendNotification); + pedalLabel->setJustificationType(Justification::centred); + pedalLabel->setFont(FontOptions(30.0f, Font::bold)); - juce::Image powerImage = ResourceManager::loadImage("resources/icons/power.png"); - if (powerImage.isValid()) { - enablePedalButton.setImages(true, true, true, - powerImage, 1.0f, {}, - powerImage, 1.0f, {}, - powerImage, 1.0f, {}); - enablePedalButton.onClick = [this] { - this->onEnableButtonClicked(); - }; - addAndMakeVisible(enablePedalButton); - } else { - DBG("Erreur : image power.png introuvable ou invalide."); - } + Image powerImage = ResourceManager::loadImage("resources/icons/power.png"); + if (powerImage.isValid()) { + enablePedalButton.setImages(true, true, true, + powerImage, 1.0f, {}, + powerImage, 1.0f, {}, + powerImage, 1.0f, {}); + enablePedalButton.onClick = [this] { + this->onEnableButtonClicked(); + }; + addAndMakeVisible(enablePedalButton); + } else { + DBG("Erreur : image power.png introuvable ou invalide."); + } - addAndMakeVisible(*pedalLabel); - addAndMakeVisible(*isEnabledIndicator); + addAndMakeVisible(*pedalLabel); + addAndMakeVisible(*isEnabledIndicator); - using Track = juce::Grid::TrackInfo; - using Fr = juce::Grid::Fr; - pedalLayout.templateRows = { - Track (Fr (2)), - Track (Fr (1)), - Track (Fr (1)), - Track (Fr (1)) - }; - pedalLayout.templateColumns = { - Track (Fr (1)) - }; + using Track = Grid::TrackInfo; + using Fr = Grid::Fr; + pedalLayout.templateRows = { + Track(Fr(2)), + Track(Fr(1)), + Track(Fr(1)), + Track(Fr(1)) + }; + pedalLayout.templateColumns = { + Track(Fr(1)) + }; - pedalLayout.items = { - juce::GridItem(*settingsLayout), - juce::GridItem(enablePedalButton), - juce::GridItem(*isEnabledIndicator), - juce::GridItem(*pedalLabel), - }; + pedalLayout.items = { + GridItem(*settingsLayout), + GridItem(enablePedalButton), + GridItem(*isEnabledIndicator), + GridItem(*pedalLabel), + }; } \ No newline at end of file diff --git a/src/components/effects/DelayEffectComponent.cpp b/src/components/effects/DelayEffectComponent.cpp index a38ade3..744780c 100644 --- a/src/components/effects/DelayEffectComponent.cpp +++ b/src/components/effects/DelayEffectComponent.cpp @@ -1,61 +1,71 @@ #include "DelayEffectComponent.h" -DelayEffectComponent::DelayEffectComponent() : BasePedalComponent(new DelayEffect()) {} - -DelayEffectComponent::DelayEffectComponent(AbstractEffect* effect) : BasePedalComponent(effect) { - if (DelayEffect* delayEffect = dynamic_cast(effect)) { - primaryColor = juce::Colours::mediumblue; - using Track = juce::Grid::TrackInfo; - using Fr = juce::Grid::Fr; - grid.templateRows = { Track (Fr (1)), Track (Fr (3)) }; - grid.templateColumns = { Track (Fr (1)), Track (Fr (1)) }; - grid.items = { - juce::GridItem(rateLabel), - juce::GridItem(delayLabel), - juce::GridItem(rateSlider), - juce::GridItem(delaySlider), - }; - rateSlider.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); - rateSlider.setTextBoxStyle(juce::Slider::TextBoxBelow,false, 100, 20); - rateSlider.setColour(juce::Slider::textBoxOutlineColourId, juce::Colours::transparentWhite); - rateSlider.setTextValueSuffix("%"); - rateSlider.setTitle("Rate"); - rateSlider.setRange(0.0, 100.0, 1); - rateSlider.setValue(50.0); - rateSlider.onValueChange = [this, delayEffect] { delayEffect->setRate(rateSlider.getValue()); }; - - rateLabel.setText("Rate", juce::dontSendNotification); - rateLabel.setJustificationType(Justification::centred); - rateLabel.attachToComponent(&rateSlider, false); - - delaySlider.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); - delaySlider.setTextValueSuffix("ms"); - delaySlider.setTitle("Delay"); - delaySlider.setTextBoxStyle(juce::Slider::TextBoxBelow,false, 100, 20); - delaySlider.setColour(juce::Slider::textBoxOutlineColourId, juce::Colours::transparentWhite); - delaySlider.setRange(0.0, 3000.0, 10); - delaySlider.setValue(500.0); - delaySlider.onValueChange = [this, delayEffect] { delayEffect->setDelay(delaySlider.getValue()); }; - - delayLabel.setText("Delay", juce::dontSendNotification); - delayLabel.setJustificationType(Justification::centred); - delayLabel.attachToComponent(&delaySlider, false); - - rateSlider.setBounds(0, 0, 200, 200); - delaySlider.setBounds(300, 0, 200, 200); - rateLabel.setBounds(rateSlider.getX(), rateSlider.getY() + 20, rateSlider.getWidth(), 20); - delayLabel.setBounds(delaySlider.getX(), delaySlider.getY() + 20, delaySlider.getWidth(), 20); - - settingsLayout = new PedalSettingsLayoutComponent(&grid); - - addAndMakeVisible(rateSlider); - addAndMakeVisible(rateLabel); - addAndMakeVisible(delaySlider); - addAndMakeVisible(delayLabel); - - this->initializePedal(); - setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); - } +DelayEffectComponent::DelayEffectComponent() : BasePedalComponent( + new DelayEffect()) {} + +DelayEffectComponent::DelayEffectComponent(AbstractEffect* effect) : + BasePedalComponent(effect) { + if (auto delayEffect = dynamic_cast(effect)) { + primaryColor = Colours::mediumblue; + using Track = Grid::TrackInfo; + using Fr = Grid::Fr; + grid.templateRows = {Track(Fr(1)), Track(Fr(3))}; + grid.templateColumns = {Track(Fr(1)), Track(Fr(1))}; + grid.items = { + GridItem(rateLabel), + GridItem(delayLabel), + GridItem(rateSlider), + GridItem(delaySlider), + }; + rateSlider.setSliderStyle(Slider::SliderStyle::RotaryVerticalDrag); + rateSlider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20); + rateSlider.setColour(Slider::textBoxOutlineColourId, + Colours::transparentWhite); + rateSlider.setTextValueSuffix("%"); + rateSlider.setTitle("Rate"); + rateSlider.setRange(0.0, 100.0, 1); + rateSlider.setValue(50.0); + rateSlider.onValueChange = [this, delayEffect] { + delayEffect->setRate(rateSlider.getValue()); + }; + + rateLabel.setText("Rate", dontSendNotification); + rateLabel.setJustificationType(Justification::centred); + rateLabel.attachToComponent(&rateSlider, false); + + delaySlider.setSliderStyle(Slider::SliderStyle::RotaryVerticalDrag); + delaySlider.setTextValueSuffix("ms"); + delaySlider.setTitle("Delay"); + delaySlider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20); + delaySlider.setColour(Slider::textBoxOutlineColourId, + Colours::transparentWhite); + delaySlider.setRange(0.0, 3000.0, 10); + delaySlider.setValue(500.0); + delaySlider.onValueChange = [this, delayEffect] { + delayEffect->setDelay(delaySlider.getValue()); + }; + + delayLabel.setText("Delay", dontSendNotification); + delayLabel.setJustificationType(Justification::centred); + delayLabel.attachToComponent(&delaySlider, false); + + rateSlider.setBounds(0, 0, 200, 200); + delaySlider.setBounds(300, 0, 200, 200); + rateLabel.setBounds(rateSlider.getX(), rateSlider.getY() + 20, + rateSlider.getWidth(), 20); + delayLabel.setBounds(delaySlider.getX(), delaySlider.getY() + 20, + delaySlider.getWidth(), 20); + + settingsLayout = new PedalSettingsLayoutComponent(&grid); + + addAndMakeVisible(rateSlider); + addAndMakeVisible(rateLabel); + addAndMakeVisible(delaySlider); + addAndMakeVisible(delayLabel); + + this->initializePedal(); + setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } } DelayEffectComponent::~DelayEffectComponent() = default; \ No newline at end of file diff --git a/src/utils/ModalOverlayComponent.cpp b/src/utils/ModalOverlayComponent.cpp index c4c7302..936a1a5 100644 --- a/src/utils/ModalOverlayComponent.cpp +++ b/src/utils/ModalOverlayComponent.cpp @@ -15,13 +15,13 @@ ModalOverlayComponent::ModalOverlayComponent(std::string viewName, juce::Compone viewNameLabel.setFont(juce::FontOptions(32.0f, juce::Font::bold)); viewNameLabel.setJustificationType(juce::Justification::centred); - juce::Image closeImage = ResourceManager::loadImage("resources/icons/close.png"); + juce::Image closeImage = ResourceManager::loadImage("resources/icons/xmark.png"); if (closeImage.isValid()) { closeOverlayButton.setImages(true, true, true,closeImage, 1.0f, {}, closeImage, 1.0f, {},closeImage, 1.0f, {}); closeOverlayButton.setSize(closeImage.getWidth(), closeImage.getHeight()); addAndMakeVisible(closeOverlayButton); } else { - DBG("Erreur : image close.png introuvable ou invalide."); + DBG("Erreur : image xmark.png introuvable ou invalide."); } closeOverlayButton.onClick = [this]() { this->onCloseOverlayButtonClicked(); }; } diff --git a/src/utils/ToggleButtonComponent.cpp b/src/utils/ToggleButtonComponent.cpp index dde3a5f..07b3baf 100644 --- a/src/utils/ToggleButtonComponent.cpp +++ b/src/utils/ToggleButtonComponent.cpp @@ -1,25 +1,42 @@ #include "ToggleButtonComponent.h" -ToggleButtonComponent::ToggleButtonComponent() -{ - setMouseCursor(juce::MouseCursor::PointingHandCursor); - setSize(100, 50); +namespace { +constexpr int buttonWidth = 100; +constexpr int buttonHeight = 50; +constexpr float toggleWidth = 50.0f; +constexpr float toggleHeight = 25.0f; +constexpr float toggleRadius = 10.0f; +constexpr float ellipseDiameter = 19.0f; +constexpr float ellipseYOffset = 3.0f; +constexpr float ellipseXOffsetOn = 0.0f; +constexpr float ellipseXOffsetOff = -22.0f; +} + +ToggleButtonComponent::ToggleButtonComponent() { + setMouseCursor(MouseCursor::PointingHandCursor); + setSize(buttonWidth, buttonHeight); } ToggleButtonComponent::~ToggleButtonComponent() = default; -void ToggleButtonComponent::paint(juce::Graphics& g) -{ - g.setColour(juce::Colours::darkgrey); - g.fillRoundedRectangle(getWidth() / 2 - 25, getHeight() / 2 - 12.5, 50, 25, 10.0f); - if (getToggleState()) - { - g.setColour(juce::Colours::green); - g.fillEllipse(getWidth() / 2, (getHeight() / 2 - 12.5) + 3, 19, 19); - } - else - { - g.setColour(juce::Colours::red); - g.fillEllipse(getWidth() / 2 - 22, (getHeight() / 2 - 12.5) + 3, 19, 19); - } +void ToggleButtonComponent::paint(Graphics& g) { + const auto centerX = static_cast(getWidth()) / 2.0f; + const auto centerY = static_cast(getHeight()) / 2.0f; + + g.setColour(Colours::darkgrey); + g.fillRoundedRectangle(centerX - toggleWidth / 2.0f, + centerY - toggleHeight / 2.0f, + toggleWidth, toggleHeight, toggleRadius); + + if (getToggleState()) { + g.setColour(Colours::green); + g.fillEllipse(centerX + ellipseXOffsetOn, + centerY - toggleHeight / 2.0f + ellipseYOffset, + ellipseDiameter, ellipseDiameter); + } else { + g.setColour(Colours::red); + g.fillEllipse(centerX + ellipseXOffsetOff, + centerY - toggleHeight / 2.0f + ellipseYOffset, + ellipseDiameter, ellipseDiameter); + } } \ No newline at end of file