diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 1aab7334f1..d9b8e00265 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -116,8 +116,8 @@ set(SLIC3R_GUI_SOURCES GUI/PluginPickerDialog.hpp GUI/PluginsDialog.cpp GUI/PluginsDialog.hpp - GUI/SpeedDialPopup.cpp - GUI/SpeedDialPopup.hpp + GUI/SpeedDialDialog.cpp + GUI/SpeedDialDialog.hpp GUI/ActionRegistry.cpp GUI/ActionRegistry.hpp GUI/ProcessRunner.cpp diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fef848ff3c..2b71398892 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -141,7 +141,7 @@ #include "slic3r/Utils/bambu_networking.hpp" #include "PluginsDialog.hpp" -#include "SpeedDialPopup.hpp" +#include "SpeedDialDialog.hpp" #include "TerminalDialog.hpp" //#ifdef WIN32 diff --git a/src/slic3r/GUI/SpeedDialDialog.cpp b/src/slic3r/GUI/SpeedDialDialog.cpp new file mode 100644 index 0000000000..3204f68d8f --- /dev/null +++ b/src/slic3r/GUI/SpeedDialDialog.cpp @@ -0,0 +1,164 @@ +#include "SpeedDialDialog.hpp" + +#include "ActionRegistry.hpp" +#include "GUI.hpp" +#include "GUI_App.hpp" +#include "MainFrame.hpp" +#include "MsgDialog.hpp" +#include "NotificationManager.hpp" +#include "Plater.hpp" +#include "Widgets/WebViewHostDialog.hpp" + +#include + +#include +#include +#include + +namespace Slic3r { namespace GUI { + +namespace { + +// ADJUST WIDTH HERE (DIP px). Fixed dialog width; was 360, now 1.5x. Height is not set here - +// the dialog auto-resizes to the page content (see resize_to_content + the list max-height in style.css). +constexpr int kPopupWidth = 540; +constexpr int kPopupMinHeight = 60; // just above the bare search-bar height, so the dialog hugs content +constexpr int kPopupMaxHeight = 282; + +int json_int_or(const nlohmann::json& j, const char* key, int fallback) +{ + auto it = j.find(key); + return it != j.end() && it->is_number() ? it->get() : fallback; +} + +wxColour bg_color() { return wxGetApp().get_window_default_clr(); } + +} + +SpeedDialWebDialog::SpeedDialWebDialog(wxWindow* parent) + : WebViewHostDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxBORDER_NONE | wxFRAME_NO_TASKBAR) +{ + SetBackgroundColour(bg_color()); + Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) { + if (!event.GetActive() && IsShown()) + Hide(); + event.Skip(); + }); + if (!create_webview("web/dialog/SpeedDial/index.html", wxEmptyString, + wxSize(kPopupWidth, kPopupMaxHeight), wxSize(kPopupWidth, kPopupMinHeight))) { + auto* sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add(new wxStaticText(this, wxID_ANY, wxS("wxWebView unavailable")), + wxSizerFlags().Border(wxALL, 20)); + SetSizer(sizer); + SetClientSize(FromDIP(wxSize(kPopupWidth, kPopupMinHeight))); + } +} + +void SpeedDialWebDialog::request_show() +{ + if (IsShown()) { + Raise(); + if (browser()) + browser()->SetFocus(); + return; + } + + Show(); + Raise(); + if (m_page_ready) + send_actions(); + if (browser()) + browser()->SetFocus(); +} + +void SpeedDialWebDialog::on_script_message(const nlohmann::json& payload) +{ + if (handle_common_script_command(payload)) + return; + + const std::string command = payload.value("command", ""); + if (command == "request_actions") { + m_page_ready = true; + send_actions(); + } + else if (command == "toggle_favourite") + wxGetApp().action_registry().set_favourite(payload.value("id", ""), payload.value("fav", false)); + else if (command == "reorder_favourites") { + std::vector ids; + if (payload.contains("ids") && payload["ids"].is_array()) + for (const auto& id : payload["ids"]) + if (id.is_string()) + ids.push_back(id.get()); + wxGetApp().action_registry().reorder_favourites(ids); + } + else if (command == "run_action") + run_action(payload.value("id", ""), payload.value("title", "")); + else if (command == "resize") + resize_to_content(json_int_or(payload, "height", 0)); +} + +void SpeedDialWebDialog::resize_to_content(int height) +{ + if (height <= 0) + return; + + int display_index = wxDisplay::GetFromWindow(this); + if (display_index == wxNOT_FOUND) + display_index = 0; + const int screen_dip = ToDIP(wxDisplay(display_index).GetClientArea().GetHeight()); + const int max_dip = std::max(kPopupMinHeight, screen_dip * 85 / 100); + const int height_dip = std::max(kPopupMinHeight, std::min(height, max_dip)); + SetClientSize(FromDIP(wxSize(kPopupWidth, height_dip))); + Layout(); +} + +void SpeedDialWebDialog::run_action(const std::string& id, const std::string& title) +{ + ActionRegistry& reg = wxGetApp().action_registry(); + const AppAction* a = reg.by_id(id); + if (!a) + return; + + const bool ask = reg.should_ask(id); + const std::string atitle = a->title(); + if (IsModal()) + EndModal(wxID_CANCEL); + else + Hide(); + + if (ask) { + const wxString label = title.empty() ? from_u8(atitle) : from_u8(title); + RichMessageDialog dlg(wxGetApp().mainframe, wxString::Format(_L("Run \"%s\"?"), label), + _L("Run plugin"), wxOK | wxCANCEL); + dlg.ShowCheckBox(_L("Don't ask again for this action")); + if (dlg.ShowModal() != wxID_OK) + return; + if (dlg.IsCheckBoxChecked()) + wxGetApp().action_registry().suppress_ask(id); + } + + wxGetApp().CallAfter([id] { + if (wxGetApp().is_closing()) + return; + AppActionRunResult result = wxGetApp().action_registry().run(id); + if (result.level == AppActionRunResult::Level::Busy) + return; + if (!result.message.IsEmpty() && wxGetApp().plater()) + wxGetApp().plater()->get_notification_manager()->push_notification( + NotificationType::CustomNotification, + result.level == AppActionRunResult::Level::Error ? NotificationManager::NotificationLevel::ErrorNotificationLevel : + NotificationManager::NotificationLevel::RegularNotificationLevel, + into_u8(result.message)); + }); +} + +void SpeedDialWebDialog::send_actions() +{ + nlohmann::json snap = wxGetApp().action_registry().snapshot(); + call_web_handler({{"command", "list_actions"}, + {"actions", std::move(snap["actions"])}, + {"favourites", std::move(snap["favourites"])}}); +} + +}} diff --git a/src/slic3r/GUI/SpeedDialDialog.hpp b/src/slic3r/GUI/SpeedDialDialog.hpp new file mode 100644 index 0000000000..7c5f8ac40b --- /dev/null +++ b/src/slic3r/GUI/SpeedDialDialog.hpp @@ -0,0 +1,27 @@ +#ifndef slic3r_GUI_SpeedDialDialog_hpp_ +#define slic3r_GUI_SpeedDialDialog_hpp_ + +#include +#include +#include + +namespace Slic3r { namespace GUI { + +class SpeedDialWebDialog : public WebViewHostDialog +{ +public: + explicit SpeedDialWebDialog(wxWindow* parent); + void request_show(); + +private: + void on_script_message(const nlohmann::json& payload) override; + void resize_to_content(int height); + void run_action(const std::string& id, const std::string& title); + void send_actions(); + + bool m_page_ready{false}; +}; + +}} + +#endif diff --git a/src/slic3r/GUI/SpeedDialPopup.cpp b/src/slic3r/GUI/SpeedDialPopup.cpp deleted file mode 100644 index 8a614d0a47..0000000000 --- a/src/slic3r/GUI/SpeedDialPopup.cpp +++ /dev/null @@ -1,429 +0,0 @@ -#include "SpeedDialPopup.hpp" - -#include "ActionRegistry.hpp" -#include "GUI.hpp" -#include "GUI_App.hpp" -#include "MainFrame.hpp" -#include "MsgDialog.hpp" -#include "NotificationManager.hpp" -#include "Plater.hpp" -#include "Widgets/PopupWindow.hpp" -#include "Widgets/WebView.hpp" -#include "Widgets/WebViewHostDialog.hpp" -#include "Widgets/StateColor.hpp" - -#include - -#include - -#include -#include -#include -#include - -namespace Slic3r { namespace GUI { - -namespace { - -// ADJUST WIDTH HERE (DIP px). Fixed popup width; was 360, now 1.5x. Height is not set here - -// the popup auto-resizes to the page content (see resize_to_content + the list max-height in style.css). -constexpr int kPopupWidth = 540; -constexpr int kPopupMinHeight = 60; // just above the bare search-bar height, so the popup hugs content -constexpr int kPopupMaxHeight = 282; - -wxString dialog_url() -{ - boost::filesystem::path path = boost::filesystem::path(resources_dir()) / "web/dialog/SpeedDial/index.html"; - return wxString("file://") + from_u8(path.make_preferred().string()); -} - -wxPoint clamped_position(wxPoint pos, const wxSize& size) -{ - int display_index = wxDisplay::GetFromPoint(pos); - if (display_index == wxNOT_FOUND) - display_index = 0; - wxRect area = wxDisplay(display_index).GetClientArea(); - pos.x = std::max(area.GetLeft(), std::min(pos.x, area.GetRight() - size.GetWidth())); - pos.y = std::max(area.GetTop(), std::min(pos.y, area.GetBottom() - size.GetHeight())); - return pos; -} - -// ADJUST POSITION HERE. Horizontal: centred over the plater. Vertical: the window TOP sits at -// 1/3 of the screen height (upper-third placement). Tune `/ 3` to move the anchor up/down, or -// change the `x` line to re-anchor horizontally. clamped_position() at the call site then nudges -// the popup back on-screen if it would spill off an edge. -wxPoint popup_position(const wxSize& size) -{ - wxWindow* ref = wxGetApp().plater(); - if (!ref) - ref = wxGetApp().mainframe; - const wxRect plater = ref ? ref->GetScreenRect() : wxDisplay(0u).GetClientArea(); - int disp = wxDisplay::GetFromPoint(wxPoint(plater.GetLeft() + plater.GetWidth() / 2, - plater.GetTop() + plater.GetHeight() / 2)); - if (disp == wxNOT_FOUND) - disp = 0; - const wxRect screen = wxDisplay(disp).GetClientArea(); - const int x = plater.GetLeft() + (plater.GetWidth() - size.GetWidth()) / 2; // centred over plater - const int y = screen.GetTop() + screen.GetHeight() / 3; // top at 1/3 screen height - return wxPoint(x, y); -} - -int json_int_or(const nlohmann::json& j, const char* key, int fallback) -{ - auto it = j.find(key); - return it != j.end() && it->is_number() ? it->get() : fallback; -} - -wxColour bg_color() { return wxGetApp().get_window_default_clr(); } - -std::string css_color(const wxColour& c) { return c.GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); } - -std::string host_theme_name() { return wxGetApp().dark_mode() ? "dark" : "light"; } - -std::string host_theme_vars_css() -{ - GUI_App& app = wxGetApp(); - const wxColour bg = app.get_window_default_clr(); - const wxColour fg = app.get_label_clr_default(); - const wxColour muted = app.get_label_clr_sys(); - const wxColour border = app.get_highlight_default_clr(); - const wxColour accent = StateColor::darkModeColorFor(wxColour("#009688")); - std::string font = app.normal_font().GetFaceName().ToStdString(); - - font.erase(std::remove_if(font.begin(), font.end(), [](char c) { - return c == '\'' || c == '"' || c == '<' || c == '>' || c == '{' || c == '}' || c == ';'; - }), font.end()); - - std::string s; - s += ":root{"; - s += "--orca-bg:" + css_color(bg) + ";"; - s += "--orca-fg:" + css_color(fg) + ";"; - s += "--orca-muted:" + css_color(muted) + ";"; - s += "--orca-border:" + css_color(border) + ";"; - s += "--orca-accent:" + css_color(accent) + ";"; - s += "--orca-accent-fg:#ffffff;"; - s += "--orca-font:" + (font.empty() ? std::string() : "'" + font + "',") + - "system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;"; - s += "color-scheme:" + host_theme_name() + ";"; - s += "}"; - return s; -} - -std::string host_theme_user_script() -{ - const std::string style = ""; - return WebViewHostDialog::document_start_injector( - style, "orca-host-theme-vars", "afterbegin", "window.__orcaHostThemed=true;var theme=\"" + host_theme_name() + "\";", - "if(document.documentElement)document.documentElement.setAttribute('data-orca-theme',theme);"); -} - -std::string host_theme_apply_js() -{ - const std::string vars_literal = nlohmann::json(host_theme_vars_css()).dump(); - const std::string theme = host_theme_name(); - return "(function(){var css=" + vars_literal + ";var theme=\"" + theme + "\";" + R"JS( -var el=document.getElementById('orca-host-theme-vars'); -if(el){el.textContent=css;} -else if(document.head){document.head.insertAdjacentHTML('afterbegin','');var e2=document.getElementById('orca-host-theme-vars');if(e2)e2.textContent=css;} -if(document.documentElement) - document.documentElement.setAttribute('data-orca-theme',theme); -})();)JS"; -} - -} - -SpeedDialWebPopup::SpeedDialWebPopup(wxWindow* parent) - : ::PopupWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS) -{ - SetBackgroundColour(bg_color()); - - auto* sizer = new wxBoxSizer(wxVERTICAL); - m_browser = WebView::CreateWebView(this, wxEmptyString); - if (m_browser) { - m_browser->AddUserScript(wxString::FromUTF8(host_theme_user_script())); - m_browser->Bind(EVT_WEBVIEW_RECREATED, &SpeedDialWebPopup::on_webview_recreated, this); - sizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); - Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &SpeedDialWebPopup::on_script_message, this, m_browser->GetId()); - } else { - auto* fallback = new wxStaticText(this, wxID_ANY, wxS("wxWebView unavailable")); - sizer->Add(fallback, wxSizerFlags().Border(wxALL, 20)); - } - SetSizer(sizer); - SetClientSize(FromDIP(wxSize(kPopupWidth, kPopupMaxHeight))); // DIP -> physical (see resize_to_content) - if (m_browser) - WebView::LoadUrl(m_browser, dialog_url()); -} - -void SpeedDialWebPopup::request_show() -{ - if (IsShown()) { - focus_browser(); - return; - } - m_pending_show = true; - if (m_browser && m_page_ready) - send_actions(); - else if (!m_browser) - show_ready(); -} - -void SpeedDialWebPopup::focus_browser() -{ - if (m_browser) - m_browser->SetFocus(); -} - -void SpeedDialWebPopup::on_script_message(wxWebViewEvent& event) -{ - nlohmann::json p = nlohmann::json::parse(event.GetString().utf8_string(), nullptr, false); - if (!p.is_object()) - return; - const std::string cmd = p.value("command", ""); - if (cmd == "request_actions") { - m_page_ready = true; - send_actions(); - } - else if (cmd == "toggle_favourite") wxGetApp().action_registry().set_favourite(p.value("id", ""), p.value("fav", false)); - else if (cmd == "reorder_favourites") { - std::vector ids; - if (p.contains("ids") && p["ids"].is_array()) - for (auto& e : p["ids"]) if (e.is_string()) ids.push_back(e.get()); - wxGetApp().action_registry().reorder_favourites(ids); - } - else if (cmd == "run_action") run_action(p.value("id", ""), p.value("title", "")); - else if (cmd == "resize") resize_to_content(json_int_or(p, "height", 0)); - else if (cmd == "close_page") Dismiss(); -} - -void SpeedDialWebPopup::on_webview_recreated(wxCommandEvent&) -{ - apply_host_theme(); -} - -void SpeedDialWebPopup::apply_host_theme() -{ - if (m_browser) - WebView::RunScript(m_browser, wxString::FromUTF8(host_theme_apply_js())); -} - -void SpeedDialWebPopup::resize_to_content(int height) -{ - if (height <= 0) - return; - // why: HTML is the source of truth - size the popup to the measured content height so - // the window always contains the WebView and never clips. `height` arrives in CSS px - // (DIP); wx SetClientSize wants physical px, so on a scaled display (e.g. 125%) applying - // DIP as physical shrinks the popup below the content and clips it. Clamp in DIP, then - // FromDIP -> physical. The only ceiling is a screen fraction; normal growth is already - // bounded by the list's own max-height. - int disp = wxDisplay::GetFromPoint(IsShown() ? GetPosition() : wxGetMousePosition()); - if (disp == wxNOT_FOUND) - disp = 0; - const int screen_dip = ToDIP(wxDisplay(disp).GetClientArea().GetHeight()); - const int max_dip = std::max(kPopupMinHeight, screen_dip * 85 / 100); - const int height_dip = std::max(kPopupMinHeight, std::min(height, max_dip)); - SetClientSize(FromDIP(wxSize(kPopupWidth, height_dip))); - Layout(); - if (m_pending_show) - show_ready(); - else if (IsShown()) - SetPosition(clamped_position(GetPosition(), GetSize())); -} - -void SpeedDialWebPopup::show_ready() -{ - if (!m_pending_show) - return; - SetPosition(clamped_position(popup_position(GetSize()), GetSize())); - Popup(); - focus_browser(); - m_pending_show = false; -} - -// Hide FIRST (scripts may open their own modals that must not stack under this -// launcher), gate on a native run-confirm unless suppressed, then run on the next -// tick via the registry (which re-resolves the capability and bumps stats). -void SpeedDialWebPopup::run_action(const std::string& id, const std::string& title) -{ - ActionRegistry& reg = wxGetApp().action_registry(); - const AppAction* a = reg.by_id(id); - if (!a) - return; - const bool ask = reg.should_ask(id); - const std::string atitle = a->title(); // capture before Dismiss; `a` may not outlive it - Dismiss(); // launcher gone before the modal / the script's own UI - - if (ask) { - const wxString label = title.empty() ? from_u8(atitle) : from_u8(title); - RichMessageDialog dlg(wxGetApp().mainframe, wxString::Format(_L("Run \"%s\"?"), label), - _L("Run plugin"), wxOK | wxCANCEL); - dlg.ShowCheckBox(_L("Don't ask again for this action")); - if (dlg.ShowModal() != wxID_OK) - return; - if (dlg.IsCheckBoxChecked()) - wxGetApp().action_registry().suppress_ask(id); - } - // why: value-capture only. Script execution may outlive this popup if the app is closing. - wxGetApp().CallAfter([id] { - // why: the queue may drain during shutdown, after MainFrame/Plater teardown; - // skip like the registry's loader callbacks do instead of running into it. - if (wxGetApp().is_closing()) - return; - AppActionRunResult o = wxGetApp().action_registry().run(id); - if (o.level == AppActionRunResult::Level::Busy) - return; - if (!o.message.IsEmpty() && wxGetApp().plater()) - wxGetApp().plater()->get_notification_manager()->push_notification( - NotificationType::CustomNotification, - o.level == AppActionRunResult::Level::Error ? NotificationManager::NotificationLevel::ErrorNotificationLevel : - NotificationManager::NotificationLevel::RegularNotificationLevel, - into_u8(o.message)); - }); -} - -// C++ -> JS push. Same escaping as WebViewHostDialog::call_web_handler: the ignore error -// handler keeps a stray non-UTF-8 byte in a plugin name from throwing and aborting the send; -// concatenation (not wxString::Format) avoids a '%' in a title being read as a format token. -void SpeedDialWebPopup::push(const nlohmann::json& j) -{ - if (!m_browser) - return; - const wxString payload = wxString::FromUTF8(j.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore)); - WebView::RunScript(m_browser, wxT("window.HandleStudio(") + payload + wxT(")")); -} - -void SpeedDialWebPopup::send_actions() -{ - nlohmann::json snap = wxGetApp().action_registry().snapshot(); - push({{"command", "list_actions"}, - {"actions", std::move(snap["actions"])}, - {"favourites", std::move(snap["favourites"])}}); -} - -SpeedDialWebDialog::SpeedDialWebDialog(wxWindow* parent) - : WebViewHostDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, - wxBORDER_NONE | wxFRAME_NO_TASKBAR) -{ - SetBackgroundColour(bg_color()); - Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) { - if (!event.GetActive() && IsShown()) - Hide(); - event.Skip(); - }); - if (!create_webview("web/dialog/SpeedDial/index.html", wxEmptyString, - wxSize(kPopupWidth, kPopupMaxHeight), wxSize(kPopupWidth, kPopupMinHeight))) { - auto* sizer = new wxBoxSizer(wxVERTICAL); - sizer->Add(new wxStaticText(this, wxID_ANY, wxS("wxWebView unavailable")), - wxSizerFlags().Border(wxALL, 20)); - SetSizer(sizer); - SetClientSize(FromDIP(wxSize(kPopupWidth, kPopupMinHeight))); - } -} - -void SpeedDialWebDialog::request_show() -{ - if (IsShown()) { - Raise(); - if (browser()) - browser()->SetFocus(); - return; - } - - Show(); - Raise(); - if (m_page_ready) - send_actions(); - if (browser()) - browser()->SetFocus(); -} - -void SpeedDialWebDialog::on_script_message(const nlohmann::json& payload) -{ - if (handle_common_script_command(payload)) - return; - - const std::string command = payload.value("command", ""); - if (command == "request_actions") { - m_page_ready = true; - send_actions(); - } - else if (command == "toggle_favourite") - wxGetApp().action_registry().set_favourite(payload.value("id", ""), payload.value("fav", false)); - else if (command == "reorder_favourites") { - std::vector ids; - if (payload.contains("ids") && payload["ids"].is_array()) - for (const auto& id : payload["ids"]) - if (id.is_string()) - ids.push_back(id.get()); - wxGetApp().action_registry().reorder_favourites(ids); - } - else if (command == "run_action") - run_action(payload.value("id", ""), payload.value("title", "")); - else if (command == "resize") - resize_to_content(json_int_or(payload, "height", 0)); -} - -void SpeedDialWebDialog::resize_to_content(int height) -{ - if (height <= 0) - return; - - int display_index = wxDisplay::GetFromWindow(this); - if (display_index == wxNOT_FOUND) - display_index = 0; - const int screen_dip = ToDIP(wxDisplay(display_index).GetClientArea().GetHeight()); - const int max_dip = std::max(kPopupMinHeight, screen_dip * 85 / 100); - const int height_dip = std::max(kPopupMinHeight, std::min(height, max_dip)); - SetClientSize(FromDIP(wxSize(kPopupWidth, height_dip))); - Layout(); -} - -void SpeedDialWebDialog::run_action(const std::string& id, const std::string& title) -{ - ActionRegistry& reg = wxGetApp().action_registry(); - const AppAction* a = reg.by_id(id); - if (!a) - return; - - const bool ask = reg.should_ask(id); - const std::string atitle = a->title(); - if (IsModal()) - EndModal(wxID_CANCEL); - else - Hide(); - - if (ask) { - const wxString label = title.empty() ? from_u8(atitle) : from_u8(title); - RichMessageDialog dlg(wxGetApp().mainframe, wxString::Format(_L("Run \"%s\"?"), label), - _L("Run plugin"), wxOK | wxCANCEL); - dlg.ShowCheckBox(_L("Don't ask again for this action")); - if (dlg.ShowModal() != wxID_OK) - return; - if (dlg.IsCheckBoxChecked()) - wxGetApp().action_registry().suppress_ask(id); - } - - wxGetApp().CallAfter([id] { - if (wxGetApp().is_closing()) - return; - AppActionRunResult result = wxGetApp().action_registry().run(id); - if (result.level == AppActionRunResult::Level::Busy) - return; - if (!result.message.IsEmpty() && wxGetApp().plater()) - wxGetApp().plater()->get_notification_manager()->push_notification( - NotificationType::CustomNotification, - result.level == AppActionRunResult::Level::Error ? NotificationManager::NotificationLevel::ErrorNotificationLevel : - NotificationManager::NotificationLevel::RegularNotificationLevel, - into_u8(result.message)); - }); -} - -void SpeedDialWebDialog::send_actions() -{ - nlohmann::json snap = wxGetApp().action_registry().snapshot(); - call_web_handler({{"command", "list_actions"}, - {"actions", std::move(snap["actions"])}, - {"favourites", std::move(snap["favourites"])}}); -} - -}} diff --git a/src/slic3r/GUI/SpeedDialPopup.hpp b/src/slic3r/GUI/SpeedDialPopup.hpp deleted file mode 100644 index 44c04f4c02..0000000000 --- a/src/slic3r/GUI/SpeedDialPopup.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef slic3r_GUI_SpeedDialPopup_hpp_ -#define slic3r_GUI_SpeedDialPopup_hpp_ - -#include "Widgets/PopupWindow.hpp" - -#include -#include -#include -#include - -namespace Slic3r { namespace GUI { - -class SpeedDialWebPopup : public ::PopupWindow -{ -public: - explicit SpeedDialWebPopup(wxWindow* parent); - void request_show(); - void focus_browser(); - -private: - void OnDismiss() override {} - void on_script_message(wxWebViewEvent& event); - void on_webview_recreated(wxCommandEvent&); - void apply_host_theme(); - void resize_to_content(int height); - void show_ready(); - void run_action(const std::string& id, const std::string& title); - void push(const nlohmann::json& j); - void send_actions(); - - wxWebView* m_browser{nullptr}; - bool m_page_ready{false}; - bool m_pending_show{false}; -}; - -class SpeedDialWebDialog : public WebViewHostDialog -{ -public: - explicit SpeedDialWebDialog(wxWindow* parent); - void request_show(); - -private: - void on_script_message(const nlohmann::json& payload) override; - void resize_to_content(int height); - void run_action(const std::string& id, const std::string& title); - void send_actions(); - - bool m_page_ready{false}; -}; - -}} - -#endif