diff --git a/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po b/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po index f1f7370c1e..2c0e5d7969 100644 --- a/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po +++ b/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po @@ -18775,6 +18775,9 @@ msgstr "" msgid "More Colors" msgstr "" +msgid "Warning: Printing by object with caution. This function may cause the print head to collide with printed parts during switching." +msgstr "警告:谨慎使用逐件打印,该功能可能会导致打印头切换时与打印件碰撞。" + #: resources/data/hints.ini: [hint:Precise wall] msgid "" "Precise wall\n" diff --git a/resources/web/guide/24/24.js b/resources/web/guide/24/24.js index f653a4298d..e972a1201b 100644 --- a/resources/web/guide/24/24.js +++ b/resources/web/guide/24/24.js @@ -1,10 +1,12 @@ +var VendorPriority = new Array("Snapmaker"); + function OnInit() { //let strInput=JSON.stringify(cData); //HandleStudio(strInput); - + TranslatePage(); - + RequestProfile(); } @@ -52,21 +54,22 @@ function HandleModelList( pVal ) return; pModel=pVal['model']; - + let nTotal=pModel.length; let ModelHtml={}; + let VendorHtmlArray={}; for(let n=0;n '+ ''+ ''; - - $('#Content').append(HtmlNewVendor); + + VendorHtmlArray[strVendor]=HtmlNewVendor; } - + let ModelName=OneModel['model']; - + //Collect Html Node Nozzel Html if( !ModelHtml.hasOwnProperty(strVendor)) ModelHtml[strVendor]=''; - + let NozzleArray=OneModel['nozzle_diameter'].split(';'); let HtmlNozzel=''; for(let m=0;m'+nNozzel+'mm nozzle'; } - + let CoverImage=OneModel['cover']; ModelHtml[strVendor]+='
'+ '
'+ '
'+OneModel['name']+'
'+ HtmlNozzel +'
'; } - + + //Append Vendor blocks in priority order + for(let n=0;n' + ''; - $('#Content').append(HtmlNewVendor); + VendorHtmlArray[strVendor] = HtmlNewVendor; } //Collect Html Node Nozzel Html @@ -272,6 +293,20 @@ function FilterModelList(keyword) { '
' + OneModel['name'] + '
' + HtmlNozzel + ''; } + //Append Vendor blocks in priority order + for (let n = 0; n < VendorPriority.length; n++) { + let strVendor = VendorPriority[n]; + if (VendorHtmlArray.hasOwnProperty(strVendor)) { + $('#Content').append(VendorHtmlArray[strVendor]); + delete VendorHtmlArray[strVendor]; + } + } + + //Append remaining vendors + for (let key in VendorHtmlArray) { + $('#Content').append(VendorHtmlArray[key]); + } + //Update Nozzel Html Append for (let key in ModelHtml) { let obj = $(".OneVendorBlock[vendor='" + key + "'] .PrinterArea"); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 21ea5be632..ab3a23437a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -7236,6 +7236,24 @@ void GUI_App::device_card_notify(const json& res) } } +void GUI_App::page_state_notify_webview(wxWebView* webview, const std::string& state) +{ + if (!webview) return; + + json notification_data; + notification_data["state"] = state; + + for (const auto& instance : m_page_state_subscribers) { + if (instance.first == webview) { + auto ptr = instance.second.lock(); + if (ptr) { + ptr->m_res_data = notification_data; + ptr->send_to_js(); + } + } + } +} + void GUI_App::cache_notify(const std::string& key, const json& res) { for (const auto& instance : m_cache_subscribers) { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 11107d08fa..608c202ea4 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -833,6 +833,7 @@ public: std::unordered_map> m_recent_file_subscribers; std::unordered_map> m_user_login_subscribers; std::unordered_map> m_device_card_subscribers; + std::unordered_map> m_page_state_subscribers; struct CachePairCompare { @@ -847,6 +848,7 @@ public: void recent_file_notify(const json& res); void user_login_notify(const json& res); void device_card_notify(const json& res); + void page_state_notify_webview(wxWebView* webview, const std::string& state); void cache_notify(const std::string& key, const json& res); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index f6e67d1c0a..f3d3c2ca5a 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1058,6 +1058,46 @@ void MainFrame::init_tabpanel() { } #endif + // Notify WCP page state change subscribers + static int prev_monitored_tab = -1; + + // Send "inactive" to previous tab if leaving a monitored tab + if (prev_monitored_tab == tpHome && sel != tpHome) { + // Leaving homepage + if (m_webview) { + wxWebView* home_webview = m_webview->getWebView(); + wxGetApp().page_state_notify_webview(home_webview, "inactive"); + } + } else if (prev_monitored_tab == tpMonitor && sel != tpMonitor) { + // Leaving device page (PrinterWebView) + if (m_printer_view) { + wxWebView* printer_webview = m_printer_view->get_browser(); + wxGetApp().page_state_notify_webview(printer_webview, "inactive"); + } + } + + // Send "active" to current tab if entering a monitored tab + if (sel == tpHome) { + // Entering homepage + if (m_webview) { + wxWebView* home_webview = m_webview->getWebView(); + wxGetApp().page_state_notify_webview(home_webview, "active"); + } + prev_monitored_tab = tpHome; + } else if (sel == tpMonitor) { + // Entering device page (PrinterWebView) + if (m_printer_view) { + wxWebView* printer_webview = m_printer_view->get_browser(); + wxGetApp().page_state_notify_webview(printer_webview, "active"); + } + prev_monitored_tab = tpMonitor; + } else { + // Update prev_monitored_tab only when leaving a monitored tab + if (prev_monitored_tab != tpHome && prev_monitored_tab != tpMonitor) { + prev_monitored_tab = -1; + } + } + if (panel) panel->SetFocus(); diff --git a/src/slic3r/GUI/NetworkTestDialog.cpp b/src/slic3r/GUI/NetworkTestDialog.cpp index 52b0736b7e..fbbb0c9519 100644 --- a/src/slic3r/GUI/NetworkTestDialog.cpp +++ b/src/slic3r/GUI/NetworkTestDialog.cpp @@ -773,15 +773,15 @@ void NetworkTestDialog::start_test_telnet(TestJob job, wxString name, wxString s wxString grade_desc; wxString grade_icon; - if (connect_time <= 100) { + if (connect_time <= 50) { grade = 1; grade_desc = "Excellent"; grade_icon = "[Level 1]"; - } else if (connect_time <= 500) { + } else if (connect_time <= 100) { grade = 2; grade_desc = "Good"; grade_icon = "[Level 2]"; - } else if (connect_time <= 1000) { + } else if (connect_time <= 400) { grade = 3; grade_desc = "Fair"; grade_icon = "[Level 3]"; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c9b4b06e5e..38f808da9e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4930,6 +4930,30 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } if (!silence) wxGetApp().app_config->update_config_dir(path.parent_path().string()); + + // BBS: Check for Snapmaker U1 + Print by Object warning after loading 3mf config + if (load_config && is_project_file) { + auto print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + auto printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + + auto print_seq_opt = print_config.option>("print_sequence"); + auto printer_model_opt = printer_config.option("printer_model"); + + if (print_seq_opt && printer_model_opt && + print_seq_opt->value == PrintSequence::ByObject && + !printer_model_opt->value.empty()) { + std::string printer_model = printer_model_opt->value; + bool is_snapmaker_u1 = boost::icontains(printer_model, "Snapmaker") && + boost::icontains(printer_model, "U1"); + + if (is_snapmaker_u1) { + if (q->get_notification_manager()) { + std::string warning_text = _u8L("Warning: Printing by object with caution. This function may cause the print head to collide with printed parts during switching."); + q->get_notification_manager()->push_plater_error_notification(warning_text); + } + } + } + } } } else { // BBS: add plate data related logic diff --git a/src/slic3r/GUI/PrinterWebView.hpp b/src/slic3r/GUI/PrinterWebView.hpp index 1944823b59..d11b14837c 100644 --- a/src/slic3r/GUI/PrinterWebView.hpp +++ b/src/slic3r/GUI/PrinterWebView.hpp @@ -46,6 +46,7 @@ public: void update_mode(); bool isSnapmakerPage(); void sendMessage(const std::string& msg); + wxWebView* get_browser() const { return m_browser; } private: void SendAPIKey(); diff --git a/src/slic3r/GUI/SSWCP.cpp b/src/slic3r/GUI/SSWCP.cpp index 8deb7b0508..239047f7dc 100644 --- a/src/slic3r/GUI/SSWCP.cpp +++ b/src/slic3r/GUI/SSWCP.cpp @@ -4282,6 +4282,66 @@ void SSWCP_MachineManage_Instance::sw_SubscribeLocalDevices() } } +// SSWCP_PageStateChange_Instance +void SSWCP_PageStateChange_Instance::process() +{ + if (m_event_id != "") { + json header; + send_to_js(); + + m_header.clear(); + m_header["event_id"] = m_event_id; + } + + if (m_cmd == "sw_SubscribePageStateChange") { + sw_SubscribePageStateChange(); + } else if (m_cmd == "sw_UnsubscribePageStateChange") { + sw_UnsubscribePageStateChange(); + } else { + handle_general_fail(); + } +} + +void SSWCP_PageStateChange_Instance::sw_SubscribePageStateChange() +{ + try { + auto self = shared_from_this(); + wxGetApp().m_page_state_subscribers[m_webview] = self; + } catch (std::exception& e) { + handle_general_fail(); + } +} + +void SSWCP_PageStateChange_Instance::sw_UnsubscribePageStateChange() +{ + try { + auto& page_state_map = wxGetApp().m_page_state_subscribers; + std::string event_id = m_param_data.count("event_id") ? m_param_data["event_id"].get() : ""; + + for (auto iter = page_state_map.begin(); iter != page_state_map.end();) { + if (iter->first == m_webview) { + auto ptr = iter->second.lock(); + if (ptr) { + if (event_id == "" || (event_id != "" && event_id == ptr->m_event_id)) { + iter = page_state_map.erase(iter); + } else { + iter++; + } + } else { + iter = page_state_map.erase(iter); + } + } else { + iter++; + } + } + + send_to_js(); + finish_job(); + } catch (std::exception& e) { + handle_general_fail(); + } +} + void SSWCP_MachineManage_Instance::sw_AddDevice() { try { @@ -5608,6 +5668,10 @@ std::unordered_set SSWCP::m_machine_manage_cmd_list = { "sw_GetLocalDevices", "sw_AddDevice", "sw_SubscribeLocalDevices", "sw_RenameDevice", "sw_SwitchModel", "sw_DeleteDevices" }; +std::unordered_set SSWCP::m_page_state_cmd_list = { + "sw_SubscribePageStateChange", "sw_UnsubscribePageStateChange" +}; + std::unordered_set SSWCP::m_mqtt_agent_cmd_list = { "sw_create_mqtt_client", "sw_mqtt_connect", "sw_mqtt_disconnect", "sw_mqtt_subscribe", "sw_mqtt_unpublish", "sw_mqtt_publish", "sw_mqtt_set_engine" }; @@ -5628,6 +5692,8 @@ std::shared_ptr SSWCP::create_sswcp_instance(std::string cmd, co instance = std::make_shared(cmd, header, data, event_id, webview); } else if (m_machine_manage_cmd_list.find(cmd) != m_machine_manage_cmd_list.end()) { instance = std::make_shared(cmd, header, data, event_id, webview); + } else if (m_page_state_cmd_list.find(cmd) != m_page_state_cmd_list.end()) { + instance = std::make_shared(cmd, header, data, event_id, webview); } else if(m_mqtt_agent_cmd_list.find(cmd) != m_mqtt_agent_cmd_list.end()) { instance = std::make_shared(cmd, header, data, event_id, webview); } @@ -5804,6 +5870,15 @@ void SSWCP::on_webview_delete(wxWebView* view) iter++; } } + + auto& page_state_map = wxGetApp().m_page_state_subscribers; + for (auto iter = page_state_map.begin(); iter != page_state_map.end();) { + if (iter->first == view) { + iter = page_state_map.erase(iter); + } else { + iter++; + } + } } std::string SSWCP::get_display_filename() diff --git a/src/slic3r/GUI/SSWCP.hpp b/src/slic3r/GUI/SSWCP.hpp index b66c3aca59..7963745995 100644 --- a/src/slic3r/GUI/SSWCP.hpp +++ b/src/slic3r/GUI/SSWCP.hpp @@ -482,6 +482,26 @@ private: void sw_DeleteDevices(); }; +// Instance class for page state change subscription +class SSWCP_PageStateChange_Instance : public SSWCP_Instance +{ +public: + SSWCP_PageStateChange_Instance(std::string cmd, const json& header, const json& data, + std::string event_id, wxWebView* webview) + : SSWCP_Instance(cmd, header, data, event_id, webview) + { + m_type = COMMON; + } + + ~SSWCP_PageStateChange_Instance() {} + + void process() override; + +private: + void sw_SubscribePageStateChange(); + void sw_UnsubscribePageStateChange(); +}; + // Instance class for Snapmaker user login class SSWCP_UserLogin_Instance : public SSWCP_Instance { @@ -589,6 +609,7 @@ private: static std::unordered_set m_login_cmd_list; // homepage login commands static std::unordered_set m_machine_manage_cmd_list; // homepage machine manage commands; static std::unordered_set m_mqtt_agent_cmd_list; // mqtt-agent commands; + static std::unordered_set m_page_state_cmd_list; // page state change commands; static TimeoutMap> m_instance_list; // Active instances static constexpr std::chrono::milliseconds DEFAULT_INSTANCE_TIMEOUT{80000}; // Default timeout (8s) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6ed0fa8467..a3ab41af94 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -49,6 +49,7 @@ #include "Search.hpp" #include "BedShapeDialog.hpp" #include "libslic3r/GCode/Thumbnails.hpp" +#include "NotificationManager.hpp" #include "BedShapeDialog.hpp" // #include "BonjourDialog.hpp" @@ -1548,6 +1549,38 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) } } + // BBS: Add warning notification for Snapmaker U1 + Print by Object + if (opt_key == "print_sequence") { + PrintSequence print_seq = m_config->opt_enum("print_sequence"); + + if (print_seq == PrintSequence::ByObject) { + // Get current printer model + auto printer_model_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option("printer_model"); + + if (printer_model_opt && !printer_model_opt->value.empty()) { + std::string printer_model = printer_model_opt->value; + + // Check if this is Snapmaker U1 printer + bool is_snapmaker_u1 = boost::icontains(printer_model, "Snapmaker") && + boost::icontains(printer_model, "U1"); + + if (is_snapmaker_u1) { + // Show red warning notification + if (wxGetApp().plater() && wxGetApp().plater()->get_notification_manager()) { + std::string warning_text = _u8L("Warning: Printing by object with caution. This function may cause the print head to collide with printed parts during switching."); + wxGetApp().plater()->get_notification_manager()->push_plater_error_notification(warning_text); + } + } + } + } else { + // Clear warning when switching away from ByObject + if (wxGetApp().plater() && wxGetApp().plater()->get_notification_manager()) { + std::string warning_text = _u8L("Warning: Printing by object with caution. This function may cause the print head to collide with printed parts during switching."); + wxGetApp().plater()->get_notification_manager()->close_plater_error_notification(warning_text); + } + } + } + // BBS set support style to default when support type changes // Orca: do this only in simple mode if (opt_key == "support_type" && m_mode == comSimple) {