diff --git a/resources/web/dialog/PluginsDialog/index.html b/resources/web/dialog/PluginsDialog/index.html
index ae4ffc8b9e..8981a7d62d 100644
--- a/resources/web/dialog/PluginsDialog/index.html
+++ b/resources/web/dialog/PluginsDialog/index.html
@@ -18,7 +18,7 @@
-
+
diff --git a/resources/web/homepage/js/home.js b/resources/web/homepage/js/home.js
index 188a9dded2..75d1af232f 100644
--- a/resources/web/homepage/js/home.js
+++ b/resources/web/homepage/js/home.js
@@ -156,12 +156,16 @@ function SetCloudMode( bOn )
m_CloudMode=bOn;
$("body").toggleClass("cloud-mode", bOn);
+
+ if( bOn )
+ {
+ $(".BtnItem").removeClass("BtnItemSelected");
+ $(".BtnShortcut").addClass("BtnItemSelected");
+ }
}
function GotoCloud()
{
- $(".BtnItem").removeClass("BtnItemSelected");
- $(".BtnShortcut").addClass("BtnItemSelected");
SetCloudMode(true);
SendSimpleCommand("homepage_open_cloud");
}
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index c963bbba72..05650d2275 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -689,6 +689,8 @@ set(SLIC3R_GUI_SOURCES
plugin/host/PluginHostUi.hpp
plugin/host/PluginPages.cpp
plugin/host/PluginPages.hpp
+ plugin/host/PluginResourceTextures.cpp
+ plugin/host/PluginResourceTextures.hpp
plugin/CloudPluginService.cpp
plugin/CloudPluginService.hpp
plugin/PluginFsUtils.cpp
@@ -712,6 +714,9 @@ set(SLIC3R_GUI_SOURCES
plugin/pluginTypes/pages/PagesPluginCapability.hpp
plugin/pluginTypes/pages/PagesPluginCapability.cpp
plugin/pluginTypes/pages/PagesPluginCapabilityTrampoline.hpp
+ plugin/pluginTypes/resourceTexture/ResourceTexturePluginCapability.hpp
+ plugin/pluginTypes/resourceTexture/ResourceTexturePluginCapability.cpp
+ plugin/pluginTypes/resourceTexture/ResourceTexturePluginCapabilityTrampoline.hpp
plugin/pluginTypes/script/ScriptPluginCapability.hpp
plugin/pluginTypes/script/ScriptPluginCapability.cpp
plugin/pluginTypes/script/ScriptPluginCapabilityTrampoline.hpp
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 020cd2a50f..b9e119220c 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -252,9 +252,11 @@
#include "slic3r/GUI/ParamsDialog.hpp"
#include "slic3r/GUI/ParamsPanel.hpp"
#include "slic3r/GUI/PartPlate.hpp"
+#include "slic3r/GUI/TextureLibrary.hpp"
#include "slic3r/GUI/Widgets/Button.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/plugin/host/PluginPages.hpp"
+#include "slic3r/plugin/host/PluginResourceTextures.hpp"
#include
#include "slic3r/GUI/Widgets/WebView.hpp"
#include
@@ -333,6 +335,23 @@ static std::shared_ptr get_orca_cloud_agent(NetworkAgent*
return agent ? std::dynamic_pointer_cast(agent->get_cloud_agent()) : nullptr;
}
+// Full {web} page URL for a same-site OrcaCloud path, or empty when it cannot be built. An already
+// open cloud pane is navigated straight to it, without re-running the session handoff.
+static wxString cloud_page_url(NetworkAgent* agent, const std::string& path)
+{
+ if (path.empty())
+ return {};
+ auto orca = get_orca_cloud_agent(agent);
+ if (!orca)
+ return {};
+ std::string base = orca->get_cloud_base_url();
+ while (!base.empty() && base.back() == '/')
+ base.pop_back();
+ if (base.empty())
+ return {};
+ return from_u8(base + path);
+}
+
void start_ping_test()
{
return;
@@ -3063,6 +3082,37 @@ void GUI_App::init_plugin_gui_wiring()
refresh_plugins_dialog();
switch_printer_agent_after_unload(capability.plugin_key);
});
+ plugin_mgr.subscribe_on_load_callback([](const std::string& plugin_key) {
+ if (wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
+ PluginResourceTextures::instance().on_plugin_register(plugin_key);
+ Slic3r::GUI::bump_texture_library_generation();
+ });
+ plugin_mgr.subscribe_on_unload_callback([](const std::string& plugin_key) {
+ if (wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
+ PluginResourceTextures::instance().on_plugin_deregister(plugin_key);
+ Slic3r::GUI::bump_texture_library_generation();
+ });
+ plugin_mgr.subscribe_on_capability_load_callback([](const PluginCapabilityId& capability) {
+ if (capability.type != PluginCapabilityType::ResourceTexture)
+ return;
+ if (wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
+ PluginResourceTextures::instance().on_cap_register(capability);
+ Slic3r::GUI::bump_texture_library_generation();
+ });
+ plugin_mgr.subscribe_on_capability_unload_callback([](const PluginCapabilityId& capability) {
+ if (capability.type != PluginCapabilityType::ResourceTexture)
+ return;
+ if (wxTheApp == nullptr || wxGetApp().is_closing())
+ return;
+ PluginResourceTextures::instance().on_cap_deregister(capability);
+ Slic3r::GUI::bump_texture_library_generation();
+ });
+ // Packs already loaded before this wiring, or in tests where no callback fires.
+ PluginResourceTextures::instance().initial_sweep();
+ Slic3r::GUI::bump_texture_library_generation();
}
bool GUI_App::on_init_inner()
@@ -5434,12 +5484,7 @@ std::string GUI_App::handle_web_request(std::string cmd)
this->request_open_project({});
}
else if (command_str.compare("homepage_open_cloud") == 0) {
- // Deferred: set_cloud_mode() may create a second native webview, which must
- // not run inside this webview's script-message callback.
- CallAfter([this]() {
- if (WebViewPanel* home = WebViewPanel::if_built())
- home->set_cloud_mode(true, cloud_webview_handoff());
- });
+ this->open_orca_cloud();
}
else if (command_str.compare("homepage_close_cloud") == 0) {
CallAfter([]() {
@@ -5588,6 +5633,22 @@ std::string GUI_App::handle_web_request(std::string cmd)
return "";
}
+void GUI_App::open_orca_cloud(const std::string& next)
+{
+ // Remembered so a login while the pane is open re-seeds the same page rather than the default.
+ m_cloud_open_path = next;
+ // Deferred: set_cloud_mode() may create the second native webview, so this must not run inside
+ // the caller's frame (a webview script-message callback or an ImGui frame).
+ CallAfter([this]() {
+ if (mainframe != nullptr)
+ mainframe->select_tab(TAB_ID_HOME);
+ // The Home page is built lazily, so the tab switch may not have created it yet: ensure() builds
+ // it if needed, matching what showing the tab does, rather than dropping the open request.
+ if (WebViewPanel* home = WebViewPanel::ensure())
+ home->set_cloud_mode(true, cloud_webview_handoff(m_cloud_open_path), cloud_page_url(m_agent, m_cloud_open_path));
+ });
+}
+
void GUI_App::handle_script_message(std::string msg, const std::string& provider)
{
try {
@@ -5865,7 +5926,7 @@ void GUI_App::on_update_machine_list(wxCommandEvent &evt)
}*/
}
-wxString GUI_App::cloud_webview_handoff()
+wxString GUI_App::cloud_webview_handoff(const std::string& next)
{
// The cloud pane loads the Start URL, not a token: the page checks the webview's own session
// and asks for a handoff itself (guide §4). Signed out, user_id is omitted and the page will
@@ -5873,7 +5934,7 @@ wxString GUI_App::cloud_webview_handoff()
auto orca = get_orca_cloud_agent(m_agent);
if (!orca)
return {};
- return from_u8(orca->build_web_session_start_url());
+ return from_u8(orca->build_web_session_start_url(next));
}
void GUI_App::request_cloud_web_session(const std::string& state)
@@ -6016,7 +6077,7 @@ void GUI_App::on_user_login_handle(wxCommandEvent &evt)
m_cloud_handoff_state.clear();
if (WebViewPanel* home = WebViewPanel::if_built())
if (home->cloud_mode_active())
- home->set_cloud_mode(true, cloud_webview_handoff());
+ home->set_cloud_mode(true, cloud_webview_handoff(m_cloud_open_path));
}
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index 076855471e..33ac8f317f 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -368,6 +368,8 @@ private:
// and a generation counter so a superseded mint/login result is dropped (guide §5, "only the
// newest request counts").
std::string m_cloud_handoff_state;
+ // The OrcaCloud path the open requests target, remembered so a login re-seed keeps the same page.
+ std::string m_cloud_open_path;
uint64_t m_cloud_handoff_gen { 0 };
bool m_show_error_msgdlg{false};
wxString m_info_dialog_content;
@@ -469,6 +471,9 @@ public:
#if wxUSE_WEBVIEW_EDGE
void init_webview_runtime();
#endif
+ // Switches to the Home tab and opens the OrcaCloud pane beside the homepage on `next`, a
+ // same-site OrcaCloud path (empty = the page's default). Work is deferred internally.
+ void open_orca_cloud(const std::string& next = std::string());
static unsigned get_colour_approx_luma(const wxColour& colour);
static bool dark_mode();
const wxColour get_label_default_clr_system();
@@ -575,7 +580,7 @@ public:
// called from the pane when the page asks for a session; it opens the desktop login dialog if
// signed out, otherwise mints a one-time token on a worker thread and loads the Complete URL
// in the same webview.
- wxString cloud_webview_handoff();
+ wxString cloud_webview_handoff(const std::string& next = std::string());
void request_cloud_web_session(const std::string& state);
void mint_cloud_web_session(const std::string& state, uint64_t gen);
void on_cloud_web_session_minted(const std::string& state, uint64_t gen, const std::string& token_hash);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp
index 3fbede05e6..4597e98fd2 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp
@@ -40,6 +40,7 @@
#include "slic3r/Utils/UndoRedo.hpp"
#include "GLGizmoUtils.hpp"
+#include
#include
#include
#include
@@ -72,6 +73,7 @@
#include
#include
#include
+#include