Introduce dark/light mode switch, EXPERIMENTAL
This commit is contained in:
parent
dd185edf96
commit
187b1c72dd
11 changed files with 202 additions and 49 deletions
2
deps/PawPaw
vendored
2
deps/PawPaw
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit ae5e26516596024a0268b5f8f1685050a248875a
|
Subproject commit 18d8835bd17da6f651a49d83f8d911d7c1858399
|
29
include/settings.hpp
Normal file
29
include/settings.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* DISTRHO Cardinal Plugin
|
||||||
|
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||||
|
*
|
||||||
|
* This program 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 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.
|
||||||
|
*
|
||||||
|
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include_next "settings.hpp"
|
||||||
|
|
||||||
|
namespace rack {
|
||||||
|
namespace settings {
|
||||||
|
|
||||||
|
extern bool darkMode;
|
||||||
|
extern int rateLimit;
|
||||||
|
|
||||||
|
} // namespace settings
|
||||||
|
} // namespace rack
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugincontext.hpp"
|
#include "plugincontext.hpp"
|
||||||
|
#include "ModuleWidgets.hpp"
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -170,7 +171,7 @@ struct HostTime : TerminalModule {
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef HEADLESS
|
#ifndef HEADLESS
|
||||||
struct HostTimeWidget : ModuleWidget {
|
struct HostTimeWidget : ModuleWidgetWith8HP {
|
||||||
static constexpr const float startX = 10.0f;
|
static constexpr const float startX = 10.0f;
|
||||||
static constexpr const float startY_top = 71.0f;
|
static constexpr const float startY_top = 71.0f;
|
||||||
static constexpr const float startY_cv = 115.0f;
|
static constexpr const float startY_cv = 115.0f;
|
||||||
|
@ -186,10 +187,7 @@ struct HostTimeWidget : ModuleWidget {
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostTime.svg")));
|
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostTime.svg")));
|
||||||
monoFontPath = asset::system("res/fonts/ShareTechMono-Regular.ttf");
|
monoFontPath = asset::system("res/fonts/ShareTechMono-Regular.ttf");
|
||||||
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
createAndAddScrews();
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
|
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 0 * padding), m, HostTime::kHostTimeRolling));
|
addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 0 * padding), m, HostTime::kHostTimeRolling));
|
||||||
addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 1 * padding), m, HostTime::kHostTimeReset));
|
addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 1 * padding), m, HostTime::kHostTimeReset));
|
||||||
|
@ -214,20 +212,16 @@ struct HostTimeWidget : ModuleWidget {
|
||||||
const float y = startY_cv + offset * padding;
|
const float y = startY_cv + offset * padding;
|
||||||
nvgBeginPath(vg);
|
nvgBeginPath(vg);
|
||||||
nvgRoundedRect(vg, startX - 1.0f, y - 2.f, box.size.x - startX * 2 + 2.f, 28.f, 4);
|
nvgRoundedRect(vg, startX - 1.0f, y - 2.f, box.size.x - startX * 2 + 2.f, 28.f, 4);
|
||||||
nvgFillColor(vg, nvgRGB(0xd0, 0xd0, 0xd0));
|
nvgFillColor(vg, rack::settings::darkMode ? nvgRGB(0xd0, 0xd0, 0xd0) : nvgRGB(0x2f, 0x2f, 0x2f));
|
||||||
nvgFill(vg);
|
nvgFill(vg);
|
||||||
nvgBeginPath(vg);
|
nvgBeginPath(vg);
|
||||||
nvgFillColor(vg, color::BLACK);
|
nvgFillColor(vg, rack::settings::darkMode ? color::BLACK : color::WHITE);
|
||||||
nvgText(vg, startX + 36, y + 16, text, nullptr);
|
nvgText(vg, startX + 36, y + 16, text, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(const DrawArgs& args) override
|
void draw(const DrawArgs& args) override
|
||||||
{
|
{
|
||||||
nvgBeginPath(args.vg);
|
drawBackground(args.vg);
|
||||||
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
|
|
||||||
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
|
|
||||||
nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
|
|
||||||
nvgFill(args.vg);
|
|
||||||
|
|
||||||
nvgFontFaceId(args.vg, 0);
|
nvgFontFaceId(args.vg, 0);
|
||||||
nvgFontSize(args.vg, 14);
|
nvgFontSize(args.vg, 14);
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "color.hpp"
|
||||||
#include "rack.hpp"
|
#include "rack.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
# undef DEBUG
|
# undef DEBUG
|
||||||
|
@ -66,22 +68,26 @@ struct ModuleWidgetWithSideScrews : ModuleWidget {
|
||||||
void drawBackground(NVGcontext* const vg) {
|
void drawBackground(NVGcontext* const vg) {
|
||||||
nvgBeginPath(vg);
|
nvgBeginPath(vg);
|
||||||
nvgRect(vg, 0, 0, box.size.x, box.size.y);
|
nvgRect(vg, 0, 0, box.size.x, box.size.y);
|
||||||
nvgFillPaint(vg, nvgLinearGradient(vg, 0, 0, 0, box.size.y,
|
if (rack::settings::darkMode)
|
||||||
nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
|
nvgFillPaint(vg, nvgLinearGradient(vg, 0, 0, 0, box.size.y,
|
||||||
|
nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
|
||||||
|
else
|
||||||
|
nvgFillPaint(vg, nvgLinearGradient(vg, 0, 0, 0, box.size.y,
|
||||||
|
nvgRGB(0xe7, 0xe6, 0xe6), nvgRGB(0xde, 0xdd, 0xdd)));
|
||||||
nvgFill(vg);
|
nvgFill(vg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawOutputJacksArea(NVGcontext* const vg, const int numOutputs) {
|
void drawOutputJacksArea(NVGcontext* const vg, const int numOutputs) {
|
||||||
nvgBeginPath(vg);
|
nvgBeginPath(vg);
|
||||||
nvgRoundedRect(vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * numOutputs, 4);
|
nvgRoundedRect(vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * numOutputs, 4);
|
||||||
nvgFillColor(vg, nvgRGB(0xd0, 0xd0, 0xd0));
|
nvgFillColor(vg, rack::settings::darkMode ? nvgRGB(0xd0, 0xd0, 0xd0) : nvgRGB(0x2f, 0x2f, 0x2f));
|
||||||
nvgFill(vg);
|
nvgFill(vg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text) {
|
void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text) {
|
||||||
const float y = startY + posY * padding;
|
const float y = startY + posY * padding;
|
||||||
nvgBeginPath(vg);
|
nvgBeginPath(vg);
|
||||||
nvgFillColor(vg, color::WHITE);
|
nvgFillColor(vg, rack::settings::darkMode ? color::WHITE : color::BLACK);
|
||||||
nvgText(vg, box.size.x * 0.5f, y + 16, text, nullptr);
|
nvgText(vg, box.size.x * 0.5f, y + 16, text, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,3 +102,4 @@ typedef ModuleWidgetWithSideScrews<3> ModuleWidgetWith3HP;
|
||||||
typedef ModuleWidgetWithSideScrews<8> ModuleWidgetWith8HP;
|
typedef ModuleWidgetWithSideScrews<8> ModuleWidgetWith8HP;
|
||||||
typedef ModuleWidgetWithSideScrews<9> ModuleWidgetWith9HP;
|
typedef ModuleWidgetWithSideScrews<9> ModuleWidgetWith9HP;
|
||||||
typedef ModuleWidgetWithSideScrews<11> ModuleWidgetWith11HP;
|
typedef ModuleWidgetWithSideScrews<11> ModuleWidgetWith11HP;
|
||||||
|
typedef ModuleWidgetWithSideScrews<25> ModuleWidgetWith25HP;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#ifndef HEADLESS
|
#ifndef HEADLESS
|
||||||
# include "glBars.hpp"
|
# include "glBars.hpp"
|
||||||
|
# include "ModuleWidgets.hpp"
|
||||||
# include "Widgets.hpp"
|
# include "Widgets.hpp"
|
||||||
#else
|
#else
|
||||||
# include "plugin.hpp"
|
# include "plugin.hpp"
|
||||||
|
@ -129,16 +130,13 @@ struct glBarsRendererWidget : OpenGlWidgetWithBrowserPreview {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct glBarsWidget : ModuleWidget {
|
struct glBarsWidget : ModuleWidgetWith25HP {
|
||||||
glBarsWidget(glBarsModule* const module)
|
glBarsWidget(glBarsModule* const module)
|
||||||
{
|
{
|
||||||
setModule(module);
|
setModule(module);
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/glBars.svg")));
|
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/glBars.svg")));
|
||||||
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
createAndAddScrews();
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
|
|
||||||
addInput(createInput<PJ301MPort>(Vec(135.0f, 20.0f), module, glBarsModule::IN1_INPUT));
|
addInput(createInput<PJ301MPort>(Vec(135.0f, 20.0f), module, glBarsModule::IN1_INPUT));
|
||||||
|
|
||||||
|
@ -151,13 +149,8 @@ struct glBarsWidget : ModuleWidget {
|
||||||
|
|
||||||
void draw(const DrawArgs& args) override
|
void draw(const DrawArgs& args) override
|
||||||
{
|
{
|
||||||
nvgBeginPath(args.vg);
|
drawBackground(args.vg);
|
||||||
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
|
ModuleWidgetWith25HP::draw(args);
|
||||||
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
|
|
||||||
nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
|
|
||||||
nvgFill(args.vg);
|
|
||||||
|
|
||||||
ModuleWidget::draw(args);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -17,12 +17,12 @@ void writeThemeAndContrastAsDefault() {}
|
||||||
void saveThemeAndContrastAsDefault(int, float) {}
|
void saveThemeAndContrastAsDefault(int, float) {}
|
||||||
|
|
||||||
void loadThemeAndContrastFromDefault(int* panelTheme, float* panelContrast) {
|
void loadThemeAndContrastFromDefault(int* panelTheme, float* panelContrast) {
|
||||||
*panelTheme = 1;
|
*panelTheme = rack::settings::darkMode ? 1 : 0;
|
||||||
*panelContrast = panelContrastDefault;
|
*panelContrast = panelContrastDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDark(int*) {
|
bool isDark(int*) {
|
||||||
return true;
|
return rack::settings::darkMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readThemeAndContrastFromDefault() {}
|
void readThemeAndContrastFromDefault() {}
|
||||||
|
@ -47,7 +47,7 @@ void PanelBaseWidget::draw(const DrawArgs& args) {
|
||||||
|
|
||||||
void InverterWidget::draw(const DrawArgs& args) {
|
void InverterWidget::draw(const DrawArgs& args) {
|
||||||
TransparentWidget::draw(args);
|
TransparentWidget::draw(args);
|
||||||
{
|
if (rack::settings::darkMode) {
|
||||||
// nvgSave(args.vg);
|
// nvgSave(args.vg);
|
||||||
nvgBeginPath(args.vg);
|
nvgBeginPath(args.vg);
|
||||||
nvgFillColor(args.vg, SCHEME_WHITE);// this is the source, the current framebuffer is the dest
|
nvgFillColor(args.vg, SCHEME_WHITE);// this is the source, the current framebuffer is the dest
|
||||||
|
@ -64,4 +64,3 @@ void InverterWidget::draw(const DrawArgs& args) {
|
||||||
// nvgRestore(args.vg);
|
// nvgRestore(args.vg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "AsyncDialog.hpp"
|
#include "AsyncDialog.hpp"
|
||||||
#include "PluginContext.hpp"
|
#include "PluginContext.hpp"
|
||||||
#include "DistrhoPluginUtils.hpp"
|
#include "DistrhoPluginUtils.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
#include <asset.hpp>
|
#include <asset.hpp>
|
||||||
#include <context.hpp>
|
#include <context.hpp>
|
||||||
|
@ -61,6 +62,7 @@ const std::string CARDINAL_VERSION = "22.07";
|
||||||
namespace rack {
|
namespace rack {
|
||||||
|
|
||||||
namespace settings {
|
namespace settings {
|
||||||
|
bool darkMode = true;
|
||||||
int rateLimit = 0;
|
int rateLimit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,6 @@ extern const std::string CARDINAL_VERSION;
|
||||||
|
|
||||||
namespace rack {
|
namespace rack {
|
||||||
|
|
||||||
namespace settings {
|
|
||||||
extern int rateLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
struct Menu;
|
struct Menu;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ BUILD_CXX_FLAGS += -faligned-new -Wno-abi
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# use our custom function to invert some colors
|
# use our custom function to invert some colors
|
||||||
|
BUILD_CXX_FLAGS += -DnsvgDelete=nsvgDeleteCardinal
|
||||||
BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal
|
BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal
|
||||||
|
|
||||||
# Rack code is not tested for this flag, unset it
|
# Rack code is not tested for this flag, unset it
|
||||||
|
|
|
@ -19,6 +19,13 @@
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace rack {
|
||||||
|
namespace settings {
|
||||||
|
extern bool darkMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "nanovg.h"
|
#include "nanovg.h"
|
||||||
|
|
||||||
|
@ -43,6 +50,7 @@ NVGcolor nvgRGBblank(unsigned char, unsigned char, unsigned char)
|
||||||
// Compile those nice implementation-in-header little libraries
|
// Compile those nice implementation-in-header little libraries
|
||||||
#define NANOSVG_IMPLEMENTATION
|
#define NANOSVG_IMPLEMENTATION
|
||||||
#define NANOSVG_ALL_COLOR_KEYWORDS
|
#define NANOSVG_ALL_COLOR_KEYWORDS
|
||||||
|
#undef nsvgDelete
|
||||||
#undef nsvgParseFromFile
|
#undef nsvgParseFromFile
|
||||||
#include <nanosvg.h>
|
#include <nanosvg.h>
|
||||||
|
|
||||||
|
@ -327,6 +335,7 @@ static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const c
|
||||||
// Special case for DrumKit background gradient
|
// Special case for DrumKit background gradient
|
||||||
if (std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0)
|
if (std::strncmp(svgFileToInvert, "/DrumKit/", 9) == 0)
|
||||||
{
|
{
|
||||||
|
std::free(paint.gradient);
|
||||||
paint.type = NSVG_PAINT_COLOR;
|
paint.type = NSVG_PAINT_COLOR;
|
||||||
paint.color = 0xff191919;
|
paint.color = 0xff191919;
|
||||||
return true;
|
return true;
|
||||||
|
@ -593,12 +602,33 @@ static inline bool invertPaint(NSVGshape* const shape, NSVGpaint& paint, const c
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
NSVGimage* nsvgParseFromFileCardinal(const char* filename, const char* units, float dpi);
|
NSVGimage* nsvgParseFromFileCardinal(const char* filename, const char* units, float dpi);
|
||||||
|
void nsvgDeleteCardinal(NSVGimage*);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ExtendedNSVGimage {
|
||||||
|
NSVGimage* handle;
|
||||||
|
NSVGshape* shapesOrig;
|
||||||
|
NSVGshape* shapesDark;
|
||||||
|
};
|
||||||
|
static std::list<ExtendedNSVGimage> loadedSVGs;
|
||||||
|
|
||||||
|
static void nsvg__duplicatePaint(NSVGpaint& dst, NSVGpaint& src)
|
||||||
|
{
|
||||||
|
if (dst.type == NSVG_PAINT_LINEAR_GRADIENT || dst.type == NSVG_PAINT_RADIAL_GRADIENT)
|
||||||
|
{
|
||||||
|
dst.gradient = static_cast<NSVGgradient*>(malloc(sizeof(NSVGgradient)));
|
||||||
|
std::memcpy(dst.gradient, src.gradient, sizeof(NSVGgradient));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* const units, const float dpi)
|
NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* const units, const float dpi)
|
||||||
{
|
{
|
||||||
if (NSVGimage* const handle = nsvgParseFromFile(filename, units, dpi))
|
if (NSVGimage* const handle = nsvgParseFromFile(filename, units, dpi))
|
||||||
{
|
{
|
||||||
|
bool hasDarkMode = false;
|
||||||
|
NSVGshape* shapesOrig;
|
||||||
|
NSVGshape* shapesDark;
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(svgFilesToInvert)/sizeof(svgFilesToInvert[0]); ++i)
|
for (size_t i = 0; i < sizeof(svgFilesToInvert)/sizeof(svgFilesToInvert[0]); ++i)
|
||||||
{
|
{
|
||||||
const char* const svgFileToInvert = svgFilesToInvert[i].filename;
|
const char* const svgFileToInvert = svgFilesToInvert[i].filename;
|
||||||
|
@ -614,7 +644,30 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con
|
||||||
const int shapeNumberToIgnore = svgFilesToInvert[i].shapeNumberToIgnore;
|
const int shapeNumberToIgnore = svgFilesToInvert[i].shapeNumberToIgnore;
|
||||||
int shapeCounter = 0;
|
int shapeCounter = 0;
|
||||||
|
|
||||||
for (NSVGshape* shape = handle->shapes; shape != nullptr; shape = shape->next, ++shapeCounter)
|
hasDarkMode = true;
|
||||||
|
shapesOrig = handle->shapes;
|
||||||
|
|
||||||
|
// duplicate all shapes, so we can swap between original and dark mode at will
|
||||||
|
shapesDark = static_cast<NSVGshape*>(malloc(sizeof(NSVGshape)));
|
||||||
|
std::memcpy(shapesDark, shapesOrig, sizeof(NSVGshape));
|
||||||
|
nsvg__duplicatePaint(shapesDark->fill, shapesOrig->fill);
|
||||||
|
nsvg__duplicatePaint(shapesDark->stroke, shapesOrig->stroke);
|
||||||
|
|
||||||
|
for (NSVGshape* shape2 = shapesDark;;)
|
||||||
|
{
|
||||||
|
if (shape2->next == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
NSVGshape* const shapedup = static_cast<NSVGshape*>(malloc(sizeof(NSVGshape)));
|
||||||
|
std::memcpy(shapedup, shape2->next, sizeof(NSVGshape));
|
||||||
|
nsvg__duplicatePaint(shapedup->fill, shape2->next->fill);
|
||||||
|
nsvg__duplicatePaint(shapedup->stroke, shape2->next->stroke);
|
||||||
|
shape2->next = shapedup;
|
||||||
|
shape2 = shapedup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shape paint inversion
|
||||||
|
for (NSVGshape* shape = shapesDark; shape != nullptr; shape = shape->next, ++shapeCounter)
|
||||||
{
|
{
|
||||||
if (shapeNumberToIgnore == shapeCounter)
|
if (shapeNumberToIgnore == shapeCounter)
|
||||||
continue;
|
continue;
|
||||||
|
@ -635,7 +688,7 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con
|
||||||
invertPaint(shape, shape->stroke, svgFileToInvert);
|
invertPaint(shape, shape->stroke, svgFileToInvert);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handle;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for AmalgamatedHarmonics background color
|
// Special case for AmalgamatedHarmonics background color
|
||||||
|
@ -643,8 +696,62 @@ NSVGimage* nsvgParseFromFileCardinal(const char* const filename, const char* con
|
||||||
if (std::strstr(filename, "/AmalgamatedHarmonics/") != nullptr)
|
if (std::strstr(filename, "/AmalgamatedHarmonics/") != nullptr)
|
||||||
handle->shapes->fill.color = 0xff191919;
|
handle->shapes->fill.color = 0xff191919;
|
||||||
|
|
||||||
|
if (hasDarkMode)
|
||||||
|
{
|
||||||
|
const ExtendedNSVGimage ext = { handle, shapesOrig, shapesDark };
|
||||||
|
loadedSVGs.push_back(ext);
|
||||||
|
|
||||||
|
if (rack::settings::darkMode)
|
||||||
|
handle->shapes = shapesDark;
|
||||||
|
}
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsvgDeleteCardinal(NSVGimage* const handle)
|
||||||
|
{
|
||||||
|
for (auto it = loadedSVGs.cbegin(), end = loadedSVGs.cend(); it != end; ++it)
|
||||||
|
{
|
||||||
|
const ExtendedNSVGimage& ext(*it);
|
||||||
|
|
||||||
|
if (ext.handle != handle)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// delete duplicated resources
|
||||||
|
for (NSVGshape *next, *shape = ext.shapesDark;;)
|
||||||
|
{
|
||||||
|
next = shape->next;
|
||||||
|
|
||||||
|
nsvg__deletePaint(&shape->fill);
|
||||||
|
nsvg__deletePaint(&shape->stroke);
|
||||||
|
std::free(shape);
|
||||||
|
|
||||||
|
if (next == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
shape = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert shapes back to original
|
||||||
|
handle->shapes = ext.shapesOrig;
|
||||||
|
|
||||||
|
loadedSVGs.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsvgDelete(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void switchDarkMode(bool darkMode)
|
||||||
|
{
|
||||||
|
if (rack::settings::darkMode == darkMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rack::settings::darkMode = darkMode;
|
||||||
|
|
||||||
|
for (ExtendedNSVGimage& ext : loadedSVGs)
|
||||||
|
ext.handle->shapes = darkMode ? ext.shapesDark : ext.shapesOrig;
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <ui/ProgressBar.hpp>
|
#include <ui/ProgressBar.hpp>
|
||||||
#include <ui/Label.hpp>
|
#include <ui/Label.hpp>
|
||||||
#include <engine/Engine.hpp>
|
#include <engine/Engine.hpp>
|
||||||
|
#include <widget/FramebufferWidget.hpp>
|
||||||
#include <window/Window.hpp>
|
#include <window/Window.hpp>
|
||||||
#include <asset.hpp>
|
#include <asset.hpp>
|
||||||
#include <context.hpp>
|
#include <context.hpp>
|
||||||
|
@ -60,6 +61,8 @@
|
||||||
# include "DistrhoStandaloneUtils.hpp"
|
# include "DistrhoStandaloneUtils.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void switchDarkMode(bool darkMode);
|
||||||
|
|
||||||
namespace rack {
|
namespace rack {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
std::string patchesPath();
|
std::string patchesPath();
|
||||||
|
@ -492,6 +495,20 @@ struct KnobScrollSensitivitySlider : ui::Slider {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void setAllFramebufferWidgetsDirty(widget::Widget* const widget)
|
||||||
|
{
|
||||||
|
for (widget::Widget* child : widget->children)
|
||||||
|
{
|
||||||
|
if (widget::FramebufferWidget* const fbw = dynamic_cast<widget::FramebufferWidget*>(child))
|
||||||
|
{
|
||||||
|
fbw->setDirty();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setAllFramebufferWidgetsDirty(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ViewButton : MenuButton {
|
struct ViewButton : MenuButton {
|
||||||
void onAction(const ActionEvent& e) override {
|
void onAction(const ActionEvent& e) override {
|
||||||
ui::Menu* menu = createMenu();
|
ui::Menu* menu = createMenu();
|
||||||
|
@ -500,6 +517,14 @@ struct ViewButton : MenuButton {
|
||||||
|
|
||||||
menu->addChild(createMenuLabel("Appearance"));
|
menu->addChild(createMenuLabel("Appearance"));
|
||||||
|
|
||||||
|
std::string darkModeText;
|
||||||
|
if (settings::darkMode)
|
||||||
|
darkModeText = CHECKMARK_STRING;
|
||||||
|
menu->addChild(createMenuItem("Dark Mode", darkModeText, []() {
|
||||||
|
switchDarkMode(!settings::darkMode);
|
||||||
|
setAllFramebufferWidgetsDirty(APP->scene);
|
||||||
|
}));
|
||||||
|
|
||||||
menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips));
|
menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips));
|
||||||
|
|
||||||
ZoomSlider* zoomSlider = new ZoomSlider;
|
ZoomSlider* zoomSlider = new ZoomSlider;
|
||||||
|
@ -563,10 +588,10 @@ struct ViewButton : MenuButton {
|
||||||
|
|
||||||
#ifdef DISTRHO_OS_WASM
|
#ifdef DISTRHO_OS_WASM
|
||||||
const bool fullscreen = APP->window->isFullScreen();
|
const bool fullscreen = APP->window->isFullScreen();
|
||||||
std::string fullscreenText = "F11";
|
std::string rightText = "F11";
|
||||||
if (fullscreen)
|
if (rightText)
|
||||||
fullscreenText += " " CHECKMARK_STRING;
|
rightText += " " CHECKMARK_STRING;
|
||||||
menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() {
|
menu->addChild(createMenuItem("Fullscreen", rightText, [=]() {
|
||||||
APP->window->setFullScreen(!fullscreen);
|
APP->window->setFullScreen(!fullscreen);
|
||||||
}));
|
}));
|
||||||
#endif
|
#endif
|
||||||
|
@ -612,10 +637,10 @@ struct EngineButton : MenuButton {
|
||||||
#ifdef DISTRHO_OS_WASM
|
#ifdef DISTRHO_OS_WASM
|
||||||
if (supportsAudioInput()) {
|
if (supportsAudioInput()) {
|
||||||
const bool enabled = isAudioInputEnabled();
|
const bool enabled = isAudioInputEnabled();
|
||||||
std::string text = "Enable Audio Input";
|
std::string rightText;
|
||||||
if (enabled)
|
if (enabled)
|
||||||
text += " " CHECKMARK_STRING;
|
rightText = CHECKMARK_STRING;
|
||||||
menu->addChild(createMenuItem(text, "", [enabled]() {
|
menu->addChild(createMenuItem("Enable Audio Input", rightText, [enabled]() {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
requestAudioInput();
|
requestAudioInput();
|
||||||
}));
|
}));
|
||||||
|
@ -623,10 +648,10 @@ struct EngineButton : MenuButton {
|
||||||
|
|
||||||
if (supportsMIDI()) {
|
if (supportsMIDI()) {
|
||||||
const bool enabled = isMIDIEnabled();
|
const bool enabled = isMIDIEnabled();
|
||||||
std::string text = "Enable MIDI";
|
std::string rightText;
|
||||||
if (enabled)
|
if (enabled)
|
||||||
text += " " CHECKMARK_STRING;
|
rightText = CHECKMARK_STRING;
|
||||||
menu->addChild(createMenuItem(text, "", [enabled]() {
|
menu->addChild(createMenuItem("Enable MIDI", rightText, [enabled]() {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
requestMIDI();
|
requestMIDI();
|
||||||
}));
|
}));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue