commit fdf84b0d27d706b2b2bd6b3a01a797ea3e2fe284
parent ef5f6a04af4bd35de03a5565a69b75b2662b2fcf
Author: Matt Demanett <matt@demanett.net>
Date: Sun, 9 Aug 2020 00:11:05 -0400
Add context-menu items to set the default skins, and rename menu item to "Panel".
Diffstat:
6 files changed, 147 insertions(+), 26 deletions(-)
diff --git a/src/menu.cpp b/src/menu.cpp
@@ -5,6 +5,27 @@ using namespace bogaudio;
#define SUBMENUS 1
+void OptionsMenuItem::addItem(const OptionMenuItem& item) {
+ _items.push_back(item);
+}
+
+void OptionsMenuItem::addSpacer() {
+ _items.push_back(SpacerOptionMenuItem());
+}
+
+Menu* OptionsMenuItem::createChildMenu() {
+ Menu* menu = new Menu;
+ for (const OptionMenuItem& item : _items) {
+ if (item.text == "<spacer>") {
+ menu->addChild(new MenuLabel());
+ }
+ else {
+ menu->addChild(new OptionMenuItem(item));
+ }
+ }
+ return menu;
+}
+
void OptionsMenuItem::addToMenu(OptionsMenuItem* item, Menu* menu) {
// one way or another, this will cause item to eventually be deleted; call only one per item.
#ifdef SUBMENUS
@@ -14,9 +35,14 @@ void OptionsMenuItem::addToMenu(OptionsMenuItem* item, Menu* menu) {
label += ":";
menu->addChild(createMenuLabel(label.c_str()));
for (const OptionMenuItem& omi : item->_items) {
- auto nomi = new OptionMenuItem(omi);
- nomi->text = std::string("\t") + nomi->text;
- menu->addChild(nomi);
+ if (omi.text == "<spacer>") {
+ menu->addChild(new MenuLabel());
+ }
+ else {
+ auto nomi = new OptionMenuItem(omi);
+ nomi->text = std::string("\t") + nomi->text;
+ menu->addChild(nomi);
+ }
}
delete item;
#endif
diff --git a/src/menu.hpp b/src/menu.hpp
@@ -34,6 +34,12 @@ struct BoolOptionMenuItem : OptionMenuItem {
{}
};
+struct SpacerOptionMenuItem : OptionMenuItem {
+ SpacerOptionMenuItem()
+ : OptionMenuItem("<spacer>", []() { return false; }, []() {})
+ {}
+};
+
struct OptionsMenuItem : MenuItem {
std::vector<OptionMenuItem> _items;
@@ -42,18 +48,9 @@ struct OptionsMenuItem : MenuItem {
this->rightText = "▸";
}
- void addItem(const OptionMenuItem& item) {
- _items.push_back(item);
- }
-
- Menu* createChildMenu() override {
- Menu* menu = new Menu;
- for (const OptionMenuItem& item : _items) {
- menu->addChild(new OptionMenuItem(item));
- }
- return menu;
- }
-
+ void addItem(const OptionMenuItem& item);
+ void addSpacer();
+ Menu* createChildMenu() override;
static void addToMenu(OptionsMenuItem* item, Menu* menu);
};
diff --git a/src/module.cpp b/src/module.cpp
@@ -1,7 +1,6 @@
#include "module.hpp"
#include "bogaudio.hpp"
-#include "skins.hpp"
using namespace bogaudio;
@@ -101,6 +100,14 @@ void BGModule::addSkinChangeListener(SkinChangeListener* listener) {
}
+BGModuleWidget::BGModuleWidget() {
+ Skins::skins().registerDefaultSkinChangeListener(this);
+}
+
+BGModuleWidget::~BGModuleWidget() {
+ Skins::skins().deregisterDefaultSkinChangeListener(this);
+}
+
void BGModuleWidget::addParam(ParamWidget* param) {
ModuleWidget::addParam(param);
if (module) {
@@ -141,15 +148,31 @@ void BGModuleWidget::appendContextMenu(Menu* menu) {
auto m = dynamic_cast<BGModule*>(module);
assert(m);
if (m->_skinnable) {
- auto skins = Skins::skins().available();
- if (skins.size() > 0) {
+ Skins* skins = &Skins::skins();
+ if (skins->available().size() > 0) {
// menu->addChild(new MenuLabel());
- OptionsMenuItem* s = new OptionsMenuItem("Skin");
+ OptionsMenuItem* s = new OptionsMenuItem("Panel");
+
s->addItem(OptionMenuItem("Default", [m]() { return m->_skin == "default"; }, [m]() { m->setSkin("default"); }));
- for (auto skin : skins) {
+ for (auto skin : skins->available()) {
std::string key = skin.key;
- s->addItem(OptionMenuItem(skin.display.c_str(), [m, key]() { return m->_skin == key; }, [m, key]() { m->setSkin(key); }));
+ s->addItem(OptionMenuItem(
+ skin.display.c_str(),
+ [m, key]() { return m->_skin == key; },
+ [m, key]() { m->setSkin(key); }
+ ));
}
+
+ s->addSpacer();
+ for (auto skin : skins->available()) {
+ std::string key = skin.key;
+ s->addItem(OptionMenuItem(
+ (std::string("Default to ") + skin.display).c_str(),
+ [key, skins]() { return skins->defaultKey() == key; },
+ [key, skins]() { skins->setDefaultSkin(key); }
+ ));
+ }
+
OptionsMenuItem::addToMenu(s, menu);
}
}
@@ -161,6 +184,19 @@ void BGModuleWidget::skinChanged(const std::string& skin) {
updatePanel();
}
+void BGModuleWidget::defaultSkinChanged(const std::string& skin) {
+ if (module) {
+ auto m = dynamic_cast<BGModule*>(module);
+ assert(m);
+ if (m->_skin == "default") {
+ m->setSkin("default");
+ }
+ }
+ else {
+ updatePanel();
+ }
+}
+
void BGModuleWidget::setPanel(Vec size, std::string slug, bool skinnable) {
_size = size;
_slug = slug;
diff --git a/src/module.hpp b/src/module.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "rack.hpp"
+#include "skins.hpp"
#include <string>
#include <vector>
@@ -60,12 +61,15 @@ struct BGModule : Module {
void addSkinChangeListener(SkinChangeListener* listener);
};
-struct BGModuleWidget : ModuleWidget, SkinChangeListener {
+struct BGModuleWidget : ModuleWidget, SkinChangeListener, DefaultSkinChangeListener {
bool _skinnable = true;
SvgPanel* _panel = NULL;
Vec _size;
std::string _slug;
+ BGModuleWidget();
+ virtual ~BGModuleWidget();
+
void appendContextMenu(Menu* menu) override;
void addParam(ParamWidget* param);
void addInput(PortWidget* input);
@@ -74,6 +78,7 @@ struct BGModuleWidget : ModuleWidget, SkinChangeListener {
virtual void contextMenu(Menu* menu) {}
void skinChanged(const std::string& skin) override;
+ void defaultSkinChanged(const std::string& skin) override;
void setPanel(Vec size, const std::string slug, bool skinnable = true);
void updatePanel();
void createScrews();
diff --git a/src/skins.cpp b/src/skins.cpp
@@ -2,10 +2,12 @@
#include "skins.hpp"
#include "bogaudio.hpp"
#include <unistd.h>
+#include <fstream>
+#include <cstdio>
-const Skins& Skins::skins() {
+Skins& Skins::skins() {
static Skins instance;
- std::lock_guard<std::mutex> lock(instance._lock);
+ std::lock_guard<std::mutex> lock(instance._instanceLock);
if (!instance._loaded) {
instance.loadSkins();
instance.loadCssValues();
@@ -95,6 +97,49 @@ NVGcolor Skins::cssColorToNVGColor(const char* color, const NVGcolor& ifError) {
return ifError;
}
+void Skins::setDefaultSkin(std::string skinKey) {
+ if (skinKey == "default") {
+ skinKey = "light";
+ }
+ std::string path = rack::asset::user("Bogaudio.json");
+ std::string error;
+ if (!validKey(skinKey)) {
+ error = "invalid key: " + skinKey;
+ }
+ else {
+ std::ofstream f(path);
+ f << "{\n \"skins\": {\n \"default\": \"";
+ f << skinKey;
+ f << "\"\n }\n}\n";
+ if (!f) {
+ error = "error writing \"" + path + "\": " + strerror(errno);
+ }
+ }
+
+ if (error.size() > 0) {
+ WARN("Bogaudio: setting default skin: %s\n", error.c_str());
+ }
+ else {
+ _default = skinKey;
+ INFO("Bogaudio: skin information written to %s\n", path.c_str());
+
+ std::lock_guard<std::mutex> lock(_defaultSkinListenersLock);
+ for (auto listener : _defaultSkinListeners) {
+ listener->defaultSkinChanged(_default);
+ }
+ }
+}
+
+void Skins::registerDefaultSkinChangeListener(DefaultSkinChangeListener* listener) {
+ std::lock_guard<std::mutex> lock(_defaultSkinListenersLock);
+ _defaultSkinListeners.insert(listener);
+}
+
+void Skins::deregisterDefaultSkinChangeListener(DefaultSkinChangeListener* listener) {
+ std::lock_guard<std::mutex> lock(_defaultSkinListenersLock);
+ _defaultSkinListeners.erase(listener);
+}
+
void Skins::loadSkins() {
_available.push_back(Skin("light", "Light"));
_available.push_back(Skin("dark", "Dark"));
diff --git a/src/skins.hpp b/src/skins.hpp
@@ -4,8 +4,13 @@
#include <mutex>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
+struct DefaultSkinChangeListener {
+ virtual void defaultSkinChanged(const std::string& skin) = 0;
+};
+
struct Skin {
std::string key;
std::string display;
@@ -17,24 +22,31 @@ class Skins {
private:
typedef std::unordered_map<std::string, std::string> css_values_map;
typedef std::unordered_map<std::string, css_values_map> skin_css_values_map;
+ typedef std::unordered_set<DefaultSkinChangeListener*> default_skin_listeners_set;
std::vector<Skin> _available;
std::string _default;
skin_css_values_map _skinCssValues;
+ default_skin_listeners_set _defaultSkinListeners;
+ std::mutex _defaultSkinListenersLock;
bool _loaded = false;
- std::mutex _lock;
+ std::mutex _instanceLock;
public:
Skins() {}
Skins(const Skins&) = delete;
void operator=(const Skins&) = delete;
- static const Skins& skins();
+ static Skins& skins();
inline const std::vector<Skin>& available() const { return _available; }
inline const std::string& defaultKey() const { return _default; }
bool validKey(const std::string& key) const;
const char* skinCssValue(const std::string& skinKey, const std::string& valueKey) const;
static NVGcolor cssColorToNVGColor(const char* color, const NVGcolor& ifError);
+ void setDefaultSkin(std::string skinKey);
+ void registerDefaultSkinChangeListener(DefaultSkinChangeListener* listener);
+ void deregisterDefaultSkinChangeListener(DefaultSkinChangeListener* listener);
+
private:
void loadSkins();
void loadCssValues();