closes #7
Processor editor and processor in seperate files. slider paramters now can be added by simply adding them in the processor, everything else is dynamic
This commit is contained in:
185
Source/PluginEditor.cpp
Normal file
185
Source/PluginEditor.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
PluginEditor.cpp
|
||||
Created: 4 Nov 2025 6:20:46pm
|
||||
Author: mickl
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "PluginEditor.h"
|
||||
#include "DemoUtilities.h"
|
||||
|
||||
|
||||
|
||||
static ZipFile* getZipFile()
|
||||
{
|
||||
static auto stream = createAssetInputStream("webviewplugin-gui_1.0.0.zip", AssertAssetExists::no);
|
||||
|
||||
if (stream == nullptr)
|
||||
return nullptr;
|
||||
|
||||
static ZipFile f{ stream.get(), false };
|
||||
return &f;
|
||||
}
|
||||
|
||||
static const char* getMimeForExtension(const String& extension)
|
||||
{
|
||||
static const std::unordered_map<String, const char*> mimeMap =
|
||||
{
|
||||
{ { "htm" }, "text/html" },
|
||||
{ { "html" }, "text/html" },
|
||||
{ { "txt" }, "text/plain" },
|
||||
{ { "jpg" }, "image/jpeg" },
|
||||
{ { "jpeg" }, "image/jpeg" },
|
||||
{ { "svg" }, "image/svg+xml" },
|
||||
{ { "ico" }, "image/vnd.microsoft.icon" },
|
||||
{ { "json" }, "application/json" },
|
||||
{ { "png" }, "image/png" },
|
||||
{ { "css" }, "text/css" },
|
||||
{ { "map" }, "application/json" },
|
||||
{ { "js" }, "text/javascript" },
|
||||
{ { "woff2" }, "font/woff2" }
|
||||
};
|
||||
|
||||
if (const auto it = mimeMap.find(extension.toLowerCase()); it != mimeMap.end())
|
||||
return it->second;
|
||||
|
||||
jassertfalse;
|
||||
return "";
|
||||
}
|
||||
|
||||
static String getExtension(String filename)
|
||||
{
|
||||
return filename.fromLastOccurrenceOf(".", false, false);
|
||||
}
|
||||
|
||||
static auto streamToVector(InputStream& stream)
|
||||
{
|
||||
std::vector<std::byte> result((size_t)stream.getTotalLength());
|
||||
stream.setPosition(0);
|
||||
[[maybe_unused]] const auto bytesRead = stream.read(result.data(), result.size());
|
||||
jassert(bytesRead == (ssize_t)result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<WebBrowserComponent::Resource> WebViewPluginAudioProcessorEditor::getResource(const String& url)
|
||||
{
|
||||
const auto urlToRetrive = url == "/" ? String{ "index.html" }
|
||||
: url.fromFirstOccurrenceOf("/", false, false);
|
||||
|
||||
if (auto* archive = getZipFile())
|
||||
{
|
||||
if (auto* entry = archive->getEntry(urlToRetrive))
|
||||
{
|
||||
auto stream = rawToUniquePtr(archive->createStreamForEntry(*entry));
|
||||
auto v = streamToVector(*stream);
|
||||
auto mime = getMimeForExtension(getExtension(entry->filename).toLowerCase());
|
||||
return WebBrowserComponent::Resource{ std::move(v),
|
||||
std::move(mime) };
|
||||
}
|
||||
}
|
||||
|
||||
if (urlToRetrive == "index.html")
|
||||
{
|
||||
auto fallbackIndexHtml = createAssetInputStream("webviewplugin-gui-fallback.html");
|
||||
return WebBrowserComponent::Resource{ streamToVector(*fallbackIndexHtml),
|
||||
String { "text/html" } };
|
||||
}
|
||||
|
||||
if (urlToRetrive == "data.txt")
|
||||
{
|
||||
WebBrowserComponent::Resource resource;
|
||||
static constexpr char testData[] = "testdata";
|
||||
MemoryInputStream stream{ testData, numElementsInArray(testData) - 1, false };
|
||||
return WebBrowserComponent::Resource{ streamToVector(stream), String { "text/html" } };
|
||||
}
|
||||
|
||||
if (urlToRetrive == "midNoteData.json")
|
||||
{
|
||||
|
||||
juce::Array<var> notes;
|
||||
int voice_num = 0;
|
||||
for (auto& voice : processorRef.shifter.voices) {
|
||||
if (voice.onoff_) {
|
||||
auto obj = new DynamicObject();
|
||||
obj->setProperty("voice", voice_num);
|
||||
obj->setProperty("midi", voice.GetMidiNote());
|
||||
notes.add(var(obj));
|
||||
}
|
||||
voice_num++;
|
||||
}
|
||||
|
||||
DynamicObject::Ptr d(new DynamicObject());
|
||||
d->setProperty("notes", notes);
|
||||
|
||||
const auto s = JSON::toString(d.get());
|
||||
MemoryInputStream stream{ s.getCharPointer(), s.getNumBytesAsUTF8(), false };
|
||||
return WebBrowserComponent::Resource{ streamToVector(stream), String { "application/json" } };
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#if JUCE_ANDROID
|
||||
// The localhost is available on this address to the emulator
|
||||
const String localDevServerAddress = "http://10.0.2.2:3000/";
|
||||
#else
|
||||
const String localDevServerAddress = "http://localhost:3000/";
|
||||
#endif
|
||||
|
||||
bool SinglePageBrowser::pageAboutToLoad(const String& newURL)
|
||||
{
|
||||
return newURL == localDevServerAddress || newURL == getResourceProviderRoot();
|
||||
}
|
||||
|
||||
|
||||
WebViewPluginAudioProcessorEditor::WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor& p)
|
||||
: AudioProcessorEditor(&p), processorRef(p)
|
||||
{
|
||||
auto options = WebBrowserComponent::Options{}
|
||||
.withBackend(WebBrowserComponent::Options::Backend::webview2)
|
||||
.withWinWebView2Options(WebBrowserComponent::Options::WinWebView2{}
|
||||
.withUserDataFolder(File::getSpecialLocation(File::SpecialLocationType::tempDirectory)))
|
||||
.withNativeIntegrationEnabled()
|
||||
.withOptionsFrom(controlParameterIndexReceiver)
|
||||
.withResourceProvider([this](const auto& url)
|
||||
{
|
||||
return getResource(url);
|
||||
},
|
||||
URL{ localDevServerAddress }.getOrigin());
|
||||
|
||||
|
||||
for (auto& sliderId : p.parameters.sliderIds) {
|
||||
slider_relays.push_back(new WebSliderRelay{ sliderId });
|
||||
slider_attatchments.push_back(new
|
||||
WebSliderParameterAttachment(
|
||||
*processorRef.state.getParameter(sliderId),
|
||||
*slider_relays.back(),
|
||||
processorRef.state.undoManager));
|
||||
options = options.withOptionsFrom(*slider_relays.back());
|
||||
}
|
||||
|
||||
webComponent = new SinglePageBrowser(options);
|
||||
addAndMakeVisible(*webComponent);
|
||||
|
||||
webComponent->goToURL(localDevServerAddress);
|
||||
//webComponent.goToURL (WebBrowserComponent::getResourceProviderRoot());
|
||||
|
||||
setSize(500, 500);
|
||||
|
||||
startTimerHz(60);
|
||||
}
|
||||
|
||||
void WebViewPluginAudioProcessorEditor::paint(Graphics& g)
|
||||
{
|
||||
// (Our component is opaque, so we must completely fill the background with a solid colour)
|
||||
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
|
||||
}
|
||||
|
||||
void WebViewPluginAudioProcessorEditor::resized()
|
||||
{
|
||||
if (webComponent == nullptr) return;
|
||||
webComponent->setBounds(getLocalBounds());
|
||||
}
|
||||
Reference in New Issue
Block a user