From d96d3154f89c93059a86ec8af8dbd7aac7c3d150 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 17 Aug 2024 10:34:06 -0400 Subject: [PATCH] User editable and streamable ColorMap files (#1132) * User editable and streamable ColorMap files You can now make a json from a colormap, save it, edit it, load it, and so on. Since that's the case I also moved the "factory" colormaps to json assets rather than raw C++, even though still only the wireframe theme is usable or correct. * Fix a small problem related to json and knob bodies --- src-ui/CMakeLists.txt | 6 +- src-ui/components/SCXTEditor.cpp | 54 ++- src-ui/components/SCXTEditor.h | 6 +- src-ui/components/SCXTEditorMenus.cpp | 47 ++ src-ui/components/mixer/PartEffectsPane.cpp | 4 +- src-ui/components/multi/ProcessorPane.cpp | 4 +- ...ayoutConsumer.cpp => JSONAssetSupport.cpp} | 8 +- ...SONLayoutConsumer.h => JSONAssetSupport.h} | 6 +- .../README_JSON_ASSETS.md} | 8 +- .../bus-effects/bonsai.json | 0 .../bus-effects/delay.json | 0 .../bus-effects/flanger.json | 0 .../bus-effects/nimbus.json | 0 .../bus-effects/phaser.json | 0 .../bus-effects/reverb1.json | 0 .../bus-effects/reverb2.json | 0 .../bus-effects/treemonster.json | 0 .../processors/bitcrusher.json | 0 .../processors/fastsvf.json | 0 .../processors/noiseam.json | 0 .../processors/phasemod.json | 0 .../processors/simpledelay.json | 0 .../processors/waveshaper.json | 0 src-ui/json-assets/themes/test-colors.json | 34 ++ .../themes/wireframe-dark-hicontrast.json | 35 ++ src-ui/json-assets/themes/wireframe-dark.json | 35 ++ .../json-assets/themes/wireframe-light.json | 34 ++ src-ui/theme/ColorMap.cpp | 424 +++++++----------- src-ui/theme/ColorMap.h | 26 +- src/browser/browser.cpp | 1 + src/browser/browser.h | 1 + src/infrastructure/user_defaults.h | 3 + 32 files changed, 449 insertions(+), 287 deletions(-) rename src-ui/connectors/{JSONLayoutConsumer.cpp => JSONAssetSupport.cpp} (93%) rename src-ui/connectors/{JSONLayoutConsumer.h => JSONAssetSupport.h} (98%) rename src-ui/{json-layout/README_JSON_LAYOUTS.md => json-assets/README_JSON_ASSETS.md} (92%) rename src-ui/{json-layout => json-assets}/bus-effects/bonsai.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/delay.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/flanger.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/nimbus.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/phaser.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/reverb1.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/reverb2.json (100%) rename src-ui/{json-layout => json-assets}/bus-effects/treemonster.json (100%) rename src-ui/{json-layout => json-assets}/processors/bitcrusher.json (100%) rename src-ui/{json-layout => json-assets}/processors/fastsvf.json (100%) rename src-ui/{json-layout => json-assets}/processors/noiseam.json (100%) rename src-ui/{json-layout => json-assets}/processors/phasemod.json (100%) rename src-ui/{json-layout => json-assets}/processors/simpledelay.json (100%) rename src-ui/{json-layout => json-assets}/processors/waveshaper.json (100%) create mode 100644 src-ui/json-assets/themes/test-colors.json create mode 100644 src-ui/json-assets/themes/wireframe-dark-hicontrast.json create mode 100644 src-ui/json-assets/themes/wireframe-dark.json create mode 100644 src-ui/json-assets/themes/wireframe-light.json diff --git a/src-ui/CMakeLists.txt b/src-ui/CMakeLists.txt index bc9a1cb5..01a46815 100644 --- a/src-ui/CMakeLists.txt +++ b/src-ui/CMakeLists.txt @@ -35,18 +35,18 @@ add_library(${PROJECT_NAME} STATIC components/multi/SingleMacroEditor.cpp connectors/SCXTResources.cpp - connectors/JSONLayoutConsumer.cpp + connectors/JSONAssetSupport.cpp theme/ColorMap.cpp theme/ThemeApplier.cpp ) -message(STATUS "Globbing json-layout directory for cmrc") +message(STATUS "Globbing json-assets directory for cmrc") file(GLOB_RECURSE scxt_json_sources LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - json-layout/*.json + json-assets/*.json ) cmrc_add_resource_library(scxtui_json_layouts NAMESPACE scxtui_json_layouts diff --git a/src-ui/components/SCXTEditor.cpp b/src-ui/components/SCXTEditor.cpp index 07caebcb..0c76083f 100644 --- a/src-ui/components/SCXTEditor.cpp +++ b/src-ui/components/SCXTEditor.cpp @@ -63,15 +63,7 @@ SCXTEditor::SCXTEditor(messaging::MessageController &e, infrastructure::Defaults setStyle(sst::jucegui::style::StyleSheet::getBuiltInStyleSheet( sst::jucegui::style::StyleSheet::EMPTY)); - auto cmid = defaultsProvider.getUserDefaultValue(infrastructure::DefaultKeys::colormapId, - theme::ColorMap::WIREFRAME); - auto cm = theme::ColorMap::createColorMap((theme::ColorMap::BuiltInColorMaps)cmid); - - auto showK = - defaultsProvider.getUserDefaultValue(infrastructure::DefaultKeys::showKnobs, false); - cm->hasKnobs = showK; - - themeApplier.recolorStylesheetWith(std::move(cm), style()); + resetColorsFromUserPreferences(); // TODO what happens with two windows open when I go away? lnf = std::make_unique(); @@ -376,9 +368,51 @@ void SCXTEditor::configureHasDiscreteMenuBuilder( int16_t SCXTEditor::getSelectedPart() const { return selectedPart; } -juce::Colour SCXTEditor::themeColor(scxt::ui::theme::ColorMap::Colors c, float alpha) +juce::Colour SCXTEditor::themeColor(scxt::ui::theme::ColorMap::Colors c, float alpha) const { return themeApplier.colors->get(c, alpha); } +void SCXTEditor::resetColorsFromUserPreferences() +{ + auto cmid = defaultsProvider.getUserDefaultValue(infrastructure::DefaultKeys::colormapId, + theme::ColorMap::WIREFRAME); + std::unique_ptr cm; + if (cmid == theme::ColorMap::FILE_COLORMAP_ID) + { + auto pt = defaultsProvider.getUserDefaultValue( + infrastructure::DefaultKeys::colormapPathIfFile, ""); + try + { + auto path = fs::path{pt}; + if (fs::exists(path)) + { + std::ifstream t(path); + std::stringstream buffer; + buffer << t.rdbuf(); + cm = theme::ColorMap::jsonToColormap(buffer.str()); + } + } + catch (fs::filesystem_error &e) + { + } + if (!cm) + { + SCLOG("Attempted to load colormap from missing colormap file " << pt); + cm = theme::ColorMap::createColorMap(theme::ColorMap::WIREFRAME); + } + } + else + { + cm = theme::ColorMap::createColorMap((theme::ColorMap::BuiltInColorMaps)cmid); + } + + assert(cm); + auto showK = + defaultsProvider.getUserDefaultValue(infrastructure::DefaultKeys::showKnobs, false); + cm->hasKnobs = showK; + + themeApplier.recolorStylesheetWith(std::move(cm), style()); +} + } // namespace scxt::ui diff --git a/src-ui/components/SCXTEditor.h b/src-ui/components/SCXTEditor.h index febef934..efc5e6b0 100644 --- a/src-ui/components/SCXTEditor.h +++ b/src-ui/components/SCXTEditor.h @@ -104,7 +104,8 @@ struct SCXTEditor : sst::jucegui::components::WindowPanel, juce::DragAndDropCont * This is an object responsible for theme and color management */ theme::ThemeApplier themeApplier; - juce::Colour themeColor(scxt::ui::theme::ColorMap::Colors, float alpha = 1.f); + juce::Colour themeColor(scxt::ui::theme::ColorMap::Colors, float alpha = 1.f) const; + void resetColorsFromUserPreferences(); sst::basic_blocks::dsp::RNG rng; @@ -281,6 +282,9 @@ struct SCXTEditor : sst::jucegui::components::WindowPanel, juce::DragAndDropCont } std::unique_ptr melatoninInspector; + + public: + std::unique_ptr fileChooser; }; template inline void HasEditor::sendToSerialization(const T &msg) diff --git a/src-ui/components/SCXTEditorMenus.cpp b/src-ui/components/SCXTEditorMenus.cpp index 7a277745..46794c01 100644 --- a/src-ui/components/SCXTEditorMenus.cpp +++ b/src-ui/components/SCXTEditorMenus.cpp @@ -117,6 +117,8 @@ void SCXTEditor::showMainMenu() }); // dp.addItem("Focus Debugger Toggle", []() {}); dp.addSeparator(); + dp.addItem("Dump Colormap JSON", [this]() { SCLOG(themeApplier.colors->toJson()); }); + dp.addSeparator(); if (melatoninInspector) { @@ -226,6 +228,7 @@ void SCXTEditor::addUIThemesMenu(juce::PopupMenu &p, bool addTitle) p.addSectionHeader("Themes"); std::vector> maps = { {theme::ColorMap::WIREFRAME, "Wireframe Colors"}, + {theme::ColorMap::LIGHT, "Wireframe Light"}, {theme::ColorMap::HICONTRAST_DARK, "High Contrast Dark"}, {theme::ColorMap::TEST, "Test Colors"}, }; @@ -247,6 +250,50 @@ void SCXTEditor::addUIThemesMenu(juce::PopupMenu &p, bool addTitle) }); } + p.addSeparator(); + p.addItem("Save Theme...", [w = juce::Component::SafePointer(this)]() { + if (!w) + return; + w->fileChooser = std::make_unique( + "Save Theme", juce::File(w->browser.themeDirectory.u8string()), "*.json"); + w->fileChooser->launchAsync(juce::FileBrowserComponent::canSelectFiles | + juce::FileBrowserComponent::saveMode | + juce::FileBrowserComponent::warnAboutOverwriting, + [w](const juce::FileChooser &c) { + auto result = c.getResults(); + if (result.isEmpty() || result.size() > 1) + { + return; + } + // send a 'save multi' message + auto json = w->themeApplier.colors->toJson(); + result[0].replaceWithText(json); + }); + }); + p.addItem("Load Theme...", [w = juce::Component::SafePointer(this)]() { + if (!w) + return; + w->fileChooser = std::make_unique( + "Load Theme", juce::File(w->browser.themeDirectory.u8string()), "*.json"); + w->fileChooser->launchAsync( + juce::FileBrowserComponent::canSelectFiles | juce::FileBrowserComponent::openMode, + [w](const juce::FileChooser &c) { + auto result = c.getResults(); + if (result.isEmpty() || result.size() > 1) + { + return; + } + auto json = result[0].loadFileAsString(); + auto cm = theme::ColorMap::jsonToColormap(json.toStdString()); + if (cm) + w->themeApplier.recolorStylesheetWith(std::move(cm), w->style()); + w->defaultsProvider.updateUserDefaultValue(infrastructure::DefaultKeys::colormapId, + theme::ColorMap::FILE_COLORMAP_ID); + w->defaultsProvider.updateUserDefaultValue( + infrastructure::DefaultKeys::colormapPathIfFile, + result[0].getFullPathName().toStdString()); + }); + }); p.addSeparator(); auto knobsOn = themeApplier.colors->hasKnobs; p.addItem("Use Knob Bodies", true, knobsOn, [w = juce::Component::SafePointer(this)]() { diff --git a/src-ui/components/mixer/PartEffectsPane.cpp b/src-ui/components/mixer/PartEffectsPane.cpp index 11feab46..bc0cf128 100644 --- a/src-ui/components/mixer/PartEffectsPane.cpp +++ b/src-ui/components/mixer/PartEffectsPane.cpp @@ -29,7 +29,7 @@ #include "components/SCXTEditor.h" #include "components/MixerScreen.h" -#include "connectors/JSONLayoutConsumer.h" +#include "connectors/JSONAssetSupport.h" #include "sst/jucegui/components/Knob.h" #include "sst/jucegui/components/Label.h" @@ -303,7 +303,7 @@ template juce::Component *PartEffectsPane::addTypedLabel(const std: void PartEffectsPane::rebuildFromJSONLibrary(const std::string &path) { bool parseWorked{false}; - auto dlyjs = connectors::JSONLayoutLibrary::jsonForComponent(path); + auto dlyjs = connectors::JSONAssetLibrary::jsonForAsset(path); connectors::JSONLayoutConsumer con; try { diff --git a/src-ui/components/multi/ProcessorPane.cpp b/src-ui/components/multi/ProcessorPane.cpp index 18251512..21301855 100644 --- a/src-ui/components/multi/ProcessorPane.cpp +++ b/src-ui/components/multi/ProcessorPane.cpp @@ -28,7 +28,7 @@ #include "ProcessorPane.h" #include "components/SCXTEditor.h" -#include "connectors/JSONLayoutConsumer.h" +#include "connectors/JSONAssetSupport.h" #include "messaging/client/client_serial.h" #include "messaging/client/client_messages.h" @@ -482,7 +482,7 @@ bool ProcessorPane::layoutControlsFromJSON(const std::string &jsonpath) bool ProcessorPane::layoutControlsFromJSON(const std::string &jsonpath, sst::jucegui::layout::ExplicitLayout &elo) { - auto dlyjs = connectors::JSONLayoutLibrary::jsonForComponent(jsonpath); + auto dlyjs = connectors::JSONAssetLibrary::jsonForAsset(jsonpath); connectors::JSONLayoutConsumer con; try { diff --git a/src-ui/connectors/JSONLayoutConsumer.cpp b/src-ui/connectors/JSONAssetSupport.cpp similarity index 93% rename from src-ui/connectors/JSONLayoutConsumer.cpp rename to src-ui/connectors/JSONAssetSupport.cpp index e6afccfa..b0c8307a 100644 --- a/src-ui/connectors/JSONLayoutConsumer.cpp +++ b/src-ui/connectors/JSONAssetSupport.cpp @@ -30,7 +30,7 @@ #include #include -#include "JSONLayoutConsumer.h" +#include "JSONAssetSupport.h" #include @@ -38,7 +38,7 @@ CMRC_DECLARE(scxtui_json_layouts); namespace scxt::ui::connectors { -std::string JSONLayoutLibrary::jsonForComponent(const std::string &nm) +std::string JSONAssetLibrary::jsonForAsset(const std::string &nm) { static bool checkedForLocal{false}; static bool isLocal{false}; @@ -61,7 +61,7 @@ std::string JSONLayoutLibrary::jsonForComponent(const std::string &nm) if (!isLocal) { - auto rp = fs::path{"src-ui"} / "json-layout"; + auto rp = fs::path{"src-ui"} / "json-assets"; if (fs::exists(rp)) { SCLOG("Setting JSON path from working dir: " << rp.u8string()); @@ -98,7 +98,7 @@ std::string JSONLayoutLibrary::jsonForComponent(const std::string &nm) try { auto fs = cmrc::scxtui_json_layouts::get_filesystem(); - auto fn = "json-layout/" + nm; + auto fn = "json-assets/" + nm; auto jsnf = fs.open(fn); std::string json(jsnf.begin(), jsnf.end()); diff --git a/src-ui/connectors/JSONLayoutConsumer.h b/src-ui/connectors/JSONAssetSupport.h similarity index 98% rename from src-ui/connectors/JSONLayoutConsumer.h rename to src-ui/connectors/JSONAssetSupport.h index fce5e0f7..073a9fab 100644 --- a/src-ui/connectors/JSONLayoutConsumer.h +++ b/src-ui/connectors/JSONAssetSupport.h @@ -34,11 +34,13 @@ #include "tao/json/binary_view.hpp" #include "tao/json/events/from_string.hpp" +#include "utils.h" + namespace scxt::ui::connectors { -struct JSONLayoutLibrary +struct JSONAssetLibrary { - static std::string jsonForComponent(const std::string &nm); + static std::string jsonForAsset(const std::string &nm); }; struct JSONLayoutConsumer diff --git a/src-ui/json-layout/README_JSON_LAYOUTS.md b/src-ui/json-assets/README_JSON_ASSETS.md similarity index 92% rename from src-ui/json-layout/README_JSON_LAYOUTS.md rename to src-ui/json-assets/README_JSON_ASSETS.md index 4b13e925..c89864c5 100644 --- a/src-ui/json-layout/README_JSON_LAYOUTS.md +++ b/src-ui/json-assets/README_JSON_ASSETS.md @@ -16,7 +16,7 @@ the first commit. ## Core Concepts - Mechanics -- Each 'screen' has a json file which lives in `src-ui/json-layouts` +- Each 'screen' has a json file which lives in `src-ui/json-assets` - Those json files have a common high level model but based on the type of thing they are mapping to, will have different features. For instance, voice processors have float and int parameters @@ -30,7 +30,7 @@ the first commit. - Method 1: Run ShortCircuit with the working directory as the root of the repo, and it will auto-detect the files - Method 2: Set the environment variabe `SCXT_LAYOUT_SOURCE_DIR` - to the json-layout directory (so to `/src-ui/json-layout`) + to the json-assets directory (so to `/src-ui/json-assets`) - With either of these methods in place, editing the source and then rebuilding (so select a different zone and select back) for procs or a different bus and back for FX) will reload @@ -58,3 +58,7 @@ and scan for consistency Document this after I do a few more and collect the result and scan for consistency + +## Theme Color Maps + +Pretty self explanatory \ No newline at end of file diff --git a/src-ui/json-layout/bus-effects/bonsai.json b/src-ui/json-assets/bus-effects/bonsai.json similarity index 100% rename from src-ui/json-layout/bus-effects/bonsai.json rename to src-ui/json-assets/bus-effects/bonsai.json diff --git a/src-ui/json-layout/bus-effects/delay.json b/src-ui/json-assets/bus-effects/delay.json similarity index 100% rename from src-ui/json-layout/bus-effects/delay.json rename to src-ui/json-assets/bus-effects/delay.json diff --git a/src-ui/json-layout/bus-effects/flanger.json b/src-ui/json-assets/bus-effects/flanger.json similarity index 100% rename from src-ui/json-layout/bus-effects/flanger.json rename to src-ui/json-assets/bus-effects/flanger.json diff --git a/src-ui/json-layout/bus-effects/nimbus.json b/src-ui/json-assets/bus-effects/nimbus.json similarity index 100% rename from src-ui/json-layout/bus-effects/nimbus.json rename to src-ui/json-assets/bus-effects/nimbus.json diff --git a/src-ui/json-layout/bus-effects/phaser.json b/src-ui/json-assets/bus-effects/phaser.json similarity index 100% rename from src-ui/json-layout/bus-effects/phaser.json rename to src-ui/json-assets/bus-effects/phaser.json diff --git a/src-ui/json-layout/bus-effects/reverb1.json b/src-ui/json-assets/bus-effects/reverb1.json similarity index 100% rename from src-ui/json-layout/bus-effects/reverb1.json rename to src-ui/json-assets/bus-effects/reverb1.json diff --git a/src-ui/json-layout/bus-effects/reverb2.json b/src-ui/json-assets/bus-effects/reverb2.json similarity index 100% rename from src-ui/json-layout/bus-effects/reverb2.json rename to src-ui/json-assets/bus-effects/reverb2.json diff --git a/src-ui/json-layout/bus-effects/treemonster.json b/src-ui/json-assets/bus-effects/treemonster.json similarity index 100% rename from src-ui/json-layout/bus-effects/treemonster.json rename to src-ui/json-assets/bus-effects/treemonster.json diff --git a/src-ui/json-layout/processors/bitcrusher.json b/src-ui/json-assets/processors/bitcrusher.json similarity index 100% rename from src-ui/json-layout/processors/bitcrusher.json rename to src-ui/json-assets/processors/bitcrusher.json diff --git a/src-ui/json-layout/processors/fastsvf.json b/src-ui/json-assets/processors/fastsvf.json similarity index 100% rename from src-ui/json-layout/processors/fastsvf.json rename to src-ui/json-assets/processors/fastsvf.json diff --git a/src-ui/json-layout/processors/noiseam.json b/src-ui/json-assets/processors/noiseam.json similarity index 100% rename from src-ui/json-layout/processors/noiseam.json rename to src-ui/json-assets/processors/noiseam.json diff --git a/src-ui/json-layout/processors/phasemod.json b/src-ui/json-assets/processors/phasemod.json similarity index 100% rename from src-ui/json-layout/processors/phasemod.json rename to src-ui/json-assets/processors/phasemod.json diff --git a/src-ui/json-layout/processors/simpledelay.json b/src-ui/json-assets/processors/simpledelay.json similarity index 100% rename from src-ui/json-layout/processors/simpledelay.json rename to src-ui/json-assets/processors/simpledelay.json diff --git a/src-ui/json-layout/processors/waveshaper.json b/src-ui/json-assets/processors/waveshaper.json similarity index 100% rename from src-ui/json-layout/processors/waveshaper.json rename to src-ui/json-assets/processors/waveshaper.json diff --git a/src-ui/json-assets/themes/test-colors.json b/src-ui/json-assets/themes/test-colors.json new file mode 100644 index 00000000..52284cec --- /dev/null +++ b/src-ui/json-assets/themes/test-colors.json @@ -0,0 +1,34 @@ +[ + { + "version": "1" + }, + { + "accent_1a": "#ffda70d6", + "accent_1b": "#ffffc0cb", + "accent_2a": "#ff61c4a3", + "accent_2a_alpha_a": "#ff4f9f84", + "accent_2a_alpha_b": "#ff4f9f84", + "accent_2a_alpha_c": "#ff4f9f84", + "accent_2b": "#ff00ffff", + "accent_2b_alpha_a": "#ff00c4c4", + "accent_2b_alpha_b": "#ff00c4c4", + "accent_2b_alpha_c": "#ff00c4c4", + "bg_1": "#ffadff2f", + "bg_2": "#ffb8860b", + "bg_3": "#ffffc0cb", + "generic_content_high": "#ff0000da", + "generic_content_highest": "#ff0000ff", + "generic_content_low": "#ff000077", + "generic_content_lowest": "#ff000000", + "generic_content_medium": "#ff0000af", + "grid_primary": "#ff393939", + "grid_secondary": "#ffa6a6a6", + "gutter_2": "#ffffc0cb", + "gutter_3": "#ffb8860b", + "knob_fill": "#ffcc00cc", + "panel_outline_2": "#ff000000", + "panel_outline_3": "#ff000000", + "warning_1a": "#ffd67272", + "warning_1b": "#ff8a0000" + } +] \ No newline at end of file diff --git a/src-ui/json-assets/themes/wireframe-dark-hicontrast.json b/src-ui/json-assets/themes/wireframe-dark-hicontrast.json new file mode 100644 index 00000000..e28f39d9 --- /dev/null +++ b/src-ui/json-assets/themes/wireframe-dark-hicontrast.json @@ -0,0 +1,35 @@ +[ + { + "version": "1", + "hoverfactor": "0.25" + }, + { + "accent_1a": "#ffffb949", + "accent_1b": "#ffd09030", + "accent_2a": "#ff2788d6", + "accent_2a_alpha_a": "#142788d6", + "accent_2a_alpha_b": "#522788d6", + "accent_2a_alpha_c": "#802788d6", + "accent_2b": "#ff004f8a", + "accent_2b_alpha_a": "#14004f8a", + "accent_2b_alpha_b": "#52004f8a", + "accent_2b_alpha_c": "#80004f8a", + "bg_1": "#ff1b1d20", + "bg_2": "#ff262a2f", + "bg_3": "#ff333333", + "generic_content_high": "#ffdfdfdf", + "generic_content_highest": "#ffffffff", + "generic_content_low": "#ff777777", + "generic_content_lowest": "#ff000000", + "generic_content_medium": "#ffafafaf", + "grid_primary": "#a8393939", + "grid_secondary": "#14a6a6a6", + "gutter_2": "#ff333333", + "gutter_3": "#ff262a2f", + "knob_fill": "#ff525252", + "panel_outline_2": "#FFEEEEEE", + "panel_outline_3": "#FFCCCCCC", + "warning_1a": "#ffd67272", + "warning_1b": "#ff8a0000" + } +] \ No newline at end of file diff --git a/src-ui/json-assets/themes/wireframe-dark.json b/src-ui/json-assets/themes/wireframe-dark.json new file mode 100644 index 00000000..ed67d9de --- /dev/null +++ b/src-ui/json-assets/themes/wireframe-dark.json @@ -0,0 +1,35 @@ +[ + { + "version": "1", + "hoverfactor": "0.1" + }, + { + "accent_1a": "#ffffb949", + "accent_1b": "#ffd09030", + "accent_2a": "#ff2788d6", + "accent_2a_alpha_a": "#142788d6", + "accent_2a_alpha_b": "#522788d6", + "accent_2a_alpha_c": "#802788d6", + "accent_2b": "#ff004f8a", + "accent_2b_alpha_a": "#14004f8a", + "accent_2b_alpha_b": "#52004f8a", + "accent_2b_alpha_c": "#80004f8a", + "bg_1": "#ff1b1d20", + "bg_2": "#ff262a2f", + "bg_3": "#ff333333", + "generic_content_high": "#ffdfdfdf", + "generic_content_highest": "#ffffffff", + "generic_content_low": "#ff777777", + "generic_content_lowest": "#ff000000", + "generic_content_medium": "#ffafafaf", + "grid_primary": "#a8393939", + "grid_secondary": "#14a6a6a6", + "gutter_2": "#ff333333", + "gutter_3": "#ff262a2f", + "knob_fill": "#ff525252", + "panel_outline_2": "#00000000", + "panel_outline_3": "#00000000", + "warning_1a": "#ffd67272", + "warning_1b": "#ff8a0000" + } +] diff --git a/src-ui/json-assets/themes/wireframe-light.json b/src-ui/json-assets/themes/wireframe-light.json new file mode 100644 index 00000000..5ef1f950 --- /dev/null +++ b/src-ui/json-assets/themes/wireframe-light.json @@ -0,0 +1,34 @@ +[ + { + "version": "1" + }, + { + "accent_1a": "#ffffb949", + "accent_1b": "#ffd09030", + "accent_2a": "#ff2788d6", + "accent_2a_alpha_a": "#142788d6", + "accent_2a_alpha_b": "#522788d6", + "accent_2a_alpha_c": "#802788d6", + "accent_2b": "#ff004f8a", + "accent_2b_alpha_a": "#14004f8a", + "accent_2b_alpha_b": "#52004f8a", + "accent_2b_alpha_c": "#80004f8a", + "bg_1": "#ffcbcdc0", + "bg_2": "#ff262a2f", + "bg_3": "#ff333333", + "generic_content_high": "#ffdfdfdf", + "generic_content_highest": "#ffffffff", + "generic_content_low": "#ff777777", + "generic_content_lowest": "#ff000000", + "generic_content_medium": "#ffafafaf", + "grid_primary": "#a8393939", + "grid_secondary": "#14a6a6a6", + "gutter_2": "#ff333333", + "gutter_3": "#ff262a2f", + "knob_fill": "#ff525252", + "panel_outline_2": "#00000000", + "panel_outline_3": "#00000000", + "warning_1a": "#ffd67272", + "warning_1b": "#ff8a0000" + } +] diff --git a/src-ui/theme/ColorMap.cpp b/src-ui/theme/ColorMap.cpp index 0a2934fe..eb41aa07 100644 --- a/src-ui/theme/ColorMap.cpp +++ b/src-ui/theme/ColorMap.cpp @@ -26,303 +26,213 @@ */ #include "ColorMap.h" +#include +#include -namespace scxt::ui::theme -{ -struct WireframeColors : ColorMap -{ - juce::Colour getImpl(ColorMap::Colors c, float alpha) const override - { - auto res = juce::Colours::red; +#include +#include +#include +#include - switch (c) - { - case accent_1a: - res = juce::Colour(0xFFFFB949); - break; - case accent_1b: - res = juce::Colour(0xFFD09030); - break; - case accent_2a: - res = juce::Colour(0xFF2788D6); - break; - case accent_2a_alpha_a: - res = getImpl(accent_2a, 0.08); - break; - case accent_2a_alpha_b: - res = getImpl(accent_2a, 0.32); - break; - case accent_2a_alpha_c: - res = getImpl(accent_2a, 0.5); - break; - case accent_2b: - res = juce::Colour(0xFF004f8A); - break; - case accent_2b_alpha_a: - res = getImpl(accent_2b, 0.08); - break; - case accent_2b_alpha_b: - res = getImpl(accent_2b, 0.32); - break; - case accent_2b_alpha_c: - res = getImpl(accent_2b, 0.5); - break; - case bg_1: - res = juce::Colour(0xFF1B1D20); - break; - case bg_2: - res = juce::Colour(0xFF262a2f); - break; - case bg_3: - res = juce::Colour(0xFF333333); - break; +#include "json/scxt_traits.h" - case knob_fill: - res = juce::Colour(82, 82, 82); - break; +#include "connectors/JSONAssetSupport.h" - case generic_content_highest: - res = juce::Colour(0xFFFFFFFF); - break; - case generic_content_high: - res = juce::Colour(0xFFDFDFDF); - break; - case generic_content_medium: - res = juce::Colour(0xFFAFAFAF); - break; - case generic_content_low: - res = juce::Colour(0xFF777777); - break; - case generic_content_lowest: - res = juce::Colour(0xFF000000); - break; +#include "utils.h" - case grid_primary: - res = juce::Colour(0xA8393939); - break; - case grid_secondary: - res = juce::Colour(0x14A6A6A6); - break; +namespace scxt::ui::theme +{ - case warning_1a: - res = juce::Colour(0xFFD67272); - break; - case warning_1b: - res = juce::Colour(0xFF8A0000); - break; +using metadata_t = std::map; +using colors_t = std::map; +using colormap_t = std::tuple; - case gutter_2: - res = getImpl(bg_3, alpha); - break; - case gutter_3: - res = getImpl(bg_2, alpha); - break; - case panel_outline_2: - case panel_outline_3: - res = juce::Colour(0x00000000); - break; - } - auto res2 = res.withAlpha(res.getAlpha() / 255.0f * alpha); - return res2; +std::string keyName(ColorMap::Colors c) +{ +#define C(x) \ + case ColorMap::Colors::x: \ + return #x; + + switch (c) + { + C(accent_1a); + C(accent_1b); + C(accent_2a); + C(accent_2a_alpha_a); + C(accent_2a_alpha_b); + C(accent_2a_alpha_c); + C(accent_2b); + C(accent_2b_alpha_a); + C(accent_2b_alpha_b); + C(accent_2b_alpha_c); + C(bg_1); + C(bg_2); + C(bg_3); + C(gutter_2); + C(gutter_3); + C(panel_outline_2); + C(panel_outline_3); + C(knob_fill); + C(generic_content_highest); + C(generic_content_high); + C(generic_content_medium); + C(generic_content_low); + C(generic_content_lowest); + C(grid_primary); + C(grid_secondary); + C(warning_1a); + C(warning_1b); } -}; +#undef C + return "error"; +} -struct TestColors : ColorMap +struct StdMapColormap : ColorMap { - juce::Colour getImpl(ColorMap::Colors c, float alpha) const override - { - auto res = juce::Colours::red; + colors_t colorMap; - switch (c) + std::array resolvedMap; + StdMapColormap(colors_t &c) { setupFromColormap(c); } + void setupFromColormap(colors_t &c) + { + colorMap = c; + std::fill(resolvedMap.begin(), resolvedMap.end(), juce::Colours::red); + std::map nameToIndex; + for (int i = 0; i < lastColor + 1; ++i) { - case accent_1a: - res = juce::Colours::orchid; - break; - case accent_1b: - res = juce::Colours::pink; - break; - case accent_2a: - res = juce::Colours::aquamarine.darker(0.3); - break; - case accent_2a_alpha_a: - res = juce::Colours::aquamarine.darker(0.6); - break; - case accent_2a_alpha_b: - res = juce::Colours::aquamarine.darker(0.6); - break; - case accent_2a_alpha_c: - res = juce::Colours::aquamarine.darker(0.6); - break; - case accent_2b: - res = juce::Colours::cyan; - break; - case accent_2b_alpha_a: - res = juce::Colours::cyan.darker(0.3); - break; - case accent_2b_alpha_b: - res = juce::Colours::cyan.darker(0.3); - break; - case accent_2b_alpha_c: - res = juce::Colours::cyan.darker(0.3); - break; - case bg_1: - res = juce::Colours::greenyellow; - break; - case bg_2: - res = juce::Colours::darkgoldenrod; - break; - case bg_3: - res = juce::Colours::pink; - break; - - case knob_fill: - res = juce::Colours::greenyellow; - break; - - case generic_content_highest: - res = juce::Colour(0xFF0000FF); - break; - case generic_content_high: - res = juce::Colour(0xFF0000DA); - break; - case generic_content_medium: - res = juce::Colour(0xFF0000AF); - break; - case generic_content_low: - res = juce::Colour(0xFF000077); - break; - case generic_content_lowest: - res = juce::Colour(0xFF000000); - break; - - case grid_primary: - res = juce::Colour(0xA8393939); - break; - case grid_secondary: - res = juce::Colour(0x14A6A6A6); - break; - - case warning_1a: - res = juce::Colour(0xFFD67272); - break; - case warning_1b: - res = juce::Colour(0xFF8A0000); - break; - - case gutter_2: - res = getImpl(bg_3, alpha); - break; - case gutter_3: - res = getImpl(bg_2, alpha); - break; - case panel_outline_2: - case panel_outline_3: - res = juce::Colour(0x00000000); - break; + nameToIndex[keyName((ColorMap::Colors(i)))] = i; + } + for (auto &[k, m] : colorMap) + { + auto n2f = nameToIndex.find(k); + if (n2f != nameToIndex.end()) + { + auto idx = n2f->second; + if (idx != -1) + { + uint32_t cx; + std::stringstream ss; + ss << std::hex << m.substr(1); + ss >> cx; + resolvedMap[idx] = juce::Colour(cx); + nameToIndex[k] = -1; + } + else + { + SCLOG("Warning: Key appears twice in colormap " << k); + } + } + else + { + SCLOG("Error: Unable to resolve colormap key '" << k << "'gre"); + } } - return res.withAlpha(alpha); + for (auto &[k, i] : nameToIndex) + { + if (i >= 0) + { + SCLOG("Error: Color map didn't contain key '" << k << "'"); + } + } + } + juce::Colour getImpl(ColorMap::Colors c, float alpha) const override + { + auto ic = (size_t)c; + auto res = resolvedMap[ic]; + if (alpha == 1.f) + return res; + + auto alp = res.getAlpha(); + auto nalp = res.getAlpha() * 1.f / 255 * alpha; + return res.withAlpha(nalp); } }; -struct HiContrastDark : ColorMap +template