diff --git a/src/slic3r/GUI/ConnectRequestHandler.cpp b/src/slic3r/GUI/ConnectRequestHandler.cpp index 0f4bf4a208..07c85ece54 100644 --- a/src/slic3r/GUI/ConnectRequestHandler.cpp +++ b/src/slic3r/GUI/ConnectRequestHandler.cpp @@ -56,7 +56,7 @@ void ConnectRequestHandler::handle_message(const std::string& message) } if (action_string.empty()) { - BOOST_LOG_TRIVIAL(error) << "Recieved invalid message from _prusaConnect (missing action). Message: " << message; + BOOST_LOG_TRIVIAL(error) << "Received invalid message from _prusaConnect (missing action). Message: " << message; return; } assert(m_actions.find(action_string) != m_actions.end()); // this assert means there is a action that has no handling. diff --git a/src/slic3r/GUI/WebViewPanel.cpp b/src/slic3r/GUI/WebViewPanel.cpp index d7c4c099a6..3e4da88fd7 100644 --- a/src/slic3r/GUI/WebViewPanel.cpp +++ b/src/slic3r/GUI/WebViewPanel.cpp @@ -592,69 +592,20 @@ void WebViewPanel::sys_color_changed() #endif } +void WebViewPanel::on_app_quit_event(const std::string& message_data) +{ + // MacOS only suplement for cmd+Q + wxGetApp().Exit(); +} + +void WebViewPanel::on_app_minimize_event(const std::string& message_data) +{ + // MacOS only suplement for cmd+M + wxGetApp().mainframe->Iconize(true); +} void WebViewPanel::define_css() { - - if (m_styles_defined) { - return; - } - m_styles_defined = true; - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; - std::string script = R"( - // loading overlay - var style = document.createElement('style'); - style.innerHTML = ` - body {} - .slic3r-loading-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(127 127 127 / 50%); - z-index: 50; - display: flex; - align-items: center; - justify-content: center; - } - .slic3r-loading-anim { - width: 60px; - aspect-ratio: 4; - --_g: no-repeat radial-gradient(circle closest-side,#000 90%,#0000); - background: - var(--_g) 0% 50%, - var(--_g) 50% 50%, - var(--_g) 100% 50%; - background-size: calc(100%/3) 100%; - animation: slic3r-loading-anim 1s infinite linear; - } - @keyframes slic3r-loading-anim { - 33%{background-size:calc(100%/3) 0% ,calc(100%/3) 100%,calc(100%/3) 100%} - 50%{background-size:calc(100%/3) 100%,calc(100%/3) 0% ,calc(100%/3) 100%} - 66%{background-size:calc(100%/3) 100%,calc(100%/3) 100%,calc(100%/3) 0% } - } - - document.head.appendChild(style); - )"; -//#ifdef __APPLE__ -#if defined(__APPLE__) - // WebView on Windows does read keyboard shortcuts - // Thus doing f.e. Reload twice would make the oparation to fail - script += R"( - (function() { - const listenerKey = 'custom-click-listener'; - if (!document[listenerKey]) { - document.addEventListener('keydown', function (event) { - if (event.key === 'F5' || (event.ctrlKey && event.key === 'r') || (event.metaKey && event.key === 'r')) { - window.ExternalApp.postMessage(JSON.stringify({ event: 'reloadHomePage', fromKeyboard: 1})); - } - }); - document[listenerKey] = true; - } - })(); - )"; -#endif // __APPLE__ - run_script(script); + assert(false); } ConnectWebViewPanel::ConnectWebViewPanel(wxWindow* parent) @@ -663,6 +614,11 @@ ConnectWebViewPanel::ConnectWebViewPanel(wxWindow* parent) auto* plater = wxGetApp().plater(); plater->Bind(EVT_UA_LOGGEDOUT, &ConnectWebViewPanel::on_user_logged_out, this); plater->Bind(EVT_UA_ID_USER_SUCCESS, &ConnectWebViewPanel::on_user_token, this); + + m_actions["appQuit"] = std::bind(&WebViewPanel::on_app_quit_event, this, std::placeholders::_1); + m_actions["appMinimize"] = std::bind(&WebViewPanel::on_app_minimize_event, this, std::placeholders::_1); + m_actions["reloadHomePage"] = std::bind(&ConnectWebViewPanel::on_reload_event, this, std::placeholders::_1); + } void ConnectWebViewPanel::late_create() @@ -976,9 +932,41 @@ void ConnectWebViewPanel::on_connect_action_print(const std::string& message_dat assert(false); } +void ConnectWebViewPanel::define_css() +{ + + if (m_styles_defined) { + return; + } + m_styles_defined = true; + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; +#if defined(__APPLE__) + // WebView on Windows does read keyboard shortcuts + // Thus doing f.e. Reload twice would make the oparation to fail + std::string script = R"( + document.addEventListener('keydown', function (event) { + if (event.key === 'F5' || (event.ctrlKey && event.key === 'r') || (event.metaKey && event.key === 'r')) { + window.webkit.messageHandlers._prusaSlicer.postMessage(JSON.stringify({ action: 'reloadHomePage', fromKeyboard: 1})); + } + if (event.metaKey && event.key === 'q') { + window.webkit.messageHandlers._prusaSlicer.postMessage(JSON.stringify({ action: 'appQuit'})); + } + if (event.metaKey && event.key === 'm') { + window.webkit.messageHandlers._prusaSlicer.postMessage(JSON.stringify({ action: 'appMinimize'})); + } + }); + )"; + run_script(script); + +#endif // defined(__APPLE__) +} + PrinterWebViewPanel::PrinterWebViewPanel(wxWindow* parent, const wxString& default_url) : WebViewPanel(parent, default_url, {"ExternalApp"}, "other_loading", "other_error", false) { + m_events["reloadHomePage"] = std::bind(&PrinterWebViewPanel::on_reload_event, this, std::placeholders::_1); + m_events["appQuit"] = std::bind(&WebViewPanel::on_app_quit_event, this, std::placeholders::_1); + m_events["appMinimize"] = std::bind(&WebViewPanel::on_app_minimize_event, this, std::placeholders::_1); } void PrinterWebViewPanel::on_navigation_request(wxWebViewEvent &evt) @@ -1025,8 +1013,35 @@ void PrinterWebViewPanel::on_loaded(wxWebViewEvent& evt) } void PrinterWebViewPanel::on_script_message(wxWebViewEvent& evt) { - // Only reload messages are being sent now. - load_default_url(); + BOOST_LOG_TRIVIAL(debug) << "received message from Physical printer page: " << evt.GetString(); + handle_message(into_u8(evt.GetString())); +} + +void PrinterWebViewPanel::handle_message(const std::string& message) +{ + + std::string event_string; + try { + std::stringstream ss(message); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (const auto action = ptree.get_optional("event"); action) { + event_string = *action; + } + } + catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(error) << "Could not parse printables message. " << e.what(); + return; + } + + if (event_string.empty()) { + BOOST_LOG_TRIVIAL(error) << "Received invalid message from printables (missing event). Message: " << message; + return; + } + assert(m_events.find(event_string) != m_events.end()); // this assert means there is an event that has no handling. + if (m_events.find(event_string) != m_events.end()) { + m_events[event_string](message); + } } void PrinterWebViewPanel::send_api_key() @@ -1070,19 +1085,67 @@ void PrinterWebViewPanel::send_credentials() setup_webview_with_credentials(m_browser, m_usr, m_psk); } +void PrinterWebViewPanel::define_css() +{ + + if (m_styles_defined) { + return; + } + m_styles_defined = true; + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; +#if defined(__APPLE__) + // WebView on Windows does read keyboard shortcuts + // Thus doing f.e. Reload twice would make the oparation to fail + std::string script = R"( + document.addEventListener('keydown', function (event) { + if (event.key === 'F5' || (event.ctrlKey && event.key === 'r') || (event.metaKey && event.key === 'r')) { + window.webkit.messageHandlers.ExternalApp.postMessage(JSON.stringify({ event: 'reloadHomePage', fromKeyboard: 1})); + } + if (event.metaKey && event.key === 'q') { + window.webkit.messageHandlers.ExternalApp.postMessage(JSON.stringify({ event: 'appQuit'})); + } + if (event.metaKey && event.key === 'm') { + window.webkit.messageHandlers.ExternalApp.postMessage(JSON.stringify({ event: 'appMinimize'})); + } + }); + )"; + run_script(script); + +#endif // defined(__APPLE__) +} + +void PrinterWebViewPanel::on_reload_event(const std::string& message_data) +{ + // Event from our error page button or keyboard shortcut + m_styles_defined = false; + try { + std::stringstream ss(message_data); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (const auto keyboard = ptree.get_optional("fromKeyboard"); keyboard && *keyboard) { + do_reload(); + } else { + // On error page do load of default url. + load_default_url(); + } + } catch (const std::exception &e) { + BOOST_LOG_TRIVIAL(error) << "Could not parse message. " << e.what(); + return; + } +} PrintablesWebViewPanel::PrintablesWebViewPanel(wxWindow* parent) : WebViewPanel(parent, GUI::from_u8(Utils::ServiceConfig::instance().printables_url()), { "ExternalApp" }, "other_loading", "other_error", false) { - - m_events["accessTokenExpired"] = std::bind(&PrintablesWebViewPanel::on_printables_event_access_token_expired, this, std::placeholders::_1); - m_events["reloadHomePage"] = std::bind(&PrintablesWebViewPanel::on_reload_event, this, std::placeholders::_1); m_events["printGcode"] = std::bind(&PrintablesWebViewPanel::on_printables_event_print_gcode, this, std::placeholders::_1); m_events["downloadFile"] = std::bind(&PrintablesWebViewPanel::on_printables_event_download_file, this, std::placeholders::_1); m_events["sliceFile"] = std::bind(&PrintablesWebViewPanel::on_printables_event_slice_file, this, std::placeholders::_1); m_events["requiredLogin"] = std::bind(&PrintablesWebViewPanel::on_printables_event_required_login, this, std::placeholders::_1); m_events["openExternalUrl"] = std::bind(&PrintablesWebViewPanel::on_printables_event_open_url, this, std::placeholders::_1); + m_events["reloadHomePage"] = std::bind(&PrintablesWebViewPanel::on_reload_event, this, std::placeholders::_1); + m_events["appQuit"] = std::bind(&WebViewPanel::on_app_quit_event, this, std::placeholders::_1); + m_events["appMinimize"] = std::bind(&WebViewPanel::on_app_minimize_event, this, std::placeholders::_1); } void PrintablesWebViewPanel::handle_message(const std::string& message) @@ -1613,17 +1676,17 @@ void PrintablesWebViewPanel::define_css() // WebView on Windows does read keyboard shortcuts // Thus doing f.e. Reload twice would make the oparation to fail script += R"( - (function() { - const listenerKey = 'custom-click-listener'; - if (!document[listenerKey]) { - document.addEventListener('keydown', function (event) { - if (event.key === 'F5' || (event.ctrlKey && event.key === 'r') || (event.metaKey && event.key === 'r')) { - window.ExternalApp.postMessage(JSON.stringify({ event: 'reloadHomePage', fromKeyboard: 1})); - } - }); - document[listenerKey] = true; + document.addEventListener('keydown', function (event) { + if (event.key === 'F5' || (event.ctrlKey && event.key === 'r') || (event.metaKey && event.key === 'r')) { + window.ExternalApp.postMessage(JSON.stringify({ event: 'reloadHomePage', fromKeyboard: 1})); } - })(); + if (event.metaKey && event.key === 'q') { + window.ExternalApp.postMessage(JSON.stringify({ event: 'appQuit'})); + } + if (event.metaKey && event.key === 'm') { + window.ExternalApp.postMessage(JSON.stringify({ event: 'appMinimize'})); + } + }); )"; #endif // defined(__APPLE__) run_script(script); diff --git a/src/slic3r/GUI/WebViewPanel.hpp b/src/slic3r/GUI/WebViewPanel.hpp index e3b4319b34..479c9ed06b 100644 --- a/src/slic3r/GUI/WebViewPanel.hpp +++ b/src/slic3r/GUI/WebViewPanel.hpp @@ -74,11 +74,14 @@ public: void set_load_default_url_on_next_error(bool val) { m_load_default_url_on_next_error = val; } + void on_app_quit_event(const std::string& message_data); + void on_app_minimize_event(const std::string& message_data); protected: virtual void late_create(); virtual void define_css(); virtual void on_page_will_load(); + wxWebView* m_browser { nullptr }; bool m_load_default_url { false }; @@ -144,6 +147,7 @@ protected: void on_reload_event(const std::string& message_data) override; void on_connect_action_close_dialog(const std::string& message_data) override {assert(false);} void on_user_token(UserAccountSuccessEvent& e); + void define_css() override; private: static wxString get_login_script(bool refresh); static wxString get_logout_script(); @@ -172,11 +176,18 @@ public: m_psk = psk; } void clear() { m_api_key.clear(); m_usr.clear(); m_psk.clear(); m_api_key_sent = false; } + + void on_reload_event(const std::string& message_data); +protected: + void define_css() override; private: std::string m_api_key; std::string m_usr; std::string m_psk; bool m_api_key_sent {false}; + + void handle_message(const std::string& message); + std::map> m_events; }; class PrintablesWebViewPanel : public WebViewPanel