Signed-off-by: falkTX <falktx@falktx.com>undefined
| @@ -82,11 +82,21 @@ | |||
| #define WEB_VIEW_DELEGATE_CLASS_NAME \ | |||
| MACRO_NAME(WebViewDelegate_, _, DISTRHO_NAMESPACE) | |||
| @interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKUIDelegate> | |||
| // FIXME | |||
| static bool loaded = false; | |||
| @interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate> | |||
| @end | |||
| @implementation WEB_VIEW_DELEGATE_CLASS_NAME | |||
| - (void)webView:(WKWebView *)webview | |||
| didFinishNavigation:(WKNavigation*)navigation | |||
| { | |||
| d_stdout("page loaded"); | |||
| loaded = true; | |||
| } | |||
| - (void)webView:(WKWebView*)webview | |||
| runJavaScriptAlertPanelWithMessage:(NSString*)message | |||
| initiatedByFrame:(WKFrameInfo*)frame | |||
| @@ -181,6 +191,15 @@ | |||
| }); | |||
| } | |||
| - (void)userContentController:(WKUserContentController*)userContentController | |||
| didReceiveScriptMessage:(WKScriptMessage*)message | |||
| { | |||
| NSString* const nsstring = static_cast<NSString*>([message body]); | |||
| const char* const string = [nsstring UTF8String]; | |||
| d_stdout("JS call received '%s'", string); | |||
| } | |||
| @end | |||
| #endif // WEB_VIEW_USING_MACOS_WEBKIT | |||
| @@ -349,25 +368,75 @@ WebViewHandle webViewCreate(const uintptr_t windowId, | |||
| (initialHeight - options.offset.y)); | |||
| WKPreferences* const prefs = [[WKPreferences alloc] init]; | |||
| [prefs setValue:@YES forKey:@"developerExtrasEnabled"]; | |||
| [prefs setValue:@YES forKey:@"javaScriptCanAccessClipboard"]; | |||
| [prefs setValue:@YES forKey:@"DOMPasteAllowed"]; | |||
| // if (debug) | |||
| { | |||
| [prefs setValue:@YES forKey:@"developerExtrasEnabled"]; | |||
| // TODO enable_write_console_messages_to_stdout | |||
| } | |||
| WKWebViewConfiguration* const config = [[WKWebViewConfiguration alloc] init]; | |||
| config.limitsNavigationsToAppBoundDomains = false; | |||
| config.preferences = prefs; | |||
| WKWebView* const webview = [[WKWebView alloc] initWithFrame:rect | |||
| configuration:config]; | |||
| [webview setHidden:YES]; | |||
| [view addSubview:webview]; | |||
| // TODO webkit_web_view_set_background_color | |||
| WEB_VIEW_DELEGATE_CLASS_NAME* const delegate = [[WEB_VIEW_DELEGATE_CLASS_NAME alloc] init]; | |||
| webview.navigationDelegate = delegate; | |||
| webview.UIDelegate = delegate; | |||
| const char* const url = "https://mastodon.falktx.com/"; | |||
| if (WKUserContentController* const controller = [config userContentController]) | |||
| { | |||
| [controller retain]; | |||
| [controller addScriptMessageHandler:delegate name:@"external"]; | |||
| } | |||
| const char* const url = "file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/index.html"; | |||
| NSString* const nsurl = [[NSString alloc] initWithBytes:url | |||
| length:std::strlen(url) | |||
| encoding:NSUTF8StringEncoding]; | |||
| NSURLRequest* const urlreq = [[NSURLRequest alloc] initWithURL: [NSURL URLWithString: nsurl]]; | |||
| [webview loadRequest:urlreq]; | |||
| // [webview loadRequest:urlreq]; | |||
| [webview loadFileRequest:urlreq | |||
| allowingReadAccessToURL:[NSURL URLWithString:@"file:///Users/falktx/Source/DISTRHO/DPF/examples/WebMeters/"]]; | |||
| d_stdout("waiting for load"); | |||
| if (! loaded) | |||
| { | |||
| NSAutoreleasePool* const pool = [[NSAutoreleasePool alloc] init]; | |||
| NSDate* const date = [NSDate distantPast]; | |||
| NSEvent* event; | |||
| while (! loaded) | |||
| { | |||
| event = [NSApp | |||
| #ifdef __MAC_10_12 | |||
| nextEventMatchingMask:NSEventMaskAny | |||
| #else | |||
| nextEventMatchingMask:NSAnyEventMask | |||
| #endif | |||
| untilDate:date | |||
| inMode:NSDefaultRunLoopMode | |||
| dequeue:YES]; | |||
| if (event == nil) | |||
| break; | |||
| [NSApp sendEvent: event]; | |||
| } | |||
| [pool release]; | |||
| } | |||
| [webview setHidden:NO]; | |||
| [nsurl release]; | |||
| @@ -441,26 +510,26 @@ void webViewDestroy(const WebViewHandle handle) | |||
| { | |||
| #if WEB_VIEW_USING_CHOC | |||
| delete handle->webview; | |||
| delete handle; | |||
| #elif WEB_VIEW_USING_MACOS_WEBKIT | |||
| [handle->webview setHidden:YES]; | |||
| [handle->webview removeFromSuperview]; | |||
| [handle->urlreq release]; | |||
| [handle->delegate release]; | |||
| delete handle; | |||
| #elif WEB_VIEW_USING_X11_IPC | |||
| XCloseDisplay(handle->display); | |||
| delete handle; | |||
| #endif | |||
| // maybe unused | |||
| (void)handle; | |||
| delete handle; | |||
| } | |||
| void webViewEvaluateJS(const WebViewHandle handle, const char* const js) | |||
| { | |||
| #if WEB_VIEW_USING_CHOC | |||
| #elif WEB_VIEW_USING_MACOS_WEBKIT | |||
| NSString* const nsjs = [[NSString alloc] initWithBytes:js | |||
| length:std::strlen(js) | |||
| encoding:NSUTF8StringEncoding]; | |||
| [handle->webview evaluateJavaScript:nsjs completionHandler:nullptr]; | |||
| [nsjs release]; | |||
| #elif WEB_VIEW_USING_X11_IPC | |||
| handle->p.signal(SIGUSR2); | |||
| #endif | |||
| @@ -705,6 +774,7 @@ static bool gtk3(Display* const display, | |||
| WebKitSettings* const settings = webkit_settings_new(); | |||
| DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false); | |||
| // TODO DOMPasteAllowed | |||
| webkit_settings_set_javascript_can_access_clipboard(settings, true); | |||
| webkit_settings_set_hardware_acceleration_policy(settings, 2 /* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */); | |||
| @@ -58,8 +58,10 @@ struct WebViewOptions { | |||
| This means it will draw on top of whatever is below it, | |||
| something to take into consideration if mixing regular widgets with web views. | |||
| Provided metrics must not have scale factor pre-applied. | |||
| @p windowId: The native window id to attach this view to (X11 Window, HWND or NSView*) | |||
| @p scaleFactor: Scale factor to use (only used on X11) | |||
| @p scaleFactor: Scale factor to use (ignored on macOS) | |||
| @p options: Extra options, optional | |||
| */ | |||
| WebViewHandle webViewCreate(uintptr_t windowId, | |||
| @@ -112,8 +112,8 @@ protected: | |||
| static const Color kColorYellow(255, 255, 0); | |||
| // get meter values | |||
| const float outLeft(fOutLeft); | |||
| const float outRight(fOutRight); | |||
| const float outLeft = fOutLeft; | |||
| const float outRight = fOutRight; | |||
| // tell DSP side to reset meter values | |||
| setState("reset", ""); | |||
| @@ -237,7 +237,8 @@ protected: | |||
| { | |||
| fOutLeft = tmpLeft; | |||
| fOutRight = tmpRight; | |||
| fNeedsReset = false; | |||
| // TODO | |||
| // fNeedsReset = false; | |||
| } | |||
| else | |||
| { | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -24,9 +24,8 @@ class ExampleUIMeters : public UI | |||
| { | |||
| public: | |||
| ExampleUIMeters() | |||
| : UI(600, 400) | |||
| : UI(600, 400, true) | |||
| { | |||
| setGeometryConstraints(600, 400, false); | |||
| } | |||
| protected: | |||
| @@ -39,8 +38,14 @@ protected: | |||
| */ | |||
| void parameterChanged(uint32_t index, float value) override | |||
| { | |||
| d_stdout("param changed %u %f", index, value); | |||
| evaluateJS("if (typeof(parameterChanged) === 'function') { parameterChanged(0, 0); }"); | |||
| // d_stdout("param changed %u %f", index, value); | |||
| char msg[512]; | |||
| { | |||
| const ScopedSafeLocale ssl; | |||
| std::snprintf(msg, sizeof(msg) - 1, | |||
| "typeof(parameterChanged) === 'function' && parameterChanged(%u, %f)", index, value); | |||
| } | |||
| evaluateJS(msg); | |||
| } | |||
| /** | |||
| @@ -4,22 +4,129 @@ | |||
| <meta charset="utf-8"> | |||
| <title></title> | |||
| <script> | |||
| const METER_COLOR_GREEN = 0; | |||
| const METER_COLOR_BLUE = 1; | |||
| const kSmoothMultiplier = 3.0; | |||
| let fColorValue = null; | |||
| let fColor = 'rgb(93, 231, 61)'; | |||
| let fOutLeft = 0.0; | |||
| let fOutRight = 0.0; | |||
| setTimeout(function() { | |||
| document.getElementById('user-agent').textContent = window.navigator.userAgent; | |||
| }, 1) | |||
| function repaint() { | |||
| const lmeter = document.getElementById('left-meter-x'); | |||
| const rmeter = document.getElementById('right-meter-x'); | |||
| lmeter.setAttribute('style', 'background:' + fColor + ';top:' + (100 * (1.0 - fOutLeft)) + '%;height:' + (100 * fOutLeft) + '%'); | |||
| rmeter.setAttribute('style', 'background:' + fColor + ';top:' + (100 * (1.0 - fOutRight)) + '%;height:' + (100 * fOutRight) + '%'); | |||
| } | |||
| function updateColor(color) { | |||
| if (fColorValue === color) | |||
| return; | |||
| fColorValue = color; | |||
| switch (color) { | |||
| case METER_COLOR_GREEN: | |||
| fColor = "rgb(93, 231, 61)"; | |||
| break; | |||
| case METER_COLOR_BLUE: | |||
| fColor = "rgb(82, 238, 248)"; | |||
| break; | |||
| } | |||
| repaint(); | |||
| } | |||
| function parameterChanged(index, value) { | |||
| console.log("parameterChanged", index, value); | |||
| switch (index) { | |||
| case 0: // color | |||
| updateColor(parseInt(Math.round(value))); | |||
| break; | |||
| case 1: // out-left | |||
| value = (fOutLeft * kSmoothMultiplier + value) / (kSmoothMultiplier + 1.0); | |||
| /**/ if (value < 0.001) value = 0.0; | |||
| else if (value > 0.999) value = 1.0; | |||
| if (fOutLeft != value) | |||
| { | |||
| fOutLeft = value; | |||
| repaint(); | |||
| } | |||
| break; | |||
| case 2: // out-right | |||
| value = (fOutRight * kSmoothMultiplier + value) / (kSmoothMultiplier + 1.0); | |||
| /**/ if (value < 0.001) value = 0.0; | |||
| else if (value > 0.999) value = 1.0; | |||
| if (fOutRight != value) | |||
| { | |||
| fOutRight = value; | |||
| repaint(); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| </script> | |||
| <style> | |||
| html, body { | |||
| background: transparent; | |||
| background: grey; | |||
| color: white; | |||
| margin: 0; | |||
| padding: 0; | |||
| } | |||
| body { | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| p { | |||
| margin: 6px; | |||
| font-size: 15px; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| width: calc(100% - 12px); | |||
| height: 15px; | |||
| white-space: nowrap; | |||
| } | |||
| #meters { | |||
| display: flex; | |||
| flex-direction: row; | |||
| } | |||
| .meter { | |||
| background: black; | |||
| margin: 6px; | |||
| margin-top: 0px; | |||
| width: calc(50vw - 9px); | |||
| height: calc(100vh - 12px - 6px - 15px); | |||
| } | |||
| .meter:first-child { | |||
| margin-right: 3px; | |||
| } | |||
| .meter:last-child { | |||
| margin-left: 3px; | |||
| } | |||
| .meter-x { | |||
| background: rgb(93, 231, 61); | |||
| position: relative; | |||
| top: 0%; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 0%; | |||
| } | |||
| </style> | |||
| </head> | |||
| <body> | |||
| <header>Hello World!</header> | |||
| <main> | |||
| <p>This is my text, nice neato.</p> | |||
| </main> | |||
| <footer></footer> | |||
| <p id="user-agent"> </p> | |||
| <div id="meters"> | |||
| <div class="meter" id="left-meter"> | |||
| <div class="meter-x" id="left-meter-x"></div> | |||
| </div> | |||
| <div class="meter" id="right-meter"> | |||
| <div class="meter-x" id="right-meter-x"></div> | |||
| </div> | |||
| </div> | |||
| </body> | |||
| </html> | |||