Merge branch 'lm_webview_improvements'

This commit is contained in:
Lukas Matena 2024-04-12 09:28:50 +02:00
commit ca27a288c8
17 changed files with 57 additions and 306 deletions

View File

@ -613,14 +613,6 @@ function(prusaslicer_copy_dlls target)
COMMAND ${CMAKE_COMMAND} -E copy ${TOP_LEVEL_PROJECT_DIR}/deps/+MPFR/mpfr/lib/win${_bits}/libmpfr-4.dll ${_out_dir}
COMMENT "Copy mpfr runtime to build tree"
VERBATIM)
if(DEFINED DESTDIR)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${DESTDIR}/usr/local/bin/WebView2Loader.dll ${_out_dir}
COMMENT "Copy WebView2Loader runtime to build tree"
VERBATIM)
endif ()
endfunction()

View File

@ -1,60 +0,0 @@
if (MSVC)
# Update the following variables if updating WebView2 SDK
set(WEBVIEW2_VERSION "1.0.705.50")
set(WEBVIEW2_URL "https://www.nuget.org/api/v2/package/Microsoft.Web.WebView2/${WEBVIEW2_VERSION}")
set(WEBVIEW2_SHA256 "6a34bb553e18cfac7297b4031f3eac2558e439f8d16a45945c22945ac404105d")
set(WEBVIEW2_DEFAULT_PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/dep_WebView2-prefix/packages/Microsoft.Web.WebView2.${WEBVIEW2_VERSION}")
set(WEBVIEW2_DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/dep_WebView2-prefix/download")
#message(STATUS "WEBVIEW2_DEFAULT_PACKAGE_DIR = ${WEBVIEW2_DEFAULT_PACKAGE_DIR}")
if(NOT EXISTS ${WEBVIEW2_PACKAGE_DIR})
unset(WEBVIEW2_PACKAGE_DIR CACHE)
endif()
set(WEBVIEW2_PACKAGE_DIR ${WEBVIEW2_DEFAULT_PACKAGE_DIR} CACHE PATH "WebView2 SDK PATH" FORCE)
#file(MAKE_DIRECTORY ${DEP_DOWNLOAD_DIR}/WebView2)
message(STATUS "WEBVIEW2_URL = ${WEBVIEW2_URL}")
message(STATUS "WEBVIEW2_DOWNLOAD_DIR = ${WEBVIEW2_DOWNLOAD_DIR}")
file(DOWNLOAD
${WEBVIEW2_URL}
${WEBVIEW2_DOWNLOAD_DIR}/WebView2.nuget
EXPECTED_HASH SHA256=${WEBVIEW2_SHA256})
file(MAKE_DIRECTORY ${WEBVIEW2_PACKAGE_DIR})
execute_process(COMMAND
${CMAKE_COMMAND} -E tar x ${WEBVIEW2_DOWNLOAD_DIR}/WebView2.nuget
WORKING_DIRECTORY ${WEBVIEW2_PACKAGE_DIR}
)
set(_srcdir ${WEBVIEW2_PACKAGE_DIR}/build/native)
set(_dstdir ${${PROJECT_NAME}_DEP_INSTALL_PREFIX})
set(_output ${_dstdir}/include/WebView2.h
${_dstdir}/bin/WebView2Loader.dll)
if(NOT EXISTS ${_dstdir}/include)
file(MAKE_DIRECTORY ${_dstdir}/include)
endif()
if(NOT EXISTS ${_dstdir}/bin)
file(MAKE_DIRECTORY ${_dstdir}/bin)
endif()
add_custom_command(
OUTPUT ${_output}
COMMAND ${CMAKE_COMMAND} -E copy ${_srcdir}/include/WebView2.h ${_dstdir}/include/
COMMAND ${CMAKE_COMMAND} -E copy ${_srcdir}/x${DEPS_BITS}/WebView2Loader.dll ${_dstdir}/bin/
)
add_custom_target(dep_WebView2 SOURCES ${_output})
set(WEBVIEW2_PACKAGE_DIR ${WEBVIEW2_PACKAGE_DIR} CACHE INTERNAL "" FORCE)
endif ()

View File

@ -16,6 +16,7 @@ endif()
if (MSVC)
set(_wx_webview "-DwxUSE_WEBVIEW_EDGE=ON")
else ()
set(_wx_webview "-DwxUSE_WEBVIEW=ON")
endif ()
@ -56,3 +57,14 @@ add_cmake_project(wxWidgets
)
set(DEP_wxWidgets_DEPENDS ZLIB PNG EXPAT JPEG NanoSVG)
if (MSVC)
# After the build, copy the WebView2Loader.dll into the installation directory.
# This should probably be done better.
add_custom_command(TARGET dep_wxWidgets POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_BINARY_DIR}/builds/wxWidgets/lib/vc_x64_lib/WebView2Loader.dll"
"${${PROJECT_NAME}_DEP_INSTALL_PREFIX}/bin/WebView2Loader.dll")
endif()

View File

@ -212,6 +212,13 @@ if (WIN32)
COMMENT "Symlinking the resources directory into the build tree"
VERBATIM
)
if (SLIC3R_GUI)
add_custom_command(TARGET PrusaSlicer POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${wxWidgets_ROOT_DIR}/bin/WebView2Loader.dll"
"${CMAKE_CURRENT_BINARY_DIR}/${CONF}/WebView2Loader.dll")
endif()
endforeach ()
else ()
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/resources" WIN_RESOURCES_SYMLINK)
@ -220,6 +227,12 @@ if (WIN32)
COMMENT "Symlinking the resources directory into the build tree"
VERBATIM
)
if (SLIC3R_GUI)
add_custom_command(TARGET PrusaSlicer POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${wxWidgets_ROOT_DIR}/bin/WebView2Loader.dll"
"${CMAKE_CURRENT_BINARY_DIR}/${CONF}/WebView2Loader.dll")
endif()
endif ()
# This has to be a separate target due to the windows command line lenght limits

View File

@ -750,13 +750,6 @@ void MainFrame::init_tabpanel()
select_tab(size_t(0)); // select Plater
});
if (wxGetApp().is_editor()) {
//m_webview = new WebViewPanel(m_tabpanel);
//m_tabpanel->AddNewPage(m_webview, "web", "cog"/*, "tab_home_active"*/);
//m_param_panel = new ParamsPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
}
m_plater = new Plater(this, this);
m_plater->Hide();
@ -1183,7 +1176,7 @@ void MainFrame::on_sys_color_changed()
wxGetApp().plater()->sys_color_changed();
// update Tabs
for (auto tab : wxGetApp().tabs_list)
for (Tab* tab : wxGetApp().tabs_list)
tab->sys_color_changed();
if (m_connect_webview)

View File

@ -938,17 +938,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
BOOST_LOG_TRIVIAL(error) << "Failed communication with Prusa Account: " << evt.data;
user_account->on_communication_fail();
});
#if 0
// for debug purposes only
this->q->Bind(EVT_UA_SUCCESS, [this](UserAccountSuccessEvent& evt) {
this->notification_manager->close_notification_of_type(NotificationType::UserAccountID);
this->notification_manager->push_notification(NotificationType::UserAccountID, NotificationManager::NotificationLevel::ImportantNotificationLevel, evt.data);
});
this->q->Bind(EVT_UA_CONNECT_USER_DATA_SUCCESS, [this](UserAccountSuccessEvent& evt) {
BOOST_LOG_TRIVIAL(error) << evt.data;
user_account->on_connect_user_data_success(evt.data);
});
#endif // 0
this->q->Bind(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, [this](UserAccountSuccessEvent& evt) {
std::string text;
bool printers_changed = false;

View File

@ -84,20 +84,6 @@ boost::filesystem::path UserAccount::get_avatar_path(bool logged) const
}
}
#if 0
void UserAccount::enqueue_user_id_action()
{
m_communication->enqueue_user_id_action();
}
void UserAccount::enqueue_connect_dummy_action()
{
m_communication->enqueue_connect_dummy_action();
}
void UserAccount::enqueue_connect_user_data_action()
{
m_communication->enqueue_connect_user_data_action();
}
#endif
void UserAccount::enqueue_connect_printers_action()
{

View File

@ -41,11 +41,6 @@ public:
void set_remember_session(bool remember);
void toggle_remember_session();
bool get_remember_session();
#if 0
void enqueue_user_id_action();
void enqueue_connect_dummy_action();
void enqueue_connect_user_data_action();
#endif
void enqueue_connect_printers_action();
void enqueue_avatar_action();

View File

@ -274,43 +274,7 @@ void UserAccountCommunication::on_login_code_recieved(const std::string& url_mes
wakeup_session_thread();
}
#if 0
void UserAccountCommunication::enqueue_user_id_action()
{
{
std::lock_guard<std::mutex> lock(m_session_mutex);
if (!m_session->is_initialized()) {
return;
}
m_session->enqueue_action(UserAccountActionID::USER_ID, nullptr, nullptr, {});
}
wakeup_session_thread();
}
void UserAccountCommunication::enqueue_connect_dummy_action()
{
{
std::lock_guard<std::mutex> lock(m_session_mutex);
if (!m_session->is_initialized()) {
BOOST_LOG_TRIVIAL(error) << "Connect Dummy endpoint connection failed - Not Logged in.";
return;
}
m_session->enqueue_action(UserAccountActionID::CONNECT_DUMMY, nullptr, nullptr, {});
}
wakeup_session_thread();
}
void UserAccountCommunication::enqueue_connect_user_data_action()
{
{
std::lock_guard<std::mutex> lock(m_session_mutex);
if (!m_session->is_initialized()) {
BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in.";
return;
}
m_session->enqueue_action(UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_USER_DATA, nullptr, nullptr, {});
}
wakeup_session_thread();
}
#endif // 0
void UserAccountCommunication::enqueue_connect_printers_action()
{

View File

@ -39,11 +39,6 @@ public:
void do_logout();
void do_clear();
// Trigger function starts various remote operations
#if 0
void enqueue_user_id_action();
void enqueue_connect_dummy_action();
void enqueue_connect_user_data_action();
#endif
void enqueue_connect_printers_action();
void enqueue_avatar_action(const std::string& url);
void enqueue_test_connection();

View File

@ -26,9 +26,6 @@ wxDEFINE_EVENT(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, UserAccountSuccessEvent);
wxDEFINE_EVENT(EVT_UA_AVATAR_SUCCESS, UserAccountSuccessEvent);
wxDEFINE_EVENT(EVT_UA_FAIL, UserAccountFailEvent);
wxDEFINE_EVENT(EVT_UA_RESET, UserAccountFailEvent);
#if 0
wxDEFINE_EVENT(EVT_UA_FAIL, UserAccountFailEvent);
#endif // 0
void UserActionPost::perform(/*UNUSED*/ wxEvtHandler* evt_handler, /*UNUSED*/ const std::string& access_token, UserActionSuccessFn success_callback, UserActionFailFn fail_callback, const std::string& input) const
{

View File

@ -24,9 +24,6 @@ wxDECLARE_EVENT(EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, UserAccountSuccessEvent);
wxDECLARE_EVENT(EVT_UA_AVATAR_SUCCESS, UserAccountSuccessEvent);
wxDECLARE_EVENT(EVT_UA_FAIL, UserAccountFailEvent); // Soft fail - clears only after some number of fails
wxDECLARE_EVENT(EVT_UA_RESET, UserAccountFailEvent); // Hard fail - clears all
#if 0
wxDECLARE_EVENT(EVT_UA_CONNECT_USER_DATA_SUCCESS, UserAccountSuccessEvent);
#endif // 0
typedef std::function<void(const std::string& body)> UserActionSuccessFn;
@ -42,12 +39,6 @@ enum class UserAccountActionID {
USER_ACCOUNT_ACTION_TEST_CONNECTION,
USER_ACCOUNT_ACTION_CONNECT_STATUS, // status of all printers
USER_ACCOUNT_ACTION_AVATAR,
#if 0
USER_ACCOUNT_ACTION_CONNECT_PRINTERS, // all info about all printers
USER_ACCOUNT_ACTION_CONNECT_USER_DATA,
USER_ACCOUNT_ACTION_CONNECT_DUMMY,
#endif // 0
};
class UserAction
{
@ -121,12 +112,6 @@ public:
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_CONNECTION] = std::make_unique<UserActionGetWithEvent>("TEST_CONNECTION", "https://account.prusa3d.com/api/v1/me/", wxEVT_NULL, EVT_UA_RESET);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS] = std::make_unique<UserActionGetWithEvent>("CONNECT_STATUS", "https://connect.prusa3d.com/slicer/status", EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, EVT_UA_FAIL);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_AVATAR] = std::make_unique<UserActionGetWithEvent>("AVATAR", "https://media.printables.com/media/", EVT_UA_AVATAR_SUCCESS, EVT_UA_FAIL);
#if 0
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_USER_DATA] = std::make_unique<UserActionGetWithEvent>("CONNECT_USER_DATA", "https://connect.prusa3d.com/app/login", EVT_UA_CONNECT_USER_DATA_SUCCESS, EVT_UA_FAIL);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_DUMMY] = std::make_unique<UserActionGetWithEvent>("CONNECT_DUMMY", "https://connect.prusa3d.com/slicer/dummy", EVT_UA_SUCCESS, EVT_UA_FAIL);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTERS] = std::make_unique<UserActionGetWithEvent>("CONNECT_PRINTERS", "https://connect.prusa3d.com/slicer/printers", EVT_UA_PRUSACONNECT_PRINTERS_SUCCESS, EVT_UA_FAIL);
#endif // 0
}
~UserAccountSession()
{
@ -138,13 +123,6 @@ public:
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_TEST_CONNECTION].reset(nullptr);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_STATUS].reset(nullptr);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_AVATAR].reset(nullptr);
#if 0
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_USER_DATA].reset(nullptr);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_DUMMY].reset(nullptr);
m_actions[UserAccountActionID::USER_ACCOUNT_ACTION_CONNECT_PRINTERS].reset(nullptr);
#endif // 0
}
void clear() {
m_access_token.clear();

View File

@ -1,37 +1,11 @@
#include "WebView.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/Utils/MacDarkMode.hpp"
#include <wx/webviewarchivehandler.h>
#include <wx/webviewfshandler.h>
#include <wx/msw/webview_edge.h>
#include <wx/uri.h>
#include "wx/private/jsscriptwrapper.h"
#include <wx/webview.h>
#include <boost/log/trivial.hpp>
#ifdef __WIN32__
#include <WebView2.h>
#elif defined __linux__
#include <gtk/gtk.h>
#define WEBKIT_API
struct WebKitWebView;
struct WebKitJavascriptResult;
extern "C" {
WEBKIT_API void
webkit_web_view_run_javascript (WebKitWebView *web_view,
const gchar *script,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
WEBKIT_API WebKitJavascriptResult *
webkit_web_view_run_javascript_finish (WebKitWebView *web_view,
GAsyncResult *result,
GError **error);
WEBKIT_API void
webkit_javascript_result_unref (WebKitJavascriptResult *js_result);
}
#endif
class FakeWebView : public wxWebView
{
@ -69,31 +43,21 @@ class FakeWebView : public wxWebView
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) override { }
};
wxWebView* WebView::CreateWebView(wxWindow * parent, wxString const & url)
wxWebView* WebView::CreateWebView(wxWindow * parent, const wxString& url)
{
#if wxUSE_WEBVIEW_EDGE
// WebView2Loader.dll in exe folder is enough?
/*
// Check if a fixed version of edge is present in
// $executable_path/edge_fixed and use it
wxFileName edgeFixedDir(wxStandardPaths::Get().GetExecutablePath());
edgeFixedDir.SetFullName("");
edgeFixedDir.AppendDir("edge_fixed");
if (edgeFixedDir.DirExists()) {
wxWebViewEdge::MSWSetBrowserExecutableDir(edgeFixedDir.GetFullPath());
wxLogMessage("Using fixed edge version");
}
*/
bool backend_available = wxWebView::IsBackendAvailable(wxWebViewBackendEdge);
#else
bool backend_available = wxWebView::IsBackendAvailable(wxWebViewBackendWebKit);
#endif
wxString correct_url = url;
#ifdef __WIN32__
correct_url.Replace("\\", "/");
#endif
if (!correct_url.empty())
correct_url = wxURI(correct_url).BuildURI();
auto webView = wxWebView::New();
wxWebView* webView = nullptr;
if (backend_available)
webView = wxWebView::New();
if (webView) {
wxString correct_url = url.empty() ? wxString("") : wxURI(url).BuildURI();
#ifdef __WIN32__
webView->SetUserAgent(wxString::Format("PrusaSlicer/v%s", SLIC3R_VERSION));
webView->Create(parent, wxID_ANY, correct_url, wxDefaultPosition, wxDefaultSize);
@ -113,7 +77,7 @@ wxWebView* WebView::CreateWebView(wxWindow * parent, wxString const & url)
Slic3r::GUI::wxGetApp().CallAfter([webView] {
#endif
if (!webView->AddScriptMessageHandler("_prusaSlicer")) {
// TODO: dialog to user
// TODO: dialog to user !!!
//wxLogError("Could not add script message handler");
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not add script message handler";
}
@ -122,55 +86,17 @@ wxWebView* WebView::CreateWebView(wxWindow * parent, wxString const & url)
#endif
webView->EnableContextMenu(false);
} else {
// TODO: dialog to user
// TODO: dialog to user !!!
BOOST_LOG_TRIVIAL(error) << "Failed to create wxWebView object. Using Dummy object instead. Webview won't be working.";
webView = new FakeWebView;
}
return webView;
}
void WebView::LoadUrl(wxWebView * webView, wxString const &url)
{
auto url2 = url;
#ifdef __WIN32__
url2.Replace("\\", "/");
#endif
if (!url2.empty()) { url2 = wxURI(url2).BuildURI(); }
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << url2.ToUTF8();
webView->LoadURL(url2);
}
bool WebView::run_script(wxWebView *webView, wxString const &javascript)
{
try {
#ifdef __WIN32__
ICoreWebView2 * webView2 = (ICoreWebView2 *) webView->GetNativeBackend();
if (webView2 == nullptr)
return false;
int count = 0;
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::OutputType::JS_OUTPUT_STRING);
wxString wrapped_code = wrapJS.GetWrappedCode();
return webView2->ExecuteScript(wrapJS.GetWrappedCode(), NULL) == 0;
#elif defined __WXMAC__
WKWebView * wkWebView = (WKWebView *) webView->GetNativeBackend();
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::OutputType::JS_OUTPUT_STRING);
Slic3r::GUI::WKWebView_evaluateJavaScript(wkWebView, wrapJS.GetWrappedCode(), nullptr);
return true;
#else
WebKitWebView *wkWebView = (WebKitWebView *) webView->GetNativeBackend();
webkit_web_view_run_javascript(
wkWebView, javascript.utf8_str(), NULL,
[](GObject *wkWebView, GAsyncResult *res, void *) {
GError * error = NULL;
auto result = webkit_web_view_run_javascript_finish((WebKitWebView*)wkWebView, res, &error);
if (!result)
g_error_free (error);
else
webkit_javascript_result_unref (result);
}, NULL);
return true;
#endif
} catch (std::exception &) {
return false;
}
webView->RunScriptAsync(javascript);
return true;
}

View File

@ -1,16 +1,14 @@
#ifndef slic3r_GUI_WebView_hpp_
#define slic3r_GUI_WebView_hpp_
#include <wx/webview.h>
class wxWebView;
class wxWindow;
class wxString;
class WebView
namespace WebView
{
public:
static wxWebView *CreateWebView(wxWindow *parent, wxString const &url);
static void LoadUrl(wxWebView * webView, wxString const &url);
static bool run_script(wxWebView * webView, wxString const & msg);
wxWebView *CreateWebView(wxWindow *parent, const wxString& url);
bool run_script(wxWebView * webView, const wxString& msg);
};
#endif // !slic3r_GUI_WebView_hpp_

View File

@ -1,26 +1,20 @@
#include "WebViewDialog.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "libslic3r_version.h"
#include "libslic3r/Utils.hpp"
#include "libslic3r/libslic3r.h"
#include "slic3r/GUI/UserAccount.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/WebView.hpp"
#include <wx/sizer.h>
#include <wx/toolbar.h>
#include <wx/textdlg.h>
#include <wx/webview.h>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "slic3r/GUI/WebView.hpp"
namespace pt = boost::property_tree;
@ -73,7 +67,7 @@ WebViewPanel::WebViewPanel(wxWindow *parent, const wxString& default_url)
#endif
// Create the webview
m_browser = WebView::CreateWebView(this, /*m_default_url*/ wxString::Format("file://%s/web/connection_failed.html", from_u8(resources_dir())));
m_browser = WebView::CreateWebView(this, /*m_default_url*/ GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string()));
if (m_browser == nullptr) {
wxLogError("Could not init m_browser");
return;
@ -170,7 +164,7 @@ void WebViewPanel::load_default_url_delayed()
void WebViewPanel::load_error_page()
{
load_url(wxString::Format("file://%s/web/connection_failed.html", from_u8(resources_dir())));
load_url(GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string()));
}
void WebViewPanel::on_show(wxShowEvent& evt)

View File

@ -1,31 +1,11 @@
#ifndef slic3r_WebViewDialog_hpp_
#define slic3r_WebViewDialog_hpp_
#include "wx/artprov.h"
#include "wx/cmdline.h"
#include "wx/notifmsg.h"
#include "wx/settings.h"
#include "wx/webview.h"
#if wxUSE_WEBVIEW_EDGE
#include "wx/msw/webview_edge.h"
#endif
#include "wx/webviewarchivehandler.h"
#include "wx/webviewfshandler.h"
#include "wx/numdlg.h"
#include "wx/infobar.h"
#include "wx/filesys.h"
#include "wx/fs_arc.h"
#include "wx/fs_mem.h"
#include "wx/stdpaths.h"
#include <wx/panel.h>
#include <wx/tbarbase.h>
#include "wx/textctrl.h"
#include <wx/timer.h>
#include <map>
class wxWebView;
class wxWebViewEvent;
namespace Slic3r {
namespace GUI {

View File

@ -13,7 +13,6 @@ namespace GUI {
#if __APPLE__
extern bool mac_dark_mode();
extern double mac_max_scaling_factor();
void WKWebView_evaluateJavaScript(void * web, wxString const & script, void (*callback)(wxString const &));
#endif