Skip to content

Commit

Permalink
User editable and streamable ColorMap files (#1132)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
baconpaul authored Aug 17, 2024
1 parent b47fb65 commit d96d315
Show file tree
Hide file tree
Showing 32 changed files with 449 additions and 287 deletions.
6 changes: 3 additions & 3 deletions src-ui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 44 additions & 10 deletions src-ui/components/SCXTEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<SCXTJuceLookAndFeel>();
Expand Down Expand Up @@ -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<theme::ColorMap> 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
6 changes: 5 additions & 1 deletion src-ui/components/SCXTEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -281,6 +282,9 @@ struct SCXTEditor : sst::jucegui::components::WindowPanel, juce::DragAndDropCont
}

std::unique_ptr<melatonin::Inspector> melatoninInspector;

public:
std::unique_ptr<juce::FileChooser> fileChooser;
};

template <typename T> inline void HasEditor::sendToSerialization(const T &msg)
Expand Down
47 changes: 47 additions & 0 deletions src-ui/components/SCXTEditorMenus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -226,6 +228,7 @@ void SCXTEditor::addUIThemesMenu(juce::PopupMenu &p, bool addTitle)
p.addSectionHeader("Themes");
std::vector<std::pair<theme::ColorMap::BuiltInColorMaps, std::string>> maps = {
{theme::ColorMap::WIREFRAME, "Wireframe Colors"},
{theme::ColorMap::LIGHT, "Wireframe Light"},
{theme::ColorMap::HICONTRAST_DARK, "High Contrast Dark"},
{theme::ColorMap::TEST, "Test Colors"},
};
Expand All @@ -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<juce::FileChooser>(
"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<juce::FileChooser>(
"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)]() {
Expand Down
4 changes: 2 additions & 2 deletions src-ui/components/mixer/PartEffectsPane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -303,7 +303,7 @@ template <typename T> 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
{
Expand Down
4 changes: 2 additions & 2 deletions src-ui/components/multi/ProcessorPane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@
#include <utils.h>

#include <filesystem/import.h>
#include "JSONLayoutConsumer.h"
#include "JSONAssetSupport.h"

#include <cmrc/cmrc.hpp>

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};
Expand All @@ -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());
Expand Down Expand Up @@ -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());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 `<scroot>/src-ui/json-layout`)
to the json-assets directory (so to `<scroot>/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
Expand Down Expand Up @@ -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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
34 changes: 34 additions & 0 deletions src-ui/json-assets/themes/test-colors.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
35 changes: 35 additions & 0 deletions src-ui/json-assets/themes/wireframe-dark-hicontrast.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
Loading

0 comments on commit d96d315

Please sign in to comment.