Skip to content

Commit

Permalink
feat: add figure combobox
Browse files Browse the repository at this point in the history
  • Loading branch information
zsliu98 committed Jul 22, 2024
1 parent f54e116 commit bbda8cc
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 6 deletions.
2 changes: 2 additions & 0 deletions source/PluginEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "PluginProcessor.h"
#include "BinaryData.h"

#include "gui/gui.hpp"

//==============================================================================
class PluginEditor : public juce::AudioProcessorEditor {
public:
Expand Down
2 changes: 1 addition & 1 deletion source/gui/combobox/click_combobox/click_combobox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace zlInterface {
ClickCombobox::ClickCombobox(const juce::String &labelText, const juce::StringArray &choices, UIBase &base)
: compactBox("", choices, base),
: compactBox(choices, base),
label("", juce::DrawableButton::ButtonStyle::ImageFitted),
labelLAF(base, labelText) {
addAndMakeVisible(compactBox);
Expand Down
1 change: 1 addition & 0 deletions source/gui/combobox/combobox.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define ZLINTERFACE_COMBOBOX_H

#include "compact_combobox/compact_combobox.hpp"
#include "compact_figure_combobox/compact_figure_combobox.hpp"
#include "left_right_combobox/left_right_combobox.hpp"
#include "click_combobox/click_combobox.hpp"

Expand Down
7 changes: 3 additions & 4 deletions source/gui/combobox/compact_combobox/compact_combobox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
#include "compact_combobox.hpp"

namespace zlInterface {
CompactCombobox::CompactCombobox(const juce::String &labelText, const juce::StringArray &choices,
UIBase &base) : uiBase(base), boxLookAndFeel(base),
animator{} {
juce::ignoreUnused(labelText);
CompactCombobox::CompactCombobox(const juce::StringArray &choices,
UIBase &base)
: uiBase(base), boxLookAndFeel(base), animator{} {
comboBox.addItemList(choices, 1);
comboBox.setScrollWheelEnabled(false);
comboBox.setInterceptsMouseClicks(false, false);
Expand Down
2 changes: 1 addition & 1 deletion source/gui/combobox/compact_combobox/compact_combobox.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
namespace zlInterface {
class CompactCombobox final : public juce::Component {
public:
CompactCombobox(const juce::String &labelText, const juce::StringArray &choices, UIBase &base);
CompactCombobox(const juce::StringArray &choices, UIBase &base);

~CompactCombobox() override;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (C) 2024 - zsliu98
// This file is part of ZLEqualizer
//
// ZLEqualizer is free software: you can redistribute it and/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.
//
// ZLEqualizer 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 ZLEqualizer. If not, see <https://www.gnu.org/licenses/>.

#include "compact_figure_combobox.hpp"

namespace zlInterface {
CompactFigureCombobox::CompactFigureCombobox(const juce::StringArray &choices,
const std::vector<juce::Drawable *> &icons,
UIBase &base)
: uiBase(base), boxLookAndFeel(base), animator{} {
const auto menu = comboBox.getRootMenu();
for (size_t i = 0; i < icons.size(); ++i) {
menu->addItem(static_cast<int>(i + 1), "", true, false, icons[i]->createCopy());
}
boxLookAndFeel.setImages(icons);

comboBox.setScrollWheelEnabled(false);
comboBox.setInterceptsMouseClicks(false, false);
comboBox.setLookAndFeel(&boxLookAndFeel);
addAndMakeVisible(comboBox);

setEditable(true);
}


CompactFigureCombobox::~CompactFigureCombobox() {
animator.cancelAllAnimations(false);
comboBox.setLookAndFeel(nullptr);
}

void CompactFigureCombobox::resized() {
auto bound = getLocalBounds().toFloat();
bound = bound.withSizeKeepingCentre(bound.getWidth(), juce::jmin(bound.getHeight(),
uiBase.getFontSize() * 2.f));
comboBox.setBounds(bound.toNearestInt());
}

void CompactFigureCombobox::mouseUp(const juce::MouseEvent &event) {
comboBox.mouseUp(event);
}

void CompactFigureCombobox::mouseDown(const juce::MouseEvent &event) {
comboBox.mouseDown(event);
}

void CompactFigureCombobox::mouseDrag(const juce::MouseEvent &event) {
comboBox.mouseDrag(event);
}

void CompactFigureCombobox::mouseEnter(const juce::MouseEvent &event) {
comboBox.mouseEnter(event);
animator.cancelAnimation(animationId, false);
if (animator.getAnimation(animationId) != nullptr)
return;
auto effect{
friz::makeAnimation<friz::Parametric, 1>(
animationId, {boxLookAndFeel.getBoxAlpha()}, {1.f}, 1000, friz::Parametric::kEaseInQuad)
};
effect->updateFn = [this](int, const auto &vals) {
boxLookAndFeel.setBoxAlpha(vals[0]);
comboBox.repaint();
};
animator.addAnimation(std::move(effect));
}

void CompactFigureCombobox::mouseExit(const juce::MouseEvent &event) {
comboBox.mouseExit(event);
animator.cancelAnimation(animationId, false);
if (animator.getAnimation(animationId) != nullptr)
return;
auto effect{
friz::makeAnimation<friz::Parametric, 1>(
animationId, {boxLookAndFeel.getBoxAlpha()}, {0.f}, 1000, friz::Parametric::kEaseOutQuad)
};
effect->updateFn = [this](int, const auto &vals) {
boxLookAndFeel.setBoxAlpha(vals[0]);
comboBox.repaint();
};
animator.addAnimation(std::move(effect));
}

void CompactFigureCombobox::mouseMove(const juce::MouseEvent &event) {
comboBox.mouseMove(event);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (C) 2024 - zsliu98
// This file is part of ZLEqualizer
//
// ZLEqualizer is free software: you can redistribute it and/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.
//
// ZLEqualizer 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 ZLEqualizer. If not, see <https://www.gnu.org/licenses/>.

#ifndef COMPACT_FIGURE_COMBOBOX_H
#define COMPACT_FIGURE_COMBOBOX_H

#include <friz/friz.h>

#include "compact_figure_combobox_look_and_feel.hpp"

namespace zlInterface {
class CompactFigureCombobox final : public juce::Component {
public:
CompactFigureCombobox(const juce::StringArray &choices,
const std::vector<juce::Drawable *> &icons,
UIBase &base);

~CompactFigureCombobox() override;

void resized() override;

void mouseUp(const juce::MouseEvent &event) override;

void mouseDown(const juce::MouseEvent &event) override;

void mouseDrag(const juce::MouseEvent &event) override;

void mouseEnter(const juce::MouseEvent &event) override;

void mouseExit(const juce::MouseEvent &event) override;

void mouseMove(const juce::MouseEvent &event) override;

inline void setEditable(const bool x) {
boxLookAndFeel.setEditable(x);
setInterceptsMouseClicks(x, false);
}

inline juce::ComboBox &getBox() { return comboBox; }

inline CompactFigureComboboxLookAndFeel &getLAF() { return boxLookAndFeel; }

private:
zlInterface::UIBase &uiBase;
CompactFigureComboboxLookAndFeel boxLookAndFeel;
juce::ComboBox comboBox;

friz::Animator animator;
static constexpr int animationId = 1;
};
}


#endif //COMPACT_FIGURE_COMBOBOX_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (C) 2024 - zsliu98
// This file is part of ZLEqualizer
//
// ZLEqualizer is free software: you can redistribute it and/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.
//
// ZLEqualizer 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 ZLEqualizer. If not, see <https://www.gnu.org/licenses/>.

#ifndef COMPACT_FIGURE_COMBOBOX_LOOK_AND_FEEL_H
#define COMPACT_FIGURE_COMBOBOX_LOOK_AND_FEEL_H

#include <juce_gui_basics/juce_gui_basics.h>

#include "../../interface_definitions.hpp"

namespace zlInterface {
class CompactFigureComboboxLookAndFeel : public juce::LookAndFeel_V4 {
public:
// rounded menu box
explicit CompactFigureComboboxLookAndFeel(UIBase &base) : uiBase(base) {
setColour(juce::PopupMenu::backgroundColourId, uiBase.getBackgroundInactiveColor());
}

void drawComboBox(juce::Graphics &g, int width, int height, bool isButtonDown, int, int, int, int,
juce::ComboBox &box) override {
juce::ignoreUnused(width, height);
const auto boxBounds = juce::Rectangle<float>(0.f, 0.f,
static_cast<float>(width),
static_cast<float>(height));
const auto cornerSize = uiBase.getFontSize() * 0.375f;
if (isButtonDown || box.isPopupActive()) {
g.setColour(uiBase.getTextInactiveColor());
g.fillRoundedRectangle(boxBounds, cornerSize);
} else {
uiBase.fillRoundedInnerShadowRectangle(g, boxBounds, cornerSize,
{
.blurRadius = 0.45f, .flip = true,
.mainColour = uiBase.getBackgroundColor().
withMultipliedAlpha(
juce::jlimit(.25f, .5f, boxAlpha.load())),
.darkShadowColor = uiBase.getDarkShadowColor().
withMultipliedAlpha(boxAlpha.load()),
.brightShadowColor = uiBase.getBrightShadowColor().
withMultipliedAlpha(boxAlpha.load()),
.changeMain = true, .changeDark = true, .changeBright = true
});
}
const auto imageId = static_cast<size_t>(box.getSelectedItemIndex());
if (imageId < images.size() && images[imageId] != nullptr) {
const auto tempDrawable = images[imageId]->createCopy();
tempDrawable->replaceColour(juce::Colour(0, 0, 0), uiBase.getTextColor());
const auto imageBound = boxBounds.withSizeKeepingCentre(boxBounds.getWidth(), uiBase.getFontSize() * fontScale);
const auto opacity = editable.load() ? 1.f : .5f;
tempDrawable->drawWithin(g, imageBound, juce::RectanglePlacement::Flags::centred, opacity);
}
}

void positionComboBoxText(juce::ComboBox &box, juce::Label &label) override {
juce::ignoreUnused(box);
label.setBounds({0, 0, 0, 0});
}

void drawPopupMenuBackground(juce::Graphics &g, int width, int height) override {
const auto cornerSize = uiBase.getFontSize() * 0.375f;
const auto boxBounds = juce::Rectangle<float>(0, 0, static_cast<float>(width),
static_cast<float>(height));
uiBase.fillRoundedInnerShadowRectangle(g, boxBounds, cornerSize, {.blurRadius = 0.45f, .flip = true});
}

void getIdealPopupMenuItemSize(const juce::String &text, const bool isSeparator, int standardMenuItemHeight,
int &idealWidth, int &idealHeight) override {
juce::ignoreUnused(text, isSeparator, standardMenuItemHeight);
idealWidth = static_cast<int>(0);
idealHeight = static_cast<int>(uiBase.getFontSize() * fontScale * 1.2f);
}

void drawPopupMenuItem(juce::Graphics &g, const juce::Rectangle<int> &area,
const bool isSeparator, const bool isActive,
const bool isHighlighted, const bool isTicked, const bool hasSubMenu,
const juce::String &text,
const juce::String &shortcutKeyText, const juce::Drawable *icon,
const juce::Colour *const textColourToUse) override {
juce::ignoreUnused(text, isSeparator, hasSubMenu, shortcutKeyText, textColourToUse);
float opacity = 1.f;
if ((isHighlighted || isTicked) && isActive && editable) {
opacity = 1.f;
} else if (!isActive) {
opacity = .5f * .25f;
} else {
opacity = .5f;
}
const auto imageBound = area.toFloat().withSizeKeepingCentre(
static_cast<float>(area.getWidth()), uiBase.getFontSize() * fontScale);
const auto tempDrawable = icon->createCopy();
tempDrawable->replaceColour(juce::Colour(0, 0, 0), uiBase.getTextColor());
tempDrawable->drawWithin(g, imageBound, juce::RectanglePlacement::Flags::centred, opacity);
}

int getMenuWindowFlags() override {
return 1;
}

int getPopupMenuBorderSize() override {
return juce::roundToInt(uiBase.getFontSize() * 0.125f);
}

inline void setEditable(const bool f) { editable.store(f); }

inline void setBoxAlpha(const float x) { boxAlpha.store(x); }

inline void setFontScale(const float x) { fontScale.store(x); }

inline float getBoxAlpha() const { return boxAlpha.load(); }

inline void setImages(const std::vector<juce::Drawable*>& x) { images = x; }

private:
std::atomic<bool> editable = true;
std::atomic<float> boxAlpha, fontScale = 1.5f;

UIBase &uiBase;
std::vector<juce::Drawable*> images;
};
}

#endif //COMPACT_FIGURE_COMBOBOX_LOOK_AND_FEEL_H
13 changes: 13 additions & 0 deletions source/panel/main_panel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (C) 2024 - zsliu98
// This file is part of ZLSplitter
//
// ZLSplitter is free software: you can redistribute it and/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.
//
// ZLSplitter 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 ZLSplitter. If not, see <https://www.gnu.org/licenses/>.

#include "main_panel.hpp"

namespace zlPanel {
} // zlPanel
21 changes: 21 additions & 0 deletions source/panel/main_panel.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (C) 2024 - zsliu98
// This file is part of ZLSplitter
//
// ZLSplitter is free software: you can redistribute it and/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.
//
// ZLSplitter 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 ZLSplitter. If not, see <https://www.gnu.org/licenses/>.

#ifndef MAIN_PANEL_HPP
#define MAIN_PANEL_HPP

namespace zlPanel {

class MainPanel {

};

} // zlPanel

#endif //MAIN_PANEL_HPP
Loading

0 comments on commit bbda8cc

Please sign in to comment.