Skip to content

Commit

Permalink
Merge branch 'webview-editor-refactor' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
MeijisIrlnd committed Sep 8, 2024
2 parents 06ab98c + 18c2191 commit 1a1707d
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 36 deletions.
2 changes: 1 addition & 1 deletion examples/delay/source/PluginEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "Parameters.h"
#include <magic_enum.hpp>
namespace examples::delay {
PluginEditor::PluginEditor(std::uint32_t width, std::uint32_t height) : mostly_harmless::gui::WebviewEditor(width, height) {
PluginEditor::PluginEditor(std::uint32_t width, std::uint32_t height) : mostly_harmless::gui::WebviewEditor(width, height, mostly_harmless::gui::Colour{ 0xFF89CC04 }) {
}

void PluginEditor::initialise(mostly_harmless::gui::EditorContext context) {
Expand Down
4 changes: 2 additions & 2 deletions examples/gain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ else ()
endif ()

add_custom_target(
Vite
gain-vite
ALL
DEPENDS ${GAIN_GUI_OUTPUT}
)
Expand All @@ -64,7 +64,7 @@ mostly_harmless_add_binary_data(Gain
ROOT ${PROJECT_BINARY_DIR}/gain-gui
BINARY_SOURCES ${GAIN_GUI_OUTPUT}
)
add_dependencies(WebResources Vite)
add_dependencies(WebResources gain-vite)

target_sources(Gain PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/source/Gain.cpp
Expand Down
12 changes: 6 additions & 6 deletions examples/gain/source/GainEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,25 @@
#include <mostlyharmless_WebResources.h>

namespace examples::gain {
[[nodiscard]] Resource createResourceFor(const std::string& name) {
[[nodiscard]] mostly_harmless::gui::WebviewEditor::Resource createResourceFor(const std::string& name) {
auto resOpt = mostly_harmless::WebResources::getNamedResource(name);
assert(resOpt);
auto [data, size] = *resOpt;
auto mimeType = mostly_harmless::gui::getMimeType(name);
assert(mimeType);
// Evil evil evil evil evil evil (but safe I think)
auto* asUnsigned = reinterpret_cast<const std::uint8_t*>(data);
Resource temp;
mostly_harmless::gui::WebviewEditor::Resource temp;
temp.data = { asUnsigned, asUnsigned + size };
temp.mimeType = *mimeType;
return temp;
}

GainEditor::GainEditor(std::uint32_t width, std::uint32_t height) : mostly_harmless::gui::WebviewEditor(width, height) {
GainEditor::GainEditor(std::uint32_t width, std::uint32_t height) : mostly_harmless::gui::WebviewEditor(width, height, mostly_harmless::gui::Colour(0xFF89CC04)) {
m_resources.emplace("/index.html", createResourceFor("index.html"));
m_resources.emplace("/index.css", createResourceFor("index.css"));
m_resources.emplace("/index.js", createResourceFor("index.js"));
auto fetchResourceCallback = [this](const std::string& url) -> std::optional<Resource> {
auto contentProvider = [this](const std::string& url) -> std::optional<mostly_harmless::gui::WebviewEditor::Resource> {
const auto requested = url == "/" ? "/index.html" : url;
const auto it = m_resources.find(requested);
if (it == m_resources.end()) return {};
Expand All @@ -46,9 +46,9 @@ namespace examples::gain {
}
initialDataStream << "};";
#if defined(GAIN_HOT_RELOAD)
this->setOptions({ .enableDebugMode = true, .initScript = initialDataStream.str() });
this->setOptions({ .enableDebug = true, .initScript = initialDataStream.str() });
#else
this->setOptions({ .enableDebugMode = true, .fetchResource = std::move(fetchResourceCallback), .initScript = initialDataStream.str() });
this->setOptions({ .enableDebug = true, .contentProvider = std::move(contentProvider), .initScript = initialDataStream.str() });
#endif
}

Expand Down
3 changes: 1 addition & 2 deletions examples/gain/source/GainEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "Parameters.h"
#include <mostly_harmless/gui/mostlyharmless_WebviewEditor.h>
namespace examples::gain {
using Resource = choc::ui::WebView::Options::Resource;
class GainEditor : public mostly_harmless::gui::WebviewEditor {
public:
GainEditor(std::uint32_t width, std::uint32_t height);
Expand All @@ -18,7 +17,7 @@ namespace examples::gain {
private:
// Usually I'd have this as a static in the TU, but because the underlying map `getNamedResource()` queries is also static, it leads to weird issues with init-order
// If I find a way to guarantee the order, I'll probably switch to that approach instead, but for now this will have to do
std::unordered_map<std::string, Resource> m_resources;
std::unordered_map<std::string, mostly_harmless::gui::WebviewEditor::Resource> m_resources;
};
} // namespace examples::gain

Expand Down
1 change: 1 addition & 0 deletions include/mostly_harmless/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(MOSTLYHARMLESS_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/gui/mostlyharmless_EditorContext.h
${CMAKE_CURRENT_SOURCE_DIR}/gui/mostlyharmless_IEditor.h
${CMAKE_CURRENT_SOURCE_DIR}/gui/mostlyharmless_WebviewEditor.h
${CMAKE_CURRENT_SOURCE_DIR}/gui/mostlyharmless_Colour.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_TaskThread.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_Timer.h
${CMAKE_CURRENT_SOURCE_DIR}/events/mostlyharmless_ParamEvent.h
Expand Down
36 changes: 36 additions & 0 deletions include/mostly_harmless/gui/mostlyharmless_Colour.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// Created by Syl on 08/09/2024.
//

#ifndef MOSTLY_HARMLESS_COLOUR_H
#define MOSTLY_HARMLESS_COLOUR_H
#include <cstdint>
namespace mostly_harmless::gui {
/**
* \brief Convenience struct representing a colour.
*/
struct Colour final {
/**
* Constructs a colour from an ARGB hex colour, in the format `0xAARRGGBB` - for example, fully opaque red would be `0xFFFF0000`
* \param argb The hex code for the desired colour.
*/
explicit Colour(std::uint32_t argb);
/**
* Constructs a colour from individual (0 to 255) rgb args. In this overload, alpha defaults to 255.
* \param r_ The 0 to 255 value for red.
* \param g_ The 0 to 255 value for green.
* \param b_ The 0 to 255 value for blue.
*/
Colour(std::uint8_t r_, std::uint8_t g_, std::uint8_t b_);
/**
* Constructs a colour from individual (0 to 255) argb args.
* \param a_ The 0 to 255 value for alpha (255 being fully opaque)
* \param r_ The 0 to 255 value for red.
* \param g_ The 0 to 255 value for green.
* \param b_ The 0 to 255 value for blue.
*/
Colour(std::uint8_t a_, std::uint8_t r_, std::uint8_t g_, std::uint8_t b_);
std::uint8_t a, r, g, b;
};
} // namespace mostly_harmless::gui
#endif // MOSTLY_HARMLESS_COLOUR_H
69 changes: 66 additions & 3 deletions include/mostly_harmless/gui/mostlyharmless_WebviewEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef MOSTLYHARMLESS_MOSTLYHARMLESS_WEBVIEWEDITOR_H
#define MOSTLYHARMLESS_MOSTLYHARMLESS_WEBVIEWEDITOR_H
#include <mostly_harmless/gui/mostlyharmless_IEditor.h>
#include <mostly_harmless/gui/mostlyharmless_Colour.h>
#include <choc/gui/choc_WebView.h>
#include <optional>
#include <string>
Expand All @@ -22,23 +23,85 @@ namespace mostly_harmless::gui {
*
* Provides the basic setup code for the Webview, but you'll likely want to derive from this, and override some of its functions.
* The underlying `choc::ui::WebView` can be accessed via the protected `m_internalWebview` member.
* If you don't call `setOptions` before initialise is called, then the internal webview will be constructed with some default options, namely:
*
* ```
* enableDebug = false
* transparentBackground = true
* ```
*
*/
class WebviewEditor : public IEditor {
public:
/**
* \brief Tiny container struct for web resources.
*
* If serving from RAM, your editor should hold an internal map of `route:Resource`, populated in your constructor. <br>
* MIME types can be retrieved with mostly_harmless::gui::getMimeType().
*/
struct Resource {
Resource() = default;
/**
* Constructs a Resource from a char[] and a mime type.
* \param content A char[] containing the data for this resource.
* \param mimeType_ The associated MIME type for this resource.
*/
Resource(std::string_view content, std::string mimeType_);
/**
* The binary data for this resource.
*/
std::vector<std::uint8_t> data;
/**
* The associated MIME type for this resource.
*/
std::string mimeType;
};

/**
* \brief Contains a set of options to construct the internal webview with.
*/
struct Options {
/**
* If true, the user will be able to right click / inspect element / etc. If false, that behaviour is disabled.
*/
bool enableDebug{ false };
/**
* If not serving from ram, leave this as a nullptr, and call `navigate` instead.<br>
* If serving the content from ram, the webview will query the backend for files to load, with a call to this lambda.<br>
* As mentioned in the docs for Resource, you should load these at construction, and keep a map `route:Resource` on hand. This lambda then, should query that map for the requested route, and return the associated resource if
* it exists, std::nullopt otherwise. Assuming a `std::unordered_map<std::string, mostly_harmless::gui::WebviewEditor::Resource>` called `m_resourceMap`, an implementation could be along the lines of:
*
* ```cpp
* const auto requested = url == "/" ? "/index.html" : url;
* const auto it = m_resources.find(requested);
* if (it == m_resources.end()) return {};
* auto resource = it->second;
* return resource;
* ```
*
*/
std::function<std::optional<Resource>(const std::string&)> contentProvider{ nullptr };
/**
* An optional (javascript) script to be executed before the page loads. If you're hosting from RAM, prefer this to the internal webview's addInitScript function - this is because internally in choc, navigate is called before the init script
* is added, meaning that a script added with addInitScript won't execute until a refresh. This arg sidesteps that, by passing it into the internal webview's constructor.
*/
std::optional<std::string> initScript{};
};
/**
* \param initialWidth The initial width for the webview.
* \param initialHeight The initial height for the webview.
* \param backgroundColour The colour to paint the actual window beneath the webview.
*/
WebviewEditor(std::uint32_t initialWidth, std::uint32_t initialHeight);
WebviewEditor(std::uint32_t initialWidth, std::uint32_t initialHeight, Colour backgroundColour);
/**
* Non default destructor for pimpl
*/
~WebviewEditor() noexcept override;
/**
* Specify some options to pass to the internal webview's constructor - note that this *must* be called *before* initialise (ie in your constructor) for them to get picked up.
* Specify some options to pass to the internal webview's constructor - note that this *must* be called *before* initialise (ie in your constructor) for them to get picked up.<br>
* \param opts The options to pass to the internal webview
*/
void setOptions(choc::ui::WebView::Options&& opts) noexcept;
void setOptions(Options&& options) noexcept;
/**
* Implementation of mostly_harmless::gui::IEditor::initialise().
* \param context The editor context (see IEditor::initialise() and EditorContext for more details).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#ifndef MOSTLYHARMLESS_MOSTLYHARMLESS_GUIHELPERSMACOS_H
#define MOSTLYHARMLESS_MOSTLYHARMLESS_GUIHELPERSMACOS_H
#include <mostly_harmless/gui/mostlyharmless_Colour.h>
#include <cstdint>
namespace mostly_harmless::gui::helpers::macos {
/**
Expand All @@ -30,7 +31,7 @@ namespace mostly_harmless::gui::helpers::macos {
* \param parentViewHandle A void* to the NSView to add the child view to.
* \param childViewHandle A void* to the NSView to add to the parent view.
*/
void reparentView(void* parentViewHandle, void* childViewHandle, std::uint32_t backgroundColour);
void reparentView(void* parentViewHandle, void* childViewHandle, Colour backgroundColour);
/**
* Sets an NSView as visible.
* \param viewHandle A void* to the NSView to set visible.
Expand Down
1 change: 1 addition & 0 deletions source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(MOSTLYHARMLESS_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/mostlyharmless_Plugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/events/mostlyharmless_EventContext.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gui/mostlyharmless_WebviewEditor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gui/mostlyharmless_Colour.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_TaskThread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_Timer.cpp
${PLATFORM_SOURCES}
Expand Down
18 changes: 18 additions & 0 deletions source/gui/mostlyharmless_Colour.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Created by Syl on 08/09/2024.
//
#include <mostly_harmless/gui/mostlyharmless_Colour.h>
namespace mostly_harmless::gui {
Colour::Colour(std::uint32_t argb) {
a = static_cast<std::uint8_t>((argb >> 24) & 0xFF);
r = static_cast<std::uint8_t>((argb >> 16) & 0xFF);
g = static_cast<std::uint8_t>((argb >> 8) & 0xFF);
b = static_cast<std::uint8_t>(argb & 0xFF);
}

Colour::Colour(std::uint8_t r_, std::uint8_t g_, std::uint8_t b_) : a(static_cast<std::uint8_t>(255)), r(r_), g(g_), b(b_) {
}

Colour::Colour(std::uint8_t a_, std::uint8_t r_, std::uint8_t g_, std::uint8_t b_) : a(a_), r(r_), g(g_), b(b_) {
}
} // namespace mostly_harmless::gui
Loading

0 comments on commit 1a1707d

Please sign in to comment.